From ceb30167e4bd0ce271f18be7b1924fc84bab14df Mon Sep 17 00:00:00 2001 From: Jon Harper Date: Mon, 1 Feb 2021 16:46:02 +0100 Subject: [PATCH 1/5] margins: now in user units, and working for all aspect ratios cases --- readme.md | 2 +- src/svg.panzoom.js | 139 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index b765c50..12f45b5 100644 --- a/readme.md +++ b/readme.md @@ -77,7 +77,7 @@ You can override the default options by passing an object in to the `.panZoom({o | wheelZoom | true | Enable mouse wheel zoom | | panButton | 0 | Which mouse button to use for pan ([info](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button)) | | oneFingerPan | false | Enables the ability to pan with only one finger instead of two for touchdevices | -| margins | false | An object {top, left, right, bottom} to restrict the pan area so that at least x px are still visible | +| margins | false | An object {top, left, right, bottom} to restrict the pan area towards this side so that at least x user units of the opposite side are still visible | | zoomFactor | 2 | How quickly to zoom when using `wheelZoom` | | zoomMin | Number.MIN_VALUE | The minimum zoom level | | zoomMax | Number.MAX_VALUE | The maximum zoom level | diff --git a/src/svg.panzoom.js b/src/svg.panzoom.js index 97f03a7..88bcc2b 100644 --- a/src/svg.panzoom.js +++ b/src/svg.panzoom.js @@ -27,20 +27,143 @@ extend(Svg, { let lastTouches let zoomInProgress = false + const viewbox = this.viewbox() + const restrictToMargins = box => { if (!margins) return box const { top, left, bottom, right } = margins - const zoom = this.width() / box.width const { width, height } = this.attr(['width', 'height']) + const preserveAspectRatio = this.node.preserveAspectRatio.baseVal + + // The current viewport (exactly what is shown on the screen, what we ultimately want to restrict) + // is not always exactly the same as current viewbox. They are different when the viewbox aspectRatio and the svg aspectRatio + // are different and preserveAspectRatio is not "none". These offsets represent the difference in user coordinates + // between the side of the viewbox and the side of the viewport. + let viewportLeftOffset = 0 + let viewportRightOffset = 0 + let viewportTopOffset = 0 + let viewportBottomOffset = 0 + + // preserveAspectRatio none has no offsets + if (preserveAspectRatio.align !== preserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE) { + const svgAspectRatio = width / height + const viewboxAspectRatio = viewbox.width / viewbox.height + // when aspectRatios are the same, there are no offsets + if (viewboxAspectRatio !== svgAspectRatio) { + const changedAxis = svgAspectRatio > viewboxAspectRatio ? 'width' : 'height' + // aspectRatio unknown is like meet because that's the default + if (preserveAspectRatio.meetOrSlice === preserveAspectRatio.SVG_MEETORSLICE_MEET) { + // in meet mode, the viewport is the viewbox, extended on one + // or both sides to match the aspectRatio of the svg + if (changedAxis === 'width') { + const widthOffset = box.width / viewboxAspectRatio * svgAspectRatio - box.width + // aspectRatio undefined is like mid because that's the default + if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX) { + viewportLeftOffset = -widthOffset / 2 + viewportRightOffset = widthOffset / 2 + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX) { + viewportRightOffset = widthOffset + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { + viewportLeftOffset = -widthOffset + } + } else { + const heightOffset = box.height * viewboxAspectRatio / svgAspectRatio - box.height + if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID) { + viewportTopOffset = -heightOffset / 2 + viewportBottomOffset = heightOffset / 2 + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN) { + viewportBottomOffset = heightOffset + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { + viewportTopOffset = -heightOffset + } + } + } else if (preserveAspectRatio.meetOrSlice === preserveAspectRatio.SVG_MEETORSLICE_SLICE) { + // in slice mode, the viewport is the viewbox, shrunk on one + // or both sides to match the aspectRatio of the svg + if (changedAxis === 'width') { + const heightOffset = box.height - box.height * viewboxAspectRatio / svgAspectRatio + if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX) { + viewportTopOffset = heightOffset / 2 + viewportBottomOffset = -heightOffset / 2 + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX) { + viewportBottomOffset = -heightOffset + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { + viewportTopOffset = heightOffset + } + } else { + const widthOffset = box.width - box.width / viewboxAspectRatio * svgAspectRatio + if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID) { + viewportLeftOffset = widthOffset / 2 + viewportRightOffset = -widthOffset / 2 + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN) { + viewportLeftOffset = -widthOffset + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { + viewportRightOffset = widthOffset + } + } + } + } + } - const leftLimit = width - left / zoom - const rightLimit = (right - width) / zoom - const topLimit = height - top / zoom - const bottomLimit = (bottom - height) / zoom - - box.x = Math.min(leftLimit, Math.max(rightLimit, box.x)) - box.y = Math.min(topLimit, Math.max(bottomLimit, box.y)) + // when box.x == leftLimit, the image is panned to the left, + // i.e the current box is to the right of the initial viewbox, + // and only the right part of the initial image is visible, i.e. + // the right side of the initial viewbox minus left margin (viewbox.x+viewbox.width-left) + // is aligned with the left side of the viewport (box.x + viewportLeftOffset): + // viewbox.width + viewbox.x - left = box.x + viewportLeftOffset + // viewbox.width + viewbox.x - left - viewportLeftOffset = box.x (= leftLimit) + const leftLimit = viewbox.width + viewbox.x - left - viewportLeftOffset + // when box.x == rightLimit, the image is panned to the right, + // i.e the current box is to the left of the initial viewbox + // and only the left part of the initial image is visible, i.e + // the left side of the initial viewbox plus right margin (viewbox.x + right) + // is aligned with the right side of the viewport (box.x + box.width + viewportRightOffset) + // viewbox.x + right = box.x + box.width + viewportRightOffset + // viewbox.x + right - box.width - viewportRightOffset = box.x (= rightLimit) + const rightLimit = viewbox.x + right - box.width - viewportRightOffset + // same with top and bottom + const topLimit = viewbox.height + viewbox.y - top - viewportTopOffset + const bottomLimit = viewbox.y + bottom - box.height - viewportBottomOffset + + box.x = Math.min(leftLimit, Math.max(rightLimit, box.x)) // enforce rightLimit <= box.x <= leftLimit + box.y = Math.min(topLimit, Math.max(bottomLimit, box.y)) // enforce bottomLimit <= box.y <= topLimit return box } From b432e494e7a8fe49dbea453ecdcb44a6b259a7f9 Mon Sep 17 00:00:00 2001 From: Jon Harper Date: Mon, 22 Feb 2021 13:43:32 +0100 Subject: [PATCH 2/5] fix viewport offsets in slice mode --- src/svg.panzoom.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/svg.panzoom.js b/src/svg.panzoom.js index 88bcc2b..973468a 100644 --- a/src/svg.panzoom.js +++ b/src/svg.panzoom.js @@ -102,40 +102,40 @@ extend(Svg, { if (changedAxis === 'width') { const heightOffset = box.height - box.height * viewboxAspectRatio / svgAspectRatio if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX) { + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID) { viewportTopOffset = heightOffset / 2 viewportBottomOffset = -heightOffset / 2 } else if ( preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX) { + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN) { viewportBottomOffset = -heightOffset } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { viewportTopOffset = heightOffset } } else { const widthOffset = box.width - box.width / viewboxAspectRatio * svgAspectRatio if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID) { + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX) { viewportLeftOffset = widthOffset / 2 viewportRightOffset = -widthOffset / 2 } else if ( preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN) { - viewportLeftOffset = -widthOffset + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX) { + viewportRightOffset = -widthOffset } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { - viewportRightOffset = widthOffset + viewportLeftOffset = widthOffset } } } From b60a2a3e0df49ef63af91bce26874332e8ebdcda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Wed, 21 Jul 2021 13:10:16 +0200 Subject: [PATCH 3/5] simplify logic --- src/svg.panzoom.js | 130 +++++++++++++++------------------------------ 1 file changed, 43 insertions(+), 87 deletions(-) diff --git a/src/svg.panzoom.js b/src/svg.panzoom.js index 973468a..8d828ab 100644 --- a/src/svg.panzoom.js +++ b/src/svg.panzoom.js @@ -1,7 +1,7 @@ import { Svg, on, off, extend, Matrix, Box } from '@svgdotjs/svg.js' const normalizeEvent = ev => - ev.touches || [{ clientX: ev.clientX, clientY: ev.clientY }] + ev.touches || [ { clientX: ev.clientX, clientY: ev.clientY } ] extend(Svg, { panZoom (options) { @@ -33,7 +33,7 @@ extend(Svg, { if (!margins) return box const { top, left, bottom, right } = margins - const { width, height } = this.attr(['width', 'height']) + const { width, height } = this.attr([ 'width', 'height' ]) const preserveAspectRatio = this.node.preserveAspectRatio.baseVal // The current viewport (exactly what is shown on the screen, what we ultimately want to restrict) @@ -51,94 +51,50 @@ extend(Svg, { const viewboxAspectRatio = viewbox.width / viewbox.height // when aspectRatios are the same, there are no offsets if (viewboxAspectRatio !== svgAspectRatio) { - const changedAxis = svgAspectRatio > viewboxAspectRatio ? 'width' : 'height' // aspectRatio unknown is like meet because that's the default - if (preserveAspectRatio.meetOrSlice === preserveAspectRatio.SVG_MEETORSLICE_MEET) { - // in meet mode, the viewport is the viewbox, extended on one - // or both sides to match the aspectRatio of the svg - if (changedAxis === 'width') { - const widthOffset = box.width / viewboxAspectRatio * svgAspectRatio - box.width - // aspectRatio undefined is like mid because that's the default - if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX) { - viewportLeftOffset = -widthOffset / 2 - viewportRightOffset = widthOffset / 2 - } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX) { - viewportRightOffset = widthOffset - } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { - viewportLeftOffset = -widthOffset - } - } else { - const heightOffset = box.height * viewboxAspectRatio / svgAspectRatio - box.height - if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID) { - viewportTopOffset = -heightOffset / 2 - viewportBottomOffset = heightOffset / 2 - } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN) { - viewportBottomOffset = heightOffset - } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { - viewportTopOffset = -heightOffset - } + const isMeet = preserveAspectRatio.meetOrSlice !== preserveAspectRatio.SVG_MEETORSLICE_SLICE + const changedAxis = svgAspectRatio > viewboxAspectRatio ? 'width' : 'height' + const isWidth = changedAxis === 'width' + + const offset = box[changedAxis] / viewboxAspectRatio * svgAspectRatio - box[changedAxis] + if ((isMeet && isWidth) || (!isMeet && !isWidth)) { + if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX) { + viewportLeftOffset = offset / 2 + viewportRightOffset = -offset / 2 + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX) { + viewportRightOffset = -offset + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { + viewportLeftOffset = offset } - } else if (preserveAspectRatio.meetOrSlice === preserveAspectRatio.SVG_MEETORSLICE_SLICE) { - // in slice mode, the viewport is the viewbox, shrunk on one - // or both sides to match the aspectRatio of the svg - if (changedAxis === 'width') { - const heightOffset = box.height - box.height * viewboxAspectRatio / svgAspectRatio - if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID) { - viewportTopOffset = heightOffset / 2 - viewportBottomOffset = -heightOffset / 2 - } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN) { - viewportBottomOffset = -heightOffset - } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { - viewportTopOffset = heightOffset - } - } else { - const widthOffset = box.width - box.width / viewboxAspectRatio * svgAspectRatio - if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX) { - viewportLeftOffset = widthOffset / 2 - viewportRightOffset = -widthOffset / 2 - } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX) { - viewportRightOffset = -widthOffset - } else if ( - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID || - preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { - viewportLeftOffset = widthOffset - } + } else { + if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID) { + viewportTopOffset = -offset / 2 + viewportBottomOffset = offset / 2 + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN) { + viewportBottomOffset = offset + } else if ( + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX || + preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { + viewportTopOffset = -offset } } + } } @@ -386,7 +342,7 @@ extend(Svg, { const p2 = this.point(lastP.x, lastP.y) - const deltaP = [p2.x - p1.x, p2.y - p1.y] + const deltaP = [ p2.x - p1.x, p2.y - p1.y ] if (!deltaP[0] && !deltaP[1]) { return From 582ecdae1e3fe0b5eda3a6a33854eaeb86e8e73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Wed, 21 Jul 2021 18:39:46 +0200 Subject: [PATCH 4/5] getting the ratio right --- src/svg.panzoom.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/svg.panzoom.js b/src/svg.panzoom.js index 8d828ab..2e02dba 100644 --- a/src/svg.panzoom.js +++ b/src/svg.panzoom.js @@ -1,7 +1,7 @@ import { Svg, on, off, extend, Matrix, Box } from '@svgdotjs/svg.js' const normalizeEvent = ev => - ev.touches || [ { clientX: ev.clientX, clientY: ev.clientY } ] + ev.touches || [{ clientX: ev.clientX, clientY: ev.clientY }] extend(Svg, { panZoom (options) { @@ -33,7 +33,7 @@ extend(Svg, { if (!margins) return box const { top, left, bottom, right } = margins - const { width, height } = this.attr([ 'width', 'height' ]) + const { width, height } = this.attr(['width', 'height']) const preserveAspectRatio = this.node.preserveAspectRatio.baseVal // The current viewport (exactly what is shown on the screen, what we ultimately want to restrict) @@ -55,9 +55,13 @@ extend(Svg, { const isMeet = preserveAspectRatio.meetOrSlice !== preserveAspectRatio.SVG_MEETORSLICE_SLICE const changedAxis = svgAspectRatio > viewboxAspectRatio ? 'width' : 'height' const isWidth = changedAxis === 'width' + const changeHorizontal = (isMeet && isWidth) || (!isMeet && !isWidth) + const ratio = changeHorizontal + ? svgAspectRatio / viewboxAspectRatio + : viewboxAspectRatio / svgAspectRatio - const offset = box[changedAxis] / viewboxAspectRatio * svgAspectRatio - box[changedAxis] - if ((isMeet && isWidth) || (!isMeet && !isWidth)) { + const offset = box[changedAxis] - box[changedAxis] * ratio + if (changeHorizontal) { if ( preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || @@ -342,7 +346,7 @@ extend(Svg, { const p2 = this.point(lastP.x, lastP.y) - const deltaP = [ p2.x - p1.x, p2.y - p1.y ] + const deltaP = [p2.x - p1.x, p2.y - p1.y] if (!deltaP[0] && !deltaP[1]) { return From 7c228301fedeb5bc564601a979ed65a575abde41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Wed, 21 Jul 2021 23:09:11 +0200 Subject: [PATCH 5/5] I coulnt read the signs... ^^ --- src/svg.panzoom.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/svg.panzoom.js b/src/svg.panzoom.js index 2e02dba..cb4d5dc 100644 --- a/src/svg.panzoom.js +++ b/src/svg.panzoom.js @@ -84,18 +84,18 @@ extend(Svg, { preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID) { - viewportTopOffset = -offset / 2 - viewportBottomOffset = offset / 2 + viewportTopOffset = offset / 2 + viewportBottomOffset = -offset / 2 } else if ( preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN) { - viewportBottomOffset = offset + viewportBottomOffset = -offset } else if ( preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX || preserveAspectRatio.align === preserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX) { - viewportTopOffset = -offset + viewportTopOffset = offset } }