index.ts 25 KB

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