Skip to content

Commit 85fee0a

Browse files
pedrolamasclaude
andauthored
refactor(GcodePreview): auto-zoom without cropping (#1867)
Signed-off-by: Pedro Lamas <pedrolamas@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent fe41a43 commit 85fee0a

1 file changed

Lines changed: 85 additions & 19 deletions

File tree

src/components/widgets/gcode-preview/GcodePreview.vue

Lines changed: 85 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,6 @@ export default class GcodePreview extends Mixins(StateMixin, BrowserMixin) {
425425
value,
426426
server: true
427427
})
428-
429-
this.reset()
430428
}
431429
432430
get followProgress (): boolean {
@@ -591,22 +589,6 @@ export default class GcodePreview extends Mixins(StateMixin, BrowserMixin) {
591589
592590
get viewBox (): BBox {
593591
const bounds = this.bounds
594-
595-
if (this.autoZoom) {
596-
const padding = Math.min(bounds.x.max - bounds.x.min, bounds.y.max - bounds.y.min) * 0.05
597-
598-
return {
599-
x: {
600-
min: bounds.x.min - padding,
601-
max: bounds.x.max + padding
602-
},
603-
y: {
604-
min: bounds.y.min - padding,
605-
max: bounds.y.max + padding
606-
}
607-
}
608-
}
609-
610592
const bedSize = this.bedSize
611593
612594
return {
@@ -714,9 +696,28 @@ export default class GcodePreview extends Mixins(StateMixin, BrowserMixin) {
714696
}
715697
}
716698
699+
@Watch('autoZoom')
700+
onAutoZoomChanged (value: boolean) {
701+
if (value) {
702+
this.$nextTick(() => this.zoomToBounds())
703+
} else {
704+
this.reset()
705+
}
706+
}
707+
708+
@Watch('bedSize')
709+
@Watch('bounds')
710+
@Watch('flipX')
711+
@Watch('flipY')
712+
onAutoZoomDependenciesChanged () {
713+
if (this.autoZoom) {
714+
this.$nextTick(() => this.zoomToBounds())
715+
}
716+
}
717+
717718
mounted () {
718719
this.panzoom = markRaw(panzoom(this.svg, {
719-
maxZoom: 20,
720+
maxZoom: 40,
720721
minZoom: 0.95,
721722
smoothScroll: this.showAnimations,
722723
@@ -733,6 +734,10 @@ export default class GcodePreview extends Mixins(StateMixin, BrowserMixin) {
733734
this.panzoom.on('panend', () => {
734735
this.panning = false
735736
})
737+
738+
if (this.autoZoom) {
739+
requestAnimationFrame(() => this.zoomToBounds())
740+
}
736741
}
737742
738743
beforeDestroy () {
@@ -744,6 +749,67 @@ export default class GcodePreview extends Mixins(StateMixin, BrowserMixin) {
744749
this.panzoom?.zoomAbs(0, 0, 1)
745750
}
746751
752+
zoomToBounds () {
753+
if (!this.panzoom || this.disabled) {
754+
return
755+
}
756+
757+
const owner = this.svg.parentElement
758+
759+
if (!owner) {
760+
return
761+
}
762+
763+
const containerWidth = owner.clientWidth
764+
const containerHeight = owner.clientHeight
765+
766+
if (containerWidth === 0 || containerHeight === 0) {
767+
return
768+
}
769+
770+
const viewBox = this.viewBox
771+
const viewBoxWidth = viewBox.x.max - viewBox.x.min
772+
const viewBoxHeight = viewBox.y.max - viewBox.y.min
773+
774+
const bounds = this.bounds
775+
const boundsWidth = bounds.x.max - bounds.x.min
776+
const boundsHeight = bounds.y.max - bounds.y.min
777+
778+
if (boundsWidth <= 0 || boundsHeight <= 0) {
779+
this.reset()
780+
781+
return
782+
}
783+
784+
const minX = this.flipX
785+
? (viewBox.x.max + viewBox.x.min) - bounds.x.max
786+
: bounds.x.min
787+
const minY = this.flipY
788+
? (viewBox.y.max + viewBox.y.min) - bounds.y.max
789+
: bounds.y.min
790+
const boundsCenterX = minX + boundsWidth / 2
791+
const boundsCenterY = minY + boundsHeight / 2
792+
793+
const unitsToPixels = Math.min(containerWidth / viewBoxWidth, containerHeight / viewBoxHeight)
794+
const offsetX = (containerWidth - viewBoxWidth * unitsToPixels) / 2
795+
const offsetY = (containerHeight - viewBoxHeight * unitsToPixels) / 2
796+
const pixelCenterX = offsetX + (boundsCenterX - viewBox.x.min) * unitsToPixels
797+
const pixelCenterY = offsetY + (boundsCenterY - viewBox.y.min) * unitsToPixels
798+
799+
const padding = 1.1
800+
const rawScale = Math.min(
801+
containerWidth / (boundsWidth * unitsToPixels),
802+
containerHeight / (boundsHeight * unitsToPixels)
803+
) / padding
804+
const scale = Math.min(Math.max(rawScale, this.panzoom.getMinZoom()), this.panzoom.getMaxZoom())
805+
806+
this.panzoom.zoomAbs(0, 0, scale)
807+
this.panzoom.moveTo(
808+
containerWidth / 2 - scale * pixelCenterX,
809+
containerHeight / 2 - scale * pixelCenterY
810+
)
811+
}
812+
747813
keepFocus () {
748814
if (!this.isMobileViewport) {
749815
this.container.focus()

0 commit comments

Comments
 (0)