@antv/infographic 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +54 -40
  2. package/README.zh-CN.md +52 -36
  3. package/dist/infographic.min.js +110 -105
  4. package/dist/infographic.min.js.map +1 -1
  5. package/esm/constants/element.d.ts +1 -1
  6. package/esm/constants/index.d.ts +1 -0
  7. package/esm/constants/index.js +1 -0
  8. package/esm/constants/service.d.ts +1 -0
  9. package/esm/constants/service.js +1 -0
  10. package/esm/designs/components/Illus.js +1 -1
  11. package/esm/designs/structures/chart-wordcloud.d.ts +11 -0
  12. package/esm/designs/structures/chart-wordcloud.js +156 -0
  13. package/esm/designs/structures/hierarchy-tree.d.ts +2 -0
  14. package/esm/designs/structures/hierarchy-tree.js +179 -50
  15. package/esm/designs/structures/index.d.ts +2 -0
  16. package/esm/designs/structures/index.js +2 -0
  17. package/esm/designs/structures/sequence-stairs-front.d.ts +8 -0
  18. package/esm/designs/structures/sequence-stairs-front.js +116 -0
  19. package/esm/designs/types.d.ts +8 -0
  20. package/esm/editor/managers/state.js +1 -1
  21. package/esm/exporter/font.js +4 -9
  22. package/esm/index.d.ts +2 -0
  23. package/esm/index.js +1 -0
  24. package/esm/options/parser.d.ts +1 -1
  25. package/esm/options/parser.js +33 -15
  26. package/esm/renderer/composites/icon.js +1 -1
  27. package/esm/renderer/composites/illus.js +1 -1
  28. package/esm/resource/loader.d.ts +2 -2
  29. package/esm/resource/loader.js +22 -11
  30. package/esm/resource/loaders/index.d.ts +1 -0
  31. package/esm/resource/loaders/index.js +1 -0
  32. package/esm/resource/loaders/remote.d.ts +1 -1
  33. package/esm/resource/loaders/remote.js +12 -3
  34. package/esm/resource/loaders/search.d.ts +1 -0
  35. package/esm/resource/loaders/search.js +52 -0
  36. package/esm/resource/types/index.d.ts +1 -0
  37. package/esm/resource/types/resource.d.ts +8 -1
  38. package/esm/resource/types/scene.d.ts +1 -0
  39. package/esm/resource/utils/data-uri.js +20 -11
  40. package/esm/resource/utils/parser.js +92 -1
  41. package/esm/resource/utils/ref.js +2 -2
  42. package/esm/runtime/Infographic.d.ts +10 -6
  43. package/esm/runtime/Infographic.js +66 -17
  44. package/esm/runtime/utils.d.ts +4 -2
  45. package/esm/runtime/utils.js +33 -13
  46. package/esm/syntax/index.d.ts +3 -0
  47. package/esm/syntax/index.js +101 -0
  48. package/esm/syntax/mapper.d.ts +3 -0
  49. package/esm/syntax/mapper.js +334 -0
  50. package/esm/syntax/parser.d.ts +14 -0
  51. package/esm/syntax/parser.js +142 -0
  52. package/esm/syntax/schema.d.ts +6 -0
  53. package/esm/syntax/schema.js +86 -0
  54. package/esm/syntax/types.d.ts +68 -0
  55. package/esm/syntax/types.js +1 -0
  56. package/esm/templates/built-in.js +4 -0
  57. package/esm/templates/hierarchy-tree.js +25 -11
  58. package/esm/templates/sequence-stairs.d.ts +2 -0
  59. package/esm/templates/sequence-stairs.js +42 -0
  60. package/esm/templates/word-cloud.d.ts +2 -0
  61. package/esm/templates/word-cloud.js +19 -0
  62. package/esm/themes/types.d.ts +1 -1
  63. package/esm/utils/design.d.ts +2 -0
  64. package/esm/utils/design.js +10 -0
  65. package/esm/utils/fetch.d.ts +1 -0
  66. package/esm/utils/fetch.js +61 -0
  67. package/esm/utils/font.js +11 -1
  68. package/esm/utils/index.d.ts +2 -0
  69. package/esm/utils/index.js +2 -0
  70. package/lib/constants/element.d.ts +1 -1
  71. package/lib/constants/index.d.ts +1 -0
  72. package/lib/constants/index.js +1 -0
  73. package/lib/constants/service.d.ts +1 -0
  74. package/lib/constants/service.js +4 -0
  75. package/lib/designs/components/Illus.js +1 -1
  76. package/lib/designs/structures/chart-wordcloud.d.ts +11 -0
  77. package/lib/designs/structures/chart-wordcloud.js +160 -0
  78. package/lib/designs/structures/hierarchy-tree.d.ts +2 -0
  79. package/lib/designs/structures/hierarchy-tree.js +179 -50
  80. package/lib/designs/structures/index.d.ts +2 -0
  81. package/lib/designs/structures/index.js +2 -0
  82. package/lib/designs/structures/sequence-stairs-front.d.ts +8 -0
  83. package/lib/designs/structures/sequence-stairs-front.js +120 -0
  84. package/lib/designs/types.d.ts +8 -0
  85. package/lib/editor/managers/state.js +1 -1
  86. package/lib/exporter/font.js +3 -8
  87. package/lib/index.d.ts +2 -0
  88. package/lib/index.js +4 -1
  89. package/lib/options/parser.d.ts +1 -1
  90. package/lib/options/parser.js +32 -14
  91. package/lib/renderer/composites/icon.js +1 -1
  92. package/lib/renderer/composites/illus.js +1 -1
  93. package/lib/resource/loader.d.ts +2 -2
  94. package/lib/resource/loader.js +21 -10
  95. package/lib/resource/loaders/index.d.ts +1 -0
  96. package/lib/resource/loaders/index.js +1 -0
  97. package/lib/resource/loaders/remote.d.ts +1 -1
  98. package/lib/resource/loaders/remote.js +12 -3
  99. package/lib/resource/loaders/search.d.ts +1 -0
  100. package/lib/resource/loaders/search.js +55 -0
  101. package/lib/resource/types/index.d.ts +1 -0
  102. package/lib/resource/types/resource.d.ts +8 -1
  103. package/lib/resource/types/scene.d.ts +1 -0
  104. package/lib/resource/utils/data-uri.js +20 -11
  105. package/lib/resource/utils/parser.js +92 -1
  106. package/lib/resource/utils/ref.js +2 -2
  107. package/lib/runtime/Infographic.d.ts +10 -6
  108. package/lib/runtime/Infographic.js +65 -16
  109. package/lib/runtime/utils.d.ts +4 -2
  110. package/lib/runtime/utils.js +35 -13
  111. package/lib/syntax/index.d.ts +3 -0
  112. package/lib/syntax/index.js +104 -0
  113. package/lib/syntax/mapper.d.ts +3 -0
  114. package/lib/syntax/mapper.js +341 -0
  115. package/lib/syntax/parser.d.ts +14 -0
  116. package/lib/syntax/parser.js +146 -0
  117. package/lib/syntax/schema.d.ts +6 -0
  118. package/lib/syntax/schema.js +89 -0
  119. package/lib/syntax/types.d.ts +68 -0
  120. package/lib/syntax/types.js +2 -0
  121. package/lib/templates/built-in.js +4 -0
  122. package/lib/templates/hierarchy-tree.js +25 -11
  123. package/lib/templates/sequence-stairs.d.ts +2 -0
  124. package/lib/templates/sequence-stairs.js +45 -0
  125. package/lib/templates/word-cloud.d.ts +2 -0
  126. package/lib/templates/word-cloud.js +22 -0
  127. package/lib/themes/types.d.ts +1 -1
  128. package/lib/utils/design.d.ts +2 -0
  129. package/lib/utils/design.js +13 -0
  130. package/lib/utils/fetch.d.ts +1 -0
  131. package/lib/utils/fetch.js +67 -0
  132. package/lib/utils/font.js +11 -1
  133. package/lib/utils/index.d.ts +2 -0
  134. package/lib/utils/index.js +2 -0
  135. package/package.json +14 -2
  136. package/src/constants/element.ts +1 -1
  137. package/src/constants/index.ts +1 -0
  138. package/src/constants/service.ts +1 -0
  139. package/src/designs/components/Illus.tsx +1 -1
  140. package/src/designs/structures/chart-wordcloud.tsx +278 -0
  141. package/src/designs/structures/hierarchy-tree.tsx +212 -59
  142. package/src/designs/structures/index.ts +2 -0
  143. package/src/designs/structures/sequence-stairs-front.tsx +291 -0
  144. package/src/designs/types.ts +9 -0
  145. package/src/editor/managers/state.ts +1 -1
  146. package/src/exporter/font.ts +4 -9
  147. package/src/index.ts +2 -0
  148. package/src/options/parser.ts +57 -28
  149. package/src/renderer/composites/icon.ts +1 -1
  150. package/src/renderer/composites/illus.ts +1 -1
  151. package/src/resource/loader.ts +22 -8
  152. package/src/resource/loaders/index.ts +1 -0
  153. package/src/resource/loaders/remote.ts +11 -3
  154. package/src/resource/loaders/search.ts +53 -0
  155. package/src/resource/types/index.ts +2 -1
  156. package/src/resource/types/resource.ts +12 -1
  157. package/src/resource/types/scene.ts +1 -0
  158. package/src/resource/utils/data-uri.ts +20 -11
  159. package/src/resource/utils/parser.ts +103 -2
  160. package/src/resource/utils/ref.ts +2 -2
  161. package/src/runtime/Infographic.tsx +103 -22
  162. package/src/runtime/utils.ts +38 -16
  163. package/src/syntax/index.ts +124 -0
  164. package/src/syntax/mapper.ts +496 -0
  165. package/src/syntax/parser.ts +171 -0
  166. package/src/syntax/schema.ts +112 -0
  167. package/src/syntax/types.ts +100 -0
  168. package/src/templates/built-in.ts +4 -0
  169. package/src/templates/hierarchy-tree.ts +34 -11
  170. package/src/templates/sequence-stairs.ts +44 -0
  171. package/src/templates/word-cloud.ts +21 -0
  172. package/src/themes/types.ts +1 -1
  173. package/src/utils/design.ts +14 -0
  174. package/src/utils/fetch.ts +90 -0
  175. package/src/utils/font.ts +11 -1
  176. package/src/utils/index.ts +2 -0
  177. package/esm/resource/types/font.d.ts +0 -12
  178. package/lib/resource/types/font.d.ts +0 -12
  179. package/src/resource/types/font.ts +0 -23
  180. /package/esm/resource/types/{font.js → scene.js} +0 -0
  181. /package/lib/resource/types/{font.js → scene.js} +0 -0
@@ -12,19 +12,37 @@ function parseOptions(options) {
12
12
  ? document.querySelector(container) || document.createElement('div')
13
13
  : container;
14
14
  const templateOptions = template
15
- ? (0, designs_1.getTemplate)(template) || {}
16
- : {};
17
- const { design: templateDesign, ...restTemplateOptions } = templateOptions;
18
- return {
19
- ...restTemplateOptions,
20
- ...restOptions,
15
+ ? (0, designs_1.getTemplate)(template)
16
+ : undefined;
17
+ const mergedThemeConfig = (0, lodash_es_1.merge)({}, templateOptions?.themeConfig, themeConfig);
18
+ const resolvedThemeConfig = theme || themeConfig || templateOptions?.themeConfig
19
+ ? parseTheme(theme, mergedThemeConfig)
20
+ : undefined;
21
+ const parsed = {
21
22
  container: parsedContainer,
22
23
  padding: (0, utils_1.parsePadding)(padding),
23
- template,
24
- design: parseDesign({ ...templateDesign, ...design }, options),
25
- theme,
26
- themeConfig: parseTheme(theme, (0, lodash_es_1.merge)({ ...restTemplateOptions?.themeConfig }, themeConfig)),
27
24
  };
25
+ if (templateOptions) {
26
+ const { design: templateDesign, ...restTemplateOptions } = templateOptions;
27
+ Object.assign(parsed, restTemplateOptions);
28
+ }
29
+ Object.assign(parsed, restOptions);
30
+ if (template)
31
+ parsed.template = template;
32
+ if (templateOptions?.design || design) {
33
+ const parsedDesign = parseDesign({ ...templateOptions?.design, ...design }, resolvedThemeConfig
34
+ ? { ...options, themeConfig: resolvedThemeConfig }
35
+ : options);
36
+ if ((0, utils_1.isNonNullableParsedDesignsOptions)(parsedDesign)) {
37
+ parsed.design = parsedDesign;
38
+ }
39
+ }
40
+ if (theme)
41
+ parsed.theme = theme;
42
+ if (resolvedThemeConfig) {
43
+ parsed.themeConfig = resolvedThemeConfig;
44
+ }
45
+ return parsed;
28
46
  }
29
47
  function normalizeWithType(obj) {
30
48
  if (typeof obj === 'string')
@@ -47,11 +65,11 @@ function parseDesign(config, options) {
47
65
  }
48
66
  function parseDesignStructure(config) {
49
67
  if (!config)
50
- throw new Error('Structure is required in design or template');
68
+ return null;
51
69
  const { type, ...userProps } = normalizeWithType(config);
52
70
  const structure = (0, designs_1.getStructure)(type);
53
71
  if (!structure)
54
- throw new Error(`Structure ${type} not found`);
72
+ return null;
55
73
  const { component } = structure;
56
74
  return {
57
75
  ...structure,
@@ -72,11 +90,11 @@ function parseDesignTitle(config, options) {
72
90
  }
73
91
  function parseDesignItem(config, options) {
74
92
  if (!config)
75
- throw new Error('Item is required in design or template');
93
+ return null;
76
94
  const { type, ...userProps } = normalizeWithType(config);
77
95
  const item = (0, designs_1.getItem)(type);
78
96
  if (!item)
79
- throw new Error(`Item ${type} not found`);
97
+ return null;
80
98
  const { component, options: itemOptions } = item;
81
99
  return {
82
100
  ...item,
@@ -23,7 +23,7 @@ function renderItemIcon(svg, node, value, options) {
23
23
  }
24
24
  function createIcon(svg, node, value, attrs) {
25
25
  // load async
26
- (0, resource_1.loadResource)(svg, value);
26
+ (0, resource_1.loadResource)(svg, 'icon', value);
27
27
  return (0, utils_1.createIconElement)(value, {
28
28
  ...(0, utils_1.getAttributes)(node, [
29
29
  'id',
@@ -11,7 +11,7 @@ function renderIllus(svg, node, value) {
11
11
  return null;
12
12
  const id = (0, resource_1.getResourceId)(config);
13
13
  const clipPathId = createClipPath(svg, node, id);
14
- (0, resource_1.loadResource)(svg, config);
14
+ (0, resource_1.loadResource)(svg, 'illus', config);
15
15
  const { data, color } = config;
16
16
  return createIllusElement(id, {
17
17
  ...parseIllusBounds(node),
@@ -1,6 +1,6 @@
1
- import type { ResourceConfig } from './types';
1
+ import type { ResourceConfig, ResourceScene } from './types';
2
2
  /**
3
3
  * load resource into svg defs
4
4
  * @returns resource ref id
5
5
  */
6
- export declare function loadResource(svg: SVGSVGElement | null, config: string | ResourceConfig): Promise<string | null>;
6
+ export declare function loadResource(svg: SVGSVGElement | null, scene: ResourceScene, config: string | ResourceConfig): Promise<string | null>;
@@ -5,19 +5,30 @@ const utils_1 = require("../utils");
5
5
  const loaders_1 = require("./loaders");
6
6
  const registry_1 = require("./registry");
7
7
  const utils_2 = require("./utils");
8
- async function getResource(config) {
8
+ async function getResource(scene, config) {
9
9
  const cfg = (0, utils_2.parseResourceConfig)(config);
10
10
  if (!cfg)
11
11
  return null;
12
- const { type, data } = cfg;
13
- if (type === 'image') {
14
- return await (0, loaders_1.loadImageBase64Resource)(data);
15
- }
16
- else if (type === 'svg') {
12
+ cfg.scene || (cfg.scene = scene);
13
+ const { source, data, format, encoding } = cfg;
14
+ if (source === 'inline') {
15
+ const isDataURI = data.startsWith('data:');
16
+ if (format === 'svg' && encoding === 'raw') {
17
+ return (0, loaders_1.loadSVGResource)(data);
18
+ }
19
+ if (format === 'svg' && isDataURI) {
20
+ return await (0, loaders_1.loadImageBase64Resource)(data);
21
+ }
22
+ if (isDataURI || format === 'image') {
23
+ return await (0, loaders_1.loadImageBase64Resource)(data);
24
+ }
17
25
  return (0, loaders_1.loadSVGResource)(data);
18
26
  }
19
- else if (type === 'remote') {
20
- return await (0, loaders_1.loadRemoteResource)(data);
27
+ else if (source === 'remote') {
28
+ return await (0, loaders_1.loadRemoteResource)(data, format);
29
+ }
30
+ else if (source === 'search') {
31
+ return await (0, loaders_1.loadSearchResource)(data, format);
21
32
  }
22
33
  else {
23
34
  const customLoader = (0, registry_1.getCustomResourceLoader)();
@@ -32,7 +43,7 @@ const RESOURCE_LOAD_MAP = new WeakMap();
32
43
  * load resource into svg defs
33
44
  * @returns resource ref id
34
45
  */
35
- async function loadResource(svg, config) {
46
+ async function loadResource(svg, scene, config) {
36
47
  if (!svg)
37
48
  return null;
38
49
  const cfg = (0, utils_2.parseResourceConfig)(config);
@@ -41,7 +52,7 @@ async function loadResource(svg, config) {
41
52
  const id = (0, utils_2.getResourceId)(cfg);
42
53
  const resource = RESOURCE_MAP.has(id)
43
54
  ? RESOURCE_MAP.get(id) || null
44
- : await getResource(cfg);
55
+ : await getResource(scene, cfg);
45
56
  if (!resource)
46
57
  return null;
47
58
  if (!RESOURCE_LOAD_MAP.has(svg))
@@ -1,3 +1,4 @@
1
1
  export * from './image';
2
2
  export * from './remote';
3
+ export * from './search';
3
4
  export * from './svg';
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./image"), exports);
18
18
  __exportStar(require("./remote"), exports);
19
+ __exportStar(require("./search"), exports);
19
20
  __exportStar(require("./svg"), exports);
@@ -1 +1 @@
1
- export declare function loadRemoteResource(resource: string): Promise<SVGSymbolElement | null>;
1
+ export declare function loadRemoteResource(resource: string, format?: string): Promise<SVGSymbolElement | null>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.loadRemoteResource = loadRemoteResource;
4
+ const utils_1 = require("../../utils");
4
5
  const image_1 = require("./image");
5
6
  const svg_1 = require("./svg");
6
7
  function isRemoteResource(resource) {
@@ -11,14 +12,22 @@ function isRemoteResource(resource) {
11
12
  return false;
12
13
  }
13
14
  }
14
- async function loadRemoteResource(resource) {
15
+ function shouldParseAsSVG(contentType, format) {
16
+ const normalized = contentType.toLowerCase();
17
+ if (normalized.includes('image/svg'))
18
+ return true;
19
+ if (!contentType && format === 'svg')
20
+ return true;
21
+ return false;
22
+ }
23
+ async function loadRemoteResource(resource, format) {
15
24
  if (!resource || !isRemoteResource(resource))
16
25
  return null;
17
- const response = await fetch(resource);
26
+ const response = await (0, utils_1.fetchWithCache)(resource);
18
27
  if (!response.ok)
19
28
  throw new Error('Failed to load resource');
20
29
  const contentType = response.headers.get('Content-Type') || '';
21
- if (contentType.includes('image/svg+xml')) {
30
+ if (shouldParseAsSVG(contentType, format)) {
22
31
  const svgText = await response.text();
23
32
  return (0, svg_1.loadSVGResource)(svgText);
24
33
  }
@@ -0,0 +1 @@
1
+ export declare function loadSearchResource(query: string, format?: string): Promise<SVGSymbolElement | null>;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadSearchResource = loadSearchResource;
4
+ const constants_1 = require("../../constants");
5
+ const utils_1 = require("../../utils");
6
+ const image_1 = require("./image");
7
+ const remote_1 = require("./remote");
8
+ const svg_1 = require("./svg");
9
+ const queryIcon = async (query) => {
10
+ try {
11
+ const params = new URLSearchParams({ text: query, topK: '1' });
12
+ const url = `${constants_1.ICON_SERVICE_URL}?${params.toString()}`;
13
+ const response = await (0, utils_1.fetchWithCache)(url);
14
+ if (!response.ok)
15
+ return null;
16
+ const result = await response.json();
17
+ if (!result?.status || !Array.isArray(result.data?.data))
18
+ return null;
19
+ return result.data.data[0] || null;
20
+ }
21
+ catch (error) {
22
+ console.error(`Failed to query icon for "${query}":`, error);
23
+ return null;
24
+ }
25
+ };
26
+ function isDataURI(resource) {
27
+ return resource.startsWith('data:');
28
+ }
29
+ function looksLikeSVG(resource) {
30
+ const str = resource.trim();
31
+ return str.startsWith('<svg') || str.startsWith('<symbol');
32
+ }
33
+ async function loadSearchResource(query, format) {
34
+ if (!query)
35
+ return null;
36
+ const result = await queryIcon(query);
37
+ if (!result)
38
+ return null;
39
+ if (looksLikeSVG(result))
40
+ return (0, svg_1.loadSVGResource)(result);
41
+ if (isDataURI(result)) {
42
+ const mimeType = result.match(/^data:([^;]+)/)?.[1] || '';
43
+ const isBase64 = result.includes(';base64,');
44
+ if (mimeType === 'image/svg+xml' && !isBase64) {
45
+ const commaIndex = result.indexOf(',');
46
+ const svgText = commaIndex >= 0 ? result.slice(commaIndex + 1) : result;
47
+ return (0, svg_1.loadSVGResource)(svgText);
48
+ }
49
+ if (mimeType === 'image/svg+xml' && format === 'svg' && isBase64) {
50
+ return (0, image_1.loadImageBase64Resource)(result);
51
+ }
52
+ return (0, image_1.loadImageBase64Resource)(result);
53
+ }
54
+ return (0, remote_1.loadRemoteResource)(result, format);
55
+ }
@@ -1 +1,2 @@
1
1
  export type * from './resource';
2
+ export type * from './scene';
@@ -1,6 +1,13 @@
1
+ import { ResourceScene } from './scene';
2
+ export type ResourceSource = 'inline' | 'remote' | 'search' | 'custom';
3
+ export type ResourceFormat = 'svg' | 'image' | 'json' | 'binary' | string;
4
+ export type ResourceEncoding = 'raw' | 'data-uri' | 'base64' | string;
1
5
  export interface ResourceConfig {
2
- type: 'image' | 'svg' | 'remote' | 'custom';
6
+ source: ResourceSource;
7
+ format?: ResourceFormat;
8
+ encoding?: ResourceEncoding;
3
9
  data: string;
10
+ scene?: ResourceScene;
4
11
  [key: string]: any;
5
12
  }
6
13
  export type Resource = SVGSymbolElement;
@@ -0,0 +1 @@
1
+ export type ResourceScene = 'icon' | 'illus';
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseDataURI = parseDataURI;
4
4
  function parseDataURI(resource) {
5
5
  if (!resource.startsWith('data:'))
6
- return { type: 'custom', data: resource };
6
+ return null;
7
7
  const commaIndex = resource.indexOf(',');
8
8
  if (commaIndex === -1)
9
9
  return null;
@@ -11,15 +11,24 @@ function parseDataURI(resource) {
11
11
  const data = resource.slice(commaIndex + 1);
12
12
  const parts = header.split(';');
13
13
  const mimeType = parts[0];
14
- if (parts.includes('base64')) {
15
- return { type: "image" /* DataURITypeEnum.Image */, data: resource };
14
+ const isBase64 = parts.includes('base64');
15
+ if (mimeType === 'image/svg+xml' && !isBase64) {
16
+ const decoded = data.startsWith('%3C') ? decodeURIComponent(data) : data;
17
+ return {
18
+ source: 'inline',
19
+ format: 'svg',
20
+ encoding: 'raw',
21
+ data: decoded,
22
+ };
23
+ }
24
+ if (mimeType.startsWith('image/')) {
25
+ const format = mimeType === 'image/svg+xml' ? 'svg' : 'image';
26
+ return {
27
+ source: 'inline',
28
+ format,
29
+ encoding: isBase64 ? 'base64' : 'data-uri',
30
+ data: resource,
31
+ };
16
32
  }
17
- const typeMap = {
18
- 'text/url': "remote" /* DataURITypeEnum.Remote */,
19
- 'image/svg+xml': "svg" /* DataURITypeEnum.SVG */,
20
- };
21
- const type = typeMap[mimeType];
22
- if (type)
23
- return { type, data };
24
- return { type: 'custom', data: resource };
33
+ return null;
25
34
  }
@@ -2,8 +2,99 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseResourceConfig = parseResourceConfig;
4
4
  const data_uri_1 = require("./data-uri");
5
+ const KNOWN_FORMATS = new Set(['svg', 'png', 'jpg', 'jpeg', 'webp', 'gif']);
6
+ function looksLikeSVG(resource) {
7
+ const str = resource.trim();
8
+ return str.startsWith('<svg') || str.startsWith('<symbol');
9
+ }
10
+ function inferFormatFromUrl(url) {
11
+ const lower = url.toLowerCase();
12
+ if (lower.endsWith('.svg') || lower.includes('.svg?'))
13
+ return 'svg';
14
+ if (lower.endsWith('.png') ||
15
+ lower.endsWith('.jpg') ||
16
+ lower.endsWith('.jpeg') ||
17
+ lower.endsWith('.webp') ||
18
+ lower.endsWith('.gif')) {
19
+ return 'image';
20
+ }
21
+ return undefined;
22
+ }
23
+ function parseRefResource(resource) {
24
+ if (!resource.startsWith('ref:'))
25
+ return null;
26
+ const rest = resource.slice(4);
27
+ const [source, ...restParts] = rest.split(':');
28
+ if (!source || restParts.length === 0)
29
+ return null;
30
+ let format;
31
+ if (restParts.length > 1 && KNOWN_FORMATS.has(restParts[0].toLowerCase())) {
32
+ format = restParts.shift()?.toLowerCase();
33
+ }
34
+ const payload = restParts.join(':');
35
+ if (!payload)
36
+ return null;
37
+ const normalizedSource = source === 'url' ? 'remote' : source;
38
+ if (normalizedSource === 'remote') {
39
+ return {
40
+ source: 'remote',
41
+ format: format || inferFormatFromUrl(payload) || undefined,
42
+ data: payload,
43
+ };
44
+ }
45
+ if (normalizedSource === 'search') {
46
+ return {
47
+ source: 'search',
48
+ format: format || 'svg',
49
+ data: payload,
50
+ };
51
+ }
52
+ if (normalizedSource === 'svg') {
53
+ return { source: 'inline', format: 'svg', data: payload, encoding: 'raw' };
54
+ }
55
+ return { source: 'custom', data: resource, format };
56
+ }
5
57
  function parseResourceConfig(config) {
6
58
  if (!config)
7
59
  return null;
8
- return typeof config === 'string' ? (0, data_uri_1.parseDataURI)(config) : config;
60
+ if (typeof config !== 'string') {
61
+ if (config.source)
62
+ return config;
63
+ const legacy = config;
64
+ if (legacy.type === 'image') {
65
+ return { source: 'inline', format: 'image', data: legacy.data };
66
+ }
67
+ if (legacy.type === 'svg') {
68
+ return {
69
+ source: 'inline',
70
+ format: 'svg',
71
+ encoding: 'raw',
72
+ data: legacy.data,
73
+ };
74
+ }
75
+ if (legacy.type === 'remote') {
76
+ return { source: 'remote', format: legacy.format, data: legacy.data };
77
+ }
78
+ if (legacy.type === 'search') {
79
+ return {
80
+ source: 'search',
81
+ format: legacy.format || 'svg',
82
+ data: legacy.data,
83
+ };
84
+ }
85
+ if (legacy.type === 'custom') {
86
+ return { source: 'custom', data: legacy.data };
87
+ }
88
+ return null;
89
+ }
90
+ const dataURIConfig = (0, data_uri_1.parseDataURI)(config);
91
+ if (dataURIConfig)
92
+ return dataURIConfig;
93
+ const refConfig = parseRefResource(config);
94
+ if (refConfig)
95
+ return refConfig;
96
+ if (looksLikeSVG(config)) {
97
+ return { source: 'inline', format: 'svg', encoding: 'raw', data: config };
98
+ }
99
+ return { source: 'custom', data: config };
9
100
  }
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getResourceId = getResourceId;
4
4
  exports.getResourceHref = getResourceHref;
5
5
  const utils_1 = require("../../utils");
6
- const data_uri_1 = require("./data-uri");
6
+ const parser_1 = require("./parser");
7
7
  function getResourceId(config) {
8
- const cfg = typeof config === 'string' ? (0, data_uri_1.parseDataURI)(config) : config;
8
+ const cfg = typeof config === 'string' ? (0, parser_1.parseResourceConfig)(config) : config;
9
9
  if (!cfg)
10
10
  return null;
11
11
  return 'rsc-' + (0, utils_1.getSimpleHash)(JSON.stringify(cfg));
@@ -1,23 +1,27 @@
1
1
  import { type ExportOptions } from '../exporter';
2
- import { InfographicOptions } from '../options';
2
+ import { InfographicOptions, ParsedInfographicOptions } from '../options';
3
3
  export declare class Infographic {
4
4
  rendered: boolean;
5
5
  private emitter;
6
6
  private node;
7
7
  private editor?;
8
+ private initialOptions;
8
9
  private options;
9
10
  private parsedOptions;
10
- constructor(options: InfographicOptions);
11
- getOptions(): InfographicOptions;
11
+ constructor(options: string | Partial<InfographicOptions>);
12
+ getOptions(): Partial<InfographicOptions>;
13
+ private setOptions;
12
14
  /**
13
15
  * Render the infographic into the container
14
16
  */
15
- render(): void;
17
+ render(options?: string | Partial<InfographicOptions>): void;
18
+ update(options: string | Partial<InfographicOptions>): void;
19
+ private performRender;
16
20
  /**
17
21
  * Compose the SVG template
18
22
  */
19
- compose(): SVGSVGElement;
20
- getTypes(): string;
23
+ compose(parsedOptions: ParsedInfographicOptions): SVGSVGElement;
24
+ getTypes(): string | undefined;
21
25
  /**
22
26
  * Export the infographic to data URL
23
27
  * @param options Export option
@@ -6,12 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Infographic = void 0;
7
7
  const jsx_runtime_1 = require("@antv/infographic/jsx-runtime");
8
8
  const eventemitter3_1 = __importDefault(require("eventemitter3"));
9
- const lodash_es_1 = require("lodash-es");
10
9
  const editor_1 = require("../editor");
11
10
  const exporter_1 = require("../exporter");
12
11
  const jsx_1 = require("../jsx");
13
12
  const options_1 = require("../options");
14
13
  const renderer_1 = require("../renderer");
14
+ const syntax_1 = require("../syntax");
15
15
  const utils_1 = require("../utils");
16
16
  const options_2 = require("./options");
17
17
  const utils_2 = require("./utils");
@@ -20,27 +20,60 @@ class Infographic {
20
20
  this.rendered = false;
21
21
  this.emitter = new eventemitter3_1.default();
22
22
  this.node = null;
23
- this.options = {
24
- ...options,
25
- data: (0, lodash_es_1.cloneDeep)(options.data),
26
- elements: (0, lodash_es_1.cloneDeep)(options.elements || []),
27
- };
28
- this.parsedOptions = (0, options_1.parseOptions)((0, utils_2.mergeOptions)(options_2.DEFAULT_OPTIONS, this.options));
23
+ this.initialOptions = {};
24
+ this.setOptions(options, 'replace', true);
29
25
  }
30
26
  getOptions() {
31
27
  return this.options;
32
28
  }
29
+ setOptions(options, mode = 'replace', isInitial = false) {
30
+ const { options: parsedOptions, errors, warnings, } = parseSyntaxOptions(options);
31
+ if (isInitial) {
32
+ this.initialOptions = (0, utils_2.cloneOptions)(parsedOptions);
33
+ }
34
+ const base = mode === 'replace'
35
+ ? (0, utils_2.mergeOptions)((0, utils_2.cloneOptions)(this.initialOptions || {}), parsedOptions)
36
+ : (0, utils_2.mergeOptions)(this.options || (0, utils_2.cloneOptions)(this.initialOptions || {}), parsedOptions);
37
+ this.options = base;
38
+ this.parsedOptions = (0, options_1.parseOptions)((0, utils_2.mergeOptions)(options_2.DEFAULT_OPTIONS, this.options));
39
+ if (warnings.length) {
40
+ this.emitter.emit('warning', warnings);
41
+ }
42
+ if (errors.length) {
43
+ this.emitter.emit('error', errors);
44
+ }
45
+ }
33
46
  /**
34
47
  * Render the infographic into the container
35
48
  */
36
- render() {
49
+ render(options) {
50
+ if (options) {
51
+ this.setOptions(options, 'replace');
52
+ }
53
+ else if (!this.options && this.initialOptions) {
54
+ this.setOptions(this.initialOptions, 'replace');
55
+ }
56
+ this.performRender();
57
+ }
58
+ update(options) {
59
+ this.setOptions(options, 'merge');
60
+ this.performRender();
61
+ }
62
+ performRender() {
63
+ const parsedOptions = this.parsedOptions;
64
+ if (!(0, utils_2.isCompleteParsedInfographicOptions)(parsedOptions)) {
65
+ this.emitter.emit('error', new Error('Incomplete options'));
66
+ return;
67
+ }
37
68
  const { container } = this.parsedOptions;
38
- const template = this.compose();
39
- const renderer = new renderer_1.Renderer(this.parsedOptions, template);
69
+ const template = this.compose(parsedOptions);
70
+ const renderer = new renderer_1.Renderer(parsedOptions, template);
40
71
  this.node = renderer.render();
41
- container.replaceChildren(this.node);
72
+ container?.replaceChildren(this.node);
73
+ this.editor?.destroy();
74
+ this.editor = undefined;
42
75
  if (this.options.editable) {
43
- this.editor = new editor_1.Editor(this.emitter, this.node, this.parsedOptions);
76
+ this.editor = new editor_1.Editor(this.emitter, this.node, parsedOptions);
44
77
  }
45
78
  this.rendered = true;
46
79
  this.emitter.emit('rendered', { node: this.node, options: this.options });
@@ -48,14 +81,14 @@ class Infographic {
48
81
  /**
49
82
  * Compose the SVG template
50
83
  */
51
- compose() {
52
- const { design, data } = this.parsedOptions;
84
+ compose(parsedOptions) {
85
+ const { design, data } = parsedOptions;
53
86
  const { title, item, items, structure } = design;
54
87
  const { component: Structure, props: structureProps } = structure;
55
88
  const Title = title.component;
56
89
  const Item = item.component;
57
90
  const Items = items.map((it) => it.component);
58
- const svg = (0, jsx_1.renderSVG)((0, jsx_runtime_1.jsx)(Structure, { data: data, Title: Title, Item: Item, Items: Items, options: this.parsedOptions, ...structureProps }));
91
+ const svg = (0, jsx_1.renderSVG)((0, jsx_runtime_1.jsx)(Structure, { data: data, Title: Title, Item: Item, Items: Items, options: parsedOptions, ...structureProps }));
59
92
  const template = (0, utils_1.parseSVG)(svg);
60
93
  if (!template) {
61
94
  throw new Error('Failed to parse SVG template');
@@ -63,7 +96,12 @@ class Infographic {
63
96
  return template;
64
97
  }
65
98
  getTypes() {
66
- const design = this.parsedOptions.design;
99
+ const parsedOptions = this.parsedOptions;
100
+ if (!(0, utils_2.isCompleteParsedInfographicOptions)(parsedOptions)) {
101
+ this.emitter.emit('error', new Error('Incomplete options'));
102
+ return;
103
+ }
104
+ const design = parsedOptions.design;
67
105
  const structure = design.structure.composites || [];
68
106
  const items = design.items.map((it) => it.composites || []);
69
107
  return (0, utils_1.getTypes)({ structure, items });
@@ -99,3 +137,14 @@ class Infographic {
99
137
  }
100
138
  }
101
139
  exports.Infographic = Infographic;
140
+ function parseSyntaxOptions(input) {
141
+ if (typeof input === 'string') {
142
+ const { options, errors, warnings } = (0, syntax_1.parseSyntax)(input);
143
+ return { options, errors, warnings };
144
+ }
145
+ return {
146
+ options: (0, utils_2.cloneOptions)(input),
147
+ errors: [],
148
+ warnings: [],
149
+ };
150
+ }
@@ -1,2 +1,4 @@
1
- import { InfographicOptions } from '../options/types';
2
- export declare function mergeOptions(object: Partial<InfographicOptions>, source: Partial<InfographicOptions>): InfographicOptions;
1
+ import type { InfographicOptions, ParsedInfographicOptions } from '../options';
2
+ export declare function mergeOptions(object: Partial<InfographicOptions>, source: Partial<InfographicOptions>): Partial<InfographicOptions>;
3
+ export declare function cloneOptions<T extends Partial<InfographicOptions>>(options: T): T;
4
+ export declare function isCompleteParsedInfographicOptions(options: Partial<ParsedInfographicOptions>): options is ParsedInfographicOptions;