309 lines
10 KiB
JavaScript
309 lines
10 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.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* 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 { __extends } from "tslib";
|
||
|
/* global Float32Array */
|
||
|
// TODO Batch by color
|
||
|
import * as graphic from '../../util/graphic.js';
|
||
|
import { createSymbol } from '../../util/symbol.js';
|
||
|
import { getECData } from '../../util/innerStore.js';
|
||
|
var BOOST_SIZE_THRESHOLD = 4;
|
||
|
var LargeSymbolPathShape = /** @class */function () {
|
||
|
function LargeSymbolPathShape() {}
|
||
|
return LargeSymbolPathShape;
|
||
|
}();
|
||
|
var LargeSymbolPath = /** @class */function (_super) {
|
||
|
__extends(LargeSymbolPath, _super);
|
||
|
function LargeSymbolPath(opts) {
|
||
|
var _this = _super.call(this, opts) || this;
|
||
|
_this._off = 0;
|
||
|
_this.hoverDataIdx = -1;
|
||
|
return _this;
|
||
|
}
|
||
|
LargeSymbolPath.prototype.getDefaultShape = function () {
|
||
|
return new LargeSymbolPathShape();
|
||
|
};
|
||
|
LargeSymbolPath.prototype.reset = function () {
|
||
|
this.notClear = false;
|
||
|
this._off = 0;
|
||
|
};
|
||
|
LargeSymbolPath.prototype.buildPath = function (path, shape) {
|
||
|
var points = shape.points;
|
||
|
var size = shape.size;
|
||
|
var symbolProxy = this.symbolProxy;
|
||
|
var symbolProxyShape = symbolProxy.shape;
|
||
|
var ctx = path.getContext ? path.getContext() : path;
|
||
|
var canBoost = ctx && size[0] < BOOST_SIZE_THRESHOLD;
|
||
|
var softClipShape = this.softClipShape;
|
||
|
var i;
|
||
|
// Do draw in afterBrush.
|
||
|
if (canBoost) {
|
||
|
this._ctx = ctx;
|
||
|
return;
|
||
|
}
|
||
|
this._ctx = null;
|
||
|
for (i = this._off; i < points.length;) {
|
||
|
var x = points[i++];
|
||
|
var y = points[i++];
|
||
|
if (isNaN(x) || isNaN(y)) {
|
||
|
continue;
|
||
|
}
|
||
|
if (softClipShape && !softClipShape.contain(x, y)) {
|
||
|
continue;
|
||
|
}
|
||
|
symbolProxyShape.x = x - size[0] / 2;
|
||
|
symbolProxyShape.y = y - size[1] / 2;
|
||
|
symbolProxyShape.width = size[0];
|
||
|
symbolProxyShape.height = size[1];
|
||
|
symbolProxy.buildPath(path, symbolProxyShape, true);
|
||
|
}
|
||
|
if (this.incremental) {
|
||
|
this._off = i;
|
||
|
this.notClear = true;
|
||
|
}
|
||
|
};
|
||
|
LargeSymbolPath.prototype.afterBrush = function () {
|
||
|
var shape = this.shape;
|
||
|
var points = shape.points;
|
||
|
var size = shape.size;
|
||
|
var ctx = this._ctx;
|
||
|
var softClipShape = this.softClipShape;
|
||
|
var i;
|
||
|
if (!ctx) {
|
||
|
return;
|
||
|
}
|
||
|
// PENDING If style or other canvas status changed?
|
||
|
for (i = this._off; i < points.length;) {
|
||
|
var x = points[i++];
|
||
|
var y = points[i++];
|
||
|
if (isNaN(x) || isNaN(y)) {
|
||
|
continue;
|
||
|
}
|
||
|
if (softClipShape && !softClipShape.contain(x, y)) {
|
||
|
continue;
|
||
|
}
|
||
|
// fillRect is faster than building a rect path and draw.
|
||
|
// And it support light globalCompositeOperation.
|
||
|
ctx.fillRect(x - size[0] / 2, y - size[1] / 2, size[0], size[1]);
|
||
|
}
|
||
|
if (this.incremental) {
|
||
|
this._off = i;
|
||
|
this.notClear = true;
|
||
|
}
|
||
|
};
|
||
|
LargeSymbolPath.prototype.findDataIndex = function (x, y) {
|
||
|
// TODO ???
|
||
|
// Consider transform
|
||
|
var shape = this.shape;
|
||
|
var points = shape.points;
|
||
|
var size = shape.size;
|
||
|
var w = Math.max(size[0], 4);
|
||
|
var h = Math.max(size[1], 4);
|
||
|
// Not consider transform
|
||
|
// Treat each element as a rect
|
||
|
// top down traverse
|
||
|
for (var idx = points.length / 2 - 1; idx >= 0; idx--) {
|
||
|
var i = idx * 2;
|
||
|
var x0 = points[i] - w / 2;
|
||
|
var y0 = points[i + 1] - h / 2;
|
||
|
if (x >= x0 && y >= y0 && x <= x0 + w && y <= y0 + h) {
|
||
|
return idx;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
};
|
||
|
LargeSymbolPath.prototype.contain = function (x, y) {
|
||
|
var localPos = this.transformCoordToLocal(x, y);
|
||
|
var rect = this.getBoundingRect();
|
||
|
x = localPos[0];
|
||
|
y = localPos[1];
|
||
|
if (rect.contain(x, y)) {
|
||
|
// Cache found data index.
|
||
|
var dataIdx = this.hoverDataIdx = this.findDataIndex(x, y);
|
||
|
return dataIdx >= 0;
|
||
|
}
|
||
|
this.hoverDataIdx = -1;
|
||
|
return false;
|
||
|
};
|
||
|
LargeSymbolPath.prototype.getBoundingRect = function () {
|
||
|
// Ignore stroke for large symbol draw.
|
||
|
var rect = this._rect;
|
||
|
if (!rect) {
|
||
|
var shape = this.shape;
|
||
|
var points = shape.points;
|
||
|
var size = shape.size;
|
||
|
var w = size[0];
|
||
|
var h = size[1];
|
||
|
var minX = Infinity;
|
||
|
var minY = Infinity;
|
||
|
var maxX = -Infinity;
|
||
|
var maxY = -Infinity;
|
||
|
for (var i = 0; i < points.length;) {
|
||
|
var x = points[i++];
|
||
|
var y = points[i++];
|
||
|
minX = Math.min(x, minX);
|
||
|
maxX = Math.max(x, maxX);
|
||
|
minY = Math.min(y, minY);
|
||
|
maxY = Math.max(y, maxY);
|
||
|
}
|
||
|
rect = this._rect = new graphic.BoundingRect(minX - w / 2, minY - h / 2, maxX - minX + w, maxY - minY + h);
|
||
|
}
|
||
|
return rect;
|
||
|
};
|
||
|
return LargeSymbolPath;
|
||
|
}(graphic.Path);
|
||
|
var LargeSymbolDraw = /** @class */function () {
|
||
|
function LargeSymbolDraw() {
|
||
|
this.group = new graphic.Group();
|
||
|
}
|
||
|
/**
|
||
|
* Update symbols draw by new data
|
||
|
*/
|
||
|
LargeSymbolDraw.prototype.updateData = function (data, opt) {
|
||
|
this._clear();
|
||
|
var symbolEl = this._create();
|
||
|
symbolEl.setShape({
|
||
|
points: data.getLayout('points')
|
||
|
});
|
||
|
this._setCommon(symbolEl, data, opt);
|
||
|
};
|
||
|
LargeSymbolDraw.prototype.updateLayout = function (data) {
|
||
|
var points = data.getLayout('points');
|
||
|
this.group.eachChild(function (child) {
|
||
|
if (child.startIndex != null) {
|
||
|
var len = (child.endIndex - child.startIndex) * 2;
|
||
|
var byteOffset = child.startIndex * 4 * 2;
|
||
|
points = new Float32Array(points.buffer, byteOffset, len);
|
||
|
}
|
||
|
child.setShape('points', points);
|
||
|
// Reset draw cursor.
|
||
|
child.reset();
|
||
|
});
|
||
|
};
|
||
|
LargeSymbolDraw.prototype.incrementalPrepareUpdate = function (data) {
|
||
|
this._clear();
|
||
|
};
|
||
|
LargeSymbolDraw.prototype.incrementalUpdate = function (taskParams, data, opt) {
|
||
|
var lastAdded = this._newAdded[0];
|
||
|
var points = data.getLayout('points');
|
||
|
var oldPoints = lastAdded && lastAdded.shape.points;
|
||
|
// Merging the exists. Each element has 1e4 points.
|
||
|
// Consider the performance balance between too much elements and too much points in one shape(may affect hover optimization)
|
||
|
if (oldPoints && oldPoints.length < 2e4) {
|
||
|
var oldLen = oldPoints.length;
|
||
|
var newPoints = new Float32Array(oldLen + points.length);
|
||
|
// Concat two array
|
||
|
newPoints.set(oldPoints);
|
||
|
newPoints.set(points, oldLen);
|
||
|
// Update endIndex
|
||
|
lastAdded.endIndex = taskParams.end;
|
||
|
lastAdded.setShape({
|
||
|
points: newPoints
|
||
|
});
|
||
|
} else {
|
||
|
// Clear
|
||
|
this._newAdded = [];
|
||
|
var symbolEl = this._create();
|
||
|
symbolEl.startIndex = taskParams.start;
|
||
|
symbolEl.endIndex = taskParams.end;
|
||
|
symbolEl.incremental = true;
|
||
|
symbolEl.setShape({
|
||
|
points: points
|
||
|
});
|
||
|
this._setCommon(symbolEl, data, opt);
|
||
|
}
|
||
|
};
|
||
|
LargeSymbolDraw.prototype.eachRendered = function (cb) {
|
||
|
this._newAdded[0] && cb(this._newAdded[0]);
|
||
|
};
|
||
|
LargeSymbolDraw.prototype._create = function () {
|
||
|
var symbolEl = new LargeSymbolPath({
|
||
|
cursor: 'default'
|
||
|
});
|
||
|
symbolEl.ignoreCoarsePointer = true;
|
||
|
this.group.add(symbolEl);
|
||
|
this._newAdded.push(symbolEl);
|
||
|
return symbolEl;
|
||
|
};
|
||
|
LargeSymbolDraw.prototype._setCommon = function (symbolEl, data, opt) {
|
||
|
var hostModel = data.hostModel;
|
||
|
opt = opt || {};
|
||
|
var size = data.getVisual('symbolSize');
|
||
|
symbolEl.setShape('size', size instanceof Array ? size : [size, size]);
|
||
|
symbolEl.softClipShape = opt.clipShape || null;
|
||
|
// Create symbolProxy to build path for each data
|
||
|
symbolEl.symbolProxy = createSymbol(data.getVisual('symbol'), 0, 0, 0, 0);
|
||
|
// Use symbolProxy setColor method
|
||
|
symbolEl.setColor = symbolEl.symbolProxy.setColor;
|
||
|
var extrudeShadow = symbolEl.shape.size[0] < BOOST_SIZE_THRESHOLD;
|
||
|
symbolEl.useStyle(
|
||
|
// Draw shadow when doing fillRect is extremely slow.
|
||
|
hostModel.getModel('itemStyle').getItemStyle(extrudeShadow ? ['color', 'shadowBlur', 'shadowColor'] : ['color']));
|
||
|
var globalStyle = data.getVisual('style');
|
||
|
var visualColor = globalStyle && globalStyle.fill;
|
||
|
if (visualColor) {
|
||
|
symbolEl.setColor(visualColor);
|
||
|
}
|
||
|
var ecData = getECData(symbolEl);
|
||
|
// Enable tooltip
|
||
|
// PENDING May have performance issue when path is extremely large
|
||
|
ecData.seriesIndex = hostModel.seriesIndex;
|
||
|
symbolEl.on('mousemove', function (e) {
|
||
|
ecData.dataIndex = null;
|
||
|
var dataIndex = symbolEl.hoverDataIdx;
|
||
|
if (dataIndex >= 0) {
|
||
|
// Provide dataIndex for tooltip
|
||
|
ecData.dataIndex = dataIndex + (symbolEl.startIndex || 0);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
LargeSymbolDraw.prototype.remove = function () {
|
||
|
this._clear();
|
||
|
};
|
||
|
LargeSymbolDraw.prototype._clear = function () {
|
||
|
this._newAdded = [];
|
||
|
this.group.removeAll();
|
||
|
};
|
||
|
return LargeSymbolDraw;
|
||
|
}();
|
||
|
export default LargeSymbolDraw;
|