transform.tsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. import { IconRotate , IconMove} from "@/assets/icons";
  2. import { css } from "@linaria/core";
  3. import { defineComponent, onMounted, ref, nextTick, reactive } from "vue";
  4. import { any } from "vue-types";
  5. import { TransformCtrl } from "@/modules/editor/controllers/TransformCtrl";
  6. export const Transforms = defineComponent({
  7. props: {
  8. ctrl: any<TransformCtrl>()
  9. },
  10. setup(props) {
  11. const ctrl = props.ctrl ? props.ctrl : new TransformCtrl();
  12. const toolbarRef = ref<HTMLElement>();
  13. const transformRef = ref<HTMLElement>();
  14. const state = reactive({
  15. toolbarW: 0,
  16. })
  17. onMounted(()=>{
  18. if (transformRef.value) ctrl.initUI(transformRef.value);
  19. nextTick(()=>{
  20. nextTick(()=>{
  21. if (!toolbarRef.value) {
  22. return
  23. }
  24. const r = toolbarRef.value.getBoundingClientRect();
  25. state.toolbarW = r.width;
  26. })
  27. })
  28. })
  29. return () => {
  30. let toolbarTop = ctrl.state.bbox.y
  31. if (toolbarTop < 0 ) {
  32. toolbarTop = 0;
  33. }
  34. return (
  35. <div
  36. ref={transformRef}
  37. class={[
  38. "absolute transfer z-998",
  39. ctrl.state.visible ? showgizmo : hideGizmo,
  40. ]}
  41. style={{
  42. top: ctrl.state.baseTop + "px"
  43. }}
  44. >
  45. <div
  46. id= "toolbar"
  47. class={toolbarStyle}
  48. style={{
  49. top: toolbarTop + "px",
  50. left: (ctrl.state.bbox.x + ctrl.state.bbox.w / 2.0 - state.toolbarW / 2.0) + "px",
  51. }}
  52. ref= {toolbarRef}
  53. >
  54. {
  55. ctrl.state.toolbarNames.map((name) => {
  56. const ToolBarComp = ctrl.toolbars[name];
  57. return <span key={name} data-toolname={name} ><ToolBarComp class="p-4px" /></span>
  58. })
  59. }
  60. </div>
  61. <div
  62. class={["absolute", selctRectStyle]}
  63. id="movecenter"
  64. style={{
  65. width: ctrl.state.width + "px",
  66. height: ctrl.state.height + "px",
  67. transform: ctrl.state.matrix,
  68. transformOrigin: `0 0`,
  69. }}
  70. >
  71. <div class={borderStyle} style={{ transform: ctrl.state.matrixInvert, transformOrigin: `0 0`}} >
  72. <div class={borderContentStyle} style={{width: ctrl.state.relWidth + "px", height: ctrl.state.relHeight + "px"}}></div>
  73. </div>
  74. <>
  75. {
  76. <div
  77. class={[resizeStyle, scaleBottomRightStyle]}
  78. style={{ transform: ctrl.state.matrixInvert }}
  79. id="scaleBottomright"
  80. />
  81. }
  82. {
  83. <div
  84. class={[resizeStyle, scaleBottomLeftStyle]}
  85. style={{ transform: ctrl.state.matrixInvert }}
  86. id="scaleBottomleft"
  87. />
  88. }
  89. {
  90. <div
  91. class={[resizeStyle, scaleTopLeftStyle]}
  92. style={{ transform: ctrl.state.matrixInvert }}
  93. id="scaleTopleft"
  94. />
  95. }
  96. {
  97. <div
  98. class={[resizeStyle, scaleTopRightStyle]}
  99. style={{ transform: ctrl.state.matrixInvert }}
  100. id="scaleTopright"
  101. />
  102. }
  103. <div class={transformBtnsStyle} style={{ transform: ctrl.state.matrixInvert }}>
  104. <div
  105. class={transBtnStyle}
  106. id="moveicon"
  107. >
  108. <IconMove />
  109. </div>
  110. <div
  111. class={transBtnStyle}
  112. id = "rotate"
  113. >
  114. <IconRotate />
  115. </div>
  116. </div>
  117. {ctrl.state.showScaleBridge && ctrl.state.showScaletop && (
  118. <div
  119. class={[resizeHeightBtnCls, scaleTopCls]}
  120. style={{ transform: ctrl.state.matrixInvert }}
  121. id="scaletop"
  122. />
  123. )}
  124. {ctrl.state.showScaleBridge && ctrl.state.showScalebottom && (
  125. <div
  126. class={[resizeHeightBtnCls, scaleBottomCls]}
  127. style={{ transform: ctrl.state.matrixInvert }}
  128. id="scalebottom"
  129. />
  130. )}
  131. {ctrl.state.showScaleBridge && (
  132. <div
  133. class={[resizeWidthBtnCls, scaleRightCls]}
  134. style={{ transform: ctrl.state.matrixInvert }}
  135. id="scaleright"
  136. />
  137. )}
  138. {ctrl.state.showScaleBridge && (
  139. <div
  140. class={[resizeWidthBtnCls, scaleLeftCls]}
  141. style={{ transform: ctrl.state.matrixInvert }}
  142. id="scaleleft"
  143. />
  144. )}
  145. </>
  146. </div>
  147. </div>
  148. );
  149. };
  150. },
  151. });
  152. const selctRectStyle = css`
  153. /* pointer-events: none; */
  154. `;
  155. const showgizmo = css`
  156. display: block;
  157. left: 0;
  158. top: 0;
  159. /* pointer-events: none; */
  160. `;
  161. const hideGizmo = css`
  162. display: none;
  163. `;
  164. const borderStyle = css`
  165. position: absolute;
  166. top: 0;
  167. left: 0;
  168. width: 100%;
  169. height: 100%;
  170. pointer-events: none;
  171. z-index: 999;
  172. `;
  173. const borderContentStyle = css`
  174. position: absolute;
  175. top: 0;
  176. left: 0;
  177. width: 100%;
  178. height: 100%;
  179. outline: 2px solid @inf-primary-color;
  180. `
  181. const resizeStyle = css`
  182. position: absolute;
  183. width: 16px;
  184. height: 16px;
  185. border-radius: 50%;
  186. background-color: #fff;
  187. z-index: 999;
  188. transform: translate(50%, 50%);
  189. pointer-events: auto;
  190. box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.2);
  191. cursor: nwse-resize;
  192. &:hover {
  193. border-color: @inf-primary-color;
  194. }
  195. `;
  196. const scaleBottomRightStyle = css`
  197. bottom: -8px;
  198. right: -8px;
  199. `;
  200. const scaleBottomLeftStyle = css`
  201. bottom: -8px;
  202. left: -8px;
  203. `;
  204. const scaleTopLeftStyle = css`
  205. top: -8px;
  206. left: -8px;
  207. `;
  208. const scaleTopRightStyle = css`
  209. top: -8px;
  210. right: -8px;
  211. `;
  212. const transformBtnsStyle = css`
  213. @apply space-x-10px whitespace-nowrap;
  214. position: absolute;
  215. bottom: 0px;
  216. left:calc(50% - 32px);
  217. font-size: 16px;
  218. z-index: 999;
  219. pointer-events: auto;
  220. transform-origin: 50% 100%;
  221. pointer-events: none;
  222. `;
  223. const transBtnStyle = css`
  224. display: inline-block;
  225. width: 28px;
  226. height: 28px;
  227. border-radius: 50%;
  228. background-color: #fff;
  229. text-align: center;
  230. line-height: 28px;
  231. font-size: 16px;
  232. color: #333;
  233. position: relative;
  234. top: 50px;
  235. @apply shadow cursor-move;
  236. pointer-events: auto;
  237. &:hover {
  238. color: #fff;
  239. background-color: @inf-primary-color;
  240. }
  241. `;
  242. const toolbarStyle = css`
  243. @apply bg-white shadow rounded space-x-4px p-4px whitespace-nowrap;
  244. position: absolute;
  245. top: 0;
  246. left: 50%;
  247. transform: translate(0%, -60px);
  248. z-index: 999;
  249. `;
  250. const resizeHeightBtnCls = css`
  251. position: absolute;
  252. width: 30px;
  253. height: 8px;
  254. border-radius: 4px;
  255. left: 50%;
  256. transform: translate(-50%, -4px);
  257. pointer-events: auto;
  258. cursor: ns-resize;
  259. background: rgba(255, 255, 255, 0.3);
  260. &:hover {
  261. background: @inf-primary-color;
  262. }
  263. @apply shadow;
  264. z-index: 999;
  265. `;
  266. const scaleTopCls = css`
  267. top: -4px;
  268. left: calc(50% - 15px);
  269. `;
  270. const scaleBottomCls = css`
  271. bottom:-4px;
  272. left: calc(50% - 15px);
  273. `;
  274. const resizeWidthBtnCls = css`
  275. position: absolute;
  276. width: 8px;
  277. height: 30px;
  278. border-radius: 4px;
  279. pointer-events: auto;
  280. cursor: ew-resize;
  281. background: rgba(255, 255, 255, 0.3);
  282. &:hover {
  283. background: @inf-primary-color;
  284. }
  285. @apply shadow;
  286. z-index: 999;
  287. `;
  288. const scaleRightCls = css`
  289. right: -4px;
  290. top: calc(50% - 15px);
  291. `;
  292. const scaleLeftCls = css`
  293. left: -4px;
  294. top: calc(50% - 15px);
  295. `;