util.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import { reactive, watch } from "vue";
  2. import { Attrib, GetSetPick } from "../type";
  3. import { inRevise, toRawType } from "./public";
  4. import { Shape } from "konva/lib/Shape";
  5. import { Group } from "konva/lib/Group";
  6. import { Stage } from "konva/lib/Stage";
  7. import { Circle } from "konva/lib/shapes/Circle";
  8. import { Entity } from "../packages";
  9. export const setShapeConfig = <T extends Group | Shape>(
  10. shape: T,
  11. config: GetSetPick<T>
  12. ) => {
  13. for (const key in config) {
  14. if (typeof shape[key as any] === "function") {
  15. shape[key as any](config[key]);
  16. }
  17. }
  18. };
  19. export const getChangePart = <T>(newIds: T[], oldIds: T[] = []) => {
  20. const addPort = newIds.filter((newId) => !oldIds.includes(newId));
  21. const delPort = oldIds.filter((oldId) => !newIds.includes(oldId));
  22. const holdPort = oldIds.filter((oldId) => newIds.includes(oldId));
  23. return { addPort, delPort, holdPort };
  24. };
  25. export const getChangeAllPoart = <T extends Attrib>(
  26. newAttribs: T[],
  27. oldAttribs: T[]
  28. ) => {
  29. const newIds = newAttribs.map(({ id }) => id);
  30. const oldIds = oldAttribs.map(({ id }) => id);
  31. const ports = getChangePart(newIds, oldIds);
  32. // 数组子项引用变化
  33. const changePort = newAttribs
  34. .filter(
  35. (newAttrib) =>
  36. !oldAttribs.includes(newAttrib) && oldIds.includes(newAttrib.id)
  37. )
  38. .map((attrib) => attrib.id);
  39. oldAttribs = newAttribs;
  40. return { ...ports, changePort };
  41. };
  42. type AttribsChange = ReturnType<typeof getChangePart> & {
  43. changePort: string[];
  44. };
  45. export const watchAttribs = (
  46. attribs: Attrib[],
  47. callback: (data: AttribsChange) => void,
  48. immediate = true
  49. ) => {
  50. return watch(
  51. () => [...attribs],
  52. (newAttribs, oldAttribs = []) => {
  53. callback(getChangeAllPoart(newAttribs, oldAttribs));
  54. },
  55. { immediate, flush: "sync" }
  56. );
  57. };
  58. export const deptComputed = <T extends Record<string, any>>(
  59. getter: () => T
  60. ) => {
  61. const data = reactive(getter());
  62. const stop = watch(getter, (newData) => {
  63. if (inRevise(data, newData)) {
  64. if (Array.isArray(newData)) {
  65. newData.forEach((item, ndx) => {
  66. data[ndx] = item;
  67. });
  68. } else {
  69. Object.keys(data).forEach((key) => delete data[key]);
  70. Object.assign(data, newData);
  71. }
  72. }
  73. });
  74. return {
  75. data: data as T,
  76. stop,
  77. };
  78. };
  79. export const partialComputed = <T extends Attrib>(getter: () => T[]) => {
  80. const data = reactive(getter()) as T[];
  81. const stop = watch(getter, (newData, oldData) => {
  82. const { addPort, delPort, changePort } = getChangeAllPoart(
  83. newData,
  84. oldData
  85. );
  86. for (const delId of delPort) {
  87. const ndx = data.findIndex((i) => i.id === delId);
  88. ~ndx && data.splice(ndx, 1);
  89. }
  90. for (const addId of addPort) {
  91. const addItem = newData.find((i) => i.id === addId);
  92. addItem && data.push(addItem);
  93. }
  94. for (const changeId of changePort) {
  95. const dataNdx = data.findIndex((i) => i.id === changeId);
  96. const newDataNdx = newData.findIndex((i) => i.id === changeId);
  97. if (inRevise(data[dataNdx], newData[newDataNdx])) {
  98. data[dataNdx] = newData[newDataNdx];
  99. }
  100. }
  101. });
  102. return {
  103. data,
  104. stop,
  105. };
  106. };
  107. export const depPartialUpdate = <T>(newData: T, oldData: T): T => {
  108. if (!inRevise(newData, oldData)) {
  109. return oldData;
  110. }
  111. if (!oldData) {
  112. return newData;
  113. }
  114. const nData = newData as any,
  115. oData = oldData as any;
  116. const type = toRawType(nData);
  117. if (toRawType(oldData) !== type) {
  118. return newData;
  119. }
  120. switch (type) {
  121. case "Array":
  122. if (nData[0]?.id || oData[0]?.id) {
  123. var { changePort, addPort, delPort } = getChangeAllPoart(nData, oData);
  124. addPort.forEach((qid) => {
  125. oData.push(nData.find(({ id }) => id === qid));
  126. });
  127. delPort.forEach((dId) => {
  128. const ndx = oData.findIndex(({ id }) => id === dId);
  129. ~ndx && oData.splice(ndx, 1);
  130. });
  131. changePort.forEach((cId) => {
  132. const nItem = nData.find(({ id }) => id === cId);
  133. const ndx = oData.findIndex(({ id }) => id === cId);
  134. oData[ndx] = depPartialUpdate(nItem, oData[ndx]);
  135. });
  136. } else {
  137. for (let i = 0; i < nData.length; i++) {
  138. oData[i] = depPartialUpdate(nData[i], oData[i]);
  139. }
  140. while (oData.length !== nData.length) {
  141. oData.pop();
  142. }
  143. }
  144. break;
  145. case "Object":
  146. const oKeys = Object.keys(oData).sort();
  147. const nKeys = Object.keys(nData).sort();
  148. var { addPort, delPort, holdPort } = getChangePart(nKeys, oKeys);
  149. for (let i = 0; i < holdPort.length; i++) {
  150. oData[oKeys[i]] = depPartialUpdate(
  151. nData[holdPort[i]],
  152. oData[holdPort[i]]
  153. );
  154. }
  155. addPort.forEach((key) => (oData[key] = nData[key]));
  156. delPort.forEach((key) => delete oData[key]);
  157. break;
  158. default:
  159. return newData;
  160. }
  161. return oldData;
  162. };
  163. export const testPoint = (stage: Stage, points: number[][]) => {
  164. points.forEach((point) => {
  165. const test = new Circle({
  166. fill: "red",
  167. radius: 5,
  168. x: point[0],
  169. y: point[1],
  170. });
  171. stage.children[0].add(test);
  172. });
  173. };
  174. export const getFlatChildren = (root: Entity) => {
  175. const flatChildren: Entity[] = [];
  176. for (const child of root.children) {
  177. flatChildren.push(child, ...getFlatChildren(child));
  178. }
  179. return flatChildren;
  180. };
  181. export const generateId = (attribs: Attrib[]) =>
  182. (Math.max(1, ...attribs.map(({ id }) => Number(id))) + 1).toString();