| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- import { lru } from '../../../utils/lru';
- import { parseGradient } from './gradient';
- function newCanvas(createCanvas, width, height) {
- const c = createCanvas ? createCanvas() : document.createElement('canvas');
- c.width = width;
- c.height = height;
- return c;
- }
- /**
- * Get a point with template.
- * @param radius
- * @param blurFactor
- * @returns
- */
- const getPointTemplate = lru((radius, blurFactor, createCanvas) => {
- const tplCanvas = newCanvas(createCanvas, radius * 2, radius * 2);
- const tplCtx = tplCanvas.getContext('2d');
- const x = radius;
- const y = radius;
- if (blurFactor === 1) {
- tplCtx.beginPath();
- tplCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
- tplCtx.fillStyle = 'rgba(0,0,0,1)';
- tplCtx.fill();
- }
- else {
- const gradient = tplCtx.createRadialGradient(x, y, radius * blurFactor, x, y, radius);
- gradient.addColorStop(0, 'rgba(0,0,0,1)');
- gradient.addColorStop(1, 'rgba(0,0,0,0)');
- tplCtx.fillStyle = gradient;
- tplCtx.fillRect(0, 0, 2 * radius, 2 * radius);
- }
- return tplCanvas;
- }, (radius) => `${radius}`);
- /**
- * Get a color palette with len = 256 base on gradient.
- * @param gradientConfig
- * @returns
- */
- function getColorPalette(gradientConfig, createCanvas) {
- const paletteCanvas = newCanvas(createCanvas, 256, 1);
- const paletteCtx = paletteCanvas.getContext('2d');
- const gradient = paletteCtx.createLinearGradient(0, 0, 256, 1);
- parseGradient(gradientConfig).forEach(([r, c]) => {
- gradient.addColorStop(r, c);
- });
- paletteCtx.fillStyle = gradient;
- paletteCtx.fillRect(0, 0, 256, 1);
- return paletteCtx.getImageData(0, 0, 256, 1).data;
- }
- /**
- * Draw all circle with alpha.
- */
- function drawAlpha(shadowCtx, min, max, data, options, createCanvas) {
- const { blur } = options;
- let len = data.length;
- while (len--) {
- const { x, y, value: v, radius } = data[len];
- // Ff value is bigger than max, use max as value.
- const value = Math.min(v, max);
- const rectX = x - radius;
- const rectY = y - radius;
- const tpl = getPointTemplate(radius, 1 - blur, createCanvas);
- // Value from minimum / value range, => [0, 1].
- const templateAlpha = (value - min) / (max - min);
- // Small values are not visible because globalAlpha < .001 cannot be read from imageData.
- shadowCtx.globalAlpha = Math.max(templateAlpha, 0.001);
- shadowCtx.drawImage(tpl, rectX, rectY);
- }
- return shadowCtx;
- }
- function colorize(shadowCtx, maxWidth, maxHeight, palette, options) {
- const { minOpacity, opacity, maxOpacity, useGradientOpacity } = options;
- const x = 0;
- const y = 0;
- const width = maxWidth;
- const height = maxHeight;
- const img = shadowCtx.getImageData(x, y, width, height);
- const imgData = img.data;
- const len = imgData.length;
- for (let i = 3; i < len; i += 4) {
- const alpha = imgData[i];
- const offset = alpha * 4;
- if (!offset) {
- continue;
- }
- // Should be in [min, max], min >= 0.
- const finalAlpha = opacity || Math.max(0, Math.min(maxOpacity, Math.max(minOpacity, alpha)));
- // Update rgba.
- imgData[i - 3] = palette[offset];
- imgData[i - 2] = palette[offset + 1];
- imgData[i - 1] = palette[offset + 2];
- imgData[i] = useGradientOpacity ? palette[offset + 3] : finalAlpha;
- }
- return img;
- }
- /**
- * Render a heatmap with canvas.
- * See [heatmap.js](https://github.com/pa7/heatmap.js/blob/master/src/renderer/canvas2d.js).
- */
- export function HeatmapRenderer(width, height, min, max, data, options, createCanvas) {
- const opts = Object.assign({ blur: 0.85, minOpacity: 0, opacity: 0.6, maxOpacity: 1, gradient: [
- [0.25, 'rgb(0,0,255)'],
- [0.55, 'rgb(0,255,0)'],
- [0.85, 'yellow'],
- [1.0, 'rgb(255,0,0)'],
- ] }, options);
- opts.minOpacity *= 255;
- opts.opacity *= 255;
- opts.maxOpacity *= 255;
- const shadowCanvas = newCanvas(createCanvas, width, height);
- const shadowCtx = shadowCanvas.getContext('2d');
- const palette = getColorPalette(opts.gradient, createCanvas);
- shadowCtx.clearRect(0, 0, width, height);
- drawAlpha(shadowCtx, min, max, data, opts, createCanvas);
- const img = colorize(shadowCtx, width, height, palette, opts);
- const canvas = newCanvas(createCanvas, width, height);
- const ctx = canvas.getContext('2d');
- ctx.putImageData(img, 0, 0);
- return ctx;
- }
- //# sourceMappingURL=index.js.map
|