diff --git a/docs/assets/api/en/API/vchart.md b/docs/assets/api/en/API/vchart.md index 0272daca5a..b7a8f6d18e 100644 --- a/docs/assets/api/en/API/vchart.md +++ b/docs/assets/api/en/API/vchart.md @@ -763,7 +763,9 @@ getCurrentThemeName: () => string; ### setCurrentTheme -**asynchronous method**, set the current Theme. +**Asynchronous method**, set the current Theme. + +**Note: If the `theme` property is configured in the chart spec, the `spec.theme` has higher priority.** ```ts /** @@ -774,6 +776,66 @@ getCurrentThemeName: () => string; setCurrentTheme: (name: string) => Promise; ``` +Usage example: + +```javascript livedemo +// Define custom theme +const customTheme = { + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + bar: { + barMaxWidth: 20, + label: { + visible: true, + position: 'top' + } + } + } +}; + +// Register theme +VChart.ThemeManager.registerTheme('myCustomTheme', customTheme); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Set theme through instance method +vchart.setCurrentTheme('myCustomTheme'); +``` + +**Note**: +- Before using the `setCurrentTheme` method, you need to register the theme first through `VChart.ThemeManager.registerTheme()` +- This method is asynchronous and returns a Promise, you can use `await` or `.then()` to handle it +- If the `theme` property is configured in the chart spec, the theme in the spec has higher priority + ### setTooltipHandler When the configuration item cannot meet the display needs of the tooltip, we also provide the ability to customize the tooltip. You can configure `TooltipHandler` To override the default tooltip presentation logic. diff --git a/docs/assets/api/zh/API/vchart.md b/docs/assets/api/zh/API/vchart.md index 8b84b4de1d..92ca0d3ad4 100644 --- a/docs/assets/api/zh/API/vchart.md +++ b/docs/assets/api/zh/API/vchart.md @@ -787,6 +787,66 @@ getCurrentThemeName: () => string; setCurrentTheme: (name: string) => Promise; ``` +使用示例: + +```javascript livedemo +// 定义自定义主题 +const customTheme = { + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + bar: { + barMaxWidth: 20, + label: { + visible: true, + position: 'top' + } + } + } +}; + +// 注册主题 +VChart.ThemeManager.registerTheme('myCustomTheme', customTheme); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// 通过实例方法设置主题 +vchart.setCurrentTheme('myCustomTheme'); +``` + +**注意**: +- 使用 `setCurrentTheme` 方法前,需要先通过 `VChart.ThemeManager.registerTheme()` 注册主题 +- 该方法为异步方法,返回 Promise,可以使用 `await` 或 `.then()` 处理 +- 如果图表 spec 中配置了 `theme` 属性,则 spec 中的主题优先级更高 + ### setTooltipHandler 当配置项无法满足 tooltip 的展示需求时,我们还提供了自定义 tooltip 的能力。可以通过配置 `TooltipHandler` 来覆盖默认 tooltip 展示逻辑。 diff --git a/docs/assets/guide/en/tutorial_docs/Theme/Apply_Theme.md b/docs/assets/guide/en/tutorial_docs/Theme/Apply_Theme.md new file mode 100644 index 0000000000..a4cd23b871 --- /dev/null +++ b/docs/assets/guide/en/tutorial_docs/Theme/Apply_Theme.md @@ -0,0 +1,595 @@ +# Theme Application Guide + +VChart provides a flexible theme application mechanism that supports applying themes at both global and chart instance levels. This article will detail how to apply different types of themes, including default themes, custom themes, extension package themes, and how to extend installed themes. + +## Theme Application Scope + +VChart supports two levels of theme application: + +### 1. Global Application + +The `ThemeManager.setCurrentTheme()` method () can be used to set a global theme, which will affect all existing chart instances on the page as well as subsequently created chart instances. + +### 2. Chart Instance Application + +Through the `theme` configuration item in the chart spec or through the constructor (), you can apply a specific theme to a single chart instance without affecting other charts. + +You can also use the `setCurrentTheme` instance method to dynamically update the current chart, provided that the theme has been registered through `VChart.ThemeManager.registerTheme`. + +```js +vchart.setCurrentTheme('userTheme'); +``` + +## Theme Types + +### 1. Default Themes + +VChart has built-in `light` and `dark` default themes that can be used directly without registration. + +#### Global Application of Default Theme + +```javascript livedemo +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +// Apply default theme globally +VChart.ThemeManager.setCurrentTheme('dark'); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### Chart Instance Application of Default Theme + +```javascript livedemo +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value', + // Specify theme name in spec + theme: 'dark' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +### 2. Custom Themes + +Custom themes are theme configuration objects defined by users. For custom content, refer to: + + + +#### Global Application of Custom Theme + +```javascript livedemo +// Define custom theme +const customTheme = { + name: 'myCustomTheme', + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + bar: { + barMaxWidth: 20, + label: { + visible: true, + position: 'top' + } + } + }, + component: { + axis: { + label: { + style: { + fill: '#666', + fontSize: 12 + } + } + } + } +}; + +// Register custom theme +VChart.ThemeManager.registerTheme('myCustomTheme', customTheme); + +// Apply custom theme globally +VChart.ThemeManager.setCurrentTheme('myCustomTheme'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### Chart Instance Application of Custom Theme + +There are two ways: + +**Method 1: Through the theme configuration item in spec** + +```javascript livedemo +// Define custom theme object +const customTheme = { + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + bar: { + barMaxWidth: 20, + label: { + visible: true, + position: 'top' + } + } + } +}; + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value', + // Pass theme object directly in spec + theme: customTheme +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +**Method 2: Through instance method** + +```javascript livedemo +// Define and register custom theme +const customTheme = { + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + bar: { + barMaxWidth: 20, + label: { + visible: true, + position: 'top' + } + } + } +}; + +VChart.ThemeManager.registerTheme('myCustomTheme', customTheme); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// Apply theme through instance method +vchart.setCurrentTheme('myCustomTheme'); +``` + +### 3. Extension Package Themes + +VChart provides an extension theme package `@visactor/vchart-theme` that contains various ready-to-use themes. +Reference: + +#### Installing Extension Theme Package + +```bash +npm install @visactor/vchart-theme +# or +yarn add @visactor/vchart-theme +``` + +#### Global Application of Extension Package Theme + +```javascript livedemo +// Import extension theme package +import { allThemeMap } from '@visactor/vchart-theme'; +import VChart from '@visactor/vchart'; + +// Register all extension themes +allThemeMap.forEach((theme, name) => { + VChart.ThemeManager.registerTheme(name, theme); +}); + +// Apply extension theme globally +VChart.ThemeManager.setCurrentTheme('vScreenVolcanoBlue'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### Chart Instance Application of Extension Package Theme + +```javascript livedemo +// Import specific theme +import vScreenVolcanoBlue from '@visactor/vchart-theme/public/vScreenVolcanoBlue.json'; +import VChart from '@visactor/vchart'; + +// Register extension theme +VChart.ThemeManager.registerTheme('vScreenVolcanoBlue', vScreenVolcanoBlue); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value', + // Specify theme name in spec + theme: 'vScreenVolcanoBlue' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +### 4. Extending Installed Themes + +Sometimes we need to make some custom modifications to an existing theme rather than completely redefining it. You can get the installed theme and then extend it. + +#### Extending Default Theme + +```javascript livedemo +// Get default theme +const defaultTheme = VChart.ThemeManager.getDefaultTheme(); + +// Extend default theme, create new theme +const extendedTheme = { + ...defaultTheme, + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + ...defaultTheme.series, + bar: { + ...defaultTheme.series?.bar, + barMaxWidth: 30, + label: { + visible: true, + position: 'top', + style: { + fill: '#333', + fontSize: 14 + } + } + } + } +}; + +// Register extended theme +VChart.ThemeManager.registerTheme('extendedLight', extendedTheme); + +// Apply extended theme +VChart.ThemeManager.setCurrentTheme('extendedLight'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### Extending Extension Package Theme + +```javascript livedemo +// Import extension theme (the following two lines are needed in development environment, not needed in vchart playground) +//import vScreenVolcanoBlue from '@visactor/vchart-theme/public/vScreenVolcanoBlue.json'; +//import VChart from '@visactor/vchart'; + +// Register original theme +VChart.ThemeManager.registerTheme('vScreenVolcanoBlue', vScreenVolcanoBlue); + +// Get registered theme +const baseTheme = VChart.ThemeManager.getTheme('vScreenVolcanoBlue'); + +// Extend theme, add custom configuration +const extendedTheme = { + ...baseTheme, + series: { + ...baseTheme.series, + bar: { + ...baseTheme.series?.bar, + barMaxWidth: 40, + label: { + visible: true, + position: 'top', + style: { + fill: '#fff', + fontSize: 16, + fontWeight: 'bold' + } + } + } + }, + component: { + ...baseTheme.component, + axis: { + ...baseTheme.component?.axis, + label: { + ...baseTheme.component?.axis?.label, + style: { + ...baseTheme.component?.axis?.label?.style, + fontSize: 14, + fontWeight: 'bold' + } + } + } + } +}; + +// Register extended theme +VChart.ThemeManager.registerTheme('extendedVolcanoBlue', extendedTheme); + +// Apply extended theme +VChart.ThemeManager.setCurrentTheme('extendedVolcanoBlue'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### Using Deep Merge to Extend Theme + +For complex theme structures, you can use a deep merge utility to extend themes: + +```javascript livedemo +// Deep merge utility function +function deepMerge(target, source) { + const output = { ...target }; + if (isObject(target) && isObject(source)) { + Object.keys(source).forEach(key => { + if (isObject(source[key])) { + if (!(key in target)) { + Object.assign(output, { [key]: source[key] }); + } else { + output[key] = deepMerge(target[key], source[key]); + } + } else { + Object.assign(output, { [key]: source[key] }); + } + }); + } + return output; +} + +function isObject(item) { + return item && typeof item === 'object' && !Array.isArray(item); +} + +// Get default theme +const baseTheme = VChart.ThemeManager.getDefaultTheme(); + +// Define extension configuration +const extension = { + series: { + bar: { + barMaxWidth: 25, + label: { + visible: true, + position: 'top' + } + } + }, + component: { + axis: { + label: { + style: { + fontSize: 14 + } + } + } + } +}; + +// Deep merge +const mergedTheme = deepMerge(baseTheme, extension); + +// Register merged theme +VChart.ThemeManager.registerTheme('mergedTheme', mergedTheme); + +// Apply theme +VChart.ThemeManager.setCurrentTheme('mergedTheme'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + + + +## Summary + +This article introduced a complete guide to VChart theme application: + +1. **Theme Application Scope**: + - Global application: Affects all charts through `ThemeManager.setCurrentTheme()` + - Chart instance application: Through the `theme` configuration item in spec or the instance's `setCurrentTheme()` method + +2. **Theme Types**: + - **Default themes**: VChart's built-in `light` and `dark` themes that can be used without registration + - **Custom themes**: Theme configuration objects defined by users + - **Extension package themes**: Rich themes provided through the `@visactor/vchart-theme` package + - **Extending installed themes**: Customizing modifications based on existing themes + +3. **Best Practices**: + - Use global themes for multiple charts that need a unified style + - Use instance themes for individual charts that need special styling + - Use theme extension for scenarios that need fine-tuning based on existing themes + +By flexibly using these theme application methods, you can easily achieve personalized customization and unified management of charts. + + diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 88169cd389..1a0727f952 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -600,6 +600,13 @@ "en": "Theme" }, "children": [ + { + "path": "Apply_Theme", + "title": { + "zh": "主题应用指南", + "en": "Theme Application Guide" + } + }, { "path": "Theme_Concept_and_Design_Rules", "title": { @@ -953,4 +960,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/docs/assets/guide/zh/tutorial_docs/Theme/Apply_Theme.md b/docs/assets/guide/zh/tutorial_docs/Theme/Apply_Theme.md new file mode 100644 index 0000000000..e078533ff7 --- /dev/null +++ b/docs/assets/guide/zh/tutorial_docs/Theme/Apply_Theme.md @@ -0,0 +1,595 @@ +# 主题应用指南 + +VChart 提供了灵活的主题应用机制,支持在全局和图表实例两个层面应用主题。本文将详细介绍如何应用不同类型的主题,包括默认主题、自定义主题、扩展包主题以及如何扩展已安装的主题。 + +## 主题应用范围 + +VChart 支持两种主题应用范围: + +### 1. 全局应用 + +通过 `ThemeManager.setCurrentTheme()` ( ) 方法可以设置全局主题,该方法会影响页面上所有已创建的图表实例以及后续创建的图表实例。 + +### 2. 图表实例应用 + +通过图表 spec 的 `theme` 配置项或通过构造函数( ),可以为单个图表实例应用特定的主题,不会影响其他图表。 + +也可以通过 setCurrentTheme 实例方法,对当前图表进行动态更新,前提是该主题通过 VChart.ThemeManager.registerTheme 注册过。 + +```js +vchart.setCurrentTheme('userTheme'); +``` + +## 主题类型 + +### 1. 默认主题 + +VChart 内置了 `light` 和 `dark` 两个默认主题,无需注册即可直接使用。 + +#### 全局应用默认主题 + +```javascript livedemo +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +// 全局应用默认主题 +VChart.ThemeManager.setCurrentTheme('dark'); + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### 图表实例应用默认主题 + +```javascript livedemo +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value', + // 在 spec 中指定主题名称 + theme: 'dark' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +### 2. 自定义主题 + +自定义主题是指用户自己定义的主题配置对象。自定义内容参考: + + + + +#### 全局应用自定义主题 + +```javascript livedemo +// 定义自定义主题 +const customTheme = { + name: 'myCustomTheme', + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + bar: { + barMaxWidth: 20, + label: { + visible: true, + position: 'top' + } + } + }, + component: { + axis: { + label: { + style: { + fill: '#666', + fontSize: 12 + } + } + } + } +}; + +// 注册自定义主题 +VChart.ThemeManager.registerTheme('myCustomTheme', customTheme); + +// 全局应用自定义主题 +VChart.ThemeManager.setCurrentTheme('myCustomTheme'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### 图表实例应用自定义主题 + +有两种方式: + +**方式一:通过 spec 的 theme 配置项** + +```javascript livedemo +// 定义自定义主题对象 +const customTheme = { + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + bar: { + barMaxWidth: 20, + label: { + visible: true, + position: 'top' + } + } + } +}; + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value', + // 直接在 spec 中传入主题对象 + theme: customTheme +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +**方式二:通过实例方法** + +```javascript livedemo +// 定义并注册自定义主题 +const customTheme = { + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + bar: { + barMaxWidth: 20, + label: { + visible: true, + position: 'top' + } + } + } +}; + +VChart.ThemeManager.registerTheme('myCustomTheme', customTheme); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); + +// 通过实例方法应用主题 +vchart.setCurrentTheme('myCustomTheme'); +``` + +### 3. 扩展包主题 + +VChart 提供了扩展主题包 `@visactor/vchart-theme`,包含多种开箱即用的主题。 +参考: + +#### 安装扩展主题包 + +```bash +npm install @visactor/vchart-theme +# 或 +yarn add @visactor/vchart-theme +``` + +#### 全局应用扩展包主题 + +```javascript livedemo +// 导入扩展主题包 +import { allThemeMap } from '@visactor/vchart-theme'; +import VChart from '@visactor/vchart'; + +// 注册所有扩展主题 +allThemeMap.forEach((theme, name) => { + VChart.ThemeManager.registerTheme(name, theme); +}); + +// 全局应用扩展主题 +VChart.ThemeManager.setCurrentTheme('vScreenVolcanoBlue'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### 图表实例应用扩展包主题 + +```javascript livedemo +// 导入特定主题 +import vScreenVolcanoBlue from '@visactor/vchart-theme/public/vScreenVolcanoBlue.json'; +import VChart from '@visactor/vchart'; + +// 注册扩展主题 +VChart.ThemeManager.registerTheme('vScreenVolcanoBlue', vScreenVolcanoBlue); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value', + // 在 spec 中指定主题名称 + theme: 'vScreenVolcanoBlue' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +### 4. 扩展已安装的主题 + +有时候我们需要在已有主题的基础上进行一些定制化修改,而不是完全重新定义。可以通过获取已安装的主题,然后进行扩展。 + +#### 扩展默认主题 + +```javascript livedemo +// 获取默认主题 +const defaultTheme = VChart.ThemeManager.getDefaultTheme(); + +// 扩展默认主题,创建新主题 +const extendedTheme = { + ...defaultTheme, + colorScheme: { + default: [ + '#FF6B6B', + '#4ECDC4', + '#45B7D1', + '#FFA07A', + '#98D8C8', + '#F7DC6F', + '#BB8FCE', + '#85C1E2' + ] + }, + series: { + ...defaultTheme.series, + bar: { + ...defaultTheme.series?.bar, + barMaxWidth: 30, + label: { + visible: true, + position: 'top', + style: { + fill: '#333', + fontSize: 14 + } + } + } + } +}; + +// 注册扩展后的主题 +VChart.ThemeManager.registerTheme('extendedLight', extendedTheme); + +// 应用扩展主题 +VChart.ThemeManager.setCurrentTheme('extendedLight'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### 扩展扩展包主题 + +```javascript livedemo +// 导入扩展主题(以下两行代码在开发环境中需要使用,vchart playground 中不需要) +//import vScreenVolcanoBlue from '@visactor/vchart-theme/public/vScreenVolcanoBlue.json'; +//import VChart from '@visactor/vchart'; + +// 注册原始主题 +VChart.ThemeManager.registerTheme('vScreenVolcanoBlue', vScreenVolcanoBlue); + +// 获取已注册的主题 +const baseTheme = VChart.ThemeManager.getTheme('vScreenVolcanoBlue'); + +// 扩展主题,添加自定义配置 +const extendedTheme = { + ...baseTheme, + series: { + ...baseTheme.series, + bar: { + ...baseTheme.series?.bar, + barMaxWidth: 40, + label: { + visible: true, + position: 'top', + style: { + fill: '#fff', + fontSize: 16, + fontWeight: 'bold' + } + } + } + }, + component: { + ...baseTheme.component, + axis: { + ...baseTheme.component?.axis, + label: { + ...baseTheme.component?.axis?.label, + style: { + ...baseTheme.component?.axis?.label?.style, + fontSize: 14, + fontWeight: 'bold' + } + } + } + } +}; + +// 注册扩展后的主题 +VChart.ThemeManager.registerTheme('extendedVolcanoBlue', extendedTheme); + +// 应用扩展主题 +VChart.ThemeManager.setCurrentTheme('extendedVolcanoBlue'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + +#### 使用深度合并扩展主题 + +对于复杂的主题结构,可以使用深度合并工具来扩展主题: + +```javascript livedemo +// 深度合并工具函数 +function deepMerge(target, source) { + const output = { ...target }; + if (isObject(target) && isObject(source)) { + Object.keys(source).forEach(key => { + if (isObject(source[key])) { + if (!(key in target)) { + Object.assign(output, { [key]: source[key] }); + } else { + output[key] = deepMerge(target[key], source[key]); + } + } else { + Object.assign(output, { [key]: source[key] }); + } + }); + } + return output; +} + +function isObject(item) { + return item && typeof item === 'object' && !Array.isArray(item); +} + +// 获取默认主题 +const baseTheme = VChart.ThemeManager.getDefaultTheme(); + +// 定义扩展配置 +const extension = { + series: { + bar: { + barMaxWidth: 25, + label: { + visible: true, + position: 'top' + } + } + }, + component: { + axis: { + label: { + style: { + fontSize: 14 + } + } + } + } +}; + +// 深度合并 +const mergedTheme = deepMerge(baseTheme, extension); + +// 注册合并后的主题 +VChart.ThemeManager.registerTheme('mergedTheme', mergedTheme); + +// 应用主题 +VChart.ThemeManager.setCurrentTheme('mergedTheme'); + +const spec = { + type: 'bar', + data: [ + { + id: 'barData', + values: [ + { type: 'A', value: 120 }, + { type: 'B', value: 200 }, + { type: 'C', value: 150 }, + { type: 'D', value: 80 } + ] + } + ], + xField: 'type', + yField: 'value' +}; + +const vchart = new VChart(spec, { dom: CONTAINER_ID }); +vchart.renderSync(); +``` + + + +## 总结 + +本文介绍了 VChart 主题应用的完整指南: + +1. **主题应用范围**: + - 全局应用:通过 `ThemeManager.setCurrentTheme()` 影响所有图表 + - 图表实例应用:通过 spec 的 `theme` 配置项或实例的 `setCurrentTheme()` 方法 + +2. **主题类型**: + - **默认主题**:VChart 内置的 `light` 和 `dark` 主题,无需注册即可使用 + - **自定义主题**:用户自己定义的主题配置对象 + - **扩展包主题**:通过 `@visactor/vchart-theme` 包提供的丰富主题 + - **扩展已安装的主题**:在已有主题基础上进行定制化修改 + +3. **最佳实践**: + - 对于需要统一风格的多个图表,使用全局主题 + - 对于需要特殊样式的单个图表,使用实例主题 + - 对于需要基于现有主题进行微调的场景,使用主题扩展 + +通过灵活运用这些主题应用方式,您可以轻松实现图表的个性化定制和统一管理。 +