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