UNPKG

cione-comp-lib

Version:

`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`

421 lines (420 loc) 15.6 kB
import "../../../../echarts/lib/echarts.mjs"; import graphicGL from "../../util/graphicGL.mjs"; import spriteUtil from "../../util/sprite.mjs"; import PointsMesh from "./PointsMesh.mjs"; import LabelsBuilder from "../../component/common/LabelsBuilder.mjs"; import Matrix4 from "../../../../claygl/src/math/Matrix4.mjs"; import retrieve from "../../util/retrieve.mjs"; import { getVisualColor, getVisualOpacity, getItemVisualColor, getItemVisualOpacity } from "../../util/visual.mjs"; import { lift } from "../../../../zrender/lib/tool/color.mjs"; var SDF_RANGE = 20; var Z_2D = -10; function isSymbolSizeSame(a, b) { return a && b && a[0] === b[0] && a[1] === b[1]; } function PointsBuilder(is2D, api) { this.rootNode = new graphicGL.Node(); this.is2D = is2D; this._labelsBuilder = new LabelsBuilder(256, 256, api); this._labelsBuilder.getMesh().renderOrder = 100; this.rootNode.add(this._labelsBuilder.getMesh()); this._api = api; this._spriteImageCanvas = document.createElement("canvas"); this._startDataIndex = 0; this._endDataIndex = 0; this._sizeScale = 1; } PointsBuilder.prototype = { constructor: PointsBuilder, highlightOnMouseover: true, update: function(seriesModel, ecModel, api, start, end) { var tmp = this._prevMesh; this._prevMesh = this._mesh; this._mesh = tmp; var data = seriesModel.getData(); if (start == null) { start = 0; } if (end == null) { end = data.count(); } this._startDataIndex = start; this._endDataIndex = end - 1; if (!this._mesh) { var material = this._prevMesh && this._prevMesh.material; this._mesh = new PointsMesh({ renderOrder: 10, frustumCulling: false }); if (material) { this._mesh.material = material; } } var material = this._mesh.material; var geometry = this._mesh.geometry; var attributes = geometry.attributes; this.rootNode.remove(this._prevMesh); this.rootNode.add(this._mesh); this._setPositionTextureToMesh(this._mesh, this._positionTexture); var symbolInfo = this._getSymbolInfo(seriesModel, start, end); var dpr = api.getDevicePixelRatio(); var itemStyle = seriesModel.getModel("itemStyle").getItemStyle(); var largeMode = seriesModel.get("large"); var pointSizeScale = 1; if (symbolInfo.maxSize > 2) { pointSizeScale = this._updateSymbolSprite(seriesModel, itemStyle, symbolInfo, dpr); material.enableTexture("sprite"); } else { material.disableTexture("sprite"); } attributes.position.init(end - start); var rgbaArr = []; if (largeMode) { material.undefine("VERTEX_SIZE"); material.undefine("VERTEX_COLOR"); var color = getVisualColor(data); var opacity = getVisualOpacity(data); graphicGL.parseColor(color, rgbaArr); rgbaArr[3] *= opacity; material.set({ color: rgbaArr, "u_Size": symbolInfo.maxSize * this._sizeScale }); } else { material.set({ color: [1, 1, 1, 1] }); material.define("VERTEX_SIZE"); material.define("VERTEX_COLOR"); attributes.size.init(end - start); attributes.color.init(end - start); this._originalOpacity = new Float32Array(end - start); } var points = data.getLayout("points"); var positionArr = attributes.position.value; for (var i = 0; i < end - start; i++) { var i3 = i * 3; var i2 = i * 2; if (this.is2D) { positionArr[i3] = points[i2]; positionArr[i3 + 1] = points[i2 + 1]; positionArr[i3 + 2] = Z_2D; } else { positionArr[i3] = points[i3]; positionArr[i3 + 1] = points[i3 + 1]; positionArr[i3 + 2] = points[i3 + 2]; } if (!largeMode) { var color = getItemVisualColor(data, i); var opacity = getItemVisualOpacity(data, i); graphicGL.parseColor(color, rgbaArr); rgbaArr[3] *= opacity; attributes.color.set(i, rgbaArr); if (rgbaArr[3] < 0.99) ; var symbolSize = data.getItemVisual(i, "symbolSize"); symbolSize = symbolSize instanceof Array ? Math.max(symbolSize[0], symbolSize[1]) : symbolSize; if (isNaN(symbolSize)) { symbolSize = 0; } attributes.size.value[i] = symbolSize * pointSizeScale * this._sizeScale; this._originalOpacity[i] = rgbaArr[3]; } } this._mesh.sizeScale = pointSizeScale; geometry.updateBoundingBox(); geometry.dirty(); this._updateMaterial(seriesModel, itemStyle); var coordSys = seriesModel.coordinateSystem; if (coordSys && coordSys.viewGL) { var methodName = coordSys.viewGL.isLinearSpace() ? "define" : "undefine"; material[methodName]("fragment", "SRGB_DECODE"); } if (!largeMode) { this._updateLabelBuilder(seriesModel, start, end); } this._updateHandler(seriesModel, ecModel, api); this._updateAnimation(seriesModel); this._api = api; }, getPointsMesh: function() { return this._mesh; }, updateLabels: function(highlightDataIndices) { this._labelsBuilder.updateLabels(highlightDataIndices); }, hideLabels: function() { this.rootNode.remove(this._labelsBuilder.getMesh()); }, showLabels: function() { this.rootNode.add(this._labelsBuilder.getMesh()); }, dispose: function() { this._labelsBuilder.dispose(); }, _updateSymbolSprite: function(seriesModel, itemStyle, symbolInfo, dpr) { symbolInfo.maxSize = Math.min(symbolInfo.maxSize * 2, 200); var symbolSize = []; if (symbolInfo.aspect > 1) { symbolSize[0] = symbolInfo.maxSize; symbolSize[1] = symbolInfo.maxSize / symbolInfo.aspect; } else { symbolSize[1] = symbolInfo.maxSize; symbolSize[0] = symbolInfo.maxSize * symbolInfo.aspect; } symbolSize[0] = symbolSize[0] || 1; symbolSize[1] = symbolSize[1] || 1; if (this._symbolType !== symbolInfo.type || !isSymbolSizeSame(this._symbolSize, symbolSize) || this._lineWidth !== itemStyle.lineWidth) { spriteUtil.createSymbolSprite(symbolInfo.type, symbolSize, { fill: "#fff", lineWidth: itemStyle.lineWidth, stroke: "transparent", shadowColor: "transparent", minMargin: Math.min(symbolSize[0] / 2, 10) }, this._spriteImageCanvas); spriteUtil.createSDFFromCanvas(this._spriteImageCanvas, Math.min(this._spriteImageCanvas.width, 32), SDF_RANGE, this._mesh.material.get("sprite").image); this._symbolType = symbolInfo.type; this._symbolSize = symbolSize; this._lineWidth = itemStyle.lineWidth; } return this._spriteImageCanvas.width / symbolInfo.maxSize * dpr; }, _updateMaterial: function(seriesModel, itemStyle) { var blendFunc = seriesModel.get("blendMode") === "lighter" ? graphicGL.additiveBlend : null; var material = this._mesh.material; material.blend = blendFunc; material.set("lineWidth", itemStyle.lineWidth / SDF_RANGE); var strokeColor = graphicGL.parseColor(itemStyle.stroke); material.set("strokeColor", strokeColor); material.transparent = true; material.depthMask = false; material.depthTest = !this.is2D; material.sortVertices = !this.is2D; }, _updateLabelBuilder: function(seriesModel, start, end) { var data = seriesModel.getData(); var geometry = this._mesh.geometry; var positionArr = geometry.attributes.position.value; var start = this._startDataIndex; var pointSizeScale = this._mesh.sizeScale; this._labelsBuilder.updateData(data, start, end); this._labelsBuilder.getLabelPosition = function(dataIndex, positionDesc, distance) { var idx3 = (dataIndex - start) * 3; return [positionArr[idx3], positionArr[idx3 + 1], positionArr[idx3 + 2]]; }; this._labelsBuilder.getLabelDistance = function(dataIndex, positionDesc, distance) { var size = geometry.attributes.size.get(dataIndex - start) / pointSizeScale; return size / 2 + distance; }; this._labelsBuilder.updateLabels(); }, _updateAnimation: function(seriesModel) { graphicGL.updateVertexAnimation([["prevPosition", "position"], ["prevSize", "size"]], this._prevMesh, this._mesh, seriesModel); }, _updateHandler: function(seriesModel, ecModel, api) { var data = seriesModel.getData(); var pointsMesh = this._mesh; var self = this; var lastDataIndex = -1; var isCartesian3D = seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === "cartesian3D"; var grid3DModel; if (isCartesian3D) { grid3DModel = seriesModel.coordinateSystem.model; } pointsMesh.seriesIndex = seriesModel.seriesIndex; pointsMesh.off("mousemove"); pointsMesh.off("mouseout"); pointsMesh.on("mousemove", function(e) { var dataIndex = e.vertexIndex + self._startDataIndex; if (dataIndex !== lastDataIndex) { if (this.highlightOnMouseover) { this.downplay(data, lastDataIndex); this.highlight(data, dataIndex); this._labelsBuilder.updateLabels([dataIndex]); } if (isCartesian3D) { api.dispatchAction({ type: "grid3DShowAxisPointer", value: [data.get(seriesModel.coordDimToDataDim("x")[0], dataIndex), data.get(seriesModel.coordDimToDataDim("y")[0], dataIndex), data.get(seriesModel.coordDimToDataDim("z")[0], dataIndex)], grid3DIndex: grid3DModel.componentIndex }); } } pointsMesh.dataIndex = dataIndex; lastDataIndex = dataIndex; }, this); pointsMesh.on("mouseout", function(e) { var dataIndex = e.vertexIndex + self._startDataIndex; if (this.highlightOnMouseover) { this.downplay(data, dataIndex); this._labelsBuilder.updateLabels(); } lastDataIndex = -1; pointsMesh.dataIndex = -1; if (isCartesian3D) { api.dispatchAction({ type: "grid3DHideAxisPointer", grid3DIndex: grid3DModel.componentIndex }); } }, this); }, updateLayout: function(seriesModel, ecModel, api) { var data = seriesModel.getData(); if (!this._mesh) { return; } var positionArr = this._mesh.geometry.attributes.position.value; var points = data.getLayout("points"); if (this.is2D) { for (var i = 0; i < points.length / 2; i++) { var i3 = i * 3; var i2 = i * 2; positionArr[i3] = points[i2]; positionArr[i3 + 1] = points[i2 + 1]; positionArr[i3 + 2] = Z_2D; } } else { for (var i = 0; i < points.length; i++) { positionArr[i] = points[i]; } } this._mesh.geometry.dirty(); api.getZr().refresh(); }, updateView: function(camera) { if (!this._mesh) { return; } var worldViewProjection = new Matrix4(); Matrix4.mul(worldViewProjection, camera.viewMatrix, this._mesh.worldTransform); Matrix4.mul(worldViewProjection, camera.projectionMatrix, worldViewProjection); this._mesh.updateNDCPosition(worldViewProjection, this.is2D, this._api); }, highlight: function(data, dataIndex) { if (dataIndex > this._endDataIndex || dataIndex < this._startDataIndex) { return; } var itemModel = data.getItemModel(dataIndex); var emphasisItemStyleModel = itemModel.getModel("emphasis.itemStyle"); var emphasisColor = emphasisItemStyleModel.get("color"); var emphasisOpacity = emphasisItemStyleModel.get("opacity"); if (emphasisColor == null) { var color = getItemVisualColor(data, dataIndex); emphasisColor = lift(color, -0.4); } if (emphasisOpacity == null) { emphasisOpacity = getItemVisualOpacity(data, dataIndex); } var colorArr = graphicGL.parseColor(emphasisColor); colorArr[3] *= emphasisOpacity; this._mesh.geometry.attributes.color.set(dataIndex - this._startDataIndex, colorArr); this._mesh.geometry.dirtyAttribute("color"); this._api.getZr().refresh(); }, downplay: function(data, dataIndex) { if (dataIndex > this._endDataIndex || dataIndex < this._startDataIndex) { return; } var color = getItemVisualColor(data, dataIndex); var opacity = getItemVisualOpacity(data, dataIndex); var colorArr = graphicGL.parseColor(color); colorArr[3] *= opacity; this._mesh.geometry.attributes.color.set(dataIndex - this._startDataIndex, colorArr); this._mesh.geometry.dirtyAttribute("color"); this._api.getZr().refresh(); }, fadeOutAll: function(fadeOutPercent) { if (this._originalOpacity) { var geo = this._mesh.geometry; for (var i = 0; i < geo.vertexCount; i++) { var fadeOutOpacity = this._originalOpacity[i] * fadeOutPercent; geo.attributes.color.value[i * 4 + 3] = fadeOutOpacity; } geo.dirtyAttribute("color"); this._api.getZr().refresh(); } }, fadeInAll: function() { this.fadeOutAll(1); }, setPositionTexture: function(texture) { if (this._mesh) { this._setPositionTextureToMesh(this._mesh, texture); } this._positionTexture = texture; }, removePositionTexture: function() { this._positionTexture = null; if (this._mesh) { this._setPositionTextureToMesh(this._mesh, null); } }, setSizeScale: function(sizeScale) { if (sizeScale !== this._sizeScale) { if (this._mesh) { var originalSize = this._mesh.material.get("u_Size"); this._mesh.material.set("u_Size", originalSize / this._sizeScale * sizeScale); var attributes = this._mesh.geometry.attributes; if (attributes.size.value) { for (var i = 0; i < attributes.size.value.length; i++) { attributes.size.value[i] = attributes.size.value[i] / this._sizeScale * sizeScale; } } } this._sizeScale = sizeScale; } }, _setPositionTextureToMesh: function(mesh, texture) { if (texture) { mesh.material.set("positionTexture", texture); } mesh.material[texture ? "enableTexture" : "disableTexture"]("positionTexture"); }, _getSymbolInfo: function(seriesModel, start, end) { if (seriesModel.get("large")) { var symbolSize = retrieve.firstNotNull(seriesModel.get("symbolSize"), 1); var maxSymbolSize; var symbolAspect; if (symbolSize instanceof Array) { maxSymbolSize = Math.max(symbolSize[0], symbolSize[1]); symbolAspect = symbolSize[0] / symbolSize[1]; } else { maxSymbolSize = symbolSize; symbolAspect = 1; } return { maxSize: symbolSize, type: seriesModel.get("symbol"), aspect: symbolAspect }; } var data = seriesModel.getData(); var symbolAspect; var symbolType = data.getItemVisual(0, "symbol") || "circle"; var maxSymbolSize = 0; for (var idx = start; idx < end; idx++) { var symbolSize = data.getItemVisual(idx, "symbolSize"); var currentSymbolType = data.getItemVisual(idx, "symbol"); var currentSymbolAspect; if (!(symbolSize instanceof Array)) { if (isNaN(symbolSize)) { continue; } currentSymbolAspect = 1; maxSymbolSize = Math.max(symbolSize, maxSymbolSize); } else { currentSymbolAspect = symbolSize[0] / symbolSize[1]; maxSymbolSize = Math.max(Math.max(symbolSize[0], symbolSize[1]), maxSymbolSize); } symbolType = currentSymbolType; symbolAspect = currentSymbolAspect; } return { maxSize: maxSymbolSize, type: symbolType, aspect: symbolAspect }; } }; export { PointsBuilder as default };