index.ts 29 KB

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