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. import { ui18n } from "@/lang";
  35. export const getRealPixel = (real: number, paperKey: PaperKey) => {
  36. const realPixelScale = paperConfigs[paperKey].scale;
  37. return real * realPixelScale;
  38. };
  39. export const getPixelReal = (pixel: number, paperKey: PaperKey) => {
  40. const realPixelScale = paperConfigs[paperKey].scale;
  41. return pixel / realPixelScale;
  42. };
  43. export const transformPaper = (
  44. real: number,
  45. paperKey: PaperKey,
  46. toPaperKey: PaperKey,
  47. ) => {
  48. const scale = paperConfigs[paperKey].scale / paperConfigs[toPaperKey].scale;
  49. return real * scale;
  50. };
  51. export const getCoverPaperScale = (cover: ImageData, paperKey: PaperKey) => {
  52. let pixelScale = (cover.widthRaw! / cover.width) * cover.proportion!.scale;
  53. const realPixelScale = paperConfigs[paperKey].scale;
  54. return realPixelScale * pixelScale;
  55. };
  56. export const getCoverWidthRaw = (
  57. cover: ImageData,
  58. paperKey: PaperKey,
  59. pp: number,
  60. ) => {
  61. const pixelScale = pp / paperConfigs[paperKey].scale;
  62. const widthRaw = (pixelScale / cover.proportion!.scale) * cover.width;
  63. return widthRaw;
  64. };
  65. export const setCoverPaperScale = (
  66. cover: ImageData,
  67. paperKey: PaperKey,
  68. scale: number,
  69. ) => {
  70. const realPixelScale = paperConfigs[paperKey].scale;
  71. cover.width =
  72. cover.widthRaw! / (scale / realPixelScale / cover.proportion!.scale);
  73. cover.height = (cover.heightRaw! / cover.widthRaw!) * cover.width;
  74. };
  75. export const genTabulationData = async (
  76. paperKey: PaperKey,
  77. compass?: number,
  78. cover?: TabCover | null,
  79. ) => {
  80. const temp: Record<string, string> = await window.platform.getTableTemp();
  81. const { margin, size } = getPaperConfig(
  82. paperConfigs[paperKey].size,
  83. paperConfigs[paperKey].scale,
  84. );
  85. const getTable = async () => {
  86. const w1 = getRealPixel(25, paperKey);
  87. const w2 = getRealPixel(55, paperKey);
  88. const h = getRealPixel(8, paperKey);
  89. const nameColl = {
  90. width: w1,
  91. height: h,
  92. padding: getRealPixel(2, paperKey),
  93. content: "",
  94. align: "center",
  95. fontSize: getRealPixel(4, paperKey),
  96. fontColor: "#000000",
  97. };
  98. const valueColl = { ...nameColl, width: w2 };
  99. const tableTemp = temp.table;
  100. const rows = Object.entries(tableTemp);
  101. const data = {
  102. ...getBaseItem(),
  103. content: rows.map(([name, value]) => [
  104. { ...nameColl, content: name },
  105. { ...valueColl, content: value },
  106. ]),
  107. fontSize: getRealPixel(4, paperKey),
  108. key: tableTableKey,
  109. width: nameColl.width + valueColl.width,
  110. height: nameColl.height * rows.length,
  111. titleHeight: h,
  112. title: temp.tableTitle,
  113. mat: [1, 0, 0, 1, 0, 0],
  114. fill: null,
  115. };
  116. const pos = getFixPosition(
  117. {
  118. right: getRealPixel(15, paperKey) + margin[1],
  119. bottom: getRealPixel(15, paperKey) + margin[2],
  120. },
  121. data,
  122. size,
  123. );
  124. return matResponse({ data, mat: new Transform().translate(pos.x, pos.y) });
  125. };
  126. const getCover = async () => {
  127. if (!cover) return;
  128. const image = await getImage(window.platform.getResource(cover.url));
  129. const rectScale = image.width / image.height;
  130. const tableCoverScale = tableCoverWidth / tableCoverHeight;
  131. let width: number, height: number;
  132. if (rectScale > tableCoverScale) {
  133. width = transformPaper(tableCoverWidth, paperKey, "a4");
  134. height = width / rectScale;
  135. } else {
  136. height = transformPaper(tableCoverHeight, paperKey, "a4");
  137. width = rectScale * height;
  138. }
  139. const coverData = {
  140. ...getBaseItem(),
  141. cornerRadius: 0,
  142. strokeWidth: 0,
  143. disableDelete: true,
  144. url: cover.url,
  145. key: tableCoverKey,
  146. proportion: cover.proportion,
  147. disableTransformer: true,
  148. widthRaw: cover.width,
  149. showScale: true,
  150. heightRaw: cover.height,
  151. zIndex: -1,
  152. width,
  153. height,
  154. mat: [1, 0, 0, 1, 0, 0],
  155. itemName: ui18n.t('cover.itemName'),
  156. };
  157. const pos = getFixPosition(
  158. {
  159. left: coverData.width / 2 + margin[3] + getRealPixel(15, paperKey),
  160. bottom: -coverData.height / 2 + margin[2] + getRealPixel(15, paperKey),
  161. },
  162. coverData,
  163. size,
  164. );
  165. coverData.mat[4] = pos.x;
  166. coverData.mat[5] = pos.y;
  167. const scale = getCoverPaperScale(coverData, paperKey);
  168. setCoverPaperScale(coverData, paperKey, Math.round(scale / 10) * 10 || 10);
  169. return coverData;
  170. };
  171. const getCoverScale = (cover: ImageData) => {
  172. const scale = (cover.widthRaw! / cover.width) * cover.proportion!.scale;
  173. const text = {
  174. ...getBaseItem(),
  175. content: `1:${scale}`,
  176. width: getRealPixel(30, paperKey),
  177. heihgt: getRealPixel(4.8, paperKey),
  178. fontSize: getRealPixel(4, paperKey),
  179. disableEditText: true,
  180. key: tableCoverScaleKey,
  181. disableDelete: true,
  182. align: "center",
  183. mat: [1, 0, 0, 1, 0, 0],
  184. };
  185. const x = cover.mat[4] - (text.width || 0) / 2;
  186. const y = cover.mat[5] + cover.height / 2 + getRealPixel(5, paperKey);
  187. text.mat[4] = x;
  188. text.mat[5] = y;
  189. return text;
  190. };
  191. const getTitle = () => {
  192. const title = {
  193. ...getBaseItem(),
  194. content: temp.title,
  195. width: size.width - margin[1] - margin[3],
  196. heihgt: getRealPixel(14.4, paperKey),
  197. fontSize: getRealPixel(12, paperKey),
  198. key: tableTitleKey,
  199. align: "center",
  200. mat: [1, 0, 0, 1, 0, 0],
  201. };
  202. const pos = {
  203. x: margin[3],
  204. y: getRealPixel(15, paperKey) + margin[0],
  205. };
  206. title.mat[4] = pos.x;
  207. title.mat[5] = pos.y;
  208. return title;
  209. };
  210. const getCompass = async () => {
  211. const mat = new Transform().rotate(MathUtils.degToRad(compass!));
  212. const style = await getIconStyle(
  213. "./icons/compass.svg",
  214. getRealPixel(37.3366 / 2.3, paperKey),
  215. getRealPixel(60 / 2.3, paperKey),
  216. );
  217. const data: IconData = {
  218. ...getBaseItem(),
  219. ...style,
  220. disableDelete: true,
  221. itemName: ui18n.t('compass.name'),
  222. coverOpcatiy: 0,
  223. strokeScaleEnabled: false,
  224. key: tableCompassKey,
  225. mat: mat.m,
  226. name: ui18n.t('compass.name'),
  227. };
  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. };