| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 | 
/** 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.*/var graphic = require("../../util/graphic");var _symbol = require("../../util/symbol");var createSymbol = _symbol.createSymbol;var IncrementalDisplayable = require("zrender/lib/graphic/IncrementalDisplayable");/** 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.*//* global Float32Array */// TODO Batch by colorvar BOOST_SIZE_THRESHOLD = 4;var LargeSymbolPath = graphic.extendShape({  shape: {    points: null  },  symbolProxy: null,  softClipShape: null,  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; // Do draw in afterBrush.    if (canBoost) {      return;    }    for (var i = 0; i < points.length;) {      var x = points[i++];      var y = points[i++];      if (isNaN(x) || isNaN(y)) {        continue;      }      if (this.softClipShape && !this.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);    }  },  afterBrush: function (ctx) {    var shape = this.shape;    var points = shape.points;    var size = shape.size;    var canBoost = size[0] < BOOST_SIZE_THRESHOLD;    if (!canBoost) {      return;    }    this.setTransform(ctx); // PENDING If style or other canvas status changed?    for (var i = 0; i < points.length;) {      var x = points[i++];      var y = points[i++];      if (isNaN(x) || isNaN(y)) {        continue;      }      if (this.softClipShape && !this.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]);    }    this.restoreTransform(ctx);  },  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;  }});function LargeSymbolDraw() {  this.group = new graphic.Group();}var largeSymbolProto = LargeSymbolDraw.prototype;largeSymbolProto.isPersistent = function () {  return !this._incremental;};/** * Update symbols draw by new data * @param {module:echarts/data/List} data * @param {Object} opt * @param {Object} [opt.clipShape] */largeSymbolProto.updateData = function (data, opt) {  this.group.removeAll();  var symbolEl = new LargeSymbolPath({    rectHover: true,    cursor: 'default'  });  symbolEl.setShape({    points: data.getLayout('symbolPoints')  });  this._setCommon(symbolEl, data, false, opt);  this.group.add(symbolEl);  this._incremental = null;};largeSymbolProto.updateLayout = function (data) {  if (this._incremental) {    return;  }  var points = data.getLayout('symbolPoints');  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);  });};largeSymbolProto.incrementalPrepareUpdate = function (data) {  this.group.removeAll();  this._clearIncremental(); // Only use incremental displayables when data amount is larger than 2 million.  // PENDING Incremental data?  if (data.count() > 2e6) {    if (!this._incremental) {      this._incremental = new IncrementalDisplayable({        silent: true      });    }    this.group.add(this._incremental);  } else {    this._incremental = null;  }};largeSymbolProto.incrementalUpdate = function (taskParams, data, opt) {  var symbolEl;  if (this._incremental) {    symbolEl = new LargeSymbolPath();    this._incremental.addDisplayable(symbolEl, true);  } else {    symbolEl = new LargeSymbolPath({      rectHover: true,      cursor: 'default',      startIndex: taskParams.start,      endIndex: taskParams.end    });    symbolEl.incremental = true;    this.group.add(symbolEl);  }  symbolEl.setShape({    points: data.getLayout('symbolPoints')  });  this._setCommon(symbolEl, data, !!this._incremental, opt);};largeSymbolProto._setCommon = function (symbolEl, data, isIncremental, opt) {  var hostModel = data.hostModel;  opt = opt || {}; // TODO  // if (data.hasItemVisual.symbolSize) {  //     // TODO typed array?  //     symbolEl.setShape('sizes', data.mapArray(  //         function (idx) {  //             var size = data.getItemVisual(idx, 'symbolSize');  //             return (size instanceof Array) ? size : [size, size];  //         }  //     ));  // }  // else {  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 visualColor = data.getVisual('color');  if (visualColor) {    symbolEl.setColor(visualColor);  }  if (!isIncremental) {    // Enable tooltip    // PENDING May have performance issue when path is extremely large    symbolEl.seriesIndex = hostModel.seriesIndex;    symbolEl.on('mousemove', function (e) {      symbolEl.dataIndex = null;      var dataIndex = symbolEl.findDataIndex(e.offsetX, e.offsetY);      if (dataIndex >= 0) {        // Provide dataIndex for tooltip        symbolEl.dataIndex = dataIndex + (symbolEl.startIndex || 0);      }    });  }};largeSymbolProto.remove = function () {  this._clearIncremental();  this._incremental = null;  this.group.removeAll();};largeSymbolProto._clearIncremental = function () {  var incremental = this._incremental;  if (incremental) {    incremental.clearDisplaybles();  }};var _default = LargeSymbolDraw;module.exports = _default;
 |