index.ts 26 KB

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