qlik-oss/sn-scatter-plot

View on GitHub
src/picasso-components/heat-map-highlight/index.js

Summary

Maintainability
A
1 hr
Test Coverage
F
51%
import KEYS from '../../constants/keys';
import getImageData from './extract-image-data';
import getPixelRatio from './get-pixel-ratio';

export default {
  require: ['renderer', 'chart'],
  renderer: 'canvas',

  render() {
    const { element } = this.chart;
    const heatMapCanvas = element.querySelector(`[data-key=${KEYS.COMPONENT.HEAT_MAP}]`);
    const heatMapHighlightCanvas = this.renderer.element();
    if (!heatMapCanvas || !heatMapHighlightCanvas) {
      return;
    }
    const { width, height } = this.rect;
    const dirtyImageData = {
      x: 0,
      y: 0,
      w: width,
      h: height,
    };
    const { actions, dataView, rtl } = this.settings.settings;
    const heatMapCanvasContext = heatMapCanvas.getContext('2d');
    const pixelRatio = getPixelRatio(heatMapCanvasContext);
    let bitmapImage;
    const ctx = heatMapHighlightCanvas.getContext('2d');
    ctx.clearRect(0, 0, width * pixelRatio, height * pixelRatio);

    const updateImageData = (range, axis) => {
      if (!bitmapImage) return;
      ctx.clearRect(0, 0, width * pixelRatio, height * pixelRatio);
      const { x, y, w, h } = getImageData(range, axis, dataView, dirtyImageData, width, height, rtl);
      dirtyImageData.x = x;
      dirtyImageData.y = y;
      dirtyImageData.w = w;
      dirtyImageData.h = h;
      ctx.drawImage(
        bitmapImage,
        x * pixelRatio,
        y * pixelRatio,
        w * pixelRatio,
        h * pixelRatio,
        x * pixelRatio,
        y * pixelRatio,
        w * pixelRatio,
        h * pixelRatio
      );
    };

    const onSelectionStart = async () => {
      if (!bitmapImage) {
        heatMapCanvas.style.opacity = 1;
        const imageData = heatMapCanvasContext.getImageData(0, 0, heatMapCanvas.width, heatMapCanvas.height);
        const pixels = imageData.data;
        for (let i = 3, n = heatMapCanvas.width * heatMapCanvas.height * 4; i < n; i += 4) {
          pixels[i] = pixels[i] === 0 ? 0 : 255;
        }
        bitmapImage = await createImageBitmap(imageData);
      }
    };

    const onBinXRange = (range) => {
      updateImageData(range, 'x');
    };

    const onBinYRange = (range) => {
      updateImageData(range, 'y');
    };

    const onBinRangeHighlightClear = () => {
      bitmapImage = undefined;
      ctx.clearRect(0, 0, width * pixelRatio, height * pixelRatio);
    };

    const onBinsRangeSelectionClear = () => {
      ctx.clearRect(0, 0, width * pixelRatio, height * pixelRatio);
      dirtyImageData.x = 0;
      dirtyImageData.y = 0;
      dirtyImageData.w = width;
      dirtyImageData.h = height;
    };

    actions.select.removeAllListeners('selectionStart');
    actions.select.removeAllListeners('binXRange');
    actions.select.removeAllListeners('binYRange');
    actions.select.removeAllListeners('binRangeHighlightClear');
    actions.select.removeAllListeners('binsRangeSelectionClear');
    actions.select.on('selectionStart', onSelectionStart);
    actions.select.on('binXRange', onBinXRange);
    actions.select.on('binYRange', onBinYRange);
    actions.select.on('binRangeHighlightClear', onBinRangeHighlightClear);
    actions.select.on('binsRangeSelectionClear', onBinsRangeSelectionClear);
  },
};