kopia lustrzana https://github.com/Tldraw/Tldraw
Webgl minimap squares (#3533)
reopening #3528 @steveruizok plz start writing actual commit messages again 🙈 this was a bit harder to untangle because they were all 'ok' --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>pull/3510/head
rodzic
6b3c0514d8
commit
0a16bc3ae9
|
@ -8219,7 +8219,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
// it will be 0,0 when its actual screen position is equal
|
||||
// to screenBounds.point. This is confusing!
|
||||
currentScreenPoint.set(sx, sy)
|
||||
currentPagePoint.set(sx / cz - cx, sy / cz - cy, sz)
|
||||
const nx = sx / cz - cx
|
||||
const ny = sy / cz - cy
|
||||
if (isFinite(nx) && isFinite(ny)) {
|
||||
currentPagePoint.set(nx, ny, sz)
|
||||
}
|
||||
|
||||
this.inputs.isPen = info.type === 'pointer' && info.isPen
|
||||
|
||||
|
|
|
@ -57,8 +57,6 @@
|
|||
"@tldraw/store": "workspace:*",
|
||||
"canvas-size": "^1.2.6",
|
||||
"classnames": "^2.3.2",
|
||||
"earcut": "^2.2.4",
|
||||
"extrude-polyline": "^1.0.6",
|
||||
"hotkeys-js": "^3.11.2",
|
||||
"lz-string": "^1.4.4"
|
||||
},
|
||||
|
@ -72,7 +70,6 @@
|
|||
"@testing-library/react": "^14.0.0",
|
||||
"@types/canvas-size": "^1.2.0",
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/earcut": "^2.1.4",
|
||||
"@types/lz-string": "^1.3.34",
|
||||
"chokidar-cli": "^3.0.0",
|
||||
"jest-canvas-mock": "^2.5.2",
|
||||
|
|
|
@ -12,25 +12,25 @@ import {
|
|||
} from '@tldraw/editor'
|
||||
import { getRgba } from './getRgba'
|
||||
import { BufferStuff, appendVertices, setupWebGl } from './minimap-webgl-setup'
|
||||
import { pie, roundedRectangle } from './minimap-webgl-shapes'
|
||||
import { applyTransformToGeometry, triangulateGeometry } from './triangulateGeometry'
|
||||
import { pie, rectangle, roundedRectangle } from './minimap-webgl-shapes'
|
||||
|
||||
export class MinimapManager {
|
||||
disposables = [] as (() => void)[]
|
||||
close = () => this.disposables.forEach((d) => d())
|
||||
gl: ReturnType<typeof setupWebGl>
|
||||
geometryCache: ComputedCache<Float32Array, TLShape>
|
||||
shapeGeometryCache: ComputedCache<Float32Array | null, TLShape>
|
||||
constructor(
|
||||
public editor: Editor,
|
||||
public readonly elem: HTMLCanvasElement
|
||||
) {
|
||||
this.gl = setupWebGl(elem)
|
||||
this.geometryCache = editor.store.createComputedCache('webgl-geometry', (r: TLShape) => {
|
||||
const pageTransform = editor.getShapePageTransform(r.id)
|
||||
const triangles = triangulateGeometry(editor.getShapeGeometry(r.id))
|
||||
return applyTransformToGeometry(triangles, pageTransform)
|
||||
this.shapeGeometryCache = editor.store.createComputedCache('webgl-geometry', (r: TLShape) => {
|
||||
const bounds = editor.getShapeMaskedPageBounds(r.id)
|
||||
if (!bounds) return null
|
||||
const arr = new Float32Array(12)
|
||||
rectangle(arr, 0, bounds.x, bounds.y, bounds.w, bounds.h)
|
||||
return arr
|
||||
})
|
||||
|
||||
this.colors = this._getColors()
|
||||
this.disposables.push(this._listenForCanvasResize(), react('minimap render', this.render))
|
||||
}
|
||||
|
@ -168,13 +168,13 @@ export class MinimapManager {
|
|||
let { x: px, y: py } = this.getPagePoint(x, y)
|
||||
|
||||
if (clampToBounds) {
|
||||
const shapesPageBounds = this.editor.getCurrentPageBounds()
|
||||
const shapesPageBounds = this.editor.getCurrentPageBounds() ?? new Box()
|
||||
const vpPageBounds = viewportPageBounds
|
||||
|
||||
const minX = (shapesPageBounds?.minX ?? 0) - vpPageBounds.width / 2
|
||||
const maxX = (shapesPageBounds?.maxX ?? 0) + vpPageBounds.width / 2
|
||||
const minY = (shapesPageBounds?.minY ?? 0) - vpPageBounds.height / 2
|
||||
const maxY = (shapesPageBounds?.maxY ?? 0) + vpPageBounds.height / 2
|
||||
const minX = shapesPageBounds.minX - vpPageBounds.width / 2
|
||||
const maxX = shapesPageBounds.maxX + vpPageBounds.width / 2
|
||||
const minY = shapesPageBounds.minY - vpPageBounds.height / 2
|
||||
const maxY = shapesPageBounds.maxY + vpPageBounds.height / 2
|
||||
|
||||
const lx = Math.max(0, minX + vpPageBounds.width - px)
|
||||
const rx = Math.max(0, -(maxX - vpPageBounds.width - px))
|
||||
|
@ -247,8 +247,9 @@ export class MinimapManager {
|
|||
|
||||
const ids = this.editor.getCurrentPageShapeIdsSorted()
|
||||
|
||||
for (const shapeId of ids) {
|
||||
const geometry = this.geometryCache.get(shapeId)
|
||||
for (let i = 0, len = ids.length; i < len; i++) {
|
||||
const shapeId = ids[i]
|
||||
const geometry = this.shapeGeometryCache.get(shapeId)
|
||||
if (!geometry) continue
|
||||
|
||||
const len = geometry.length
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Box, Vec } from '@tldraw/editor'
|
||||
import { Box, HALF_PI, PI, PI2, Vec } from '@tldraw/editor'
|
||||
|
||||
export const numArcSegmentsPerCorner = 10
|
||||
|
||||
export const roundedRectangleDataSize =
|
||||
// num triangles in corners
|
||||
4 * 6 * numArcSegmentsPerCorner +
|
||||
|
@ -16,7 +17,7 @@ export function pie(
|
|||
radius,
|
||||
numArcSegments = 20,
|
||||
startAngle = 0,
|
||||
endAngle = Math.PI * 2,
|
||||
endAngle = PI2,
|
||||
offset = 0,
|
||||
}: {
|
||||
center: Vec
|
||||
|
@ -40,7 +41,8 @@ export function pie(
|
|||
return array
|
||||
}
|
||||
|
||||
function rectangle(
|
||||
/** @internal **/
|
||||
export function rectangle(
|
||||
array: Float32Array,
|
||||
offset: number,
|
||||
x: number,
|
||||
|
@ -98,8 +100,8 @@ export function roundedRectangle(data: Float32Array, box: Box, radius: number):
|
|||
offset,
|
||||
center: innerBox.point,
|
||||
radius,
|
||||
startAngle: Math.PI,
|
||||
endAngle: Math.PI * 1.5,
|
||||
startAngle: PI,
|
||||
endAngle: PI * 1.5,
|
||||
})
|
||||
|
||||
offset += numArcSegments * 6
|
||||
|
@ -110,8 +112,8 @@ export function roundedRectangle(data: Float32Array, box: Box, radius: number):
|
|||
offset,
|
||||
center: Vec.Add(innerBox.point, new Vec(innerBox.w, 0)),
|
||||
radius,
|
||||
startAngle: Math.PI * 1.5,
|
||||
endAngle: Math.PI * 2,
|
||||
startAngle: PI * 1.5,
|
||||
endAngle: PI2,
|
||||
})
|
||||
|
||||
offset += numArcSegments * 6
|
||||
|
@ -123,7 +125,7 @@ export function roundedRectangle(data: Float32Array, box: Box, radius: number):
|
|||
center: Vec.Add(innerBox.point, innerBox.size),
|
||||
radius,
|
||||
startAngle: 0,
|
||||
endAngle: Math.PI / 2,
|
||||
endAngle: HALF_PI,
|
||||
})
|
||||
|
||||
offset += numArcSegments * 6
|
||||
|
@ -134,8 +136,8 @@ export function roundedRectangle(data: Float32Array, box: Box, radius: number):
|
|||
offset,
|
||||
center: Vec.Add(innerBox.point, new Vec(0, innerBox.h)),
|
||||
radius,
|
||||
startAngle: Math.PI / 2,
|
||||
endAngle: Math.PI,
|
||||
startAngle: HALF_PI,
|
||||
endAngle: PI,
|
||||
})
|
||||
|
||||
return roundedRectangleDataSize
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
import { Geometry2d, Mat } from '@tldraw/editor'
|
||||
import earcut from 'earcut'
|
||||
// @ts-expect-error
|
||||
import extrudePolyline from 'extrude-polyline'
|
||||
|
||||
const stroke = extrudePolyline({
|
||||
thickness: 10, // this is in page space
|
||||
cap: 'square',
|
||||
join: 'bevel',
|
||||
miterLimit: 1,
|
||||
})
|
||||
|
||||
export function triangulateGeometry(geometry: Geometry2d) {
|
||||
const vertices = geometry.vertices
|
||||
if (!geometry.isClosed || !geometry.isFilled) {
|
||||
const points = vertices.map((v) => [v.x, v.y])
|
||||
if (geometry.isClosed) points.push([vertices[0].x, vertices[0].y])
|
||||
const triangles = stroke.build(points)
|
||||
const arr = new Float32Array(triangles.cells.length * 3 * 2)
|
||||
let j = 0
|
||||
for (const cell of triangles.cells) {
|
||||
arr[j++] = triangles.positions[cell[0]][0]
|
||||
arr[j++] = triangles.positions[cell[0]][1]
|
||||
|
||||
arr[j++] = triangles.positions[cell[1]][0]
|
||||
arr[j++] = triangles.positions[cell[1]][1]
|
||||
|
||||
arr[j++] = triangles.positions[cell[2]][0]
|
||||
arr[j++] = triangles.positions[cell[2]][1]
|
||||
}
|
||||
|
||||
return new Float32Array(arr)
|
||||
} else {
|
||||
const points = vertices.map((v) => [v.x, v.y]).flat()
|
||||
if (geometry.isClosed) points.push(vertices[0].x, vertices[0].y)
|
||||
const triangles = earcut(points)
|
||||
const arr = new Float32Array(triangles.length * 2)
|
||||
let j = 0
|
||||
for (const i of triangles) {
|
||||
arr[j * 2] = points[i * 2]
|
||||
arr[j * 2 + 1] = points[i * 2 + 1]
|
||||
j++
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
}
|
||||
|
||||
export function applyTransformToGeometry(geometry: Float32Array, transform: Mat) {
|
||||
const transformedGeometry = new Float32Array(geometry.length)
|
||||
for (let i = 0; i < transformedGeometry.length; i += 2) {
|
||||
;[transformedGeometry[i], transformedGeometry[i + 1]] = Mat.applyToXY(
|
||||
transform,
|
||||
geometry[i],
|
||||
geometry[i + 1]
|
||||
)
|
||||
}
|
||||
return transformedGeometry
|
||||
}
|
51
yarn.lock
51
yarn.lock
|
@ -7953,13 +7953,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/earcut@npm:^2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "@types/earcut@npm:2.1.4"
|
||||
checksum: 167e1c6d60e9d964d0f496c11b5065b9d155b4c1df04fb9abcec88af2c16213999ea8ed7cddeec9475620152e7e9e99a0f118e1c8070e1396cf0f299642beb6b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/eslint-scope@npm:^3.7.3":
|
||||
version: 3.7.7
|
||||
resolution: "@types/eslint-scope@npm:3.7.7"
|
||||
|
@ -9728,13 +9721,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"as-number@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "as-number@npm:1.0.0"
|
||||
checksum: 672e0593d170e00e0f2c4c62438be8dac9d01fb60b73dc7d1df82446704b77b6d02bf61c87e061ec0050408cb4157aa6b46021578fe0ff67d7a8085e9d673305
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"as-table@npm:^1.0.36":
|
||||
version: 1.0.55
|
||||
resolution: "as-table@npm:1.0.55"
|
||||
|
@ -11985,13 +11971,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"earcut@npm:^2.2.4":
|
||||
version: 2.2.4
|
||||
resolution: "earcut@npm:2.2.4"
|
||||
checksum: ca8b24714cc2fa67f98fbca6ddcf64bb42ee8d75d0b4f1a81486b3282b0f7f1bf9ec49ad4d02149985886a0c8a03a173463f2acb1f51fa0bb7ba2e1d4aa1254d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eastasianwidth@npm:^0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "eastasianwidth@npm:0.2.0"
|
||||
|
@ -13813,17 +13792,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"extrude-polyline@npm:^1.0.6":
|
||||
version: 1.0.6
|
||||
resolution: "extrude-polyline@npm:1.0.6"
|
||||
dependencies:
|
||||
as-number: "npm:^1.0.0"
|
||||
gl-vec2: "npm:^1.0.0"
|
||||
polyline-miter-util: "npm:^1.0.1"
|
||||
checksum: b44652bc25fe37979813b03e58f36c6ceb7661916d2e6f861f3652909c934d49e919e73ce8fabed7798432c3c61603f796f2ff9c030b49ae43cd072f104bbc45
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"extsprintf@npm:1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "extsprintf@npm:1.3.0"
|
||||
|
@ -14624,13 +14592,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"gl-vec2@npm:^1.0.0":
|
||||
version: 1.3.0
|
||||
resolution: "gl-vec2@npm:1.3.0"
|
||||
checksum: 6d5210d6c4288e1ea470c429d27967bec48a4305be2fa6a09db9f76d995b38eb78b71a27507d2703f97dad2376b317d7d2d970fdcc16feee6d463e592fe783fd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2":
|
||||
version: 5.1.2
|
||||
resolution: "glob-parent@npm:5.1.2"
|
||||
|
@ -20609,15 +20570,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"polyline-miter-util@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "polyline-miter-util@npm:1.0.1"
|
||||
dependencies:
|
||||
gl-vec2: "npm:^1.0.0"
|
||||
checksum: 50fef7e78575f31fd281fe8f9a7683de1e36672e5ba84bddc338c3cfcf6fd0270742ae68e33350fd3a47eb3befa457ef31eefc408778ad178532a626d45e8aaf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-discard-duplicates@npm:^5.1.0":
|
||||
version: 5.1.0
|
||||
resolution: "postcss-discard-duplicates@npm:5.1.0"
|
||||
|
@ -23588,13 +23540,10 @@ __metadata:
|
|||
"@tldraw/store": "workspace:*"
|
||||
"@types/canvas-size": "npm:^1.2.0"
|
||||
"@types/classnames": "npm:^2.3.1"
|
||||
"@types/earcut": "npm:^2.1.4"
|
||||
"@types/lz-string": "npm:^1.3.34"
|
||||
canvas-size: "npm:^1.2.6"
|
||||
chokidar-cli: "npm:^3.0.0"
|
||||
classnames: "npm:^2.3.2"
|
||||
earcut: "npm:^2.2.4"
|
||||
extrude-polyline: "npm:^1.0.6"
|
||||
hotkeys-js: "npm:^3.11.2"
|
||||
jest-canvas-mock: "npm:^2.5.2"
|
||||
jest-environment-jsdom: "npm:^29.4.3"
|
||||
|
|
Ładowanie…
Reference in New Issue