tm-render - 副本.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. <template>
  2. <view class="tm-render" @touchmove.stop.prevent="">
  3. <!-- #ifdef MP-WEIXIN || MP-QQ || MP-KUAISHOU -->
  4. <canvas :style="{width:`${c_w}px`,height:`${c_h}px`}" @mouseup="touchend" @mousedown="touchstart"
  5. @mousemove="touchmove" @touchend="touchend" @touchmove="touchmove" @touchstart="touchstart" id="exid"
  6. canvas-id="exid" type="2d"></canvas>
  7. <!-- #endif -->
  8. <!-- #ifndef MP-WEIXIN || MP-QQ || MP-KUAISHOU -->
  9. <canvas :style="{width:`${c_w}px`,height:`${c_h}px`}" @mouseup="touchend" @mousedown="touchstart"
  10. @mousemove="touchmove" @touchend="touchend" @touchmove="touchmove" @touchstart="touchstart" id="exid"
  11. canvas-id="exid" ></canvas>
  12. <!-- #endif -->
  13. </view>
  14. </template>
  15. <script>
  16. import CRender from '@/tm-vuetify/tool/function/crender/class/crender.class'
  17. // import Graph from '@/tm-vuetify/tool/function/crender/class/graph.class'
  18. // import {CRender,GRAPHS} from '@/tm-vuetify/tool/function/render/index.js'
  19. let render = null;
  20. export default {
  21. name: "tm-render",
  22. props: {
  23. width: {
  24. type: Number,
  25. default: 0
  26. },
  27. height: {
  28. type: Number,
  29. default: 600
  30. }
  31. },
  32. computed: {
  33. c_w: {
  34. get: function() {
  35. return this.cavan_width;
  36. },
  37. set: function(val) {
  38. this.cavan_width = val;
  39. },
  40. },
  41. c_h: function() {
  42. return uni.upx2px(this.height);
  43. }
  44. },
  45. created() {
  46. const dpr = uni.getSystemInfoSync().pixelRatio
  47. this.dpr = dpr;
  48. this.c_w = uni.upx2px(this.width);
  49. },
  50. data() {
  51. return {
  52. cavan_width: 0,
  53. canvaConfig: null,
  54. dragGrpahId: '',//当前正在拖动或者点击的项目id.
  55. old_x: 0,
  56. old_y: 0,
  57. isDrag: false,
  58. dpr: 1
  59. };
  60. },
  61. mounted() {
  62. this.$nextTick(function() {
  63. this.inits();
  64. })
  65. },
  66. destroyed() {
  67. render = null;
  68. clearTimeout(555)
  69. },
  70. methods: {
  71. async inits() {
  72. let t = this;
  73. let res = await this.$Querey('.tm-render', this).catch(e => {})
  74. let p = res[0];
  75. t.c_w = p.width || 300;
  76. t.canvaConfig = p;
  77. //#ifdef MP-WEIXIN || MP-QQ || MP-KUAISHOU
  78. uni.createSelectorQuery().in(t).select('#exid').fields({
  79. node: true,
  80. context: true,
  81. }, function(res) {
  82. let canvas = res.node;
  83. let ctx = canvas.getContext('2d')
  84. ctx['dpr'] = t.dpr;
  85. ctx['scaledpr'] = 10 / (10 * t.dpr);
  86. const w = ctx['width'] = t.c_w
  87. const h = ctx['height'] = t.c_h
  88. // canvas.width = res[0].width * dpr
  89. // canvas.height = res[0].height * dpr
  90. const dpr = uni.getSystemInfoSync().pixelRatio
  91. canvas.width = w * dpr
  92. canvas.height = h * dpr
  93. // 设置 canvas 坐标原点
  94. ctx.translate(0, 0);
  95. ctx.scale(dpr, dpr)
  96. render = new CRender(ctx, t, canvas)
  97. t.$nextTick(function() {
  98. t.$emit('render', render.area);
  99. })
  100. }).exec()
  101. //#endif
  102. //#ifndef MP-WEIXIN || MP-QQ || MP-KUAISHOU
  103. let ctx = uni.createCanvasContext('exid', t)
  104. ctx['dpr'] = t.dpr;
  105. ctx['scaledpr'] = 10 / (10 * t.dpr);
  106. const w = ctx['width'] = t.c_w
  107. const h = ctx['height'] = t.c_h
  108. render = new CRender(ctx, t)
  109. t.$nextTick(function() {
  110. t.$emit('render', render.area);
  111. })
  112. //#endif
  113. },
  114. wait(time) {
  115. return new Promise(resolve => setTimeout(resolve, time))
  116. },
  117. getTextWidthAndPos(shape) {
  118. if (!render) return [0, 0, 0, 0];
  119. let {
  120. content,
  121. position,
  122. maxWidth,
  123. rowGap
  124. } = shape.shape
  125. const {
  126. textBaseline,
  127. fontSize,
  128. textAlign
  129. } = shape.style
  130. let [x, y] = position
  131. content = content.split('\n')
  132. const rowNum = content.length
  133. const lineHeight = fontSize + rowGap
  134. const allHeight = rowNum * lineHeight - rowGap
  135. const twidth = render.ctx.measureText(content + "").width;
  136. if (textBaseline === 'middle') {
  137. y -= allHeight * rowNum + fontSize / 2
  138. }
  139. if (textBaseline === 'bottom') {
  140. y += fontSize
  141. }
  142. if (textAlign === 'center') {
  143. x -= twidth / 2
  144. y += fontSize
  145. }
  146. return [x, y, twidth, allHeight]
  147. // measureText
  148. },
  149. getRender() {
  150. return render;
  151. },
  152. async addGraph(obj) {
  153. let t = this;
  154. let pf = obj;
  155. if (typeof obj == 'object' && Array.isArray(obj)) {
  156. let c = obj.filter(el => {
  157. return {
  158. ...el,
  159. tmid: uni.$tm.guid()
  160. };
  161. })
  162. pf = c;
  163. } else if (typeof obj == 'object' && !Array.isArray(obj)) {
  164. pf = [{
  165. ...pf,
  166. tmid: uni.$tm.guid()
  167. }]
  168. }
  169. let graphs = pf.map(config => render.add(config))
  170. graphs.forEach((graph, i) => {
  171. const config = pf[i]
  172. t.updateGraphConfigByKey(graph, config)
  173. })
  174. await render.launchAnimation()
  175. //释放内存。
  176. // graphs = []
  177. return graphs.length == 1 ? graphs[0] : graphs;
  178. },
  179. //添加完毕需要更新下,才会显示。
  180. updateGraphConfigByKey(graph, config) {
  181. const keys = Object.keys(config)
  182. keys.forEach(async key => {
  183. if (key === 'shape' || key === 'style') {
  184. // graph.animation('shape', {x:config.shape.x+5}, true)
  185. await graph.animation(key, config[key], true)
  186. } else {
  187. graph[key] = config[key]
  188. }
  189. })
  190. },
  191. touchend(event) {
  192. let t = this;
  193. let evx = 0;
  194. let evy = 0;
  195. //触摸
  196. if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
  197. evx = event.changedTouches[0].x
  198. evy = event.changedTouches[0].y
  199. //电脑端。
  200. } else {
  201. evx = event.pageX - this.canvaConfig.left
  202. evy = event.pageY - this.canvaConfig.top;
  203. }
  204. let x = evx;
  205. let y = evy;
  206. this.dragGrpahId = "";
  207. this.isDrag = false
  208. //触发画板的事件。
  209. this.$emit('touchend', {
  210. x: x,
  211. y: y
  212. })
  213. //在那个元素上离开的。
  214. let gps = render.graphs;
  215. let isClickGrpahs = gps.filter((el, index) => {
  216. if (el.name == 'text') {
  217. let rect = t.getTextWidthAndPos(el);
  218. el.hoverRect = rect
  219. }
  220. return el.hoverCheck([x, y], el) || el.hoverCheckProcessor([x, y], el);
  221. });
  222. if (isClickGrpahs.length > 0) {
  223. let nowgap = isClickGrpahs[0];
  224. // 执行元素上绑定的事件。
  225. if (nowgap[event.type]) nowgap[event.type].call(nowgap, {
  226. x: x,
  227. y: y
  228. });
  229. }
  230. },
  231. touchmove(event) {
  232. let t = this;
  233. let evx = 0;
  234. let evy = 0;
  235. let isPc = false
  236. //触摸
  237. if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
  238. evx = event.changedTouches[0].x
  239. evy = event.changedTouches[0].y
  240. isPc = false
  241. //电脑端。
  242. } else {
  243. evx = event.pageX - this.canvaConfig.left
  244. evy = event.pageY - this.canvaConfig.top;
  245. isPc = true;
  246. }
  247. let movex = evx - this.old_x;
  248. let movey = evy - this.old_y;
  249. let x = evx;
  250. let y = evy;
  251. // 触发发画板的事件
  252. this.$emit('touchmove', {
  253. x: x,
  254. y: y
  255. })
  256. if(this.isDrag==false) return;
  257. //在哪个元素移动的。
  258. let gps = render.graphs;
  259. let isClickGrpahs = gps.filter((el, index) => {
  260. return (el.hoverCheck([x, y], el) || el.hoverCheckProcessor([x, y], el))&&el.tmid==t.dragGrpahId;
  261. });
  262. if (isClickGrpahs.length > 0) {
  263. let nowgap = isClickGrpahs[0];
  264. if (isPc) {
  265. movex = evx - this.old_x;
  266. movey = evy - this.old_y;
  267. }
  268. if ((nowgap.drag === true && this.isDrag == true) || (nowgap.drag === true && isPc == false)) {
  269. if (nowgap.name == "circle" || nowgap.name == "ellipse" ||
  270. nowgap.name == "ring" || nowgap.name == "arc" || nowgap.name == "regPolygon") {
  271. nowgap.attr('shape', {
  272. rx: movex,
  273. ry: movey
  274. })
  275. } else if (nowgap.name == "rect" ||nowgap.name == 'rectRound'|| nowgap.name == "path"|| nowgap.name == "image"|| nowgap.name == "star" || nowgap.name =='arrow') {
  276. nowgap.attr('shape', {
  277. x: movex,
  278. y: movey
  279. })
  280. } else if (nowgap.name == "text") {
  281. nowgap.attr('shape', {
  282. position: [movex, movey]
  283. })
  284. }
  285. // 执行元素上绑定的事件。
  286. if (nowgap[event.type]) nowgap[event.type].call(nowgap, {
  287. x: movex,
  288. y: movey
  289. });
  290. // if(nowgap['mousemove']||nowgap['touchmove']){
  291. // if (nowgap['mousemove']) nowgap.mousemove.call(nowgap,{x:movex,y:movey})
  292. // if (nowgap['touchmove']) nowgap.touchmove.call(nowgap,{x:movex,y:movey})
  293. // }
  294. }
  295. //配置不允许拖出边界。
  296. // if(this.dragGrpahId === nowgap.tmid
  297. // && movex+nowgap.shape.w<this.canvaConfig.width
  298. // && movey+nowgap.shape.h<this.canvaConfig.height
  299. // && x>=0&&y>=0&&movex>=0&&movey>=0
  300. // ){
  301. // }
  302. // this.$emit('shape:touchmove',{x:x,y:y,shape:nowgap})
  303. }
  304. },
  305. touchstart(event) {
  306. let t = this;
  307. let evx = 0;
  308. let evy = 0;
  309. let isPc = false
  310. //触摸
  311. if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
  312. evx = event.changedTouches[0].x
  313. evy = event.changedTouches[0].y
  314. isPc = false
  315. //电脑端。
  316. } else {
  317. evx = event.pageX - this.canvaConfig.left
  318. evy = event.pageY - this.canvaConfig.top
  319. isPc = true;
  320. }
  321. let x = evx
  322. let y = evy
  323. let gps = render.graphs;
  324. //点中了哪些图片,第一个是最顶层的,依次类推。
  325. let isClickGrpahs = gps.filter((el, index) => {
  326. // if (el.name == 'text') {
  327. // let rect = t.getTextWidthAndPos(el);
  328. // el.hoverRect = rect
  329. // }
  330. // 要判断谁的层级高就是先托动谁。
  331. return el.hoverCheck([x, y], el) || el.hoverCheckProcessor([x, y], el);
  332. });
  333. if (isClickGrpahs.length > 0) {
  334. var indexOfMax = 0;
  335. var max = isClickGrpahs.reduce( (a,c,i) => c.index > a ? (indexOfMax = i,c.index) : a, 0)
  336. let nowgap = isClickGrpahs[indexOfMax];
  337. if (nowgap.drag === true) {
  338. this.dragGrpahId = nowgap.tmid;
  339. let gapPos = [];
  340. if (nowgap.name == "circle" || nowgap.name == "ellipse" ||
  341. nowgap.name == "ring" || nowgap.name == "arc" || nowgap.name == "regPolygon"
  342. ) {
  343. gapPos = [nowgap.shape.rx, nowgap.shape.ry]
  344. } else if (nowgap.name == "rect" ||nowgap.name == 'rectRound'|| nowgap.name == "path"|| nowgap.name == "image"|| nowgap.name == "star"|| nowgap.name =='arrow') {
  345. gapPos = [nowgap.shape.x, nowgap.shape.y]
  346. } else if (nowgap.name == "text") {
  347. gapPos = nowgap.shape.position
  348. }
  349. if (isPc) {
  350. this.old_x = evx - gapPos[0]
  351. this.old_y = evy - gapPos[1];
  352. } else {
  353. this.old_x = x - gapPos[0];
  354. this.old_y = y - gapPos[1];
  355. }
  356. this.isDrag = true
  357. }
  358. // 执行元素上绑定的事件。
  359. if (nowgap[event.type]) nowgap[event.type].call(nowgap, {
  360. x: x,
  361. y: y
  362. });
  363. // if(nowgap['mousedwon']||nowgap['touchstart']||nowgap['mouseenter']){
  364. // if (nowgap['mousedwon']) nowgap.mousedwon.call(nowgap,{x:x,y:y})
  365. // if (nowgap['touchstart']) nowgap.touchstart.call(nowgap,{x:x,y:y})
  366. // if (nowgap['mouseenter']) nowgap.mouseenter.call(nowgap,{x:x,y:y})
  367. // }
  368. } else {
  369. this.dragGrpahId = ""
  370. }
  371. this.$emit('touchstart', {
  372. x: x,
  373. y: y
  374. })
  375. },
  376. },
  377. }
  378. </script>
  379. <style lang="scss">
  380. body {}
  381. </style>