qlik-oss/sn-scatter-plot

View on GitHub
src/picasso-definition/interactions/pinch.js

Summary

Maintainability
B
4 hrs
Test Coverage
A
95%
import KEYS from '../../constants/keys';
import zoom from '../../view-handler/zoom';
import clearMinor from '../../utils/clear-minor';
import isInBinValueSelection from '../../utils/is-in-bin-value-selection';

const EVENT_NAME = 'zoom';

let lastScale = 0;
let lastRectSize;

function isWithinThreshold(diff) {
  return Math.abs(diff) > 0.01;
}

const pinch = ({ chart, actions, viewHandler, rtl, models }) => ({
  type: 'Pinch',
  key: 'pinchZoom',
  options: {
    event: EVENT_NAME,
    pointers: 2,
    threshold: 0,
    enable(r, e) {
      if (this.started === EVENT_NAME || !e) {
        return true;
      }
      if (!actions.zoom.enabled()) {
        return false;
      }
      if (isInBinValueSelection(chart)) {
        return false;
      }

      this.area = chart
        .componentsFromPoint({ x: e.center.x, y: e.center.y })
        .filter((c) => c.key === KEYS.COMPONENT.POINT || c.key === KEYS.COMPONENT.HEAT_MAP);

      if (!this.area.length) {
        return false;
      }

      const rectSize = this.area[0]?.rect?.computedPhysical;

      if (rectSize?.height && rectSize?.width) {
        lastRectSize = { ...rectSize };
      }
      this.componentSize = lastRectSize;

      return true;
    },
  },
  events: {
    zoomstart(e) {
      clearMinor({ chart, actions });
      e.preventDefault();
      lastScale = e.scale;
      this.started = EVENT_NAME;
      const initialDataView = viewHandler.getDataView();
      this[EVENT_NAME] = {
        componentSize: this.componentSize,
        ...initialDataView,
      };
    },
    zoommove(e) {
      e.preventDefault();
      // Pinch zoom
      if (e.scale > 1.1 || e.scale < 0.9) {
        const diff = e.scale - lastScale;

        if (isWithinThreshold(diff)) {
          zoom({
            e,
            chart,
            componentSize: this.componentSize,
            viewHandler,
            pinchZoomFactor: lastScale / e.scale,
            models,
          });
          lastScale = e.scale;
        }
      }
      // Pan
      else {
        const { componentSize, xAxisMin, xAxisMax, yAxisMax, yAxisMin } = this[EVENT_NAME];

        const xDiff = (xAxisMax - xAxisMin) * (e.deltaX / componentSize.width);
        const yDiff = (yAxisMax - yAxisMin) * (e.deltaY / componentSize.height);

        const dataView = {
          xAxisMin: rtl ? xAxisMin + xDiff : xAxisMin - xDiff,
          xAxisMax: rtl ? xAxisMax + xDiff : xAxisMax - xDiff,
          yAxisMin: yAxisMin + yDiff,
          yAxisMax: yAxisMax + yDiff,
        };

        viewHandler.setDataView(dataView);
      }
    },
    zoomend(e) {
      e.preventDefault();
      this.started = false;
    },
    zoomcancel(e) {
      e.preventDefault();
      this.started = false;
    },
  },
});

export default pinch;