281 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
 | |
| /*
 | |
| * 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.
 | |
| */
 | |
| 
 | |
| var _config = require("../../config");
 | |
| 
 | |
| var __DEV__ = _config.__DEV__;
 | |
| 
 | |
| var echarts = require("../../echarts");
 | |
| 
 | |
| var graphic = require("../../util/graphic");
 | |
| 
 | |
| var HeatmapLayer = require("./HeatmapLayer");
 | |
| 
 | |
| var zrUtil = require("zrender/lib/core/util");
 | |
| 
 | |
| /*
 | |
| * 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.
 | |
| */
 | |
| function getIsInPiecewiseRange(dataExtent, pieceList, selected) {
 | |
|   var dataSpan = dataExtent[1] - dataExtent[0];
 | |
|   pieceList = zrUtil.map(pieceList, function (piece) {
 | |
|     return {
 | |
|       interval: [(piece.interval[0] - dataExtent[0]) / dataSpan, (piece.interval[1] - dataExtent[0]) / dataSpan]
 | |
|     };
 | |
|   });
 | |
|   var len = pieceList.length;
 | |
|   var lastIndex = 0;
 | |
|   return function (val) {
 | |
|     // Try to find in the location of the last found
 | |
|     for (var i = lastIndex; i < len; i++) {
 | |
|       var interval = pieceList[i].interval;
 | |
| 
 | |
|       if (interval[0] <= val && val <= interval[1]) {
 | |
|         lastIndex = i;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (i === len) {
 | |
|       // Not found, back interation
 | |
|       for (var i = lastIndex - 1; i >= 0; i--) {
 | |
|         var interval = pieceList[i].interval;
 | |
| 
 | |
|         if (interval[0] <= val && val <= interval[1]) {
 | |
|           lastIndex = i;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return i >= 0 && i < len && selected[i];
 | |
|   };
 | |
| }
 | |
| 
 | |
| function getIsInContinuousRange(dataExtent, range) {
 | |
|   var dataSpan = dataExtent[1] - dataExtent[0];
 | |
|   range = [(range[0] - dataExtent[0]) / dataSpan, (range[1] - dataExtent[0]) / dataSpan];
 | |
|   return function (val) {
 | |
|     return val >= range[0] && val <= range[1];
 | |
|   };
 | |
| }
 | |
| 
 | |
| function isGeoCoordSys(coordSys) {
 | |
|   var dimensions = coordSys.dimensions; // Not use coorSys.type === 'geo' because coordSys maybe extended
 | |
| 
 | |
|   return dimensions[0] === 'lng' && dimensions[1] === 'lat';
 | |
| }
 | |
| 
 | |
| var _default = echarts.extendChartView({
 | |
|   type: 'heatmap',
 | |
|   render: function (seriesModel, ecModel, api) {
 | |
|     var visualMapOfThisSeries;
 | |
|     ecModel.eachComponent('visualMap', function (visualMap) {
 | |
|       visualMap.eachTargetSeries(function (targetSeries) {
 | |
|         if (targetSeries === seriesModel) {
 | |
|           visualMapOfThisSeries = visualMap;
 | |
|         }
 | |
|       });
 | |
|     });
 | |
|     this.group.removeAll();
 | |
|     this._incrementalDisplayable = null;
 | |
|     var coordSys = seriesModel.coordinateSystem;
 | |
| 
 | |
|     if (coordSys.type === 'cartesian2d' || coordSys.type === 'calendar') {
 | |
|       this._renderOnCartesianAndCalendar(seriesModel, api, 0, seriesModel.getData().count());
 | |
|     } else if (isGeoCoordSys(coordSys)) {
 | |
|       this._renderOnGeo(coordSys, seriesModel, visualMapOfThisSeries, api);
 | |
|     }
 | |
|   },
 | |
|   incrementalPrepareRender: function (seriesModel, ecModel, api) {
 | |
|     this.group.removeAll();
 | |
|   },
 | |
|   incrementalRender: function (params, seriesModel, ecModel, api) {
 | |
|     var coordSys = seriesModel.coordinateSystem;
 | |
| 
 | |
|     if (coordSys) {
 | |
|       this._renderOnCartesianAndCalendar(seriesModel, api, params.start, params.end, true);
 | |
|     }
 | |
|   },
 | |
|   _renderOnCartesianAndCalendar: function (seriesModel, api, start, end, incremental) {
 | |
|     var coordSys = seriesModel.coordinateSystem;
 | |
|     var width;
 | |
|     var height;
 | |
| 
 | |
|     if (coordSys.type === 'cartesian2d') {
 | |
|       var xAxis = coordSys.getAxis('x');
 | |
|       var yAxis = coordSys.getAxis('y');
 | |
|       width = xAxis.getBandWidth();
 | |
|       height = yAxis.getBandWidth();
 | |
|     }
 | |
| 
 | |
|     var group = this.group;
 | |
|     var data = seriesModel.getData();
 | |
|     var itemStyleQuery = 'itemStyle';
 | |
|     var hoverItemStyleQuery = 'emphasis.itemStyle';
 | |
|     var labelQuery = 'label';
 | |
|     var hoverLabelQuery = 'emphasis.label';
 | |
|     var style = seriesModel.getModel(itemStyleQuery).getItemStyle(['color']);
 | |
|     var hoverStl = seriesModel.getModel(hoverItemStyleQuery).getItemStyle();
 | |
|     var labelModel = seriesModel.getModel(labelQuery);
 | |
|     var hoverLabelModel = seriesModel.getModel(hoverLabelQuery);
 | |
|     var coordSysType = coordSys.type;
 | |
|     var dataDims = coordSysType === 'cartesian2d' ? [data.mapDimension('x'), data.mapDimension('y'), data.mapDimension('value')] : [data.mapDimension('time'), data.mapDimension('value')];
 | |
| 
 | |
|     for (var idx = start; idx < end; idx++) {
 | |
|       var rect;
 | |
| 
 | |
|       if (coordSysType === 'cartesian2d') {
 | |
|         // Ignore empty data
 | |
|         if (isNaN(data.get(dataDims[2], idx))) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         var point = coordSys.dataToPoint([data.get(dataDims[0], idx), data.get(dataDims[1], idx)]);
 | |
|         rect = new graphic.Rect({
 | |
|           shape: {
 | |
|             x: Math.floor(Math.round(point[0]) - width / 2),
 | |
|             y: Math.floor(Math.round(point[1]) - height / 2),
 | |
|             width: Math.ceil(width),
 | |
|             height: Math.ceil(height)
 | |
|           },
 | |
|           style: {
 | |
|             fill: data.getItemVisual(idx, 'color'),
 | |
|             opacity: data.getItemVisual(idx, 'opacity')
 | |
|           }
 | |
|         });
 | |
|       } else {
 | |
|         // Ignore empty data
 | |
|         if (isNaN(data.get(dataDims[1], idx))) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         rect = new graphic.Rect({
 | |
|           z2: 1,
 | |
|           shape: coordSys.dataToRect([data.get(dataDims[0], idx)]).contentShape,
 | |
|           style: {
 | |
|             fill: data.getItemVisual(idx, 'color'),
 | |
|             opacity: data.getItemVisual(idx, 'opacity')
 | |
|           }
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       var itemModel = data.getItemModel(idx); // Optimization for large datset
 | |
| 
 | |
|       if (data.hasItemOption) {
 | |
|         style = itemModel.getModel(itemStyleQuery).getItemStyle(['color']);
 | |
|         hoverStl = itemModel.getModel(hoverItemStyleQuery).getItemStyle();
 | |
|         labelModel = itemModel.getModel(labelQuery);
 | |
|         hoverLabelModel = itemModel.getModel(hoverLabelQuery);
 | |
|       }
 | |
| 
 | |
|       var rawValue = seriesModel.getRawValue(idx);
 | |
|       var defaultText = '-';
 | |
| 
 | |
|       if (rawValue && rawValue[2] != null) {
 | |
|         defaultText = rawValue[2];
 | |
|       }
 | |
| 
 | |
|       graphic.setLabelStyle(style, hoverStl, labelModel, hoverLabelModel, {
 | |
|         labelFetcher: seriesModel,
 | |
|         labelDataIndex: idx,
 | |
|         defaultText: defaultText,
 | |
|         isRectText: true
 | |
|       });
 | |
|       rect.setStyle(style);
 | |
|       graphic.setHoverStyle(rect, data.hasItemOption ? hoverStl : zrUtil.extend({}, hoverStl));
 | |
|       rect.incremental = incremental; // PENDING
 | |
| 
 | |
|       if (incremental) {
 | |
|         // Rect must use hover layer if it's incremental.
 | |
|         rect.useHoverLayer = true;
 | |
|       }
 | |
| 
 | |
|       group.add(rect);
 | |
|       data.setItemGraphicEl(idx, rect);
 | |
|     }
 | |
|   },
 | |
|   _renderOnGeo: function (geo, seriesModel, visualMapModel, api) {
 | |
|     var inRangeVisuals = visualMapModel.targetVisuals.inRange;
 | |
|     var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange; // if (!visualMapping) {
 | |
|     //     throw new Error('Data range must have color visuals');
 | |
|     // }
 | |
| 
 | |
|     var data = seriesModel.getData();
 | |
|     var hmLayer = this._hmLayer || this._hmLayer || new HeatmapLayer();
 | |
|     hmLayer.blurSize = seriesModel.get('blurSize');
 | |
|     hmLayer.pointSize = seriesModel.get('pointSize');
 | |
|     hmLayer.minOpacity = seriesModel.get('minOpacity');
 | |
|     hmLayer.maxOpacity = seriesModel.get('maxOpacity');
 | |
|     var rect = geo.getViewRect().clone();
 | |
|     var roamTransform = geo.getRoamTransform();
 | |
|     rect.applyTransform(roamTransform); // Clamp on viewport
 | |
| 
 | |
|     var x = Math.max(rect.x, 0);
 | |
|     var y = Math.max(rect.y, 0);
 | |
|     var x2 = Math.min(rect.width + rect.x, api.getWidth());
 | |
|     var y2 = Math.min(rect.height + rect.y, api.getHeight());
 | |
|     var width = x2 - x;
 | |
|     var height = y2 - y;
 | |
|     var dims = [data.mapDimension('lng'), data.mapDimension('lat'), data.mapDimension('value')];
 | |
|     var points = data.mapArray(dims, function (lng, lat, value) {
 | |
|       var pt = geo.dataToPoint([lng, lat]);
 | |
|       pt[0] -= x;
 | |
|       pt[1] -= y;
 | |
|       pt.push(value);
 | |
|       return pt;
 | |
|     });
 | |
|     var dataExtent = visualMapModel.getExtent();
 | |
|     var isInRange = visualMapModel.type === 'visualMap.continuous' ? getIsInContinuousRange(dataExtent, visualMapModel.option.range) : getIsInPiecewiseRange(dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected);
 | |
|     hmLayer.update(points, width, height, inRangeVisuals.color.getNormalizer(), {
 | |
|       inRange: inRangeVisuals.color.getColorMapper(),
 | |
|       outOfRange: outOfRangeVisuals.color.getColorMapper()
 | |
|     }, isInRange);
 | |
|     var img = new graphic.Image({
 | |
|       style: {
 | |
|         width: width,
 | |
|         height: height,
 | |
|         x: x,
 | |
|         y: y,
 | |
|         image: hmLayer.canvas
 | |
|       },
 | |
|       silent: true
 | |
|     });
 | |
|     this.group.add(img);
 | |
|   },
 | |
|   dispose: function () {}
 | |
| });
 | |
| 
 | |
| module.exports = _default; | 
