draw transform from action instead of stage
This commit is contained in:
parent
f0e0546a66
commit
c2e99866cf
283
src/main.js
283
src/main.js
|
|
@ -769,10 +769,167 @@ let actions = {
|
||||||
updateLayers()
|
updateLayers()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
transformObjects: {
|
||||||
|
initialize: (frame, _selection, direction, mouse, transform=undefined) => {
|
||||||
|
let bbox = undefined
|
||||||
|
const selection = {}
|
||||||
|
for (let item of _selection) {
|
||||||
|
if (bbox==undefined) {
|
||||||
|
bbox = getRotatedBoundingBox(item)
|
||||||
|
} else {
|
||||||
|
growBoundingBox(bbox, getRotatedBoundingBox(item))
|
||||||
|
}
|
||||||
|
selection[item.idx] = {x: item.x, y: item.y, scale_x: item.scale_x, scale_y: item.scale_y, rotation: item.rotation}
|
||||||
|
}
|
||||||
|
let action = {
|
||||||
|
type: "transformObjects",
|
||||||
|
oldState: structuredClone(frame.keys),
|
||||||
|
frame: frame.idx,
|
||||||
|
transform: {
|
||||||
|
initial: {
|
||||||
|
x: {min: bbox.x.min, max: bbox.x.max},
|
||||||
|
y: {min: bbox.y.min, max: bbox.y.max},
|
||||||
|
rotation: 0,
|
||||||
|
mouse: {x: mouse.x, y: mouse.y},
|
||||||
|
selection: selection
|
||||||
|
},
|
||||||
|
current: {
|
||||||
|
x: {min: bbox.x.min, max: bbox.x.max},
|
||||||
|
y: {min: bbox.y.min, max: bbox.y.max},
|
||||||
|
scale_x: 1,
|
||||||
|
scale_y: 1,
|
||||||
|
rotation: 0,
|
||||||
|
mouse: {x: mouse.x, y: mouse.y},
|
||||||
|
selection: structuredClone(selection)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selection: selection,
|
||||||
|
direction: direction
|
||||||
|
}
|
||||||
|
if (transform) {
|
||||||
|
action.transform = transform
|
||||||
|
}
|
||||||
|
return action
|
||||||
|
},
|
||||||
|
update: (action, mouse) => {
|
||||||
|
const initial = action.transform.initial
|
||||||
|
const current = action.transform.current
|
||||||
|
console.log(action.direction)
|
||||||
|
if (action.direction.indexOf('n') != -1) {
|
||||||
|
current.y.min = mouse.y
|
||||||
|
} else if (action.direction.indexOf('s') != -1) {
|
||||||
|
current.y.max = mouse.y
|
||||||
|
}
|
||||||
|
if (action.direction.indexOf('w') != -1) {
|
||||||
|
current.x.min = mouse.x
|
||||||
|
} else if (action.direction.indexOf('e') != -1) {
|
||||||
|
current.x.max = mouse.x
|
||||||
|
}
|
||||||
|
if (context.dragDirection == 'r') {
|
||||||
|
const pivot = {
|
||||||
|
x: (initial.x.min+initial.x.max)/2,
|
||||||
|
y: (initial.y.min+initial.y.max)/2,
|
||||||
|
}
|
||||||
|
current.rotation = signedAngleBetweenVectors(pivot, initial.mouse, mouse)
|
||||||
|
const {dx, dy} = rotateAroundPointIncremental(current.x.min, current.y.min, pivot, current.rotation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the scaling factor based on the difference between current and initial values
|
||||||
|
action.transform.current.scale_x = (current.x.max - current.x.min) / (initial.x.max - initial.x.min);
|
||||||
|
action.transform.current.scale_y = (current.y.max - current.y.min) / (initial.y.max - initial.y.min);
|
||||||
|
return action
|
||||||
|
},
|
||||||
|
render: (action, ctx) => {
|
||||||
|
const initial = action.transform.initial
|
||||||
|
const current = action.transform.current
|
||||||
|
ctx.save()
|
||||||
|
ctx.translate((current.x.max+current.x.min)/2, (current.y.max - current.y.min)/2)
|
||||||
|
ctx.rotate(current.rotation)
|
||||||
|
ctx.translate(-(current.x.max+current.x.min)/2, -(current.y.max - current.y.min)/2)
|
||||||
|
console.log(action.selection)
|
||||||
|
const cxt = {
|
||||||
|
ctx: ctx,
|
||||||
|
selection: [],
|
||||||
|
shapeselection: []
|
||||||
|
}
|
||||||
|
for (let obj in action.selection) {
|
||||||
|
const object = pointerList[obj]
|
||||||
|
object.draw(cxt)
|
||||||
|
}
|
||||||
|
ctx.strokeStyle = '#00ffff'
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.rect(current.x.min, current.y.min, current.x.max-current.x.min, current.y.max-current.y.min)
|
||||||
|
ctx.stroke()
|
||||||
|
ctx.fillStyle = "#000000"
|
||||||
|
const rectRadius = 5
|
||||||
|
const xdiff = current.x.max - current.x.min
|
||||||
|
const ydiff = current.y.max - current.y.min
|
||||||
|
for (let i of [[0,0],[0.5,0],[1,0],[1,0.5],[1,1],[0.5,1],[0,1],[0,0.5]]) {
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.rect(
|
||||||
|
current.x.min + xdiff * i[0] - rectRadius,
|
||||||
|
current.y.min + ydiff * i[1] - rectRadius,
|
||||||
|
rectRadius*2, rectRadius*2
|
||||||
|
)
|
||||||
|
ctx.fill()
|
||||||
|
}
|
||||||
|
ctx.restore()
|
||||||
|
},
|
||||||
|
finalize: (action) => {
|
||||||
|
undoStack.push({name: "transformObjects", action: action})
|
||||||
|
actions.transformObjects.execute(action)
|
||||||
|
context.activeAction = undefined
|
||||||
|
updateMenu()
|
||||||
|
},
|
||||||
|
execute: (action) => {
|
||||||
|
const frame = pointerList[action.frame]
|
||||||
|
const initial = action.transform.initial
|
||||||
|
const current = action.transform.current
|
||||||
|
const delta_x = current.x.min - initial.x.min;
|
||||||
|
const delta_y = current.y.min - initial.y.min;
|
||||||
|
const delta_rot = current.rotation - initial.rotation
|
||||||
|
// frame.keys = structuredClone(action.newState)
|
||||||
|
console.log(action)
|
||||||
|
for (let idx in action.selection) {
|
||||||
|
const item = frame.keys[idx]
|
||||||
|
const xoffset = action.selection[idx].x - initial.x.min
|
||||||
|
const yoffset = action.selection[idx].y - initial.y.min
|
||||||
|
item.x = initial.x.min + delta_x + xoffset * current.scale_x
|
||||||
|
item.y = initial.y.min + delta_y + yoffset * current.scale_y
|
||||||
|
item.scale_x = action.selection[idx].scale_x * current.scale_x
|
||||||
|
item.scale_y = action.selection[idx].scale_y * current.scale_y
|
||||||
|
item.rotation = action.selection[idx].rotation + delta_rot
|
||||||
|
}
|
||||||
|
updateUI()
|
||||||
|
},
|
||||||
|
rollback: (action) => {
|
||||||
|
let frame = pointerList[action.frame]
|
||||||
|
frame.keys = structuredClone(action.oldState)
|
||||||
|
updateUI()
|
||||||
|
}
|
||||||
|
},
|
||||||
editFrame: {
|
editFrame: {
|
||||||
|
initialize: (frame) => {
|
||||||
|
let action = {
|
||||||
|
type: "editFrame",
|
||||||
|
oldState: structuredClone(frame.keys),
|
||||||
|
frame: frame.idx
|
||||||
|
}
|
||||||
|
return action
|
||||||
|
},
|
||||||
|
finalize: (action, frame) => {
|
||||||
|
action.newState = structuredClone(frame.keys)
|
||||||
|
undoStack.push({name: "editFrame", action: action})
|
||||||
|
actions.editFrame.execute(action)
|
||||||
|
context.activeAction = undefined
|
||||||
|
updateMenu()
|
||||||
|
},
|
||||||
|
render: (action, ctx) => {
|
||||||
|
|
||||||
|
},
|
||||||
create: (frame) => {
|
create: (frame) => {
|
||||||
redoStack.length = 0; // Clear redo stack
|
redoStack.length = 0; // Clear redo stack
|
||||||
console.log(frame.idx in startProps)
|
|
||||||
if (!(frame.idx in startProps)) return;
|
if (!(frame.idx in startProps)) return;
|
||||||
let action = {
|
let action = {
|
||||||
newState: structuredClone(frame.keys),
|
newState: structuredClone(frame.keys),
|
||||||
|
|
@ -2652,12 +2809,14 @@ class GraphicsObject {
|
||||||
}
|
}
|
||||||
draw(context) {
|
draw(context) {
|
||||||
let ctx = context.ctx;
|
let ctx = context.ctx;
|
||||||
|
ctx.save()
|
||||||
ctx.translate(this.x, this.y)
|
ctx.translate(this.x, this.y)
|
||||||
ctx.rotate(this.rotation)
|
ctx.rotate(this.rotation)
|
||||||
ctx.scale(this.scale_x, this.scale_y)
|
ctx.scale(this.scale_x, this.scale_y)
|
||||||
// if (this.currentFrameNum>=this.maxFrame) {
|
// if (this.currentFrameNum>=this.maxFrame) {
|
||||||
// this.currentFrameNum = 0;
|
// this.currentFrameNum = 0;
|
||||||
// }
|
// }
|
||||||
|
if (context.activeAction && this.idx in context.activeAction.selection) return;
|
||||||
for (let layer of this.layers) {
|
for (let layer of this.layers) {
|
||||||
if (context.activeObject==this && !layer.visible) continue;
|
if (context.activeObject==this && !layer.visible) continue;
|
||||||
let frame = layer.getFrame(this.currentFrameNum)
|
let frame = layer.getFrame(this.currentFrameNum)
|
||||||
|
|
@ -2790,6 +2949,7 @@ class GraphicsObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctx.restore()
|
||||||
}
|
}
|
||||||
transformMouse(mouse) {
|
transformMouse(mouse) {
|
||||||
if (this.parent) {
|
if (this.parent) {
|
||||||
|
|
@ -3754,7 +3914,7 @@ function stage() {
|
||||||
if (hitTest(mouse, child)) {
|
if (hitTest(mouse, child)) {
|
||||||
context.dragging = true
|
context.dragging = true
|
||||||
context.lastMouse = mouse
|
context.lastMouse = mouse
|
||||||
context.activeObject.currentFrame.saveState()
|
context.activeAction = actions.editFrame.initialize(context.activeObject.currentFrame)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3777,7 +3937,7 @@ function stage() {
|
||||||
}
|
}
|
||||||
context.dragging = true
|
context.dragging = true
|
||||||
selected = true
|
selected = true
|
||||||
context.activeObject.currentFrame.saveState()
|
context.activeAction = actions.editFrame.initialize(context.activeObject.currentFrame)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3825,7 +3985,12 @@ function stage() {
|
||||||
selection: structuredClone(selection)
|
selection: structuredClone(selection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.activeObject.currentFrame.saveState()
|
context.activeAction = actions.transformObjects.initialize(
|
||||||
|
context.activeObject.currentFrame,
|
||||||
|
context.selection,
|
||||||
|
transformPoint,
|
||||||
|
mouse
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
transformPoint = getPointNearBox(bbox, mouse, 30, false)
|
transformPoint = getPointNearBox(bbox, mouse, 30, false)
|
||||||
if (transformPoint) {
|
if (transformPoint) {
|
||||||
|
|
@ -3847,7 +4012,12 @@ function stage() {
|
||||||
selection: structuredClone(selection)
|
selection: structuredClone(selection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.activeObject.currentFrame.saveState()
|
context.activeAction = actions.transformObjects.initialize(
|
||||||
|
context.activeObject.currentFrame,
|
||||||
|
context.selection,
|
||||||
|
'r',
|
||||||
|
mouse
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
stage.style.cursor = "default"
|
stage.style.cursor = "default"
|
||||||
}
|
}
|
||||||
|
|
@ -3950,7 +4120,9 @@ function stage() {
|
||||||
context.activeShape = undefined
|
context.activeShape = undefined
|
||||||
break;
|
break;
|
||||||
case "select":
|
case "select":
|
||||||
if (context.activeVertex) {
|
if (context.activeAction) {
|
||||||
|
actions[context.activeAction.type].finalize(context.activeAction, context.activeObject.currentFrame)
|
||||||
|
} else if (context.activeVertex) {
|
||||||
let newCurves = []
|
let newCurves = []
|
||||||
for (let i in context.activeVertex.shape.curves) {
|
for (let i in context.activeVertex.shape.curves) {
|
||||||
if (i in context.activeVertex.current.startCurves) {
|
if (i in context.activeVertex.current.startCurves) {
|
||||||
|
|
@ -3974,13 +4146,16 @@ function stage() {
|
||||||
actions.editShape.create(context.activeCurve.shape, newCurves)
|
actions.editShape.create(context.activeCurve.shape, newCurves)
|
||||||
} else if (context.selection.length) {
|
} else if (context.selection.length) {
|
||||||
actions.select.create()
|
actions.select.create()
|
||||||
actions.editFrame.create(context.activeObject.currentFrame)
|
// actions.editFrame.create(context.activeObject.currentFrame)
|
||||||
} else if (context.shapeselection.length) {
|
} else if (context.shapeselection.length) {
|
||||||
actions.select.create()
|
actions.select.create()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "transform":
|
case "transform":
|
||||||
actions.editFrame.create(context.activeObject.currentFrame)
|
if (context.activeAction) {
|
||||||
|
actions[context.activeAction.type].finalize(context.activeAction, context.activeObject.currentFrame)
|
||||||
|
}
|
||||||
|
// actions.editFrame.create(context.activeObject.currentFrame)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -4166,53 +4341,56 @@ function stage() {
|
||||||
stage.style.cursor = "default"
|
stage.style.cursor = "default"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (context.dragDirection) {
|
// if (context.dragDirection) {
|
||||||
let initial = context.activeTransform.initial
|
// let initial = context.activeTransform.initial
|
||||||
let current = context.activeTransform.current
|
// let current = context.activeTransform.current
|
||||||
let initialSelection = context.activeTransform.initial.selection
|
// let initialSelection = context.activeTransform.initial.selection
|
||||||
if (context.dragDirection.indexOf('n') != -1) {
|
// if (context.dragDirection.indexOf('n') != -1) {
|
||||||
current.y.min = mouse.y
|
// current.y.min = mouse.y
|
||||||
} else if (context.dragDirection.indexOf('s') != -1) {
|
// } else if (context.dragDirection.indexOf('s') != -1) {
|
||||||
current.y.max = mouse.y
|
// current.y.max = mouse.y
|
||||||
}
|
// }
|
||||||
if (context.dragDirection.indexOf('w') != -1) {
|
// if (context.dragDirection.indexOf('w') != -1) {
|
||||||
current.x.min = mouse.x
|
// current.x.min = mouse.x
|
||||||
} else if (context.dragDirection.indexOf('e') != -1) {
|
// } else if (context.dragDirection.indexOf('e') != -1) {
|
||||||
current.x.max = mouse.x
|
// current.x.max = mouse.x
|
||||||
}
|
// }
|
||||||
// Calculate the translation difference between current and initial values
|
// // Calculate the translation difference between current and initial values
|
||||||
let delta_x = current.x.min - initial.x.min;
|
// let delta_x = current.x.min - initial.x.min;
|
||||||
let delta_y = current.y.min - initial.y.min;
|
// let delta_y = current.y.min - initial.y.min;
|
||||||
|
|
||||||
if (context.dragDirection == 'r') {
|
// if (context.dragDirection == 'r') {
|
||||||
let pivot = {
|
// let pivot = {
|
||||||
x: (initial.x.min+initial.x.max)/2,
|
// x: (initial.x.min+initial.x.max)/2,
|
||||||
y: (initial.y.min+initial.y.max)/2,
|
// y: (initial.y.min+initial.y.max)/2,
|
||||||
}
|
// }
|
||||||
current.rotation = signedAngleBetweenVectors(pivot, initial.mouse, mouse)
|
// current.rotation = signedAngleBetweenVectors(pivot, initial.mouse, mouse)
|
||||||
const {dx, dy} = rotateAroundPointIncremental(current.x.min, current.y.min, pivot, current.rotation)
|
// const {dx, dy} = rotateAroundPointIncremental(current.x.min, current.y.min, pivot, current.rotation)
|
||||||
// delta_x -= dx
|
// // delta_x -= dx
|
||||||
// delta_y -= dy
|
// // delta_y -= dy
|
||||||
// console.log(dx, dy)
|
// // console.log(dx, dy)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// This is probably unnecessary since initial rotation is 0
|
// // This is probably unnecessary since initial rotation is 0
|
||||||
const delta_rot = current.rotation - initial.rotation
|
// const delta_rot = current.rotation - initial.rotation
|
||||||
|
|
||||||
// Calculate the scaling factor based on the difference between current and initial values
|
// // Calculate the scaling factor based on the difference between current and initial values
|
||||||
const scale_x_ratio = (current.x.max - current.x.min) / (initial.x.max - initial.x.min);
|
// const scale_x_ratio = (current.x.max - current.x.min) / (initial.x.max - initial.x.min);
|
||||||
const scale_y_ratio = (current.y.max - current.y.min) / (initial.y.max - initial.y.min);
|
// const scale_y_ratio = (current.y.max - current.y.min) / (initial.y.max - initial.y.min);
|
||||||
|
|
||||||
for (let idx in initialSelection) {
|
// for (let idx in initialSelection) {
|
||||||
let item = context.activeObject.currentFrame.keys[idx]
|
// let item = context.activeObject.currentFrame.keys[idx]
|
||||||
let xoffset = initialSelection[idx].x - initial.x.min
|
// let xoffset = initialSelection[idx].x - initial.x.min
|
||||||
let yoffset = initialSelection[idx].y - initial.y.min
|
// let yoffset = initialSelection[idx].y - initial.y.min
|
||||||
item.x = initial.x.min + delta_x + xoffset * scale_x_ratio
|
// item.x = initial.x.min + delta_x + xoffset * scale_x_ratio
|
||||||
item.y = initial.y.min + delta_y + yoffset * scale_y_ratio
|
// item.y = initial.y.min + delta_y + yoffset * scale_y_ratio
|
||||||
item.scale_x = initialSelection[idx].scale_x * scale_x_ratio
|
// item.scale_x = initialSelection[idx].scale_x * scale_x_ratio
|
||||||
item.scale_y = initialSelection[idx].scale_y * scale_y_ratio
|
// item.scale_y = initialSelection[idx].scale_y * scale_y_ratio
|
||||||
item.rotation = initialSelection[idx].rotation + delta_rot
|
// item.rotation = initialSelection[idx].rotation + delta_rot
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
if (context.activeAction) {
|
||||||
|
actions[context.activeAction.type].update(context.activeAction, mouse)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -5224,6 +5402,9 @@ function renderUI() {
|
||||||
ctx.arc(point.x, point.y, 3, 0, 2*Math.PI)
|
ctx.arc(point.x, point.y, 3, 0, 2*Math.PI)
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
}
|
}
|
||||||
|
if (context.activeAction) {
|
||||||
|
actions[context.activeAction.type].render(context.activeAction, ctx)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
for (let selectionRect of document.querySelectorAll(".selectionRect")) {
|
for (let selectionRect of document.querySelectorAll(".selectionRect")) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue