index.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. <template>
  2. <div class="go-sketch-rule">
  3. <sketch-rule
  4. v-if="sketchRuleReDraw"
  5. :thick="thick"
  6. :scale="scale"
  7. :width="canvasBox().width"
  8. :height="canvasBox().height"
  9. :startX="startX"
  10. :startY="startY"
  11. :lines="lines"
  12. :palette="paletteStyle"
  13. >
  14. </sketch-rule>
  15. <div ref="$app" class="edit-screens" @scroll="handleScroll">
  16. <div ref="$container" class="edit-screen-container" :style="{ width: width * 2 + 'px' }">
  17. <div
  18. ref="refSketchRuleBox"
  19. class="canvas"
  20. @mousedown="dragCanvas"
  21. :style="{ marginLeft: '-' + (canvasBox().width / 2 - 25) + 'px' }"
  22. >
  23. <div :style="{ pointerEvents: isPressSpace ? 'none' : 'auto' }">
  24. <slot></slot>
  25. </div>
  26. </div>
  27. </div>
  28. </div>
  29. <!-- 修复右下角白点用的 -->
  30. <div v-if="designStore.getDarkTheme" class="fix-edit-screens-block"></div>
  31. </div>
  32. </template>
  33. <script setup lang="ts">
  34. import { ref, reactive, onMounted, toRefs, watch, onUnmounted, computed } from 'vue'
  35. import { listen } from 'dom-helpers'
  36. import { useDesignStore } from '@/store/modules/designStore/designStore'
  37. import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  38. import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
  39. import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
  40. import throttle from 'lodash/throttle'
  41. const chartEditStore = useChartEditStore()
  42. const chartLayoutStore = useChartLayoutStore()
  43. const designStore = useDesignStore()
  44. const thick = 20
  45. let prevMoveXValue = [0, 0]
  46. let prevMoveYValue = [0, 0]
  47. const $app = ref()
  48. const sketchRuleReDraw = ref(true)
  49. const refSketchRuleBox = ref()
  50. const $container = ref()
  51. const isPressSpace = ref(false)
  52. const cursorStyle = ref('auto')
  53. const { width, height } = toRefs(chartEditStore.getEditCanvasConfig)
  54. const startX = ref(0)
  55. const startY = ref(0)
  56. const lines = reactive({ h: [], v: [] })
  57. const scale = computed(() => {
  58. return chartEditStore.getEditCanvas.scale
  59. })
  60. // 滚动条拖动的高度
  61. const containerWidth = computed(() => {
  62. return `${height.value * 2}px`
  63. })
  64. // 主题
  65. const paletteStyle = computed(() => {
  66. const isDarkTheme = designStore.getDarkTheme
  67. return isDarkTheme
  68. ? {
  69. bgColor: '#18181c',
  70. longfgColor: '#4d4d4d',
  71. shortfgColor: '#4d4d4d',
  72. fontColor: '#4d4d4d',
  73. shadowColor: '#18181c',
  74. borderColor: '#18181c',
  75. cornerActiveColor: '#18181c'
  76. }
  77. : {}
  78. })
  79. // 颜色
  80. const themeColor = computed(() => {
  81. return designStore.getAppTheme
  82. })
  83. // 处理鼠标拖动
  84. const handleWheel = (e: any) => {
  85. if (e.ctrlKey || e.metaKey) {
  86. e.preventDefault()
  87. let resScale = scale.value
  88. // 放大(200%)
  89. if (e.wheelDelta >= 0 && scale.value < 2) {
  90. resScale = scale.value + 0.05
  91. chartEditStore.setScale(resScale)
  92. return
  93. }
  94. // 缩小(10%)
  95. if (e.wheelDelta < 0 && scale.value > 0.1) {
  96. resScale = scale.value - 0.05
  97. chartEditStore.setScale(resScale)
  98. }
  99. }
  100. }
  101. // 滚动条处理
  102. const handleScroll = () => {
  103. if (!$app.value) return
  104. const screensRect = $app.value.getBoundingClientRect()
  105. const canvasRect = refSketchRuleBox.value.getBoundingClientRect()
  106. // 标尺开始的刻度
  107. startX.value = (screensRect.left + thick - canvasRect.left) / scale.value
  108. startY.value = (screensRect.top + thick - canvasRect.top) / scale.value
  109. }
  110. // 拖拽处理
  111. const dragCanvas = (e: any) => {
  112. e.preventDefault()
  113. e.stopPropagation()
  114. if (e.which == 2) isPressSpace.value = true
  115. else if (!window.$KeyboardActive?.space) return
  116. // @ts-ignore
  117. document.activeElement?.blur()
  118. const startX = e.pageX
  119. const startY = e.pageY
  120. const listenMousemove = listen(window, 'mousemove', (e: any) => {
  121. const nx = e.pageX - startX
  122. const ny = e.pageY - startY
  123. const [prevMoveX1, prevMoveX2] = prevMoveXValue
  124. const [prevMoveY1, prevMoveY2] = prevMoveYValue
  125. prevMoveXValue = [prevMoveX2, nx]
  126. prevMoveYValue = [prevMoveY2, ny]
  127. $app.value.scrollLeft -=
  128. prevMoveX2 > prevMoveX1 ? Math.abs(prevMoveX2 - prevMoveX1) : -Math.abs(prevMoveX2 - prevMoveX1)
  129. $app.value.scrollTop -=
  130. prevMoveY2 > prevMoveY1 ? Math.abs(prevMoveY2 - prevMoveY1) : -Math.abs(prevMoveY2 - prevMoveY1)
  131. })
  132. const listenMouseup = listen(window, 'mouseup', () => {
  133. listenMousemove()
  134. listenMouseup()
  135. prevMoveXValue = [0, 0]
  136. prevMoveYValue = [0, 0]
  137. isPressSpace.value = false
  138. })
  139. }
  140. // 计算画布大小
  141. const canvasBox = () => {
  142. const layoutDom = document.getElementById('go-chart-edit-layout')
  143. if (layoutDom) {
  144. return {
  145. height: layoutDom.clientHeight - 25,
  146. width: layoutDom.clientWidth
  147. }
  148. }
  149. return {
  150. width: width.value,
  151. height: height.value
  152. }
  153. }
  154. // 重绘标尺
  155. const reDraw = () => {
  156. sketchRuleReDraw.value = false
  157. setTimeout(() => {
  158. sketchRuleReDraw.value = true
  159. }, 10)
  160. }
  161. // 滚动居中
  162. const canvasPosCenter = () => {
  163. const { width: containerWidth, height: containerHeight } = $container.value.getBoundingClientRect()
  164. const { width, height } = canvasBox()
  165. $app.value.scrollLeft = containerWidth / 2 - width / 2
  166. $app.value.scrollTop = containerHeight / 2 - height / 2
  167. }
  168. // 处理主题变化
  169. watch(
  170. () => designStore.getDarkTheme,
  171. () => {
  172. reDraw()
  173. }
  174. )
  175. // // 处理标尺重制大小
  176. watch(
  177. () => scale.value,
  178. (newValue, oldValue) => {
  179. if (oldValue !== newValue && chartLayoutStore.getRePositionCanvas) {
  180. chartLayoutStore.setItemUnHandle(ChartLayoutStoreEnum.RE_POSITION_CANVAS, false)
  181. handleScroll()
  182. setTimeout(() => {
  183. canvasPosCenter()
  184. reDraw()
  185. }, 400)
  186. } else {
  187. throttle(reDraw, 20)
  188. }
  189. }
  190. )
  191. // 处理鼠标样式
  192. watch(
  193. () => isPressSpace.value,
  194. newValue => {
  195. cursorStyle.value = newValue ? 'grab' : 'auto'
  196. }
  197. )
  198. onMounted(() => {
  199. if ($app.value) {
  200. $app.value.addEventListener('wheel', handleWheel, { passive: false })
  201. canvasPosCenter()
  202. }
  203. })
  204. onUnmounted(() => {
  205. if ($app.value) {
  206. $app.value.removeEventListener('wheel', handleWheel)
  207. }
  208. })
  209. window.onKeySpacePressHold = (isHold: boolean) => {
  210. isPressSpace.value = isHold
  211. }
  212. </script>
  213. <style>
  214. /* 使用 SCSS 会报错,直接使用最基础的 CSS 进行修改,
  215. 此库有计划 Vue3 版本,但是开发的时候还没发布 */
  216. #mb-ruler {
  217. top: 0;
  218. left: 0;
  219. }
  220. /* 横线 */
  221. #mb-ruler .v-container .lines .line {
  222. /* 最大缩放 200% */
  223. width: 200vw !important;
  224. border-top: 1px dashed v-bind('themeColor') !important;
  225. }
  226. #mb-ruler .v-container .indicator {
  227. border-bottom: 1px dashed v-bind('themeColor') !important;
  228. }
  229. /* 竖线 */
  230. #mb-ruler .h-container .lines .line {
  231. /* 最大缩放 200% */
  232. height: 200vh !important;
  233. border-left: 1px dashed v-bind('themeColor') !important;
  234. }
  235. #mb-ruler .h-container .indicator {
  236. border-left: 1px dashed v-bind('themeColor') !important;
  237. }
  238. /* 坐标数值背景颜色 */
  239. #mb-ruler .indicator .value {
  240. background-color: rgba(0, 0, 0, 0);
  241. }
  242. /* 删除按钮 */
  243. #mb-ruler .line .del {
  244. padding: 0;
  245. color: v-bind('themeColor');
  246. font-size: 26px;
  247. font-weight: bolder;
  248. }
  249. #mb-ruler .corner {
  250. border-width: 0 !important;
  251. }
  252. </style>
  253. <style lang="scss" scoped>
  254. @include go('sketch-rule') {
  255. position: relative;
  256. overflow: hidden;
  257. width: 100%;
  258. height: 100%;
  259. .edit-screens {
  260. position: absolute;
  261. width: 100%;
  262. height: 100%;
  263. overflow: auto;
  264. user-select: none;
  265. padding-bottom: 0px;
  266. /* firefox */
  267. scrollbar-color: rgba(144, 146, 152, 0.3) transparent;
  268. scrollbar-width: thin;
  269. /* chrome */
  270. &::-webkit-scrollbar,
  271. &::-webkit-scrollbar-track-piece {
  272. background-color: transparent;
  273. }
  274. &::-webkit-scrollbar {
  275. width: 7px;
  276. }
  277. &::-webkit-scrollbar-thumb {
  278. border-radius: 5px;
  279. background-color: rgba(144, 146, 152, 0.3);
  280. }
  281. }
  282. .fix-edit-screens-block {
  283. position: absolute;
  284. bottom: 0;
  285. right: 0;
  286. width: 10px;
  287. height: 10px;
  288. background-color: $--color-dark-bg-1;
  289. }
  290. .edit-screen-container {
  291. position: absolute;
  292. height: v-bind('containerWidth');
  293. top: 0;
  294. left: 0;
  295. }
  296. .canvas {
  297. position: absolute;
  298. top: 50%;
  299. left: 50%;
  300. transform-origin: 50% 0;
  301. transform: translateY(-50%);
  302. &:hover {
  303. cursor: v-bind('cursorStyle');
  304. }
  305. &:active {
  306. cursor: crosshair;
  307. }
  308. }
  309. }
  310. </style>