UNPKG

cione-comp-lib

Version:

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

275 lines (274 loc) 10.9 kB
import "../../../../echarts/lib/echarts.mjs"; import graphicGL from "../../util/graphicGL.mjs"; import retrieve from "../../util/retrieve.mjs"; import ViewGL from "../../core/ViewGL.mjs"; import VectorFieldParticleSurface from "./VectorFieldParticleSurface.mjs"; import ChartView from "../../../../echarts/lib/view/Chart.mjs"; var FlowGLView = ChartView.extend({ type: "flowGL", __ecgl__: true, init: function(ecModel, api) { this.viewGL = new ViewGL("orthographic"); this.groupGL = new graphicGL.Node(); this.viewGL.add(this.groupGL); this._particleSurface = new VectorFieldParticleSurface(); var planeMesh = new graphicGL.Mesh({ geometry: new graphicGL.PlaneGeometry(), material: new graphicGL.Material({ shader: new graphicGL.Shader({ vertex: graphicGL.Shader.source("ecgl.color.vertex"), fragment: graphicGL.Shader.source("ecgl.color.fragment") }), transparent: true }) }); planeMesh.material.enableTexture("diffuseMap"); this.groupGL.add(planeMesh); this._planeMesh = planeMesh; }, render: function(seriesModel, ecModel, api) { var particleSurface = this._particleSurface; particleSurface.setParticleType(seriesModel.get("particleType")); particleSurface.setSupersampling(seriesModel.get("supersampling")); this._updateData(seriesModel, api); this._updateCamera(api.getWidth(), api.getHeight(), api.getDevicePixelRatio()); var particleDensity = retrieve.firstNotNull(seriesModel.get("particleDensity"), 128); particleSurface.setParticleDensity(particleDensity, particleDensity); var planeMesh = this._planeMesh; var time = +new Date(); var self = this; var firstFrame = true; planeMesh.__percent = 0; planeMesh.stopAnimation(); planeMesh.animate("", { loop: true }).when(1e5, { __percent: 1 }).during(function() { var timeNow = +new Date(); var dTime = Math.min(timeNow - time, 20); time = time + dTime; if (self._renderer) { particleSurface.update(self._renderer, api, dTime / 1e3, firstFrame); planeMesh.material.set("diffuseMap", particleSurface.getSurfaceTexture()); } firstFrame = false; }).start(); var itemStyleModel = seriesModel.getModel("itemStyle"); var color = graphicGL.parseColor(itemStyleModel.get("color")); color[3] *= retrieve.firstNotNull(itemStyleModel.get("opacity"), 1); planeMesh.material.set("color", color); particleSurface.setColorTextureImage(seriesModel.get("colorTexture"), api); particleSurface.setParticleSize(seriesModel.get("particleSize")); particleSurface.particleSpeedScaling = seriesModel.get("particleSpeed"); particleSurface.motionBlurFactor = 1 - Math.pow(0.1, seriesModel.get("particleTrail")); }, updateTransform: function(seriesModel, ecModel, api) { this._updateData(seriesModel, api); }, afterRender: function(globeModel, ecModel, api, layerGL) { var renderer = layerGL.renderer; this._renderer = renderer; }, _updateData: function(seriesModel, api) { var coordSys = seriesModel.coordinateSystem; var dims = coordSys.dimensions.map(function(coordDim) { return seriesModel.coordDimToDataDim(coordDim)[0]; }); var data = seriesModel.getData(); var xExtent = data.getDataExtent(dims[0]); var yExtent = data.getDataExtent(dims[1]); var gridWidth = seriesModel.get("gridWidth"); var gridHeight = seriesModel.get("gridHeight"); if (gridWidth == null || gridWidth === "auto") { var aspect = (xExtent[1] - xExtent[0]) / (yExtent[1] - yExtent[0]); gridWidth = Math.round(Math.sqrt(aspect * data.count())); } if (gridHeight == null || gridHeight === "auto") { gridHeight = Math.ceil(data.count() / gridWidth); } var vectorFieldTexture = this._particleSurface.vectorFieldTexture; var pixels = vectorFieldTexture.pixels; if (!pixels || pixels.length !== gridHeight * gridWidth * 4) { pixels = vectorFieldTexture.pixels = new Float32Array(gridWidth * gridHeight * 4); } else { for (var i = 0; i < pixels.length; i++) { pixels[i] = 0; } } var maxMag = 0; var minMag = Infinity; var points = new Float32Array(data.count() * 2); var offset = 0; var bbox = [[Infinity, Infinity], [-Infinity, -Infinity]]; data.each([dims[0], dims[1], "vx", "vy"], function(x, y, vx, vy) { var pt = coordSys.dataToPoint([x, y]); points[offset++] = pt[0]; points[offset++] = pt[1]; bbox[0][0] = Math.min(pt[0], bbox[0][0]); bbox[0][1] = Math.min(pt[1], bbox[0][1]); bbox[1][0] = Math.max(pt[0], bbox[1][0]); bbox[1][1] = Math.max(pt[1], bbox[1][1]); var mag = Math.sqrt(vx * vx + vy * vy); maxMag = Math.max(maxMag, mag); minMag = Math.min(minMag, mag); }); data.each(["vx", "vy"], function(vx, vy, i2) { var xPix = Math.round((points[i2 * 2] - bbox[0][0]) / (bbox[1][0] - bbox[0][0]) * (gridWidth - 1)); var yPix = gridHeight - 1 - Math.round((points[i2 * 2 + 1] - bbox[0][1]) / (bbox[1][1] - bbox[0][1]) * (gridHeight - 1)); var idx = (yPix * gridWidth + xPix) * 4; pixels[idx] = vx / maxMag * 0.5 + 0.5; pixels[idx + 1] = vy / maxMag * 0.5 + 0.5; pixels[idx + 3] = 1; }); vectorFieldTexture.width = gridWidth; vectorFieldTexture.height = gridHeight; if (seriesModel.get("coordinateSystem") === "bmap") { this._fillEmptyPixels(vectorFieldTexture); } vectorFieldTexture.dirty(); this._updatePlanePosition(bbox[0], bbox[1], seriesModel, api); this._updateGradientTexture(data.getVisual("visualMeta"), [minMag, maxMag]); }, _fillEmptyPixels: function(texture) { var pixels = texture.pixels; var width = texture.width; var height = texture.height; function fetchPixel(x2, y2, rg) { x2 = Math.max(Math.min(x2, width - 1), 0); y2 = Math.max(Math.min(y2, height - 1), 0); var idx2 = (y2 * (width - 1) + x2) * 4; if (pixels[idx2 + 3] === 0) { return false; } rg[0] = pixels[idx2]; rg[1] = pixels[idx2 + 1]; return true; } function addPixel(a, b, out) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; } var center = [], left = [], right = [], top = [], bottom = []; var weight = 0; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var idx = (y * (width - 1) + x) * 4; if (pixels[idx + 3] === 0) { weight = center[0] = center[1] = 0; if (fetchPixel(x - 1, y, left)) { weight++; addPixel(left, center, center); } if (fetchPixel(x + 1, y, right)) { weight++; addPixel(right, center, center); } if (fetchPixel(x, y - 1, top)) { weight++; addPixel(top, center, center); } if (fetchPixel(x, y + 1, bottom)) { weight++; addPixel(bottom, center, center); } center[0] /= weight; center[1] /= weight; pixels[idx] = center[0]; pixels[idx + 1] = center[1]; } pixels[idx + 3] = 1; } } }, _updateGradientTexture: function(visualMeta, magExtent) { if (!visualMeta || !visualMeta.length) { this._particleSurface.setGradientTexture(null); return; } this._gradientTexture = this._gradientTexture || new graphicGL.Texture2D({ image: document.createElement("canvas") }); var gradientTexture = this._gradientTexture; var canvas = gradientTexture.image; canvas.width = 200; canvas.height = 1; var ctx = canvas.getContext("2d"); var gradient = ctx.createLinearGradient(0, 0.5, canvas.width, 0.5); visualMeta[0].stops.forEach(function(stop) { var offset; if (magExtent[1] === magExtent[0]) { offset = 0; } else { offset = stop.value / magExtent[1]; offset = Math.min(Math.max(offset, 0), 1); } gradient.addColorStop(offset, stop.color); }); ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); gradientTexture.dirty(); this._particleSurface.setGradientTexture(this._gradientTexture); }, _updatePlanePosition: function(leftTop, rightBottom, seriesModel, api) { var limitedResult = this._limitInViewportAndFullFill(leftTop, rightBottom, seriesModel, api); leftTop = limitedResult.leftTop; rightBottom = limitedResult.rightBottom; this._particleSurface.setRegion(limitedResult.region); this._planeMesh.position.set((leftTop[0] + rightBottom[0]) / 2, api.getHeight() - (leftTop[1] + rightBottom[1]) / 2, 0); var width = rightBottom[0] - leftTop[0]; var height = rightBottom[1] - leftTop[1]; this._planeMesh.scale.set(width / 2, height / 2, 1); this._particleSurface.resize(Math.max(Math.min(width, 2048), 1), Math.max(Math.min(height, 2048), 1)); if (this._renderer) { this._particleSurface.clearFrame(this._renderer); } }, _limitInViewportAndFullFill: function(leftTop, rightBottom, seriesModel, api) { var newLeftTop = [Math.max(leftTop[0], 0), Math.max(leftTop[1], 0)]; var newRightBottom = [Math.min(rightBottom[0], api.getWidth()), Math.min(rightBottom[1], api.getHeight())]; if (seriesModel.get("coordinateSystem") === "bmap") { var lngRange = seriesModel.getData().getDataExtent(seriesModel.coordDimToDataDim("lng")[0]); var isContinuous = Math.floor(lngRange[1] - lngRange[0]) >= 359; if (isContinuous) { if (newLeftTop[0] > 0) { newLeftTop[0] = 0; } if (newRightBottom[0] < api.getWidth()) { newRightBottom[0] = api.getWidth(); } } } var width = rightBottom[0] - leftTop[0]; var height = rightBottom[1] - leftTop[1]; var newWidth = newRightBottom[0] - newLeftTop[0]; var newHeight = newRightBottom[1] - newLeftTop[1]; var region = [(newLeftTop[0] - leftTop[0]) / width, 1 - newHeight / height - (newLeftTop[1] - leftTop[1]) / height, newWidth / width, newHeight / height]; return { leftTop: newLeftTop, rightBottom: newRightBottom, region }; }, _updateCamera: function(width, height, dpr) { this.viewGL.setViewport(0, 0, width, height, dpr); var camera = this.viewGL.camera; camera.left = camera.bottom = 0; camera.top = height; camera.right = width; camera.near = 0; camera.far = 100; camera.position.z = 10; }, remove: function() { this._planeMesh.stopAnimation(); this.groupGL.removeAll(); }, dispose: function() { if (this._renderer) { this._particleSurface.dispose(this._renderer); } this.groupGL.removeAll(); } }); export { FlowGLView as default };