diff --git a/README.md b/README.md index f8ce8fe00..18040d3b7 100644 --- a/README.md +++ b/README.md @@ -60,15 +60,36 @@ For example, ### Global Variables These global variables can be used in doc: -+ `${galleryViewPath}` -+ `${galleryEditorPath}` -+ `${websitePath}` -+ `${handbookPath}` - -Note: All of them are ended with a `/`, therefore, use them like `${galleryEditorPath}pie-legend`. ++ `${galleryViewPath}`: Use it like `${galleryViewPath}pie-legend`. ++ `${galleryEditorPath}`: Use it like `${galleryEditorPath}pie-legend`. ++ `${optionDocPath}`: Use it like `${optionDocPath}#xAxis.type`. ++ `${apiDocPath}`: Use it like `${apiDocPath}#echarts.init`. ++ `${handbookPath}`: Use it like `${handbookPath}basics/import`. ++ `${websitePath}`: Use it like `${websitePath}/examples/en/index.html#chart-type-custom`. See samples in "Reference of echarts-examples or other links" +### Reference of Other ECharts Option + +A `~` can be used to refer to a option item in the same doc. For example: +```md +[xAxis.name](~xAxis.name) +``` + +To reference an anchor in different doc, it can be: +```md +[itemStyle](option.html#series.itemStyle) +[action.highlight](api.html#action.highlight) +[Custom Series](tutorial.html#Custom%20Series) +[Use ECharts with bundler and NPM](${handbookPath}basics/import) +``` + +To add references in a code block, we have to: +```md +// See doc: ${optionDocPath}#series-bar.select +// See doc: ${apiDocPath}#echarts.init +``` + ### Reference of echarts-examples or Other Links Embed an example in doc (display the example directly in doc with an iframe. To avoid performance issues, do not overuse it.): @@ -77,6 +98,11 @@ Embed an example in doc (display the example directly in doc with an iframe. To ~[700x300](${galleryViewPath}doc-example/aria-pie&edit=1&reset=1) ``` +Insert an image: +```md +[600xauto](~axis-align-with-label.png) +``` + Provide an example link in doc: ```md [vertically scrollable legend](${galleryEditorPath}pie-legend&edit=1&reset=1) @@ -88,21 +114,6 @@ Provide a website link in doc: [Apache ECharts website](${websitePath}/en/download.html) ``` -### Reference of Other ECharts Option - -A `~` can be used to refer to a option item in the same doc. For example: -```md -[xAxis.name](~xAxis.name) -``` - -If intending to reference an anchor in different doc, it can be: -```md -[itemStyle](option.html#series.itemStyle) -[action.highlight](api.html#action.highlight) -[Custom Series](tutorial.html#Custom%20Series) -[Use ECharts with bundler and NPM](${handbookPath}basics/import) -``` - ### Notice diff --git a/config/env.asf.js b/config/env.asf.js index df5487365..9bc9c9560 100644 --- a/config/env.asf.js +++ b/config/env.asf.js @@ -3,6 +3,8 @@ const path = require('path'); module.exports = { galleryViewPath: 'https://echarts.apache.org/examples/${lang}/view.html?c=', galleryEditorPath: 'https://echarts.apache.org/examples/${lang}/editor.html?c=', + optionDocPath: 'https://echarts.apache.org/${lang}/option.html', + apiDocPath: 'https://echarts.apache.org/${lang}/api.html', handbookPath: 'https://echarts.apache.org/handbook/${lang}/', websitePath: 'https://echarts.apache.org', diff --git a/config/env.dev.js b/config/env.dev.js index 127270d47..cdcb030ce 100644 --- a/config/env.dev.js +++ b/config/env.dev.js @@ -3,6 +3,8 @@ const path = require('path'); module.exports = { galleryViewPath: 'http://localhost/echarts-website/examples/${lang}/view.html?c=', galleryEditorPath: 'http://localhost/echarts-website/examples/${lang}/editor.html?c=', + optionDocPath: 'https://echarts.apache.org/${lang}/option.html', + apiDocPath: 'https://echarts.apache.org/${lang}/api.html', handbookPath: 'http://localhost/echarts-website/handbook/${lang}/', websitePath: 'http://localhost/echarts-website', diff --git a/config/env.localsite.js b/config/env.localsite.js index 242b29b76..91550c65c 100644 --- a/config/env.localsite.js +++ b/config/env.localsite.js @@ -3,6 +3,8 @@ const path = require('path'); module.exports = { galleryViewPath: 'http://localhost/echarts-website/examples/${lang}/view.html?c=', galleryEditorPath: 'http://localhost/echarts-website/examples/${lang}/editor.html?c=', + optionDocPath: 'https://echarts.apache.org/${lang}/option.html', + apiDocPath: 'https://echarts.apache.org/${lang}/api.html', handbookPath: 'http://localhost/echarts-website/handbook/${lang}/', websitePath: './', diff --git a/en/api/action.md b/en/api/action.md index 666038429..e3ac4a20b 100644 --- a/en/api/action.md +++ b/en/api/action.md @@ -28,6 +28,37 @@ name?: string,{{/target}} +{{ target: action-axis-break-expand-collapse-common }} +Can not be used to create a new axis break. +```ts +dispatchAction({ + type: '${actionType}', + + // The target axis components can be queried by either index, id, or name. + xAxisIndex?: 'all' | number; + xAxisId?: string | number; + xAxisName?: string; + yAxisIndex?: 'all' | number; + yAxisId?: string | number; + yAxisName?: string; + singleAxisIndex?: 'all' | number; + singleAxisId?: string | number; + singleAxisName?: number; + + breaks: { + // Use the start/end to identify the target break items. + // See more details in doc: ${optionDocPath}#xAxis.breaks.start + start: string | number | Date, + end: string | number | Date, + } +}) +``` + +Then event [axisbreakchanged](~events.axisbreakchanged) is triggered. + +See also [axis break isExpanded](option.html#xAxis.breaks.isExpanded). +{{/target}} + {{ target: action }} # action @@ -127,6 +158,39 @@ dispatchAction({ }) ``` + +## axis + +### expandAxisBreak + +{{ use: partial-version(version = "6.0.0") }} + +Expand one or multiple existing axis break items. + +{{ use: action-axis-break-expand-collapse-common( + actionType = "expandAxisBreak" +) }} + +### collapseAxisBreak + +{{ use: partial-version(version = "6.0.0") }} + +Collapse one or multiple existing axis break items. + +{{ use: action-axis-break-expand-collapse-common( + actionType = "collapseAxisBreak" +) }} + +### toggleAxisBreak + +{{ use: partial-version(version = "6.0.0") }} + +Toggle (expand/collapse) one or multiple existing axis break items. + +{{ use: action-axis-break-expand-collapse-common( + actionType = "toggleAxisBreak" +) }} + ## legend Actions related to [legend component](option.html#legend), [legend component](option.html#legend) should be imported before use. diff --git a/en/api/events.md b/en/api/events.md index 398755013..7d3953853 100644 --- a/en/api/events.md +++ b/en/api/events.md @@ -202,6 +202,43 @@ Event when trigger legend scroll. ``` +## axisbreakchanged(Event) + +{{ use: partial-version(version = "6.0.0") }} + +**ACTION:** [expandAxisBreak](~action.axis.expandAxisBreak), [collapseAxisBreak](~action.axis.collapseAxisBreak) and [toggleAxisBreak](~action.axis.toggleAxisBreak) will trigger this event. + +```ts +{ + type: 'axisbreakchanged'; + // The type of the action that triggered this event. + fromAction: 'expandAxisBreak' | 'collapseAxisBreak' | 'toggleAxisBreak'; + // The original input action payload. + fromActionPayload: Payload; + // This breaks array only includes only break items that is specified + // in the action, rather than all break items existing in axes. + breaks: { + // start/end is also the unique identifier of this break item. + start: number; + end: number; + + // The index of the axis this break item belongs to. + xAxisIndex?: number; + yAxisIndex?: number; + singleAxisIndex?: number; + + // The state after updating. + isExpanded: boolean; + old: { + // The previous state. + isExpanded: boolean; + }; + }[] +} +``` + +**Notice:**When using [chart.setOption](~echartsInstance.setOption) to update axis breaks, this event is not triggered. Only actions trigger this event. + ## datazoom(Event) **ACTION:** [dataZoom](~action.dataZoom.dataZoom) @@ -221,6 +258,7 @@ Event emitted after zooming data area. endValue?: number } ``` + ## datarangeselected(Event) **ACTION:** [selectDataRange](~action.dataRange.selectDataRange) Event emitted after range is changed in visualMap. diff --git a/en/api/version.md b/en/api/version.md index 191ddadd7..09dee9a6d 100644 --- a/en/api/version.md +++ b/en/api/version.md @@ -1,9 +1,11 @@ {{ target: partial-version }} +
{{ if: ${deprecated} }} -> Deprecated since `v${version}`. ${deprecated} +Deprecated since `v${version}`. ${deprecated} {{ else }} -> Since `v${version}` +Since `v${version}` {{ /if }} +
{{ // this line break is necessary for md quote }} diff --git a/en/option-gl/component/axis3D-common.md b/en/option-gl/component/axis3D-common.md index 6b04d27a4..472d979ad 100644 --- a/en/option-gl/component/axis3D-common.md +++ b/en/option-gl/component/axis3D-common.md @@ -82,7 +82,9 @@ The margin between the axis label and the axis line. {{ /if }} ##${prefix|default('#')} formatter(string|Function) = null -{{use: axis-common-formatter-desc}} +{{ use: axis-common-formatter-desc( + componentType=${componentType} +) }} ##${prefix|default('#')} textStyle(Object) diff --git a/en/option-gl/partial/version.md b/en/option-gl/partial/version.md index c0ff95323..825ccf4a5 100644 --- a/en/option-gl/partial/version.md +++ b/en/option-gl/partial/version.md @@ -1,8 +1,10 @@ {{ target: partial-version }} +
{{ if: ${deprecated} }} -> Deprecated since{{ if: ${isECharts} }} ECharts{{ /if }} `v${version}`. ${deprecated} +Deprecated since{{ if: ${isECharts} }} ECharts{{ /if }} `v${version}`. ${deprecated} {{ else }} -> Since{{ if: ${isECharts} }} ECharts{{ /if }} `v${version}` +Since{{ if: ${isECharts} }} ECharts{{ /if }} `v${version}` {{ /if }} +
diff --git a/en/option/component/axis-common.md b/en/option/component/axis-common.md index c0afeffdc..6ba96d871 100644 --- a/en/option/component/axis-common.md +++ b/en/option/component/axis-common.md @@ -56,65 +56,139 @@ When setting [jitter](~${componentType}.jitter) and [jitterOverlap](~${component {{ use: partial-version(version = "6.0.0") }} -Break axis data, where each sub-element represents a segment of truncated space. +Defines axis breaks. Each entry represents a collapsed or skipped range of the axis. ~[800x400](${galleryViewPath}intraday-breaks-2&edit=1&reset=1) +~[800x400](${galleryViewPath}intraday-breaks-1&edit=1&reset=1) +~[800x400](${galleryViewPath}bar-breaks-brush&edit=1&reset=1) -> Break axis is a technique that truncates portions of the coordinate axis to compress the display space of non-critical data segments in charts. Its core purposes are: +**Other examples:** [bar-breaks-simple](${galleryEditorPath}bar-breaks-simple&edit=1&reset=1), [line-fisheye-lens](${galleryEditorPath}line-fisheye-lens&edit=1&reset=1) + + +> An axis break is a technique that collapses portions of the coordinate axis to compress the display space of non-critical data segments in charts. Its core purposes are: > > + **Highlight differences**: When there are extreme differences between data values (such as one value being much larger than others), it prevents large value bars from overwhelmingly occupying space, making small value differences difficult to distinguish. > + **Save space**: Reduces blank areas caused by extreme values, making charts more compact. > -> Please note that break axis should only be used when necessary to avoid misleading users. When using break axis, the truncated parts and corresponding values should usually be clearly indicated. +> Please note that axis breaks should only be used when necessary to avoid misleading users. When using axis breaks, the collapsed parts and corresponding values should usually be clearly indicated. > -> Break axis cannot be used in category axes ([type](~${componentType}.type): `'category'`). +> Axis breaks cannot be used in category axes ([type](~${componentType}.type): `'category'`). + + +If you import ECharts by [only importing the necessary components](${handbookPath}basics/import), you need to import and register the feature `AxisBreak` explicitly. For example, +```ts +import * as echarts from 'echarts/core'; +import { BarChart } from 'echarts/charts'; +import { + TitleComponent, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent +} from 'echarts/components'; + +// Import the feature AxisBreak +import { AxisBreak } from 'echarts/features'; + +import { CanvasRenderer } from 'echarts/renderers'; + +// Register +echarts.use([ + BarChart, + TitleComponent, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent, + AxisBreak, + CanvasRenderer +]); + +var myChart = echarts.init(document.getElementById('main')); +myChart.setOption({ + // ... +}); +``` + ##${prefix} start(string|number|Date) -The start value for truncation. +{{ use: partial-version(version = "6.0.0") }} + +The start value for the axis break area, specified in data domain defined by `series.data`, rather than in pixels. + +{{ use: partial-scale-data-value-desc( + componentType = ${componentType}, + notSupportCategory = true +) }} -+ For coordinate axes with [type](~${componentType}.type) as `'value'` or `'log'`, use `number` type values -+ For coordinate axes with [type](~${componentType}.type) as `'time'`: - + `string` type time values (e.g., `'2024-04-09 13:00:00'`) - + `number` type timestamps (e.g., `(new Date('2024-04-09 13:00:00')).getTime()`) - + `Date` type time objects (e.g., `new Date('2024-04-09 13:00:00')`). +{{ use: partial-axis-break-identifier-desc( + componentType = ${componentType} +)}} ##${prefix} end(string|number|Date) -The end value for truncation. +{{ use: partial-version(version = "6.0.0") }} + +The end value for the axis break area, specified in data domain defined by `series.data`, rather than in pixels. -+ For coordinate axes with [type](~${componentType}.type) as `'value'` or `'log'`, use `number` type values -+ For coordinate axes with [type](~${componentType}.type) as `'time'`: - + `string` type time values (e.g., `'2024-04-09 13:00:00'`) - + `number` type timestamps (e.g., `(new Date('2024-04-09 13:00:00')).getTime()`) - + `Date` type time objects (e.g., `new Date('2024-04-09 13:00:00')`). +{{ use: partial-scale-data-value-desc( + componentType = ${componentType}, + notSupportCategory = true +) }} + +{{ use: partial-axis-break-identifier-desc( + componentType = ${componentType} +)}} ##${prefix} gap(number|string) -The display size of the break axis truncated area. +{{ use: partial-version(version = "6.0.0") }} + +It determines the visual size of the axis break area. + ++ Percentage (string): + + Specifies the proportion relative to the axis. For example, `'5%'` means that the final size of the axis break area will always be `'5%'` of the axis length. Using a percentage ensures that the pixel size of the axis break area remains stable, and does not change when [${componentType}.min](~${componentType}.min), [${componentType}.max](~${componentType}.max), or [dataZoom](~dataZoom) are modified. For this reason, using a percentage is recommended in most scenarios. ++ Absolute value: + + Its unit is the same as [start](~${componentType}.breaks.start) and [end](~${componentType}.breaks.end), referring to a value in the data domain defined by the business data (`series.data`), rather than pixels. It represents mapping (replacing) the `[start, end]` interval with `[start, start + gap]`. Therefore, if set as an absolute value, the pixel size of the axis break area will change when [${componentType}.min](~${componentType}.min), [${componentType}.max](~${componentType}.max), or [dataZoom](~dataZoom) are modified. + +**Notice:** Within a [${componentType}.breaks](~${componentType}.breaks) array, `gap` must be specified either entirely in percentages or entirely in absolute values. Mixing the two is not allowed, as it may lead to unexpected results. -+ `number`: Same unit as `start` and `end`, not representing pixel size -+ `string`: - + Supports percentage forms like `'35%'`, representing relative proportion to the coordinate axis data area size - + Supports strings like `'123'`, equivalent to `number` type `123`, note that it does not represent pixel size +{{ use: partial-axis-break-identifier-desc( + componentType = ${componentType} +)}} ##${prefix} isExpanded(boolean) = false -Whether this truncated area is expanded, default is `false`. +{{ use: partial-version(version = "6.0.0") }} + +Whether this axis break area is expanded, default is `false`. + +{{ use: partial-axis-break-identifier-desc( + componentType = ${componentType} +)}} #${prefix} breakArea {{ use: partial-version(version = "6.0.0") }} -Style of the break axis truncated area. +Style of the axis break area. + +See also the introduction to the axis break in [${componentType}.breaks](~${componentType}breaks). ##${prefix} show(boolean) = true -Whether to show the truncated area. +{{ use: partial-version(version = "6.0.0") }} + +Whether to show the axis break area. ##${prefix} itemStyle -Style of the truncated area. +{{ use: partial-version(version = "6.0.0") }} + +Style of the axis break area. {{ use: partial-item-style( prefix = '###', @@ -127,37 +201,52 @@ Style of the truncated area. ##${prefix} zigzagAmplitude(number) = 4 -The amplitude (in the direction perpendicular to the coordinate axis) of the truncated zigzag. The size of the truncated zigzag in the direction perpendicular to the coordinate axis is always the same across different zigzags. +{{ use: partial-version(version = "6.0.0") }} + +The amplitude (in the direction perpendicular to the coordinate axis) of the zigzag. The size of different teeth is always the same. The unit is pixel. If set to `0`, the zigzag degenerates into a straight line. ##${prefix} zigzagMinSpan(number) = 4 -The minimum size of the truncated zigzag in the coordinate axis direction. +{{ use: partial-version(version = "6.0.0") }} -> The size of the truncated zigzag in the coordinate axis direction is a random number between `zigzagMinSpan` and `zigzagMaxSpan`. Randomness is used to simulate the effect of torn paper. +The minimum size of each tooth. The unit is pixel. + +> The size of a tooth is a random number between `zigzagMinSpan` and `zigzagMaxSpan`. Randomness is used to simulate the effect of torn paper. ##${prefix} zigzagMaxSpan(number) = 20 -The maximum size of the truncated zigzag in the coordinate axis direction. +{{ use: partial-version(version = "6.0.0") }} -> The size of the truncated zigzag in the coordinate axis direction is a random number between `zigzagMinSpan` and `zigzagMaxSpan`. Randomness is used to simulate the effect of torn paper. +The maximum size of each tooth. The unit is pixel. + +> The size of a tooth is a random number between `zigzagMinSpan` and `zigzagMaxSpan`. Randomness is used to simulate the effect of torn paper. ##${prefix} zigzagZ(number) = 100 -The `z` value of the truncated zigzag. Controls the front-to-back order of graphics. Graphics with smaller `z` values will be covered by graphics with larger `z` values. +{{ use: partial-version(version = "6.0.0") }} + +The `z` value of the zigzag. Controls the front-to-back order of graphics. Graphics with smaller `z` values will be covered by graphics with larger `z` values. ##${prefix} expandOnClick(boolean) = true -Whether to expand the truncated area when clicking on the break axis truncated area. +{{ use: partial-version(version = "6.0.0") }} + +Whether to expand the axis break area when clicking on it. #${prefix} breakLabelLayout(Object) {{ use: partial-version(version = "6.0.0") }} -Break axis label layout. +Axis breaks label layout. + +See also the introduction to the axis break in [${componentType}.breaks](~${componentType}breaks). + ##${prefix} moveOverlap(string|boolean) = 'auto' -When break axis labels overlap, whether to move labels to avoid overlap. +{{ use: partial-version(version = "6.0.0") }} + +When axis break labels overlap, whether to move labels to avoid overlap. `'auto'` or `true` means moving labels to avoid overlap when overlapping occurs; `false` means not moving. {{ /if }} @@ -270,7 +359,10 @@ The margin between the axis label and the axis line. ##${prefix} formatter(string|Function) = null -{{ use: axis-common-formatter-desc() }} +{{ use: axis-common-formatter-desc( + componentType = ${componentType}, + supportAxisBreak = true +) }} ##${prefix} showMinLabel(boolean) = null @@ -1034,6 +1126,10 @@ The first parameter is index of category, and the second parameter is the name o {{ target: axis-common-formatter-desc }} +{{ if: !${axisTypeProp} }} +{{ var: axisTypeProp = 'type' }} +{{ /if }} + Formatter of axis label, which supports string template and callback function. Example: @@ -1041,15 +1137,48 @@ Example: // Use string template; template variable is the default label of axis {value} formatter: '{value} kg' // Use callback. -formatter: function (value, index) { +formatter: function (value, index, extra?) { return value + 'kg'; } ``` --- -For axes of time [type](~${componentType}.type): `'time'`, `formatter` supports the following forms: +
+ +{{ if: ${supportAxisBreak} }} +**When [axis break](${componentType}.breaks) is used** +The break info can be obtained from the `extra` param: +```ts +type AxisLabelFormatterExtraBreakPart = { + // If this label is a axis break start or end. + break?: { + type: 'start' | 'end'; + // The parsed `start`/`end`, always be numbers, and has been + // sorted and intersection removed, therefore, they may not + // equal to the original input of `start`/`end`. + start: number; + end: number; + } +} +formatter = function (value, index, extra: AxisLabelFormatterExtraBreakPart) { + if (extra && extra.break) { + console.log(extra.break); + } + return value + 'kg'; +} +``` +Notice: null checking must be performed. +{{ /if }} + +--- + +
+ +**For a time axis ([`${componentType}.${axisTypeProp}: 'time'`](~${componentType}.${axisTypeProp}))** + +`formatter` supports the following forms: - **String Templates**: an easy and fast way to make frequently used date/time template, formed in `string` - **Callback Functions**: customized formatter to make complex format, formed in `Function` - **Cascading Templates**: to adopt different formatters for different time granularity, formed in `object` @@ -1111,6 +1240,17 @@ formatter: function (value, index) { } return texts.join('/'); } + +// Moreover, `echarts.time.format` can be used: +formatter: function (value, index) { + // Follow the template rules above. + const timeStrLocal = echarts.time.format(value, '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}'); + // The third param `true` indicates that format time based on UTC. + const timeStrUTC = echarts.time.format(value, '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}', true); + // Notice, if using UTC, ${optionDocPath}#useUTC need to be also set as `true` + // for consistency. + return timeStrLocal; +} ``` ** Cascading Templates ** @@ -1228,3 +1368,25 @@ Whether to show the tooltip. Defaults to `false`. ) }} + +{{ target: partial-scale-data-value-desc }} + +- If [axis.type](~${componentType}.type) is `'value'` or `'log'`, use `number` type values. +{{ if: ${notSupportCategory} }} +- If [axis.type](~${componentType}.type) is `'category'`: not supported yet. +{{ else }} +- If [axis.type](~${componentType}.type) is `'category'`, the value can be: + - The original string, such as `'categoryA'`, `'categoryB'`. + - The ordinal number. For example, if a catergory axis is defined as `data: ['categoryA', 'categoryB', 'categoryC']`, and the ordinal `2` represents `'categoryC'` (starting from `0`). Moreover, it can be set as negative number, like `-3`. +{{ /if }} +- If [axis.type](~${componentType}.type) is `'time'`, the value can be: + - `string` type represents any time format that can be parsed by [method `parseDate` in `echarts/src/util/number.ts`](https://github.com/apache/echarts/blob/master/src/util/number.ts), e.g., `'2024-04-09 13:00:00'`. + - `number` type represents a timestamp, e.g., `1712667600000`. + - `Date` type time objects, e.g., `new Date('2024-04-09T13:00:00Z')`. + + + +{{ target: partial-axis-break-identifier-desc }} + +Note: [${componentType}.breaks.start](~${componentType}.breaks.start) and [${componentType}.breaks.end](~${componentType}.breaks.end) are the unique identifiers for each break item. When calling [chart.setOption](api.html#echartsInstance.setOption) to modify [${componentType}.breaks.gap](~${componentType}.breaks.gap) or [${componentType}.breaks.isExpanded](~${componentType}.breaks.isExpanded), `start` and `end` must be specified. Update animations will only occur if `start` and `end` are not modified; no animation will occur if they are changed. + diff --git a/en/option/component/timeline.md b/en/option/component/timeline.md index 8116e97cd..4d3dfaeba 100644 --- a/en/option/component/timeline.md +++ b/en/option/component/timeline.md @@ -527,7 +527,10 @@ Rotation angle of `label`, in which positive values refer to counter clockwise r #${prefix} formatter(string|Function) = null -{{ use: axis-common-formatter-desc() }} +{{ use: axis-common-formatter-desc( + componentType = ${componentType}, + axisTypeProp = 'axisType' +) }} {{ if: ${state} }} {{ use: partial-text-style( diff --git a/en/option/option.md b/en/option/option.md index 2e8677800..f90b7fd2a 100644 --- a/en/option/option.md +++ b/en/option/option.md @@ -164,6 +164,11 @@ The default value of `useUTC` is false, for sake of considering: Notice: the setting only affects "display time", not "parse time". For how time value (like `1491339540396`, `'2013-01-04'`, ...) is parsed in echarts, see [the time part in date](~series-line.data). +Notice: if you set `useUTC: true` and use the helper method `echarts.time.format` (or other similar third-party methods), it should also be configured to format in UTC. For example, +```ts +// The third param `true` indicates that format time based on UTC. +const timeStrUTC = echarts.time.format(value, '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}', true); +``` {{import: partial-rich-inherit-plain-label}} diff --git a/en/option/partial/version.md b/en/option/partial/version.md index ab87c8c82..60974bb52 100644 --- a/en/option/partial/version.md +++ b/en/option/partial/version.md @@ -1,9 +1,11 @@ {{ target: partial-version }} +
{{ if: ${deprecated} }} -> Deprecated since `v${version}`. ${deprecated} +Deprecated since `v${version}`. ${deprecated} {{ else }} -> Since `v${version}` +Since `v${version}` {{ /if }} +
diff --git a/src/style/mixin.scss b/src/style/mixin.scss index 8ecd9b603..9dc0917f0 100644 --- a/src/style/mixin.scss +++ b/src/style/mixin.scss @@ -16,6 +16,14 @@ margin-left: 0px; padding: 10px 20px; + + p { + font-size: 13px; + } + pre { + font-size: 13px; + background-color: #fff; + } } iframe { @@ -73,4 +81,16 @@ a { font-family: 'Source Code Pro', STHeiti, "Microsoft Yahei", "WenQuanYi Micro Hei", sans-serif; } + + .doc-partial-version { + font-size: 12px; + background: #f3f3f3; + margin: 10px 20px 10px 0; + padding: 10px; + border-left: 2px solid #ddd; + + code { + color: #0086b3; + } + } } diff --git a/zh/api/action.md b/zh/api/action.md index fb802b251..85f729d40 100644 --- a/zh/api/action.md +++ b/zh/api/action.md @@ -28,6 +28,38 @@ name?: string,{{/target}} +{{ target: action-axis-break-expand-collapse-common }} +不能用于创建新的 axis break 。 +```ts +dispatchAction({ + type: '${actionType}', + + // 坐标轴可以用 index、id 或 name 来检索到。 + xAxisIndex?: 'all' | number; + xAxisId?: string | number; + xAxisName?: string; + yAxisIndex?: 'all' | number; + yAxisId?: string | number; + yAxisName?: string; + singleAxisIndex?: 'all' | number; + singleAxisId?: string | number; + singleAxisName?: number; + + breaks: { + // 使用 start/end 来定位要更改的 break 项。 + // 更多信息参见文档:${optionDocPath}#xAxis.breaks.start + start: string | number | Date, + end: string | number | Date, + } +}) +``` + +继而事件 [axisbreakchanged](~events.axisbreakchanged) 会被派发。 + +也参见 [axis break isExpanded](option.html#xAxis.breaks.isExpanded)。 +{{/target}} + + {{ target: action }} # action @@ -126,6 +158,39 @@ dispatchAction({ ``` +## axis + +### expandAxisBreak + +{{ use: partial-version(version = "6.0.0") }} + +展开一个或多个已存在的 axis break 项。不能用于创建新的 axis break 。 + +{{ use: action-axis-break-expand-collapse-common( + actionType = "expandAxisBreak" +) }} + +### collapseAxisBreak + +{{ use: partial-version(version = "6.0.0") }} + +折叠一个或多个已存在的 axis break 项。不能用于创建新的 axis break 。 + +{{ use: action-axis-break-expand-collapse-common( + actionType = "collapseAxisBreak" +) }} + +### toggleAxisBreak + +{{ use: partial-version(version = "6.0.0") }} + +切换(展开/折叠)一个或多个已存在的 axis break 项。不能用于创建新的 axis break 。 + +{{ use: action-axis-break-expand-collapse-common( + actionType = "toggleAxisBreak" +) }} + + ## legend [图例组件](option.html#legend)相关的行为,必须引入[图例组件](option.html#legend)后才能使用。 diff --git a/zh/api/events.md b/zh/api/events.md index e4953f1a2..6ce19f90b 100644 --- a/zh/api/events.md +++ b/zh/api/events.md @@ -201,6 +201,44 @@ chart.on('mouseover', {seriesIndex: 1, name: 'xx'}, function (params) { ``` +## axisbreakchanged(Event) + +{{ use: partial-version(version = "6.0.0") }} + +**ACTION:** [expandAxisBreak](~action.axis.expandAxisBreak), [collapseAxisBreak](~action.axis.collapseAxisBreak) and [toggleAxisBreak](~action.axis.toggleAxisBreak) 会派发本事件。 + +```ts +{ + type: 'axisbreakchanged'; + // 触发本事件的 action 的 type 。 + fromAction: 'expandAxisBreak' | 'collapseAxisBreak' | 'toggleAxisBreak'; + // 触发本事件的 action 的 payload 。 + fromActionPayload: Payload; + // 本 breaks 数组里只包含 action 里指定的 break 项, + // 而非 axis 里存在的所有 break 项。 + breaks: { + // start/end 也被用于本 break 项的唯一标识。 + start: number; + end: number; + + // 本 break item 所在的 axis 的 index。 + xAxisIndex?: number; + yAxisIndex?: number; + singleAxisIndex?: number; + + // 更新后的状态。 + isExpanded: boolean; + old: { + // 更新前的状态。 + isExpanded: boolean; + }; + }[] +} +``` + +**注意:**使用 [chart.setOption](~echartsInstance.setOption) 更新 axis breaks 时,不会触发本事件。只有 action 会触发本事件。 + + ## datazoom(Event) **ACTION:** [dataZoom](~action.dataZoom.dataZoom) diff --git a/zh/api/version.md b/zh/api/version.md index aea7002e6..36f0782a5 100644 --- a/zh/api/version.md +++ b/zh/api/version.md @@ -1,9 +1,11 @@ {{ target: partial-version }} +
{{ if: ${deprecated} }} -> 从 `v${version}` 开始不推荐使用(deprecated)。${deprecated} +从 `v${version}` 开始不推荐使用(deprecated)。${deprecated} {{ else }} -> 从 `v${version}` 开始支持 +从 `v${version}` 开始支持 {{ /if }} +
{{ // this line break is necessary for md quote }} diff --git a/zh/option-gl/component/axis3D-common.md b/zh/option-gl/component/axis3D-common.md index 9a8747543..8d5a055d0 100644 --- a/zh/option-gl/component/axis3D-common.md +++ b/zh/option-gl/component/axis3D-common.md @@ -82,7 +82,9 @@ formatter: function (value, index) { {{ /if }} ##${prefix|default('#')} formatter(string|Function) = null -{{use: axis-common-formatter-desc}} +{{ use: axis-common-formatter-desc( + componentType=${componentType} +) }} ##${prefix|default('#')} textStyle(Object) diff --git a/zh/option-gl/partial/version.md b/zh/option-gl/partial/version.md index 45166dd61..cf9cb8a55 100644 --- a/zh/option-gl/partial/version.md +++ b/zh/option-gl/partial/version.md @@ -1,8 +1,10 @@ {{ target: partial-version }} +
{{ if: ${deprecated} }} -> 从{{ if: ${isECharts} }} ECharts{{ /if }} `v${version}` 开始不推荐使用(deprecated)。${deprecated} +从{{ if: ${isECharts} }} ECharts{{ /if }} `v${version}` 开始不推荐使用(deprecated)。${deprecated} {{ else }} -> 从{{ if: ${isECharts} }} ECharts{{ /if }} `v${version}` 开始支持 +从{{ if: ${isECharts} }} ECharts{{ /if }} `v${version}` 开始支持 {{ /if }} +
diff --git a/zh/option/component/axis-common.md b/zh/option/component/axis-common.md index 82f1bf808..87fa0f3e4 100644 --- a/zh/option/component/axis-common.md +++ b/zh/option/component/axis-common.md @@ -57,6 +57,11 @@ 断轴的截断数据,每一个子元素表示一段截断的空间。 ~[800x400](${galleryViewPath}intraday-breaks-2&edit=1&reset=1) +~[800x400](${galleryViewPath}intraday-breaks-1&edit=1&reset=1) +~[800x400](${galleryViewPath}bar-breaks-brush&edit=1&reset=1) + +**其他例子:** [bar-breaks-simple](${galleryEditorPath}bar-breaks-simple&edit=1&reset=1), [line-fisheye-lens](${galleryEditorPath}line-fisheye-lens&edit=1&reset=1) + > 断轴是一种通过在坐标轴上截断部分区域,从而压缩图表中非关键数据段的展示空间的技术。其核心目的是: > @@ -67,51 +72,118 @@ > > 断轴无法在类目轴([type](~${componentType}.type): `'category'`)中使用。 +如果 ECharts 的 `import` 方式是 [只 `import` 所需要的组件](${handbookPath}basics/import),断轴功能需要被手动 `import` 和注册。例如, +```ts +import * as echarts from 'echarts/core'; +import { BarChart } from 'echarts/charts'; +import { + TitleComponent, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent +} from 'echarts/components'; + +// import 断轴功能 +import { AxisBreak } from 'echarts/features'; + +import { CanvasRenderer } from 'echarts/renderers'; + +// 注册 +echarts.use([ + BarChart, + TitleComponent, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent, + AxisBreak, + CanvasRenderer +]); + +var myChart = echarts.init(document.getElementById('main')); +myChart.setOption({ + // ... +}); +``` + ##${prefix} start(string|number|Date) -开始截断的值。 +{{ use: partial-version(version = "6.0.0") }} -+ 对于 [type](~${componentType}.type) 是 `'value'` 或 `'log'` 类型的坐标轴,使用 `number` 类型的值 -+ 对于 [type](~${componentType}.type) 是 `'time'` 类型的坐标轴 - + `string` 类型的时间值(例如 `'2024-04-09 13:00:00'`) - + `number` 类型的时间戳(例如 `(new Date('2024-04-09 13:00:00')).getTime()`) - + `Date` 类型的时间对象(例如 `new Date('2024-04-09 13:00:00')`)。 +开始截断的值。它是业务数据(`series.data`)所定义的值域中的某个值,而非像素值。 + +{{ use: partial-scale-data-value-desc( + componentType = ${componentType}, + notSupportCategory = true +) }} + +{{ use: partial-axis-break-identifier-desc( + componentType = ${componentType} +)}} ##${prefix} end(string|number|Date) -结束截断的值。 +{{ use: partial-version(version = "6.0.0") }} + +结束截断的值。它是业务数据(`series.data`)所定义的值域中的某个值,而非像素值。 -+ 对于 [type](~${componentType}.type) 是 `'value'` 或 `'log'` 类型的坐标轴,使用 `number` 类型的值 -+ 对于 [type](~${componentType}.type) 是 `'time'` 类型的坐标轴 - + `string` 类型的时间值(例如 `'2024-04-09 13:00:00'`) - + `number` 类型的时间戳(例如 `(new Date('2024-04-09 13:00:00')).getTime()`) - + `Date` 类型的时间对象(例如 `new Date('2024-04-09 13:00:00')`)。 +{{ use: partial-scale-data-value-desc( + componentType = ${componentType}, + notSupportCategory = true +) }} + +{{ use: partial-axis-break-identifier-desc( + componentType = ${componentType} +)}} ##${prefix} gap(number|string) -断轴截断区域展示的大小。 +{{ use: partial-version(version = "6.0.0") }} + +决定了断轴截断区域最终展示的尺寸(高或者宽)。其值可为: -+ `number`:单位和 `start` 与 `end` 相同,而不表示像素大小 -+ `string`: - + 支持例如 `'35%'` 的百分比形式,表示相对于坐标轴数据区域大小的相对比例 - + 支持例如 `'123'` 的字符串,等同于 `number` 类型的 `123,注意不表示像素大小 ++ 百分比(字符串): + + 表示相对于坐标轴的比例。例如 `'5%'`,表示断轴截断区域最终显示的尺寸总为坐标轴尺寸的 `'5%'`。使用百分比能保证断轴截断区域的像素尺寸稳定,不随着 [${componentType}.min](~${componentType}.min)、[${componentType}.max](~${componentType}.max)、[dataZoom](~dataZoom) 变化而变化,因此目前大多数场景都适合使用百分比。 ++ 绝对值: + + 其单位和 [start](~${componentType}.breaks.start) 与 [end](~${componentType}.breaks.end) 相同,是业务数据(`series.data`)所定义的值域中的某个值,而非像素值。它表示把 `[start, end]` 这个区间映射(替换)为 `[start, start + gap]`。因此,设为绝对值时,断轴截断区域的像素尺寸会随着 [${componentType}.min](~${componentType}.min)、[${componentType}.max](~${componentType}.max)、[dataZoom](~dataZoom) 变化而变化。 + +**注意:**在一个 [${componentType}.breaks](~${componentType}.breaks) 数组中,`gap` 只允许全使用百分比,或者全使用绝对值,不允许混合使用,否者效果可能不符合预期。 + +{{ use: partial-axis-break-identifier-desc( + componentType = ${componentType} +)}} ##${prefix} isExpanded(boolean) = false +{{ use: partial-version(version = "6.0.0") }} + 该截断区域是否已展开,默认为 `false`。 +{{ use: partial-axis-break-identifier-desc( + componentType = ${componentType} +)}} + #${prefix} breakArea {{ use: partial-version(version = "6.0.0") }} 断轴截断区域的样式。 +断轴的基本介绍参见 [${componentType}.breaks](~${componentType}breaks)。 + ##${prefix} show(boolean) = true +{{ use: partial-version(version = "6.0.0") }} + 是否显示截断区域。 ##${prefix} itemStyle +{{ use: partial-version(version = "6.0.0") }} + 截断区域样式。 {{ use: partial-item-style( @@ -125,26 +197,36 @@ ##${prefix} zigzagAmplitude(number) = 4 -截断锯齿的振幅(垂直坐标轴方向上)大小。截断锯齿在垂直坐标轴的方向上的大小在不同锯齿上总是相同的。 +{{ use: partial-version(version = "6.0.0") }} + +锯齿的振幅(垂直于坐标轴方向上)大小。这个大小在不同锯齿上总是相同的。单位为像素。如果设为 `0` 则锯齿退化成一条直线。 ##${prefix} zigzagMinSpan(number) = 4 -截断锯齿在坐标轴方向上最小的大小。 +{{ use: partial-version(version = "6.0.0") }} + +每个锯齿跨度的最小值。单位为像素。 -> 截断锯齿在坐标轴方向上的大小是 `zigzagMinSpan` 和 `zigzagMaxSpan` 之间的随机数。通过随机来模拟纸片撕开的效果。 +> 每个锯齿跨度大小是 `zigzagMinSpan` 和 `zigzagMaxSpan` 之间的随机数。通过随机来模拟纸片撕开的效果。 ##${prefix} zigzagMaxSpan(number) = 20 -截断锯齿在坐标轴方向上最大的大小。 +{{ use: partial-version(version = "6.0.0") }} + +每个锯齿跨度的最大值。单位为像素。 -> 截断锯齿在坐标轴方向上的大小是 `zigzagMinSpan` 和 `zigzagMaxSpan` 之间的随机数。通过随机来模拟纸片撕开的效果。 +> 每个锯齿跨度大小是 `zigzagMinSpan` 和 `zigzagMaxSpan` 之间的随机数。通过随机来模拟纸片撕开的效果。 ##${prefix} zigzagZ(number) = 100 -截断锯齿的 `z` 值。控制图形的前后顺序。`z` 值小的图形会被 `z` 值大的图形覆盖。 +{{ use: partial-version(version = "6.0.0") }} + +锯齿的 `z` 值。控制图形的前后顺序。`z` 值小的图形会被 `z` 值大的图形覆盖。 ##${prefix} expandOnClick(boolean) = true +{{ use: partial-version(version = "6.0.0") }} + 点击断轴截断区域是否展开截断区域。 #${prefix} breakLabelLayout(Object) @@ -153,8 +235,13 @@ 断轴文字布局。 +断轴的基本介绍参见 [${componentType}.breaks](~${componentType}breaks)。 + + ##${prefix} moveOverlap(string|boolean) = 'auto' +{{ use: partial-version(version = "6.0.0") }} + 当断轴文字重叠时,是否移动文字来避免重叠。 `'auto'` 或 `true` 表示重叠时移动文字来避免重叠;`false` 表示不移动。 @@ -270,7 +357,10 @@ X 轴或者 Y 轴的轴线是否在另一个轴的 0 刻度上,只有在另一 ##${prefix} formatter(string|Function) -{{ use: axis-common-formatter-desc() }} +{{ use: axis-common-formatter-desc( + componentType = ${componentType}, + supportAxisBreak = true +) }} ##${prefix} showMinLabel(boolean) @@ -805,7 +895,7 @@ boundaryGap: ['20%', '20%'] 不设置时会自动计算最小值保证坐标轴刻度的均匀分布。 -在类目轴中,也可以设置为类目的序数(如类目轴 `data: ['类A', '类B', '类C']` 中,序数 `2` 表示 `'类C'`。也可以设置为负数,如 `-3`)。 +{{ use: partial-scale-data-value-desc() }} 当设置成 `function` 形式时,可以根据计算得出的数据最大最小值设定坐标轴的最小值。如: @@ -827,7 +917,7 @@ min: function (value) { 不设置时会自动计算最大值保证坐标轴刻度的均匀分布。 -在类目轴中,也可以设置为类目的序数(如类目轴 `data: ['类A', '类B', '类C']` 中,序数 `2` 表示 `'类C'`。也可以设置为负数,如 `-3`)。 +{{ use: partial-scale-data-value-desc() }} 当设置成 `function` 形式时,可以根据计算得出的数据最大最小值设定坐标轴的最小值。如: @@ -1031,6 +1121,10 @@ ${name}的显示间隔,在类目轴中有效。{{ if: !${isAxisLabel} }}默认 {{ target: axis-common-formatter-desc }} +{{ if: !${axisTypeProp} }} +{{ var: axisTypeProp = 'type' }} +{{ /if }} + 刻度标签的内容格式器,支持字符串模板和回调函数两种形式。 示例: @@ -1038,15 +1132,47 @@ ${name}的显示间隔,在类目轴中有效。{{ if: !${isAxisLabel} }}默认 // 使用字符串模板,模板变量为刻度默认标签 {value} formatter: '{value} kg' // 使用函数模板,函数参数分别为刻度数值(类目),刻度的索引 -formatter: function (value, index) { +formatter: function (value, index, extra?) { + return value + 'kg'; +} +``` + +--- + +
+ +{{ if: ${supportAxisBreak} }} +**如果使用了 [axis break](${componentType}.breaks)** + +break 信息可以在参数 `extra` 里被获取: +```ts +type AxisLabelFormatterExtraBreakPart = { + // 如果这个 label 是 break 的 start 或者 end + break?: { + type: 'start' | 'end'; + // 这是解析过的 `start`/`end` 值,必然为 number,且进行过排序和重叠 + // 去除,所以不一定和原先输入的 `start`/`end` 的类型和值相同。 + start: number; + end: number; + } +} +formatter = function (value, index, extra: AxisLabelFormatterExtraBreakPart) { + if (extra && extra.break) { + console.log(extra.break); + } return value + 'kg'; } ``` +注意:使用前需要判空。 +{{ /if }} --- -对于时间轴([type](~${componentType}.type): `'time'`),`formatter` 的字符串模板支持多种形式: +
+**对于时间轴([`${componentType}.${axisTypeProp}: 'time'`](~${componentType}.${axisTypeProp}))** + +`formatter` 的字符串模板支持多种形式: - **字符串模板**:简单快速实现常用日期时间模板,`string` 类型 - **回调函数**:自定义 formatter,可以用来实现复杂高级的格式,`Function` 类型 - **分级模板**:为不同时间粒度的标签使用不同的 formatter,`object` 类型 @@ -1106,6 +1232,16 @@ formatter: function (value, index) { } return texts.join('/'); } + +// 另外,`echarts.time.format` 也可以被使用: +formatter: function (value, index) { + // 时间模版的规则如上描述。 + const timeStrLocal = echarts.time.format(value, '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}'); + // 第三个参数表示,基于 UTC 解析时间。 + const timeStrUTC = echarts.time.format(value, '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}', true); + // 注意:如果使用 UTC,${optionDocPath}#useUTC 也要设置为 `true`,保持一致。 + return timeStrLocal; +} ``` ** 分级模板 ** @@ -1224,3 +1360,24 @@ xAxis: { ) }} + +{{ target: partial-scale-data-value-desc }} + +- 如果 [axis.type](~${componentType}.type) 是 `'value'` 或 `'log'`,则使用 `number` 类型的值。 +{{ if: ${notSupportCategory} }} +- 如果 [axis.type](~${componentType}.type) 是 `'category'`:不支持。 +{{ else }} +- 如果 [axis.type](~${componentType}.type) 是 `'category'`,值可以是: + - 原始字符串,例如 `'categoryA'`、`'categoryB'`。 + - 序号。例如,如果类目轴定义为 `data: ['categoryA', 'categoryB', 'categoryC']`,则序号 `2` 表示 `'categoryC'`(从 `0` 开始计数)。此外,也可以设置为负数,例如 `-3`。 +{{ /if }} +- 如果 [axis.type](~${componentType}.type) 是 `'time'`,值可以是: + - `string` 类型,表示任意能被 [方法 `parseDate` (`echarts/src/util/number.ts`)](https://github.com/apache/echarts/blob/master/src/util/number.ts) 解析的时间格式,例如 `'2024-04-09 13:00:00'`。 + - `number` 类型,表示时间戳,例如 `1712667600000`。 + - `Date` 类型的时间对象,例如 `new Date('2024-04-09T13:00:00Z')`。 + + + +{{ target: partial-axis-break-identifier-desc }} + +注:[${componentType}.breaks.start](~${componentType}.breaks.start) 和 [${componentType}.breaks.end](~${componentType}.breaks.end) 是每个 break 项的唯一标志。当调用 [chart.setOption](api.html#echartsInstance.setOption) 修改 [${componentType}.breaks.gap](~${componentType}.breaks.gap) 或 [${componentType}.breaks.isExpanded](~${componentType}.breaks.isExpanded) 时,`start` `end` 必须指定,且如果 `start` `end` 不修改才会有更新动画,修改了则无。 diff --git a/zh/option/component/timeline.md b/zh/option/component/timeline.md index e03b98e4f..e0ebe91e4 100644 --- a/zh/option/component/timeline.md +++ b/zh/option/component/timeline.md @@ -887,7 +887,10 @@ const option = { #${prefix} formatter(string|Function) = null -{{ use: axis-common-formatter-desc() }} +{{ use: axis-common-formatter-desc( + componentType = ${componentType}, + axisTypeProp = 'axisType' +) }} {{ if: ${state} }} {{ use: partial-text-style( diff --git a/zh/option/option.md b/zh/option/option.md index 770482807..685adc7b5 100644 --- a/zh/option/option.md +++ b/zh/option/option.md @@ -164,6 +164,12 @@ ECharts 2 里是底层强制使用单独的层绘制高亮图形,但是会带 注意,这个参数实际影响的是『展示』,而非用户输入的时间值的解析。 关于用户输入的时间值(例如 `1491339540396`, `'2013-01-04'` 等)的解析,参见 [date 中时间相关部分](~series-line.data)。 +注意,如果设置了 `useUTC: true`,并且使用了帮助函数 `echarts.time.format`(或者其他第三方类似函数),它同样要设置成按照 UTC 运作。例如, +```ts +// 第三个参数 `true` 表示,按照 UTC 来解释时间。 +const timeStrUTC = echarts.time.format(value, '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}', true); +``` + {{import: partial-rich-inherit-plain-label }} diff --git a/zh/option/partial/version.md b/zh/option/partial/version.md index 8f2d72e37..fbcd0fe5b 100644 --- a/zh/option/partial/version.md +++ b/zh/option/partial/version.md @@ -1,7 +1,10 @@ {{ target: partial-version }} + +
{{ if: ${deprecated} }} -> 从 `v${version}` 开始不推荐使用(deprecated)。${deprecated} +从 `v${version}` 开始不推荐使用(deprecated)。${deprecated} {{ else }} -> 从 `v${version}` 开始支持 +从 `v${version}` 开始支持 {{ /if }} +