| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| import * as echarts from '../../echarts'; |
| import * as zrUtil from 'zrender/src/core/util'; |
| import * as graphic from '../../util/graphic'; |
| import MapDraw from '../../component/helper/MapDraw'; |
| var HIGH_DOWN_PROP = '__seriesMapHighDown'; |
| var RECORD_VERSION_PROP = '__seriesMapCallKey'; |
| export default echarts.extendChartView({ |
| type: 'map', |
| render: function (mapModel, ecModel, api, payload) { |
| // Not render if it is an toggleSelect action from self |
| if (payload && payload.type === 'mapToggleSelect' && payload.from === this.uid) { |
| return; |
| } |
| |
| var group = this.group; |
| group.removeAll(); |
| |
| if (mapModel.getHostGeoModel()) { |
| return; |
| } // Not update map if it is an roam action from self |
| |
| |
| if (!(payload && payload.type === 'geoRoam' && payload.componentType === 'series' && payload.seriesId === mapModel.id)) { |
| if (mapModel.needsDrawMap) { |
| var mapDraw = this._mapDraw || new MapDraw(api, true); |
| group.add(mapDraw.group); |
| mapDraw.draw(mapModel, ecModel, api, this, payload); |
| this._mapDraw = mapDraw; |
| } else { |
| // Remove drawed map |
| this._mapDraw && this._mapDraw.remove(); |
| this._mapDraw = null; |
| } |
| } else { |
| var mapDraw = this._mapDraw; |
| mapDraw && group.add(mapDraw.group); |
| } |
| |
| mapModel.get('showLegendSymbol') && ecModel.getComponent('legend') && this._renderSymbols(mapModel, ecModel, api); |
| }, |
| remove: function () { |
| this._mapDraw && this._mapDraw.remove(); |
| this._mapDraw = null; |
| this.group.removeAll(); |
| }, |
| dispose: function () { |
| this._mapDraw && this._mapDraw.remove(); |
| this._mapDraw = null; |
| }, |
| _renderSymbols: function (mapModel, ecModel, api) { |
| var originalData = mapModel.originalData; |
| var group = this.group; |
| originalData.each(originalData.mapDimension('value'), function (value, originalDataIndex) { |
| if (isNaN(value)) { |
| return; |
| } |
| |
| var layout = originalData.getItemLayout(originalDataIndex); |
| |
| if (!layout || !layout.point) { |
| // Not exists in map |
| return; |
| } |
| |
| var point = layout.point; |
| var offset = layout.offset; |
| var circle = new graphic.Circle({ |
| style: { |
| // Because the special of map draw. |
| // Which needs statistic of multiple series and draw on one map. |
| // And each series also need a symbol with legend color |
| // |
| // Layout and visual are put one the different data |
| fill: mapModel.getData().getVisual('color') |
| }, |
| shape: { |
| cx: point[0] + offset * 9, |
| cy: point[1], |
| r: 3 |
| }, |
| silent: true, |
| // Do not overlap the first series, on which labels are displayed. |
| z2: 8 + (!offset ? graphic.Z2_EMPHASIS_LIFT + 1 : 0) |
| }); // 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) { |
| var fullData = mapModel.mainSeries.getData(); |
| var name = originalData.getName(originalDataIndex); |
| var fullIndex = fullData.indexOfName(name); |
| var itemModel = originalData.getItemModel(originalDataIndex); |
| var labelModel = itemModel.getModel('label'); |
| var hoverLabelModel = itemModel.getModel('emphasis.label'); |
| var regionGroup = 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(mapModel.getFormattedLabel(fullIndex, 'normal'), name); |
| var emphasisText = zrUtil.retrieve2(mapModel.getFormattedLabel(fullIndex, 'emphasis'), normalText); |
| var highDownRecord = regionGroup[HIGH_DOWN_PROP]; |
| var recordVersion = Math.random(); // Prevent from register listeners duplicatedly when roaming. |
| |
| if (!highDownRecord) { |
| highDownRecord = regionGroup[HIGH_DOWN_PROP] = {}; |
| var onEmphasis = zrUtil.curry(onRegionHighDown, true); |
| var onNormal = zrUtil.curry(onRegionHighDown, false); |
| regionGroup.on('mouseover', onEmphasis).on('mouseout', onNormal).on('emphasis', onEmphasis).on('normal', onNormal); |
| } // Prevent removed regions effect current grapics. |
| |
| |
| regionGroup[RECORD_VERSION_PROP] = recordVersion; |
| zrUtil.extend(highDownRecord, { |
| recordVersion: recordVersion, |
| circle: circle, |
| labelModel: labelModel, |
| hoverLabelModel: hoverLabelModel, |
| emphasisText: emphasisText, |
| normalText: normalText |
| }); // FIXME |
| // Consider set option when emphasis. |
| |
| enterRegionHighDown(highDownRecord, false); |
| } |
| |
| group.add(circle); |
| }); |
| } |
| }); |
| |
| function onRegionHighDown(toHighOrDown) { |
| var highDownRecord = this[HIGH_DOWN_PROP]; |
| |
| if (highDownRecord && highDownRecord.recordVersion === this[RECORD_VERSION_PROP]) { |
| enterRegionHighDown(highDownRecord, toHighOrDown); |
| } |
| } |
| |
| function enterRegionHighDown(highDownRecord, toHighOrDown) { |
| var circle = highDownRecord.circle; |
| var labelModel = highDownRecord.labelModel; |
| var hoverLabelModel = highDownRecord.hoverLabelModel; |
| var emphasisText = highDownRecord.emphasisText; |
| var normalText = highDownRecord.normalText; |
| |
| if (toHighOrDown) { |
| circle.style.extendFrom(graphic.setTextStyle({}, hoverLabelModel, { |
| text: hoverLabelModel.get('show') ? emphasisText : null |
| }, { |
| isRectText: true, |
| useInsideStyle: false |
| }, true)); // Make label upper than others if overlaps. |
| |
| circle.__mapOriginalZ2 = circle.z2; |
| circle.z2 += graphic.Z2_EMPHASIS_LIFT; |
| } else { |
| graphic.setTextStyle(circle.style, labelModel, { |
| text: labelModel.get('show') ? normalText : null, |
| textPosition: labelModel.getShallow('position') || 'bottom' |
| }, { |
| isRectText: true, |
| useInsideStyle: false |
| }); // Trigger normalize style like padding. |
| |
| circle.dirty(false); |
| |
| if (circle.__mapOriginalZ2 != null) { |
| circle.z2 = circle.__mapOriginalZ2; |
| circle.__mapOriginalZ2 = null; |
| } |
| } |
| } |