index.ts 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. import { Effect, ModuleControl } from "queenjs";
  2. import { reactive } from "vue";
  3. import { EditorModule } from "../../module";
  4. import { ObjsContainer } from "./ObjsContainer";
  5. import { CompObject } from "./compObj";
  6. import Event from "./event";
  7. import { Matrix } from "./matrix";
  8. import { Project, VectorLenth } from "./objects/mathUtils";
  9. import { Point } from "./objects/point";
  10. import { indexOf } from "lodash";
  11. /**
  12. * 页面画布空间进行选择
  13. */
  14. const MODE_SEL_RECT = 1;
  15. const MODE_MOVING = 2;
  16. const MODE_ROTATE = 3;
  17. const MODE_SCALE_WIDTH = 4;
  18. const MODE_SCALE_SCALE = 5;
  19. const MODE_NONE = 0;
  20. export class SelectCtrl extends ModuleControl<EditorModule> {
  21. transEvent = {
  22. startX: 0,
  23. startY: 0,
  24. offsetX: 0,
  25. offsetY: 0,
  26. width: 0,
  27. height: 0,
  28. };
  29. transferStyle = reactive({
  30. baseCardTop: "0px",
  31. showGizmo: false,
  32. editingText: false,
  33. width: 0,
  34. height: 0,
  35. relWidth: 0,
  36. relHeight: 0,
  37. matrix: "matrix(1,0,0,1,0,0)",
  38. matrixInvert: "matrix(1,0,0,1,0,0)",
  39. showOrthScale: false,
  40. mode: MODE_NONE,
  41. });
  42. selected: any[] = []; //选中的所有组件ids
  43. pageEl?: HTMLElement;
  44. selCanvas = {} as HTMLCanvasElement;
  45. _downed = false;
  46. _selCtx = {} as CanvasRenderingContext2D;
  47. _state = MODE_SEL_RECT;
  48. _selDownX = 0;
  49. _selDownY = 0;
  50. _selBox = {} as DOMRect;
  51. _selCanvaseSize = { w: 0, h: 0 };
  52. _downClientX = 0;
  53. _downClientY = 0;
  54. //groupCtrl = new GroupActionCtrl(this.module);
  55. bus = new Event();
  56. viewport?: HTMLElement;
  57. initEvents(
  58. pageEl: HTMLElement,
  59. selCanvas: HTMLCanvasElement,
  60. viewport: HTMLElement
  61. ) {
  62. this.viewport = viewport;
  63. this.pageEl = pageEl;
  64. this.selCanvas = selCanvas;
  65. const b = selCanvas.getBoundingClientRect();
  66. selCanvas.width = b.width * 2;
  67. selCanvas.height = b.height * 2;
  68. this._selCtx = selCanvas.getContext("2d") as CanvasRenderingContext2D;
  69. this._selCanvaseSize.w = selCanvas.width * 2;
  70. this._selCanvaseSize.h = selCanvas.height * 2;
  71. viewport.addEventListener("mousedown", this.onDocMouseDown.bind(this), {
  72. capture: true,
  73. });
  74. window.addEventListener("resize", this.onResize.bind(this));
  75. this.initEffects();
  76. }
  77. initEffects() {
  78. //相应相应的事件
  79. Effect.array(()=>this.store.selected).list({
  80. remove:()=>{
  81. console.log("xxx")
  82. },
  83. change:(added:string[], removed:string[])=>{
  84. console.log("changeMap=>", added, removed)
  85. this._updateSelects();
  86. },
  87. }).run();
  88. }
  89. _mouseDownFlag = "";
  90. _mouseDownTimestamp = 0;
  91. _containers:Map<string, ObjsContainer> = new Map();
  92. _updateSelects() {
  93. const selecteds = this.store.selected;
  94. const ObjC = this._containers.get(this.store.selectId)
  95. let objs = [];
  96. for (let item of selecteds) {
  97. objs.push( new CompObject(this.compMap[item]) )
  98. }
  99. this.selecteObjs(objs, ObjC);
  100. if (this.store.selectId) {
  101. this._containers.set(this.store.selectId, this.objContainer as ObjsContainer);
  102. }
  103. }
  104. _downClickedCompId = "";
  105. onDocMouseDown(e: MouseEvent) {
  106. this._mouseDownTimestamp = Date.now();
  107. if (!this.pageEl || !this.selCanvas) return;
  108. if (this.store.textEditingState) return;
  109. document.addEventListener("mousemove", this.onDocMouseMove, {
  110. capture: true,
  111. });
  112. //mouseup和click都会被触发, 监听click事件可以阻止子组件的点击行为
  113. document.addEventListener("click", this.onDocMouseUp.bind(this), {
  114. capture: true,
  115. once: true,
  116. });
  117. let box = this.pageEl.getBoundingClientRect();
  118. const pageX = e.clientX - box?.left;
  119. const pageY = e.clientY - box?.top;
  120. this._state = MODE_NONE;
  121. const sel = this.selCanvas.getBoundingClientRect();
  122. const selX = e.clientX - sel.left;
  123. const sely = e.clientY - sel.top;
  124. this._selDownX = selX;
  125. this._selDownY = sely;
  126. this._selBox = sel;
  127. this._downClientX = e.clientX;
  128. this._downClientY = e.clientY;
  129. this._downClickedCompId = this.compClickTest2(e);
  130. this._downed = true;
  131. this._mouseDownFlag = this.getDivTransformFlag(e.target as any);
  132. if (!this._mouseDownFlag) {
  133. //选框点击判断
  134. let isClickSelRect = false;
  135. if (this.selected.length > 0) {
  136. const card = this.store.currStreamCard.$el;
  137. box = card.getBoundingClientRect();
  138. const cardX = pageX;
  139. const cardY = e.clientY - box.top;
  140. isClickSelRect = this.objContainer?.testClick(cardX, cardY) as boolean;
  141. if (isClickSelRect) {
  142. this._state = MODE_MOVING;
  143. }
  144. }
  145. if (!isClickSelRect) { //点击在选框之外
  146. if (!this._downClickedCompId) {//没有点击到组件
  147. const view = this.viewport?.getBoundingClientRect() as any;
  148. const isOut =
  149. e.clientX < view.left ||
  150. e.clientX > view.right ||
  151. e.clientY < view.top ||
  152. e.clientY > view.bottom;
  153. if (!isOut) {
  154. this._state = MODE_SEL_RECT;
  155. }
  156. }
  157. //else {//点击到选框之外的组件, 把时间放到mouseup 时相应.
  158. // this._state = MODE_MOVING;
  159. // const obj = this.compMap[comps[0].id];
  160. // this.selecteObjs([new CompObject(obj)]);
  161. // }
  162. }
  163. } else if (this._mouseDownFlag == "rotate") {
  164. this._state = MODE_ROTATE;
  165. } else if (this._mouseDownFlag.indexOf("move") > -1) {
  166. this._state = MODE_MOVING;
  167. } else if (this._mouseDownFlag.indexOf("scale") > -1) {
  168. this._state = MODE_SCALE_WIDTH;
  169. if (this.store.selected.length == 1 && this.store.currComp.compKey == "Text") {//拖拽的是文本
  170. const scaleFlags = ["scaleBottomright", "scaleBottomleft", "scaleTopleft", "scaleTopright"]
  171. if (scaleFlags.indexOf(this._mouseDownFlag) > -1 ) {
  172. this._state = MODE_SCALE_SCALE;
  173. }
  174. }
  175. }
  176. this._movePreClientX = this._downClientX;
  177. this._movePreClientY = this._downClientY;
  178. this._initMovePos.x = -1;
  179. this._initMovePos.y = -1;
  180. }
  181. _initMovePos = { x: -1, y: -1 };
  182. getDivFlag(div: HTMLElement, flag="editable") {
  183. let c: any = div;
  184. if (!c) return ""
  185. let i = 0;
  186. do {
  187. if (c[flag]) return c[flag];
  188. c = c.parentElement;
  189. i += 1;
  190. if (i > 16) {
  191. return ""
  192. }
  193. } while (c);
  194. return "";
  195. }
  196. getDivId(div: HTMLElement) {
  197. let c: any = div;
  198. if (!c) return;
  199. let i = 0;
  200. do {
  201. if (c.id) return c.id;
  202. c = c.parentElement;
  203. i += 1;
  204. if (i > 5) {
  205. return;
  206. }
  207. } while (c);
  208. }
  209. getDivTransformFlag(div: HTMLElement) {
  210. const id = this.getDivId(div);
  211. if (!id) return "";
  212. if ( id.indexOf("rotate")>-1 || id.indexOf("move") > -1 || id.indexOf("scale") > -1 || id.indexOf("toolbar") > -1) return id;
  213. return "";
  214. }
  215. compClickTest2(e: MouseEvent) {
  216. const compId = this.getDivFlag(e.target as any, "compId");
  217. console.log("down click=>", compId);
  218. return compId;
  219. }
  220. compClickTest(e: MouseEvent) {
  221. const cards = this.store.streamCardIds;
  222. let n = cards.length;
  223. const compMap = this.store.designData.compMap;
  224. //@ts-ignore
  225. const pbox = this.pageEl.getBoundingClientRect();
  226. const pageX = e.clientX - pbox?.left;
  227. const Out: any[] = [];
  228. while (n--) {
  229. const cardComp = compMap[cards[n]];
  230. const box = cardComp.$el.getBoundingClientRect();
  231. const cardY = e.clientY - box.top;
  232. const cardChilds = cardComp.children.default || [];
  233. let maxZ = -1;
  234. let topItem = null;
  235. for (const key of cardChilds) {
  236. const c = compMap[key];
  237. const m = Matrix.createFromDiv(c.$el);
  238. const localp = m.applyInverse(new Point(pageX, cardY));
  239. const cw = this.helper.designSizeToPx(c.layout.size?.[0] as number);
  240. const ch = this.helper.designSizeToPx(c.layout.size?.[1] as number);
  241. const out =
  242. localp.x < 0 || localp.x > cw || localp.y < 0 || localp.y > ch;
  243. if (!out) {
  244. let z = c.layout.zIndex || 0;
  245. if (z > maxZ) {
  246. maxZ = z;
  247. topItem = {
  248. id: key,
  249. el: c.$el,
  250. cardX: pageX,
  251. cardY: cardY,
  252. cardId: cards[n],
  253. startMatrix: m,
  254. };
  255. }
  256. }
  257. }
  258. if (topItem) {
  259. Out.push(topItem);
  260. return Out;
  261. }
  262. }
  263. return Out;
  264. }
  265. streamCardClickTest(e: MouseEvent) {
  266. const cards = this.store.streamCardIds;
  267. let n = cards.length;
  268. const compMap = this.store.designData.compMap;
  269. //@ts-ignore
  270. const pbox = this.pageEl.getBoundingClientRect();
  271. const pageX = e.clientX - pbox?.left;
  272. if (pageX < 0 || pageX > pbox.width) return "";
  273. while (n--) {
  274. const card = compMap[cards[n]];
  275. const box = card.$el.getBoundingClientRect();
  276. if (e.clientY >= box.top && e.clientY <= box.bottom)
  277. return { id: cards[n], x: pageX, y: e.clientY - box.top };
  278. }
  279. return "";
  280. }
  281. _moveSelectUpdated = false;
  282. translate(xOffset: number, yOffset: number) {
  283. const objContainer = this.objContainer as ObjsContainer;
  284. objContainer.translate(xOffset, yOffset);
  285. this.upgateGizmoStyle();
  286. }
  287. movingMousemove(e: MouseEvent) {
  288. const objContainer = this.objContainer as ObjsContainer;
  289. if (this._initMovePos.x == -1 && this._initMovePos.y == -1) {
  290. const obj = this.objContainer as ObjsContainer;
  291. this._initMovePos = { x: obj.parent.x, y: obj.parent.y };
  292. }
  293. objContainer.setPivot(0);
  294. objContainer.translate(
  295. e.clientX - this._movePreClientX,
  296. e.clientY - this._movePreClientY
  297. );
  298. this.upgateGizmoStyle();
  299. }
  300. _movePreClientX = 0;
  301. _movePreClientY = 0;
  302. onDocMouseMove = (e: MouseEvent) => {
  303. if (!this.pageEl) return;
  304. // if (!this._downed) {
  305. // this.checkHover();
  306. // return;
  307. // }
  308. if (this._state) {
  309. e.preventDefault();
  310. e.stopPropagation();
  311. }
  312. switch (this._state) {
  313. case MODE_SEL_RECT: //选框模式
  314. this.drawSelRect(e);
  315. break;
  316. case MODE_MOVING:
  317. this.movingMousemove(e);
  318. break;
  319. case MODE_ROTATE:
  320. this.rotateMousemove(e);
  321. break;
  322. case MODE_SCALE_WIDTH:
  323. case MODE_SCALE_SCALE:
  324. this.scaleMousemove(e);
  325. }
  326. this._movePreClientY = e.clientY;
  327. this._movePreClientX = e.clientX;
  328. };
  329. get compMap() {
  330. return this.store.designData.compMap;
  331. }
  332. onDocMouseUp(e: MouseEvent) {
  333. let isClick = false;
  334. let offsetT = Date.now() - this._mouseDownTimestamp;
  335. const dx = Math.abs(e.clientX - this._downClientX);
  336. const dy = Math.abs(e.clientY - this._downClientY);
  337. if (dx < 2 && dy < 2 && offsetT < 200) {
  338. isClick = true;
  339. }
  340. document.removeEventListener("mousemove", this.onDocMouseMove, {
  341. capture: true,
  342. });
  343. if (this._mouseDownFlag == "toolbar") {
  344. return;
  345. }
  346. if (isClick) {
  347. this._state = MODE_NONE;
  348. this.actions.pickComp(this._downClickedCompId);
  349. }
  350. if (this._state == MODE_SEL_RECT && !isClick) {
  351. //选择空间转 streamCard空间
  352. const card = this.store.currStreamCard;
  353. const box = card.$el.getBoundingClientRect();
  354. this.rectSelect(
  355. this._lastSelRect[0] - box.left,
  356. this._lastSelRect[1] - box.top,
  357. this._lastSelRect[2],
  358. this._lastSelRect[3]
  359. );
  360. }
  361. if (this._state == MODE_ROTATE) {
  362. this.rotateMouseUp(e);
  363. } else if (this._state == MODE_SCALE_WIDTH || this._state == MODE_SCALE_SCALE) {
  364. this.scaleMouseUp(e);
  365. } else if (this._state == MODE_MOVING) {
  366. this.moveMouseUp(e, isClick);
  367. }
  368. this._state = MODE_NONE;
  369. this._downed = false;
  370. this._moveSelectUpdated = false;
  371. this._selCtx?.clearRect(
  372. 0,
  373. 0,
  374. this._selCanvaseSize.w,
  375. this._selCanvaseSize.h
  376. );
  377. this.upgateGizmoStyle();
  378. this.helper.extendStreamCard(this.store.currStreamCardId);
  379. }
  380. moveMouseUp(e: MouseEvent, clicked:boolean) {
  381. const history = this.controls.historyCtrl.history;
  382. const obj = this.objContainer as ObjsContainer;
  383. const lastX = obj.parent.x,
  384. lastY = obj.parent.y;
  385. const initX = this._initMovePos.x,
  386. initY = this._initMovePos.y;
  387. this._initMovePos.x = -1;
  388. this._initMovePos.y = -1;
  389. if (initX == -1 && initY == -1) return;
  390. obj.setPivot(0);
  391. history.record({
  392. undo: () => {
  393. console.log("undo ");
  394. const currObj = this.objContainer as ObjsContainer;
  395. currObj.setPivot(0);
  396. currObj.parent.x = initX;
  397. currObj.parent.y = initY;
  398. currObj.parent.updateTransform();
  399. currObj.updateCompState();
  400. this.upgateGizmoStyle();
  401. this.helper.extendStreamCard(this.store.currStreamCardId);
  402. },
  403. redo: () => {
  404. const currObj = this.objContainer as ObjsContainer;
  405. currObj.setPivot(0);
  406. currObj.parent.x = lastX;
  407. currObj.parent.y = lastY;
  408. currObj.parent.updateTransform();
  409. currObj.updateCompState();
  410. this.upgateGizmoStyle();
  411. this.helper.extendStreamCard(this.store.currStreamCardId);
  412. },
  413. } as any);
  414. history.submit();
  415. }
  416. rectSelect(x: number, y: number, width: number, height: number) {
  417. const childs =
  418. this.compMap[this.store.currStreamCardId].children.default || [];
  419. let n = childs.length;
  420. const outs = [];
  421. while (n--) {
  422. const o = new CompObject(this.compMap[childs[n]]);
  423. if (o.testRect({ x, y, w: width, h: height }, true)) {
  424. //相交
  425. outs.push(o.comp.id);
  426. }
  427. }
  428. this.actions.selectObjs(outs);
  429. if (outs.length < 1) {
  430. this.actions.pickComp(this.store.currStreamCardId);
  431. }
  432. }
  433. upgateGizmoStyle() {
  434. this.transferStyle.mode = this._state;
  435. if (this.selected.length < 1) {
  436. this.transferStyle.showGizmo = false;
  437. return;
  438. }
  439. this.transferStyle.showGizmo = false;
  440. //@ts-ignore
  441. const yoff = this.store.currStreamCard.$el.getBoundingClientRect().top - this.pageEl?.getBoundingClientRect().top;
  442. this.transferStyle.baseCardTop = yoff + "px";
  443. const selector = this.objContainer as ObjsContainer;
  444. if (!selector) {
  445. return;
  446. }
  447. this.transferStyle.showGizmo = true;
  448. let obj = selector.parent;
  449. let w = selector.rect.width,
  450. h = selector.rect.height;
  451. let tmp = new Matrix();
  452. tmp.copyFrom(obj.worldTransform);
  453. let matrix = `matrix(${tmp.a},${tmp.b},${tmp.c},${tmp.d},${tmp.tx},${tmp.ty})`;
  454. tmp.rotate(-tmp.getRotate());
  455. tmp.invert();
  456. let matrixInvert = `matrix(${tmp.a},${tmp.b},${tmp.c},${tmp.d},0,0)`;
  457. this.transferStyle.width = w;
  458. this.transferStyle.height = h;
  459. this.transferStyle.relWidth = w * obj.scale.x;
  460. this.transferStyle.relHeight = h * obj.scale.y;
  461. this.transferStyle.matrix = matrix;
  462. this.transferStyle.matrixInvert = matrixInvert;
  463. this.transferStyle.showOrthScale = this.selected.length == 1;
  464. }
  465. selectId(id: string) {
  466. //选中ids之前 id对应组件必须已经渲染
  467. console.log("selectId=>", id);
  468. }
  469. _lastSelRect = [0, 0, 0, 0];
  470. drawSelRect(e: MouseEvent) {
  471. const ctx = this._selCtx;
  472. const dx = this._selDownX;
  473. const dy = this._selDownY;
  474. const currX = e.clientX - this._selBox.left;
  475. const currY = e.clientY - this._selBox.top;
  476. const x = Math.min(currX, dx),
  477. y = Math.min(dy, currY);
  478. ctx.clearRect(0, 0, this._selCanvaseSize.w, this._selCanvaseSize.h);
  479. ctx.fillStyle = "rgba(232, 139, 0, 0.16)";
  480. const w = Math.abs(currX - dx);
  481. const h = Math.abs(currY - dy);
  482. ctx.fillRect(x * 2, y * 2, w * 2, h * 2);
  483. ctx.lineWidth = 2;
  484. ctx.strokeStyle = "#E88B00";
  485. ctx.strokeRect(x * 2, y * 2, w * 2, h * 2);
  486. this._lastSelRect[0] = x + this._selBox.left;
  487. this._lastSelRect[1] = y + this._selBox.top;
  488. this._lastSelRect[2] = w;
  489. this._lastSelRect[3] = h;
  490. }
  491. checkHover() {
  492. this.selCanvas;
  493. }
  494. onResize() {
  495. const b = this.selCanvas.getBoundingClientRect();
  496. this.selCanvas.width = b.width * 2;
  497. this.selCanvas.height = b.height * 2;
  498. this._selCtx = this.selCanvas.getContext("2d") as CanvasRenderingContext2D;
  499. this._selCanvaseSize.w = b.width * 2;
  500. this._selCanvaseSize.h = b.height * 2;
  501. }
  502. //
  503. checkIntersect(compId: string, e: MouseEvent) {
  504. const currCard = this.store.currStreamCard.$el;
  505. const comp = this.store.designData.compMap[compId];
  506. //排除坐标没有在streamCard空间内的坐标
  507. //把当前的card坐标转为 组件的自己local坐标判断是否在方框外面
  508. const cardBox = currCard.getBoundingClientRect();
  509. const cardX = e.clientX - cardBox.left;
  510. const cardY = e.clientY - cardBox.top;
  511. //const m = Matrix.createFromComp(comp.layout.transform)
  512. }
  513. objContainer?: ObjsContainer;
  514. selecteObjs(objs: any[], ContainerBox?: ObjsContainer) {
  515. if (this.selected.length == 0 && objs.length == 0) return;
  516. if (
  517. this.selected.length == 1 &&
  518. objs.length == 1 &&
  519. this.selected[0] == objs[0]
  520. )
  521. return;
  522. if (this.objContainer) {
  523. this.objContainer.destroy();
  524. this.objContainer = undefined;
  525. }
  526. let newObjContainer = undefined;
  527. if (objs.length > 0 && objs[0]) {
  528. newObjContainer = ContainerBox ? ContainerBox : new ObjsContainer(objs);
  529. if (ContainerBox) {
  530. objs.forEach((obj) => {
  531. ContainerBox.parent.addChildWorldNoChange(obj);
  532. });
  533. ContainerBox.selected = objs;
  534. ContainerBox.parent.updateTransform();
  535. }
  536. }
  537. this.objContainer = newObjContainer;
  538. this.selected = objs;
  539. this.emitChange();
  540. this.upgateGizmoStyle();
  541. return this.selected;
  542. }
  543. emitChange() {
  544. const selected = this.selected;
  545. if (selected.length && selected[0]) {
  546. this.bus.emit("showProps", selected[0].from);
  547. } else {
  548. this.bus.emit("showProps");
  549. }
  550. this.bus.emit("selectedChange");
  551. }
  552. rotateCenter?: { x: number; y: number };
  553. ratatePre = 0;
  554. objinitAngleRad = 0;
  555. rotateCmd = false;
  556. lastRad = 0;
  557. rotateMousemove(e: MouseEvent) {
  558. const card = this.store.currStreamCard;
  559. const rect = card.$el.getBoundingClientRect();
  560. let StartX = e.clientX - rect.left;
  561. let StartY = e.clientY - rect.top;
  562. const objContainer = this.objContainer as ObjsContainer;
  563. //获取当前屏幕坐标和选框中心点坐标,计算旋转值
  564. if (!this.rotateCenter) {
  565. //let rect = this.objContainer.parent.getBounds(false);
  566. let center = objContainer.setPivot(4);
  567. this.rotateCenter = center;
  568. let vec = { x: StartX - center.x, y: StartY - center.y };
  569. let angle = Math.atan2(vec.y, vec.x);
  570. if (angle < 0) angle += 2 * Math.PI;
  571. this.ratatePre = angle;
  572. this.objinitAngleRad = objContainer.parent.rotation;
  573. this.rotateCmd = true;
  574. return;
  575. }
  576. let center = this.rotateCenter;
  577. let vec = { x: StartX - center.x, y: StartY - center.y };
  578. let angle = Math.atan2(vec.y, vec.x);
  579. if (angle < 0) angle += 2 * Math.PI;
  580. let dta = this.objinitAngleRad + angle - this.ratatePre;
  581. if (e.shiftKey) {
  582. //规整到0 90 180 270
  583. if (dta < 0) dta += 2 * Math.PI;
  584. let Deg45 = Math.PI / 4.0;
  585. let Deg90 = Math.PI / 2.0;
  586. let Deg135 = Deg45 * 3;
  587. let Deg225 = Deg45 * 5;
  588. let Deg270 = Deg45 * 6;
  589. let Deg315 = Deg45 * 7;
  590. if (dta < Deg45) {
  591. dta = 0;
  592. } else if (dta < Deg135) {
  593. dta = Deg90;
  594. } else if (dta < Deg225) {
  595. dta = Math.PI;
  596. } else if (dta < Deg315) {
  597. dta = Deg270;
  598. } else {
  599. dta = 0;
  600. }
  601. }
  602. this.lastRad = dta;
  603. console.log("rotate=>", dta);
  604. objContainer.rotate(dta);
  605. // this.emit("translateChange", this.objContainer)
  606. this.upgateGizmoStyle();
  607. }
  608. rotateMouseUp(e: MouseEvent) {
  609. this.rotateCenter = undefined;
  610. if (!this.rotateCmd) return;
  611. let scope = this;
  612. let last = this.lastRad;
  613. let initrad = scope.objinitAngleRad;
  614. const history = this.controls.historyCtrl.history;
  615. this.objContainer?.setPivot(0);
  616. history.record({
  617. undo: () => {
  618. const objContainer = this.objContainer as ObjsContainer;
  619. this.objContainer?.setPivot(4);
  620. this.objContainer?.rotate(initrad);
  621. this.objContainer?.setPivot(0);
  622. this.objContainer?.updateCompState();
  623. this.upgateGizmoStyle();
  624. this.helper.extendStreamCard(this.store.currStreamCardId);
  625. },
  626. redo: () => {
  627. console.log("redo ");
  628. const objContainer = this.objContainer as ObjsContainer;
  629. this.objContainer?.setPivot(4);
  630. this.objContainer?.rotate(last);
  631. this.objContainer?.setPivot(0);
  632. this.objContainer?.updateCompState();
  633. this.upgateGizmoStyle();
  634. this.helper.extendStreamCard(this.store.currStreamCardId);
  635. },
  636. } as any);
  637. history.submit();
  638. this.rotateCmd = false;
  639. }
  640. //缩放选中的对象
  641. scalePivot?: any;
  642. scaleIndex = 0;
  643. mainAxisVector = { x: 0, y: 0 };
  644. initScale = { x: 1, y: 1 };
  645. mainAxisVectorLenth = 0;
  646. xAxisVector = { x: 1, y: 1 };
  647. xAxisVectorLength = 0;
  648. yAxisVector = { x: 1, y: 1 };
  649. yAxisVectorLength = 0;
  650. scaleCmd = false;
  651. lastScale = { x: 1, y: 1 };
  652. initScaleWith = { w: 0, h: 0 };
  653. scaleMousemove(event: MouseEvent) {
  654. let dirIndexs = [
  655. "scaleBottomright",
  656. "scaleBottomleft",
  657. "scaleTopleft",
  658. "scaleTopright",
  659. ];
  660. let dirOrth = ["scaleright", "scaleleft", "scalebottom", "scaletop"];
  661. const rect = this.store.currStreamCard.$el.getBoundingClientRect();
  662. let StartX = event.clientX - rect.left;
  663. let StartY = event.clientY - rect.top;
  664. const objContainer = this.objContainer as ObjsContainer;
  665. //获取当前屏幕坐标和选框中心点坐标,计算旋转值
  666. if (!this.scalePivot) {
  667. let dir = this._mouseDownFlag;
  668. let scaleIndex = dirIndexs.indexOf(dir);
  669. if (scaleIndex == -1) {
  670. scaleIndex = dirOrth.indexOf(dir);
  671. if (scaleIndex == 2) scaleIndex = 0;
  672. }
  673. let pivot = objContainer.setPivot(scaleIndex);
  674. this.scaleIndex = scaleIndex;
  675. this.scalePivot = pivot;
  676. this.mainAxisVector = { x: StartX - pivot.x, y: StartY - pivot.y };
  677. let scale = objContainer.parent.scale;
  678. this.initScale = { x: scale.x, y: scale.y };
  679. this.initScaleWith = { w: objContainer.width, h: objContainer.height };
  680. this.mainAxisVectorLenth = VectorLenth(
  681. this.mainAxisVector.x,
  682. this.mainAxisVector.y
  683. );
  684. let ret = objContainer.getPivotXY(scaleIndex);
  685. this.xAxisVector = ret.x;
  686. this.xAxisVectorLength = VectorLenth(ret.x.x, ret.x.y);
  687. this.yAxisVector = ret.y;
  688. this.yAxisVectorLength = VectorLenth(ret.y.x, ret.y.y);
  689. return;
  690. }
  691. this.scaleCmd = true;
  692. let center = this.scalePivot;
  693. let vec = { x: StartX - center.x, y: StartY - center.y };
  694. if (event.shiftKey) {
  695. //按住shift 自由缩放
  696. let dtaX = Project(vec, this.xAxisVector) / this.xAxisVectorLength;
  697. let dtaY = Project(vec, this.yAxisVector) / this.yAxisVectorLength;
  698. this.lastScale.x = dtaX * this.initScale.x;
  699. this.lastScale.y = dtaY * this.initScale.y;
  700. // objContainer.scale(this.lastScale.x, this.lastScale.y);
  701. const currW = this.initScaleWith.w * this.lastScale.x;
  702. objContainer.scaleSize(currW, this.lastScale.y * this.initScaleWith.h);
  703. } else {
  704. let mainVec = this.mainAxisVector;
  705. let dtaScale = Project(vec, mainVec) / this.mainAxisVectorLenth;
  706. console.log("dtaScale=>", dtaScale);
  707. let i = dirOrth.indexOf(this._mouseDownFlag);
  708. if (i == -1) {
  709. this.lastScale.x = dtaScale * this.initScale.x;
  710. this.lastScale.y = dtaScale * this.initScale.y;
  711. if (this._state == MODE_SCALE_SCALE) {
  712. objContainer.scale(this.lastScale.x, this.lastScale.y);
  713. } else {
  714. objContainer.scaleSize(this.lastScale.x, this.lastScale.y);
  715. }
  716. } else if (i == 0 || i == 1) {
  717. this.lastScale.x = dtaScale * this.initScale.x;
  718. // objContainer.scaleX(this.lastScale.x);
  719. objContainer.scaleWidth(this.lastScale.x);
  720. } else if (i == 2 || i == 3) {
  721. this.lastScale.y = dtaScale * this.initScale.y;
  722. // objContainer.scaleY(this.lastScale.y);
  723. objContainer.scaleHeight(this.lastScale.y);
  724. }
  725. }
  726. this.upgateGizmoStyle();
  727. }
  728. scaleMouseUp(event: MouseEvent) {
  729. this.scalePivot = undefined;
  730. if (this.scaleCmd) {
  731. let preScale = { x: this.initScale.x, y: this.initScale.y };
  732. let scaleIndex = this.scaleIndex;
  733. let lastScale = { x: this.lastScale.x, y: this.lastScale.y };
  734. const history = this.controls.historyCtrl.history;
  735. this.objContainer?.setPivot(0);
  736. const scaleMode = this._state;
  737. history.record({
  738. undo: () => {
  739. console.log("undo ");
  740. this.objContainer?.setPivot(scaleIndex);
  741. if (scaleMode == MODE_SCALE_WIDTH) {
  742. this.objContainer?.scaleSize(preScale.x, preScale.y);
  743. } else {
  744. this.objContainer?.scale(preScale.x, preScale.y);
  745. }
  746. this.objContainer?.setPivot(0);
  747. this.objContainer?.updateCompState();
  748. this.upgateGizmoStyle();
  749. this.helper.extendStreamCard(this.store.currStreamCardId);
  750. },
  751. redo: () => {
  752. console.log("redo ");
  753. this.objContainer?.setPivot(scaleIndex);
  754. if (scaleMode == MODE_SCALE_WIDTH) {
  755. this.objContainer?.scaleSize(lastScale.x, lastScale.y);
  756. } else {
  757. this.objContainer?.scale(lastScale.x, lastScale.y);
  758. }
  759. this.objContainer?.setPivot(0);
  760. this.objContainer?.updateCompState();
  761. this.upgateGizmoStyle();
  762. this.helper.extendStreamCard(this.store.currStreamCardId);
  763. },
  764. } as any);
  765. history.submit();
  766. this.scaleCmd = false;
  767. }
  768. }
  769. }