gen-tab.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. import { getBaseItem } from "@/core/components/util";
  2. import {
  3. getPaperConfig,
  4. paperConfigs,
  5. PaperKey,
  6. } from "@/example/components/slide/actions";
  7. import {
  8. tableCompassKey,
  9. tableCoverHeight,
  10. tableCoverKey,
  11. tableCoverScaleKey,
  12. tableCoverWidth,
  13. tableTableKey,
  14. tableTitleKey,
  15. } from "../../../constant";
  16. import { matResponse } from "@/core/components/table";
  17. import { Transform } from "konva/lib/Util";
  18. import { getFixPosition } from "@/utils/bound";
  19. import { getImage } from "@/utils/resource";
  20. import { ImageData } from "@/core/components/image";
  21. import { DrawData } from "@/core/components";
  22. import { getEmptyStoreData, StoreData } from "@/core/store/store";
  23. import { defaultLayer } from "@/constant";
  24. import { getIconStyle, IconData } from "@/core/components/icon";
  25. import { MathUtils } from "three";
  26. import {
  27. getCurrentNdxRaw,
  28. getSerialFontW,
  29. joinKey,
  30. SerialData,
  31. defaultStyle as serialDefaultStyle,
  32. } from "@/core/components/serial";
  33. import type { TabCover } from "../../store";
  34. export const getRealPixel = (real: number, paperKey: PaperKey) => {
  35. const realPixelScale = paperConfigs[paperKey].scale;
  36. return real * realPixelScale;
  37. };
  38. export const getPixelReal = (pixel: number, paperKey: PaperKey) => {
  39. const realPixelScale = paperConfigs[paperKey].scale;
  40. return pixel / realPixelScale;
  41. };
  42. export const transformPaper = (
  43. real: number,
  44. paperKey: PaperKey,
  45. toPaperKey: PaperKey,
  46. ) => {
  47. const scale = paperConfigs[paperKey].scale / paperConfigs[toPaperKey].scale;
  48. return real * scale;
  49. };
  50. export const getCoverPaperScale = (cover: ImageData, paperKey: PaperKey) => {
  51. let pixelScale = (cover.widthRaw! / cover.width) * cover.proportion!.scale;
  52. const realPixelScale = paperConfigs[paperKey].scale;
  53. return realPixelScale * pixelScale;
  54. };
  55. export const getCoverWidthRaw = (
  56. cover: ImageData,
  57. paperKey: PaperKey,
  58. pp: number,
  59. ) => {
  60. const pixelScale = pp / paperConfigs[paperKey].scale;
  61. const widthRaw = (pixelScale / cover.proportion!.scale) * cover.width;
  62. return widthRaw;
  63. };
  64. export const setCoverPaperScale = (
  65. cover: ImageData,
  66. paperKey: PaperKey,
  67. scale: number,
  68. ) => {
  69. const realPixelScale = paperConfigs[paperKey].scale;
  70. cover.width =
  71. cover.widthRaw! / (scale / realPixelScale / cover.proportion!.scale);
  72. cover.height = (cover.heightRaw! / cover.widthRaw!) * cover.width;
  73. };
  74. export const genTabulationData = async (
  75. paperKey: PaperKey,
  76. compass?: number,
  77. cover?: TabCover | null,
  78. ) => {
  79. const temp: Record<string, string> = await window.platform.getTableTemp();
  80. const { margin, size } = getPaperConfig(
  81. paperConfigs[paperKey].size,
  82. paperConfigs[paperKey].scale,
  83. );
  84. const getTable = async () => {
  85. const w1 = getRealPixel(25, paperKey);
  86. const w2 = getRealPixel(55, paperKey);
  87. const h = getRealPixel(8, paperKey);
  88. const nameColl = {
  89. width: w1,
  90. height: h,
  91. padding: getRealPixel(2, paperKey),
  92. content: "",
  93. align: "center",
  94. fontSize: getRealPixel(4, paperKey),
  95. fontColor: "#000000",
  96. };
  97. const valueColl = { ...nameColl, width: w2 };
  98. const tableTemp = temp.table;
  99. const rows = Object.entries(tableTemp);
  100. const data = {
  101. ...getBaseItem(),
  102. content: rows.map(([name, value]) => [
  103. { ...nameColl, content: name },
  104. { ...valueColl, content: value },
  105. ]),
  106. fontSize: getRealPixel(4, paperKey),
  107. key: tableTableKey,
  108. width: nameColl.width + valueColl.width,
  109. height: nameColl.height * rows.length,
  110. titleHeight: h,
  111. title: temp.tableTitle,
  112. mat: [1, 0, 0, 1, 0, 0],
  113. fill: null,
  114. };
  115. const pos = getFixPosition(
  116. {
  117. right: getRealPixel(15, paperKey) + margin[1],
  118. bottom: getRealPixel(15, paperKey) + margin[2],
  119. },
  120. data,
  121. size,
  122. );
  123. return matResponse({ data, mat: new Transform().translate(pos.x, pos.y) });
  124. };
  125. const getCover = async () => {
  126. if (!cover) return;
  127. const image = await getImage(window.platform.getResource(cover.url));
  128. const rectScale = image.width / image.height;
  129. const tableCoverScale = tableCoverWidth / tableCoverHeight;
  130. let width: number, height: number;
  131. if (rectScale > tableCoverScale) {
  132. width = transformPaper(tableCoverWidth, paperKey, "a4");
  133. height = width / rectScale;
  134. } else {
  135. height = transformPaper(tableCoverHeight, paperKey, "a4");
  136. width = rectScale * height;
  137. }
  138. const coverData = {
  139. ...getBaseItem(),
  140. cornerRadius: 0,
  141. strokeWidth: 0,
  142. disableDelete: true,
  143. url: cover.url,
  144. key: tableCoverKey,
  145. proportion: cover.proportion,
  146. disableTransformer: true,
  147. widthRaw: cover.width,
  148. showScale: true,
  149. heightRaw: cover.height,
  150. zIndex: -1,
  151. width,
  152. height,
  153. mat: [1, 0, 0, 1, 0, 0],
  154. itemName: "比例",
  155. };
  156. const pos = getFixPosition(
  157. {
  158. left: coverData.width / 2 + margin[3] + getRealPixel(15, paperKey),
  159. bottom: -coverData.height / 2 + margin[2] + getRealPixel(15, paperKey),
  160. },
  161. coverData,
  162. size,
  163. );
  164. coverData.mat[4] = pos.x;
  165. coverData.mat[5] = pos.y;
  166. const scale = getCoverPaperScale(coverData, paperKey);
  167. setCoverPaperScale(coverData, paperKey, Math.round(scale / 10) * 10 || 10);
  168. return coverData;
  169. };
  170. const getCoverScale = (cover: ImageData) => {
  171. const scale = (cover.widthRaw! / cover.width) * cover.proportion!.scale;
  172. const text = {
  173. ...getBaseItem(),
  174. content: `1:${scale}`,
  175. width: getRealPixel(30, paperKey),
  176. heihgt: getRealPixel(4.8, paperKey),
  177. fontSize: getRealPixel(4, paperKey),
  178. disableEditText: true,
  179. key: tableCoverScaleKey,
  180. disableDelete: true,
  181. align: "center",
  182. mat: [1, 0, 0, 1, 0, 0],
  183. };
  184. const x = cover.mat[4] - (text.width || 0) / 2;
  185. const y = cover.mat[5] + cover.height / 2 + getRealPixel(5, paperKey);
  186. text.mat[4] = x;
  187. text.mat[5] = y;
  188. return text;
  189. };
  190. const getTitle = () => {
  191. const title = {
  192. ...getBaseItem(),
  193. content: temp.title,
  194. width: size.width - margin[1] - margin[3],
  195. heihgt: getRealPixel(14.4, paperKey),
  196. fontSize: getRealPixel(12, paperKey),
  197. key: tableTitleKey,
  198. align: "center",
  199. mat: [1, 0, 0, 1, 0, 0],
  200. };
  201. const pos = {
  202. x: margin[3],
  203. y: getRealPixel(15, paperKey) + margin[0],
  204. };
  205. title.mat[4] = pos.x;
  206. title.mat[5] = pos.y;
  207. return title;
  208. };
  209. const getCompass = async () => {
  210. const mat = new Transform().rotate(MathUtils.degToRad(compass!));
  211. const style = await getIconStyle(
  212. "./icons/compass.svg",
  213. getRealPixel(37.3366 / 2.3, paperKey),
  214. getRealPixel(60 / 2.3, paperKey),
  215. );
  216. const data: IconData = {
  217. ...getBaseItem(),
  218. ...style,
  219. disableDelete: true,
  220. itemName: "指南针",
  221. coverOpcatiy: 0,
  222. strokeScaleEnabled: false,
  223. key: tableCompassKey,
  224. mat: mat.m,
  225. name: "指南针",
  226. };
  227. console.error("指南针", data);
  228. const pos = getFixPosition(
  229. {
  230. right: getRealPixel(8, paperKey) + margin[1],
  231. top: getRealPixel(42, paperKey) + margin[2],
  232. },
  233. data,
  234. size,
  235. );
  236. data.mat[4] = pos.x;
  237. data.mat[5] = pos.y;
  238. return data;
  239. };
  240. const getSerials = (refImage: ImageData, items: TabCover["syncItems"]) => {
  241. if (!items) return;
  242. const scale = refImage.width / refImage.widthRaw!;
  243. const offset = {
  244. x: refImage.widthRaw! / 2,
  245. y: refImage.heightRaw! / 2,
  246. };
  247. const mat = new Transform()
  248. .multiply(new Transform(refImage.mat))
  249. .scale(scale, scale)
  250. .translate(-offset.x, -offset.y);
  251. const serials: SerialData[] = [];
  252. let i = 0;
  253. for (const shape of items) {
  254. const start = {
  255. x: shape.rect.x,
  256. y: shape.rect.y,
  257. // x: refImage.widthRaw,
  258. // y: refImage.heightRaw
  259. };
  260. const point = mat.point(start);
  261. const s = {
  262. ...serialDefaultStyle,
  263. ...getBaseItem(),
  264. padding: 3,
  265. key: "join-" + shape.id,
  266. content: (++i).toString(),
  267. strokeWidth: getRealPixel(0.5, paperKey),
  268. mat: [1, 0, 0, 1, point.x, point.y],
  269. radiusX: 1,
  270. desc: shape.desc || "",
  271. radiusY: 1,
  272. };
  273. const radius = (getSerialFontW(s) * Math.sqrt(2)) / 2;
  274. s.radiusX = s.radiusY = radius;
  275. serials.push(s);
  276. }
  277. return serials;
  278. };
  279. const data: DrawData = {
  280. table: [await getTable()],
  281. serial: [],
  282. };
  283. if (temp.title) {
  284. data.text = [getTitle()];
  285. }
  286. const image = await getCover();
  287. if (image) {
  288. data.image = [image];
  289. data.text!.push(getCoverScale(image));
  290. const serials = getSerials(image, cover?.syncItems);
  291. if (serials) {
  292. data.serial = serials;
  293. }
  294. }
  295. if (compass !== undefined) {
  296. data.icon = [await getCompass()];
  297. }
  298. return data;
  299. };
  300. export const repTabulationStore = async (
  301. paperKey: PaperKey,
  302. compass?: number,
  303. cover?: TabCover,
  304. store?: StoreData,
  305. ) => {
  306. const repData = await genTabulationData(paperKey, compass, cover);
  307. const layer = store?.layers && store?.layers[defaultLayer];
  308. if (!layer || !store.config) {
  309. return {
  310. ...(store || {}),
  311. config: {
  312. ...getEmptyStoreData().config,
  313. ...(store?.config || {}),
  314. },
  315. layers: {
  316. ...(store?.layers || {}),
  317. [defaultLayer]: repData,
  318. },
  319. };
  320. }
  321. if (repData.image?.length) {
  322. const imageData = repData.image[0];
  323. const images = layer.image || [];
  324. const imageNdx = images.findIndex((item) => item.key === imageData.key);
  325. if (~imageNdx) {
  326. images[imageNdx] = imageData;
  327. images[imageNdx] = {
  328. ...imageData,
  329. mat: images[imageNdx].mat,
  330. };
  331. } else {
  332. images.push(imageData);
  333. }
  334. layer.image = images;
  335. const scaleData = repData.text!.find(
  336. (item) => item.key === tableCoverScaleKey,
  337. )!;
  338. const texts = layer.text || [];
  339. const textNdx = texts.findIndex((item) => item.key === scaleData.key);
  340. if (~textNdx) {
  341. texts[textNdx].content = scaleData.content;
  342. } else {
  343. texts.push(scaleData);
  344. }
  345. layer.text = texts;
  346. }
  347. if (repData.icon) {
  348. const iconData = repData.icon[0];
  349. const icons = layer.icon || [];
  350. const iconNdx = icons.findIndex((item) => item.key === iconData.key);
  351. if (~iconNdx) {
  352. icons[iconNdx] = iconData;
  353. } else {
  354. icons.push(iconData);
  355. }
  356. layer.icon = icons;
  357. }
  358. if (repData.serial) {
  359. if (layer.serial) {
  360. const oldSerials = [...layer.serial];
  361. const notAutoSerials = oldSerials.filter(
  362. (item) => !item.key?.startsWith("join-"),
  363. );
  364. const newSerials = [...repData.serial, ...notAutoSerials];
  365. layer.serial = newSerials;
  366. const tableNdx = layer.table
  367. ? layer.table.findIndex((table) => table.key === joinKey)
  368. : -1;
  369. if (~tableNdx) {
  370. const table = layer.table![tableNdx];
  371. layer.table!.splice(tableNdx, 1);
  372. for (const serial of notAutoSerials) {
  373. for (let r = 0; r < table.content.length; r++) {
  374. for (let c = 0; c < table.content[r].length; c += 2) {
  375. if (table.content[r][c].content === serial.content) {
  376. serial.desc = table.content[r][c + 1].content;
  377. }
  378. }
  379. }
  380. }
  381. }
  382. const updateSerials = [...repData.serial];
  383. for (const serial of notAutoSerials) {
  384. serial.content = getCurrentNdxRaw(updateSerials);
  385. updateSerials.push(serial);
  386. }
  387. } else {
  388. layer.serial = repData.serial;
  389. }
  390. }
  391. // if (import.meta.env.DEV) {
  392. // layer.table = repData.table
  393. // layer.text = repData.text
  394. // }
  395. store.layers[defaultLayer] = layer;
  396. return store;
  397. };