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
David Sheldrick 2024-04-19 14:49:15 +01:00 zatwierdzone przez GitHub
rodzic 6b3c0514d8
commit 0a16bc3ae9
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
6 zmienionych plików z 33 dodań i 139 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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",

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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"