import { Transform } from "konva/lib/Util"; import { BaseItem, generateSnapInfos, getBaseItem, getRectSnapPoints, } from "../util.ts"; import { getMouseColors } from "@/utils/colors.ts"; import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts"; import { Size } from "@/utils/math.ts"; import { getSvgContent, parseSvgContent } from "@/utils/resource.ts"; import { Color } from "three"; export const shapeName = "图例"; export const defaultStyle = { coverFill: "#000000", coverOpcatiy: 0, strokeScaleEnabled: false, width: 80, height: 80, }; type ColorCounts = [string, number][]; const colorsManage = (counts: ColorCounts, color: any) => { if (!color) { return; } const colorHex = new Color(color).getHexString(); const item = counts.find(([c]) => c === colorHex); if (!item) { counts.push([colorHex, 1]); } else { item[1]++; } }; const findColor = (counts: ColorCounts) => { let ndx = -1; let max = 0; for (let i = 0; i < counts.length; i++) { if (counts[i][1] >= max) { ndx = i; max = counts[i][1]; } } if (~ndx) { return `#${counts[ndx][0]}`; } }; export const getIconStyle = async ( url: string, width = defaultStyle.width, height = defaultStyle.height, fixed = false ) => { const svgContent = parseSvgContent(await getSvgContent(url)); if (!fixed) { if (width / height > svgContent.width / svgContent.height) { width = (svgContent.width / svgContent.height) * height; } else { height = (svgContent.height / svgContent.width) * width; } } const fillColorCounts: [string, number][] = []; const strokeColorCounts: [string, number][] = []; for (let i = 0; i < svgContent.paths.length; i++) { colorsManage(fillColorCounts, svgContent.paths[i].fill); colorsManage(strokeColorCounts, svgContent.paths[i].stroke); } const color = { fill: findColor(fillColorCounts) || null, stroke: findColor(strokeColorCounts) || null, }; if (!color.fill && !color.stroke) { color.stroke = "#000000"; } return { url, width, height, ...color, }; }; export const addMode = "dot"; export const getSnapInfos = (data: IconData) => { return generateSnapInfos(getSnapPoints(data), true, false); }; export const getSnapPoints = (data: IconData) => { const tf = new Transform(data.mat); const w = data.width || defaultStyle.width; const h = data.height || defaultStyle.height; const points = getRectSnapPoints(w, h); return points.map((v) => tf.point(v)); }; export const getMouseStyle = (data: IconData) => { const fillStatus = getMouseColors(data.coverFill || defaultStyle.coverFill); const hCoverOpcaoty = data.coverOpcatiy ? data.coverOpcatiy : 0.3; return { default: { coverFill: data.coverFill || defaultStyle.coverFill, coverOpcatiy: data.coverOpcatiy || 0, }, hover: { coverFill: fillStatus.hover, coverOpcatiy: hCoverOpcaoty }, select: { coverFill: fillStatus.select, coverOpcatiy: hCoverOpcaoty }, focus: { coverFill: fillStatus.select, coverOpcatiy: hCoverOpcaoty }, press: { coverFill: fillStatus.press, coverOpcatiy: hCoverOpcaoty }, }; }; export type IconData = Partial & BaseItem & Size & { fill?: string | null; stroke?: string | null; name?: string; strokeWidth?: number; coverFill?: string; coverStroke?: string; coverStrokeWidth?: number; mat: number[]; url: string; }; export const dataToConfig = (data: IconData) => { return { ...defaultStyle, ...data, }; }; export const interactiveToData: InteractiveTo<"icon"> = ({ info, preset = {}, viewTransform, ...args }) => { if (info.cur) { console.error(preset); return interactiveFixData({ ...args, viewTransform, info, data: { ...getBaseItem(), ...preset } as unknown as IconData, }); } }; export const interactiveFixData: InteractiveFix<"icon"> = ({ data, info, }) => { const mat = new Transform().translate(info.cur!.x, info.cur!.y); data.mat = mat.m; return data; }; export const matResponse = ({ data, mat, increment, }: MatResponseProps<"icon">) => { data.mat = increment ? mat.copy().multiply(new Transform(data.mat)).m : mat.m; return data; }; export const getPredefine = (key: keyof IconData) => { if (key === "fill" || key === "stroke") { return { canun: true }; } };