import { reactive, watch } from "vue"; import { Attrib, GetSetPick } from "../type"; import { inRevise, toRawType } from "./public"; import { Shape } from "konva/lib/Shape"; import { Group } from "konva/lib/Group"; export const setShapeConfig = ( shape: T, config: GetSetPick ) => { for (const key in config) { if (typeof shape[key as any] === "function") { shape[key as any](config[key]); } } }; export const getChangePart = (newIds: T[], oldIds: T[] = []) => { const addPort = newIds.filter((newId) => !oldIds.includes(newId)); const delPort = oldIds.filter((oldId) => !newIds.includes(oldId)); const holdPort = oldIds.filter((oldId) => newIds.includes(oldId)); return { addPort, delPort, holdPort }; }; export const getChangeAllPoart = ( newAttribs: T[], oldAttribs: T[] ) => { const newIds = newAttribs.map(({ id }) => id); const oldIds = oldAttribs.map(({ id }) => id); const ports = getChangePart(newIds, oldIds); // 数组子项引用变化 const changePort = newAttribs .filter( (newAttrib) => !oldAttribs.includes(newAttrib) && oldIds.includes(newAttrib.id) ) .map((attrib) => attrib.id); oldAttribs = newAttribs; return { ...ports, changePort }; }; type AttribsChange = ReturnType & { changePort: string[]; }; export const watchAttribs = ( attribs: Attrib[], callback: (data: AttribsChange) => void, immediate = true ) => { return watch( () => [...attribs], (newAttribs, oldAttribs = []) => { callback(getChangeAllPoart(newAttribs, oldAttribs)); }, { immediate, flush: "sync" } ); }; export const deptComputed = >( getter: () => T ) => { const data = reactive(getter()); const stop = watch(getter, (newData) => { if (inRevise(data, newData)) { if (Array.isArray(newData)) { newData.forEach((item, ndx) => { data[ndx] = item; }); } else { Object.keys(data).forEach((key) => delete data[key]); Object.assign(data, newData); } } }); return { data: data as T, stop, }; }; export const partialComputed = (getter: () => T[]) => { const data = reactive(getter()) as T[]; const stop = watch(getter, (newData, oldData) => { const { addPort, delPort, changePort } = getChangeAllPoart( newData, oldData ); for (const delId of delPort) { const ndx = data.findIndex((i) => i.id === delId); ~ndx && data.splice(ndx, 1); } for (const addId of addPort) { const addItem = newData.find((i) => i.id === addId); addItem && data.push(addItem); } for (const changeId of changePort) { const dataNdx = data.findIndex((i) => i.id === changeId); const newDataNdx = newData.findIndex((i) => i.id === changeId); if (inRevise(data[dataNdx], newData[newDataNdx])) { data[dataNdx] = newData[newDataNdx]; } } }); return { data, stop, }; }; export const depPartialUpdate = (newData: T, oldData: T): T => { if (!inRevise(newData, oldData)) { return oldData; } if (!oldData) { return newData; } const nData = newData as any, oData = oldData as any; const type = toRawType(nData); if (toRawType(oldData) !== type) { return newData; } switch (type) { case "Array": if (nData[0]?.id || oData[0]?.id) { var { changePort, addPort, delPort } = getChangeAllPoart(nData, oData); addPort.forEach((qid) => { oData.push(nData.find(({ id }) => id === qid)); }); delPort.forEach((dId) => { const ndx = oData.findIndex(({ id }) => id === dId); ~ndx && oData.splice(ndx, 1); }); changePort.forEach((cId) => { const nItem = nData.find(({ id }) => id === cId); const ndx = oData.findIndex(({ id }) => id === cId); oData[ndx] = depPartialUpdate(nItem, oData[ndx]); }); } else { for (let i = 0; i < nData.length; i++) { oData[i] = depPartialUpdate(nData[i], oData[i]); } while (oData.length !== nData.length) { oData.pop(); } } break; case "Object": const oKeys = Object.keys(oData).sort(); const nKeys = Object.keys(nData).sort(); var { addPort, delPort, holdPort } = getChangePart(nKeys, oKeys); for (let i = 0; i < holdPort.length; i++) { oData[oKeys[i]] = depPartialUpdate( nData[holdPort[i]], oData[holdPort[i]] ); } addPort.forEach((key) => (oData[key] = nData[key])); delPort.forEach((key) => delete oData[key]); break; default: return newData; } return oldData; };