import { Bounds } from './objects/bounds'; import { Rectangle } from './objects/rectangle'; import { Container } from './objects/container'; import { CompObject } from './compObj'; import { Matrix } from './matrix'; import { Events } from "queenjs" import { RxValue } from '../ReactCtrl/rxValue'; import { DesignComp } from '../../objects/DesignTemp/DesignComp'; import { Transform } from './objects/transform'; import { history } from '../../objects/DesignTemp/factory'; import { designSizeToPx } from '../../module/utils'; type FnGetCompObj = (id:string)=>DesignComp; const AngleNames = [ "scaleBottomright", "scaleBottomleft", "scaleTopleft", "scaleTopright", ]; const EdgeNames = ["scaleright", "scaleleft", "scalebottom", "scaletop"]; export class Gizemo extends Events { aabb = new Bounds(); tempBound = new Bounds(); parent = new Container(); rect = new Rectangle(); pivotIndex = 0; selected:CompObject[] = []; history = history; state = RxValue.create({ transform: { selected: [] as string[], x: 0, y: 0, w: 0, h: 0, sx: 1, sy: 1, px: 0, py: 0, r: 0, }, lastId: "", scaleWidth: 1, scaleHeight: 1, mouse: "" }, this.history) lastSelChanged = false; getCompObj: FnGetCompObj; constructor(getCompObj: FnGetCompObj) { super() this.getCompObj = getCompObj; this.parent.sortableChildren = false; this.initGizmoEvent(); } get selectedIds() { return this.selected.map(item=>item.comp.id); } getBound() { //加上parent的旋转和平移 this.tempBound.clear(); this.tempBound.addFrame(this.parent.transform, 0, 0, this.width, this.height); return this.tempBound.getRectangle(); } get width() { return this.rect.width } get height() { return this.rect.height; } childSubs = [] as any[]; addChildWorldNoChange(child: CompObject) { const m = this.parent.worldTransform.clone(); m.invert(); const wm = child.worldTransform.clone(); wm.prepend(m); child.setMatrix(wm); this.parent.addChild(child); child.updateTransform(); } initGizmoEvent() { this.state.onTransformChanged((t, ot)=>{ if (t.selected != ot.selected) { this.destroy(); this.rect.width = t.w; this.rect.height = t.h; this.parent.width = t.w; this.parent.height = t.h; this.parent.setTransform(t.x, t.y, t.sx, t.sy, t.r, 0, 0, t.px, t.py) this.parent.updateTransform(); const objs :any= []; t.selected.forEach((oid) => { const obj = new CompObject(this.getCompObj(oid), true) let box = obj.calculateBounds(); this.aabb.addBounds(box); objs.push(obj); this.addChildWorldNoChange(obj); let first = true; const s= obj.state.onTransformChanged(()=>{ if (!first) this.updateSize(); first = false; }) this.childSubs.push(s); }); this.selected = objs; this.parent.updateTransform(); this.updateCompState(); this.emit("change"); return; } if (t.selected.length < 1) { this.destroy(); this.emit("change"); return; } //只是移动操作 this.parent.x = t.x; this.parent.y = t.y; this.rect.width = t.w; this.rect.height = t.h; this.parent.scale.x = t.sx; this.parent.scale.y = t.sy; this.parent.rotation = t.r; this.parent.pivot.x = t.px; this.parent.pivot.y = t.py; this.parent._boundsID++; this.parent.updateTransform(); this.updateCompState(); this.emit("change"); }) } initScaleSizeEvent() { this.state.onScaleWidthChanged((x)=>{ const prew = this.parent.scale.x * this.rect.width; //怎么改对应的偏移值 this.parent.scale.x = x const w = this.parent.scale.x * this.rect.width; this.parent.updateTransform(); this.applyChildWidth({scaleX: w / prew }) this.updateCompState(); this.emit("change"); }) } selectObjs(ids: string[], force=false) { let noChange = false; if (!force && this.selected.length == ids.length ) { if (ids.length == 0) { noChange = true; } else if (ids.length == 1) { if (ids[0] == this.selected[0].comp.id) { noChange = true; } } else { const id1 = ids.sort().join(""); const id2 = this.selected.map(item=>item.comp.id).sort().join(""); if (id1 == id2) { noChange = true; } } } this.lastSelChanged = !noChange; console.log("changing....", this.lastSelChanged); if (noChange) { return; } let n = ids.length; const selected = ids; let w = 0, h = 0, x = 0, y = 0, sx = 1 , sy = 1, r = 0, px=0, py=0; if (n == 1) { //单对象 let obj = new CompObject(this.getCompObj(selected[0])); w = obj.width; h = obj.height; const transform = new Transform(); transform.setFromMatrix(obj.worldTransform); x = transform.position.x; y = transform.position.y; sx = transform.scale.x; sy = transform.scale.y; r = transform.rotation; } else if (n>1) { const bound = new Bounds(); while (n--) { let obj = new CompObject(this.getCompObj(selected[n]) ); let box = obj.calculateBounds(); bound.addBounds(box); } //构建当前对象的转换矩阵 let rect = new Rectangle(); bound.getRectangle(rect); this.rect = rect; w = rect.width; h = rect.height; x = rect.x; y = rect.y; } this.state.setTransform({selected: ids, x, y, w, h, sx,sy, r, px, py}) } testClick(sx:number,sy:number) { let w = this.width; let h = this.height; let local = {x:0,y:0} as any; this.parent.worldTransform.applyInverse({x:sx,y:sy} as any, local); if( local.x < 0 || local.x > w ) return false; if( local.y < 0 || local.y > h ) return false; return true; } rotate(r:number, submit = false) { const t = {...this.state.transform}; t.r = r; this.state.setTransform(t); if (submit) this.history.submit(); } //index // 0 --5-- 1 // | | // 8 4 6 // | | // 3 --7---2 setPivot(index:number) { let rect = this.rect; let pivots = [ { x: 0, y: 0 }, { x: rect.width, y: 0 }, { x: rect.width, y: rect.height }, { x: 0, y: rect.height }, { x: rect.width / 2.0, y: rect.height / 2.0 }, { x: rect.width / 2.0, y: 0 }, { x: rect.width , y: rect.height / 2.0 }, { x: rect.width / 2.0 , y: rect.height}, { x: 0, y: rect.height / 2.0}, ]; let targetPivot = pivots[index]; let point = { x: targetPivot.x, y: targetPivot.y } as any; this.parent.worldTransform.apply(point, point); const t = {...this.state.transform}; t.px = targetPivot.x; t.py = targetPivot.y; t.x = point.x; t.y = point.y; this.pivotIndex = index; this.state.setTransform(t); return { x: point.x, y: point.y}; } setPivot2(x:number, y:number) { let targetPivot = {x, y} let point = { x, y } as any; this.parent.worldTransform.apply(point, point); const t = {...this.state.transform}; t.px = targetPivot.x; t.py = targetPivot.y; t.x = point.x; t.y = point.y; this.state.setTransform(t); return { x: point.x, y: point.y}; } getPivotXY(index:number) { let rect = this.rect; let pivots = [ { x: 0, y: 0 }, { x: rect.width, y: 0 }, { x: rect.width, y: rect.height }, { x: 0, y: rect.height }, { x: rect.width / 2.0, y: rect.height / 2.0 }, { x: rect.width / 2.0, y: 0 }, { x: rect.width , y: rect.height / 2.0 }, { x: rect.width / 2.0 , y: rect.height}, { x: 0, y: rect.height / 2.0}, ]; let targetPivot = pivots[index]; let point = { x: targetPivot.x, y: targetPivot.y } as any; this.parent.worldTransform.apply(point, point); let yIndex = 0, xIndex = 0; if (index == 3) { yIndex = 0; xIndex = 2; } else if (index == 0) { yIndex = 3; xIndex = 1; } else if (index == 1) { yIndex = 2; xIndex = 0; } else if (index == 2) { yIndex = 1; xIndex = 3; } let pointY = pivots[yIndex]; let pY = { x: pointY.x, y: pointY.y } as any; this.parent.worldTransform.apply(pY, pY); let pointX = pivots[xIndex]; let pX = { x: pointX.x, y: pointX.y } as any; this.parent.worldTransform.apply(pX, pX); let xVec = { x: (pX.x - point.x), y: (pX.y - point.y) }; let yVec = { x: (pY.x - point.x), y: (pY.y - point.y) }; return { x: xVec, y: yVec }; } scale(x:number, y:number, submit = false) { const t = {...this.state.transform}; t.sx = x; t.sy = y; this.state.setTransform(t); if (submit) this.history.submit(); } scaleX(x:number, submit= false) { const t = {...this.state.transform}; t.sx = x; this.state.setTransform(t); if (submit) this.history.submit(); } scaleY(y:number, submit= false) { const t = {...this.state.transform}; t.sy = y; this.state.setTransform(t); if (submit) this.history.submit(); } applyChildWidth(option:{scaleX?:number, scaleY?:number}) { if (this.selected.length < 1) return; const obj = this.selected[0]; //先移除 this.parent.removeChildWorldNoChange(obj); const m = new Matrix(); m.scale(option.scaleX ? option.scaleX : 1, option.scaleY? option.scaleY : 1) m.invert(); m.prepend(obj.worldTransform) obj.transform.setFromMatrix(m) if (option.scaleX) { obj.width = option.scaleX * obj.width; } if (option.scaleY) { obj.height = option.scaleY * obj.height; } obj.updateTransform(); this.parent.addChildWorldNoChange(obj); } scaleSize(x:number, y:number) { let preW = this.parent.scale.x * this.rect.width; let preH = this.parent.scale.y * this.rect.height; this.parent.scale.y = y this.parent.scale.x = x const Width = this.parent.scale.x * this.rect.width; const Height = this.parent.scale.y * this.rect.height; this.parent.updateTransform(); this.applyChildWidth({scaleX: Width / preW, scaleY: Height/preH}) this.updateCompState(); } scaleWidth(x:number) { this.state.setScaleWidth(x); } scaleHeight(y:number) { const preH = this.parent.scale.y * this.rect.height; this.parent.scale.y = y const h = this.parent.scale.y * this.rect.height; this.parent.updateTransform(); this.applyChildWidth({scaleY: h / preH}); this.updateCompState(); } translate(xOffset:number, yOffset:number, submit=false) { const t = {...this.state.transform}; t.x += xOffset; t.y += yOffset; this.state.setTransform(t); if (submit) this.history.submit(); } destroy() {//选中的对象坐标转到画布空间坐标 let selected = this.selected; let n = selected.length; while (n--) { let child = selected[n]; this.parent.removeChildWorldNoChange(child) child.comp.layout.transformMatrix = child.worldTransform.getMatrixStr(); } this.selected = []; this.parent.removeChildren(0, this.parent.children.length); //获取选择对象的aabb(画布空间) this.aabb.clear(); this.childSubs.forEach(s=>{ s.unsubscribe(); }) this.childSubs = []; } updateCompState() { let n = this.selected.length; while (n--) { let child = this.selected[n]; if (child.comp) child.comp.layout.transformMatrix = child.worldTransform.getMatrixStr(); } } reSelectCurrElemnts() { let t = {...this.state.transform} t.selected = this.state.transform.selected.slice(0) this.state.setTransform(t); } updateSize() { let selected = this.selected; let n = selected.length; this.setPivot(0) this.aabb.clear(); this.selected.forEach((obj) => { let box = obj.calculateBounds(); this.aabb.addBounds(box); }); this.aabb.getRectangle(this.rect); let x = this.rect.x, y = this.rect.y, sx = 1, sy= 1; if ( n == 1) { const s = selected[0].worldTransform.getScale(); sx = s.x; sy = s.y; } const r = n == 1 ?selected[0].rotation : 0; this.parent.setTransform(x, y, sx, sy, r, 0, 0, 0, 0); this.parent.updateTransform(); const w = n == 1 ? selected[0].width : this.rect.width; const h = n == 1 ? selected[0].height : this.rect.height; this.rect.width = w; this.rect.height = h; this.state.transform.w = w this.state.transform.h = h; this.state.transform.x = x; this.state.transform.y = y; this.state.transform.sx = sx; this.state.transform.sy = sy; this.state.transform.r = r; this.state.transform.px = 0; this.state.transform.py = 0; this.emit("change"); } }