fix: address Greptile review and fix CI test mock for touch handlers
Three fixes in one commit:
1. **CI test mock** — Added addEventListener/removeEventListener to the
Node.js makeElement mock so viewport.addEventListener() calls in the
touch handler registration don't crash with 'not a function'.
2. **Two-finger pan during pinch** — Replaced _setScale() call with
direct transform math. The new formula computes scale and position
simultaneously:
ratio = boundedScale / pinchStartScale
x = currMidX - (startMidX - startPosX) * ratio
This keeps the diagram under both fingers regardless of midpoint
drift, enabling simultaneous zoom + pan.
3. **Post-pinch click suppression** — _onTouchEnd now sets dragged=true
when exiting pinch mode so any synthesized click event is caught
by the existing dragged guard in _openViewerOnClick instead of
opening the lightbox.
This commit is contained in:
1 parent
7419b1bb51
commit
0403f00789
2 files changed
+31
-6
No files matched your search
+22
-6
@@ -2016,6 +2016,10 @@ function _mountMermaidViewer(svgEl, options = {}) {
|
||||
pinching: false,
|
||||
pinchStartDist: 0,
|
||||
pinchStartScale: 1,
|
||||
pinchStartCX: 0,
|
||||
pinchStartCY: 0,
|
||||
pinchStartX: 0,
|
||||
pinchStartY: 0,
|
||||
};
|
||||
root._mermaidViewer = state;
|
||||
|
||||
@@ -2219,6 +2223,11 @@ function _mountMermaidViewer(svgEl, options = {}) {
|
||||
state.pinching = true;
|
||||
state.pinchStartDist = _touchDist(e.touches);
|
||||
state.pinchStartScale = state.scale;
|
||||
state.pinchStartX = state.x;
|
||||
state.pinchStartY = state.y;
|
||||
const rect = viewport.getBoundingClientRect();
|
||||
state.pinchStartCX = (e.touches[0].clientX + e.touches[1].clientX) / 2 - (rect.left || 0);
|
||||
state.pinchStartCY = (e.touches[0].clientY + e.touches[1].clientY) / 2 - (rect.top || 0);
|
||||
_endPointerDrag();
|
||||
if(e.preventDefault) e.preventDefault();
|
||||
}
|
||||
@@ -2226,19 +2235,26 @@ function _mountMermaidViewer(svgEl, options = {}) {
|
||||
|
||||
function _onTouchMove(e){
|
||||
if(!state.pinching || e.touches.length < 2) return;
|
||||
const rect = viewport.getBoundingClientRect();
|
||||
const cx = (e.touches[0].clientX + e.touches[1].clientX) / 2 - (rect.left || 0);
|
||||
const cy = (e.touches[0].clientY + e.touches[1].clientY) / 2 - (rect.top || 0);
|
||||
const currDist = _touchDist(e.touches);
|
||||
if(state.pinchStartDist > 0){
|
||||
const rect = viewport.getBoundingClientRect();
|
||||
const cx = (e.touches[0].clientX + e.touches[1].clientX) / 2 - (rect.left || 0);
|
||||
const cy = (e.touches[0].clientY + e.touches[1].clientY) / 2 - (rect.top || 0);
|
||||
_setScale(state.pinchStartScale * (currDist / state.pinchStartDist), cx, cy);
|
||||
if(state.pinchStartDist > 0 && state.pinchStartScale > 0){
|
||||
const rawScale = state.pinchStartScale * (currDist / state.pinchStartDist);
|
||||
const boundedScale = Math.max(_minScale(), Math.min(_MERMAID_VIEWER_MAX_SCALE, rawScale));
|
||||
const ratio = boundedScale / state.pinchStartScale;
|
||||
state.scale = boundedScale;
|
||||
state.x = cx - (state.pinchStartCX - state.pinchStartX) * ratio;
|
||||
state.y = cy - (state.pinchStartCY - state.pinchStartY) * ratio;
|
||||
_applyTransform();
|
||||
}
|
||||
if(e.preventDefault) e.preventDefault();
|
||||
}
|
||||
|
||||
function _onTouchEnd(e){
|
||||
if(e.touches.length < 2){
|
||||
if(e.touches.length < 2 && state.pinching){
|
||||
state.pinching = false;
|
||||
state.dragged = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,15 @@ function makeElement(tagName) {
|
||||
this.releasedPointerId = pointerId;
|
||||
if (this.capturedPointerId === pointerId) this.capturedPointerId = null;
|
||||
},
|
||||
_listeners: {},
|
||||
addEventListener(type, handler, _options) {
|
||||
(this._listeners[type] ||= []).push(handler);
|
||||
},
|
||||
removeEventListener(type, handler) {
|
||||
const list = this._listeners[type] || [];
|
||||
const idx = list.indexOf(handler);
|
||||
if (idx >= 0) list.splice(idx, 1);
|
||||
},
|
||||
cloneNode() {
|
||||
const copy = makeElement(this.tagName);
|
||||
copy.className = this.className;
|
||||
|
||||
Reference in new issue
Block a user