From 4c7d9a4ab57e6da1a7ce89d494ab73a1a7cc1883 Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 5 Jan 2022 17:54:03 +0800 Subject: [PATCH 1/3] feat(tooltip): add valueFormatter --- src/component/tooltip/TooltipView.ts | 24 +- src/component/tooltip/tooltipMarkup.ts | 320 +++++++++++-------------- src/model/mixin/dataFormat.ts | 13 +- src/util/types.ts | 7 + test/tooltip-valueFormatter.html | 96 ++++++++ 5 files changed, 266 insertions(+), 194 deletions(-) create mode 100644 test/tooltip-valueFormatter.html diff --git a/src/component/tooltip/TooltipView.ts b/src/component/tooltip/TooltipView.ts index bc1e3a7124..fc69ecff50 100644 --- a/src/component/tooltip/TooltipView.ts +++ b/src/component/tooltip/TooltipView.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { bind, each, clone, trim, isString, isFunction, isArray, isObject } from 'zrender/src/core/util'; +import { bind, each, clone, trim, isString, isFunction, isArray, isObject, extend } from 'zrender/src/core/util'; import env from 'zrender/src/core/env'; import TooltipHTMLContent from './TooltipHTMLContent'; import TooltipRichContent from './TooltipRichContent'; @@ -585,11 +585,16 @@ class TooltipView extends ComponentView { const seriesTooltipResult = normalizeTooltipFormatResult( series.formatTooltip(dataIndex, true, null) ); - if (seriesTooltipResult.markupFragment) { - axisSectionMarkup.blocks.push(seriesTooltipResult.markupFragment); + const frag = seriesTooltipResult.frag; + if (frag) { + const valueFormatter = buildTooltipModel( + [series as Model], + globalTooltipModel + ).get('valueFormatter'); + axisSectionMarkup.blocks.push(valueFormatter ? extend({ valueFormatter }, frag) : frag); } - if (seriesTooltipResult.markupText) { - markupTextArrLegacy.push(seriesTooltipResult.markupText); + if (seriesTooltipResult.text) { + markupTextArrLegacy.push(seriesTooltipResult.text); } cbParamsList.push(cbParams); }); @@ -682,16 +687,17 @@ class TooltipView extends ComponentView { dataModel.formatTooltip(dataIndex, false, dataType) ); const orderMode = tooltipModel.get('order'); - const markupText = seriesTooltipResult.markupFragment - ? buildTooltipMarkup( - seriesTooltipResult.markupFragment, + const valueFormatter = tooltipModel.get('valueFormatter'); + const frag = seriesTooltipResult.frag; + const markupText = frag ? buildTooltipMarkup( + valueFormatter ? extend({ valueFormatter }, frag) : frag, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), tooltipModel.get('textStyle') ) - : seriesTooltipResult.markupText; + : seriesTooltipResult.text; const asyncTicket = 'item_' + dataModel.name + '_' + dataIndex; diff --git a/src/component/tooltip/tooltipMarkup.ts b/src/component/tooltip/tooltipMarkup.ts index 2e88c1df30..03aeab0653 100644 --- a/src/component/tooltip/tooltipMarkup.ts +++ b/src/component/tooltip/tooltipMarkup.ts @@ -19,7 +19,7 @@ import { Dictionary, TooltipRenderMode, ColorString, - TooltipOrderMode, DimensionType + TooltipOrderMode, DimensionType, CommonTooltipOption, OptionDataValue } from '../../util/types'; import { TooltipMarkerType, getTooltipMarker, encodeHTML, @@ -88,8 +88,8 @@ function getTooltipTextStyle( type GapLevel = number; // See `TooltipMarkupLayoutIntent['innerGapLevel']`. // (value from UI design) -const HTML_GAPS: { [key in GapLevel]: number } = [0, 10, 20, 30]; -const RICH_TEXT_GAPS: { [key in GapLevel]: string } = ['', '\n', '\n\n', '\n\n\n']; +const HTML_GAPS: Record = [0, 10, 20, 30]; +const RICH_TEXT_GAPS: Record = ['', '\n', '\n\n', '\n\n\n']; /** * This is an abstract layer to insulate the upper usage of tooltip content @@ -128,7 +128,6 @@ export type TooltipMarkupBlockFragment = interface TooltipMarkupBlock { // Use to make comparison when `sortBlocks: true`. sortParam?: unknown; - __gapLevelBetweenSubBlocks?: number; } export interface TooltipMarkupSection extends TooltipMarkupBlock { @@ -141,6 +140,8 @@ export interface TooltipMarkupSection extends TooltipMarkupBlock { blocks?: TooltipMarkupBlockFragment[]; // Enable to sort blocks when making final html or richText. sortBlocks?: boolean; + + valueFormatter?: CommonTooltipOption['valueFormatter'] } export interface TooltipMarkupNameValueBlock extends TooltipMarkupBlock { @@ -161,6 +162,8 @@ export interface TooltipMarkupNameValueBlock extends TooltipMarkupBlock { // null/undefined/NaN/''... (displayed as '-'). noName?: boolean; noValue?: boolean; + + valueFormatter?: CommonTooltipOption['valueFormatter'] } /** @@ -180,10 +183,7 @@ export function createTooltipMarkup(type: TooltipMarkupBlockFragment['type'], op // Can be null/undefined, which means generate nothing markup text. type MarkupText = string; interface TooltipMarkupFragmentBuilder { - planLayout( - fragment: TooltipMarkupBlockFragment - ): void; - build( + ( ctx: TooltipMarkupBuildContext, fragment: TooltipMarkupBlockFragment, topMarginForOuterGap: number, @@ -191,167 +191,51 @@ interface TooltipMarkupFragmentBuilder { ): MarkupText; } -function getBuilder(fragment: TooltipMarkupBlockFragment): TooltipMarkupFragmentBuilder { - return hasOwn(builderMap, fragment.type) && builderMap[fragment.type]; +function isSectionFragment(frag: TooltipMarkupBlockFragment): frag is TooltipMarkupSection { + return frag.type === 'section'; } -const builderMap: { [key in TooltipMarkupBlockFragment['type']]: TooltipMarkupFragmentBuilder } = { - - /** - * A `section` block is like: - * ``` - * header - * subBlock - * subBlock - * ... - * ``` - */ - section: { - planLayout: function (fragment: TooltipMarkupSection) { - const subBlockLen = fragment.blocks.length; - const thisBlockHasInnerGap = subBlockLen > 1 || (subBlockLen > 0 && !fragment.noHeader); - - let thisGapLevelBetweenSubBlocks = 0; - each(fragment.blocks, function (subBlock) { - getBuilder(subBlock).planLayout(subBlock); - const subGapLevel = subBlock.__gapLevelBetweenSubBlocks; - - // If the some of the sub-blocks have some gaps (like 10px) inside, this block - // should use a larger gap (like 20px) to distinguish those sub-blocks. - if (subGapLevel >= thisGapLevelBetweenSubBlocks) { - thisGapLevelBetweenSubBlocks = subGapLevel + ( - ( - thisBlockHasInnerGap && ( - // 0 always can not be readable gap level. - !subGapLevel - // If no header, always keep the sub gap level. Otherwise - // look weird in case `multipleSeries`. - || (subBlock.type === 'section' && !subBlock.noHeader) - ) - ) ? 1 : 0 - ); - } - }); - fragment.__gapLevelBetweenSubBlocks = thisGapLevelBetweenSubBlocks; - }, - - build( - ctx, - fragment: TooltipMarkupSection, - topMarginForOuterGap, - toolTipTextStyle - ): string { - const noHeader = fragment.noHeader; - const gaps = getGap(fragment); - - const subMarkupText = buildSubBlocks( - ctx, - fragment, - noHeader ? topMarginForOuterGap : gaps.html, - toolTipTextStyle - ); - - if (noHeader) { - return subMarkupText; - } +function getBuilder(frag: TooltipMarkupBlockFragment): TooltipMarkupFragmentBuilder { + return isSectionFragment(frag) ? buildSection : buildNameValue; +} - const displayableHeader = makeValueReadable(fragment.header, 'ordinal', ctx.useUTC); - const {nameStyle} = getTooltipTextStyle(toolTipTextStyle, ctx.renderMode); - if (ctx.renderMode === 'richText') { - return wrapInlineNameRichText(ctx, displayableHeader, nameStyle as RichTextStyle) + gaps.richText - + subMarkupText; - } - else { - return wrapBlockHTML( - `
` - + encodeHTML(displayableHeader) - + '
' - + subMarkupText, - topMarginForOuterGap +function getBlockGapLevel(frag: TooltipMarkupBlockFragment) { + if (isSectionFragment(frag)) { + let thisGapLevelBetweenSubBlocks = 0; + const subBlockLen = frag.blocks.length; + const thisBlockHasInnerGap = subBlockLen > 1 || (subBlockLen > 0 && !frag.noHeader); + each(frag.blocks, function (subBlock) { + const subGapLevel = getBlockGapLevel(subBlock); + // If the some of the sub-blocks have some gaps (like 10px) inside, this block + // should use a larger gap (like 20px) to distinguish those sub-blocks. + if (subGapLevel >= thisGapLevelBetweenSubBlocks) { + thisGapLevelBetweenSubBlocks = subGapLevel + ( + ( + thisBlockHasInnerGap && ( + // 0 always can not be readable gap level. + !subGapLevel + // If no header, always keep the sub gap level. Otherwise + // look weird in case `multipleSeries`. + || (subBlock.type === 'section' && !subBlock.noHeader) + ) + ) ? 1 : 0 ); } - } - }, - - /** - * A `nameValue` block is like: - * ``` - * marker name value - * ``` - */ - nameValue: { - planLayout: function (fragment: TooltipMarkupNameValueBlock) { - fragment.__gapLevelBetweenSubBlocks = 0; - }, - - build(ctx, fragment: TooltipMarkupNameValueBlock, topMarginForOuterGap, toolTipTextStyle) { - const renderMode = ctx.renderMode; - const noName = fragment.noName; - const noValue = fragment.noValue; - const noMarker = !fragment.markerType; - const name = fragment.name; - const value = fragment.value; - const useUTC = ctx.useUTC; - - if (noName && noValue) { - return; - } - - const markerStr = noMarker - ? '' - : ctx.markupStyleCreator.makeTooltipMarker( - fragment.markerType, - fragment.markerColor || '#333', - renderMode - ); - const readableName = noName - ? '' - : makeValueReadable(name, 'ordinal', useUTC); - const valueTypeOption = fragment.valueType; - const readableValueList = noValue - ? [] - : (isArray(value) - ? map(value, (val, idx) => makeValueReadable( - val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption, useUTC - )) - : [makeValueReadable( - value, isArray(valueTypeOption) ? valueTypeOption[0] : valueTypeOption, useUTC - )] - ); - const valueAlignRight = !noMarker || !noName; - // It little weird if only value next to marker but far from marker. - const valueCloseToMarker = !noMarker && noName; - - const {nameStyle, valueStyle} = getTooltipTextStyle(toolTipTextStyle, renderMode); - - return renderMode === 'richText' - ? ( - (noMarker ? '' : markerStr) - + (noName ? '' : wrapInlineNameRichText(ctx, readableName, nameStyle as RichTextStyle)) - // Value has commas inside, so use ' ' as delimiter for multiple values. - + (noValue ? '' : wrapInlineValueRichText( - ctx, readableValueList, valueAlignRight, valueCloseToMarker, valueStyle as RichTextStyle - )) - ) - : wrapBlockHTML( - (noMarker ? '' : markerStr) - + (noName ? '' : wrapInlineNameHTML(readableName, !noMarker, nameStyle as string)) - + (noValue ? '' : wrapInlineValueHTML( - readableValueList, valueAlignRight, valueCloseToMarker, valueStyle as string - )), - topMarginForOuterGap - ); - } + }); } -}; - + return 0; +} -function buildSubBlocks( +function buildSection( ctx: TooltipMarkupBuildContext, fragment: TooltipMarkupSection, topMarginForOuterGap: number, - tooltipTextStyle: TooltipOption['textStyle'] -): MarkupText { + toolTipTextStyle: TooltipOption['textStyle'] +) { + const noHeader = fragment.noHeader; + + const gaps = getGap(getBlockGapLevel(fragment)); + const subMarkupTextList: string[] = []; let subBlocks = fragment.blocks || []; assert(!subBlocks || isArray(subBlocks)); @@ -371,25 +255,102 @@ function buildSubBlocks( } } - const gaps = getGap(fragment); each(subBlocks, function (subBlock, idx) { - const subMarkupText = getBuilder(subBlock).build( - ctx, + const valueFormatter = fragment.valueFormatter; + const subMarkupText = getBuilder(subBlock)( + // Inherit valueFormatter + valueFormatter ? extend(extend({}, ctx), { valueFormatter }) : ctx, subBlock, idx > 0 ? gaps.html : 0, - tooltipTextStyle + toolTipTextStyle ); subMarkupText != null && subMarkupTextList.push(subMarkupText); }); - if (!subMarkupTextList.length) { + const subMarkupText = ctx.renderMode === 'richText' + ? subMarkupTextList.join(gaps.richText) + : wrapBlockHTML( + subMarkupTextList.join(''), + topMarginForOuterGap + ); + + if (noHeader) { + return subMarkupText; + } + + const displayableHeader = makeValueReadable(fragment.header, 'ordinal', ctx.useUTC); + const {nameStyle} = getTooltipTextStyle(toolTipTextStyle, ctx.renderMode); + if (ctx.renderMode === 'richText') { + return wrapInlineNameRichText(ctx, displayableHeader, nameStyle as RichTextStyle) + gaps.richText + + subMarkupText; + } + else { + return wrapBlockHTML( + `
` + + encodeHTML(displayableHeader) + + '
' + + subMarkupText, + topMarginForOuterGap + ); + } +} + +function buildNameValue( + ctx: TooltipMarkupBuildContext, + fragment: TooltipMarkupNameValueBlock, + topMarginForOuterGap: number, + toolTipTextStyle: TooltipOption['textStyle'] +) { + const renderMode = ctx.renderMode; + const noName = fragment.noName; + const noValue = fragment.noValue; + const noMarker = !fragment.markerType; + const name = fragment.name; + const useUTC = ctx.useUTC; + const valueFormatter = fragment.valueFormatter || ctx.valueFormatter || ((value) => { + value = isArray(value) ? value : [value]; + return map(value as unknown[], (val, idx) => makeValueReadable( + val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption, useUTC + )); + }); + + if (noName && noValue) { return; } - return ctx.renderMode === 'richText' - ? subMarkupTextList.join(gaps.richText) + const markerStr = noMarker + ? '' + : ctx.markupStyleCreator.makeTooltipMarker( + fragment.markerType, + fragment.markerColor || '#333', + renderMode + ); + const readableName = noName + ? '' + : makeValueReadable(name, 'ordinal', useUTC); + const valueTypeOption = fragment.valueType; + const readableValueList = noValue ? [] : valueFormatter(fragment.value as OptionDataValue); + const valueAlignRight = !noMarker || !noName; + // It little weird if only value next to marker but far from marker. + const valueCloseToMarker = !noMarker && noName; + + const {nameStyle, valueStyle} = getTooltipTextStyle(toolTipTextStyle, renderMode); + + return renderMode === 'richText' + ? ( + (noMarker ? '' : markerStr) + + (noName ? '' : wrapInlineNameRichText(ctx, readableName, nameStyle as RichTextStyle)) + // Value has commas inside, so use ' ' as delimiter for multiple values. + + (noValue ? '' : wrapInlineValueRichText( + ctx, readableValueList, valueAlignRight, valueCloseToMarker, valueStyle as RichTextStyle + )) + ) : wrapBlockHTML( - subMarkupTextList.join(''), + (noMarker ? '' : markerStr) + + (noName ? '' : wrapInlineNameHTML(readableName, !noMarker, nameStyle as string)) + + (noValue ? '' : wrapInlineValueHTML( + readableValueList, valueAlignRight, valueCloseToMarker, valueStyle as string + )), topMarginForOuterGap ); } @@ -399,6 +360,8 @@ interface TooltipMarkupBuildContext { renderMode: TooltipRenderMode; orderMode: TooltipOrderMode; markupStyleCreator: TooltipMarkupStyleCreator; + + valueFormatter: CommonTooltipOption['valueFormatter'] } /** @@ -417,25 +380,24 @@ export function buildTooltipMarkup( } const builder = getBuilder(fragment); - builder.planLayout(fragment); const ctx: TooltipMarkupBuildContext = { useUTC: useUTC, renderMode: renderMode, orderMode: orderMode, - markupStyleCreator: markupStyleCreator + markupStyleCreator: markupStyleCreator, + valueFormatter: fragment.valueFormatter }; - return builder.build(ctx, fragment, 0, toolTipTextStyle); + return builder(ctx, fragment, 0, toolTipTextStyle); } -function getGap(fragment: TooltipMarkupBlock): { +function getGap(gapLevel: number): { html: number; richText: string } { - const gapLevelBetweenSubBlocks = fragment.__gapLevelBetweenSubBlocks; return { - html: HTML_GAPS[gapLevelBetweenSubBlocks], - richText: RICH_TEXT_GAPS[gapLevelBetweenSubBlocks] + html: HTML_GAPS[gapLevel], + richText: RICH_TEXT_GAPS[gapLevel] }; } @@ -462,7 +424,7 @@ function wrapInlineNameHTML( } function wrapInlineValueHTML( - valueList: string[], + valueList: string | string[], alignRight: boolean, valueCloseToMarker: boolean, style: string @@ -470,6 +432,7 @@ function wrapInlineValueHTML( // Do not too close to marker, considering there are multiple values separated by spaces. const paddingStr = valueCloseToMarker ? '10px' : '20px'; const alignCSS = alignRight ? `float:right;margin-left:${paddingStr}` : ''; + valueList = isArray(valueList) ? valueList : [valueList]; return ( `` // Value has commas inside, so use ' ' as delimiter for multiple values. @@ -484,7 +447,7 @@ function wrapInlineNameRichText(ctx: TooltipMarkupBuildContext, name: string, st function wrapInlineValueRichText( ctx: TooltipMarkupBuildContext, - valueList: string[], + values: string | string[], alignRight: boolean, valueCloseToMarker: boolean, style: RichTextStyle @@ -493,7 +456,10 @@ function wrapInlineValueRichText( const paddingLeft = valueCloseToMarker ? 10 : 20; alignRight && styles.push({ padding: [0, 0, 0, paddingLeft], align: 'right' }); // Value has commas inside, so use ' ' as delimiter for multiple values. - return ctx.markupStyleCreator.wrapRichTextStyle(valueList.join(' '), styles); + return ctx.markupStyleCreator.wrapRichTextStyle( + isArray(values) ? values.join(' ') : values, + styles + ); } diff --git a/src/model/mixin/dataFormat.ts b/src/model/mixin/dataFormat.ts index 87cf12b613..96713541ef 100644 --- a/src/model/mixin/dataFormat.ts +++ b/src/model/mixin/dataFormat.ts @@ -220,14 +220,11 @@ type TooltipFormatResult = /** * For backward compat, normalize the return from `formatTooltip`. */ -export function normalizeTooltipFormatResult( - result: TooltipFormatResult - // markersExisting: Dictionary -): { +export function normalizeTooltipFormatResult(result: TooltipFormatResult): { // If `markupFragment` exists, `markupText` should be ignored. - markupFragment: TooltipMarkupBlockFragment; + frag: TooltipMarkupBlockFragment; // Can be `null`/`undefined`, means no tooltip. - markupText: string; + text: string; // Merged with `markersExisting`. // markers: Dictionary; } { @@ -256,8 +253,8 @@ export function normalizeTooltipFormatResult( } return { - markupText: markupText, + text: markupText, // markers: markers || markersExisting, - markupFragment: markupFragment + frag: markupFragment }; } diff --git a/src/util/types.ts b/src/util/types.ts index 95e5b5027d..893de66b07 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -1253,6 +1253,13 @@ export interface CommonTooltipOption { alwaysShowContent?: boolean formatter?: string | TooltipFormatterCallback + + /** + * Formatter of value. + * + * Will be ignored if tooltip.formatter is specified. + */ + valueFormatter?: (value: OptionDataValue | OptionDataValue[]) => string /** * Absolution pixel [x, y] array. Or relative percent string [x, y] array. * If trigger is 'item'. position can be set to 'inside' / 'top' / 'left' / 'right' / 'bottom', diff --git a/test/tooltip-valueFormatter.html b/test/tooltip-valueFormatter.html new file mode 100644 index 0000000000..3d6f9e158f --- /dev/null +++ b/test/tooltip-valueFormatter.html @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + From 6b33202fcb59d6bba885022f0d5808134ed38550 Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 5 Jan 2022 22:09:38 +0800 Subject: [PATCH 2/3] feat(valueFormatter): fix gap --- src/component/tooltip/tooltipMarkup.ts | 19 +-- test/tooltip-valueFormatter.html | 183 ++++++++++++++++++++++++- 2 files changed, 190 insertions(+), 12 deletions(-) diff --git a/src/component/tooltip/tooltipMarkup.ts b/src/component/tooltip/tooltipMarkup.ts index 03aeab0653..b893cd8c0a 100644 --- a/src/component/tooltip/tooltipMarkup.ts +++ b/src/component/tooltip/tooltipMarkup.ts @@ -201,27 +201,28 @@ function getBuilder(frag: TooltipMarkupBlockFragment): TooltipMarkupFragmentBuil function getBlockGapLevel(frag: TooltipMarkupBlockFragment) { if (isSectionFragment(frag)) { - let thisGapLevelBetweenSubBlocks = 0; + let gapLevel = 0; const subBlockLen = frag.blocks.length; - const thisBlockHasInnerGap = subBlockLen > 1 || (subBlockLen > 0 && !frag.noHeader); + const hasInnerGap = subBlockLen > 1 || (subBlockLen > 0 && !frag.noHeader); each(frag.blocks, function (subBlock) { const subGapLevel = getBlockGapLevel(subBlock); // If the some of the sub-blocks have some gaps (like 10px) inside, this block // should use a larger gap (like 20px) to distinguish those sub-blocks. - if (subGapLevel >= thisGapLevelBetweenSubBlocks) { - thisGapLevelBetweenSubBlocks = subGapLevel + ( - ( - thisBlockHasInnerGap && ( + if (subGapLevel >= gapLevel) { + gapLevel = subGapLevel + ( + +( + hasInnerGap && ( // 0 always can not be readable gap level. !subGapLevel // If no header, always keep the sub gap level. Otherwise // look weird in case `multipleSeries`. - || (subBlock.type === 'section' && !subBlock.noHeader) + || (isSectionFragment(subBlock) && !subBlock.noHeader) ) - ) ? 1 : 0 + ) ); } }); + return gapLevel; } return 0; } @@ -271,7 +272,7 @@ function buildSection( ? subMarkupTextList.join(gaps.richText) : wrapBlockHTML( subMarkupTextList.join(''), - topMarginForOuterGap + noHeader ? topMarginForOuterGap : gaps.html ); if (noHeader) { diff --git a/test/tooltip-valueFormatter.html b/test/tooltip-valueFormatter.html index 3d6f9e158f..be4f2270b9 100644 --- a/test/tooltip-valueFormatter.html +++ b/test/tooltip-valueFormatter.html @@ -38,6 +38,8 @@
+
+
@@ -77,9 +79,6 @@ 'Basic valueFormatter of item tooltip' ], option: option - // height: 300, - // buttons: [{text: 'btn-txt', onclick: function () {}}], - // recordCanvas: true, }); chart.dispatchAction({ @@ -90,7 +89,185 @@ }); + + + From cbdf73b0a4eade66558877c44011d5306f6bb4ad Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 6 Jan 2022 00:13:04 +0800 Subject: [PATCH 3/3] test(valueFormatter): add recorded user interaction --- test/runTest/actions/__meta__.json | 1 + test/runTest/actions/tooltip-valueFormatter.json | 1 + 2 files changed, 2 insertions(+) create mode 100644 test/runTest/actions/tooltip-valueFormatter.json diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index 60cd43e8c9..5a20cf80cb 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -178,6 +178,7 @@ "tooltip-link": 2, "tooltip-rich": 1, "tooltip-setOption": 2, + "tooltip-valueFormatter": 3, "tree-image": 1, "tree-legend": 1, "tree-radial": 1, diff --git a/test/runTest/actions/tooltip-valueFormatter.json b/test/runTest/actions/tooltip-valueFormatter.json new file mode 100644 index 0000000000..9c0f89f1ca --- /dev/null +++ b/test/runTest/actions/tooltip-valueFormatter.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousedown","time":512,"x":136,"y":330},{"type":"mouseup","time":519,"x":136,"y":330},{"time":520,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":875,"x":136,"y":330},{"type":"mousemove","time":1075,"x":205,"y":328},{"type":"mousemove","time":1280,"x":212,"y":328},{"type":"mousedown","time":1379,"x":212,"y":328},{"type":"mouseup","time":1392,"x":212,"y":328},{"time":1393,"delay":400,"type":"screenshot-auto"}],"scrollY":0,"scrollX":0,"timestamp":1641396552788},{"name":"Action 2","ops":[{"type":"mousedown","time":455,"x":279,"y":305},{"type":"mouseup","time":459,"x":279,"y":305},{"time":460,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1139,"x":280,"y":305},{"type":"mousemove","time":1338,"x":316,"y":305},{"type":"mousedown","time":1607,"x":316,"y":305},{"type":"mouseup","time":1611,"x":316,"y":305},{"time":1612,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1970,"x":317,"y":305},{"type":"mousemove","time":2170,"x":366,"y":360},{"type":"mousemove","time":2370,"x":370,"y":364},{"type":"mousedown","time":2606,"x":370,"y":364},{"type":"mouseup","time":2620,"x":370,"y":364},{"time":2621,"delay":400,"type":"screenshot-auto"}],"scrollY":430,"scrollX":0,"timestamp":1641396619208},{"name":"Action 3","ops":[{"type":"mousedown","time":450,"x":219,"y":375},{"type":"mouseup","time":454,"x":219,"y":375},{"time":455,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":817,"x":221,"y":375},{"type":"mousemove","time":1022,"x":412,"y":360},{"type":"mousemove","time":1226,"x":426,"y":357},{"type":"mousedown","time":1470,"x":426,"y":357},{"type":"mouseup","time":1474,"x":426,"y":357},{"time":1475,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1904,"x":427,"y":357},{"type":"mousemove","time":2123,"x":583,"y":359},{"type":"mousemove","time":2324,"x":585,"y":359},{"type":"mousedown","time":2486,"x":585,"y":359},{"type":"mouseup","time":2500,"x":585,"y":359},{"time":2501,"delay":400,"type":"screenshot-auto"}],"scrollY":774,"scrollX":0,"timestamp":1641396598613}] \ No newline at end of file