index.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.HeatmapRenderer = void 0;
  4. const lru_1 = require("../../../utils/lru");
  5. const gradient_1 = require("./gradient");
  6. function newCanvas(createCanvas, width, height) {
  7. const c = createCanvas ? createCanvas() : document.createElement('canvas');
  8. c.width = width;
  9. c.height = height;
  10. return c;
  11. }
  12. /**
  13. * Get a point with template.
  14. * @param radius
  15. * @param blurFactor
  16. * @returns
  17. */
  18. const getPointTemplate = (0, lru_1.lru)((radius, blurFactor, createCanvas) => {
  19. const tplCanvas = newCanvas(createCanvas, radius * 2, radius * 2);
  20. const tplCtx = tplCanvas.getContext('2d');
  21. const x = radius;
  22. const y = radius;
  23. if (blurFactor === 1) {
  24. tplCtx.beginPath();
  25. tplCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
  26. tplCtx.fillStyle = 'rgba(0,0,0,1)';
  27. tplCtx.fill();
  28. }
  29. else {
  30. const gradient = tplCtx.createRadialGradient(x, y, radius * blurFactor, x, y, radius);
  31. gradient.addColorStop(0, 'rgba(0,0,0,1)');
  32. gradient.addColorStop(1, 'rgba(0,0,0,0)');
  33. tplCtx.fillStyle = gradient;
  34. tplCtx.fillRect(0, 0, 2 * radius, 2 * radius);
  35. }
  36. return tplCanvas;
  37. }, (radius) => `${radius}`);
  38. /**
  39. * Get a color palette with len = 256 base on gradient.
  40. * @param gradientConfig
  41. * @returns
  42. */
  43. function getColorPalette(gradientConfig, createCanvas) {
  44. const paletteCanvas = newCanvas(createCanvas, 256, 1);
  45. const paletteCtx = paletteCanvas.getContext('2d');
  46. const gradient = paletteCtx.createLinearGradient(0, 0, 256, 1);
  47. (0, gradient_1.parseGradient)(gradientConfig).forEach(([r, c]) => {
  48. gradient.addColorStop(r, c);
  49. });
  50. paletteCtx.fillStyle = gradient;
  51. paletteCtx.fillRect(0, 0, 256, 1);
  52. return paletteCtx.getImageData(0, 0, 256, 1).data;
  53. }
  54. /**
  55. * Draw all circle with alpha.
  56. */
  57. function drawAlpha(shadowCtx, min, max, data, options, createCanvas) {
  58. const { blur } = options;
  59. let len = data.length;
  60. while (len--) {
  61. const { x, y, value: v, radius } = data[len];
  62. // Ff value is bigger than max, use max as value.
  63. const value = Math.min(v, max);
  64. const rectX = x - radius;
  65. const rectY = y - radius;
  66. const tpl = getPointTemplate(radius, 1 - blur, createCanvas);
  67. // Value from minimum / value range, => [0, 1].
  68. const templateAlpha = (value - min) / (max - min);
  69. // Small values are not visible because globalAlpha < .001 cannot be read from imageData.
  70. shadowCtx.globalAlpha = Math.max(templateAlpha, 0.001);
  71. shadowCtx.drawImage(tpl, rectX, rectY);
  72. }
  73. return shadowCtx;
  74. }
  75. function colorize(shadowCtx, maxWidth, maxHeight, palette, options) {
  76. const { minOpacity, opacity, maxOpacity, useGradientOpacity } = options;
  77. const x = 0;
  78. const y = 0;
  79. const width = maxWidth;
  80. const height = maxHeight;
  81. const img = shadowCtx.getImageData(x, y, width, height);
  82. const imgData = img.data;
  83. const len = imgData.length;
  84. for (let i = 3; i < len; i += 4) {
  85. const alpha = imgData[i];
  86. const offset = alpha * 4;
  87. if (!offset) {
  88. continue;
  89. }
  90. // Should be in [min, max], min >= 0.
  91. const finalAlpha = opacity || Math.max(0, Math.min(maxOpacity, Math.max(minOpacity, alpha)));
  92. // Update rgba.
  93. imgData[i - 3] = palette[offset];
  94. imgData[i - 2] = palette[offset + 1];
  95. imgData[i - 1] = palette[offset + 2];
  96. imgData[i] = useGradientOpacity ? palette[offset + 3] : finalAlpha;
  97. }
  98. return img;
  99. }
  100. /**
  101. * Render a heatmap with canvas.
  102. * See [heatmap.js](https://github.com/pa7/heatmap.js/blob/master/src/renderer/canvas2d.js).
  103. */
  104. function HeatmapRenderer(width, height, min, max, data, options, createCanvas) {
  105. const opts = Object.assign({ blur: 0.85, minOpacity: 0, opacity: 0.6, maxOpacity: 1, gradient: [
  106. [0.25, 'rgb(0,0,255)'],
  107. [0.55, 'rgb(0,255,0)'],
  108. [0.85, 'yellow'],
  109. [1.0, 'rgb(255,0,0)'],
  110. ] }, options);
  111. opts.minOpacity *= 255;
  112. opts.opacity *= 255;
  113. opts.maxOpacity *= 255;
  114. const shadowCanvas = newCanvas(createCanvas, width, height);
  115. const shadowCtx = shadowCanvas.getContext('2d');
  116. const palette = getColorPalette(opts.gradient, createCanvas);
  117. shadowCtx.clearRect(0, 0, width, height);
  118. drawAlpha(shadowCtx, min, max, data, opts, createCanvas);
  119. const img = colorize(shadowCtx, width, height, palette, opts);
  120. const canvas = newCanvas(createCanvas, width, height);
  121. const ctx = canvas.getContext('2d');
  122. ctx.putImageData(img, 0, 0);
  123. return ctx;
  124. }
  125. exports.HeatmapRenderer = HeatmapRenderer;
  126. //# sourceMappingURL=index.js.map