mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
Merge pull request #6602 from logseq/fix/whiteboards-scroll-zoom
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { TLApp, TLEvents, TLTool } from '@tldraw/core'
|
||||
import type { TLReactEventMap } from '@tldraw/react'
|
||||
import Vec from '@tldraw/vec'
|
||||
import { type Shape, LogseqPortalShape } from '../../shapes'
|
||||
import { CreatingState, IdleState } from './states'
|
||||
|
||||
@@ -16,15 +15,7 @@ export class LogseqPortalTool extends TLTool<
|
||||
|
||||
Shape = LogseqPortalShape
|
||||
|
||||
private pinchCamera(point: number[], delta: number[], zoom: number) {
|
||||
const { camera } = this.app.viewport
|
||||
const nextPoint = Vec.sub(camera.point, Vec.div(delta, camera.zoom))
|
||||
const p0 = Vec.sub(Vec.div(point, camera.zoom), nextPoint)
|
||||
const p1 = Vec.sub(Vec.div(point, zoom), nextPoint)
|
||||
this.app.setCamera(Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))), zoom)
|
||||
}
|
||||
|
||||
onPinch: TLEvents<Shape>['pinch'] = info => {
|
||||
this.pinchCamera(info.point, [0, 0], info.offset[0])
|
||||
this.app.viewport.pinchCamera(info.point, [0, 0], info.offset[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,22 +82,30 @@ export class TLViewport {
|
||||
return Vec.mul(Vec.add(point, camera.point), camera.zoom)
|
||||
}
|
||||
|
||||
zoomIn = (): this => {
|
||||
const { camera, bounds } = this
|
||||
const zoom: number = Math.min(TLViewport.maxZoom, camera.zoom / ZOOM_UPDATE_FACTOR)
|
||||
const center = [bounds.width / 2, bounds.height / 2]
|
||||
const p0 = Vec.sub(Vec.div(center, camera.zoom), center)
|
||||
const p1 = Vec.sub(Vec.div(center, zoom), center)
|
||||
return this.update({ point: Vec.toFixed(Vec.add(camera.point, Vec.sub(p1, p0))), zoom })
|
||||
pinchCamera = (point: number[], delta: number[], zoom: number): this => {
|
||||
const { camera } = this
|
||||
zoom = Math.max(TLViewport.minZoom, Math.min(TLViewport.maxZoom, zoom));
|
||||
const nextPoint = Vec.sub(camera.point, Vec.div(delta, camera.zoom))
|
||||
const p0 = Vec.sub(Vec.div(point, camera.zoom), nextPoint)
|
||||
const p1 = Vec.sub(Vec.div(point, zoom), nextPoint)
|
||||
return this.update({ point: Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))), zoom })
|
||||
}
|
||||
|
||||
zoomOut = (): this => {
|
||||
const { camera, bounds } = this
|
||||
const zoom: number = Math.max(TLViewport.minZoom, camera.zoom * ZOOM_UPDATE_FACTOR)
|
||||
setZoom = (zoom: number) => {
|
||||
const { bounds } = this
|
||||
const center = [bounds.width / 2, bounds.height / 2]
|
||||
const p0 = Vec.sub(Vec.div(center, camera.zoom), center)
|
||||
const p1 = Vec.sub(Vec.div(center, zoom), center)
|
||||
return this.update({ point: Vec.toFixed(Vec.add(camera.point, Vec.sub(p1, p0))), zoom })
|
||||
this.pinchCamera(center, [0, 0], zoom)
|
||||
}
|
||||
|
||||
zoomIn = () => {
|
||||
const { camera } = this
|
||||
this.setZoom(camera.zoom / ZOOM_UPDATE_FACTOR)
|
||||
}
|
||||
|
||||
zoomOut = () => {
|
||||
const { camera, bounds } = this
|
||||
this.setZoom(camera.zoom * ZOOM_UPDATE_FACTOR)
|
||||
|
||||
}
|
||||
|
||||
resetZoom = (): this => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Vec } from '@tldraw/vec'
|
||||
import type { TLEventMap, TLEventInfo, TLEvents } from '../../../../types'
|
||||
import type { TLShape } from '../../../shapes'
|
||||
import type { TLApp } from '../../../TLApp'
|
||||
@@ -26,21 +25,13 @@ export class PinchingState<
|
||||
|
||||
private prevDelta: number[] = [0, 0]
|
||||
|
||||
private pinchCamera(point: number[], delta: number[], zoom: number) {
|
||||
const { camera } = this.app.viewport
|
||||
const nextPoint = Vec.sub(camera.point, Vec.div(delta, camera.zoom))
|
||||
const p0 = Vec.sub(Vec.div(point, camera.zoom), nextPoint)
|
||||
const p1 = Vec.sub(Vec.div(point, zoom), nextPoint)
|
||||
this.app.setCamera(Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))), zoom)
|
||||
}
|
||||
|
||||
onEnter = (info: GestureInfo<S, K>) => {
|
||||
this.prevDelta = info.info.delta
|
||||
this.origin = info.info.point
|
||||
}
|
||||
|
||||
onPinch: TLEvents<S>['pinch'] = info => {
|
||||
this.pinchCamera(info.point, [0, 0], info.offset[0])
|
||||
this.app.viewport.pinchCamera(info.point, [0, 0], info.offset[0])
|
||||
}
|
||||
|
||||
onPinchEnd: TLEvents<S>['pinch'] = () => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Vec } from '@tldraw/vec'
|
||||
import type { TLEventMap, TLEventInfo, TLEvents } from '../../../../types'
|
||||
import type { TLShape } from '../../../shapes'
|
||||
import type { TLApp } from '../../../TLApp'
|
||||
@@ -22,16 +21,14 @@ export class PinchingState<
|
||||
> extends TLToolState<S, K, R, P> {
|
||||
static id = 'pinching'
|
||||
|
||||
private pinchCamera(point: number[], delta: number[], zoom: number) {
|
||||
onPinch: TLEvents<S>['pinch'] = (info, event: any) => {
|
||||
const { camera } = this.app.viewport
|
||||
const nextPoint = Vec.sub(camera.point, Vec.div(delta, camera.zoom))
|
||||
const p0 = Vec.sub(Vec.div(point, camera.zoom), nextPoint)
|
||||
const p1 = Vec.sub(Vec.div(point, zoom), nextPoint)
|
||||
this.app.setCamera(Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))), zoom)
|
||||
}
|
||||
|
||||
onPinch: TLEvents<S>['pinch'] = info => {
|
||||
this.pinchCamera(info.point, [0, 0], info.offset[0])
|
||||
// Normalize the value of deltaZ from raw WheelEvent
|
||||
const deltaZ = normalizeWheel(event)[2] * 0.01
|
||||
if (deltaZ === 0) return;
|
||||
const zoom = camera.zoom - deltaZ * camera.zoom;
|
||||
this.app.viewport.pinchCamera(info.point, [0, 0], zoom)
|
||||
}
|
||||
|
||||
onPinchEnd: TLEvents<S>['pinch'] = () => {
|
||||
@@ -42,3 +39,26 @@ export class PinchingState<
|
||||
this.tool.transition('idle')
|
||||
}
|
||||
}
|
||||
|
||||
// Adapted from https://stackoverflow.com/a/13650579
|
||||
function normalizeWheel(event: WheelEvent) {
|
||||
const MAX_ZOOM_STEP = 10
|
||||
const { deltaY, deltaX } = event
|
||||
|
||||
let deltaZ = 0
|
||||
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
const signY = Math.sign(event.deltaY)
|
||||
const absDeltaY = Math.abs(event.deltaY)
|
||||
|
||||
let dy = deltaY
|
||||
|
||||
if (absDeltaY > MAX_ZOOM_STEP) {
|
||||
dy = MAX_ZOOM_STEP * signY
|
||||
}
|
||||
|
||||
deltaZ = dy
|
||||
}
|
||||
|
||||
return [deltaX, deltaY, deltaZ]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user