diff --git a/.eslintrc.json b/.eslintrc.json index 7f37e95..b1b49a0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -23,6 +23,7 @@ "@typescript-eslint/no-unused-vars": "warn", "@typescript-eslint/no-explicit-any": "warn", "@typescript-eslint/no-unsafe-declaration-merging": "warn", + "@typescript-eslint/no-namespace": "warn", "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/ban-ts-comment": "warn" } diff --git a/package.json b/package.json index 998f385..18268c8 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "github-web-widget": "^4.0.0-rc.2", "js-base64": "^3.7.6", "koajax": "^0.9.6", + "lodash.memoize": "^4.1.2", "marked": "^12.0.0", "mobx": "^6.12.0", "web-cell": "^3.0.0-rc.15", @@ -35,6 +36,7 @@ "@parcel/transformer-less": "~2.11.0", "@parcel/transformer-typescript-tsc": "~2.11.0", "@parcel/transformer-webmanifest": "~2.11.0", + "@types/lodash.memoize": "^4.1.9", "@types/node": "^18.19.15", "@typescript-eslint/eslint-plugin": "^7.0.1", "@typescript-eslint/parser": "^7.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c6142a..7905cf9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ dependencies: koajax: specifier: ^0.9.6 version: 0.9.6(typescript@5.3.3) + lodash.memoize: + specifier: ^4.1.2 + version: 4.1.2 marked: specifier: ^12.0.0 version: 12.0.0 @@ -67,6 +70,9 @@ devDependencies: '@parcel/transformer-webmanifest': specifier: ~2.11.0 version: 2.11.0 + '@types/lodash.memoize': + specifier: ^4.1.9 + version: 4.1.9 '@types/node': specifier: ^18.19.15 version: 18.19.15 @@ -2841,6 +2847,16 @@ packages: '@types/node': 18.19.15 dev: true + /@types/lodash.memoize@4.1.9: + resolution: {integrity: sha512-glY1nQuoqX4Ft8Uk+KfJudOD7DQbbEDF6k9XpGncaohW3RW4eSWBlx6AA0fZCrh40tZcQNH4jS/Oc59J6Eq+aw==} + dependencies: + '@types/lodash': 4.14.202 + dev: true + + /@types/lodash@4.14.202: + resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} + dev: true + /@types/marked@5.0.2: resolution: {integrity: sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg==} dev: true @@ -5242,6 +5258,10 @@ packages: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} dev: true + /lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: false + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true diff --git a/source/component/ECharts/Chart.tsx b/source/component/ECharts/Chart.tsx index decec34..ba82c08 100644 --- a/source/component/ECharts/Chart.tsx +++ b/source/component/ECharts/Chart.tsx @@ -1,13 +1,30 @@ +import { JsxProps } from 'dom-renderer'; +import { EChartsOption } from 'echarts'; import { ECharts, init } from 'echarts/core'; +import { ECBasicOption } from 'echarts/types/dist/shared'; import { CustomElement, parseDOM } from 'web-utility'; - -import { ChartType, loadRenderer } from './utility'; +import { + BUILTIN_CHARTS_MAP, + BUITIN_COMPONENTS_MAP, + ChartType, + ECChartOptionName, + ECComponentOptionName, + loadChart, + loadComponent, + loadRenderer, + proxyPrototype +} from './utility'; export class EChartsElement extends HTMLElement implements CustomElement { + #data: EChartsOption = {}; #type: ChartType; #core?: ECharts; #buffer = []; + toJSON() { + return this.#core?.getOption(); + } + set type(value: ChartType) { this.#type = value; this.setAttribute('type', value); @@ -21,13 +38,15 @@ export class EChartsElement extends HTMLElement implements CustomElement { constructor() { super(); + proxyPrototype(this, this.#data, (key, value) => + this.setProperty(key.toString(), value) + ); this.attachShadow({ mode: 'open' }).append( parseDOM('
')[0] ); - this.addEventListener('optionchange', ({ detail }: CustomEvent) => { - if (this.#core) this.#core.setOption(detail); - else this.#buffer.push(detail); - }); + this.addEventListener('optionchange', ({ detail }: CustomEvent) => + this.setOption(detail) + ); } connectedCallback() { @@ -39,16 +58,54 @@ export class EChartsElement extends HTMLElement implements CustomElement { this.#core = init(this.shadowRoot.firstElementChild as HTMLDivElement); - for (const option of this.#buffer) this.#core.setOption(option); + this.setOption(this.#data); + + for (const option of this.#buffer) this.setOption(option); this.#buffer.length = 0; } + + async setOption(data: EChartsOption) { + if (!this.#core) { + this.#buffer.push(data); + return; + } + + for (const key of Object.keys(data)) + if (key in BUITIN_COMPONENTS_MAP) + await loadComponent(key as ECComponentOptionName); + else if (key in BUILTIN_CHARTS_MAP) + await loadChart(key as ECChartOptionName); + + this.#core.setOption(data, false, true); + } + + setProperty(key: string, value: any) { + this.#data[key] = value; + + if (value != null) + switch (typeof value) { + case 'object': + break; + case 'boolean': + if (value) super.setAttribute(key, key + ''); + else super.removeAttribute(key); + break; + default: + super.setAttribute(key, value + ''); + } + else super.removeAttribute(key); + + this.setOption(this.#data); + } } customElements.define('ec-chart', EChartsElement); declare global { - interface HTMLElementTagNameMap { - 'ec-chart': EChartsElement; + namespace JSX { + interface IntrinsicElements { + 'ec-chart': JsxProps