text: import echarts from 'echarts/lib/echarts';
  
  function makeSprite(size, canvas, draw) {
      // http://simonsarris.com/blog/346-how-you-clear-your-canvas-matters
      // http://jsperf.com/canvasclear
      // Set width and height is fast
      // And use the exist canvas if possible
      // http://jsperf.com/create-canvas-vs-set-width-height/2
      var canvas = canvas || document.createElement('canvas');
      canvas.width = size;
      canvas.height = size;
      var ctx = canvas.getContext('2d');
  
      draw && draw(ctx);
  
      return canvas;
  }
  
  function makePath(symbol, symbolSize, style, marginBias) {
      if (!echarts.util.isArray(symbolSize)) {
          symbolSize = [symbolSize, symbolSize];
      }
      var margin = spriteUtil.getMarginByStyle(style, marginBias);
      var width = symbolSize[0] + margin.left + margin.right;
      var height = symbolSize[1] + margin.top + margin.bottom;
      var path = echarts.helper.createSymbol(symbol, 0, 0, symbolSize[0], symbolSize[1]);
  
      var size = Math.max(width, height);
  
      path.position = [margin.left, margin.top];
      if (width > height) {
          path.position[1] += (size - height) / 2;
      }
      else {
          path.position[0] += (size - width) / 2;
      }
  
      var rect = path.getBoundingRect();
      path.position[0] -= rect.x;
      path.position[1] -= rect.y;
  
      path.setStyle(style);
  
      path.update();
  
      path.__size = size;
  
      return path;
  }
  
      // http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf
  function generateSDF(ctx, sourceImageData, range) {
  
      var sourceWidth = sourceImageData.width;
      var sourceHeight = sourceImageData.height;
  
      var width = ctx.canvas.width;
      var height = ctx.canvas.height;
  
      var scaleX = sourceWidth / width;
      var scaleY = sourceHeight / height;
  
      function sign(r) {
          return r < 128 ? 1 : -1;
      }
      function searchMinDistance(x, y) {
          var minDistSqr = Infinity;
          x = Math.floor(x * scaleX);
          y = Math.floor(y * scaleY);
          var i = y * sourceWidth + x;
          var r = sourceImageData.data[i * 4];
          var a = sign(r);
          // Search for min distance
          for (var y2 = Math.max(y - range, 0); y2 < Math.min(y + range, sourceHeight); y2++) {
              for (var x2 = Math.max(x - range, 0); x2 < Math.min(x + range, sourceWidth); x2++) {
                  var i = y2 * sourceWidth + x2;
                  var r2 = sourceImageData.data[i * 4];
                  var b = sign(r2);
                  var dx = x2 - x;
                  var dy = y2 - y;
                  if (a !== b) {
                      var distSqr = dx * dx + dy * dy;
                      if (distSqr < minDistSqr) {
                          minDistSqr = distSqr;
                      }
                  }
              }
          }
          return a * Math.sqrt(minDistSqr);
      }
  
      var sdfImageData = ctx.createImageData(width, height);
      for (var y = 0; y < height; y++) {
          for (var x = 0; x < width; x++) {
              var dist = searchMinDistance(x, y);
  
              var normalized = dist / range * 0.5 + 0.5;
              var i = (y * width + x) * 4;
              sdfImageData.data[i++] = (1.0 - normalized) * 255;
              sdfImageData.data[i++] = (1.0 - normalized) * 255;
              sdfImageData.data[i++] = (1.0 - normalized) * 255;
              sdfImageData.data[i++] = 255;
          }
      }
  
      return sdfImageData;
  }
  
  var spriteUtil = {
  
      getMarginByStyle: function (style) {
          var minMargin = style.minMargin || 0;
  
          var lineWidth = 0;
          if (style.stroke && style.stroke !== 'none') {
              lineWidth = style.lineWidth == null ? 1 : style.lineWidth;
          }
          var shadowBlurSize = style.shadowBlur || 0;
          var shadowOffsetX = style.shadowOffsetX || 0;
          var shadowOffsetY = style.shadowOffsetY || 0;
  
          var margin = {};
          margin.left = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize, minMargin);
          margin.right = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize, minMargin);
          margin.top = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize, minMargin);
          margin.bottom = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize, minMargin);
  
          return margin;
      },
  
      // TODO Not consider shadowOffsetX, shadowOffsetY.
      /**
       * @param {string} symbol
       * @param {number | Array.<number>} symbolSize
       * @param {Object} style
       */
      createSymbolSprite: function (symbol, symbolSize, style, canvas) {
          var path = makePath(symbol, symbolSize, style);
  
          var margin = spriteUtil.getMarginByStyle(style);
  
          return {
              image: makeSprite(path.__size, canvas, function (ctx) {
                  path.brush(ctx);
              }),
              margin: margin
          };
      },
  
      createSDFFromCanvas: function (canvas, size, range, outCanvas) {
          // TODO Create a low resolution SDF from high resolution image.
          return makeSprite(size, outCanvas, function (outCtx) {
              var ctx = canvas.getContext('2d');
              var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  
              outCtx.putImageData(generateSDF(outCtx, imgData, range), 0, 0);
          });
      },
  
      createSimpleSprite: function (size, canvas) {
          return makeSprite(size, canvas, function (ctx) {
              var halfSize = size / 2;
              ctx.beginPath();
              ctx.arc(halfSize, halfSize, 60, 0, Math.PI * 2, false) ;
              ctx.closePath();
  
              var gradient = ctx.createRadialGradient(
                  halfSize, halfSize, 0, halfSize, halfSize, halfSize
              );
              gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
              gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.5)');
              gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
              ctx.fillStyle = gradient;
              ctx.fill();
          });
      }
  };
  
  export default spriteUtil;