提交 7d2908fb 编写于 作者: S sushuang

(1) Fix map rich label missing when missing data

(2) Fix map label miss to enter formatter when missing data.
(3) Fix #9682
上级 660d2134
...@@ -23,7 +23,7 @@ import SeriesModel from '../../model/Series'; ...@@ -23,7 +23,7 @@ import SeriesModel from '../../model/Series';
import {encodeHTML, addCommas} from '../../util/format'; import {encodeHTML, addCommas} from '../../util/format';
import dataSelectableMixin from '../../component/helper/selectableMixin'; import dataSelectableMixin from '../../component/helper/selectableMixin';
import {retrieveRawAttr} from '../../data/helper/dataProvider'; import {retrieveRawAttr} from '../../data/helper/dataProvider';
import geoCreator from '../../coord/geo/geoCreator'; import geoSourceManager from '../../coord/geo/geoSourceManager';
var MapSeries = SeriesModel.extend({ var MapSeries = SeriesModel.extend({
...@@ -45,43 +45,40 @@ var MapSeries = SeriesModel.extend({ ...@@ -45,43 +45,40 @@ var MapSeries = SeriesModel.extend({
*/ */
seriesGroup: [], seriesGroup: [],
init: function (option) {
// this._fillOption(option, this.getMapType());
// this.option = option;
MapSeries.superApply(this, 'init', arguments);
this.updateSelectedMap(this._createSelectableList());
},
getInitialData: function (option) { getInitialData: function (option) {
return createListSimply(this, ['value']); var data = createListSimply(this, ['value']);
},
mergeOption: function (newOption) {
// this._fillOption(newOption, this.getMapType());
MapSeries.superApply(this, 'mergeOption', arguments);
this.updateSelectedMap(this._createSelectableList());
},
_createSelectableList: function () {
var data = this.getRawData();
var valueDim = data.mapDimension('value'); var valueDim = data.mapDimension('value');
var targetList = []; var dataNameMap = zrUtil.createHashMap();
var selectTargetList = [];
var toAppendNames = [];
for (var i = 0, len = data.count(); i < len; i++) { for (var i = 0, len = data.count(); i < len; i++) {
targetList.push({ var name = data.getName(i);
name: data.getName(i), dataNameMap.set(name, true);
selectTargetList.push({
name: name,
value: data.get(valueDim, i), value: data.get(valueDim, i),
selected: retrieveRawAttr(data, i, 'selected') selected: retrieveRawAttr(data, i, 'selected')
}); });
} }
targetList = geoCreator.getFilledRegions(targetList, this.getMapType(), this.option.nameMap); var geoSource = geoSourceManager.load(this.getMapType(), this.option.nameMap);
zrUtil.each(geoSource.regions, function (region) {
var name = region.name;
if (!dataNameMap.get(name)) {
selectTargetList.push({name: name});
toAppendNames.push(name);
}
});
this.updateSelectedMap(selectTargetList);
return targetList; // Complete data with missing regions. The consequent processes (like visual
// map and render) can not be performed without a "full data". For example,
// find `dataIndex` by name.
data.appendValues([], toAppendNames);
return data;
}, },
/** /**
...@@ -99,14 +96,14 @@ var MapSeries = SeriesModel.extend({ ...@@ -99,14 +96,14 @@ var MapSeries = SeriesModel.extend({
return (this.getHostGeoModel() || this).option.map; return (this.getHostGeoModel() || this).option.map;
}, },
_fillOption: function (option, mapName) { // _fillOption: function (option, mapName) {
// Shallow clone // Shallow clone
// option = zrUtil.extend({}, option); // option = zrUtil.extend({}, option);
// option.data = geoCreator.getFilledRegions(option.data, mapName, option.nameMap); // option.data = geoCreator.getFilledRegions(option.data, mapName, option.nameMap);
// return option; // return option;
}, // },
getRawValue: function (dataIndex) { getRawValue: function (dataIndex) {
// Use value stored in data instead because it is calculated from multiple series // Use value stored in data instead because it is calculated from multiple series
......
...@@ -85,12 +85,12 @@ export default echarts.extendChartView({ ...@@ -85,12 +85,12 @@ export default echarts.extendChartView({
var originalData = mapModel.originalData; var originalData = mapModel.originalData;
var group = this.group; var group = this.group;
originalData.each(originalData.mapDimension('value'), function (value, idx) { originalData.each(originalData.mapDimension('value'), function (value, originalDataIndex) {
if (isNaN(value)) { if (isNaN(value)) {
return; return;
} }
var layout = originalData.getItemLayout(idx); var layout = originalData.getItemLayout(originalDataIndex);
if (!layout || !layout.point) { if (!layout || !layout.point) {
// Not exists in map // Not exists in map
...@@ -116,28 +116,44 @@ export default echarts.extendChartView({ ...@@ -116,28 +116,44 @@ export default echarts.extendChartView({
}, },
silent: true, silent: true,
// Do not overlap the first series, on which labels are displayed. // Do not overlap the first series, on which labels are displayed.
z2: !offset ? 10 : 8 z2: 8 + (!offset ? graphic.Z2_EMPHASIS_LIFT + 1 : 0)
}); });
// First data on the same region // Only the series that has the first value on the same region is in charge of rendering the label.
// But consider the case:
// series: [
// {id: 'X', type: 'map', map: 'm', {data: [{name: 'A', value: 11}, {name: 'B', {value: 22}]},
// {id: 'Y', type: 'map', map: 'm', {data: [{name: 'A', value: 21}, {name: 'C', {value: 33}]}
// ]
// The offset `0` of item `A` is at series `X`, but of item `C` is at series `Y`.
// For backward compatibility, we follow the rule that render label `A` by the
// settings on series `X` but render label `C` by the settings on series `Y`.
if (!offset) { if (!offset) {
var fullData = mapModel.mainSeries.getData(); var fullData = mapModel.mainSeries.getData();
var name = originalData.getName(idx); var name = originalData.getName(originalDataIndex);
var fullIndex = fullData.indexOfName(name); var fullIndex = fullData.indexOfName(name);
var itemModel = originalData.getItemModel(idx); var itemModel = originalData.getItemModel(originalDataIndex);
var labelModel = itemModel.getModel('label'); var labelModel = itemModel.getModel('label');
var hoverLabelModel = itemModel.getModel('emphasis.label'); var hoverLabelModel = itemModel.getModel('emphasis.label');
var polygonGroups = fullData.getItemGraphicEl(fullIndex); var polygonGroups = fullData.getItemGraphicEl(fullIndex);
// `getFormattedLabel` needs to use `getData` inside. Here
// `mapModel.getData()` is shallow cloned from `mainSeries.getData()`.
// FIXME
// If this is not the `mainSeries`, the item model (like label formatter)
// set on original data item will never get. But it has been working
// like that from the begining, and this scenario is rarely encountered.
// So it won't be fixed until have to.
var normalText = zrUtil.retrieve2( var normalText = zrUtil.retrieve2(
mapModel.getFormattedLabel(idx, 'normal'), mapModel.getFormattedLabel(fullIndex, 'normal'),
name name
); );
var emphasisText = zrUtil.retrieve2( var emphasisText = zrUtil.retrieve2(
mapModel.getFormattedLabel(idx, 'emphasis'), mapModel.getFormattedLabel(fullIndex, 'emphasis'),
normalText normalText
); );
...@@ -148,7 +164,7 @@ export default echarts.extendChartView({ ...@@ -148,7 +164,7 @@ export default echarts.extendChartView({
circle.style.extendFrom(hoverStyle); circle.style.extendFrom(hoverStyle);
// Make label upper than others if overlaps. // Make label upper than others if overlaps.
circle.__mapOriginalZ2 = circle.z2; circle.__mapOriginalZ2 = circle.z2;
circle.z2 += 1; circle.z2 += graphic.Z2_EMPHASIS_LIFT;
}; };
var onNormal = function () { var onNormal = function () {
......
...@@ -279,7 +279,7 @@ MapDraw.prototype = { ...@@ -279,7 +279,7 @@ MapDraw.prototype = {
if ( if (
(isGeo || isDataNaN && (showLabel || hoverShowLabel)) (isGeo || isDataNaN && (showLabel || hoverShowLabel))
|| (itemLayout && itemLayout.showLabel) || (itemLayout && itemLayout.showLabel)
) { ) {
var query = !isGeo ? dataIdx : region.name; var query = !isGeo ? dataIdx : region.name;
var labelFetcher; var labelFetcher;
...@@ -290,6 +290,10 @@ MapDraw.prototype = { ...@@ -290,6 +290,10 @@ MapDraw.prototype = {
var textEl = new graphic.Text({ var textEl = new graphic.Text({
position: region.center.slice(), position: region.center.slice(),
// FIXME
// label rotation is not support yet in geo or regions of series-map
// that has no data. The rotation will be effected by this `scale`.
// So needed to change to RectText?
scale: [1 / scale[0], 1 / scale[1]], scale: [1 / scale[0], 1 / scale[1]],
z2: 10, z2: 10,
silent: true silent: true
......
...@@ -416,10 +416,10 @@ listProto.initData = function (data, nameList, dimValueGetter) { ...@@ -416,10 +416,10 @@ listProto.initData = function (data, nameList, dimValueGetter) {
this.defaultDimValueGetter = defaultDimValueGetters[ this.defaultDimValueGetter = defaultDimValueGetters[
this._rawData.getSource().sourceFormat this._rawData.getSource().sourceFormat
]; ];
// Default dim value getter // Default dim value getter
this._dimValueGetter = dimValueGetter = dimValueGetter this._dimValueGetter = dimValueGetter = dimValueGetter
|| this.defaultDimValueGetter; || this.defaultDimValueGetter;
this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;
// Reset raw extent. // Reset raw extent.
this._rawExtent = {}; this._rawExtent = {};
...@@ -436,6 +436,9 @@ listProto.getProvider = function () { ...@@ -436,6 +436,9 @@ listProto.getProvider = function () {
return this._rawData; return this._rawData;
}; };
/**
* Caution: Can be only called on raw data (before `this._indices` created).
*/
listProto.appendData = function (data) { listProto.appendData = function (data) {
if (__DEV__) { if (__DEV__) {
zrUtil.assert(!this._indices, 'appendData can only be called on raw data.'); zrUtil.assert(!this._indices, 'appendData can only be called on raw data.');
...@@ -451,6 +454,71 @@ listProto.appendData = function (data) { ...@@ -451,6 +454,71 @@ listProto.appendData = function (data) {
this._initDataFromProvider(start, end); this._initDataFromProvider(start, end);
}; };
/**
* Caution: Can be only called on raw data (before `this._indices` created).
* This method does not modify `rawData` (`dataProvider`), but only
* add values to storage.
*
* The final count will be increased by `Math.max(values.length, names.length)`.
*
* @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like
* [
* [12, 33, 44],
* [NaN, 43, 1],
* ['-', 'asdf', 0]
* ]
* Each item is exaclty cooresponding to a dimension.
* @param {Array.<string>} [names]
*/
listProto.appendValues = function (values, names) {
var chunkSize = this._chunkSize;
var storage = this._storage;
var dimensions = this.dimensions;
var dimLen = dimensions.length;
var rawExtent = this._rawExtent;
var start = this.count();
var end = start + Math.max(values.length, names ? names.length : 0);
var originalChunkCount = this._chunkCount;
for (var i = 0; i < dimLen; i++) {
var dim = dimensions[i];
prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);
this._chunkCount = storage[dim].length;
}
var emptyDataItem = new Array(dimLen);
for (var idx = start; idx < end; idx++) {
var sourceIdx = idx - start;
var chunkIndex = Math.floor(idx / chunkSize);
var chunkOffset = idx % chunkSize;
// Store the data by dimensions
for (var k = 0; k < dimLen; k++) {
var dim = dimensions[k];
var val = this._dimValueGetterArrayRows(
values[sourceIdx] || emptyDataItem, dim, sourceIdx, k
);
storage[dim][chunkIndex][chunkOffset] = val;
var dimRawExtent = rawExtent[dim];
val < dimRawExtent[0] && (dimRawExtent[0] = val);
val > dimRawExtent[1] && (dimRawExtent[1] = val);
}
if (names) {
this._nameList[idx] = names[sourceIdx];
}
}
this._rawCount = this._count = end;
// Reset data extent
this._extent = {};
prepareInvertedIndex(this);
};
listProto._initDataFromProvider = function (start, end) { listProto._initDataFromProvider = function (start, end) {
// Optimize. // Optimize.
if (start >= end) { if (start >= end) {
...@@ -469,8 +537,7 @@ listProto._initDataFromProvider = function (start, end) { ...@@ -469,8 +537,7 @@ listProto._initDataFromProvider = function (start, end) {
var nameRepeatCount = this._nameRepeatCount = {}; var nameRepeatCount = this._nameRepeatCount = {};
var nameDimIdx; var nameDimIdx;
var chunkCount = this._chunkCount; var originalChunkCount = this._chunkCount;
var lastChunkIndex = chunkCount - 1;
for (var i = 0; i < dimLen; i++) { for (var i = 0; i < dimLen; i++) {
var dim = dimensions[i]; var dim = dimensions[i];
if (!rawExtent[dim]) { if (!rawExtent[dim]) {
...@@ -484,26 +551,13 @@ listProto._initDataFromProvider = function (start, end) { ...@@ -484,26 +551,13 @@ listProto._initDataFromProvider = function (start, end) {
if (dimInfo.otherDims.itemId === 0) { if (dimInfo.otherDims.itemId === 0) {
this._idDimIdx = i; this._idDimIdx = i;
} }
var DataCtor = dataCtors[dimInfo.type];
if (!storage[dim]) { if (!storage[dim]) {
storage[dim] = []; storage[dim] = [];
} }
var resizeChunkArray = storage[dim][lastChunkIndex];
if (resizeChunkArray && resizeChunkArray.length < chunkSize) {
var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));
// The cost of the copy is probably inconsiderable
// within the initial chunkSize.
for (var j = 0; j < resizeChunkArray.length; j++) {
newStore[j] = resizeChunkArray[j];
}
storage[dim][lastChunkIndex] = newStore;
}
// Create new chunks. prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);
for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {
storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));
}
this._chunkCount = storage[dim].length; this._chunkCount = storage[dim].length;
} }
...@@ -529,12 +583,8 @@ listProto._initDataFromProvider = function (start, end) { ...@@ -529,12 +583,8 @@ listProto._initDataFromProvider = function (start, end) {
dimStorage[chunkOffset] = val; dimStorage[chunkOffset] = val;
var dimRawExtent = rawExtent[dim]; var dimRawExtent = rawExtent[dim];
if (val < dimRawExtent[0]) { val < dimRawExtent[0] && (dimRawExtent[0] = val);
dimRawExtent[0] = val; val > dimRawExtent[1] && (dimRawExtent[1] = val);
}
if (val > dimRawExtent[1]) {
dimRawExtent[1] = val;
}
} }
// ??? FIXME not check by pure but sourceFormat? // ??? FIXME not check by pure but sourceFormat?
...@@ -593,6 +643,27 @@ listProto._initDataFromProvider = function (start, end) { ...@@ -593,6 +643,27 @@ listProto._initDataFromProvider = function (start, end) {
prepareInvertedIndex(this); prepareInvertedIndex(this);
}; };
function prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {
var DataCtor = dataCtors[dimInfo.type];
var lastChunkIndex = chunkCount - 1;
var dim = dimInfo.name;
var resizeChunkArray = storage[dim][lastChunkIndex];
if (resizeChunkArray && resizeChunkArray.length < chunkSize) {
var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));
// The cost of the copy is probably inconsiderable
// within the initial chunkSize.
for (var j = 0; j < resizeChunkArray.length; j++) {
newStore[j] = resizeChunkArray[j];
}
storage[dim][lastChunkIndex] = newStore;
}
// Create new chunks.
for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {
storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));
}
}
function prepareInvertedIndex(list) { function prepareInvertedIndex(list) {
var invertedIndicesMap = list._invertedIndicesMap; var invertedIndicesMap = list._invertedIndicesMap;
zrUtil.each(invertedIndicesMap, function (invertedIndices, dim) { zrUtil.each(invertedIndicesMap, function (invertedIndices, dim) {
......
...@@ -37,7 +37,7 @@ var inner = makeInner(); ...@@ -37,7 +37,7 @@ var inner = makeInner();
/** /**
* @alias module:echarts/model/Model * @alias module:echarts/model/Model
* @constructor * @constructor
* @param {Object} option * @param {Object} [option]
* @param {module:echarts/model/Model} [parentModel] * @param {module:echarts/model/Model} [parentModel]
* @param {module:echarts/model/Global} [ecModel] * @param {module:echarts/model/Global} [ecModel]
*/ */
......
...@@ -48,7 +48,8 @@ var mathMax = Math.max; ...@@ -48,7 +48,8 @@ var mathMax = Math.max;
var mathMin = Math.min; var mathMin = Math.min;
var EMPTY_OBJ = {}; var EMPTY_OBJ = {};
var Z2_LIFT_VALUE = 1;
export var Z2_EMPHASIS_LIFT = 1;
/** /**
* Extend shape with parameters * Extend shape with parameters
...@@ -344,7 +345,7 @@ function doSingleEnterHover(el) { ...@@ -344,7 +345,7 @@ function doSingleEnterHover(el) {
if (!useHoverLayer) { if (!useHoverLayer) {
el.dirty(false); el.dirty(false);
el.z2 += Z2_LIFT_VALUE; el.z2 += Z2_EMPHASIS_LIFT;
} }
} }
...@@ -381,7 +382,7 @@ function doSingleLeaveHover(el) { ...@@ -381,7 +382,7 @@ function doSingleLeaveHover(el) {
// when `el` is on emphasis state. So here by comparing with 1, we try // when `el` is on emphasis state. So here by comparing with 1, we try
// hard to make the bug case rare. // hard to make the bug case rare.
var normalZ2 = el.__cachedNormalZ2; var normalZ2 = el.__cachedNormalZ2;
if (normalZ2 != null && el.z2 - normalZ2 === Z2_LIFT_VALUE) { if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {
el.z2 = normalZ2; el.z2 = normalZ2;
} }
} }
......
...@@ -26,25 +26,25 @@ under the License. ...@@ -26,25 +26,25 @@ under the License.
<script src="lib/config.js"></script> <script src="lib/config.js"></script>
<script src="lib/jquery.min.js"></script> <script src="lib/jquery.min.js"></script>
<script src="lib/facePrint.js"></script> <script src="lib/facePrint.js"></script>
<script src="lib/testHelper.js"></script>
<!-- <script src="ut/lib/canteen.js"></script> -->
<link rel="stylesheet" href="lib/reset.css" />
</head> </head>
<body> <body>
<style>
html, body, #main {
width: 100%;
height: 100%;
margin: 0;
}
</style>
<div id="main"></div>
<script>
<!-- <div id="main0"></div> -->
<div id="main1"></div>
<script>
require([ require([
'echarts' 'echarts'
], function (echarts) { ], function (echarts) {
require(['map/js/china'], function () { require(['map/js/china'], function () {
var chart = echarts.init(document.getElementById('main'));
var itemStyle = { var itemStyle = {
normal:{ normal:{
borderColor: 'rgba(0, 0, 0, 0.2)' borderColor: 'rgba(0, 0, 0, 0.2)'
...@@ -58,7 +58,7 @@ under the License. ...@@ -58,7 +58,7 @@ under the License.
} }
}; };
chart.setOption({ var option = {
tooltip: {}, tooltip: {},
title : { title : {
text: '内蒙古和青海没数据也要能被选中', text: '内蒙古和青海没数据也要能被选中',
...@@ -75,7 +75,7 @@ under the License. ...@@ -75,7 +75,7 @@ under the License.
max: 1500, max: 1500,
left: 'left', left: 'left',
top: 'bottom', top: 'bottom',
text:['',''], // 文本,默认为数值文本 text: ['',''],
calculable : true calculable : true
}, },
selectedMode: 'single', selectedMode: 'single',
...@@ -218,21 +218,160 @@ under the License. ...@@ -218,21 +218,160 @@ under the License.
] ]
} }
] ]
};
var chart = testHelper.create(echarts, 'main0', {
option: option,
height: 550
}); });
chart.on('click', function (param) { if (chart) {
chart.on('click', function (param) {
console.log(param);
});
}
});
});
</script>
<script>
require([
'echarts'
], function (echarts) {
require(['map/js/china'], function () {
var itemStyle = {
normal:{
borderColor: 'rgba(0, 0, 0, 0.2)'
},
emphasis:{
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
};
var option = {
tooltip: {},
legend: {
orient: 'vertical',
left: 'left',
data:['iphone3','iphone4','iphone5']
},
visualMap: {
min: 0,
max: 1500,
left: 'left',
top: 'bottom',
text:['',''],
calculable : true
},
selectedMode: 'multiple',
series: [
{
name: 'iphone3',
type: 'map',
map: 'china',
itemStyle: itemStyle,
showLegendSymbol: true,
// zoom: 10,
// center: [115.97, 29.71],
roam: true,
label: {
show: true,
rotate: 40,
formatter: '{b}:{value|{c}}',
backgroundColor: '#fff',
padding: [3, 5],
borderRadius: 3,
borderWidth: 1,
borderColor: 'rgba(0,0,0,0.5)',
color: '#934',
rich: {
value: {
color: '#019D2D',
fontSize: 14
}
}
},
emphasis: {
label: {show: true}
},
data:[
{name: '北京',value: 234},
{name: '天津',value: 432}
]
},
{
name: 'iphone4',
type: 'map',
mapType: 'china',
itemStyle: itemStyle,
showLegendSymbol: true,
label: {
show: true,
rotate: 90,
formatter: '{b}:{value|{c}}',
backgroundColor: '#fff',
padding: [3, 5],
borderRadius: 3,
borderWidth: 1,
borderColor: 'rgba(0,0,0,0.5)',
color: '#934',
rich: {
value: {
color: '#019D2D',
fontSize: 14
}
}
},
emphasis: {
label: {show: true}
},
data:[
{name: '北京',value: 567},
{name: '河北',value: 321}
]
}
]
};
var chart = testHelper.create(echarts, 'main1', {
option: option,
// recordCanvas: true,
title: [
'1. 北京、天津、河北 rich text 正常倾斜(河北竖直)(其他 region 都没数据,显示 NaN)',
'2. selectedMode: "multiple"',
'所有 label 样式一致(例外:没数据的 label 并不 rotate,因为这还没支持)'
]
});
chart && chart.on('click', function (param) {
console.log(param); console.log(param);
}); });
// setTimeout(function () {
// chart.setOption({
// series: [{
// zoom: 5
// }]
// });
// }, 2000);
}); });
}); });
</script> </script>
</body> </body>
</html> </html>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册