Web Dev Solutions

Catalin Mititiuc

aboutsummaryrefslogtreecommitdiff
blob: 9faae0a5603038c5a942ce8ae746da10debf67a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
const minDistanceThreshold = 5;

function distanceBetween({ x: x1, y: y1 }, { x: x2, y: y2 }) {
  return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
}

function minDistanceThresholdIsMet(startPt, endPt) {
  return distanceBetween(startPt, endPt) >= minDistanceThreshold;
}

function getPositionChangeInLocalCoords(svg, startPt, endPt) {
  const matrix = svg.getScreenCTM().inverse(),
    localStartPt = startPt.matrixTransform(matrix),
    localEndPt = endPt.matrixTransform(matrix);

  return {
    x: localStartPt.x - localEndPt.x,
    y: localStartPt.y - localEndPt.y
  };
}

function stopEventPropagationToChildren(svg, type) {
  svg.addEventListener(type, e => e.stopPropagation(), { capture: true, once: true });
}

function setToCurrentPointerCoords(point, e) {
  point.x = e.clientX;
  point.y = e.clientY;

  return point;
}

function getPanCoords(svg, startPt, movePt, initialPos) {
  const posChange = getPositionChangeInLocalCoords(svg, startPt, movePt);

  return {
    x: initialPos.x + posChange.x,
    y: initialPos.y + posChange.y
  };
}

function setViewBoxPosition(svg, { x, y }) {
  const { width, height } = svg.viewBox.baseVal;

  svg.setAttributeNS(null, 'viewBox', `${x} ${y} ${width} ${height}`);
}

export default function (svg, e) {
  const { x, y } = svg.viewBox.baseVal,
    startPt = setToCurrentPointerCoords(new DOMPoint(), e),
    movePt = new DOMPoint();

  let isPanning = false;

  function pointerMove(e) {
    setToCurrentPointerCoords(movePt, e);

    if (!isPanning && minDistanceThresholdIsMet(startPt, movePt)) {
      isPanning = true;
      e.target.setPointerCapture(e.pointerId);
      setToCurrentPointerCoords(startPt, e);
      stopEventPropagationToChildren(svg, 'click');
    }

    if (isPanning) {
      setViewBoxPosition(svg, getPanCoords(svg, startPt, movePt, { x, y }));
    }
  }

  svg.addEventListener('pointermove', pointerMove);

  svg.addEventListener(
    'pointerup',
    () => svg.removeEventListener('pointermove', pointerMove),
    { once: true }
  );
}