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; |