/** * Surface texture in the 3D scene. * Provide management and rendering of zrender shapes and groups * * @module echarts-gl/util/EChartsSurface * @author Yi Shen(http://github.com/pissang) */ import Texture2D from 'claygl/src/Texture2D'; import Vector3 from 'claygl/src/math/Vector3'; import Vector2 from 'claygl/src/math/Vector2'; var events = ['mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'click', 'dblclick', 'contextmenu']; function makeHandlerName(eventName) { return '_on' + eventName; } /** * @constructor * @alias echarts-gl/util/EChartsSurface * @param {module:echarts~ECharts} chart */ var EChartsSurface = function (chart) { var self = this; this._texture = new Texture2D({ anisotropic: 32, flipY: false, surface: this, dispose: function (renderer) { self.dispose(); Texture2D.prototype.dispose.call(this, renderer); } }); events.forEach(function (eventName) { this[makeHandlerName(eventName)] = function (eveObj) { if (!eveObj.triangle) { return; } this._meshes.forEach(function (mesh) { this.dispatchEvent(eventName, mesh, eveObj.triangle, eveObj.point); }, this); }; }, this); this._meshes = []; if (chart) { this.setECharts(chart); } // Texture updated callback; this.onupdate = null; }; EChartsSurface.prototype = { constructor: EChartsSurface, getTexture: function () { return this._texture; }, setECharts: function (chart) { this._chart = chart; var canvas = chart.getDom(); if (!(canvas instanceof HTMLCanvasElement)) { console.error('ECharts must init on canvas if it is used as texture.'); // Use an empty canvas canvas = document.createElement('canvas'); } else { var self = this; // Wrap refreshImmediately var zr = chart.getZr(); var oldRefreshImmediately = zr.__oldRefreshImmediately || zr.refreshImmediately; zr.refreshImmediately = function () { oldRefreshImmediately.call(this); self._texture.dirty(); self.onupdate && self.onupdate(); }; zr.__oldRefreshImmediately = oldRefreshImmediately; } this._texture.image = canvas; this._texture.dirty(); this.onupdate && this.onupdate(); }, /** * @method * @param {clay.Mesh} attachedMesh * @param {Array.} triangle Triangle indices * @param {clay.math.Vector3} point */ dispatchEvent: function () { var p0 = new Vector3(); var p1 = new Vector3(); var p2 = new Vector3(); var uv0 = new Vector2(); var uv1 = new Vector2(); var uv2 = new Vector2(); var uv = new Vector2(); var vCross = new Vector3(); return function (eventName, attachedMesh, triangle, point) { var geo = attachedMesh.geometry; var position = geo.attributes.position; var texcoord = geo.attributes.texcoord0; var dot = Vector3.dot; var cross = Vector3.cross; position.get(triangle[0], p0.array); position.get(triangle[1], p1.array); position.get(triangle[2], p2.array); texcoord.get(triangle[0], uv0.array); texcoord.get(triangle[1], uv1.array); texcoord.get(triangle[2], uv2.array); cross(vCross, p1, p2); var det = dot(p0, vCross); var t = dot(point, vCross) / det; cross(vCross, p2, p0); var u = dot(point, vCross) / det; cross(vCross, p0, p1); var v = dot(point, vCross) / det; Vector2.scale(uv, uv0, t); Vector2.scaleAndAdd(uv, uv, uv1, u); Vector2.scaleAndAdd(uv, uv, uv2, v); var x = uv.x * this._chart.getWidth(); var y = uv.y * this._chart.getHeight(); this._chart.getZr().handler.dispatch(eventName, { zrX: x, zrY: y }); }; }(), attachToMesh: function (mesh) { if (this._meshes.indexOf(mesh) >= 0) { return; } events.forEach(function (eventName) { mesh.on(eventName, this[makeHandlerName(eventName)], this); }, this); this._meshes.push(mesh); }, detachFromMesh: function (mesh) { var idx = this._meshes.indexOf(mesh); if (idx >= 0) { this._meshes.splice(idx, 1); } events.forEach(function (eventName) { mesh.off(eventName, this[makeHandlerName(eventName)]); }, this); }, dispose: function () { this._meshes.forEach(function (mesh) { this.detachFromMesh(mesh); }, this); } }; export default EChartsSurface;