docs: function (data, width, height, normalize, colorFunc, isInRange) {
          var brush = this._getBrush();
          var gradientInRange = this._getGradient(data, colorFunc, 'inRange');
          var gradientOutOfRange = this._getGradient(data, colorFunc, 'outOfRange');
          var r = this.pointSize + this.blurSize;
  
          var canvas = this.canvas;
          var ctx = canvas.getContext('2d');
          var len = data.length;
          canvas.width = width;
          canvas.height = height;
          for (var i = 0; i < len; ++i) {
              var p = data[i];
              var x = p[0];
              var y = p[1];
              var value = p[2];
  
              // calculate alpha using value
              var alpha = normalize(value);
  
              // draw with the circle brush with alpha
              ctx.globalAlpha = alpha;
              ctx.drawImage(brush, x - r, y - r);
          }
  
          if (!canvas.width || !canvas.height) {
              // Avoid "Uncaught DOMException: Failed to execute 'getImageData' on
              // 'CanvasRenderingContext2D': The source height is 0."
              return canvas;
          }
  
          // colorize the canvas using alpha value and set with gradient
          var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  
          var pixels = imageData.data;
          var offset = 0;
          var pixelLen = pixels.length;
          var minOpacity = this.minOpacity;
          var maxOpacity = this.maxOpacity;
          var diffOpacity = maxOpacity - minOpacity;
  
          while (offset < pixelLen) {
              var alpha = pixels[offset + 3] / 256;
              var gradientOffset = Math.floor(alpha * (GRADIENT_LEVELS - 1)) * 4;
              // Simple optimize to ignore the empty data
              if (alpha > 0) {
                  var gradient = isInRange(alpha) ? gradientInRange : gradientOutOfRange;
                  // Any alpha > 0 will be mapped to [minOpacity, maxOpacity]
                  alpha > 0 && (alpha = alpha * diffOpacity + minOpacity);
                  pixels[offset++] = gradient[gradientOffset];
                  pixels[offset++] = gradient[gradientOffset + 1];
                  pixels[offset++] = gradient[gradientOffset + 2];
                  pixels[offset++] = gradient[gradientOffset + 3] * alpha * 256;
              }
              else {
                  offset += 4;
              }
          }
          ctx.putImageData(imageData, 0, 0);
  
          return canvas;
      }