component.tsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import { defineComponent, onMounted , ref, effect} from "vue";
  2. import { string } from "vue-types";
  3. import { useCompData } from ".";
  4. import { useEditor } from "../../../..";
  5. import { View } from "../View";
  6. import { CompUI } from "../..";
  7. import { values } from "lodash";
  8. import { Angle } from "@/modules/editor/controllers/SelectCtrl/objects/mathUtils";
  9. function findNearestPoint(points: number[][], w:number, h:number, sx:number, sy:number) {
  10. const n = points.length;
  11. let minv = 100000;
  12. let minIndex = -1;
  13. const positions = []
  14. for(let i=0; i<n; i++) {
  15. const p = points[i];
  16. const x = w *p[0];
  17. const y = h *p[1];
  18. positions.push([x, y]);
  19. const ln = (sx-x)*(sx-x) + (sy-y)*(sy-y);
  20. if ( ln < minv ) {
  21. minIndex = i;
  22. minv = ln;
  23. if(!(sx < (x -10) || sx > (x + 10) || sy < (y -10) || sy > (y+10) ) ) {
  24. return {clicked: true, index: i};
  25. }
  26. }
  27. }
  28. let preIndex = minIndex -1;
  29. if (preIndex < 0 ) preIndex = n-1;
  30. let afterIndex = minIndex + 1;
  31. if ( afterIndex >= n) afterIndex = 0;
  32. const currV = {x:sx-positions[minIndex][0], y:sy-positions[minIndex][1]};
  33. const preV = {x:positions[preIndex][0]-positions[minIndex][0], y:positions[preIndex][1]-positions[minIndex][1]}
  34. const afterV = {x:positions[afterIndex][0]-positions[minIndex][0], y:positions[afterIndex][1]-positions[minIndex][1]}
  35. const a1 = Angle(currV, preV)
  36. const a2 = Angle(currV, afterV);
  37. if (a1 < a2) {
  38. return {index: preIndex};
  39. }
  40. return {index: minIndex};
  41. }
  42. export const Component = defineComponent({
  43. props: {
  44. compId: string().isRequired,
  45. },
  46. setup(props) {
  47. const { helper, controls , store} = useEditor();
  48. const data = useCompData(props.compId);
  49. const canvasRef = ref<HTMLCanvasElement>();
  50. onMounted(()=>{
  51. // draw();
  52. let isDragingIndex = -1;
  53. canvasRef.value?.addEventListener("dblclick", function(e:MouseEvent){
  54. const x = helper.pxToDesignSize(e.offsetX )
  55. const y = helper.pxToDesignSize(e.offsetY)
  56. const points = data.value.points as number[][];
  57. const w = data.layout.size[0];
  58. const h = data.layout.size[1];
  59. //判断直线相交求解点到直线的距离
  60. const ret = findNearestPoint(data.value.points, w , h, x, y);
  61. //判断是否
  62. console.log("dbclick=>xxxxx", ret);
  63. if (ret.clicked) {//点击删除
  64. points.splice(ret.index, 1);
  65. if (points.length < 4) {
  66. return;
  67. }
  68. } else {
  69. points.splice(ret.index+1, 0, [x / w, y / h]);
  70. }
  71. draw();
  72. })
  73. canvasRef.value?.addEventListener("mousedown", function(e:MouseEvent){
  74. if (store.currCompId != props.compId) return;
  75. const el = canvasRef.value as HTMLCanvasElement;
  76. const x = helper.pxToDesignSize(e.offsetX )
  77. const y = helper.pxToDesignSize(e.offsetY)
  78. console.log(x , y);
  79. const points = data.value.points as number[][];
  80. const width = data.layout.size[0];
  81. const height = data.layout.size[1];
  82. let n = points.length;
  83. isDragingIndex = -1;
  84. let initX = 0;
  85. let initY = 0;
  86. while(n--) {
  87. const p = points[n];
  88. const px = width * p[0];
  89. const py = height * p[1];
  90. if(!(x < (px -10) || x > (px + 10) || y < (py -10) || y > (py+10) ) ) {
  91. isDragingIndex = n;
  92. initX = p[0]
  93. initY = p[1]
  94. break;
  95. }
  96. }
  97. const dragingX = x;
  98. const dragingY = y;
  99. if (isDragingIndex != -1) {
  100. e.preventDefault();
  101. e.stopPropagation();
  102. const move = function (e:MouseEvent){
  103. if ( isDragingIndex == -1) return;
  104. const offx = (helper.pxToDesignSize(e.offsetX ) - dragingX) / width;
  105. const offy = (helper.pxToDesignSize(e.offsetY ) - dragingY) / height;
  106. points[isDragingIndex][0] = initX + offx;
  107. points[isDragingIndex][1] = initY + offy;
  108. draw();
  109. }
  110. el.addEventListener("mousemove", move)
  111. el.addEventListener("mouseup", function(e:MouseEvent){
  112. el.removeEventListener("mousemove", move);
  113. });
  114. el.addEventListener("mouseleave", function(e:MouseEvent){
  115. el.removeEventListener("mousemove", move);
  116. })
  117. }
  118. }, )
  119. effect(draw);
  120. })
  121. function draw() {
  122. const canvas = canvasRef.value as HTMLCanvasElement;
  123. if (!canvas) return;
  124. const ctx = canvasRef.value?.getContext("2d") as CanvasRenderingContext2D;
  125. const width = data.layout.size[0];
  126. const height = data.layout.size[1];
  127. canvas.width = Math.ceil(Math.max(1, width));
  128. canvas.height = Math.ceil(Math.max(1, height));
  129. ctx.clearRect(0, 0, canvas.width, canvas.height);
  130. ctx.lineWidth = data.value.lineWidth;
  131. ctx.strokeStyle = data.value.lineColor;
  132. const padding = 0.2;
  133. ctx.lineJoin = "round";
  134. ctx.beginPath();
  135. let points = data.value.points as number[][];
  136. if (data.value.points.length == 0) {
  137. data.value.points = [[padding, 0.5, 0.4, 0.1], [1 - padding, 0.5, 0.4, 0.1]];
  138. points = data.value.points;
  139. }
  140. points.forEach((p, index)=>{
  141. const x = width * p[0];
  142. const y = height * p[1];
  143. if (index == 0) {
  144. ctx.moveTo(x, y)
  145. } else {
  146. const preIndex = index -1;
  147. const prep = points[preIndex];
  148. if (prep[2] != undefined) {
  149. ctx.quadraticCurveTo( width *prep[2], height *prep[3], x, y);
  150. } else {
  151. ctx.lineTo(x, y);
  152. }
  153. }
  154. })
  155. if (data.value.isClose) {
  156. ctx.closePath();
  157. }
  158. if (data.value.lineWidth !== 0) {
  159. ctx.stroke();
  160. }
  161. if (data.value.isFill) {
  162. let bColor = data.value.fillColor;
  163. if (!bColor) bColor = data.value.lineColor;
  164. ctx.fillStyle = bColor;
  165. ctx.fill();
  166. }
  167. points.forEach((p, index)=>{
  168. const x = width * p[0];
  169. const y = height * p[1];
  170. if (store.isEditMode && store.currCompId == props.compId) {
  171. ctx.fillStyle = "red"
  172. ctx.beginPath();
  173. ctx.arc(x, y, 5, 0, Math.PI*2);
  174. ctx.fill();
  175. }
  176. })
  177. }
  178. return () => (
  179. <View compId={props.compId}>
  180. <canvas ref={canvasRef} style={{width:"100%", height: "100%"}}> </canvas>
  181. </View>
  182. );
  183. },
  184. });