Skip to content

Commit

Permalink
feat: TransformRect2D
Browse files Browse the repository at this point in the history
  • Loading branch information
qq15725 committed Jan 21, 2025
1 parent d66d69b commit db9e8eb
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 65 deletions.
96 changes: 50 additions & 46 deletions src/editor/CanvasItemEditor.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import type { InputEvent, InputEventKey, PointerInputEvent, PropertyDeclaration } from '../core'
import type { CanvasItem, CanvasItemStyle } from '../scene'
import { Control, Node2D, Ruler, Scaler, XScrollBar, YScrollBar } from '../scene'
import { Control, Node2D, Ruler, Scaler, TransformRect2D, XScrollBar, YScrollBar } from '../scene'

export class CanvasItemEditor extends Control {
protected _pointerStart?: CanvasItemStyle
protected _pointerOffset?: { x: number, y: number }
selected?: CanvasItem
dragging?: CanvasItem
hovered?: CanvasItem

hover = new Node2D({
name: 'hover',
internalMode: 'back',
Expand All @@ -15,30 +21,21 @@ export class CanvasItemEditor extends Control {
},
})

selectionRect = new Node2D({
name: 'selectionRect',
transformRect = new TransformRect2D({
name: 'transformRect',
internalMode: 'back',
style: {
visibility: 'hidden',
width: 1,
height: 1,
backgroundColor: 0x00FF000F,
outlineStyle: 'solid',
outlineColor: 0x00FF00FF,
outlineWidth: 2,
pointerEvents: 'none',
},
})

selector = new Node2D({
name: 'selector',
})

scaler = new Scaler({
internalMode: 'back',
}).on('updateScale', (scale) => {
this.ruler.scale = scale
this._updateScrollbars()
this._updateSelectionRect()
})

xScrollBar = new XScrollBar({
Expand Down Expand Up @@ -76,15 +73,11 @@ export class CanvasItemEditor extends Control {
}, [
this.drawboard,
this.hover,
this.selectionRect,
this.transformRect,
this.xScrollBar,
this.yScrollBar,
])

protected _pointerStart?: CanvasItemStyle
protected _pointerOffset?: { x: number, y: number }
selected?: CanvasItem

constructor() {
super()
this._onPointerdown = this._onPointerdown.bind(this)
Expand Down Expand Up @@ -127,60 +120,71 @@ export class CanvasItemEditor extends Control {
protected _onPointerdown(e: PointerInputEvent): void {
const target = e.target
this._pointerOffset = { x: e.offsetX, y: e.offsetY }
this.selected = target
this.dragging = target
if (target instanceof Node2D) {
this.selected = target
this._pointerStart = target.style.clone()
}
else {
this.selected = undefined
this._pointerStart = undefined
this.selectionRect.style.visibility = 'visible'
this.selectionRect.style.left = e.screen.x
this.selectionRect.style.top = e.screen.y
this.selectionRect.style.width = 1
this.selectionRect.style.height = 1
}
this._onHover()
this._updateHover()
this._updateSelectionRect()
}

protected _onPointermove(e: PointerInputEvent): void {
const { selected, _pointerStart, _pointerOffset } = this
const target = e.target
const { selected, dragging, _pointerStart, _pointerOffset } = this
if (selected && target?.is(selected)) {
this.hovered = undefined
}
else {
this.hovered = target
}
const offset = _pointerOffset
? { x: (e.offsetX - _pointerOffset.x), y: (e.offsetY - _pointerOffset.y) }
: { x: 0, y: 0 }
if (selected && _pointerStart) {
selected.style.left = _pointerStart.left + offset.x
selected.style.top = _pointerStart.top + offset.y
}
else {
if (this.selectionRect.isVisibleInTree()) {
this.selectionRect.style.width = offset.x
this.selectionRect.style.height = offset.y
}
if (dragging && _pointerStart) {
dragging.style.left = _pointerStart.left + offset.x
dragging.style.top = _pointerStart.top + offset.y
}
this._onHover()
this._updateHover()
this._updateSelectionRect()
}

protected _onPointerup(): void {
this.selected = undefined
this.selectionRect.style.visibility = 'hidden'
this._onHover()
this.dragging = undefined
this._updateHover()
this._updateSelectionRect()
}

protected _onHover(): void {
const selected = this.selected
if (selected instanceof Node2D) {
protected _updateHover(): void {
const hovered = this.hovered
if (hovered instanceof Node2D) {
this.hover.style.visibility = 'visible'
this.hover.style.width = selected.style.width
this.hover.style.height = selected.style.height
this.hover.transform.set(selected.transform)
this.hover.style.width = hovered.style.width
this.hover.style.height = hovered.style.height
this.hover.transform.set(hovered.transform)
this.hover.requestRedraw()
}
else {
this.hover.style.visibility = 'hidden'
}
}

protected _updateSelectionRect(): void {
if (this.selected) {
this.transformRect.style.visibility = 'visible'
this.transformRect.style.width = this.selected.style.width
this.transformRect.style.height = this.selected.style.height
this.transformRect.transform.set((this.selected as Node2D).transform)
this.transformRect.requestReflow()
}
else {
this.transformRect.style.visibility = 'hidden'
}
}

protected _updateScrollbars(): void {
const scale = this.ruler.scale
const scrollHeight = this.drawboard.style.height * scale
Expand Down
6 changes: 3 additions & 3 deletions src/scene/2d/Node2D.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { InputEvent, InputEventKey, PointerInputEvent } from '../../core'
import type { InputEvent, InputEventKey, PointerInputEvent, PropertyDeclaration } from '../../core'
import type { CanvasBatchable, CanvasItemProperties, Node } from '../main'
import { customNode, Rect2, Transform2D } from '../../core'
import { CanvasItem } from '../main'
Expand All @@ -20,8 +20,8 @@ export class Node2D extends CanvasItem {
.append(children)
}

protected override _updateStyleProperty(key: PropertyKey, value: any, oldValue: any): void {
super._updateStyleProperty(key, value, oldValue)
protected _updateStyleProperty(key: PropertyKey, value: any, oldValue: any, declaration?: PropertyDeclaration): void {
super._updateStyleProperty(key, value, oldValue, declaration)

switch (key) {
case 'width':
Expand Down
58 changes: 58 additions & 0 deletions src/scene/2d/TransformRect2D.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { PropertyDeclaration } from '../../core'
import type { Rectangulable } from '../main/interfaces'
import type { Node2DProperties } from './Node2D'
import { property } from '../../core'
import { Texture2D } from '../resources'
import { Node2D } from './Node2D'

export interface TransformRect2DProperties extends Node2DProperties {
//
}

export class TransformRect2D extends Node2D implements Rectangulable {
@property({ default: 6 }) declare size: number

protected _updateStyleProperty(key: PropertyKey, value: any, oldValue: any, declaration?: PropertyDeclaration): void {
super._updateStyleProperty(key, value, oldValue, declaration)

switch (key) {
case 'width':
case 'height':
this.requestRedraw()
break
}
}

protected _drawCircle(x: number, y: number): void {
this.context.arc(x, y, this.size, 0, Math.PI * 2, true)
this.context.fillStyle = Texture2D.WHITE
this.context.fill()

this.context.arc(x, y, this.size, 0, Math.PI * 2, true)
this.context.strokeStyle = 'rgba(0, 0, 0, 0.2)'
this.context.stroke()
}

protected _drawEllipse(x: number, y: number): void {
this.context.roundRect(x - this.size, y - this.size * 2, this.size * 2, this.size * 4, this.size)
this.context.fillStyle = Texture2D.WHITE
this.context.fill()

this.context.roundRect(x - this.size, y - this.size * 2, this.size * 2, this.size * 4, this.size)
this.context.strokeStyle = 'rgba(0, 0, 0, 0.2)'
this.context.stroke()
}

protected override _draw(): void {
const { width, height } = this.style
this.context.rect(0, 0, width, height)
this.context.strokeStyle = '#00FF00'
this.context.stroke()
this._drawCircle(0, 0)
this._drawCircle(width, height)
this._drawCircle(0, height)
this._drawEllipse(0, height / 2)
this._drawCircle(width, 0)
this._drawEllipse(width, height / 2)
}
}
1 change: 1 addition & 0 deletions src/scene/2d/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from './Lottie2D'
export * from './Node2D'
export * from './Text2D'
export * from './TextureRect2D'
export * from './TransformRect2D'
export * from './Video2D'
37 changes: 21 additions & 16 deletions src/scene/main/CanvasContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export class CanvasContext extends Path2D {
miterLimit?: number

_defaultStyle = Texture2D.EMPTY
_stroke: StrokedGraphics[] = []
_fille: FilledGraphics[] = []
_strokes: StrokedGraphics[] = []
_fills: FilledGraphics[] = []

stroke(): void {
let texture: Texture2D = this._defaultStyle
Expand All @@ -47,7 +47,7 @@ export class CanvasContext extends Path2D {
}

if (this.curves.length) {
this._stroke.push({
this._strokes.push({
path: new Path2D(this),
texture,
textureTransform: this.textureTransform,
Expand Down Expand Up @@ -86,7 +86,7 @@ export class CanvasContext extends Path2D {
texture = new ColorTexture(this.fillStyle)
}
}
this._fille.push({
this._fills.push({
path: new Path2D(this),
texture,
textureTransform: this.textureTransform,
Expand All @@ -104,8 +104,8 @@ export class CanvasContext extends Path2D {
this.lineJoin = source.lineJoin
this.lineWidth = source.lineWidth
this.miterLimit = source.miterLimit
this._stroke = source._stroke.slice()
this._fille = source._fille.slice()
this._strokes = source._strokes.slice()
this._fills = source._fills.slice()
return this
}

Expand All @@ -118,8 +118,8 @@ export class CanvasContext extends Path2D {
this.lineJoin = undefined
this.lineWidth = undefined
this.miterLimit = undefined
this._stroke.length = 0
this._fille.length = 0
this._strokes.length = 0
this._fills.length = 0
return this
}

Expand Down Expand Up @@ -154,6 +154,7 @@ export class CanvasContext extends Path2D {
let uvs: number[] = []
let startUv = 0
let texture: Texture2D | undefined
let verticesLen = vertices.length

const push = (type: CanvasBatchable['type']): void => {
batchables.push({
Expand All @@ -167,14 +168,15 @@ export class CanvasContext extends Path2D {
indices = []
uvs = []
texture = undefined
verticesLen = vertices.length
}

let verticesLen = vertices.length

for (let len = this._fille.length, i = 0; i < len; i++) {
const graphics = this._fille[i]
texture ??= graphics.texture
if (texture !== graphics.texture) {
for (let len = this._fills.length, i = 0; i < len; i++) {
const graphics = this._fills[i]
if (!texture) {
texture = graphics.texture
}
else if (!texture.is(graphics.texture)) {
push('fill')
}
startUv = vertices.length
Expand All @@ -183,6 +185,9 @@ export class CanvasContext extends Path2D {
indices,
})
this.buildUvs(startUv, vertices, uvs, graphics.texture, graphics.textureTransform)
if (!texture) {
texture = graphics.texture
}
}

if (vertices.length - verticesLen > 0) {
Expand All @@ -191,9 +196,9 @@ export class CanvasContext extends Path2D {

verticesLen = vertices.length

for (let len = this._stroke.length, i = 0; i < len; i++) {
for (let len = this._strokes.length, i = 0; i < len; i++) {
startUv = vertices.length
const graphics = this._stroke[i]
const graphics = this._strokes[i]
texture ??= graphics.texture
graphics.path.strokeTriangulate({
vertices,
Expand Down

0 comments on commit db9e8eb

Please sign in to comment.