From c80384b5df2d371af9fbc09782f09465e2e6b214 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Tue, 2 Aug 2022 18:01:49 +0800 Subject: [PATCH 01/23] feat(funnel): set prop to flatten the funnel exit #14863 --- src/chart/funnel/FunnelSeries.ts | 8 +- src/chart/funnel/funnelLayout.ts | 95 +++++++----- test/funnel.html | 257 ++++++++++++++++--------------- 3 files changed, 194 insertions(+), 166 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index 152cdb37da..ba55884cee 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -19,8 +19,8 @@ import * as zrUtil from 'zrender/src/core/util'; import createSeriesDataSimply from '../helper/createSeriesDataSimply'; -import {defaultEmphasis} from '../../util/model'; -import {makeSeriesEncodeForNameBased} from '../../data/helper/sourceHelper'; +import { defaultEmphasis } from '../../util/model'; +import { makeSeriesEncodeForNameBased } from '../../data/helper/sourceHelper'; import LegendVisualProvider from '../../visual/LegendVisualProvider'; import SeriesModel from '../../model/Series'; import { @@ -45,7 +45,7 @@ import SeriesData from '../../data/SeriesData'; type FunnelLabelOption = Omit & { position?: LabelOption['position'] - | 'outer' | 'inner' | 'center' | 'rightTop' | 'rightBottom' | 'leftTop' | 'leftBottom' + | 'outer' | 'inner' | 'center' | 'rightTop' | 'rightBottom' | 'leftTop' | 'leftBottom' }; interface FunnelStatesMixin { @@ -94,6 +94,8 @@ export interface FunnelSeriesOption funnelAlign?: HorizontalAlign | VerticalAlign + exitShape?: 'rect' | 'default' + data?: (OptionDataValueNumeric | OptionDataValueNumeric[] | FunnelDataItemOption)[] } diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 4d433c1b1e..f91a5be676 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -18,7 +18,7 @@ */ import * as layout from '../../util/layout'; -import {parsePercent, linearMap} from '../../util/number'; +import { parsePercent, linearMap } from '../../util/number'; import FunnelSeriesModel, { FunnelSeriesOption, FunnelDataItemOption } from './FunnelSeries'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -28,9 +28,9 @@ import { isFunction } from 'zrender/src/core/util'; function getViewRect(seriesModel: FunnelSeriesModel, api: ExtensionAPI) { return layout.getLayoutRect( seriesModel.getBoxLayoutParams(), { - width: api.getWidth(), - height: api.getHeight() - } + width: api.getWidth(), + height: api.getHeight() + } ); } @@ -263,9 +263,9 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { parsePercent(seriesModel.get('minSize'), viewHeight), parsePercent(seriesModel.get('maxSize'), viewHeight) ] : [ - parsePercent(seriesModel.get('minSize'), viewWidth), - parsePercent(seriesModel.get('maxSize'), viewWidth) - ]; + parsePercent(seriesModel.get('minSize'), viewWidth), + parsePercent(seriesModel.get('maxSize'), viewWidth) + ]; const dataExtent = data.getDataExtent(valueDim); let min = seriesModel.get('min'); let max = seriesModel.get('max'); @@ -337,52 +337,69 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { indices = indices.reverse(); } - for (let i = 0; i < indices.length; i++) { - const idx = indices[i]; - const nextIdx = indices[i + 1]; - const itemModel = data.getItemModel(idx); + const getSideLen = function (sideLen: number | string): number { - if (orient === 'horizontal') { - let width = itemModel.get(['itemStyle', 'width']); - if (width == null) { - width = itemSize; + if (sideLen == null) { + sideLen = itemSize; + } + else { + if (orient === 'horizontal') { + sideLen = parsePercent(sideLen, viewWidth); + } else { + sideLen = parsePercent(sideLen, viewHeight); } - else { - width = parsePercent(width, viewWidth); - if (sort === 'ascending') { - width = -width; - } + + if (sort === 'ascending') { + sideLen = -sideLen; } + } + return sideLen; - const start = getLinePoints(idx, x); - const end = getLinePoints(nextIdx, x + width); + } - x += width + gap; + const exitShape = seriesModel.get('exitShape'); + const setLayoutPoints = + // The subsequent funnel shape modification will be done in this func. + // We don’t need to concern direction when we use this function to set points. + function ( + index: number, + idx: number, + nextIdx: number, + sideLen: number, + pos: number, + ): void { + const start = getLinePoints(idx, pos); + let end; + + if (index === indices.length - 1 && exitShape === 'rect') { + end = getLinePoints(idx, pos + sideLen); + } else { + end = getLinePoints(nextIdx, pos + sideLen); + } data.setItemLayout(idx, { points: start.concat(end.slice().reverse()) }); } + + for (let i = 0; i < indices.length; i++) { + const idx = indices[i]; + const nextIdx = indices[i + 1]; + const itemModel = data.getItemModel(idx); + + if (orient === 'horizontal') { + let width = getSideLen(itemModel.get(['itemStyle', 'width'])); + + setLayoutPoints(i, idx, nextIdx, width, x); + + x += width + gap; + } else { - let height = itemModel.get(['itemStyle', 'height']); - if (height == null) { - height = itemSize; - } - else { - height = parsePercent(height, viewHeight); - if (sort === 'ascending') { - height = -height; - } - } + let height = getSideLen(itemModel.get(['itemStyle', 'height'])); - const start = getLinePoints(idx, y); - const end = getLinePoints(nextIdx, y + height); + setLayoutPoints(i, idx, nextIdx, height, y); y += height + gap; - - data.setItemLayout(idx, { - points: start.concat(end.slice().reverse()) - }); } } diff --git a/test/funnel.html b/test/funnel.html index e182739966..83a7c3cffb 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -1,4 +1,3 @@ - - - - - - - - - -
- + + + - var chart = echarts.init(document.getElementById('main'), null, { + + +
+ + - - \ No newline at end of file From 4605cfca3f56585488dcda7e75692fa2ee9b2a46 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sat, 6 Aug 2022 11:41:43 +0800 Subject: [PATCH 02/23] feat(funnel): add dynamic height new prop #16445 --- src/chart/funnel/FunnelSeries.ts | 7 +- src/chart/funnel/funnelLayout.ts | 114 +++++++++++++++++++++++++++---- test/funnel.html | 19 ++++-- 3 files changed, 118 insertions(+), 22 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index ba55884cee..5c98a1906c 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -94,9 +94,11 @@ export interface FunnelSeriesOption funnelAlign?: HorizontalAlign | VerticalAlign - exitShape?: 'rect' | 'default' + exitShape?: 'rect' | 'none' data?: (OptionDataValueNumeric | OptionDataValueNumeric[] | FunnelDataItemOption)[] + + dynamicHeight?: boolean } class FunnelSeriesModel extends SeriesModel { @@ -196,7 +198,8 @@ class FunnelSeriesModel extends SeriesModel { itemStyle: { borderColor: '#212121' } - } + }, + dynamicHeight: false, }; } diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index f91a5be676..4bf5c57be0 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -250,22 +250,40 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { ecModel.eachSeriesByType('funnel', function (seriesModel: FunnelSeriesModel) { const data = seriesModel.getData(); const valueDim = data.mapDimension('value'); + const valueArr = data.mapArray(valueDim, function (val: number) { + return val; + }); const sort = seriesModel.get('sort'); const viewRect = getViewRect(seriesModel, api); const orient = seriesModel.get('orient'); + const dynamicHeight = seriesModel.get('dynamicHeight'); const viewWidth = viewRect.width; const viewHeight = viewRect.height; let indices = getSortedIndices(data, sort); let x = viewRect.x; let y = viewRect.y; - const sizeExtent = orient === 'horizontal' ? [ - parsePercent(seriesModel.get('minSize'), viewHeight), - parsePercent(seriesModel.get('maxSize'), viewHeight) - ] : [ - parsePercent(seriesModel.get('minSize'), viewWidth), - parsePercent(seriesModel.get('maxSize'), viewWidth) - ]; + let gap = seriesModel.get('gap'); + const gapSum = gap * (data.count() - 1); + let sizeExtent: Array = null; + if (dynamicHeight) { + sizeExtent = orient === 'horizontal' ? [ + parsePercent(seriesModel.get('minSize'), viewWidth - gapSum), + parsePercent(seriesModel.get('maxSize'), viewWidth - gapSum) + ] : [ + parsePercent(seriesModel.get('minSize'), viewHeight - gapSum), + parsePercent(seriesModel.get('maxSize'), viewHeight - gapSum) + ]; + } else { + sizeExtent = orient === 'horizontal' ? [ + parsePercent(seriesModel.get('minSize'), viewHeight), + parsePercent(seriesModel.get('maxSize'), viewHeight) + ] : [ + parsePercent(seriesModel.get('minSize'), viewWidth), + parsePercent(seriesModel.get('maxSize'), viewWidth) + ]; + } + const dataExtent = data.getDataExtent(valueDim); let min = seriesModel.get('min'); let max = seriesModel.get('max'); @@ -277,9 +295,13 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } const funnelAlign = seriesModel.get('funnelAlign'); - let gap = seriesModel.get('gap'); - const viewSize = orient === 'horizontal' ? viewWidth : viewHeight; - let itemSize = (viewSize - gap * (data.count() - 1)) / data.count(); + let viewSize: number; + if (dynamicHeight) { + viewSize = orient === 'vertical' ? viewWidth : viewHeight; + } else { + viewSize = orient === 'horizontal' ? viewWidth : viewHeight; + } + let itemSize = (viewSize - gapSum) / data.count(); const getLinePoints = function (idx: number, offset: number) { // End point index is data.count() and we assign it 0 @@ -324,6 +346,46 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { ]; }; + const getLinePointsInDyHeight = function (offset: number, itemSize: number) { + if (orient === 'horizontal') { + const itemHeight = itemSize; + let y0; + switch (funnelAlign) { + case 'top': + y0 = y; + break; + case 'center': + y0 = y + (viewHeight - itemHeight) / 2; + break; + case 'bottom': + y0 = y + (viewHeight - itemHeight); + break; + } + + return [ + [offset, y0], + [offset, y0 + itemHeight] + ]; + } + const itemWidth = itemSize; + let x0; + switch (funnelAlign) { + case 'left': + x0 = x; + break; + case 'center': + x0 = x + (viewWidth - itemWidth) / 2; + break; + case 'right': + x0 = x + viewWidth - itemWidth; + break; + } + return [ + [x0, offset], + [x0 + itemWidth, offset] + ]; + }; + if (sort === 'ascending') { // From bottom to top itemSize = -itemSize; @@ -337,7 +399,13 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { indices = indices.reverse(); } - const getSideLen = function (sideLen: number | string): number { + const getSideLen = function (sideLen: number | string, idx?: number): number { + if (dynamicHeight) { + // in dy height, user can't set itemHeight or itemWidth + const val = data.get(valueDim, idx) as number || 0; + sideLen = -linearMap(val, [0, valueArr.reduce((pre, cur) => pre + cur)], sizeExtent, true); + return sideLen; + } if (sideLen == null) { sideLen = itemSize; @@ -358,6 +426,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } const exitShape = seriesModel.get('exitShape'); + let resSize = sizeExtent[1]; + let maxSize = sizeExtent[1]; const setLayoutPoints = // The subsequent funnel shape modification will be done in this func. // We don’t need to concern direction when we use this function to set points. @@ -368,6 +438,24 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { sideLen: number, pos: number, ): void { + if (dynamicHeight) { + + + const start = getLinePointsInDyHeight(pos, resSize / maxSize * viewSize); + let end; + + if (index === indices.length - 1 && exitShape === 'rect') { + end = getLinePointsInDyHeight(pos + sideLen, resSize / maxSize * viewSize); + } else { + resSize += sideLen; + end = getLinePointsInDyHeight(pos + sideLen, resSize / maxSize * viewSize); + } + + data.setItemLayout(idx, { + points: start.concat(end.slice().reverse()) + }); + return; + } const start = getLinePoints(idx, pos); let end; @@ -388,14 +476,14 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const itemModel = data.getItemModel(idx); if (orient === 'horizontal') { - let width = getSideLen(itemModel.get(['itemStyle', 'width'])); + let width = getSideLen(itemModel.get(['itemStyle', 'width']), idx); setLayoutPoints(i, idx, nextIdx, width, x); x += width + gap; } else { - let height = getSideLen(itemModel.get(['itemStyle', 'height'])); + let height = getSideLen(itemModel.get(['itemStyle', 'height']), idx); setLayoutPoints(i, idx, nextIdx, height, y); diff --git a/test/funnel.html b/test/funnel.html index 83a7c3cffb..e82ee2d336 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -84,8 +84,9 @@ left: 300, right: 300, sort: 'ascending', - orient: 'horizontal', + orient: 'vertical', exitShape: 'rect', + dynamicHeight: true, label: { normal: { position: 'leftTop' @@ -98,9 +99,9 @@ { value: 80, name: '点击', - itemStyle: { - height: '10%' - }, + // itemStyle: { + // height: '10%' + // }, label: { position: 'insideLeft' } @@ -109,7 +110,7 @@ value: 100, name: '展现', itemStyle: { - height: '30%' + width: '20%' }, label: { position: 'insideRight' @@ -122,10 +123,11 @@ var config = { sort: 'ascending', - orient: 'horizontal', + orient: 'vertical', labelPosition: 'leftTop', labelLineLen: 20, exitShape: 'rect', + dynamicHeight: 'true', }; function update() { @@ -145,6 +147,7 @@ } }, exitShape: config.exitShape, + dynamicHeight: config.dynamicHeight === 'true' ? true : false, }] }); } @@ -152,7 +155,7 @@ var gui = new dat.GUI(); gui.add(config, 'sort', ['descending', 'ascending', 'none']) .onChange(update); - gui.add(config, 'orient', ['vertical', 'horizontal']) + gui.add(config, 'orient', ['vertical', 'vertical']) .onChange(update); gui.add(config, 'labelPosition', ['inside', 'center', 'insideLeft', 'insideRight', 'left', 'right', 'top', 'bottom', 'leftTop', 'leftBottom', 'rightTop', 'rightBottom']) .onChange(update); @@ -160,6 +163,8 @@ .onChange(update); gui.add(config, 'exitShape', ['rect', 'default']) .onChange(update); + gui.add(config, 'dynamicHeight', ['true', 'false']) + .onChange(update); }); From cf4166c3880cd43cd4ae797ebb4f9f7c73730f9d Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sat, 6 Aug 2022 11:56:48 +0800 Subject: [PATCH 03/23] feat(funnel): add dynamic height new prop #16445 --- src/chart/funnel/funnelLayout.ts | 6 ++++-- test/funnel.html | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 4bf5c57be0..55f572e116 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -403,7 +403,9 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { if (dynamicHeight) { // in dy height, user can't set itemHeight or itemWidth const val = data.get(valueDim, idx) as number || 0; - sideLen = -linearMap(val, [0, valueArr.reduce((pre, cur) => pre + cur)], sizeExtent, true); + sideLen = sort === 'ascending' ? + -linearMap(val, [0, valueArr.reduce((pre, cur) => pre + cur)], sizeExtent, true) : + linearMap(val, [0, valueArr.reduce((pre, cur) => pre + cur)], sizeExtent, true); return sideLen; } @@ -447,7 +449,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { if (index === indices.length - 1 && exitShape === 'rect') { end = getLinePointsInDyHeight(pos + sideLen, resSize / maxSize * viewSize); } else { - resSize += sideLen; + resSize += sort === 'ascending' ? sideLen : -sideLen; end = getLinePointsInDyHeight(pos + sideLen, resSize / maxSize * viewSize); } diff --git a/test/funnel.html b/test/funnel.html index e82ee2d336..fb5915b231 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -155,7 +155,7 @@ var gui = new dat.GUI(); gui.add(config, 'sort', ['descending', 'ascending', 'none']) .onChange(update); - gui.add(config, 'orient', ['vertical', 'vertical']) + gui.add(config, 'orient', ['vertical', 'horizontal']) .onChange(update); gui.add(config, 'labelPosition', ['inside', 'center', 'insideLeft', 'insideRight', 'left', 'right', 'top', 'bottom', 'leftTop', 'leftBottom', 'rightTop', 'rightBottom']) .onChange(update); From 5d65776d11c6361063ecb0eddb19fde0624b3a7f Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sun, 7 Aug 2022 12:31:27 +0800 Subject: [PATCH 04/23] feat(funnel): fix code styles error --- src/chart/funnel/FunnelSeries.ts | 2 +- src/chart/funnel/funnelLayout.ts | 37 +++++++++++++++++--------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index 5c98a1906c..9c6587ae07 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -199,7 +199,7 @@ class FunnelSeriesModel extends SeriesModel { borderColor: '#212121' } }, - dynamicHeight: false, + dynamicHeight: false }; } diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 55f572e116..878f8d0c03 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -274,7 +274,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { parsePercent(seriesModel.get('minSize'), viewHeight - gapSum), parsePercent(seriesModel.get('maxSize'), viewHeight - gapSum) ]; - } else { + } + else { sizeExtent = orient === 'horizontal' ? [ parsePercent(seriesModel.get('minSize'), viewHeight), parsePercent(seriesModel.get('maxSize'), viewHeight) @@ -298,7 +299,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { let viewSize: number; if (dynamicHeight) { viewSize = orient === 'vertical' ? viewWidth : viewHeight; - } else { + } + else { viewSize = orient === 'horizontal' ? viewWidth : viewHeight; } let itemSize = (viewSize - gapSum) / data.count(); @@ -399,13 +401,14 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { indices = indices.reverse(); } + const valueSum = valueArr.reduce((pre, cur) => pre + cur); + const getSideLen = function (sideLen: number | string, idx?: number): number { if (dynamicHeight) { // in dy height, user can't set itemHeight or itemWidth const val = data.get(valueDim, idx) as number || 0; - sideLen = sort === 'ascending' ? - -linearMap(val, [0, valueArr.reduce((pre, cur) => pre + cur)], sizeExtent, true) : - linearMap(val, [0, valueArr.reduce((pre, cur) => pre + cur)], sizeExtent, true); + sideLen = linearMap(val, [0, valueSum], sizeExtent, true); + sideLen = sort === 'ascending' ? -sideLen : sideLen; return sideLen; } @@ -415,7 +418,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { else { if (orient === 'horizontal') { sideLen = parsePercent(sideLen, viewWidth); - } else { + } + else { sideLen = parsePercent(sideLen, viewHeight); } @@ -424,12 +428,11 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } } return sideLen; - - } + }; const exitShape = seriesModel.get('exitShape'); let resSize = sizeExtent[1]; - let maxSize = sizeExtent[1]; + const maxSize = sizeExtent[1]; const setLayoutPoints = // The subsequent funnel shape modification will be done in this func. // We don’t need to concern direction when we use this function to set points. @@ -438,17 +441,16 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { idx: number, nextIdx: number, sideLen: number, - pos: number, + pos: number ): void { if (dynamicHeight) { - - const start = getLinePointsInDyHeight(pos, resSize / maxSize * viewSize); let end; if (index === indices.length - 1 && exitShape === 'rect') { end = getLinePointsInDyHeight(pos + sideLen, resSize / maxSize * viewSize); - } else { + } + else { resSize += sort === 'ascending' ? sideLen : -sideLen; end = getLinePointsInDyHeight(pos + sideLen, resSize / maxSize * viewSize); } @@ -463,14 +465,15 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { if (index === indices.length - 1 && exitShape === 'rect') { end = getLinePoints(idx, pos + sideLen); - } else { + } + else { end = getLinePoints(nextIdx, pos + sideLen); } data.setItemLayout(idx, { points: start.concat(end.slice().reverse()) }); - } + }; for (let i = 0; i < indices.length; i++) { const idx = indices[i]; @@ -478,14 +481,14 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const itemModel = data.getItemModel(idx); if (orient === 'horizontal') { - let width = getSideLen(itemModel.get(['itemStyle', 'width']), idx); + const width = getSideLen(itemModel.get(['itemStyle', 'width']), idx); setLayoutPoints(i, idx, nextIdx, width, x); x += width + gap; } else { - let height = getSideLen(itemModel.get(['itemStyle', 'height']), idx); + const height = getSideLen(itemModel.get(['itemStyle', 'height']), idx); setLayoutPoints(i, idx, nextIdx, height, y); From 903f00e02ec13fc05b674f4188d0fbc089d9ef4e Mon Sep 17 00:00:00 2001 From: gxd3 Date: Fri, 12 Aug 2022 18:56:08 +0800 Subject: [PATCH 05/23] feat(funnel): add exitWidth prop --- src/chart/funnel/FunnelSeries.ts | 2 ++ src/chart/funnel/funnelLayout.ts | 14 +++++++++++++- test/funnel.html | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index 9c6587ae07..f873a1bba5 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -99,6 +99,8 @@ export interface FunnelSeriesOption data?: (OptionDataValueNumeric | OptionDataValueNumeric[] | FunnelDataItemOption)[] dynamicHeight?: boolean + + exitWidth?: string } class FunnelSeriesModel extends SeriesModel { diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 878f8d0c03..1654fdf0f1 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -432,7 +432,19 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const exitShape = seriesModel.get('exitShape'); let resSize = sizeExtent[1]; - const maxSize = sizeExtent[1]; + let maxSize = sizeExtent[1]; + let exitWidth: string | number = seriesModel.get('exitWidth'); + if (exitWidth) { + const percentReg = /^\w{1,2}\.{0,}\w{0,}%$/; + if (percentReg.test(exitWidth)) { + exitWidth = parseInt(exitWidth, 10); + resSize = maxSize = 100 * maxSize / (100 - exitWidth); + } + else { + throw new Error(`the exitWidth must be in percentage format and cannot be greater than 99%, + but you set it as '${exitWidth}'`); + } + } const setLayoutPoints = // The subsequent funnel shape modification will be done in this func. // We don’t need to concern direction when we use this function to set points. diff --git a/test/funnel.html b/test/funnel.html index fb5915b231..742593690c 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -87,6 +87,7 @@ orient: 'vertical', exitShape: 'rect', dynamicHeight: true, + exitWidth: '33%', label: { normal: { position: 'leftTop' @@ -128,6 +129,7 @@ labelLineLen: 20, exitShape: 'rect', dynamicHeight: 'true', + exitWidth: 33, }; function update() { @@ -148,6 +150,7 @@ }, exitShape: config.exitShape, dynamicHeight: config.dynamicHeight === 'true' ? true : false, + exitWidth: `${config.exitWidth}%` }] }); } @@ -165,6 +168,8 @@ .onChange(update); gui.add(config, 'dynamicHeight', ['true', 'false']) .onChange(update); + gui.add(config, 'exitWidth', 0, 100) + .onChange(update); }); From a67891c0b14a2cc077451555d13e2a2b4c279a37 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sun, 14 Aug 2022 19:33:13 +0800 Subject: [PATCH 06/23] feat(funnel):add transform rate between each data --- src/chart/funnel/FunnelSeries.ts | 2 + src/chart/funnel/FunnelView.ts | 177 +++++++++++++++++++++++++++++-- src/chart/funnel/funnelLayout.ts | 80 +++++++++++++- test/funnel.html | 45 +++++++- 4 files changed, 288 insertions(+), 16 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index f873a1bba5..d7f0794dfe 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -101,6 +101,8 @@ export interface FunnelSeriesOption dynamicHeight?: boolean exitWidth?: string + + showRate?: boolean } class FunnelSeriesModel extends SeriesModel { diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index e4a922afca..ddb27d06f7 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -20,7 +20,7 @@ import * as graphic from '../../util/graphic'; import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; import ChartView from '../../view/Chart'; -import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries'; +import FunnelSeriesModel, { FunnelDataItemOption } from './FunnelSeries'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -122,10 +122,12 @@ class FunnelPiece extends graphic.Polygon { defaultOpacity: style.opacity, defaultText: data.getName(idx) }, - { normal: { - align: labelLayout.textAlign, - verticalAlign: labelLayout.verticalAlign - } } + { + normal: { + align: labelLayout.textAlign, + verticalAlign: labelLayout.verticalAlign + } + } ); polygon.setTextConfig({ @@ -167,8 +169,139 @@ class FunnelPiece extends graphic.Polygon { stroke: visualColor }); } + + ratePiece: RatePiece } +class RatePiece extends graphic.Polygon { + + constructor(data: SeriesData, idx: number) { + super(); + + const polygon = this; + const labelLine = new graphic.Polyline(); + const text = new graphic.Text(); + polygon.setTextContent(text); + this.setTextGuideLine(labelLine); + + this.updateData(data, idx, true); + } + updateData(data: SeriesData, idx: number, firstCreate?: boolean) { + const polygon = this; + const layout = data.getItemLayout(idx); + const seriesModel = data.hostModel; + let opacity: number; + if (layout.isLastPiece) { + opacity = 1 + } else { + opacity = 0.5; + } + + if (!firstCreate) { + saveOldStyle(polygon); + } + + if (layout.isLastPiece) { + polygon.useStyle(Object.assign(data.getItemVisual(idx, 'style'), { fill: 'rgba(0,0,0,0)' })); + } else { + polygon.useStyle(data.getItemVisual(idx, 'style')); + } + + if (firstCreate) { + polygon.setShape({ + points: layout.ratePoints + }); + polygon.style.opacity = 0; + graphic.initProps(polygon, { + style: { + opacity, + } + }, seriesModel, idx); + } + else { + graphic.updateProps(polygon, { + style: { + opacity + }, + shape: { + points: layout.ratePoints + } + }, seriesModel, idx); + } + this._updateLabel(data, idx); + } + _updateLabel(data: SeriesData, idx: number) { + const polygon = this; + const labelLine = this.getTextGuideLine(); + const labelText = polygon.getTextContent(); + + const seriesModel = data.hostModel; + const itemModel = data.getItemModel(idx); + const layout = data.getItemLayout(idx); + const labelLayout = layout.rateLabel; + const style = data.getItemVisual(idx, 'style'); + const visualColor = style.fill as ColorString; + + setLabelStyle( + // position will not be used in setLabelStyle + labelText, + getLabelStatesModels(itemModel), + { + labelFetcher: data.hostModel as FunnelSeriesModel, + labelDataIndex: idx, + defaultOpacity: style.opacity, + defaultText: layout.rate + }, + { + normal: { + align: labelLayout.textAlign, + verticalAlign: labelLayout.verticalAlign + } + } + ); + + polygon.setTextConfig({ + local: true, + inside: !!labelLayout.inside, + insideStroke: visualColor, + // insideFill: 'auto', + outsideFill: visualColor + }); + + const linePoints = labelLayout.linePoints; + + labelLine.setShape({ + points: linePoints + }); + + polygon.textGuideLineConfig = { + anchor: linePoints ? new graphic.Point(linePoints[0][0], linePoints[0][1]) : null + }; + + // Make sure update style on labelText after setLabelStyle. + // Because setLabelStyle will replace a new style on it. + graphic.updateProps(labelText, { + style: { + x: labelLayout.x, + y: labelLayout.y + } + }, seriesModel, idx); + + labelText.attr({ + rotation: labelLayout.rotation, + originX: labelLayout.x, + originY: labelLayout.y, + z2: 10 + }); + + setLabelLineStyle(polygon, getLabelLineStatesModels(itemModel), { + // Default use item visual color + stroke: visualColor + }); + } +} + + class FunnelView extends ChartView { static type = 'funnel' as const; type = FunnelView.type; @@ -183,6 +316,8 @@ class FunnelView extends ChartView { const group = this.group; + const showRate = seriesModel.get('showRate') && !seriesModel.get('dynamicHeight'); + data.diff(oldData) .add(function (idx) { const funnelPiece = new FunnelPiece(data, idx); @@ -190,6 +325,12 @@ class FunnelView extends ChartView { data.setItemGraphicEl(idx, funnelPiece); group.add(funnelPiece); + + if (showRate) { + const ratePiece = new RatePiece(data, idx); + group.add(ratePiece); + funnelPiece.ratePiece = ratePiece; + } }) .update(function (newIdx, oldIdx) { const piece = oldData.getItemGraphicEl(oldIdx) as FunnelPiece; @@ -198,10 +339,32 @@ class FunnelView extends ChartView { group.add(piece); data.setItemGraphicEl(newIdx, piece); + + const ratePiece = piece.ratePiece; + if (showRate) { + if (ratePiece) { + ratePiece.updateData(data, newIdx); + group.add(ratePiece); + } else { + const ratePiece = new RatePiece(data, newIdx); + group.add(ratePiece); + piece.ratePiece = ratePiece; + } + } + else { + if (ratePiece) { + graphic.removeElementWithFadeOut(ratePiece, seriesModel, oldIdx); + piece.ratePiece = null; + } + } }) .remove(function (idx) { - const piece = oldData.getItemGraphicEl(idx); + const piece = oldData.getItemGraphicEl(idx) as FunnelPiece; graphic.removeElementWithFadeOut(piece, seriesModel, idx); + if (showRate) { + const ratePiece = piece.ratePiece; + graphic.removeElementWithFadeOut(ratePiece, seriesModel, idx); + } }) .execute(); @@ -213,7 +376,7 @@ class FunnelView extends ChartView { this._data = null; } - dispose() {} + dispose() { } } diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 1654fdf0f1..ceac1e9c22 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -246,6 +246,37 @@ function labelLayout(data: SeriesData) { }); } +function rateLabelLayout(data: SeriesData) { + data.each(function (idx) { + const layout = data.getItemLayout(idx); + const points = layout.ratePoints; + + const isLabelInside = true; + + let textAlign; + let textX; + let textY; + let linePoints; + + textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4; + textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4; + textAlign = 'center'; + + linePoints = [ + [textX, textY], [textX, textY] + ]; + + layout.rateLabel = { + linePoints: linePoints, + x: textX, + y: textY, + verticalAlign: 'middle', + textAlign: textAlign, + inside: isLabelInside + }; + }); +} + export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { ecModel.eachSeriesByType('funnel', function (seriesModel: FunnelSeriesModel) { const data = seriesModel.getData(); @@ -348,7 +379,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { ]; }; - const getLinePointsInDyHeight = function (offset: number, itemSize: number) { + const getLinePointsBySize = function (offset: number, itemSize: number) { if (orient === 'horizontal') { const itemHeight = itemSize; let y0; @@ -434,6 +465,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { let resSize = sizeExtent[1]; let maxSize = sizeExtent[1]; let exitWidth: string | number = seriesModel.get('exitWidth'); + if (exitWidth) { const percentReg = /^\w{1,2}\.{0,}\w{0,}%$/; if (percentReg.test(exitWidth)) { @@ -445,6 +477,9 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { but you set it as '${exitWidth}'`); } } + + const showRate = seriesModel.get('showRate'); + let firstVal: number; const setLayoutPoints = // The subsequent funnel shape modification will be done in this func. // We don’t need to concern direction when we use this function to set points. @@ -456,15 +491,15 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { pos: number ): void { if (dynamicHeight) { - const start = getLinePointsInDyHeight(pos, resSize / maxSize * viewSize); + const start = getLinePointsBySize(pos, resSize / maxSize * viewSize); let end; if (index === indices.length - 1 && exitShape === 'rect') { - end = getLinePointsInDyHeight(pos + sideLen, resSize / maxSize * viewSize); + end = getLinePointsBySize(pos + sideLen, resSize / maxSize * viewSize); } else { resSize += sort === 'ascending' ? sideLen : -sideLen; - end = getLinePointsInDyHeight(pos + sideLen, resSize / maxSize * viewSize); + end = getLinePointsBySize(pos + sideLen, resSize / maxSize * viewSize); } data.setItemLayout(idx, { @@ -472,6 +507,40 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { }); return; } + else if (showRate) { + const dataStart = getLinePoints(idx, pos); + let dataEnd; + if (exitWidth !== undefined && index === indices.length - 1) { + const val = data.get(valueDim, idx) as number || 0; + const itemSize = linearMap(val, [min, max], sizeExtent, true); + const exitSize = itemSize * (exitWidth as number) / 100; + dataEnd = getLinePointsBySize(pos + sideLen / 2, exitSize); + } else { + dataEnd = getLinePoints(idx, pos + sideLen / 2); + } + const rateStart = getLinePoints(idx, pos + sideLen / 2); + const rateEnd = getLinePoints(nextIdx, pos + sideLen); + + const val = data.get(valueDim, idx) as number || 0; + const nextVal = data.get(valueDim, nextIdx) as number || 0; + let rate: number | string = nextVal / val; + rate = 'Rate ' + (rate * 100).toFixed(0) + '%'; + if (index === 0) { + firstVal = val; + } else if (index === indices.length - 1) { + const lastVal = val; + rate = lastVal / firstVal; + rate = 'Overall rate ' + (rate * 100).toFixed(0) + '%'; + } + + data.setItemLayout(idx, { + points: dataStart.concat(dataEnd.slice().reverse()), + ratePoints: rateStart.concat(rateEnd.slice().reverse()), + isLastPiece: index === indices.length - 1, + rate + }) + return; + } const start = getLinePoints(idx, pos); let end; @@ -509,5 +578,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } labelLayout(data); + if (showRate && !dynamicHeight) { + rateLabelLayout(data); + } }); } diff --git a/test/funnel.html b/test/funnel.html index 742593690c..b68ac614e8 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -85,9 +85,10 @@ right: 300, sort: 'ascending', orient: 'vertical', - exitShape: 'rect', - dynamicHeight: true, + exitShape: 'default', + dynamicHeight: false, exitWidth: '33%', + showRate: true, label: { normal: { position: 'leftTop' @@ -127,9 +128,15 @@ orient: 'vertical', labelPosition: 'leftTop', labelLineLen: 20, - exitShape: 'rect', - dynamicHeight: 'true', + exitShape: 'default', + dynamicHeight: 'false', exitWidth: 33, + showRate: 'true', + data1: 60, + data2: 40, + data3: 20, + data4: 80, + data5: 100 }; function update() { @@ -150,7 +157,23 @@ }, exitShape: config.exitShape, dynamicHeight: config.dynamicHeight === 'true' ? true : false, - exitWidth: `${config.exitWidth}%` + exitWidth: `${config.exitWidth}%`, + showRate: config.showRate === 'true', + data: [ + { value: config.data1, name: '访问' }, + { value: config.data2, name: '咨询' }, + { value: config.data3, name: '订单' }, + { + value: config.data4, + name: '点击', + + }, + { + value: config.data5, + name: '展现', + }, + + ] }] }); } @@ -170,6 +193,18 @@ .onChange(update); gui.add(config, 'exitWidth', 0, 100) .onChange(update); + gui.add(config, 'showRate', ['true', 'false']) + .onChange(update); + gui.add(config, 'data1', 0, 100) + .onChange(update); + gui.add(config, 'data2', 0, 100) + .onChange(update); + gui.add(config, 'data3', 0, 100) + .onChange(update); + gui.add(config, 'data4', 0, 100) + .onChange(update); + gui.add(config, 'data5', 0, 100) + .onChange(update); }); From 8703c20d0655914dc7447184d7b0340908efdabe Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sun, 14 Aug 2022 19:40:08 +0800 Subject: [PATCH 07/23] feat(funnel):add transform rate between each data --- src/chart/funnel/FunnelView.ts | 15 +++++++++------ src/chart/funnel/funnelLayout.ts | 21 +++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index ddb27d06f7..d288d253f0 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -170,7 +170,7 @@ class FunnelPiece extends graphic.Polygon { }); } - ratePiece: RatePiece + ratePiece: RatePiece; } class RatePiece extends graphic.Polygon { @@ -192,8 +192,9 @@ class RatePiece extends graphic.Polygon { const seriesModel = data.hostModel; let opacity: number; if (layout.isLastPiece) { - opacity = 1 - } else { + opacity = 1; + } + else { opacity = 0.5; } @@ -203,7 +204,8 @@ class RatePiece extends graphic.Polygon { if (layout.isLastPiece) { polygon.useStyle(Object.assign(data.getItemVisual(idx, 'style'), { fill: 'rgba(0,0,0,0)' })); - } else { + } + else { polygon.useStyle(data.getItemVisual(idx, 'style')); } @@ -214,7 +216,7 @@ class RatePiece extends graphic.Polygon { polygon.style.opacity = 0; graphic.initProps(polygon, { style: { - opacity, + opacity } }, seriesModel, idx); } @@ -345,7 +347,8 @@ class FunnelView extends ChartView { if (ratePiece) { ratePiece.updateData(data, newIdx); group.add(ratePiece); - } else { + } + else { const ratePiece = new RatePiece(data, newIdx); group.add(ratePiece); piece.ratePiece = ratePiece; diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index ceac1e9c22..e7fbd2f410 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -253,16 +253,11 @@ function rateLabelLayout(data: SeriesData) { const isLabelInside = true; - let textAlign; - let textX; - let textY; - let linePoints; - - textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4; - textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4; - textAlign = 'center'; + const textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4; + const textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4; + const textAlign = 'center'; - linePoints = [ + const linePoints = [ [textX, textY], [textX, textY] ]; @@ -515,7 +510,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const itemSize = linearMap(val, [min, max], sizeExtent, true); const exitSize = itemSize * (exitWidth as number) / 100; dataEnd = getLinePointsBySize(pos + sideLen / 2, exitSize); - } else { + } + else { dataEnd = getLinePoints(idx, pos + sideLen / 2); } const rateStart = getLinePoints(idx, pos + sideLen / 2); @@ -527,7 +523,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { rate = 'Rate ' + (rate * 100).toFixed(0) + '%'; if (index === 0) { firstVal = val; - } else if (index === indices.length - 1) { + } + else if (index === indices.length - 1) { const lastVal = val; rate = lastVal / firstVal; rate = 'Overall rate ' + (rate * 100).toFixed(0) + '%'; @@ -538,7 +535,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { ratePoints: rateStart.concat(rateEnd.slice().reverse()), isLastPiece: index === indices.length - 1, rate - }) + }); return; } const start = getLinePoints(idx, pos); From 94ad84bce76ffffe647f211f843b2ee4e2027e7a Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sat, 3 Sep 2022 15:43:51 +0800 Subject: [PATCH 08/23] feat(funnel): add dynamic size mapping mode --- src/chart/funnel/FunnelSeries.ts | 13 +- src/chart/funnel/FunnelView.ts | 27 +-- src/chart/funnel/funnelLayout.ts | 230 +++++++++++--------- test/funnel.html | 357 ++++++++++++++++--------------- 4 files changed, 335 insertions(+), 292 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index d7f0794dfe..e73b2bb883 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -94,15 +94,17 @@ export interface FunnelSeriesOption funnelAlign?: HorizontalAlign | VerticalAlign - exitShape?: 'rect' | 'none' - data?: (OptionDataValueNumeric | OptionDataValueNumeric[] | FunnelDataItemOption)[] - dynamicHeight?: boolean - exitWidth?: string showRate?: boolean + + lastWidth?: string + + dynamicSize?: boolean + + dynamicHeight?: boolean } class FunnelSeriesModel extends SeriesModel { @@ -202,8 +204,7 @@ class FunnelSeriesModel extends SeriesModel { itemStyle: { borderColor: '#212121' } - }, - dynamicHeight: false + } }; } diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index d288d253f0..9d8cb32771 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -20,7 +20,7 @@ import * as graphic from '../../util/graphic'; import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; import ChartView from '../../view/Chart'; -import FunnelSeriesModel, { FunnelDataItemOption } from './FunnelSeries'; +import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -122,12 +122,10 @@ class FunnelPiece extends graphic.Polygon { defaultOpacity: style.opacity, defaultText: data.getName(idx) }, - { - normal: { - align: labelLayout.textAlign, - verticalAlign: labelLayout.verticalAlign - } - } + { normal: { + align: labelLayout.textAlign, + verticalAlign: labelLayout.verticalAlign + } } ); polygon.setTextConfig({ @@ -186,11 +184,13 @@ class RatePiece extends graphic.Polygon { this.updateData(data, idx, true); } + updateData(data: SeriesData, idx: number, firstCreate?: boolean) { const polygon = this; const layout = data.getItemLayout(idx); const seriesModel = data.hostModel; let opacity: number; + if (layout.isLastPiece) { opacity = 1; } @@ -232,6 +232,7 @@ class RatePiece extends graphic.Polygon { } this._updateLabel(data, idx); } + _updateLabel(data: SeriesData, idx: number) { const polygon = this; const labelLine = this.getTextGuideLine(); @@ -249,7 +250,7 @@ class RatePiece extends graphic.Polygon { labelText, getLabelStatesModels(itemModel), { - labelFetcher: data.hostModel as FunnelSeriesModel, + // labelFetcher: data.hostModel as FunnelSeriesModel, labelDataIndex: idx, defaultOpacity: style.opacity, defaultText: layout.rate @@ -303,7 +304,6 @@ class RatePiece extends graphic.Polygon { } } - class FunnelView extends ChartView { static type = 'funnel' as const; type = FunnelView.type; @@ -317,8 +317,9 @@ class FunnelView extends ChartView { const oldData = this._data; const group = this.group; - - const showRate = seriesModel.get('showRate') && !seriesModel.get('dynamicHeight'); + const dynamicHeight = seriesModel.get('dynamicHeight'); + const dynamicSize = seriesModel.get('dynamicSize'); + const showRate = seriesModel.get('showRate') && !(dynamicHeight || dynamicSize); data.diff(oldData) .add(function (idx) { @@ -342,6 +343,7 @@ class FunnelView extends ChartView { group.add(piece); data.setItemGraphicEl(newIdx, piece); + // rate funnel piece may remove in this mount func const ratePiece = piece.ratePiece; if (showRate) { if (ratePiece) { @@ -364,6 +366,7 @@ class FunnelView extends ChartView { .remove(function (idx) { const piece = oldData.getItemGraphicEl(idx) as FunnelPiece; graphic.removeElementWithFadeOut(piece, seriesModel, idx); + if (showRate) { const ratePiece = piece.ratePiece; graphic.removeElementWithFadeOut(ratePiece, seriesModel, idx); @@ -379,7 +382,7 @@ class FunnelView extends ChartView { this._data = null; } - dispose() { } + dispose() {} } diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index e7fbd2f410..0fa19bd461 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -18,7 +18,7 @@ */ import * as layout from '../../util/layout'; -import { parsePercent, linearMap } from '../../util/number'; +import {parsePercent, linearMap} from '../../util/number'; import FunnelSeriesModel, { FunnelSeriesOption, FunnelDataItemOption } from './FunnelSeries'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -28,9 +28,9 @@ import { isFunction } from 'zrender/src/core/util'; function getViewRect(seriesModel: FunnelSeriesModel, api: ExtensionAPI) { return layout.getLayoutRect( seriesModel.getBoxLayoutParams(), { - width: api.getWidth(), - height: api.getHeight() - } + width: api.getWidth(), + height: api.getHeight() + } ); } @@ -274,43 +274,48 @@ function rateLabelLayout(data: SeriesData) { export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { ecModel.eachSeriesByType('funnel', function (seriesModel: FunnelSeriesModel) { + // data about const data = seriesModel.getData(); const valueDim = data.mapDimension('value'); const valueArr = data.mapArray(valueDim, function (val: number) { return val; }); + + // direction about const sort = seriesModel.get('sort'); - const viewRect = getViewRect(seriesModel, api); const orient = seriesModel.get('orient'); - const dynamicHeight = seriesModel.get('dynamicHeight'); + + // size and pos about + const viewRect = getViewRect(seriesModel, api); const viewWidth = viewRect.width; const viewHeight = viewRect.height; - let indices = getSortedIndices(data, sort); let x = viewRect.x; let y = viewRect.y; + let indices = getSortedIndices(data, sort); + let gap = seriesModel.get('gap'); const gapSum = gap * (data.count() - 1); - let sizeExtent: Array = null; - if (dynamicHeight) { - sizeExtent = orient === 'horizontal' ? [ - parsePercent(seriesModel.get('minSize'), viewWidth - gapSum), - parsePercent(seriesModel.get('maxSize'), viewWidth - gapSum) - ] : [ - parsePercent(seriesModel.get('minSize'), viewHeight - gapSum), - parsePercent(seriesModel.get('maxSize'), viewHeight - gapSum) - ]; - } - else { - sizeExtent = orient === 'horizontal' ? [ - parsePercent(seriesModel.get('minSize'), viewHeight), - parsePercent(seriesModel.get('maxSize'), viewHeight) - ] : [ - parsePercent(seriesModel.get('minSize'), viewWidth), - parsePercent(seriesModel.get('maxSize'), viewWidth) - ]; - } + // mapping mode about + const dynamicHeight = seriesModel.get('dynamicHeight'); + const dynamicSize = seriesModel.get('dynamicSize'); + + // size extent based on orient and mapping mode + // determine the width extent of the funnel piece when dynamicHeight is false + // determine the height extent of the funnel piece when dynamicHeight if true + const isHorizontal = orient === 'horizontal'; + const size = dynamicHeight ? ( + isHorizontal ? viewWidth - gapSum : viewHeight - gapSum + ) : ( + isHorizontal ? viewHeight : viewWidth + ); + const sizeExtent = [ + parsePercent(seriesModel.get('minSize'), size), + parsePercent(seriesModel.get('maxSize'), size) + ]; + + // data extent const dataExtent = data.getDataExtent(valueDim); let min = seriesModel.get('min'); let max = seriesModel.get('max'); @@ -321,16 +326,14 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { max = dataExtent[1]; } - const funnelAlign = seriesModel.get('funnelAlign'); - let viewSize: number; - if (dynamicHeight) { - viewSize = orient === 'vertical' ? viewWidth : viewHeight; - } - else { - viewSize = orient === 'horizontal' ? viewWidth : viewHeight; - } + // determine the height of the funnel + const viewSize = dynamicHeight ? (isHorizontal ? viewHeight : viewWidth + ) : ( + isHorizontal ? viewWidth : viewHeight); let itemSize = (viewSize - gapSum) / data.count(); + const funnelAlign = seriesModel.get('funnelAlign'); + const getLinePoints = function (idx: number, offset: number) { // End point index is data.count() and we assign it 0 if (orient === 'horizontal') { @@ -375,6 +378,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { }; const getLinePointsBySize = function (offset: number, itemSize: number) { + // do not caculate line width in this func if (orient === 'horizontal') { const itemHeight = itemSize; let y0; @@ -414,67 +418,94 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { ]; }; + // adjust related param if (sort === 'ascending') { // From bottom to top itemSize = -itemSize; - gap = -gap; + const symbol = !dynamicHeight && dynamicSize ? 1 : -1; + gap = gap * symbol; if (orient === 'horizontal') { - x += viewWidth; + x += symbol === 1 ? 0 : viewWidth; } else { - y += viewHeight; + y += symbol === 1 ? 0 : viewHeight; } indices = indices.reverse(); } + else { + if (dynamicSize && !dynamicHeight) { + gap = -gap; + if (orient === 'horizontal') { + x += viewWidth; + } + else { + y += viewHeight; + } + } + } + + // dynamicSize about + const areaExtent = [0, viewHeight * viewWidth / 2]; + // auxiliary variable + let cumulativeArea = 0; + let cumulativeHeight = 0; + // piece top and bottom + let pieceAreaBottom = 0; + let pieceAreaTop = 0; const valueSum = valueArr.reduce((pre, cur) => pre + cur); - const getSideLen = function (sideLen: number | string, idx?: number): number { + const getPieceHeight = function (pieceHeight: number | string, idx?: number): number { + // get funnel piece height pass to getLinePoints func based on data value + const val = data.get(valueDim, idx) as number || 0; + if (dynamicHeight) { // in dy height, user can't set itemHeight or itemWidth - const val = data.get(valueDim, idx) as number || 0; - sideLen = linearMap(val, [0, valueSum], sizeExtent, true); - sideLen = sort === 'ascending' ? -sideLen : sideLen; - return sideLen; - } + pieceHeight = linearMap(val, [0, valueSum], [0, size], true); - if (sideLen == null) { - sideLen = itemSize; + pieceHeight = sort === 'ascending' ? -pieceHeight : pieceHeight; + return pieceHeight; } - else { - if (orient === 'horizontal') { - sideLen = parsePercent(sideLen, viewWidth); - } - else { - sideLen = parsePercent(sideLen, viewHeight); - } + else if (dynamicSize) { + // in dy size, user can't set itemHeight or itemWidth too + const pieceArea = linearMap(val, [0, valueSum], areaExtent, true); - if (sort === 'ascending') { - sideLen = -sideLen; - } - } - return sideLen; - }; + cumulativeArea += pieceArea; + pieceAreaTop = pieceAreaBottom; + + // calculate bottom line length and top line length + pieceAreaBottom = Math.sqrt(2 * cumulativeArea * size / viewSize); + pieceHeight = pieceAreaBottom * viewSize / size - cumulativeHeight; - const exitShape = seriesModel.get('exitShape'); - let resSize = sizeExtent[1]; - let maxSize = sizeExtent[1]; - let exitWidth: string | number = seriesModel.get('exitWidth'); + cumulativeHeight += pieceHeight; + pieceHeight = sort === 'ascending' ? pieceHeight : -pieceHeight; + return pieceHeight; + } - if (exitWidth) { - const percentReg = /^\w{1,2}\.{0,}\w{0,}%$/; - if (percentReg.test(exitWidth)) { - exitWidth = parseInt(exitWidth, 10); - resSize = maxSize = 100 * maxSize / (100 - exitWidth); + // default mapping + if (pieceHeight == null) { + pieceHeight = itemSize; } else { - throw new Error(`the exitWidth must be in percentage format and cannot be greater than 99%, - but you set it as '${exitWidth}'`); + pieceHeight = parsePercent(pieceHeight, orient === 'horizontal' ? viewWidth : viewHeight); + pieceHeight = sort === 'ascending' ? -pieceHeight : pieceHeight; } - } + return pieceHeight; + }; + + // dy height funnel size about + const lastWidth = parsePercent(seriesModel.get('lastWidth'), 100); + lastWidth >= 100 && console.warn('lastWidth shouldn\'t be greater than or equal to 100'); + const maxSize = lastWidth < 100 ? sizeExtent[1] * 100 / (100 - lastWidth) : sizeExtent[1]; + let resSize = maxSize; + // rate funnel about const showRate = seriesModel.get('showRate'); let firstVal: number; + + // exit shape control + const exitWidth = parsePercent(seriesModel.get('exitWidth'), 100); + const setLayoutPoints = // The subsequent funnel shape modification will be done in this func. // We don’t need to concern direction when we use this function to set points. @@ -482,20 +513,25 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { index: number, idx: number, nextIdx: number, - sideLen: number, + pieceHeight: number, pos: number ): void { if (dynamicHeight) { const start = getLinePointsBySize(pos, resSize / maxSize * viewSize); - let end; + index === indices.length - 1 && exitWidth === 100 + || ( + resSize += sort === 'ascending' ? pieceHeight : -pieceHeight + ); + const end = getLinePointsBySize(pos + pieceHeight, resSize / maxSize * viewSize); - if (index === indices.length - 1 && exitShape === 'rect') { - end = getLinePointsBySize(pos + sideLen, resSize / maxSize * viewSize); - } - else { - resSize += sort === 'ascending' ? sideLen : -sideLen; - end = getLinePointsBySize(pos + sideLen, resSize / maxSize * viewSize); - } + data.setItemLayout(idx, { + points: start.concat(end.slice().reverse()) + }); + return; + } + else if (dynamicSize) { + const start = getLinePointsBySize(pos, pieceAreaTop); + const end = getLinePointsBySize(pos + pieceHeight, pieceAreaBottom); data.setItemLayout(idx, { points: start.concat(end.slice().reverse()) @@ -503,21 +539,24 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { return; } else if (showRate) { + // data piece const dataStart = getLinePoints(idx, pos); let dataEnd; + const val = data.get(valueDim, idx) as number || 0; if (exitWidth !== undefined && index === indices.length - 1) { - const val = data.get(valueDim, idx) as number || 0; const itemSize = linearMap(val, [min, max], sizeExtent, true); - const exitSize = itemSize * (exitWidth as number) / 100; - dataEnd = getLinePointsBySize(pos + sideLen / 2, exitSize); + const exitSize = itemSize * exitWidth / 100; + dataEnd = getLinePointsBySize(pos + pieceHeight / 2, exitSize); } else { - dataEnd = getLinePoints(idx, pos + sideLen / 2); + dataEnd = getLinePoints(idx, pos + pieceHeight / 2); } - const rateStart = getLinePoints(idx, pos + sideLen / 2); - const rateEnd = getLinePoints(nextIdx, pos + sideLen); - const val = data.get(valueDim, idx) as number || 0; + // rate piece + const rateStart = getLinePoints(idx, pos + pieceHeight / 2); + const rateEnd = getLinePoints(nextIdx, pos + pieceHeight); + + // rate label text about const nextVal = data.get(valueDim, nextIdx) as number || 0; let rate: number | string = nextVal / val; rate = 'Rate ' + (rate * 100).toFixed(0) + '%'; @@ -538,15 +577,12 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { }); return; } - const start = getLinePoints(idx, pos); - let end; - if (index === indices.length - 1 && exitShape === 'rect') { - end = getLinePoints(idx, pos + sideLen); - } - else { - end = getLinePoints(nextIdx, pos + sideLen); - } + const start = getLinePoints(idx, pos); + const end = getLinePoints( + index === indices.length - 1 && exitWidth === 100 ? idx : nextIdx, + pos + pieceHeight + ); data.setItemLayout(idx, { points: start.concat(end.slice().reverse()) @@ -559,14 +595,14 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const itemModel = data.getItemModel(idx); if (orient === 'horizontal') { - const width = getSideLen(itemModel.get(['itemStyle', 'width']), idx); + const width = getPieceHeight(itemModel.get(['itemStyle', 'width']), idx); setLayoutPoints(i, idx, nextIdx, width, x); x += width + gap; } else { - const height = getSideLen(itemModel.get(['itemStyle', 'height']), idx); + const height = getPieceHeight(itemModel.get(['itemStyle', 'height']), idx); setLayoutPoints(i, idx, nextIdx, height, y); @@ -575,7 +611,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } labelLayout(data); - if (showRate && !dynamicHeight) { + if (showRate && !dynamicHeight && !dynamicSize) { rateLabelLayout(data); } }); diff --git a/test/funnel.html b/test/funnel.html index b68ac614e8..94a068b055 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -18,196 +18,199 @@ --> + + + + + + + + +
+ - - - - - - -
- - + + \ No newline at end of file From 4e0842e8527d4896d5b6b5118c7ef121c40cd857 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sat, 3 Sep 2022 15:51:39 +0800 Subject: [PATCH 09/23] feat(funnel): fix funnel code style --- src/chart/funnel/FunnelSeries.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index e73b2bb883..ff6c713e0e 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -19,8 +19,8 @@ import * as zrUtil from 'zrender/src/core/util'; import createSeriesDataSimply from '../helper/createSeriesDataSimply'; -import { defaultEmphasis } from '../../util/model'; -import { makeSeriesEncodeForNameBased } from '../../data/helper/sourceHelper'; +import {defaultEmphasis} from '../../util/model'; +import {makeSeriesEncodeForNameBased} from '../../data/helper/sourceHelper'; import LegendVisualProvider from '../../visual/LegendVisualProvider'; import SeriesModel from '../../model/Series'; import { @@ -45,7 +45,7 @@ import SeriesData from '../../data/SeriesData'; type FunnelLabelOption = Omit & { position?: LabelOption['position'] - | 'outer' | 'inner' | 'center' | 'rightTop' | 'rightBottom' | 'leftTop' | 'leftBottom' + | 'outer' | 'inner' | 'center' | 'rightTop' | 'rightBottom' | 'leftTop' | 'leftBottom' }; interface FunnelStatesMixin { From fa55aca4eb7a08c3f26d28a9f8cb9993e4ecf7f3 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Mon, 5 Sep 2022 13:39:24 +0800 Subject: [PATCH 10/23] feat(funnel): change lastWidth as thickDegree which mean dynamicHeight funnel thick --- src/chart/funnel/FunnelSeries.ts | 2 +- src/chart/funnel/funnelLayout.ts | 6 +++--- test/funnel.html | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index ff6c713e0e..b917a89ebb 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -100,7 +100,7 @@ export interface FunnelSeriesOption showRate?: boolean - lastWidth?: string + thickDegree?: string dynamicSize?: boolean diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 0fa19bd461..bff9e4bf65 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -494,9 +494,9 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { }; // dy height funnel size about - const lastWidth = parsePercent(seriesModel.get('lastWidth'), 100); - lastWidth >= 100 && console.warn('lastWidth shouldn\'t be greater than or equal to 100'); - const maxSize = lastWidth < 100 ? sizeExtent[1] * 100 / (100 - lastWidth) : sizeExtent[1]; + const thickDegree = parsePercent(seriesModel.get('thickDegree'), 100); + thickDegree >= 100 && console.warn('thickDegree shouldn\'t be greater than or equal to 100'); + const maxSize = thickDegree < 100 ? sizeExtent[1] * 100 / (100 - thickDegree) : sizeExtent[1]; let resSize = maxSize; // rate funnel about diff --git a/test/funnel.html b/test/funnel.html index 94a068b055..bef36a3ae2 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -85,7 +85,7 @@ dynamicHeight:false, dynamicSize:true, exitWidth: '33%', - lastWidth: '33%', + thickDegree: '33%', showRate: true, label: { normal: { @@ -130,7 +130,7 @@ dynamicHeight: 'false', dynamicSize: 'true', exitWidth: 33, - lastWidth: 33, + thickDegree: 33, showRate: 'true', data1: 60, data2: 40, @@ -158,7 +158,7 @@ dynamicHeight: config.dynamicHeight === 'true', dynamicSize: config.dynamicSize ==='true', exitWidth: `${config.exitWidth}%`, - lastWidth: `${config.lastWidth}%`, + thickDegree: `${config.thickDegree}%`, showRate: config.showRate === 'true', data: [ { value: config.data1, name: '访问' }, @@ -194,7 +194,7 @@ .onChange(update); gui.add(config, 'exitWidth', 0, 100) .onChange(update); - gui.add(config, 'lastWidth', 0, 100) + gui.add(config, 'thickDegree', 0, 100) .onChange(update); gui.add(config, 'showRate', ['true', 'false']) .onChange(update); From 5aaf7b45cbe7118b9a5ac8f1b0eda17e0b7335c1 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Mon, 5 Sep 2022 13:53:13 +0800 Subject: [PATCH 11/23] feat(funnel): fix the bug thay exit width can greater than 100% --- src/chart/funnel/funnelLayout.ts | 2 +- test/funnel.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index bff9e4bf65..dafbb64443 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -545,7 +545,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const val = data.get(valueDim, idx) as number || 0; if (exitWidth !== undefined && index === indices.length - 1) { const itemSize = linearMap(val, [min, max], sizeExtent, true); - const exitSize = itemSize * exitWidth / 100; + const exitSize = itemSize * (exitWidth > 100 ? 100 : exitWidth) / 100; dataEnd = getLinePointsBySize(pos + pieceHeight / 2, exitSize); } else { diff --git a/test/funnel.html b/test/funnel.html index bef36a3ae2..e92fa20066 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -192,7 +192,7 @@ .onChange(update); gui.add(config, 'dynamicSize', ['true', 'false']) .onChange(update); - gui.add(config, 'exitWidth', 0, 100) + gui.add(config, 'exitWidth', 0, 200) .onChange(update); gui.add(config, 'thickDegree', 0, 100) .onChange(update); From 18a0dea340fefa005ccc948fba5e2b1fef2016a7 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Tue, 6 Sep 2022 11:13:46 +0800 Subject: [PATCH 12/23] feat(funnel):add auto test, and change dynamciSize into dynamciArea --- src/chart/funnel/FunnelSeries.ts | 2 +- src/chart/funnel/FunnelView.ts | 4 +- src/chart/funnel/funnelLayout.ts | 14 +- test/funnel.html | 300 +++++++++++++++++++++++-------- 4 files changed, 235 insertions(+), 85 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index b917a89ebb..b8069aedd7 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -102,7 +102,7 @@ export interface FunnelSeriesOption thickDegree?: string - dynamicSize?: boolean + dynamicArea?: boolean dynamicHeight?: boolean } diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index 9d8cb32771..ccfaefed1f 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -318,8 +318,8 @@ class FunnelView extends ChartView { const group = this.group; const dynamicHeight = seriesModel.get('dynamicHeight'); - const dynamicSize = seriesModel.get('dynamicSize'); - const showRate = seriesModel.get('showRate') && !(dynamicHeight || dynamicSize); + const dynamicArea = seriesModel.get('dynamicArea'); + const showRate = seriesModel.get('showRate') && !(dynamicHeight || dynamicArea); data.diff(oldData) .add(function (idx) { diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index dafbb64443..17aed7517c 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -299,7 +299,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { // mapping mode about const dynamicHeight = seriesModel.get('dynamicHeight'); - const dynamicSize = seriesModel.get('dynamicSize'); + const dynamicArea = seriesModel.get('dynamicArea'); // size extent based on orient and mapping mode // determine the width extent of the funnel piece when dynamicHeight is false @@ -422,7 +422,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { if (sort === 'ascending') { // From bottom to top itemSize = -itemSize; - const symbol = !dynamicHeight && dynamicSize ? 1 : -1; + const symbol = !dynamicHeight && dynamicArea ? 1 : -1; gap = gap * symbol; if (orient === 'horizontal') { x += symbol === 1 ? 0 : viewWidth; @@ -433,7 +433,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { indices = indices.reverse(); } else { - if (dynamicSize && !dynamicHeight) { + if (dynamicArea && !dynamicHeight) { gap = -gap; if (orient === 'horizontal') { x += viewWidth; @@ -444,7 +444,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } } - // dynamicSize about + // dynamicArea about const areaExtent = [0, viewHeight * viewWidth / 2]; // auxiliary variable let cumulativeArea = 0; @@ -466,7 +466,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { pieceHeight = sort === 'ascending' ? -pieceHeight : pieceHeight; return pieceHeight; } - else if (dynamicSize) { + else if (dynamicArea) { // in dy size, user can't set itemHeight or itemWidth too const pieceArea = linearMap(val, [0, valueSum], areaExtent, true); @@ -529,7 +529,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { }); return; } - else if (dynamicSize) { + else if (dynamicArea) { const start = getLinePointsBySize(pos, pieceAreaTop); const end = getLinePointsBySize(pos + pieceHeight, pieceAreaBottom); @@ -611,7 +611,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } labelLayout(data); - if (showRate && !dynamicHeight && !dynamicSize) { + if (showRate && !dynamicHeight && !dynamicArea) { rateLabelLayout(data); } }); diff --git a/test/funnel.html b/test/funnel.html index e92fa20066..ada76aac74 100644 --- a/test/funnel.html +++ b/test/funnel.html @@ -1,3 +1,5 @@ + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + \ No newline at end of file From fe14b3ba7bba6f9fd52c255cdf73b18860cc4e21 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Fri, 21 Oct 2022 11:38:14 +0800 Subject: [PATCH 16/23] feat(funnel): use formatter to set rate label text --- src/chart/funnel/FunnelSeries.ts | 6 +++--- src/chart/funnel/FunnelView.ts | 6 +++--- src/chart/funnel/funnelLayout.ts | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index b6649ee578..a73503687b 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -19,8 +19,8 @@ import * as zrUtil from 'zrender/src/core/util'; import createSeriesDataSimply from '../helper/createSeriesDataSimply'; -import { defaultEmphasis } from '../../util/model'; -import { makeSeriesEncodeForNameBased } from '../../data/helper/sourceHelper'; +import {defaultEmphasis} from '../../util/model'; +import {makeSeriesEncodeForNameBased} from '../../data/helper/sourceHelper'; import LegendVisualProvider from '../../visual/LegendVisualProvider'; import SeriesModel from '../../model/Series'; import { @@ -45,7 +45,7 @@ import SeriesData from '../../data/SeriesData'; type FunnelLabelOption = Omit & { position?: LabelOption['position'] - | 'outer' | 'inner' | 'center' | 'rightTop' | 'rightBottom' | 'leftTop' | 'leftBottom' + | 'outer' | 'inner' | 'center' | 'rightTop' | 'rightBottom' | 'leftTop' | 'leftBottom' }; interface FunnelStatesMixin { diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index 8e8efaea52..6f3a7d8edf 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -20,7 +20,7 @@ import * as zrUtil from 'zrender/src/core/util'; import * as graphic from '../../util/graphic'; import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; import ChartView from '../../view/Chart'; -import FunnelSeriesModel, { FunnelDataItemOption } from './FunnelSeries'; +import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -129,7 +129,7 @@ const rateLabelFetcher = { class FunnelPiece extends graphic.Polygon { /** - * @param type judge is data blocks and conversion blocks + * @param type judge is data blocks or conversion blocks */ constructor(data: SeriesData, idx: number, type: 'data' | 'rate') { @@ -375,7 +375,7 @@ class FunnelView extends ChartView { this._data = null; } - dispose() { } + dispose() {} } diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 3f5bc9ce57..c0bf14e737 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -18,7 +18,7 @@ */ import * as layout from '../../util/layout'; -import { parsePercent, linearMap } from '../../util/number'; +import {parsePercent, linearMap} from '../../util/number'; import FunnelSeriesModel, { FunnelSeriesOption, FunnelDataItemOption } from './FunnelSeries'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -28,9 +28,9 @@ import { isFunction } from 'zrender/src/core/util'; function getViewRect(seriesModel: FunnelSeriesModel, api: ExtensionAPI) { return layout.getLayoutRect( seriesModel.getBoxLayoutParams(), { - width: api.getWidth(), - height: api.getHeight() - } + width: api.getWidth(), + height: api.getHeight() + } ); } From 646736cb5e5612a2ba336a435022da1331d5875f Mon Sep 17 00:00:00 2001 From: gxd3 Date: Fri, 21 Oct 2022 16:48:18 +0800 Subject: [PATCH 17/23] feat(funnel): run test visual of funnel new feat --- test/funnel1.html | 8 ++++---- test/runTest/actions/__meta__.json | 1 + test/runTest/actions/funnel1.json | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 test/runTest/actions/funnel1.json diff --git a/test/funnel1.html b/test/funnel1.html index af488ef182..aecdef5e1f 100644 --- a/test/funnel1.html +++ b/test/funnel1.html @@ -81,7 +81,7 @@ left: 300, right: 300, sort: 'ascending', - orient: 'horizontal', + orient: 'vertical', label: { normal: { position: 'leftTop' @@ -119,7 +119,7 @@ const config = { sort: 'ascending', - orient: 'horizontal', + orient: 'vertical', dynamicHeight: 'true', exitWidth: 0, maxSize: 100, @@ -179,7 +179,7 @@ const config = { sort: 'ascending', - orient: 'horizontal', + orient: 'vertical', showRate: 'true', exitWidth: 100, }; @@ -228,7 +228,7 @@ const config = { sort: 'ascending', - orient: 'horizontal', + orient: 'vertical', dynamicArea: 'true', }; diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index c08e7ae77e..b17568d29c 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -89,6 +89,7 @@ "emphasis-disabled": 13, "emphasis-inherit": 1, "funnel": 2, + "funnel1": 3, "gauge-simple": 2, "geo-map": 4, "geo-map-features": 3, diff --git a/test/runTest/actions/funnel1.json b/test/runTest/actions/funnel1.json new file mode 100644 index 0000000000..d6ec798efe --- /dev/null +++ b/test/runTest/actions/funnel1.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousemove","time":217,"x":778,"y":151},{"type":"mousemove","time":420,"x":720,"y":49},{"type":"mousemove","time":634,"x":709,"y":23},{"type":"mousemove","time":839,"x":706,"y":15},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":1926,"target":"select"},{"type":"mousemove","time":1935,"x":712,"y":6},{"type":"mousemove","time":2143,"x":711,"y":9},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string>div>div.c>select","value":"none","time":2988,"target":"select"},{"type":"mousemove","time":3005,"x":708,"y":19},{"type":"mousemove","time":3212,"x":706,"y":11},{"type":"mousemove","time":3432,"x":706,"y":10},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string>div>div.c>select","value":"ascending","time":4796,"target":"select"},{"type":"mousemove","time":4805,"x":694,"y":31},{"type":"mousemove","time":5032,"x":691,"y":38},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":5911,"target":"select"},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":7106,"target":"select"},{"type":"mousemove","time":7240,"x":674,"y":76},{"type":"mousemove","time":7447,"x":675,"y":70},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"false","time":8212,"target":"select"},{"type":"mousemove","time":8222,"x":670,"y":97},{"type":"mousemove","time":8422,"x":666,"y":97},{"type":"mousedown","time":8605,"x":700,"y":96},{"type":"mousemove","time":8644,"x":700,"y":95},{"type":"mouseup","time":8698,"x":705,"y":94},{"type":"mousemove","time":8848,"x":733,"y":94},{"type":"mousedown","time":9052,"x":734,"y":92},{"type":"mousemove","time":9099,"x":734,"y":92},{"type":"mouseup","time":9144,"x":735,"y":91},{"type":"mousemove","time":9338,"x":743,"y":91},{"type":"mousemove","time":9451,"x":742,"y":91},{"type":"mousedown","time":9523,"x":742,"y":91},{"type":"mouseup","time":9588,"x":742,"y":91},{"type":"mousemove","time":9675,"x":742,"y":91},{"type":"mousemove","time":9875,"x":746,"y":93},{"type":"mousedown","time":10027,"x":746,"y":94},{"type":"mouseup","time":10078,"x":746,"y":94},{"type":"mousemove","time":10140,"x":746,"y":94},{"type":"mousemove","time":10148,"x":745,"y":94},{"type":"mousemove","time":10350,"x":737,"y":91},{"type":"mousedown","time":10367,"x":737,"y":91},{"type":"mouseup","time":10499,"x":742,"y":93},{"type":"mousemove","time":10588,"x":743,"y":93},{"type":"mousemove","time":10793,"x":745,"y":96},{"type":"mousedown","time":10853,"x":745,"y":96},{"type":"mouseup","time":10956,"x":746,"y":96},{"type":"mousemove","time":11000,"x":746,"y":96},{"type":"mousemove","time":11219,"x":736,"y":91},{"type":"mousedown","time":11254,"x":737,"y":92},{"type":"mouseup","time":11416,"x":744,"y":95},{"type":"mousemove","time":11426,"x":746,"y":95},{"type":"mousemove","time":11647,"x":744,"y":98},{"type":"mousemove","time":11850,"x":698,"y":96},{"type":"mousemove","time":12052,"x":661,"y":94},{"type":"mousemove","time":12260,"x":653,"y":94},{"type":"mousedown","time":12391,"x":651,"y":94},{"type":"mousemove","time":12460,"x":651,"y":94},{"type":"mouseup","time":12492,"x":651,"y":94},{"type":"mousemove","time":12693,"x":651,"y":98},{"type":"mousemove","time":12894,"x":665,"y":141},{"type":"mousemove","time":13103,"x":689,"y":131},{"type":"mousedown","time":13142,"x":689,"y":131},{"type":"mouseup","time":13257,"x":695,"y":131},{"type":"mousemove","time":13394,"x":740,"y":130},{"type":"mousedown","time":13592,"x":741,"y":124},{"type":"mousemove","time":13663,"x":741,"y":124},{"type":"mouseup","time":13677,"x":741,"y":124},{"type":"mousemove","time":13866,"x":738,"y":130},{"type":"mousemove","time":14071,"x":676,"y":124},{"type":"mousemove","time":14277,"x":667,"y":127},{"type":"mousedown","time":14391,"x":663,"y":125},{"type":"mouseup","time":14461,"x":663,"y":125},{"type":"mousemove","time":14488,"x":663,"y":125},{"type":"mousemove","time":14695,"x":655,"y":127},{"type":"mousemove","time":14913,"x":645,"y":125},{"type":"mousedown","time":15024,"x":645,"y":125},{"type":"mouseup","time":15127,"x":645,"y":125},{"type":"mousemove","time":15179,"x":645,"y":124},{"type":"mousemove","time":15385,"x":651,"y":126},{"type":"mousedown","time":15405,"x":651,"y":126},{"type":"mouseup","time":15489,"x":651,"y":126},{"type":"mousemove","time":15695,"x":652,"y":126},{"type":"mousemove","time":15896,"x":702,"y":118},{"type":"mousedown","time":15960,"x":702,"y":118},{"type":"mouseup","time":16040,"x":702,"y":118},{"type":"mousemove","time":16096,"x":711,"y":120},{"type":"mousemove","time":16297,"x":734,"y":121},{"type":"mousedown","time":16441,"x":735,"y":121},{"type":"mouseup","time":16505,"x":735,"y":121},{"type":"mousemove","time":16523,"x":735,"y":121},{"type":"mousemove","time":16556,"x":735,"y":121},{"type":"mousemove","time":16757,"x":740,"y":123},{"type":"mousemove","time":16963,"x":729,"y":128},{"type":"mousemove","time":17170,"x":702,"y":163},{"type":"mousemove","time":17388,"x":668,"y":152},{"type":"mousedown","time":17407,"x":668,"y":152},{"type":"mouseup","time":17494,"x":668,"y":152},{"type":"mousemove","time":17599,"x":675,"y":154},{"type":"mousemove","time":17806,"x":694,"y":148},{"type":"mousedown","time":17821,"x":694,"y":148},{"type":"mouseup","time":17892,"x":694,"y":148},{"type":"mousemove","time":18013,"x":703,"y":150},{"type":"mousemove","time":18233,"x":691,"y":151},{"type":"mousedown","time":18436,"x":682,"y":149},{"type":"mousemove","time":18464,"x":682,"y":149},{"type":"mouseup","time":18497,"x":682,"y":149},{"type":"mousemove","time":18664,"x":666,"y":311},{"type":"mousedown","time":18795,"x":664,"y":431},{"type":"mouseup","time":18865,"x":664,"y":431},{"type":"mousemove","time":18873,"x":664,"y":431},{"type":"mousemove","time":19097,"x":664,"y":431},{"type":"mousemove","time":19305,"x":668,"y":483},{"type":"mousemove","time":19524,"x":668,"y":484}],"scrollY":95,"scrollX":0,"timestamp":1666341040748},{"name":"Action 2","ops":[{"type":"mousemove","time":59,"x":721,"y":587},{"type":"mousemove","time":259,"x":743,"y":194},{"type":"mousemove","time":462,"x":679,"y":60},{"type":"mousemove","time":673,"x":688,"y":11},{"type":"mousemove","time":907,"x":688,"y":8},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":2014,"target":"select"},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"ascending","time":3191,"target":"select"},{"type":"mousemove","time":3202,"x":686,"y":22},{"type":"mousemove","time":3408,"x":686,"y":12},{"type":"mousemove","time":3634,"x":685,"y":10},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"none","time":4429,"target":"select"},{"type":"mousemove","time":4541,"x":693,"y":37},{"type":"mousemove","time":4742,"x":693,"y":35},{"type":"mousemove","time":4944,"x":695,"y":18},{"type":"mousemove","time":5152,"x":696,"y":15},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":7259,"target":"select"},{"type":"mousemove","time":7394,"x":700,"y":5},{"type":"mousemove","time":7602,"x":691,"y":23},{"type":"mousemove","time":7821,"x":691,"y":25},{"type":"mousemove","time":7994,"x":692,"y":21},{"type":"mousemove","time":8202,"x":694,"y":8},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"ascending","time":9133,"target":"select"},{"type":"mousemove","time":9153,"x":689,"y":39},{"type":"mousemove","time":9356,"x":688,"y":40},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":10270,"target":"select"},{"type":"mousemove","time":10281,"x":686,"y":48},{"type":"mousemove","time":10489,"x":686,"y":45},{"type":"mousemove","time":10735,"x":685,"y":43},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":11742,"target":"select"},{"type":"mousemove","time":11752,"x":695,"y":37},{"type":"mousemove","time":11952,"x":694,"y":45},{"type":"mousemove","time":12160,"x":682,"y":56},{"type":"mousemove","time":12367,"x":689,"y":63},{"type":"mousedown","time":12535,"x":673,"y":62},{"type":"mousemove","time":12592,"x":673,"y":62},{"type":"mouseup","time":12617,"x":673,"y":62},{"type":"mousemove","time":12793,"x":664,"y":62},{"type":"mousemove","time":13005,"x":653,"y":63},{"type":"mousedown","time":13152,"x":648,"y":64},{"type":"mousemove","time":13205,"x":648,"y":64},{"type":"mouseup","time":13221,"x":648,"y":64},{"type":"mousemove","time":13426,"x":650,"y":65},{"type":"mousemove","time":13633,"x":654,"y":66},{"type":"mousedown","time":13653,"x":654,"y":66},{"type":"mouseup","time":13722,"x":654,"y":66},{"type":"mousemove","time":13842,"x":716,"y":66},{"type":"mousemove","time":14048,"x":724,"y":68},{"type":"mousemove","time":14254,"x":737,"y":67},{"type":"mousedown","time":14408,"x":741,"y":65},{"type":"mousemove","time":14469,"x":741,"y":65},{"type":"mouseup","time":14504,"x":741,"y":65},{"type":"mousemove","time":14665,"x":741,"y":66},{"type":"mousemove","time":14872,"x":743,"y":76},{"type":"mousedown","time":15005,"x":739,"y":70},{"type":"mousemove","time":15076,"x":739,"y":70},{"type":"mouseup","time":15272,"x":747,"y":71},{"type":"mousemove","time":15281,"x":747,"y":71},{"type":"mousemove","time":15491,"x":746,"y":73},{"type":"mousemove","time":15694,"x":683,"y":90},{"type":"mousemove","time":15900,"x":682,"y":96},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string:nth-child(4)>div>div.c>select","value":"false","time":16880,"target":"select"},{"type":"mousemove","time":16889,"x":685,"y":114},{"type":"mousemove","time":17090,"x":683,"y":106},{"type":"mousemove","time":17293,"x":681,"y":96},{"type":"mousemove","time":17500,"x":681,"y":95},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string:nth-child(4)>div>div.c>select","value":"true","time":18330,"target":"select"},{"type":"mousemove","time":18345,"x":696,"y":100},{"type":"mousemove","time":18553,"x":703,"y":107},{"type":"mousemove","time":18781,"x":705,"y":120},{"type":"mousemove","time":18988,"x":706,"y":122},{"type":"mousemove","time":19192,"x":699,"y":153},{"type":"mousemove","time":19402,"x":758,"y":170},{"type":"mousemove","time":19846,"x":776,"y":159},{"type":"mousemove","time":20058,"x":700,"y":261},{"type":"mousemove","time":20258,"x":671,"y":417},{"type":"mousemove","time":20466,"x":680,"y":434},{"type":"mousedown","time":20476,"x":680,"y":434},{"type":"mouseup","time":20575,"x":680,"y":434},{"type":"mousemove","time":20825,"x":679,"y":433},{"type":"mousemove","time":21025,"x":729,"y":170},{"type":"mousemove","time":21225,"x":684,"y":150},{"type":"mousemove","time":21425,"x":537,"y":44},{"type":"mousemove","time":21625,"x":519,"y":21},{"type":"mousedown","time":21777,"x":519,"y":12},{"type":"mousemove","time":21829,"x":519,"y":12},{"type":"mouseup","time":21857,"x":519,"y":12},{"type":"mousemove","time":22311,"x":519,"y":12},{"type":"mousedown","time":22463,"x":517,"y":10},{"type":"mouseup","time":22519,"x":517,"y":10},{"type":"mousemove","time":22541,"x":515,"y":10},{"type":"mousemove","time":22741,"x":418,"y":16},{"type":"mousemove","time":22952,"x":393,"y":13},{"type":"mousedown","time":23119,"x":391,"y":12},{"type":"mousemove","time":23157,"x":391,"y":12},{"type":"mouseup","time":23168,"x":391,"y":12},{"type":"mousedown","time":23788,"x":391,"y":12},{"type":"mouseup","time":23854,"x":391,"y":12},{"type":"mousemove","time":24047,"x":395,"y":12},{"type":"mousemove","time":24259,"x":471,"y":12},{"type":"mousemove","time":24459,"x":486,"y":12},{"type":"mousemove","time":24670,"x":510,"y":12},{"type":"mousemove","time":24825,"x":509,"y":12},{"type":"mousemove","time":25025,"x":473,"y":12},{"type":"mousedown","time":25176,"x":470,"y":12},{"type":"mousemove","time":25256,"x":470,"y":12},{"type":"mouseup","time":25319,"x":470,"y":12},{"type":"mousedown","time":25952,"x":470,"y":12},{"type":"mouseup","time":26045,"x":470,"y":12},{"type":"mousemove","time":26130,"x":470,"y":12},{"type":"mousemove","time":26344,"x":513,"y":12},{"type":"mousedown","time":26450,"x":513,"y":12},{"type":"mouseup","time":26522,"x":513,"y":12},{"type":"mousedown","time":27250,"x":513,"y":12},{"type":"mouseup","time":27319,"x":513,"y":12},{"type":"mousemove","time":27368,"x":513,"y":12},{"type":"mousemove","time":27574,"x":434,"y":15},{"type":"mousemove","time":27786,"x":423,"y":15},{"type":"mousemove","time":27993,"x":408,"y":14},{"type":"mousemove","time":28203,"x":374,"y":12},{"type":"mousemove","time":28420,"x":312,"y":11},{"type":"mousedown","time":28488,"x":312,"y":11},{"type":"mouseup","time":28553,"x":312,"y":11},{"type":"mousedown","time":29136,"x":312,"y":11},{"type":"mouseup","time":29192,"x":312,"y":11},{"type":"mousemove","time":29279,"x":313,"y":14},{"type":"mousemove","time":29492,"x":587,"y":390},{"type":"mousemove","time":29695,"x":783,"y":594},{"type":"mousedown","time":29766,"x":784,"y":595},{"type":"mouseup","time":29817,"x":784,"y":595},{"type":"mousemove","time":29904,"x":784,"y":595}],"scrollY":861,"scrollX":0,"timestamp":1666341129488},{"name":"Action 3","ops":[{"type":"mousemove","time":704,"x":770,"y":596},{"type":"mousemove","time":911,"x":675,"y":74},{"type":"mousemove","time":1112,"x":678,"y":33},{"type":"mousemove","time":1313,"x":683,"y":14},{"type":"mousemove","time":1533,"x":683,"y":14},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":2522,"target":"select"},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string>div>div.c>select","value":"none","time":3799,"target":"select"},{"type":"mousemove","time":3890,"x":698,"y":15},{"type":"mousemove","time":4128,"x":698,"y":10},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string>div>div.c>select","value":"ascending","time":5147,"target":"select"},{"type":"mousemove","time":5258,"x":699,"y":8},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":6547,"target":"select"},{"type":"mousemove","time":6588,"x":706,"y":16},{"type":"mousemove","time":6799,"x":699,"y":30},{"type":"mousemove","time":7000,"x":698,"y":35},{"type":"mousemove","time":7201,"x":697,"y":43},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":8149,"target":"select"},{"type":"mousemove","time":8225,"x":702,"y":56},{"type":"mousemove","time":8431,"x":701,"y":44},{"type":"mousemove","time":8734,"x":700,"y":42},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":9605,"target":"select"},{"type":"mousemove","time":9661,"x":710,"y":47},{"type":"mousemove","time":9866,"x":709,"y":51},{"type":"mousemove","time":10068,"x":703,"y":62},{"type":"mousemove","time":10268,"x":698,"y":67},{"type":"mousemove","time":10477,"x":696,"y":68},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"false","time":11269,"target":"select"},{"type":"mousemove","time":11404,"x":695,"y":72},{"type":"mousemove","time":11615,"x":694,"y":69},{"type":"mousemove","time":11851,"x":694,"y":69},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"true","time":13273,"target":"select"},{"type":"mousemove","time":13635,"x":692,"y":52},{"type":"mousemove","time":13843,"x":692,"y":87},{"type":"mousemove","time":14061,"x":782,"y":326}],"scrollY":1572,"scrollX":0,"timestamp":1666341412440}] \ No newline at end of file From 83d6a844c89b8fb72a351556a547cbaf2612b2fe Mon Sep 17 00:00:00 2001 From: gxd3 Date: Fri, 21 Oct 2022 17:54:27 +0800 Subject: [PATCH 18/23] feat(funnle): visual test of all funnel new feat --- test/funnel1.html | 103 +------------------ test/funnel2.html | 154 +++++++++++++++++++++++++++++ test/funnel3.html | 149 ++++++++++++++++++++++++++++ test/runTest/actions/__meta__.json | 4 +- test/runTest/actions/funnel1.json | 2 +- test/runTest/actions/funnel2.json | 1 + test/runTest/actions/funnel3.json | 1 + 7 files changed, 310 insertions(+), 104 deletions(-) create mode 100644 test/funnel2.html create mode 100644 test/funnel3.html create mode 100644 test/runTest/actions/funnel2.json create mode 100644 test/runTest/actions/funnel3.json diff --git a/test/funnel1.html b/test/funnel1.html index aecdef5e1f..0592d57175 100644 --- a/test/funnel1.html +++ b/test/funnel1.html @@ -42,8 +42,6 @@ }
-
-
- - diff --git a/test/funnel2.html b/test/funnel2.html new file mode 100644 index 0000000000..8676652c83 --- /dev/null +++ b/test/funnel2.html @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/test/funnel3.html b/test/funnel3.html new file mode 100644 index 0000000000..6ec4442dc1 --- /dev/null +++ b/test/funnel3.html @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index b17568d29c..b13ab35536 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -89,7 +89,9 @@ "emphasis-disabled": 13, "emphasis-inherit": 1, "funnel": 2, - "funnel1": 3, + "funnel1": 1, + "funnel2": 1, + "funnel3": 1, "gauge-simple": 2, "geo-map": 4, "geo-map-features": 3, diff --git a/test/runTest/actions/funnel1.json b/test/runTest/actions/funnel1.json index d6ec798efe..5ef7660003 100644 --- a/test/runTest/actions/funnel1.json +++ b/test/runTest/actions/funnel1.json @@ -1 +1 @@ -[{"name":"Action 1","ops":[{"type":"mousemove","time":217,"x":778,"y":151},{"type":"mousemove","time":420,"x":720,"y":49},{"type":"mousemove","time":634,"x":709,"y":23},{"type":"mousemove","time":839,"x":706,"y":15},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":1926,"target":"select"},{"type":"mousemove","time":1935,"x":712,"y":6},{"type":"mousemove","time":2143,"x":711,"y":9},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string>div>div.c>select","value":"none","time":2988,"target":"select"},{"type":"mousemove","time":3005,"x":708,"y":19},{"type":"mousemove","time":3212,"x":706,"y":11},{"type":"mousemove","time":3432,"x":706,"y":10},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string>div>div.c>select","value":"ascending","time":4796,"target":"select"},{"type":"mousemove","time":4805,"x":694,"y":31},{"type":"mousemove","time":5032,"x":691,"y":38},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":5911,"target":"select"},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":7106,"target":"select"},{"type":"mousemove","time":7240,"x":674,"y":76},{"type":"mousemove","time":7447,"x":675,"y":70},{"type":"valuechange","selector":"main1>div.dg.main>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"false","time":8212,"target":"select"},{"type":"mousemove","time":8222,"x":670,"y":97},{"type":"mousemove","time":8422,"x":666,"y":97},{"type":"mousedown","time":8605,"x":700,"y":96},{"type":"mousemove","time":8644,"x":700,"y":95},{"type":"mouseup","time":8698,"x":705,"y":94},{"type":"mousemove","time":8848,"x":733,"y":94},{"type":"mousedown","time":9052,"x":734,"y":92},{"type":"mousemove","time":9099,"x":734,"y":92},{"type":"mouseup","time":9144,"x":735,"y":91},{"type":"mousemove","time":9338,"x":743,"y":91},{"type":"mousemove","time":9451,"x":742,"y":91},{"type":"mousedown","time":9523,"x":742,"y":91},{"type":"mouseup","time":9588,"x":742,"y":91},{"type":"mousemove","time":9675,"x":742,"y":91},{"type":"mousemove","time":9875,"x":746,"y":93},{"type":"mousedown","time":10027,"x":746,"y":94},{"type":"mouseup","time":10078,"x":746,"y":94},{"type":"mousemove","time":10140,"x":746,"y":94},{"type":"mousemove","time":10148,"x":745,"y":94},{"type":"mousemove","time":10350,"x":737,"y":91},{"type":"mousedown","time":10367,"x":737,"y":91},{"type":"mouseup","time":10499,"x":742,"y":93},{"type":"mousemove","time":10588,"x":743,"y":93},{"type":"mousemove","time":10793,"x":745,"y":96},{"type":"mousedown","time":10853,"x":745,"y":96},{"type":"mouseup","time":10956,"x":746,"y":96},{"type":"mousemove","time":11000,"x":746,"y":96},{"type":"mousemove","time":11219,"x":736,"y":91},{"type":"mousedown","time":11254,"x":737,"y":92},{"type":"mouseup","time":11416,"x":744,"y":95},{"type":"mousemove","time":11426,"x":746,"y":95},{"type":"mousemove","time":11647,"x":744,"y":98},{"type":"mousemove","time":11850,"x":698,"y":96},{"type":"mousemove","time":12052,"x":661,"y":94},{"type":"mousemove","time":12260,"x":653,"y":94},{"type":"mousedown","time":12391,"x":651,"y":94},{"type":"mousemove","time":12460,"x":651,"y":94},{"type":"mouseup","time":12492,"x":651,"y":94},{"type":"mousemove","time":12693,"x":651,"y":98},{"type":"mousemove","time":12894,"x":665,"y":141},{"type":"mousemove","time":13103,"x":689,"y":131},{"type":"mousedown","time":13142,"x":689,"y":131},{"type":"mouseup","time":13257,"x":695,"y":131},{"type":"mousemove","time":13394,"x":740,"y":130},{"type":"mousedown","time":13592,"x":741,"y":124},{"type":"mousemove","time":13663,"x":741,"y":124},{"type":"mouseup","time":13677,"x":741,"y":124},{"type":"mousemove","time":13866,"x":738,"y":130},{"type":"mousemove","time":14071,"x":676,"y":124},{"type":"mousemove","time":14277,"x":667,"y":127},{"type":"mousedown","time":14391,"x":663,"y":125},{"type":"mouseup","time":14461,"x":663,"y":125},{"type":"mousemove","time":14488,"x":663,"y":125},{"type":"mousemove","time":14695,"x":655,"y":127},{"type":"mousemove","time":14913,"x":645,"y":125},{"type":"mousedown","time":15024,"x":645,"y":125},{"type":"mouseup","time":15127,"x":645,"y":125},{"type":"mousemove","time":15179,"x":645,"y":124},{"type":"mousemove","time":15385,"x":651,"y":126},{"type":"mousedown","time":15405,"x":651,"y":126},{"type":"mouseup","time":15489,"x":651,"y":126},{"type":"mousemove","time":15695,"x":652,"y":126},{"type":"mousemove","time":15896,"x":702,"y":118},{"type":"mousedown","time":15960,"x":702,"y":118},{"type":"mouseup","time":16040,"x":702,"y":118},{"type":"mousemove","time":16096,"x":711,"y":120},{"type":"mousemove","time":16297,"x":734,"y":121},{"type":"mousedown","time":16441,"x":735,"y":121},{"type":"mouseup","time":16505,"x":735,"y":121},{"type":"mousemove","time":16523,"x":735,"y":121},{"type":"mousemove","time":16556,"x":735,"y":121},{"type":"mousemove","time":16757,"x":740,"y":123},{"type":"mousemove","time":16963,"x":729,"y":128},{"type":"mousemove","time":17170,"x":702,"y":163},{"type":"mousemove","time":17388,"x":668,"y":152},{"type":"mousedown","time":17407,"x":668,"y":152},{"type":"mouseup","time":17494,"x":668,"y":152},{"type":"mousemove","time":17599,"x":675,"y":154},{"type":"mousemove","time":17806,"x":694,"y":148},{"type":"mousedown","time":17821,"x":694,"y":148},{"type":"mouseup","time":17892,"x":694,"y":148},{"type":"mousemove","time":18013,"x":703,"y":150},{"type":"mousemove","time":18233,"x":691,"y":151},{"type":"mousedown","time":18436,"x":682,"y":149},{"type":"mousemove","time":18464,"x":682,"y":149},{"type":"mouseup","time":18497,"x":682,"y":149},{"type":"mousemove","time":18664,"x":666,"y":311},{"type":"mousedown","time":18795,"x":664,"y":431},{"type":"mouseup","time":18865,"x":664,"y":431},{"type":"mousemove","time":18873,"x":664,"y":431},{"type":"mousemove","time":19097,"x":664,"y":431},{"type":"mousemove","time":19305,"x":668,"y":483},{"type":"mousemove","time":19524,"x":668,"y":484}],"scrollY":95,"scrollX":0,"timestamp":1666341040748},{"name":"Action 2","ops":[{"type":"mousemove","time":59,"x":721,"y":587},{"type":"mousemove","time":259,"x":743,"y":194},{"type":"mousemove","time":462,"x":679,"y":60},{"type":"mousemove","time":673,"x":688,"y":11},{"type":"mousemove","time":907,"x":688,"y":8},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":2014,"target":"select"},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"ascending","time":3191,"target":"select"},{"type":"mousemove","time":3202,"x":686,"y":22},{"type":"mousemove","time":3408,"x":686,"y":12},{"type":"mousemove","time":3634,"x":685,"y":10},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"none","time":4429,"target":"select"},{"type":"mousemove","time":4541,"x":693,"y":37},{"type":"mousemove","time":4742,"x":693,"y":35},{"type":"mousemove","time":4944,"x":695,"y":18},{"type":"mousemove","time":5152,"x":696,"y":15},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":7259,"target":"select"},{"type":"mousemove","time":7394,"x":700,"y":5},{"type":"mousemove","time":7602,"x":691,"y":23},{"type":"mousemove","time":7821,"x":691,"y":25},{"type":"mousemove","time":7994,"x":692,"y":21},{"type":"mousemove","time":8202,"x":694,"y":8},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string>div>div.c>select","value":"ascending","time":9133,"target":"select"},{"type":"mousemove","time":9153,"x":689,"y":39},{"type":"mousemove","time":9356,"x":688,"y":40},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":10270,"target":"select"},{"type":"mousemove","time":10281,"x":686,"y":48},{"type":"mousemove","time":10489,"x":686,"y":45},{"type":"mousemove","time":10735,"x":685,"y":43},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":11742,"target":"select"},{"type":"mousemove","time":11752,"x":695,"y":37},{"type":"mousemove","time":11952,"x":694,"y":45},{"type":"mousemove","time":12160,"x":682,"y":56},{"type":"mousemove","time":12367,"x":689,"y":63},{"type":"mousedown","time":12535,"x":673,"y":62},{"type":"mousemove","time":12592,"x":673,"y":62},{"type":"mouseup","time":12617,"x":673,"y":62},{"type":"mousemove","time":12793,"x":664,"y":62},{"type":"mousemove","time":13005,"x":653,"y":63},{"type":"mousedown","time":13152,"x":648,"y":64},{"type":"mousemove","time":13205,"x":648,"y":64},{"type":"mouseup","time":13221,"x":648,"y":64},{"type":"mousemove","time":13426,"x":650,"y":65},{"type":"mousemove","time":13633,"x":654,"y":66},{"type":"mousedown","time":13653,"x":654,"y":66},{"type":"mouseup","time":13722,"x":654,"y":66},{"type":"mousemove","time":13842,"x":716,"y":66},{"type":"mousemove","time":14048,"x":724,"y":68},{"type":"mousemove","time":14254,"x":737,"y":67},{"type":"mousedown","time":14408,"x":741,"y":65},{"type":"mousemove","time":14469,"x":741,"y":65},{"type":"mouseup","time":14504,"x":741,"y":65},{"type":"mousemove","time":14665,"x":741,"y":66},{"type":"mousemove","time":14872,"x":743,"y":76},{"type":"mousedown","time":15005,"x":739,"y":70},{"type":"mousemove","time":15076,"x":739,"y":70},{"type":"mouseup","time":15272,"x":747,"y":71},{"type":"mousemove","time":15281,"x":747,"y":71},{"type":"mousemove","time":15491,"x":746,"y":73},{"type":"mousemove","time":15694,"x":683,"y":90},{"type":"mousemove","time":15900,"x":682,"y":96},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string:nth-child(4)>div>div.c>select","value":"false","time":16880,"target":"select"},{"type":"mousemove","time":16889,"x":685,"y":114},{"type":"mousemove","time":17090,"x":683,"y":106},{"type":"mousemove","time":17293,"x":681,"y":96},{"type":"mousemove","time":17500,"x":681,"y":95},{"type":"valuechange","selector":"main2>div.dg.main>ul>li.cr.string:nth-child(4)>div>div.c>select","value":"true","time":18330,"target":"select"},{"type":"mousemove","time":18345,"x":696,"y":100},{"type":"mousemove","time":18553,"x":703,"y":107},{"type":"mousemove","time":18781,"x":705,"y":120},{"type":"mousemove","time":18988,"x":706,"y":122},{"type":"mousemove","time":19192,"x":699,"y":153},{"type":"mousemove","time":19402,"x":758,"y":170},{"type":"mousemove","time":19846,"x":776,"y":159},{"type":"mousemove","time":20058,"x":700,"y":261},{"type":"mousemove","time":20258,"x":671,"y":417},{"type":"mousemove","time":20466,"x":680,"y":434},{"type":"mousedown","time":20476,"x":680,"y":434},{"type":"mouseup","time":20575,"x":680,"y":434},{"type":"mousemove","time":20825,"x":679,"y":433},{"type":"mousemove","time":21025,"x":729,"y":170},{"type":"mousemove","time":21225,"x":684,"y":150},{"type":"mousemove","time":21425,"x":537,"y":44},{"type":"mousemove","time":21625,"x":519,"y":21},{"type":"mousedown","time":21777,"x":519,"y":12},{"type":"mousemove","time":21829,"x":519,"y":12},{"type":"mouseup","time":21857,"x":519,"y":12},{"type":"mousemove","time":22311,"x":519,"y":12},{"type":"mousedown","time":22463,"x":517,"y":10},{"type":"mouseup","time":22519,"x":517,"y":10},{"type":"mousemove","time":22541,"x":515,"y":10},{"type":"mousemove","time":22741,"x":418,"y":16},{"type":"mousemove","time":22952,"x":393,"y":13},{"type":"mousedown","time":23119,"x":391,"y":12},{"type":"mousemove","time":23157,"x":391,"y":12},{"type":"mouseup","time":23168,"x":391,"y":12},{"type":"mousedown","time":23788,"x":391,"y":12},{"type":"mouseup","time":23854,"x":391,"y":12},{"type":"mousemove","time":24047,"x":395,"y":12},{"type":"mousemove","time":24259,"x":471,"y":12},{"type":"mousemove","time":24459,"x":486,"y":12},{"type":"mousemove","time":24670,"x":510,"y":12},{"type":"mousemove","time":24825,"x":509,"y":12},{"type":"mousemove","time":25025,"x":473,"y":12},{"type":"mousedown","time":25176,"x":470,"y":12},{"type":"mousemove","time":25256,"x":470,"y":12},{"type":"mouseup","time":25319,"x":470,"y":12},{"type":"mousedown","time":25952,"x":470,"y":12},{"type":"mouseup","time":26045,"x":470,"y":12},{"type":"mousemove","time":26130,"x":470,"y":12},{"type":"mousemove","time":26344,"x":513,"y":12},{"type":"mousedown","time":26450,"x":513,"y":12},{"type":"mouseup","time":26522,"x":513,"y":12},{"type":"mousedown","time":27250,"x":513,"y":12},{"type":"mouseup","time":27319,"x":513,"y":12},{"type":"mousemove","time":27368,"x":513,"y":12},{"type":"mousemove","time":27574,"x":434,"y":15},{"type":"mousemove","time":27786,"x":423,"y":15},{"type":"mousemove","time":27993,"x":408,"y":14},{"type":"mousemove","time":28203,"x":374,"y":12},{"type":"mousemove","time":28420,"x":312,"y":11},{"type":"mousedown","time":28488,"x":312,"y":11},{"type":"mouseup","time":28553,"x":312,"y":11},{"type":"mousedown","time":29136,"x":312,"y":11},{"type":"mouseup","time":29192,"x":312,"y":11},{"type":"mousemove","time":29279,"x":313,"y":14},{"type":"mousemove","time":29492,"x":587,"y":390},{"type":"mousemove","time":29695,"x":783,"y":594},{"type":"mousedown","time":29766,"x":784,"y":595},{"type":"mouseup","time":29817,"x":784,"y":595},{"type":"mousemove","time":29904,"x":784,"y":595}],"scrollY":861,"scrollX":0,"timestamp":1666341129488},{"name":"Action 3","ops":[{"type":"mousemove","time":704,"x":770,"y":596},{"type":"mousemove","time":911,"x":675,"y":74},{"type":"mousemove","time":1112,"x":678,"y":33},{"type":"mousemove","time":1313,"x":683,"y":14},{"type":"mousemove","time":1533,"x":683,"y":14},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":2522,"target":"select"},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string>div>div.c>select","value":"none","time":3799,"target":"select"},{"type":"mousemove","time":3890,"x":698,"y":15},{"type":"mousemove","time":4128,"x":698,"y":10},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string>div>div.c>select","value":"ascending","time":5147,"target":"select"},{"type":"mousemove","time":5258,"x":699,"y":8},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string>div>div.c>select","value":"descending","time":6547,"target":"select"},{"type":"mousemove","time":6588,"x":706,"y":16},{"type":"mousemove","time":6799,"x":699,"y":30},{"type":"mousemove","time":7000,"x":698,"y":35},{"type":"mousemove","time":7201,"x":697,"y":43},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":8149,"target":"select"},{"type":"mousemove","time":8225,"x":702,"y":56},{"type":"mousemove","time":8431,"x":701,"y":44},{"type":"mousemove","time":8734,"x":700,"y":42},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":9605,"target":"select"},{"type":"mousemove","time":9661,"x":710,"y":47},{"type":"mousemove","time":9866,"x":709,"y":51},{"type":"mousemove","time":10068,"x":703,"y":62},{"type":"mousemove","time":10268,"x":698,"y":67},{"type":"mousemove","time":10477,"x":696,"y":68},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"false","time":11269,"target":"select"},{"type":"mousemove","time":11404,"x":695,"y":72},{"type":"mousemove","time":11615,"x":694,"y":69},{"type":"mousemove","time":11851,"x":694,"y":69},{"type":"valuechange","selector":"main3>div.dg.main>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"true","time":13273,"target":"select"},{"type":"mousemove","time":13635,"x":692,"y":52},{"type":"mousemove","time":13843,"x":692,"y":87},{"type":"mousemove","time":14061,"x":782,"y":326}],"scrollY":1572,"scrollX":0,"timestamp":1666341412440}] \ No newline at end of file +[{"name":"Action 1","ops":[{"type":"mousemove","time":165,"x":645,"y":243},{"type":"mousemove","time":365,"x":711,"y":59},{"type":"mousemove","time":572,"x":707,"y":29},{"type":"mousemove","time":781,"x":703,"y":9},{"type":"mousemove","time":987,"x":703,"y":8},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"descending","time":1903,"target":"select"},{"time":1904,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1910,"x":692,"y":22},{"type":"mousemove","time":2112,"x":689,"y":16},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"none","time":3097,"target":"select"},{"time":3098,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3105,"x":684,"y":32},{"type":"mousemove","time":3305,"x":681,"y":16},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"ascending","time":4746,"target":"select"},{"time":4747,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4754,"x":668,"y":53},{"type":"mousemove","time":4959,"x":667,"y":48},{"type":"mousemove","time":5173,"x":667,"y":47},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":5881,"target":"select"},{"time":5882,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":5900,"x":666,"y":38},{"type":"mousemove","time":6105,"x":666,"y":37},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":7037,"target":"select"},{"time":7038,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7097,"x":663,"y":63},{"type":"mousemove","time":7297,"x":663,"y":67},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"false","time":8180,"target":"select"},{"time":8181,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":8198,"x":665,"y":73},{"type":"mousemove","time":8404,"x":664,"y":70},{"type":"mousemove","time":8631,"x":664,"y":68},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"true","time":9421,"target":"select"},{"time":9422,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9429,"x":672,"y":108},{"type":"mousemove","time":9631,"x":702,"y":100},{"type":"mousemove","time":9839,"x":711,"y":95},{"type":"mousedown","time":9962,"x":716,"y":96},{"type":"mousemove","time":10056,"x":720,"y":96},{"type":"mousemove","time":10265,"x":736,"y":98},{"type":"mouseup","time":10310,"x":738,"y":97},{"time":10311,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":10473,"x":733,"y":96},{"type":"mousemove","time":10694,"x":717,"y":97},{"type":"mousemove","time":10831,"x":717,"y":97},{"type":"mousedown","time":10937,"x":720,"y":98},{"type":"mousemove","time":11050,"x":699,"y":97},{"type":"mousemove","time":11262,"x":639,"y":89},{"type":"mouseup","time":11455,"x":617,"y":92},{"time":11456,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":11471,"x":617,"y":92},{"type":"mousemove","time":11680,"x":678,"y":110},{"type":"mousemove","time":11881,"x":678,"y":111},{"type":"mousemove","time":12081,"x":682,"y":128},{"type":"mousedown","time":12155,"x":682,"y":128},{"type":"mouseup","time":12251,"x":683,"y":127},{"time":12252,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12291,"x":683,"y":127},{"type":"mousemove","time":12497,"x":660,"y":127},{"type":"mousemove","time":12697,"x":656,"y":126},{"type":"mousemove","time":12898,"x":705,"y":132},{"type":"mousedown","time":12989,"x":711,"y":133},{"type":"mouseup","time":13089,"x":713,"y":133},{"time":13090,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":13104,"x":713,"y":133},{"type":"mousemove","time":13313,"x":700,"y":143},{"type":"mousemove","time":13513,"x":680,"y":159},{"type":"mousedown","time":13573,"x":678,"y":159},{"type":"mouseup","time":13670,"x":677,"y":158},{"time":13671,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":13713,"x":671,"y":158},{"type":"mousemove","time":13913,"x":662,"y":159},{"type":"mousemove","time":14114,"x":658,"y":157},{"type":"mousemove","time":14321,"x":658,"y":156},{"type":"mousedown","time":14455,"x":663,"y":152},{"type":"mouseup","time":14529,"x":663,"y":152},{"time":14530,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":14544,"x":663,"y":152},{"type":"mousemove","time":14746,"x":678,"y":151},{"type":"mousemove","time":14954,"x":679,"y":151},{"type":"mousemove","time":15183,"x":497,"y":27},{"type":"mousemove","time":15388,"x":458,"y":14},{"type":"mousedown","time":15518,"x":456,"y":17},{"type":"mouseup","time":15577,"x":455,"y":17},{"time":15578,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":15626,"x":455,"y":17},{"type":"mousemove","time":15814,"x":455,"y":17},{"type":"mousemove","time":16014,"x":454,"y":12},{"type":"mousedown","time":16089,"x":454,"y":12},{"type":"mouseup","time":16155,"x":454,"y":12},{"time":16156,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":16229,"x":529,"y":12},{"type":"mousemove","time":16430,"x":541,"y":12},{"type":"mousemove","time":16643,"x":522,"y":12},{"type":"mousedown","time":16701,"x":522,"y":12},{"type":"mouseup","time":16757,"x":522,"y":12},{"time":16758,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":17357,"x":522,"y":12},{"type":"mouseup","time":17427,"x":522,"y":12},{"time":17428,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":17672,"x":521,"y":12},{"type":"mousemove","time":17874,"x":650,"y":156},{"type":"mousemove","time":18083,"x":603,"y":517},{"type":"mousemove","time":18287,"x":572,"y":578}],"scrollY":94,"scrollX":0,"timestamp":1666345765764}] \ No newline at end of file diff --git a/test/runTest/actions/funnel2.json b/test/runTest/actions/funnel2.json new file mode 100644 index 0000000000..6770de15c6 --- /dev/null +++ b/test/runTest/actions/funnel2.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousemove","time":216,"x":782,"y":348},{"type":"mousemove","time":416,"x":670,"y":80},{"type":"mousemove","time":621,"x":664,"y":4},{"type":"mousemove","time":783,"x":667,"y":0},{"type":"mousemove","time":988,"x":671,"y":10},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"descending","time":2289,"target":"select"},{"time":2290,"delay":400,"type":"screenshot-auto"},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"none","time":3871,"target":"select"},{"time":3872,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4015,"x":687,"y":17},{"type":"mousemove","time":4225,"x":687,"y":15},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"descending","time":5598,"target":"select"},{"time":5599,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":5608,"x":698,"y":16},{"type":"mousemove","time":5811,"x":691,"y":28},{"type":"mousemove","time":6015,"x":689,"y":37},{"type":"mousemove","time":6248,"x":689,"y":43},{"type":"mousemove","time":6482,"x":689,"y":43},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":7640,"target":"select"},{"time":7641,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7715,"x":689,"y":45},{"type":"mousemove","time":7922,"x":684,"y":63},{"type":"mousemove","time":8131,"x":680,"y":70},{"type":"mousemove","time":8336,"x":670,"y":71},{"type":"mousedown","time":8380,"x":669,"y":71},{"type":"mouseup","time":8441,"x":669,"y":71},{"time":8442,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":8580,"x":669,"y":71},{"type":"mousemove","time":8664,"x":668,"y":71},{"type":"mousemove","time":8864,"x":667,"y":72},{"type":"mousedown","time":9057,"x":690,"y":69},{"type":"mousemove","time":9093,"x":690,"y":69},{"type":"mouseup","time":9141,"x":690,"y":69},{"time":9142,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9299,"x":695,"y":69},{"type":"mousedown","time":9499,"x":703,"y":69},{"type":"mousemove","time":9519,"x":704,"y":69},{"type":"mouseup","time":9609,"x":704,"y":69},{"time":9610,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9737,"x":698,"y":56},{"type":"mousedown","time":9923,"x":696,"y":53},{"type":"mousemove","time":9941,"x":696,"y":53},{"type":"mouseup","time":9978,"x":695,"y":51},{"time":9979,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":10148,"x":694,"y":43},{"type":"mousemove","time":10367,"x":694,"y":40},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":11205,"target":"select"},{"time":11206,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":11214,"x":683,"y":86},{"type":"mousemove","time":11414,"x":680,"y":92},{"type":"mousemove","time":11626,"x":675,"y":96},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(4)>div>div.c>select","value":"false","time":12850,"target":"select"},{"time":12851,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12883,"x":680,"y":113},{"type":"mousemove","time":13083,"x":677,"y":106},{"type":"mousemove","time":13289,"x":674,"y":98},{"type":"mousemove","time":13507,"x":671,"y":89},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(4)>div>div.c>select","value":"true","time":14474,"target":"select"},{"time":14475,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":14482,"x":671,"y":228},{"type":"mousemove","time":14682,"x":670,"y":357},{"type":"mousemove","time":14893,"x":664,"y":367},{"type":"mousemove","time":15099,"x":461,"y":62},{"type":"mousemove","time":15311,"x":458,"y":16},{"type":"mousemove","time":15515,"x":451,"y":1},{"type":"mousedown","time":15714,"x":450,"y":8},{"type":"mousemove","time":15740,"x":450,"y":8},{"type":"mouseup","time":15777,"x":450,"y":8},{"time":15778,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":16316,"x":450,"y":9},{"type":"mousedown","time":16509,"x":450,"y":10},{"type":"mousemove","time":16523,"x":450,"y":10},{"type":"mouseup","time":16577,"x":450,"y":10},{"time":16578,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":16733,"x":450,"y":10},{"type":"mousemove","time":16932,"x":481,"y":10},{"type":"mousemove","time":17132,"x":494,"y":7},{"type":"mousedown","time":17313,"x":504,"y":7},{"type":"mousemove","time":17392,"x":504,"y":7},{"type":"mouseup","time":17418,"x":504,"y":7},{"time":17419,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":18109,"x":504,"y":7},{"type":"mouseup","time":18178,"x":504,"y":7},{"time":18179,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":18398,"x":504,"y":8},{"type":"mousemove","time":18599,"x":399,"y":20},{"type":"mousemove","time":18809,"x":307,"y":20},{"type":"mousemove","time":19015,"x":277,"y":14},{"type":"mousedown","time":19226,"x":257,"y":12},{"type":"mousemove","time":19242,"x":257,"y":12},{"type":"mouseup","time":19314,"x":257,"y":12},{"time":19315,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":20194,"x":257,"y":12},{"type":"mouseup","time":20282,"x":257,"y":12},{"time":20283,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":20847,"x":259,"y":11},{"type":"mousemove","time":21048,"x":426,"y":376},{"type":"mousemove","time":21259,"x":430,"y":592}],"scrollY":166,"scrollX":0,"timestamp":1666345365626}] \ No newline at end of file diff --git a/test/runTest/actions/funnel3.json b/test/runTest/actions/funnel3.json new file mode 100644 index 0000000000..5a9187e99a --- /dev/null +++ b/test/runTest/actions/funnel3.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousemove","time":43,"x":648,"y":398},{"type":"mousemove","time":251,"x":658,"y":396},{"type":"mousemove","time":451,"x":747,"y":62},{"type":"mousemove","time":652,"x":696,"y":31},{"type":"mousemove","time":858,"x":693,"y":19},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"descending","time":1707,"target":"select"},{"time":1708,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1715,"x":694,"y":12},{"type":"mousemove","time":1916,"x":693,"y":12},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"ascending","time":2725,"target":"select"},{"time":2726,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":2768,"x":692,"y":13},{"type":"mousemove","time":2976,"x":691,"y":12},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"none","time":3890,"target":"select"},{"time":3891,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3952,"x":685,"y":23},{"type":"mousemove","time":4159,"x":677,"y":35},{"type":"mousemove","time":4401,"x":685,"y":18},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"ascending","time":5336,"target":"select"},{"time":5337,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":5343,"x":678,"y":38},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":6373,"target":"select"},{"time":6374,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":6625,"x":674,"y":35},{"type":"mousemove","time":6826,"x":674,"y":36},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":7732,"target":"select"},{"time":7733,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7751,"x":673,"y":65},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"false","time":9024,"target":"select"},{"time":9025,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9335,"x":669,"y":68},{"type":"mousemove","time":9540,"x":669,"y":66},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"true","time":10784,"target":"select"},{"time":10785,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":10793,"x":542,"y":32},{"type":"mousemove","time":10993,"x":531,"y":20},{"type":"mousemove","time":11202,"x":513,"y":13},{"type":"mousemove","time":11412,"x":513,"y":12},{"type":"mousedown","time":11480,"x":513,"y":12},{"type":"mouseup","time":11559,"x":513,"y":12},{"time":11560,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":12216,"x":513,"y":12},{"type":"mouseup","time":12274,"x":513,"y":12},{"time":12275,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12367,"x":512,"y":11},{"type":"mousemove","time":12567,"x":415,"y":11},{"type":"mousemove","time":12776,"x":369,"y":15},{"type":"mousedown","time":12969,"x":381,"y":11},{"type":"mouseup","time":13028,"x":381,"y":11},{"time":13029,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":13061,"x":381,"y":11},{"type":"mousedown","time":13616,"x":381,"y":11},{"type":"mouseup","time":13741,"x":381,"y":11},{"time":13742,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":13817,"x":379,"y":11},{"type":"mousemove","time":14017,"x":284,"y":11},{"type":"mousemove","time":14217,"x":270,"y":10},{"type":"mousedown","time":14358,"x":270,"y":10},{"type":"mouseup","time":14428,"x":270,"y":10},{"time":14429,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":15067,"x":270,"y":10},{"type":"mouseup","time":15143,"x":270,"y":10},{"time":15144,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":15520,"x":270,"y":11},{"type":"mousemove","time":15720,"x":651,"y":347},{"type":"mousemove","time":15930,"x":739,"y":593}],"scrollY":112,"scrollX":0,"timestamp":1666345939904}] \ No newline at end of file From f5b1065e3c93e49502d182728c08f81fe98f92dc Mon Sep 17 00:00:00 2001 From: gxd3 Date: Fri, 21 Oct 2022 19:31:42 +0800 Subject: [PATCH 19/23] feat(funnel): rename test case file, delete dynamicArea --- src/chart/funnel/FunnelSeries.ts | 2 - src/chart/funnel/FunnelView.ts | 1 - src/chart/funnel/funnelLayout.ts | 63 +------- ...funnel1.html => funnel-dynamicHeight.html} | 0 test/{funnel2.html => funnel-showRate.html} | 0 test/funnel3.html | 149 ------------------ test/runTest/actions/__meta__.json | 5 +- ...funnel1.json => funnel-dynamicHeight.json} | 0 .../{funnel2.json => funnel-showRate.json} | 0 test/runTest/actions/funnel3.json | 1 - 10 files changed, 8 insertions(+), 213 deletions(-) rename test/{funnel1.html => funnel-dynamicHeight.html} (100%) rename test/{funnel2.html => funnel-showRate.html} (100%) delete mode 100644 test/funnel3.html rename test/runTest/actions/{funnel1.json => funnel-dynamicHeight.json} (100%) rename test/runTest/actions/{funnel2.json => funnel-showRate.json} (100%) delete mode 100644 test/runTest/actions/funnel3.json diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index a73503687b..4b87fe7e45 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -101,8 +101,6 @@ export interface FunnelSeriesOption showRate?: boolean - dynamicArea?: boolean - dynamicHeight?: boolean /** diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index 6f3a7d8edf..cbfb526585 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -310,7 +310,6 @@ class FunnelView extends ChartView { seriesModel.get('showRate') && !( seriesModel.get('dynamicHeight') - || seriesModel.get('dynamicArea') || seriesModel.get('sort') === 'none' ); diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index c0bf14e737..3841e59378 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -299,7 +299,6 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { // mapping mode about const dynamicHeight = seriesModel.get('dynamicHeight'); - const dynamicArea = seriesModel.get('dynamicArea'); const showRate = seriesModel.get('showRate'); // size extent based on orient and mapping mode // determine the width extent of the funnel piece when dynamicHeight is false @@ -314,7 +313,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { parsePercent(seriesModel.get('minSize'), size), size ]; - if (!dynamicHeight && !dynamicArea) { + if (!dynamicHeight) { sizeExtent[1] = parsePercent(seriesModel.get('maxSize'), size); } @@ -345,18 +344,17 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { if (sort === 'ascending') { // From bottom to top itemSize = -itemSize; - const symbol = !dynamicHeight && dynamicArea ? 1 : -1; - gap = gap * symbol; + gap = -gap; if (orient === 'horizontal') { - x += symbol === 1 ? 0 : viewWidth; + x += viewWidth; } else { - y += symbol === 1 ? 0 : viewHeight; + y += viewHeight; } indices = indices.reverse(); } else { - if (dynamicArea && !dynamicHeight) { + if (!dynamicHeight) { gap = -gap; if (orient === 'horizontal') { x += viewWidth; @@ -417,7 +415,6 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { // exit shape control const exitWidth = parsePercent(seriesModel.get('exitWidth'), 100); - // dy height funnel piece about let setDynamicHeightPoints: ( @@ -447,47 +444,6 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { })(); } - // dy area funnel piece about - let getAreaPieceHeight: (val: number, pieceHeight: number | string) => number | null = null; - let setAreaPiecePoint: (idx: number, pos: number, pieceHeight: number) => void | null = null; - if (dynamicArea) { - ({ getAreaPieceHeight, setAreaPiecePoint } = (function () { - // dynamicArea about - const areaExtent = [0, viewHeight * viewWidth / 2]; - // auxiliary variable - let cumulativeArea = 0; - let cumulativeHeight = 0; - // piece top and bottom - let pieceAreaBottom = 0; - let pieceAreaTop = 0; - const getAreaPieceHeight = function (val: number, pieceHeight: number | string) { - const pieceArea = linearMap(val, [0, valueSum], areaExtent, true); - - cumulativeArea += pieceArea; - pieceAreaTop = pieceAreaBottom; - - // calculate bottom line length and top line length - pieceAreaBottom = Math.sqrt(2 * cumulativeArea * size / viewSize); - pieceHeight = pieceAreaBottom * viewSize / size - cumulativeHeight; - - cumulativeHeight += pieceHeight; - pieceHeight = sort === 'ascending' ? pieceHeight : -pieceHeight; - return pieceHeight; - }; - - const setAreaPiecePoint = function (idx: number, pos: number, pieceHeight: number) { - const start = getLinePoints(pos, pieceAreaTop); - const end = getLinePoints(pos + pieceHeight, pieceAreaBottom); - - data.setItemLayout(idx, { - points: start.concat(end.slice().reverse()) - }); - }; - - return { getAreaPieceHeight, setAreaPiecePoint }; - })()); - } - // rate funnel about let setRatePiecePoint: ( index: number, @@ -571,9 +527,6 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { pieceHeight = sort === 'ascending' ? -pieceHeight : pieceHeight; return pieceHeight; } - else if (dynamicArea) { - return getAreaPieceHeight(val, pieceHeight); - } // default mapping or show rate pieceHeight if (pieceHeight == null) { @@ -600,10 +553,6 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { setDynamicHeightPoints(index, idx, pos, pieceHeight); return; } - else if (dynamicArea) { - setAreaPiecePoint(idx, pos, pieceHeight); - return; - } else if (showRate && sort !== 'none') { setRatePiecePoint(index, idx, nextIdx, pos, pieceHeight); return; @@ -636,7 +585,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } labelLayout(data); - if (showRate && !dynamicHeight && !dynamicArea && sort !== 'none') { + if (showRate && !dynamicHeight && sort !== 'none') { rateLabelLayout(data); } }); diff --git a/test/funnel1.html b/test/funnel-dynamicHeight.html similarity index 100% rename from test/funnel1.html rename to test/funnel-dynamicHeight.html diff --git a/test/funnel2.html b/test/funnel-showRate.html similarity index 100% rename from test/funnel2.html rename to test/funnel-showRate.html diff --git a/test/funnel3.html b/test/funnel3.html deleted file mode 100644 index 6ec4442dc1..0000000000 --- a/test/funnel3.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - -
- - - - - - \ No newline at end of file diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index b13ab35536..e4398c5596 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -89,9 +89,8 @@ "emphasis-disabled": 13, "emphasis-inherit": 1, "funnel": 2, - "funnel1": 1, - "funnel2": 1, - "funnel3": 1, + "funnel-dynamicHeight": 1, + "funnel-showRate": 1, "gauge-simple": 2, "geo-map": 4, "geo-map-features": 3, diff --git a/test/runTest/actions/funnel1.json b/test/runTest/actions/funnel-dynamicHeight.json similarity index 100% rename from test/runTest/actions/funnel1.json rename to test/runTest/actions/funnel-dynamicHeight.json diff --git a/test/runTest/actions/funnel2.json b/test/runTest/actions/funnel-showRate.json similarity index 100% rename from test/runTest/actions/funnel2.json rename to test/runTest/actions/funnel-showRate.json diff --git a/test/runTest/actions/funnel3.json b/test/runTest/actions/funnel3.json deleted file mode 100644 index 5a9187e99a..0000000000 --- a/test/runTest/actions/funnel3.json +++ /dev/null @@ -1 +0,0 @@ -[{"name":"Action 1","ops":[{"type":"mousemove","time":43,"x":648,"y":398},{"type":"mousemove","time":251,"x":658,"y":396},{"type":"mousemove","time":451,"x":747,"y":62},{"type":"mousemove","time":652,"x":696,"y":31},{"type":"mousemove","time":858,"x":693,"y":19},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"descending","time":1707,"target":"select"},{"time":1708,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1715,"x":694,"y":12},{"type":"mousemove","time":1916,"x":693,"y":12},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"ascending","time":2725,"target":"select"},{"time":2726,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":2768,"x":692,"y":13},{"type":"mousemove","time":2976,"x":691,"y":12},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"none","time":3890,"target":"select"},{"time":3891,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3952,"x":685,"y":23},{"type":"mousemove","time":4159,"x":677,"y":35},{"type":"mousemove","time":4401,"x":685,"y":18},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string>div>div.c>select","value":"ascending","time":5336,"target":"select"},{"time":5337,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":5343,"x":678,"y":38},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"horizontal","time":6373,"target":"select"},{"time":6374,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":6625,"x":674,"y":35},{"type":"mousemove","time":6826,"x":674,"y":36},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(2)>div>div.c>select","value":"vertical","time":7732,"target":"select"},{"time":7733,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7751,"x":673,"y":65},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"false","time":9024,"target":"select"},{"time":9025,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9335,"x":669,"y":68},{"type":"mousemove","time":9540,"x":669,"y":66},{"type":"valuechange","selector":"div.dg.ac>div.dg.main.a>ul>li.cr.string:nth-child(3)>div>div.c>select","value":"true","time":10784,"target":"select"},{"time":10785,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":10793,"x":542,"y":32},{"type":"mousemove","time":10993,"x":531,"y":20},{"type":"mousemove","time":11202,"x":513,"y":13},{"type":"mousemove","time":11412,"x":513,"y":12},{"type":"mousedown","time":11480,"x":513,"y":12},{"type":"mouseup","time":11559,"x":513,"y":12},{"time":11560,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":12216,"x":513,"y":12},{"type":"mouseup","time":12274,"x":513,"y":12},{"time":12275,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12367,"x":512,"y":11},{"type":"mousemove","time":12567,"x":415,"y":11},{"type":"mousemove","time":12776,"x":369,"y":15},{"type":"mousedown","time":12969,"x":381,"y":11},{"type":"mouseup","time":13028,"x":381,"y":11},{"time":13029,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":13061,"x":381,"y":11},{"type":"mousedown","time":13616,"x":381,"y":11},{"type":"mouseup","time":13741,"x":381,"y":11},{"time":13742,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":13817,"x":379,"y":11},{"type":"mousemove","time":14017,"x":284,"y":11},{"type":"mousemove","time":14217,"x":270,"y":10},{"type":"mousedown","time":14358,"x":270,"y":10},{"type":"mouseup","time":14428,"x":270,"y":10},{"time":14429,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":15067,"x":270,"y":10},{"type":"mouseup","time":15143,"x":270,"y":10},{"time":15144,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":15520,"x":270,"y":11},{"type":"mousemove","time":15720,"x":651,"y":347},{"type":"mousemove","time":15930,"x":739,"y":593}],"scrollY":112,"scrollX":0,"timestamp":1666345939904}] \ No newline at end of file From b7a2e5ca2a38cc7177540bd180911eb109d8e864 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Tue, 25 Oct 2022 19:11:53 +0800 Subject: [PATCH 20/23] feat(funnel): remove unnecessary data from label format params --- src/chart/funnel/FunnelSeries.ts | 1 + src/chart/funnel/FunnelView.ts | 98 ++++++++++++++------------------ src/chart/funnel/funnelLayout.ts | 88 ++++++++++++++-------------- test/funnel-showRate.html | 7 ++- 4 files changed, 94 insertions(+), 100 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index 4b87fe7e45..e502dd4c47 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -60,6 +60,7 @@ export interface FunnelStateOption { label?: FunnelLabelOption labelLine?: LabelLineOption rateLabel?: FunnelLabelOption + overallRateLabel?: FunnelLabelOption } export interface FunnelDataItemOption diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index cbfb526585..b9275672df 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -20,27 +20,21 @@ import * as zrUtil from 'zrender/src/core/util'; import * as graphic from '../../util/graphic'; import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; import ChartView from '../../view/Chart'; -import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries'; +import FunnelSeriesModel, { FunnelDataItemOption } from './FunnelSeries'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; import { ColorString, - DimensionLoose, DisplayState, InterpolatableValue, - OptionDataValue, SeriesDataType } from '../../util/types'; import { setLabelLineStyle, getLabelLineStatesModels } from '../../label/labelGuideHelper'; import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle'; import { saveOldStyle } from '../../animation/basicTransition'; -import { formatTpl } from '../../util/format'; -import { error } from '../../util/log'; -import { retrieveRawValue } from '../../data/helper/dataProvider'; const opacityAccessPath = ['itemStyle', 'opacity'] as const; -const DIMENSION_LABEL_REG = /\{@(.+?)\}/g; const rateLabelFetcher = { getFormattedLabel( @@ -60,17 +54,6 @@ const rateLabelFetcher = { const { hostModel, layout } = this as unknown as { hostModel: FunnelSeriesModel, layout: any }; const data = hostModel.getData(dataType); - const { rate, isLastPiece, nextName, preName } = layout; - const params = { ...hostModel.getDataParams(labelDataIndex), rate, isLastPiece, nextName, preName }; - - if (extendParams) { - params.value = extendParams.interpolatedValue; - } - - if (labelDimIndex != null && zrUtil.isArray(params.value)) { - params.value = params.value[labelDimIndex]; - } - if (!formatter) { const itemModel = data.getItemModel(labelDataIndex); // @ts-ignore @@ -78,46 +61,53 @@ const rateLabelFetcher = { ? ['rateLabel', 'formatter'] : [status, 'rateLabel', 'formatter'] ); - if (!formatter) { - return; - } } - if (zrUtil.isFunction(formatter)) { - params.status = status; - params.dimensionIndex = labelDimIndex; - return formatter(params); + + const { rate, isLastPiece, nextName, preName, preIndex, nextIndex } = layout; + + if (isLastPiece) { + const itemModel = data.getItemModel(labelDataIndex); + // @ts-ignore + formatter = itemModel.get(status === 'normal' + ? ['overallRateLabel', 'formatter'] + : [status, 'overallRateLabel', 'formatter'] + ); } - else if (zrUtil.isString(formatter)) { - params.$vars.push('preName'); // e - params.$vars.push('nextName'); // f - params.$vars.push('rate'); // g - const str = formatTpl(formatter, params); - // Support 'aaa{@[3]}bbb{@product}ccc'. - // Do not support '}' in dim name util have to. - return str.replace(DIMENSION_LABEL_REG, function (origin, dimStr: string) { - const len = dimStr.length; - - let dimLoose: DimensionLoose = dimStr; - if (dimLoose.charAt(0) === '[' && dimLoose.charAt(len - 1) === ']') { - dimLoose = +dimLoose.slice(1, len - 1); // Also support: '[]' => 0 - if (__DEV__) { - if (isNaN(dimLoose)) { - error(`Invalide label formatter: @${dimStr}, only support @[0], @[1], @[2], ...`); - } - } - } - let val = retrieveRawValue(data, labelDataIndex, dimLoose) as OptionDataValue; + type RateParams = { + rate: string, + preName : string, + nextName : string, + preIndex : string, + nextIndex : string, + isLastPiece : any, + }; - if (extendParams && zrUtil.isArray(extendParams.interpolatedValue)) { - const dimIndex = data.getDimensionIndex(dimLoose); - if (dimIndex >= 0) { - val = extendParams.interpolatedValue[dimIndex]; - } - } + const params: RateParams = { + rate, // a + preName, // b + nextName, // c + preIndex, // d + nextIndex, // e + isLastPiece + }; - return val != null ? val + '' : ''; - }); + const maps = [ + ['a', 'rate'], + ['b', 'preName'], + ['c', 'nextName'], + ['d', 'preIndex'], + ['e', 'nextIndex'] + ]; + + if (zrUtil.isFunction(formatter)) { + return formatter(params); + } + else if (zrUtil.isString(formatter)) { + return maps.reduce( + (preStr, curMap) => preStr.replace('{' + curMap[0] + '}', + params[curMap[1] as keyof RateParams]), formatter + ); } return ''; } @@ -374,7 +364,7 @@ class FunnelView extends ChartView { this._data = null; } - dispose() {} + dispose() { } } diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 3841e59378..1d7ff07115 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -18,7 +18,7 @@ */ import * as layout from '../../util/layout'; -import {parsePercent, linearMap} from '../../util/number'; +import { parsePercent, linearMap } from '../../util/number'; import FunnelSeriesModel, { FunnelSeriesOption, FunnelDataItemOption } from './FunnelSeries'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -28,9 +28,9 @@ import { isFunction } from 'zrender/src/core/util'; function getViewRect(seriesModel: FunnelSeriesModel, api: ExtensionAPI) { return layout.getLayoutRect( seriesModel.getBoxLayoutParams(), { - width: api.getWidth(), - height: api.getHeight() - } + width: api.getWidth(), + height: api.getHeight() + } ); } @@ -353,17 +353,6 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { } indices = indices.reverse(); } - else { - if (!dynamicHeight) { - gap = -gap; - if (orient === 'horizontal') { - x += viewWidth; - } - else { - y += viewHeight; - } - } - } const getLinePoints = function (offset: number, itemSize: number) { // do not caculate line width in this func @@ -452,8 +441,42 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { pos: number, pieceHeight: number ) => void | null = null; - let getConverRate: (index: number, idx: number, nextIdx: number) => any | null = null; + if (showRate) { + const getConverRate = (function () { + let firstVal: number; + let firstName: string; + let firstIndex: number; + // get rate fixed decimal places + const rateFixed = seriesModel.get('rateFixed'); + return function (index: number, idx: number, nextIdx: number) { + const val = data.get(valueDim, idx) as number || 0; + const nextVal = data.get(valueDim, nextIdx) as number || 0; + let preName = data.getName(idx); + let nextName = data.getName(nextIdx); + let preIndex = idx; + let nextIndex = nextIdx; + let rate: number | string = nextVal / val; + rate = (rate * 100).toFixed(rateFixed) + '%'; + if (index === 0) { + firstVal = val; + firstName = data.getName(idx); + firstIndex = idx; + } + else if (index === indices.length - 1) { + const lastVal = val; + rate = lastVal / firstVal; + rate = (rate * 100).toFixed(rateFixed) + '%'; + nextName = preName; + preName = firstName; + preIndex = firstIndex; + nextIndex = idx; + } + preIndex = preIndex + 1; + nextIndex = nextIndex + 1; + return { rate, nextName, preName, preIndex, nextIndex }; + }; + })(); setRatePiecePoint = function ( index: number, idx: number, @@ -477,7 +500,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const rateEnd = getLinePoints(pos + pieceHeight, nextSize); // rate string about - const { rate, nextName, preName } = getConverRate(index, idx, nextIdx); + const { rate, nextName, preName, preIndex, nextIndex } = getConverRate(index, idx, nextIdx); data.setItemLayout(idx, { points: dataStart.concat(dataEnd.slice().reverse()), @@ -485,35 +508,12 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { isLastPiece: index === indices.length - 1, rate, nextName, - preName + preName, + preIndex, + nextIndex }); }; - getConverRate = (function () { - let firstVal: number; - let firstName: string; - // get rate fixed decimal places - const rateFixed = seriesModel.get('rateFixed'); - return function (index: number, idx: number, nextIdx: number) { - const val = data.get(valueDim, idx) as number || 0; - const nextVal = data.get(valueDim, nextIdx) as number || 0; - let preName = data.getName(idx); - let nextName = data.getName(nextIdx); - let rate: number | string = nextVal / val; - rate = (rate * 100).toFixed(rateFixed) + '%'; - if (index === 0) { - firstVal = val; - firstName = data.getName(idx); - } - else if (index === indices.length - 1) { - const lastVal = val; - rate = lastVal / firstVal; - rate = (rate * 100).toFixed(rateFixed) + '%'; - nextName = preName; - preName = firstName; - } - return { rate, nextName, preName }; - }; - })(); + } // get the height of funnel piece diff --git a/test/funnel-showRate.html b/test/funnel-showRate.html index 8676652c83..18bfd7c9a7 100644 --- a/test/funnel-showRate.html +++ b/test/funnel-showRate.html @@ -86,12 +86,15 @@ } }, rateLabel: { - formatter: '{e}-{f} {g}' + formatter: '{b}-{c} {a}' + }, + overallRateLabel:{ + formatter: 'Overall rate {a}' }, data: [ { value: 60, name: '访问' }, { value: 40, name: '咨询' }, - { value: 20, name: '订单', rateLabel: { formatter: 'Overall rate {g}' } }, + { value: 20, name: '订单' }, { value: 80, name: '点击' }, { value: 100, name: '展现' } ] From 19d9b6b14304e9fdc1e07e75ce3d1b0a38f2681f Mon Sep 17 00:00:00 2001 From: gxd3 Date: Thu, 27 Oct 2022 21:24:29 +0800 Subject: [PATCH 21/23] feat(funnel): remove tpl from rate label fomatter --- src/chart/funnel/FunnelView.ts | 29 +++++++---------------------- src/chart/funnel/funnelLayout.ts | 27 +++++++++++++-------------- test/funnel-showRate.html | 6 +++--- 3 files changed, 23 insertions(+), 39 deletions(-) diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index b9275672df..e715680337 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -20,7 +20,7 @@ import * as zrUtil from 'zrender/src/core/util'; import * as graphic from '../../util/graphic'; import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; import ChartView from '../../view/Chart'; -import FunnelSeriesModel, { FunnelDataItemOption } from './FunnelSeries'; +import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -63,7 +63,7 @@ const rateLabelFetcher = { ); } - const { rate, isLastPiece, nextName, preName, preIndex, nextIndex } = layout; + const { rate, isLastPiece, nextName, preName, preDataIndex, nextDataIndex } = layout; if (isLastPiece) { const itemModel = data.getItemModel(labelDataIndex); @@ -78,37 +78,22 @@ const rateLabelFetcher = { rate: string, preName : string, nextName : string, - preIndex : string, - nextIndex : string, - isLastPiece : any, + preDataIndex : string, + nextDataIndex : string, }; const params: RateParams = { rate, // a preName, // b nextName, // c - preIndex, // d - nextIndex, // e - isLastPiece + preDataIndex, // d + nextDataIndex // e }; - const maps = [ - ['a', 'rate'], - ['b', 'preName'], - ['c', 'nextName'], - ['d', 'preIndex'], - ['e', 'nextIndex'] - ]; - if (zrUtil.isFunction(formatter)) { return formatter(params); } - else if (zrUtil.isString(formatter)) { - return maps.reduce( - (preStr, curMap) => preStr.replace('{' + curMap[0] + '}', - params[curMap[1] as keyof RateParams]), formatter - ); - } + return ''; } }; diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 1d7ff07115..89033a0253 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -18,7 +18,7 @@ */ import * as layout from '../../util/layout'; -import { parsePercent, linearMap } from '../../util/number'; +import {parsePercent, linearMap} from '../../util/number'; import FunnelSeriesModel, { FunnelSeriesOption, FunnelDataItemOption } from './FunnelSeries'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -446,7 +446,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const getConverRate = (function () { let firstVal: number; let firstName: string; - let firstIndex: number; + let firstDataIndex: number; // get rate fixed decimal places const rateFixed = seriesModel.get('rateFixed'); return function (index: number, idx: number, nextIdx: number) { @@ -454,14 +454,14 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const nextVal = data.get(valueDim, nextIdx) as number || 0; let preName = data.getName(idx); let nextName = data.getName(nextIdx); - let preIndex = idx; - let nextIndex = nextIdx; + let preDataIndex = idx; + let nextDataIndex = nextIdx; let rate: number | string = nextVal / val; rate = (rate * 100).toFixed(rateFixed) + '%'; if (index === 0) { firstVal = val; firstName = data.getName(idx); - firstIndex = idx; + firstDataIndex = idx; } else if (index === indices.length - 1) { const lastVal = val; @@ -469,12 +469,12 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { rate = (rate * 100).toFixed(rateFixed) + '%'; nextName = preName; preName = firstName; - preIndex = firstIndex; - nextIndex = idx; + preDataIndex = firstDataIndex; + nextDataIndex = idx; } - preIndex = preIndex + 1; - nextIndex = nextIndex + 1; - return { rate, nextName, preName, preIndex, nextIndex }; + preDataIndex = preDataIndex + 1; + nextDataIndex = nextDataIndex + 1; + return { rate, nextName, preName, preDataIndex, nextDataIndex }; }; })(); setRatePiecePoint = function ( @@ -500,8 +500,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { const rateEnd = getLinePoints(pos + pieceHeight, nextSize); // rate string about - const { rate, nextName, preName, preIndex, nextIndex } = getConverRate(index, idx, nextIdx); - + const { rate, nextName, preName, preDataIndex, nextDataIndex } = getConverRate(index, idx, nextIdx); data.setItemLayout(idx, { points: dataStart.concat(dataEnd.slice().reverse()), ratePoints: rateStart.concat(rateEnd.slice().reverse()), @@ -509,8 +508,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { rate, nextName, preName, - preIndex, - nextIndex + preDataIndex, + nextDataIndex }); }; diff --git a/test/funnel-showRate.html b/test/funnel-showRate.html index 18bfd7c9a7..cffdbd9b31 100644 --- a/test/funnel-showRate.html +++ b/test/funnel-showRate.html @@ -86,10 +86,10 @@ } }, rateLabel: { - formatter: '{b}-{c} {a}' + formatter: ({ rate }) => 'rate ' + rate }, - overallRateLabel:{ - formatter: 'Overall rate {a}' + overallRateLabel: { + formatter: ({ rate }) => 'Overall rate ' + rate }, data: [ { value: 60, name: '访问' }, From f4d568148484175fa0c2e8b2ce75ea578f8b897d Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sun, 30 Oct 2022 22:36:44 +0800 Subject: [PATCH 22/23] feat(funnel): fix overall rate label set styles separately --- src/chart/funnel/FunnelSeries.ts | 23 ++++++++++++----------- src/chart/funnel/FunnelView.ts | 17 +++++++++-------- src/chart/funnel/funnelLayout.ts | 13 +++++++------ test/funnel-showRate.html | 6 ++++-- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts index e502dd4c47..83aa8112ce 100644 --- a/src/chart/funnel/FunnelSeries.ts +++ b/src/chart/funnel/FunnelSeries.ts @@ -48,6 +48,10 @@ type FunnelLabelOption = Omit & { | 'outer' | 'inner' | 'center' | 'rightTop' | 'rightBottom' | 'leftTop' | 'leftBottom' }; +type FunnelRateLabelOption = Omit & { + precision: number +}; + interface FunnelStatesMixin { emphasis?: DefaultStatesMixinEmphasis } @@ -59,8 +63,8 @@ export interface FunnelStateOption { itemStyle?: ItemStyleOption label?: FunnelLabelOption labelLine?: LabelLineOption - rateLabel?: FunnelLabelOption - overallRateLabel?: FunnelLabelOption + rateLabel?: FunnelRateLabelOption + overallRateLabel?: FunnelRateLabelOption } export interface FunnelDataItemOption @@ -103,12 +107,6 @@ export interface FunnelSeriesOption showRate?: boolean dynamicHeight?: boolean - - /** - * @param rateFixed determine how much decimal places rate will keep - */ - - rateFixed?: number } class FunnelSeriesModel extends SeriesModel { @@ -188,7 +186,11 @@ class FunnelSeriesModel extends SeriesModel { }, rateLabel: { show: true, - position: 'center' + precision: 2 + }, + overallRateLabel: { + show: true, + precision: 2 }, labelLine: { show: true, @@ -212,8 +214,7 @@ class FunnelSeriesModel extends SeriesModel { itemStyle: { borderColor: '#212121' } - }, - rateFixed: 0 + } }; } diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index e715680337..1688149dfb 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -20,7 +20,7 @@ import * as zrUtil from 'zrender/src/core/util'; import * as graphic from '../../util/graphic'; import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; import ChartView from '../../view/Chart'; -import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries'; +import FunnelSeriesModel, { FunnelDataItemOption } from './FunnelSeries'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import SeriesData from '../../data/SeriesData'; @@ -76,10 +76,10 @@ const rateLabelFetcher = { type RateParams = { rate: string, - preName : string, - nextName : string, - preDataIndex : string, - nextDataIndex : string, + preName: string, + nextName: string, + preDataIndex: string, + nextDataIndex: string, }; const params: RateParams = { @@ -151,7 +151,7 @@ class FunnelPiece extends graphic.Polygon { if (firstCreate) { polygon.setShape({ - points: points + points }); polygon.style.opacity = 0; graphic.initProps(polygon, { @@ -166,7 +166,7 @@ class FunnelPiece extends graphic.Polygon { opacity: opacity }, shape: { - points: points + points } }, seriesModel, idx); } @@ -204,11 +204,12 @@ class FunnelPiece extends graphic.Polygon { ) }; } + const rateLabel = layout.isLastPiece ? 'overallRateLabel' : 'rateLabel'; setLabelStyle( // position will not be used in setLabelStyle labelText, - getLabelStatesModels(itemModel, type === 'data' ? undefined : 'rateLabel'), + getLabelStatesModels(itemModel, type === 'data' ? undefined : rateLabel), { labelFetcher: type === 'data' ? data.hostModel as FunnelSeriesModel : rateFetcher, labelDataIndex: idx, diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index 89033a0253..e73c0161fc 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -28,9 +28,9 @@ import { isFunction } from 'zrender/src/core/util'; function getViewRect(seriesModel: FunnelSeriesModel, api: ExtensionAPI) { return layout.getLayoutRect( seriesModel.getBoxLayoutParams(), { - width: api.getWidth(), - height: api.getHeight() - } + width: api.getWidth(), + height: api.getHeight() + } ); } @@ -448,7 +448,8 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { let firstName: string; let firstDataIndex: number; // get rate fixed decimal places - const rateFixed = seriesModel.get('rateFixed'); + const ratePrecision = seriesModel.get(['rateLabel', 'precision']); + const overallRatePrecision = seriesModel.get(['overallRateLabel', 'precision']); return function (index: number, idx: number, nextIdx: number) { const val = data.get(valueDim, idx) as number || 0; const nextVal = data.get(valueDim, nextIdx) as number || 0; @@ -457,7 +458,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { let preDataIndex = idx; let nextDataIndex = nextIdx; let rate: number | string = nextVal / val; - rate = (rate * 100).toFixed(rateFixed) + '%'; + rate = (rate * 100).toFixed(ratePrecision) + '%'; if (index === 0) { firstVal = val; firstName = data.getName(idx); @@ -466,7 +467,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { else if (index === indices.length - 1) { const lastVal = val; rate = lastVal / firstVal; - rate = (rate * 100).toFixed(rateFixed) + '%'; + rate = (rate * 100).toFixed(overallRatePrecision) + '%'; nextName = preName; preName = firstName; preDataIndex = firstDataIndex; diff --git a/test/funnel-showRate.html b/test/funnel-showRate.html index cffdbd9b31..a66a77af03 100644 --- a/test/funnel-showRate.html +++ b/test/funnel-showRate.html @@ -86,10 +86,12 @@ } }, rateLabel: { - formatter: ({ rate }) => 'rate ' + rate + formatter: ({ rate }) => 'rate ' + rate, }, overallRateLabel: { - formatter: ({ rate }) => 'Overall rate ' + rate + formatter: ({ rate }) => 'Overall rate ' + rate, + precision: 0, + color: 'red' }, data: [ { value: 60, name: '访问' }, From ebda31ab0e95b018f8a682e6535384e5cafb60b8 Mon Sep 17 00:00:00 2001 From: gxd3 Date: Sun, 30 Oct 2022 22:56:31 +0800 Subject: [PATCH 23/23] feat(funnel): give formatter in params --- src/chart/funnel/FunnelView.ts | 4 +++- src/chart/funnel/funnelLayout.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts index 1688149dfb..60b49a7076 100644 --- a/src/chart/funnel/FunnelView.ts +++ b/src/chart/funnel/FunnelView.ts @@ -80,6 +80,7 @@ const rateLabelFetcher = { nextName: string, preDataIndex: string, nextDataIndex: string, + formatter: string | ((params: object) => string) }; const params: RateParams = { @@ -87,7 +88,8 @@ const rateLabelFetcher = { preName, // b nextName, // c preDataIndex, // d - nextDataIndex // e + nextDataIndex, // e + formatter }; if (zrUtil.isFunction(formatter)) { diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts index e73c0161fc..335ee0d6f2 100644 --- a/src/chart/funnel/funnelLayout.ts +++ b/src/chart/funnel/funnelLayout.ts @@ -488,7 +488,7 @@ export default function funnelLayout(ecModel: GlobalModel, api: ExtensionAPI) { // get this size const itemSize = getItemSize(idx); let exitSize = itemSize; - if (exitWidth !== undefined && index === indices.length - 1) { + if (exitWidth != null && index === indices.length - 1) { exitSize = itemSize * (exitWidth > 100 ? 100 : exitWidth) / 100; } // data piece