You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2020/09/07 05:27:41 UTC
[incubator-echarts] 01/01: fix: (1) Fix some buggy display result
in tooltip, like 2 value axis scatter,
add add test cases for them. (2) Buggy results in tooltip.renderModel:
'richText' for each cases. And add test cases for them. (3) Add styles to
renderMode: 'richText',
make them the same as renderMode: 'html'. (4) Make `tooltip.confine` default
`true` if `tooltip.renderMode` is `richText`. And fix the positioning of it
to avoid to overflow the container,
which will be cut. (5) Fix the `tooltip.formatter` callbac [...]
This is an automated email from the ASF dual-hosted git repository.
sushuang pushed a commit to branch new-tooltip2
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
commit bb4559fe4c6be0cc6cd16d445ec34f99d8503143
Author: 100pah <su...@gmail.com>
AuthorDate: Mon Sep 7 13:24:43 2020 +0800
fix:
(1) Fix some buggy display result in tooltip, like 2 value axis scatter, add add test cases for them.
(2) Buggy results in tooltip.renderModel: 'richText' for each cases. And add test cases for them.
(3) Add styles to renderMode: 'richText', make them the same as renderMode: 'html'.
(4) Make `tooltip.confine` default `true` if `tooltip.renderMode` is `richText`. And fix the positioning of it to avoid to overflow the container, which will be cut.
(5) Fix the `tooltip.formatter` callback in `renderMode: 'richText'`, previously the concatenating rich text by `params.marker.content` does not work.
(6) Refactor the implementation of `Series['formatTooltip']`:
Add a abstract layer named `TooltipMarkup` to describe the tooltip layout requirement for each series,
instead of lots of messy code to concatenate `html` and `richText` in each series.
`TooltipMarkup` is responsible for generating `html` or `richText` finally.
Add `TooltipMarkup` is also in charge of sort the tooltip by `valueAsc`, `valueDesc`, `seriesAsc`, `seriesDesc`.
[TEST_CASES]: test/new-tooltip.html
[PENDING]: Do we need to expose API (like `tooltipMarkup.ts#TooltipMarkupStyleCreator`) to `tooltip.formatter` callback, by which users can add richText style themselves. At present users is not able to do that.
But if we expose that kind of API, there is an issue:
should we use ZRender style (use `fill` to describe text color)
or ECharts label style (use `color` to describe text color).
---
src/chart/graph/GraphSeries.ts | 38 +-
src/chart/lines/LinesSeries.ts | 18 +-
src/chart/map/MapSeries.ts | 30 +-
src/chart/radar/RadarSeries.ts | 67 +-
src/chart/sankey/SankeySeries.ts | 43 +-
src/chart/themeRiver/ThemeRiverSeries.ts | 28 +-
src/chart/tree/TreeSeries.ts | 25 +-
src/chart/treemap/TreemapSeries.ts | 19 +-
src/component/axisPointer/axisTrigger.ts | 4 +-
src/component/marker/MarkerModel.ts | 37 +-
src/component/timeline/SliderTimelineModel.ts | 2 +-
src/component/timeline/SliderTimelineView.ts | 5 +-
src/component/tooltip/TooltipHTMLContent.ts | 49 +-
src/component/tooltip/TooltipModel.ts | 10 +-
src/component/tooltip/TooltipRichContent.ts | 76 +-
src/component/tooltip/TooltipView.ts | 301 ++++----
.../tooltip/helper.ts} | 32 +-
src/component/tooltip/seriesFormatTooltip.ts | 154 ++++
src/component/tooltip/tooltipMarkup.ts | 529 +++++++++++++
src/coord/radar/IndicatorAxis.ts | 2 -
src/model/Series.ts | 191 +----
src/model/mixin/dataFormat.ts | 83 ++-
src/util/format.ts | 121 ++-
src/util/log.ts | 2 +-
src/util/model.ts | 5 +-
src/util/number.ts | 9 +
src/util/time.ts | 2 +-
src/util/types.ts | 8 +-
test/new-tooltip.html | 825 ++++++++++++++-------
29 files changed, 1765 insertions(+), 950 deletions(-)
diff --git a/src/chart/graph/GraphSeries.ts b/src/chart/graph/GraphSeries.ts
index 9cac9cf..1623c9c 100644
--- a/src/chart/graph/GraphSeries.ts
+++ b/src/chart/graph/GraphSeries.ts
@@ -21,7 +21,6 @@ import List from '../../data/List';
import * as zrUtil from 'zrender/src/core/util';
import {defaultEmphasis} from '../../util/model';
import Model from '../../model/Model';
-import {encodeHTML} from '../../util/format';
import createGraphFromNodeEdge from '../helper/createGraphFromNodeEdge';
import LegendVisualProvider from '../../visual/LegendVisualProvider';
import {
@@ -43,8 +42,7 @@ import {
LineLabelOption,
StatesOptionMixin,
GraphEdgeItemObject,
- OptionDataValueNumeric,
- TooltipRenderMode
+ OptionDataValueNumeric
} from '../../util/types';
import SeriesModel from '../../model/Series';
import Graph from '../../data/Graph';
@@ -52,6 +50,8 @@ import GlobalModel from '../../model/Global';
import { VectorArray } from 'zrender/src/core/vector';
import { ForceLayoutInstance } from './forceLayout';
import { LineDataVisual } from '../../visual/commonVisualTypes';
+import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
+import { defaultSeriesFormatTooltip } from '../../component/tooltip/seriesFormatTooltip';
type GraphDataValue = OptionDataValue | OptionDataValue[];
@@ -333,14 +333,10 @@ class GraphSeriesModel extends SeriesModel<GraphSeriesOption> {
return this._categoriesData;
}
- /**
- * @override
- */
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
- dataType: string,
- renderMode: TooltipRenderMode
+ dataType: string
) {
if (dataType === 'edge') {
const nodeData = this.getData();
@@ -349,19 +345,23 @@ class GraphSeriesModel extends SeriesModel<GraphSeriesOption> {
const sourceName = nodeData.getName(edge.node1.dataIndex);
const targetName = nodeData.getName(edge.node2.dataIndex);
- const html = [];
- sourceName != null && html.push(sourceName);
- targetName != null && html.push(targetName);
- let htmlStr = encodeHTML(html.join(' > '));
+ const nameArr = [];
+ sourceName != null && nameArr.push(sourceName);
+ targetName != null && nameArr.push(targetName);
- if (params.value) {
- htmlStr += ' : ' + encodeHTML(params.value);
- }
- return htmlStr;
- }
- else { // dataType === 'node' or empty
- return super.formatTooltip.apply(this, arguments as any);
+ return createTooltipMarkup('nameValue', {
+ name: nameArr.join(' > '),
+ value: params.value,
+ noValue: params.value == null
+ });
}
+ // dataType === 'node' or empty
+ const nodeMarkup = defaultSeriesFormatTooltip({
+ series: this,
+ dataIndex: dataIndex,
+ multipleSeries: multipleSeries
+ });
+ return nodeMarkup;
}
_updateCategoriesData() {
diff --git a/src/chart/lines/LinesSeries.ts b/src/chart/lines/LinesSeries.ts
index 905a49c..a75d7e4 100644
--- a/src/chart/lines/LinesSeries.ts
+++ b/src/chart/lines/LinesSeries.ts
@@ -22,7 +22,6 @@
import SeriesModel from '../../model/Series';
import List from '../../data/List';
import { concatArray, mergeAll, map } from 'zrender/src/core/util';
-import {encodeHTML} from '../../util/format';
import CoordinateSystem from '../../CoordinateSystem';
import {
SeriesOption,
@@ -34,11 +33,11 @@ import {
LineStyleOption,
OptionDataValue,
LineLabelOption,
- StatesOptionMixin,
- TooltipRenderMode
+ StatesOptionMixin
} from '../../util/types';
import GlobalModel from '../../model/Global';
import type { LineDrawModelOption } from '../helper/LineDraw';
+import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
const Uint32Arr = typeof Uint32Array === 'undefined' ? Array : Uint32Array;
const Float64Arr = typeof Float64Array === 'undefined' ? Array : Float64Array;
@@ -324,8 +323,7 @@ class LinesSeriesModel extends SeriesModel<LinesSeriesOption> {
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
- dataType: string,
- renderMode: TooltipRenderMode
+ dataType: string
) {
const data = this.getData();
const itemModel = data.getItemModel<LinesDataItemOption>(dataIndex);
@@ -335,11 +333,13 @@ class LinesSeriesModel extends SeriesModel<LinesSeriesOption> {
}
const fromName = itemModel.get('fromName');
const toName = itemModel.get('toName');
- const html = [];
- fromName != null && html.push(fromName);
- toName != null && html.push(toName);
+ const nameArr = [];
+ fromName != null && nameArr.push(fromName);
+ toName != null && nameArr.push(toName);
- return encodeHTML(html.join(' > '));
+ return createTooltipMarkup('nameValue', {
+ name: nameArr.join(' > ')
+ });
}
preventIncremental() {
diff --git a/src/chart/map/MapSeries.ts b/src/chart/map/MapSeries.ts
index 98d4c66..0354b4d 100644
--- a/src/chart/map/MapSeries.ts
+++ b/src/chart/map/MapSeries.ts
@@ -21,7 +21,6 @@
import * as zrUtil from 'zrender/src/core/util';
import createListSimply from '../helper/createListSimply';
import SeriesModel from '../../model/Series';
-import {encodeHTML, addCommas, concatTooltipHtml} from '../../util/format';
import geoSourceManager from '../../coord/geo/geoSourceManager';
import {makeSeriesEncodeForNameBased} from '../../data/helper/sourceHelper';
import {
@@ -34,14 +33,14 @@ import {
OptionDataValueNumeric,
ParsedValue,
SeriesOnGeoOptionMixin,
- StatesOptionMixin,
- TooltipRenderMode
+ StatesOptionMixin
} from '../../util/types';
import { Dictionary } from 'zrender/src/core/types';
import GeoModel, { GeoCommonOptionMixin, GeoItemStyleOption } from '../../coord/geo/GeoModel';
import List from '../../data/List';
import Model from '../../model/Model';
import Geo from '../../coord/geo/Geo';
+import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
export interface MapStateOption {
itemStyle?: GeoItemStyleOption
@@ -185,12 +184,11 @@ class MapSeries extends SeriesModel<MapSeriesOption> {
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
- dataType: string,
- renderMode: TooltipRenderMode
- ): string {
+ dataType: string
+ ) {
// FIXME orignalData and data is a bit confusing
const data = this.getData();
- const formattedValue = addCommas(this.getRawValue(dataIndex));
+ const value = this.getRawValue(dataIndex);
const name = data.getName(dataIndex);
const seriesGroup = this.seriesGroup;
@@ -199,19 +197,17 @@ class MapSeries extends SeriesModel<MapSeriesOption> {
const otherIndex = seriesGroup[i].originalData.indexOfName(name);
const valueDim = data.mapDimension('value');
if (!isNaN(seriesGroup[i].originalData.get(valueDim, otherIndex) as number)) {
- seriesNames.push(
- encodeHTML(seriesGroup[i].name)
- );
+ seriesNames.push(seriesGroup[i].name);
}
}
- if (renderMode === 'richText') {
- return seriesNames.join(', ') + (seriesNames.length ? '\n' : '')
- + encodeHTML(name) + ': ' + formattedValue;
- }
-
- return `<div style="font-size:12px;color:#6e7079;">${seriesNames.join(', ')}</div>`
- + concatTooltipHtml(name, formattedValue);
+ return createTooltipMarkup('section', {
+ header: seriesNames.join(', '),
+ noHeader: !seriesNames.length,
+ blocks: [createTooltipMarkup('nameValue', {
+ name: name, value: value
+ })]
+ });
}
getTooltipPosition = function (this: MapSeries, dataIndex: number): number[] {
diff --git a/src/chart/radar/RadarSeries.ts b/src/chart/radar/RadarSeries.ts
index 4c99034..f7c5175 100644
--- a/src/chart/radar/RadarSeries.ts
+++ b/src/chart/radar/RadarSeries.ts
@@ -20,7 +20,6 @@
import SeriesModel from '../../model/Series';
import createListSimply from '../helper/createListSimply';
import * as zrUtil from 'zrender/src/core/util';
-import {encodeHTML, concatTooltipHtml} from '../../util/format';
import LegendVisualProvider from '../../visual/LegendVisualProvider';
import {
SeriesOption,
@@ -31,13 +30,12 @@ import {
AreaStyleOption,
OptionDataValue,
StatesOptionMixin,
- OptionDataItemObject,
- TooltipRenderMode,
- TooltipOrderMode
+ OptionDataItemObject
} from '../../util/types';
import GlobalModel from '../../model/Global';
import List from '../../data/List';
import Radar from '../../coord/radar/Radar';
+import { createTooltipMarkup, retrieveVisualColorForTooltipMarker as retrieveVisualColorForTooltip } from '../../component/tooltip/tooltipMarkup';
type RadarSeriesDataValue = OptionDataValue[];
@@ -98,60 +96,31 @@ class RadarSeriesModel extends SeriesModel<RadarSeriesOption> {
formatTooltip(
dataIndex: number,
multipleSeries?: boolean,
- dataType?: string,
- renderMode?: TooltipRenderMode,
- order?: TooltipOrderMode
+ dataType?: string
) {
const data = this.getData();
const coordSys = this.coordinateSystem;
const indicatorAxes = coordSys.getIndicatorAxes();
const name = this.getData().getName(dataIndex);
- zrUtil.each(indicatorAxes, function (axis, idx) {
- axis.value = data.get(data.mapDimension(axis.dim), dataIndex);
- });
- switch (order) {
- case 'valueAsc':
- indicatorAxes.sort(function (a, b) {
- return +(a.value) - +(b.value);
- });
- break;
-
- case 'valueDesc':
- indicatorAxes.sort(function (a, b) {
- return +(b.value) - +(a.value);
- });
- break;
-
- case 'seriesDesc':
- indicatorAxes.reverse();
- break;
+ const nameToDisplay = name === '' ? this.name : name;
+ const markerColor = retrieveVisualColorForTooltip(this, dataIndex);
- case 'seriesAsc':
- default:
- break;
- }
-
- if (renderMode === 'richText') {
- return encodeHTML(name === '' ? this.name : name) + '\n'
- + zrUtil.map(indicatorAxes, function (axis) {
- const val = data.get(data.mapDimension(axis.dim), dataIndex);
- return encodeHTML(axis.name) + ': ' + val;
- }).join('\n');
- }
- return '<div style="font-size:12px;color:#6e7079;line-height:1;margin-top:-4px;">'
- + encodeHTML(name === '' ? this.name : name)
- + '</div>'
- + zrUtil.map(indicatorAxes, function (axis) {
+ return createTooltipMarkup('section', {
+ header: nameToDisplay,
+ sortBlocks: true,
+ blocks: zrUtil.map(indicatorAxes, axis => {
const val = data.get(data.mapDimension(axis.dim), dataIndex);
- return '<div style="margin: 11px 0 0;line-height:1">'
- + concatTooltipHtml(axis.name, val)
- + '</div>';
- }).join('');
+ return createTooltipMarkup('nameValue', {
+ markerType: 'subItem',
+ markerColor: markerColor,
+ name: axis.name,
+ value: val,
+ sortParam: val
+ });
+ })
+ });
}
- /**
- * @implement
- */
getTooltipPosition(dataIndex: number) {
if (dataIndex != null) {
const data = this.getData();
diff --git a/src/chart/sankey/SankeySeries.ts b/src/chart/sankey/SankeySeries.ts
index 08428f2..28d5e6f 100644
--- a/src/chart/sankey/SankeySeries.ts
+++ b/src/chart/sankey/SankeySeries.ts
@@ -19,7 +19,6 @@
import SeriesModel from '../../model/Series';
import createGraphFromNodeEdge from '../helper/createGraphFromNodeEdge';
-import {concatTooltipHtml, encodeHTML} from '../../util/format';
import Model from '../../model/Model';
import {
SeriesOption,
@@ -33,12 +32,13 @@ import {
StatesOptionMixin,
OptionDataItemObject,
GraphEdgeItemObject,
- OptionDataValueNumeric,
- TooltipRenderMode
+ OptionDataValueNumeric
} from '../../util/types';
import GlobalModel from '../../model/Global';
import List from '../../data/List';
import { LayoutRect } from '../../util/layout';
+import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
+import { defaultSeriesFormatTooltip } from '../../component/tooltip/seriesFormatTooltip';
type FocusNodeAdjacency = boolean | 'inEdges' | 'outEdges' | 'allEdges';
@@ -225,38 +225,37 @@ class SankeySeriesModel extends SeriesModel<SankeySeriesOption> {
return this.getGraph().edgeData;
}
- /**
- * @override
- */
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
- dataType: 'node' | 'edge',
- renderMode: TooltipRenderMode
+ dataType: 'node' | 'edge'
) {
+ function noValue(val: unknown): boolean {
+ return isNaN(val as number) || val == null;
+ }
// dataType === 'node' or empty do not show tooltip by default
if (dataType === 'edge') {
const params = this.getDataParams(dataIndex, dataType);
const rawDataOpt = params.data;
- if (renderMode === 'richText') {
- return encodeHTML(rawDataOpt.source + ' -- ' + rawDataOpt.target) + params.value;
- }
- return '<div style="line-height:1">'
- + concatTooltipHtml(rawDataOpt.source + ' -- ' + rawDataOpt.target, params.value || '')
- + '</div>';
+ const edgeValue = params.value;
+ const edgeName = rawDataOpt.source + ' -- ' + rawDataOpt.target;
+ return createTooltipMarkup('nameValue', {
+ name: edgeName,
+ value: edgeValue,
+ noValue: noValue(edgeValue)
+ });
}
- else if (dataType === 'node') {
+ // dataType === 'node'
+ else {
const node = this.getGraph().getNodeByIndex(dataIndex);
const value = node.getLayout().value;
const name = this.getDataParams(dataIndex, dataType).data.name;
- if (renderMode === 'richText') {
- return encodeHTML(value ? name : '') + ': ' + (value || '');
- }
- return '<div style="line-height:1">'
- + concatTooltipHtml(value ? name : '', value || '')
- + '</div>';
+ return createTooltipMarkup('nameValue', {
+ name: name,
+ value: value,
+ noValue: noValue(value)
+ });
}
- return super.formatTooltip(dataIndex, multipleSeries, dataType, renderMode);
}
optionUpdated() {
diff --git a/src/chart/themeRiver/ThemeRiverSeries.ts b/src/chart/themeRiver/ThemeRiverSeries.ts
index 3b97a25..d1650e5 100644
--- a/src/chart/themeRiver/ThemeRiverSeries.ts
+++ b/src/chart/themeRiver/ThemeRiverSeries.ts
@@ -23,7 +23,6 @@ import {getDimensionTypeByAxis} from '../../data/helper/dimensionHelper';
import List from '../../data/List';
import * as zrUtil from 'zrender/src/core/util';
import {groupData, SINGLE_REFERRING} from '../../util/model';
-import {concatTooltipHtml, encodeHTML} from '../../util/format';
import LegendVisualProvider from '../../visual/LegendVisualProvider';
import {
SeriesOption,
@@ -33,12 +32,12 @@ import {
OptionDataValueNumeric,
ItemStyleOption,
BoxLayoutOptionMixin,
- ZRColor,
- TooltipRenderMode
+ ZRColor
} from '../../util/types';
import SingleAxis from '../../coord/single/SingleAxis';
import GlobalModel from '../../model/Global';
import Single from '../../coord/single/Single';
+import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
const DATA_NAME_INDEX = 2;
@@ -285,29 +284,16 @@ class ThemeRiverSeriesModel extends SeriesModel<ThemeRiverSeriesOption> {
return {dataIndices: indices, nestestValue: nestestValue};
}
- /**
- * @override
- * @param {number} dataIndex index of data
- */
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
- dataType: string,
- renderMode: TooltipRenderMode
- ): string {
+ dataType: string
+ ) {
const data = this.getData();
- const htmlName = data.getName(dataIndex);
- let htmlValue = data.get(data.mapDimension('value'), dataIndex);
- if (isNaN(htmlValue as number) || htmlValue == null) {
- htmlValue = '-';
- }
+ const name = data.getName(dataIndex);
+ const value = data.get(data.mapDimension('value'), dataIndex);
- if (renderMode === 'richText') {
- return encodeHTML(htmlName) + ': ' + htmlValue;
- }
- return '<div style="margin: 11px 0 0;line-height:1">'
- + concatTooltipHtml(htmlName, htmlValue)
- + '</div>';
+ return createTooltipMarkup('nameValue', { name: name, value: value });
}
static defaultOption: ThemeRiverSeriesOption = {
diff --git a/src/chart/tree/TreeSeries.ts b/src/chart/tree/TreeSeries.ts
index 28f5046..e5a49f6 100644
--- a/src/chart/tree/TreeSeries.ts
+++ b/src/chart/tree/TreeSeries.ts
@@ -19,7 +19,6 @@
import SeriesModel from '../../model/Series';
import Tree from '../../data/Tree';
-import { concatTooltipHtml, encodeHTML } from '../../util/format';
import {
SeriesOption,
SymbolOptionMixin,
@@ -30,13 +29,13 @@ import {
LabelOption,
OptionDataValue,
StatesOptionMixin,
- OptionDataItemObject,
- TooltipRenderMode
+ OptionDataItemObject
} from '../../util/types';
import List from '../../data/List';
import View from '../../coord/View';
import { LayoutRect } from '../../util/layout';
import Model from '../../model/Model';
+import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
interface CurveLineStyleOption extends LineStyleOption{
curveness?: number
@@ -201,15 +200,11 @@ class TreeSeriesModel extends SeriesModel<TreeSeriesOption> {
this.option.center = center;
}
- /**
- * @override
- */
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
- dataType: string,
- renderMode: TooltipRenderMode
- ): string {
+ dataType: string
+ ) {
const tree = this.getData().tree;
const realRoot = tree.root.children[0];
let node = tree.getNodeByDataIndex(dataIndex);
@@ -220,13 +215,11 @@ class TreeSeriesModel extends SeriesModel<TreeSeriesOption> {
node = node.parentNode;
}
- if (renderMode === 'richText') {
- return encodeHTML(name) + ': ' + ((isNaN(value as number) || value == null) ? '' : value);
- }
-
- return '<div style="line-height:1">'
- + concatTooltipHtml(name, (isNaN(value as number) || value == null) ? '' : value)
- + '</div>';
+ return createTooltipMarkup('nameValue', {
+ name: name,
+ value: value,
+ noValue: isNaN(value as number) || value == null
+ });
}
static defaultOption: TreeSeriesOption = {
diff --git a/src/chart/treemap/TreemapSeries.ts b/src/chart/treemap/TreemapSeries.ts
index c622a74..5444a26 100644
--- a/src/chart/treemap/TreemapSeries.ts
+++ b/src/chart/treemap/TreemapSeries.ts
@@ -21,11 +21,6 @@ import * as zrUtil from 'zrender/src/core/util';
import SeriesModel from '../../model/Series';
import Tree, { TreeNode } from '../../data/Tree';
import Model from '../../model/Model';
-import {
- addCommas,
- concatTooltipHtml,
- encodeHTML
-} from '../../util/format';
import {wrapTreePathInfo} from '../helper/treeHelper';
import {
SeriesOption,
@@ -33,7 +28,6 @@ import {
ItemStyleOption,
LabelOption,
RoamOptionMixin,
- TooltipRenderMode,
CallbackDataParams,
ColorString,
StatesOptionMixin
@@ -42,6 +36,7 @@ import GlobalModel from '../../model/Global';
import { LayoutRect } from '../../util/layout';
import List from '../../data/List';
import { normalizeToArray } from '../../util/model';
+import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
// Only support numberic value.
type TreemapSeriesDataValue = number | number[];
@@ -377,21 +372,13 @@ class TreemapSeriesModel extends SeriesModel<TreemapSeriesOption> {
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
- dataType: string,
- renderMode: TooltipRenderMode
+ dataType: string
) {
const data = this.getData();
const value = this.getRawValue(dataIndex) as TreemapSeriesDataValue;
- const formattedValue = zrUtil.isArray(value)
- ? addCommas(value[0] as number) : addCommas(value as number);
const name = data.getName(dataIndex);
- if (renderMode === 'richText') {
- return encodeHTML(name) + ': ' + formattedValue;
- }
- return '<div style="line-height:1">'
- + concatTooltipHtml(name, formattedValue)
- + '</div>';
+ return createTooltipMarkup('nameValue', { name: name, value: value });
}
/**
diff --git a/src/component/axisPointer/axisTrigger.ts b/src/component/axisPointer/axisTrigger.ts
index f9fedc9..0bc672f 100644
--- a/src/component/axisPointer/axisTrigger.ts
+++ b/src/component/axisPointer/axisTrigger.ts
@@ -41,7 +41,7 @@ interface DataIndex {
type BatchItem = DataIndex;
-interface DataByAxis {
+export interface DataByAxis {
// TODO: TYPE Value type
value: string | number
axisIndex: number
@@ -56,7 +56,7 @@ interface DataByAxis {
formatter: AxisPointerOption['label']['formatter']
}
}
-interface DataByCoordSys {
+export interface DataByCoordSys {
coordSysId: string
coordSysIndex: number
coordSysType: string
diff --git a/src/component/marker/MarkerModel.ts b/src/component/marker/MarkerModel.ts
index 243d767..341bf5b 100644
--- a/src/component/marker/MarkerModel.ts
+++ b/src/component/marker/MarkerModel.ts
@@ -19,8 +19,7 @@
import * as zrUtil from 'zrender/src/core/util';
import env from 'zrender/src/core/env';
-import {addCommas, concatTooltipHtml, encodeHTML} from '../../util/format';
-import DataFormatMixin from '../../model/mixin/dataFormat';
+import { DataFormatMixin } from '../../model/mixin/dataFormat';
import ComponentModel from '../../model/Component';
import SeriesModel from '../../model/Series';
import {
@@ -29,13 +28,13 @@ import {
AnimationOptionMixin,
Dictionary,
CommonTooltipOption,
- ScaleDataValue,
- TooltipRenderMode
+ ScaleDataValue
} from '../../util/types';
import Model from '../../model/Model';
import GlobalModel from '../../model/Global';
import List from '../../data/List';
import { makeInner, defaultEmphasis } from '../../util/model';
+import { createTooltipMarkup } from '../tooltip/tooltipMarkup';
function fillLabel(opt: DisplayStateHostOption) {
defaultEmphasis(opt, 'label', ['show']);
@@ -201,27 +200,21 @@ abstract class MarkerModel<Opts extends MarkerOption = MarkerOption> extends Com
formatTooltip(
dataIndex: number,
multipleSeries: boolean,
- dataType: string,
- renderMode: TooltipRenderMode
+ dataType: string
) {
const data = this.getData();
const value = this.getRawValue(dataIndex);
- const formattedValue = zrUtil.isArray(value)
- ? zrUtil.map(value, addCommas).join(', ') : addCommas(value as number);
- const name = encodeHTML(data.getName(dataIndex));
- let html = `<div style="font-size:12px;line-height:1;margin:0 0 8px 0;">${encodeHTML(this.name)}</div>`;
- if (value != null || name) {
- html += renderMode === 'html' ? '' : '\n';
- }
- if (name) {
- html += `<div style="line-height:1"><span style="font-size:12px;color:#6e7079;">${name}</span>`;
- }
- if (value != null) {
- html = renderMode === 'html'
- ? concatTooltipHtml(html, formattedValue, true) + (name ? '</div>' : '')
- : (html + formattedValue);
- }
- return html;
+ const itemName = data.getName(dataIndex);
+
+ return createTooltipMarkup('section', {
+ header: this.name,
+ blocks: [createTooltipMarkup('nameValue', {
+ name: itemName,
+ value: value,
+ noName: !itemName,
+ noValue: value == null
+ })]
+ });
}
getData(): List<this> {
diff --git a/src/component/timeline/SliderTimelineModel.ts b/src/component/timeline/SliderTimelineModel.ts
index 72a96ae..a5cc4e4 100644
--- a/src/component/timeline/SliderTimelineModel.ts
+++ b/src/component/timeline/SliderTimelineModel.ts
@@ -18,7 +18,7 @@
*/
import TimelineModel, { TimelineOption } from './TimelineModel';
-import DataFormatMixin from '../../model/mixin/dataFormat';
+import { DataFormatMixin } from '../../model/mixin/dataFormat';
import ComponentModel from '../../model/Component';
import { mixin } from 'zrender/src/core/util';
import List from '../../data/List';
diff --git a/src/component/timeline/SliderTimelineView.ts b/src/component/timeline/SliderTimelineView.ts
index a088e7f..e8688f8 100644
--- a/src/component/timeline/SliderTimelineView.ts
+++ b/src/component/timeline/SliderTimelineView.ts
@@ -26,7 +26,6 @@ import TimelineView from './TimelineView';
import TimelineAxis from './TimelineAxis';
import {createSymbol} from '../../util/symbol';
import * as numberUtil from '../../util/number';
-import {encodeHTML} from '../../util/format';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../ExtensionAPI';
import { merge, each, extend, clone, isString, bind, defaults, retrieve2 } from 'zrender/src/core/util';
@@ -46,6 +45,7 @@ import { parsePercent } from 'zrender/src/contain/text';
import { makeInner } from '../../util/model';
import { getECData } from '../../util/ecData';
import { enableHoverEmphasis } from '../../util/states';
+import { createTooltipMarkup } from '../tooltip/tooltipMarkup';
const PI = Math.PI;
@@ -129,7 +129,8 @@ class SliderTimelineView extends TimelineView {
const axis = this._axis = this._createAxis(layoutInfo, timelineModel);
timelineModel.formatTooltip = function (dataIndex: number) {
- return encodeHTML(axis.scale.getLabel({value: dataIndex}));
+ const name = axis.scale.getLabel({value: dataIndex});
+ return createTooltipMarkup('nameValue', { noName: true, value: name });
};
each(
diff --git a/src/component/tooltip/TooltipHTMLContent.ts b/src/component/tooltip/TooltipHTMLContent.ts
index 8cdf33f..2545342 100644
--- a/src/component/tooltip/TooltipHTMLContent.ts
+++ b/src/component/tooltip/TooltipHTMLContent.ts
@@ -27,10 +27,12 @@ import ExtensionAPI from '../../ExtensionAPI';
import { ZRenderType } from 'zrender/src/zrender';
import { TooltipOption } from './TooltipModel';
import Model from '../../model/Model';
-import { ZRRawEvent, Dictionary } from 'zrender/src/core/types';
+import { ZRRawEvent } from 'zrender/src/core/types';
import { ColorString, ZRColor } from '../../util/types';
import CanvasPainter from 'zrender/src/canvas/Painter';
import SVGPainter from 'zrender/src/svg/Painter';
+import { shouldTooltipConfine } from './helper';
+import { getPaddingFromTooltipModel } from './tooltipMarkup';
const each = zrUtil.each;
const toCamelCase = formatUtil.toCamelCase;
@@ -50,22 +52,6 @@ function mirrowPos(pos: string): string {
return pos;
}
-
-function getFinalColor(color: ZRColor): string {
- let finalNearPointColor = '#fff';
- if (zrUtil.isObject(color) && color.type !== 'pattern') {
- finalNearPointColor = color.colorStops[0].color;
- }
- else if (zrUtil.isObject(color) && (color.type === 'pattern')) {
- finalNearPointColor = 'transparent';
- }
- else if (zrUtil.isString(color)) {
- finalNearPointColor = color;
- }
-
- return finalNearPointColor;
-}
-
function assembleArrow(
backgroundColor: ColorString,
borderColor: ZRColor,
@@ -75,7 +61,7 @@ function assembleArrow(
return '';
}
- borderColor = getFinalColor(borderColor);
+ borderColor = formatUtil.convertToColorString(borderColor);
const arrowPos = mirrowPos(arrowPosition);
let centerPos = '';
let rotate = 0;
@@ -145,7 +131,7 @@ function assembleCssText(tooltipModel: Model<TooltipOption>, isFirstShow: boolea
const shadowOffsetX = tooltipModel.get('shadowOffsetX');
const shadowOffsetY = tooltipModel.get('shadowOffsetY');
const textStyleModel = tooltipModel.getModel('textStyle');
- const padding = tooltipModel.get('padding');
+ const padding = getPaddingFromTooltipModel(tooltipModel, 'html');
const boxShadow = `${shadowOffsetX}px ${shadowOffsetY}px ${shadowBlur}px ${shadowColor}`;
cssText.push('box-shadow:' + boxShadow);
@@ -335,7 +321,7 @@ class TooltipHTMLContent {
const el = this.el;
const styleCoord = this._styleCoord;
const offset = el.offsetHeight / 2;
- nearPointColor = getFinalColor(nearPointColor);
+ nearPointColor = formatUtil.convertToColorString(nearPointColor);
el.style.cssText = gCssText + assembleCssText(tooltipModel, this._firstShow)
// Because of the reason described in:
// http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore
@@ -359,7 +345,7 @@ class TooltipHTMLContent {
setContent(
content: string,
- markers: Dictionary<ColorString>,
+ markers: unknown,
tooltipModel: Model<TooltipOption>,
borderColor?: ZRColor,
arrowPosition?: TooltipOption['position']
@@ -369,11 +355,12 @@ class TooltipHTMLContent {
}
this.el.innerHTML = content;
this.el.innerHTML += (
- zrUtil.isString(arrowPosition)
- && tooltipModel.get('trigger') === 'item'
- && !tooltipModel.get('confine')
- )
- ? assembleArrow(tooltipModel.get('backgroundColor'), borderColor, arrowPosition) : '';
+ zrUtil.isString(arrowPosition)
+ && tooltipModel.get('trigger') === 'item'
+ && !shouldTooltipConfine(tooltipModel)
+ )
+ ? assembleArrow(tooltipModel.get('backgroundColor'), borderColor, arrowPosition)
+ : '';
}
setEnterable(enterable: boolean) {
@@ -389,9 +376,13 @@ class TooltipHTMLContent {
const styleCoord = this._styleCoord;
makeStyleCoord(styleCoord, this._zr, this._appendToBody, zrX, zrY);
- const style = this.el.style;
- style.left = styleCoord[0] + 'px';
- style.top = styleCoord[1] + 'px';
+ if (styleCoord[0] != null && styleCoord[1] != null) {
+ const style = this.el.style;
+ // If using float on style, the final width of the dom might
+ // keep changing slightly while mouse move. So `toFixed(0)` them.
+ style.left = styleCoord[0].toFixed(0) + 'px';
+ style.top = styleCoord[1].toFixed(0) + 'px';
+ }
}
hide() {
diff --git a/src/component/tooltip/TooltipModel.ts b/src/component/tooltip/TooltipModel.ts
index 4b6c459..a7bd3e3 100644
--- a/src/component/tooltip/TooltipModel.ts
+++ b/src/component/tooltip/TooltipModel.ts
@@ -97,9 +97,10 @@ class TooltipModel extends ComponentModel<TooltipOption> {
renderMode: 'auto', // 'auto' | 'html' | 'richText'
- // whether restraint content inside viewRect
- // For compatibility reason, default is false
- confine: false,
+ // whether restraint content inside viewRect.
+ // If renderMode: 'richText', default true.
+ // If renderMode: 'html', defaut false (for backward compat).
+ confine: null,
showDelay: 0,
@@ -129,7 +130,8 @@ class TooltipModel extends ComponentModel<TooltipOption> {
// Tooltip inside padding, default is 5 for all direction
// Array is allowed to set up, right, bottom, left, same with css
- padding: 10,
+ // The default value: See `tooltip/tooltipMarkup.ts#getPaddingFromTooltipModel`.
+ padding: null,
// Extra css text
extraCssText: '',
diff --git a/src/component/tooltip/TooltipRichContent.ts b/src/component/tooltip/TooltipRichContent.ts
index 510b997..d9f9652 100644
--- a/src/component/tooltip/TooltipRichContent.ts
+++ b/src/component/tooltip/TooltipRichContent.ts
@@ -21,10 +21,10 @@ import * as zrUtil from 'zrender/src/core/util';
import ExtensionAPI from '../../ExtensionAPI';
import { ZRenderType } from 'zrender/src/zrender';
import { TooltipOption } from './TooltipModel';
-import { Dictionary } from 'zrender/src/core/types';
-import { ColorString, ZRColor } from '../../util/types';
+import { ZRColor } from '../../util/types';
import Model from '../../model/Model';
import ZRText, { TextStyleProps } from 'zrender/src/graphic/Text';
+import { TooltipMarkupStyleCreator, getPaddingFromTooltipModel } from './tooltipMarkup';
class TooltipRichContent {
@@ -67,7 +67,7 @@ class TooltipRichContent {
*/
setContent(
content: string,
- markerRich: Dictionary<ColorString>,
+ markupStyleCreator: TooltipMarkupStyleCreator,
tooltipModel: Model<TooltipOption>,
borderColor: ZRColor,
arrowPosition: TooltipOption['position']
@@ -76,43 +76,11 @@ class TooltipRichContent {
this._zr.remove(this.el);
}
- const markers: TextStyleProps['rich'] = {};
- let text = content;
- const prefix = '{marker';
- const suffix = '|}';
- let startId = text.indexOf(prefix);
- while (startId >= 0) {
- const endId = text.indexOf(suffix);
- const name = text.substr(startId + prefix.length, endId - startId - prefix.length);
- if (name.indexOf('sub') > -1) {
- markers['marker' + name] = {
- width: 4,
- height: 4,
- borderRadius: 2,
- backgroundColor: markerRich[name]
-
- // TODO: textOffset is not implemented for rich text
- // textOffset: [3, 0]
- };
- }
- else {
- markers['marker' + name] = {
- width: 10,
- height: 10,
- borderRadius: 5,
- backgroundColor: markerRich[name]
- };
- }
-
- text = text.substr(endId + 1);
- startId = text.indexOf(prefix);
- }
-
this.el = new ZRText({
style: {
- rich: markers,
+ rich: markupStyleCreator.richTextStyles,
text: content,
- lineHeight: 20,
+ lineHeight: 22,
backgroundColor: tooltipModel.get('backgroundColor'),
borderRadius: tooltipModel.get('borderRadius'),
borderWidth: 1,
@@ -122,7 +90,7 @@ class TooltipRichContent {
shadowOffsetX: tooltipModel.get('shadowOffsetX'),
shadowOffsetY: tooltipModel.get('shadowOffsetY'),
fill: tooltipModel.get(['textStyle', 'color']),
- padding: tooltipModel.get('padding'),
+ padding: getPaddingFromTooltipModel(tooltipModel, 'richText'),
verticalAlign: 'top',
align: 'left'
},
@@ -154,15 +122,26 @@ class TooltipRichContent {
}
getSize() {
+ const el = this.el;
const bounding = this.el.getBoundingRect();
- return [bounding.width, bounding.height];
+ // bounding rect does not include shadow. For renderMode richText,
+ // if overflow, it will be cut. So calculate them accurately.
+ const shadowOuterSize = calcShadowOuterSize(el.style);
+ return [
+ bounding.width + shadowOuterSize.left + shadowOuterSize.right,
+ bounding.height + shadowOuterSize.top + shadowOuterSize.bottom
+ ];
}
moveTo(x: number, y: number) {
const el = this.el;
if (el) {
- el.x = x;
- el.y = y;
+ const style = el.style;
+ const borderWidth = mathMaxWith0(style.borderWidth || 0);
+ const shadowOuterSize = calcShadowOuterSize(style);
+ // rich text x, y do not include border.
+ el.x = x + borderWidth + shadowOuterSize.left;
+ el.y = y + borderWidth + shadowOuterSize.top;
el.markRedraw();
}
}
@@ -205,5 +184,20 @@ class TooltipRichContent {
}
}
+function mathMaxWith0(val: number): number {
+ return Math.max(0, val);
+}
+
+function calcShadowOuterSize(style: TextStyleProps) {
+ const shadowBlur = mathMaxWith0(style.shadowBlur || 0);
+ const shadowOffsetX = mathMaxWith0(style.shadowOffsetX || 0);
+ const shadowOffsetY = mathMaxWith0(style.shadowOffsetY || 0);
+ return {
+ left: mathMaxWith0(shadowBlur - shadowOffsetX),
+ right: mathMaxWith0(shadowBlur + shadowOffsetX),
+ top: mathMaxWith0(shadowBlur - shadowOffsetY),
+ bottom: mathMaxWith0(shadowBlur + shadowOffsetY)
+ };
+}
export default TooltipRichContent;
diff --git a/src/component/tooltip/TooltipView.ts b/src/component/tooltip/TooltipView.ts
index c88bec3..d877177 100644
--- a/src/component/tooltip/TooltipView.ts
+++ b/src/component/tooltip/TooltipView.ts
@@ -47,11 +47,13 @@ import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../ExtensionAPI';
import TooltipModel, {TooltipOption} from './TooltipModel';
import Element from 'zrender/src/Element';
-import { Dictionary } from 'zrender/src/core/types';
import { AxisBaseModel } from '../../coord/AxisBaseModel';
-import { CoordinateSystem } from '../../coord/CoordinateSystem';
// import { isDimensionStacked } from '../../data/helper/dataStackHelper';
import { getECData } from '../../util/ecData';
+import { shouldTooltipConfine } from './helper';
+import { DataByCoordSys, DataByAxis } from '../axisPointer/axisTrigger';
+import { normalizeTooltipFormatResult } from '../../model/mixin/dataFormat';
+import { createTooltipMarkup, buildTooltipMarkup, TooltipMarkupStyleCreator } from './tooltipMarkup';
const bind = zrUtil.bind;
const each = zrUtil.each;
@@ -67,19 +69,6 @@ interface DataIndex {
dataIndexInside: number
}
-interface DataByAxis {
- // TODO: TYPE Value type
- value: string | number
- axisIndex: number
- axisDim: string
- axisType: string
- axisId: string
-
- seriesDataIndices: DataIndex[]
-}
-interface DataByCoordSys {
- dataByAxis: DataByAxis[]
-}
interface ShowTipPayload {
type?: 'showTip'
@@ -90,7 +79,7 @@ interface ShowTipPayload {
// Type 2
dataByCoordSys?: DataByCoordSys[]
- tooltipOption?: CommonTooltipOption<TooltipDataParams | TooltipDataParams[]>
+ tooltipOption?: CommonTooltipOption<TooltipCallbackDataParams | TooltipCallbackDataParams[]>
// Type 3
seriesIndex?: number
@@ -122,12 +111,12 @@ interface TryShowParams {
*/
dataByCoordSys?: DataByCoordSys[]
- tooltipOption?: CommonTooltipOption<TooltipDataParams | TooltipDataParams[]>
+ tooltipOption?: CommonTooltipOption<TooltipCallbackDataParams | TooltipCallbackDataParams[]>
position?: TooltipOption['position']
}
-type TooltipDataParams = CallbackDataParams & {
+type TooltipCallbackDataParams = CallbackDataParams & {
axisDim?: string
axisIndex?: number
axisType?: string
@@ -136,19 +125,14 @@ type TooltipDataParams = CallbackDataParams & {
axisValue?: string | number
axisValueLabel?: string
marker?: formatUtil.TooltipMarker
- // params below should not be exposed to callback
- html?: string
- position?: number[]
- coordinateSystem?: CoordinateSystem
};
+
class TooltipView extends ComponentView {
static type = 'tooltip' as const;
type = TooltipView.type;
private _renderMode: TooltipRenderMode;
- private _newLine: '' | '\n';
-
private _tooltipModel: TooltipModel;
private _ecModel: GlobalModel;
@@ -179,19 +163,11 @@ class TooltipView extends ComponentView {
const renderMode = tooltipModel.get('renderMode');
this._renderMode = getTooltipRenderMode(renderMode);
- let tooltipContent;
- if (this._renderMode === 'html') {
- tooltipContent = new TooltipHTMLContent(api.getDom(), api, {
+ this._tooltipContent = this._renderMode === 'richText'
+ ? new TooltipRichContent(api)
+ : new TooltipHTMLContent(api.getDom(), api, {
appendToBody: tooltipModel.get('appendToBody', true)
});
- this._newLine = '';
- }
- else {
- tooltipContent = new TooltipRichContent(api);
- this._newLine = '\n';
- }
-
- this._tooltipContent = tooltipContent;
}
render(
@@ -227,7 +203,7 @@ class TooltipView extends ComponentView {
this._keepShow();
}
- _initGlobalListener() {
+ private _initGlobalListener() {
const tooltipModel = this._tooltipModel;
const triggerOn = tooltipModel.get('triggerOn');
@@ -248,7 +224,7 @@ class TooltipView extends ComponentView {
);
}
- _keepShow() {
+ private _keepShow() {
const tooltipModel = this._tooltipModel;
const ecModel = this._ecModel;
const api = this._api;
@@ -390,7 +366,7 @@ class TooltipView extends ComponentView {
// Be compatible with previous design, that is, when tooltip.type is 'axis' and
// dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer
// and tooltip.
- _manuallyAxisShowTip(
+ private _manuallyAxisShowTip(
tooltipModel: TooltipModel,
ecModel: GlobalModel,
api: ExtensionAPI,
@@ -432,7 +408,7 @@ class TooltipView extends ComponentView {
return true;
}
- _tryShow(
+ private _tryShow(
e: TryShowParams,
dispatchAction: ExtensionAPI['dispatchAction']
) {
@@ -467,7 +443,7 @@ class TooltipView extends ComponentView {
}
}
- _showOrMove(
+ private _showOrMove(
tooltipModel: Model<TooltipOption>,
cb: () => void
) {
@@ -483,26 +459,26 @@ class TooltipView extends ComponentView {
: cb();
}
- _showAxisTooltip(
+ private _showAxisTooltip(
dataByCoordSys: DataByCoordSys[],
e: TryShowParams
) {
const ecModel = this._ecModel;
const globalTooltipModel = this._tooltipModel;
-
const point = [e.offsetX, e.offsetY];
-
- const singleDefaultHTML: string[] = [];
- const singleParamsList: TooltipDataParams[] = [];
const singleTooltipModel = buildTooltipModel([
e.tooltipOption,
globalTooltipModel
]);
-
const renderMode = this._renderMode;
- const newLine = this._newLine;
-
- const markers = {};
+ const cbParamsList: TooltipCallbackDataParams[] = [];
+ const articleMarkup = createTooltipMarkup('section', {
+ blocks: [],
+ noHeader: true
+ });
+ // Only for legacy: `Serise['formatTooltip']` returns a string.
+ const markupTextArrLegacy: string[] = [];
+ const markupStyleCreator = new TooltipMarkupStyleCreator();
each(dataByCoordSys, function (itemCoordSys) {
// let coordParamList = [];
@@ -514,54 +490,56 @@ class TooltipView extends ComponentView {
// globalTooltipModel
// ]);
// let displayMode = coordTooltipModel.get('displayMode');
- // let paramsList = displayMode === 'single' ? singleParamsList : [];
-
- each(itemCoordSys.dataByAxis, function (item) {
- const axisModel = ecModel.getComponent(item.axisDim + 'Axis', item.axisIndex) as AxisBaseModel;
- const axisValue = item.value;
- const seriesDefaultHTML: string[] = [];
+ // let paramsList = displayMode === 'single' ? infoBySeriesList : [];
+ each(itemCoordSys.dataByAxis, function (axisItem) {
+ const axisModel = ecModel.getComponent(axisItem.axisDim + 'Axis', axisItem.axisIndex) as AxisBaseModel;
+ const axisValue = axisItem.value;
if (!axisModel || axisValue == null) {
return;
}
-
- const valueLabel = axisPointerViewHelper.getValueLabel(
+ const axisValueLabel = axisPointerViewHelper.getValueLabel(
axisValue, axisModel.axis, ecModel,
- item.seriesDataIndices,
- // @ts-ignore
- item.valueLabelOpt
+ axisItem.seriesDataIndices,
+ axisItem.valueLabelOpt
);
+ const axisSectionMarkup = createTooltipMarkup('section', {
+ header: axisValueLabel,
+ noHeader: !zrUtil.trim(axisValueLabel),
+ sortBlocks: true,
+ blocks: []
+ });
+ articleMarkup.blocks.push(axisSectionMarkup);
- zrUtil.each(item.seriesDataIndices, function (idxItem) {
+ zrUtil.each(axisItem.seriesDataIndices, function (idxItem) {
const series = ecModel.getSeriesByIndex(idxItem.seriesIndex);
const dataIndex = idxItem.dataIndexInside;
- const dataParams = series && series.getDataParams(dataIndex) as TooltipDataParams;
- dataParams.axisDim = item.axisDim;
- dataParams.axisIndex = item.axisIndex;
- dataParams.axisType = item.axisType;
- dataParams.axisId = item.axisId;
- dataParams.axisValue = axisHelper.getAxisRawValue(axisModel.axis, { value: axisValue as number });
- dataParams.axisValueLabel = valueLabel;
- dataParams.marker = formatUtil.getTooltipMarker({
- color: dataParams.color as ColorString,
- renderMode
- });
-
- singleParamsList.push(dataParams);
- const seriesTooltip = series.formatTooltip(
- dataIndex, true, null, renderMode as TooltipRenderMode
+ const cbParams = series.getDataParams(dataIndex) as TooltipCallbackDataParams;
+ cbParams.axisDim = axisItem.axisDim;
+ cbParams.axisIndex = axisItem.axisIndex;
+ cbParams.axisType = axisItem.axisType;
+ cbParams.axisId = axisItem.axisId;
+ cbParams.axisValue = axisHelper.getAxisRawValue(
+ axisModel.axis, { value: axisValue as number }
+ );
+ cbParams.axisValueLabel = axisValueLabel;
+ // Pre-create marker style for makers. Users can assemble richText
+ // text in `formatter` callback and use those markers style.
+ cbParams.marker = markupStyleCreator.makeTooltipMarker(
+ 'item', formatUtil.convertToColorString(cbParams.color), renderMode
);
- let html;
- if (zrUtil.isObject(seriesTooltip)) {
- html = seriesTooltip.html;
- const newMarkers = seriesTooltip.markers;
- zrUtil.merge(markers, newMarkers);
+ const seriesTooltipResult = normalizeTooltipFormatResult(
+ series.formatTooltip(dataIndex, true, null)
+ );
+ if (seriesTooltipResult.markupFragment) {
+ axisSectionMarkup.blocks.push(seriesTooltipResult.markupFragment);
}
- else {
- html = seriesTooltip;
+ if (seriesTooltipResult.markupText) {
+ markupTextArrLegacy.push(seriesTooltipResult.markupText);
}
- dataParams.html = html;
+ cbParamsList.push(cbParams);
+
// const data = series.getData();
// const dims = zrUtil.map(series.coordinateSystem.dimensions, function (coordDim) {
// return data.mapDimension(coordDim);
@@ -583,65 +561,24 @@ class TooltipView extends ComponentView {
// isStacked
// }, ecModel).point;
});
-
- switch (singleTooltipModel.get('order')) {
- case 'valueAsc':
- singleParamsList.sort(function (a, b) {
- return +(a.data) - +(b.data);
- });
- break;
-
- case 'valueDesc':
- singleParamsList.sort(function (a, b) {
- return +(b.data) - +(a.data);
- });
- break;
-
- case 'seriesDesc':
- singleParamsList.reverse();
- break;
-
- case 'seriesAsc':
- default:
- break;
- }
-
- zrUtil.each(singleParamsList, function (params) {
- seriesDefaultHTML.push(params.html);
- delete params.html;
- });
-
- // Default tooltip content
- // FIXME
- // (1) shold be the first data which has name?
- // (2) themeRiver, firstDataIndex is array, and first line is unnecessary.
- const firstLine = valueLabel;
- if (renderMode !== 'html') {
- singleDefaultHTML.push(seriesDefaultHTML.join(newLine));
- }
- else {
- singleDefaultHTML.push(
- (
- firstLine
- ? (
- '<div style="font-size:12px;color:#6e7079;line-height:1;margin-top:-4px;">'
- + formatUtil.encodeHTML(firstLine) + '</div>'
- + newLine
- )
- : ''
- )
- + seriesDefaultHTML.reverse().join(newLine)
- );
- }
- singleDefaultHTML.push('<br/>');
});
- }, this);
+ });
- // In most case, the second axis is shown upper than the first one.
- singleDefaultHTML.pop();
- const singleDefaultHTMLStr = singleDefaultHTML.join(this._newLine + this._newLine);
+ // In most cases, the second axis is displays upper on the first one.
+ // So we reverse it to look better.
+ articleMarkup.blocks.reverse();
+ markupTextArrLegacy.reverse();
const positionExpr = e.position;
+ const orderMode = singleTooltipModel.get('order');
+
+ const builtMarkupText = buildTooltipMarkup(
+ articleMarkup, markupStyleCreator, renderMode, orderMode
+ );
+ builtMarkupText && markupTextArrLegacy.unshift(builtMarkupText);
+ const blockBreak = renderMode === 'richText' ? '\n\n' : '<br/>';
+ const allMarkupText = markupTextArrLegacy.join(blockBreak);
+
this._showOrMove(singleTooltipModel, function (this: TooltipView) {
if (this._updateContentNotChangedOnAxis(dataByCoordSys)) {
this._updatePosition(
@@ -649,13 +586,13 @@ class TooltipView extends ComponentView {
positionExpr,
point[0], point[1],
this._tooltipContent,
- singleParamsList
+ cbParamsList
);
}
else {
this._showTooltipContent(
- singleTooltipModel, singleDefaultHTMLStr, singleParamsList, Math.random() + '',
- point[0], point[1], positionExpr, undefined, markers
+ singleTooltipModel, allMarkupText, cbParamsList, Math.random() + '',
+ point[0], point[1], positionExpr, null, markupStyleCreator
);
}
});
@@ -664,7 +601,7 @@ class TooltipView extends ComponentView {
// from dispatchAction.
}
- _showSeriesItemTooltip(
+ private _showSeriesItemTooltip(
e: TryShowParams,
el: ECElement,
dispatchAction: ExtensionAPI['dispatchAction']
@@ -682,6 +619,7 @@ class TooltipView extends ComponentView {
const dataIndex = ecData.dataIndex;
const dataType = ecData.dataType;
const data = dataModel.getData(dataType);
+ const renderMode = this._renderMode;
const tooltipModel = buildTooltipModel([
data.getItemModel<TooltipableOption>(dataIndex),
@@ -694,32 +632,35 @@ class TooltipView extends ComponentView {
if (tooltipTrigger != null && tooltipTrigger !== 'item') {
return;
}
- const tooltipOrder = tooltipModel.get('order');
const params = dataModel.getDataParams(dataIndex, dataType);
- params.marker = formatUtil.getTooltipMarker({
- color: params.color as ColorString,
- renderMode: this._renderMode
- });
+ const markupStyleCreator = new TooltipMarkupStyleCreator();
+ // Pre-create marker style for makers. Users can assemble richText
+ // text in `formatter` callback and use those markers style.
+ params.marker = markupStyleCreator.makeTooltipMarker(
+ 'item', formatUtil.convertToColorString(params.color), renderMode
+ );
- const seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._renderMode, tooltipOrder);
- let defaultHtml: string;
- let markers: Dictionary<ColorString>;
- if (zrUtil.isObject(seriesTooltip)) {
- defaultHtml = seriesTooltip.html;
- markers = seriesTooltip.markers;
- }
- else {
- defaultHtml = seriesTooltip;
- markers = null;
- }
+ const seriesTooltipResult = normalizeTooltipFormatResult(
+ dataModel.formatTooltip(dataIndex, false, dataType)
+ );
+ const orderMode = tooltipModel.get('order');
+ const markupText = seriesTooltipResult.markupFragment
+ ? buildTooltipMarkup(
+ seriesTooltipResult.markupFragment,
+ markupStyleCreator,
+ renderMode,
+ orderMode
+ )
+ : seriesTooltipResult.markupText;
const asyncTicket = 'item_' + dataModel.name + '_' + dataIndex;
this._showOrMove(tooltipModel, function (this: TooltipView) {
this._showTooltipContent(
- tooltipModel, defaultHtml, params, asyncTicket,
- e.offsetX, e.offsetY, e.position, e.target, markers
+ tooltipModel, markupText, params, asyncTicket,
+ e.offsetX, e.offsetY, e.position, e.target,
+ markupStyleCreator
);
});
@@ -734,7 +675,7 @@ class TooltipView extends ComponentView {
});
}
- _showComponentItemTooltip(
+ private _showComponentItemTooltip(
e: TryShowParams,
el: ECElement,
dispatchAction: ExtensionAPI['dispatchAction']
@@ -751,6 +692,8 @@ class TooltipView extends ComponentView {
const subTooltipModel = new Model(tooltipOpt, this._tooltipModel, this._ecModel);
const defaultHtml = subTooltipModel.get('content');
const asyncTicket = Math.random() + '';
+ // PENDING: this case do not support richText style yet.
+ const markupStyleCreator = new TooltipMarkupStyleCreator();
// Do not check whether `trigger` is 'none' here, because `trigger`
// only works on cooridinate system. In fact, we have not found case
@@ -760,7 +703,7 @@ class TooltipView extends ComponentView {
this._showTooltipContent(
// Use formatterParams from element defined in component
subTooltipModel, defaultHtml, subTooltipModel.get('formatterParams') as any || {},
- asyncTicket, e.offsetX, e.offsetY, e.position, el
+ asyncTicket, e.offsetX, e.offsetY, e.position, el, markupStyleCreator
);
});
@@ -771,18 +714,18 @@ class TooltipView extends ComponentView {
});
}
- _showTooltipContent(
+ private _showTooltipContent(
// Use Model<TooltipOption> insteadof TooltipModel because this model may be from series or other options.
// Instead of top level tooltip.
tooltipModel: Model<TooltipOption>,
defaultHtml: string,
- params: TooltipDataParams | TooltipDataParams[],
+ params: TooltipCallbackDataParams | TooltipCallbackDataParams[],
asyncTicket: string,
x: number,
y: number,
positionExpr: TooltipOption['position'],
- el?: ECElement,
- markers?: Dictionary<ColorString>
+ el: ECElement,
+ markupStyleCreator: TooltipMarkupStyleCreator
) {
// Reset ticket
this._ticket = '';
@@ -808,7 +751,7 @@ class TooltipView extends ComponentView {
else if (zrUtil.isFunction(formatter)) {
const callback = bind(function (cbTicket: string, html: string) {
if (cbTicket === this._ticket) {
- tooltipContent.setContent(html, markers, tooltipModel, nearPoint.color, positionExpr);
+ tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPoint.color, positionExpr);
this._updatePosition(
tooltipModel, positionExpr, x, y, tooltipContent, params, el
);
@@ -818,7 +761,7 @@ class TooltipView extends ComponentView {
html = formatter(params, asyncTicket, callback);
}
- tooltipContent.setContent(html, markers, tooltipModel, nearPoint.color, positionExpr);
+ tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPoint.color, positionExpr);
tooltipContent.show(tooltipModel, nearPoint.color);
this._updatePosition(
tooltipModel, positionExpr, x, y, tooltipContent, params, el
@@ -826,9 +769,9 @@ class TooltipView extends ComponentView {
}
- _getNearestPoint(
+ private _getNearestPoint(
point: number[],
- tooltipDataParams: TooltipDataParams | TooltipDataParams[],
+ tooltipDataParams: TooltipCallbackDataParams | TooltipCallbackDataParams[],
trigger: TooltipOption['trigger']
): {
color: ZRColor;
@@ -874,13 +817,13 @@ class TooltipView extends ComponentView {
// };
}
- _updatePosition(
+ private _updatePosition(
tooltipModel: Model<TooltipOption>,
positionExpr: TooltipOption['position'],
x: number, // Mouse x
y: number, // Mouse y
content: TooltipHTMLContent | TooltipRichContent,
- params: TooltipDataParams | TooltipDataParams[],
+ params: TooltipCallbackDataParams | TooltipCallbackDataParams[],
el?: Element
) {
const viewWidth = this._api.getWidth();
@@ -939,7 +882,7 @@ class TooltipView extends ComponentView {
align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0);
vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0);
- if (tooltipModel.get('confine')) {
+ if (shouldTooltipConfine(tooltipModel)) {
const pos = confineTooltipPosition(
x, y, content, viewWidth, viewHeight
);
@@ -952,7 +895,7 @@ class TooltipView extends ComponentView {
// FIXME
// Should we remove this but leave this to user?
- _updateContentNotChangedOnAxis(dataByCoordSys: DataByCoordSys[]) {
+ private _updateContentNotChangedOnAxis(dataByCoordSys: DataByCoordSys[]) {
const lastCoordSys = this._lastDataByCoordSys;
let contentNotChanged = !!lastCoordSys
&& lastCoordSys.length === dataByCoordSys.length;
@@ -988,7 +931,7 @@ class TooltipView extends ComponentView {
return !!contentNotChanged;
}
- _hide(dispatchAction: ExtensionAPI['dispatchAction']) {
+ private _hide(dispatchAction: ExtensionAPI['dispatchAction']) {
// Do not directly hideLater here, because this behavior may be prevented
// in dispatchAction when showTip is dispatched.
@@ -1056,7 +999,11 @@ function refixTooltipPosition(
const height = size.height;
if (gapH != null) {
- if (x + width + gapH > viewWidth) {
+ // Add extra 2 pixels for this case:
+ // At present the "values" in defaut tooltip are using CSS `float: right`.
+ // When the right edge of the tooltip box is on the right side of the
+ // viewport, the `float` layout might push the "values" to the second line.
+ if (x + width + gapH + 2 > viewWidth) {
x -= width + gapH;
}
else {
diff --git a/src/coord/radar/IndicatorAxis.ts b/src/component/tooltip/helper.ts
similarity index 58%
copy from src/coord/radar/IndicatorAxis.ts
copy to src/component/tooltip/helper.ts
index 116e166..3520056 100644
--- a/src/coord/radar/IndicatorAxis.ts
+++ b/src/component/tooltip/helper.ts
@@ -17,27 +17,13 @@
* under the License.
*/
-import Axis from '../Axis';
-import Scale from '../../scale/Scale';
-import { OptionAxisType } from '../axisCommonTypes';
-import { AxisBaseModel } from '../AxisBaseModel';
-import { InnerIndicatorAxisOption } from './RadarModel';
-
-class IndicatorAxis extends Axis {
-
- type: OptionAxisType = 'value';
-
- angle = 0;
-
- name = '';
-
- model: AxisBaseModel<InnerIndicatorAxisOption>;
-
- value?: number | string;
-
- constructor(dim: string, scale: Scale, radiusExtent?: [number, number]) {
- super(dim, scale, radiusExtent);
- }
+import { TooltipOption } from './TooltipModel';
+import Model from '../../model/Model';
+
+export function shouldTooltipConfine(tooltipModel: Model<TooltipOption>): boolean {
+ const confineOption = tooltipModel.get('confine');
+ return confineOption != null
+ ? !!confineOption
+ // In richText mode, the outside part can not be visible.
+ : tooltipModel.get('renderMode') === 'richText';
}
-
-export default IndicatorAxis;
\ No newline at end of file
diff --git a/src/component/tooltip/seriesFormatTooltip.ts b/src/component/tooltip/seriesFormatTooltip.ts
new file mode 100644
index 0000000..18197be
--- /dev/null
+++ b/src/component/tooltip/seriesFormatTooltip.ts
@@ -0,0 +1,154 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import SeriesModel from '../../model/Series';
+import { trim, isArray, each, reduce } from 'zrender/src/core/util';
+import { DimensionName, DimensionType, ColorString } from '../../util/types';
+import {
+ retrieveVisualColorForTooltipMarker,
+ TooltipMarkupBlockFragment,
+ createTooltipMarkup,
+ TooltipMarkupSection
+} from './tooltipMarkup';
+import { retrieveRawValue } from '../../data/helper/dataProvider';
+import { isNameSpecified } from '../../util/model';
+
+
+export function defaultSeriesFormatTooltip(opt: {
+ series: SeriesModel;
+ dataIndex: number;
+ // `multipleSeries` means multiple series displayed in one tooltip,
+ // and this method only return the part of one series.
+ multipleSeries: boolean;
+}): TooltipMarkupSection {
+ const series = opt.series;
+ const dataIndex = opt.dataIndex;
+ const multipleSeries = opt.multipleSeries;
+
+ const data = series.getData();
+ const tooltipDims = data.mapDimensionsAll('defaultedTooltip');
+ const tooltipDimLen = tooltipDims.length;
+ const value = series.getRawValue(dataIndex) as any;
+ const isValueArr = isArray(value);
+ const markerColor = retrieveVisualColorForTooltipMarker(series, dataIndex);
+
+ // Complicated rule for pretty tooltip.
+ let inlineValue;
+ let inlineValueType: DimensionType | DimensionType[];
+ let subBlocks: TooltipMarkupBlockFragment[];
+ let sortParam: unknown;
+ if (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen)) {
+ const formatArrResult = formatTooltipArrayValue(value, series, dataIndex, tooltipDims, markerColor);
+ inlineValue = formatArrResult.inlineValues;
+ inlineValueType = formatArrResult.inlineValueTypes;
+ subBlocks = formatArrResult.blocks;
+ // Only support tooltip sort by the first inline value. It's enough in most cases.
+ sortParam = formatArrResult.inlineValues[0];
+ }
+ else if (tooltipDimLen) {
+ const dimInfo = data.getDimensionInfo(tooltipDims[0]);
+ sortParam = inlineValue = retrieveRawValue(data, dataIndex, tooltipDims[0]);
+ inlineValueType = dimInfo.type;
+ }
+ else {
+ sortParam = inlineValue = isValueArr ? value[0] : value;
+ }
+
+ // Do not show generated series name. It might not be readable.
+ const seriesNameSpecified = isNameSpecified(series);
+ const seriesName = seriesNameSpecified && series.name || '';
+ const itemName = data.getName(dataIndex);
+ const inlineName = multipleSeries ? seriesName : itemName;
+
+ return createTooltipMarkup('section', {
+ header: seriesName,
+ // When series name not specified, do not show a header line with only '-'.
+ // This case alway happen in tooltip.trigger: 'item'.
+ noHeader: multipleSeries || !seriesNameSpecified,
+ sortParam: sortParam,
+ blocks: [
+ createTooltipMarkup('nameValue', {
+ markerType: 'item',
+ markerColor: markerColor,
+ // Do not mix display seriesName and itemName in one tooltip,
+ // which might confuses users.
+ name: inlineName,
+ // name dimension might be auto assigned, where the name might
+ // be not readable. So we check trim here.
+ noName: !trim(inlineName),
+ value: inlineValue,
+ valueType: inlineValueType
+ })
+ ].concat(subBlocks || [] as any)
+ });
+}
+
+function formatTooltipArrayValue(
+ value: unknown[],
+ series: SeriesModel,
+ dataIndex: number,
+ tooltipDims: DimensionName[],
+ colorStr: ColorString
+): {
+ inlineValues: unknown[];
+ inlineValueTypes: DimensionType[];
+ blocks: TooltipMarkupBlockFragment[];
+} {
+ // check: category-no-encode-has-axis-data in dataset.html
+ const data = series.getData();
+ const isValueMultipleLine = reduce(value, function (isValueMultipleLine, val, idx) {
+ const dimItem = data.getDimensionInfo(idx);
+ return isValueMultipleLine = isValueMultipleLine
+ || (dimItem && dimItem.tooltip !== false && dimItem.displayName != null);
+ }, false);
+
+ const inlineValues: unknown[] = [];
+ const inlineValueTypes: DimensionType[] = [];
+ const blocks: TooltipMarkupBlockFragment[] = [];
+
+ tooltipDims.length
+ ? each(tooltipDims, function (dim) {
+ setEachItem(retrieveRawValue(data, dataIndex, dim), dim);
+ })
+ // By default, all dims is used on tooltip.
+ : each(value, setEachItem);
+
+ function setEachItem(val: unknown, dim: DimensionName | number): void {
+ const dimInfo = data.getDimensionInfo(dim);
+ // If `dimInfo.tooltip` is not set, show tooltip.
+ if (!dimInfo || dimInfo.otherDims.tooltip === false) {
+ return;
+ }
+ if (isValueMultipleLine) {
+ blocks.push(createTooltipMarkup('nameValue', {
+ markerType: 'subItem',
+ markerColor: colorStr,
+ name: dimInfo.displayName,
+ value: val,
+ valueType: dimInfo.type
+ }));
+ }
+ else {
+ inlineValues.push(val);
+ inlineValueTypes.push(dimInfo.type);
+ }
+ }
+
+ return { inlineValues, inlineValueTypes, blocks };
+}
diff --git a/src/component/tooltip/tooltipMarkup.ts b/src/component/tooltip/tooltipMarkup.ts
new file mode 100644
index 0000000..40f78c4
--- /dev/null
+++ b/src/component/tooltip/tooltipMarkup.ts
@@ -0,0 +1,529 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import {
+ Dictionary, TooltipRenderMode, ColorString,
+ TooltipOrderMode, DimensionType
+} from '../../util/types';
+import {
+ TooltipMarkerType, getTooltipMarker, encodeHTML,
+ makeValueReadable, convertToColorString
+} from '../../util/format';
+import { isString, each, hasOwn, isArray, map, assert, extend } from 'zrender/src/core/util';
+import { SortOrderComparator } from '../../data/helper/dataValueHelper';
+import SeriesModel from '../../model/Series';
+import { getRandomIdBase } from '../../util/number';
+import Model from '../../model/Model';
+import { TooltipOption } from './TooltipModel';
+
+
+const TOOLTIP_NAME_TEXT_STYLE_CSS = 'font-size:12px;color:#6e7079';
+const TOOLTIP_TEXT_STYLE_RICH = {
+ fontSize: 12,
+ fill: '#6e7079'
+};
+const TOOLTIP_VALUE_TEXT_STYLE_CSS = 'font-size:14px;color:#464646;font-weight:900';
+const TOOLTIP_VALUE_TEXT_STYLE_RICH = {
+ fontSize: 14,
+ fill: '#464646',
+ fontWeight: 900
+};
+const TOOLTIP_LINE_HEIGHT_CSS = 'line-height:1';
+
+// 0: no gap in this block.
+// 1: has max gap in level 1 in this block.
+// ...
+type GapLevel = number;
+// See `TooltipMarkupLayoutIntent['innerGapLevel']`.
+// (value from UI design)
+const HTML_GAPS: { [key in GapLevel]: number } = [0, 10, 20, 30];
+const RICH_TEXT_GAPS: { [key in GapLevel]: string } = ['', '\n', '\n\n', '\n\n\n'];
+
+/**
+ * This is an abstract layer to insulate the upper usage of tooltip content
+ * from the different backends according to different `renderMode` ('html' or 'richText').
+ * With the help of the abstract layer, it does not need to consider how to create and
+ * assemble html or richText snippets when making tooltip content.
+ *
+ * @usage
+ *
+ * ```ts
+ * class XxxSeriesModel {
+ * formatTooltip(
+ * dataIndex: number,
+ * multipleSeries: boolean,
+ * dataType: string
+ * ) {
+ * ...
+ * return createTooltipMarkup('section', {
+ * header: header,
+ * blocks: [
+ * createTooltipMarkup('nameValue', {
+ * name: name,
+ * value: value,
+ * noValue: value == null
+ * })
+ * ]
+ * });
+ * }
+ * }
+ * ```
+ */
+export type TooltipMarkupBlockFragment =
+ TooltipMarkupSection
+ | TooltipMarkupNameValueBlock;
+
+interface TooltipMarkupBlock {
+ // Use to make comparison when `sortBlocks: true`.
+ sortParam?: unknown;
+ __gapLevelBetweenSubBlocks?: number;
+}
+
+export interface TooltipMarkupSection extends TooltipMarkupBlock {
+ type: 'section';
+ header?: unknown;
+ // If `noHeader` is `true`, do not display header.
+ // Otherwise, always display it even if it is
+ // null/undefined/NaN/''... (displayed as '-').
+ noHeader?: boolean;
+ blocks?: TooltipMarkupBlockFragment[];
+ // Enable to sort blocks when making final html or richText.
+ sortBlocks?: boolean;
+}
+
+export interface TooltipMarkupNameValueBlock extends TooltipMarkupBlock {
+ type: 'nameValue';
+ // If `!markerType`, tooltip marker is not used.
+ markerType?: TooltipMarkerType;
+ markerColor?: ColorString;
+ name?: string;
+ // Also support value is `[121, 555, 94.2]`.
+ value?: unknown | unknown[];
+ // If not specified, treat value as normal string or numeric.
+ // If needs to display formatted time, set as 'time'.
+ // If needs to display original string with numeric guessing, set as 'ordinal'.
+ // If both `value` and `valueType` are array, each valueType[i] cooresponds to value[i].
+ valueType?: DimensionType | DimensionType[];
+ // If `noName` or `noValue` is `true`, do not display name or value.
+ // Otherwise, always display them even if they are
+ // null/undefined/NaN/''... (displayed as '-').
+ noName?: boolean;
+ noValue?: boolean;
+}
+
+/**
+ * Create tooltip markup by this function, we can get TS type check.
+ */
+// eslint-disable-next-line max-len
+export function createTooltipMarkup(type: 'section', option: Omit<TooltipMarkupSection, 'type'>): TooltipMarkupSection;
+// eslint-disable-next-line max-len
+export function createTooltipMarkup(type: 'nameValue', option: Omit<TooltipMarkupNameValueBlock, 'type'>): TooltipMarkupNameValueBlock;
+// eslint-disable-next-line max-len
+export function createTooltipMarkup(type: TooltipMarkupBlockFragment['type'], option: Omit<TooltipMarkupBlockFragment, 'type'>): TooltipMarkupBlockFragment {
+ (option as TooltipMarkupBlockFragment).type = type;
+ return option as TooltipMarkupBlockFragment;
+}
+
+
+// Can be null/undefined, which means generate nothing markup text.
+type MarkupText = string;
+interface TooltipMarkupFragmentBuilder {
+ planLayout(
+ fragment: TooltipMarkupBlockFragment
+ ): void;
+ build(
+ ctx: TooltipMarkupBuildContext,
+ fragment: TooltipMarkupBlockFragment,
+ topMarginForOuterGap: number
+ ): MarkupText;
+}
+
+function getBuilder(fragment: TooltipMarkupBlockFragment): TooltipMarkupFragmentBuilder {
+ return hasOwn(builderMap, fragment.type) && builderMap[fragment.type];
+}
+
+const builderMap: { [key in TooltipMarkupBlockFragment['type']]: TooltipMarkupFragmentBuilder } = {
+
+ /**
+ * A `section` block is like:
+ * ```
+ * header
+ * subBlock
+ * subBlock
+ * ...
+ * ```
+ */
+ section: {
+ planLayout: function (fragment: TooltipMarkupSection) {
+ const subBlockLen = fragment.blocks.length;
+ const thisBlockHasInnerGap = subBlockLen > 1 || (subBlockLen > 0 && !fragment.noHeader);
+
+ let thisGapLevelBetweenSubBlocks = 0;
+ each(fragment.blocks, function (subBlock) {
+ getBuilder(subBlock).planLayout(subBlock);
+ const subGapLevel = subBlock.__gapLevelBetweenSubBlocks;
+
+ // If the some of the sub-blocks have some gaps (like 10px) inside, this block
+ // should use a larger gap (like 20px) to distinguish those sub-blocks.
+ if (subGapLevel >= thisGapLevelBetweenSubBlocks) {
+ thisGapLevelBetweenSubBlocks = subGapLevel + (
+ (
+ thisBlockHasInnerGap && (
+ // 0 always can not be readable gap level.
+ !subGapLevel
+ // If no header, always keep the sub gap level. Otherwise
+ // look weird in case `multipleSeries`.
+ || (subBlock.type === 'section' && !subBlock.noHeader)
+ )
+ ) ? 1 : 0
+ );
+ }
+ });
+ fragment.__gapLevelBetweenSubBlocks = thisGapLevelBetweenSubBlocks;
+ },
+
+ build(ctx, fragment: TooltipMarkupSection, topMarginForOuterGap): string {
+ const noHeader = fragment.noHeader;
+ const gaps = getGap(fragment);
+
+ const subMarkupText = buildSubBlocks(
+ ctx,
+ fragment,
+ noHeader ? topMarginForOuterGap : gaps.html
+ );
+
+ if (noHeader) {
+ return subMarkupText;
+ }
+
+ const displayableHeader = makeValueReadable(fragment.header, 'ordinal');
+ if (ctx.renderMode === 'richText') {
+ return wrapInlineNameRichText(ctx, displayableHeader) + gaps.richText
+ + subMarkupText;
+ }
+ else {
+ return wrapBlockHTML(
+ `<div style="${TOOLTIP_NAME_TEXT_STYLE_CSS};${TOOLTIP_LINE_HEIGHT_CSS};">`
+ + encodeHTML(displayableHeader)
+ + '</div>'
+ + subMarkupText,
+ topMarginForOuterGap
+ );
+ }
+ }
+ },
+
+ /**
+ * A `nameValue` block is like:
+ * ```
+ * marker name value
+ * ```
+ */
+ nameValue: {
+ planLayout: function (fragment: TooltipMarkupNameValueBlock) {
+ fragment.__gapLevelBetweenSubBlocks = 0;
+ },
+
+ build(ctx, fragment: TooltipMarkupNameValueBlock, topMarginForOuterGap) {
+ const renderMode = ctx.renderMode;
+ const noName = fragment.noName;
+ const noValue = fragment.noValue;
+ const noMarker = !fragment.markerType;
+ const name = fragment.name;
+ const value = fragment.value;
+
+ if (noName && noValue) {
+ return;
+ }
+
+ const markerStr = noMarker
+ ? ''
+ : ctx.markupStyleCreator.makeTooltipMarker(
+ fragment.markerType,
+ fragment.markerColor || '#333',
+ renderMode
+ );
+ const readableName = noName
+ ? ''
+ : makeValueReadable(name, 'ordinal');
+ const valueTypeOption = fragment.valueType;
+ const readableValueList = noValue
+ ? []
+ : (isArray(value)
+ ? map(value, (val, idx) => makeValueReadable(
+ val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption
+ ))
+ : [makeValueReadable(
+ value, isArray(valueTypeOption) ? valueTypeOption[0] : valueTypeOption
+ )]
+ );
+ const valueAlignRight = !noMarker || !noName;
+ // It little weird if only value next to marker but far from marker.
+ const valueCloseToMarker = !noMarker && noName;
+
+ return renderMode === 'richText'
+ ? (
+ (noMarker ? '' : markerStr)
+ + (noName ? '' : wrapInlineNameRichText(ctx, readableName))
+ // Value has commas inside, so use ' ' as delimiter for multiple values.
+ + (noValue ? '' : wrapInlineValueRichText(
+ ctx, readableValueList, valueAlignRight, valueCloseToMarker
+ ))
+ )
+ : wrapBlockHTML(
+ (noMarker ? '' : markerStr)
+ + (noName ? '' : wrapInlineNameHTML(readableName, !noMarker))
+ + (noValue ? '' : wrapInlineValueHTML(
+ readableValueList, valueAlignRight, valueCloseToMarker
+ )),
+ topMarginForOuterGap
+ );
+ }
+ }
+};
+
+
+function buildSubBlocks(
+ ctx: TooltipMarkupBuildContext,
+ fragment: TooltipMarkupSection,
+ topMarginForOuterGap: number
+): MarkupText {
+ const subMarkupTextList: string[] = [];
+ let subBlocks = fragment.blocks || [];
+ assert(!subBlocks || isArray(subBlocks));
+ subBlocks = subBlocks || [];
+
+ const orderMode = ctx.orderMode;
+ if (fragment.sortBlocks && orderMode) {
+ subBlocks = subBlocks.slice();
+ const orderMap = { valueAsc: 'asc', valueDesc: 'desc' } as const;
+ if (hasOwn(orderMap, orderMode)) {
+ const comparator = new SortOrderComparator(orderMap[orderMode as 'valueAsc' | 'valueDesc'], null);
+ subBlocks.sort((a, b) => comparator.evaluate(a.sortParam, b.sortParam));
+ }
+ // FIXME 'seriesDesc' necessary?
+ else if (orderMode === 'seriesDesc') {
+ subBlocks.reverse();
+ }
+ }
+
+ const gaps = getGap(fragment);
+ each(subBlocks, function (subBlock, idx) {
+ const subMarkupText = getBuilder(subBlock).build(
+ ctx,
+ subBlock,
+ idx > 0 ? gaps.html : 0
+ );
+ subMarkupText != null && subMarkupTextList.push(subMarkupText);
+ });
+
+ if (!subMarkupTextList.length) {
+ return;
+ }
+
+ return ctx.renderMode === 'richText'
+ ? subMarkupTextList.join(gaps.richText)
+ : wrapBlockHTML(
+ subMarkupTextList.join(''),
+ topMarginForOuterGap
+ );
+}
+
+interface TooltipMarkupBuildContext {
+ renderMode: TooltipRenderMode;
+ orderMode: TooltipOrderMode;
+ markupStyleCreator: TooltipMarkupStyleCreator;
+}
+
+/**
+ * @return markupText. null/undefined means no content.
+ */
+export function buildTooltipMarkup(
+ fragment: TooltipMarkupBlockFragment,
+ markupStyleCreator: TooltipMarkupStyleCreator,
+ renderMode: TooltipRenderMode,
+ orderMode: TooltipOrderMode
+): MarkupText {
+ if (!fragment) {
+ return;
+ }
+
+ const builder = getBuilder(fragment);
+ builder.planLayout(fragment);
+ const ctx: TooltipMarkupBuildContext = {
+ renderMode: renderMode,
+ orderMode: orderMode,
+ markupStyleCreator: markupStyleCreator
+ };
+ return builder.build(ctx, fragment, 0);
+}
+
+
+function getGap(fragment: TooltipMarkupBlock): {
+ html: number;
+ richText: string
+} {
+ const gapLevelBetweenSubBlocks = fragment.__gapLevelBetweenSubBlocks;
+ return {
+ html: HTML_GAPS[gapLevelBetweenSubBlocks],
+ richText: RICH_TEXT_GAPS[gapLevelBetweenSubBlocks]
+ };
+}
+
+function wrapBlockHTML(
+ encodedContent: string,
+ topGap: number
+): string {
+ const clearfix = '<div style="clear:both"></div>';
+ const marginCSS = `margin: ${topGap}px 0 0`;
+ return `<div style="${marginCSS};${TOOLTIP_LINE_HEIGHT_CSS};">`
+ + encodedContent + clearfix
+ + '</div>';
+}
+
+function wrapInlineNameHTML(name: string, leftHasMarker: boolean): string {
+ const marginCss = leftHasMarker ? 'margin-left:2px' : '';
+ return `<span style="${TOOLTIP_NAME_TEXT_STYLE_CSS};${marginCss}">`
+ + encodeHTML(name)
+ + '</span>';
+}
+
+function wrapInlineValueHTML(valueList: string[], alignRight: boolean, valueCloseToMarker: boolean): string {
+ // Do not too close to marker, considering there are multiple values separated by spaces.
+ const paddingStr = valueCloseToMarker ? '10px' : '20px';
+ const alignCSS = alignRight ? `float:right;margin-left:${paddingStr}` : '';
+ return (
+ `<span style="${alignCSS};${TOOLTIP_VALUE_TEXT_STYLE_CSS}">`
+ // Value has commas inside, so use ' ' as delimiter for multiple values.
+ + map(valueList, value => encodeHTML(value)).join(' ')
+ + '</span>'
+ );
+}
+
+function wrapInlineNameRichText(ctx: TooltipMarkupBuildContext, name: string): string {
+ return ctx.markupStyleCreator.wrapRichTextStyle(name, TOOLTIP_TEXT_STYLE_RICH);
+}
+
+function wrapInlineValueRichText(
+ ctx: TooltipMarkupBuildContext,
+ valueList: string[],
+ alignRight: boolean,
+ valueCloseToMarker: boolean
+): string {
+ const styles: Dictionary<unknown>[] = [TOOLTIP_VALUE_TEXT_STYLE_RICH];
+ const paddingLeft = valueCloseToMarker ? 10 : 20;
+ alignRight && styles.push({ padding: [0, 0, 0, paddingLeft], align: 'right' });
+ // Value has commas inside, so use ' ' as delimiter for multiple values.
+ return ctx.markupStyleCreator.wrapRichTextStyle(valueList.join(' '), styles);
+}
+
+
+export function retrieveVisualColorForTooltipMarker(
+ series: SeriesModel,
+ dataIndex: number
+): ColorString {
+ const style = series.getData().getItemVisual(dataIndex, 'style');
+ const color = style[series.visualDrawType];
+ return convertToColorString(color);
+}
+
+export function getPaddingFromTooltipModel(
+ model: Model<TooltipOption>,
+ renderMode: TooltipRenderMode
+): number | number[] {
+ const padding = model.get('padding');
+ return padding != null
+ ? padding
+ // We give slightly different to look pretty.
+ : renderMode === 'richText'
+ ? [8, 10]
+ : 10;
+}
+
+/**
+ * The major feature is generate styles for `renderMode: 'richText'`.
+ * But it also serves `renderMode: 'html'` to provide
+ * "renderMode-independent" API.
+ */
+export class TooltipMarkupStyleCreator {
+ readonly richTextStyles: Dictionary<Dictionary<unknown>> = {};
+
+ // Notice that "generate a style name" usuall happens repeatly when mouse moving and
+ // displaying a tooltip. So we put the `_nextStyleNameId` as a member of each creator
+ // rather than static shared by all creators (which will cause it increase to fast).
+ private _nextStyleNameId: number = getRandomIdBase();
+
+ private _generateStyleName() {
+ return '__EC_aUTo_' + this._nextStyleNameId++;
+ }
+
+ makeTooltipMarker(
+ markerType: TooltipMarkerType,
+ colorStr: ColorString,
+ renderMode: TooltipRenderMode
+ ): string {
+ const markerId = renderMode === 'richText'
+ ? this._generateStyleName()
+ : null;
+ const marker = getTooltipMarker({
+ color: colorStr,
+ type: markerType,
+ renderMode,
+ markerId: markerId
+ });
+ if (isString(marker)) {
+ return marker;
+ }
+ else {
+ if (__DEV__) {
+ assert(markerId);
+ }
+ this.richTextStyles[markerId] = marker.style;
+ return marker.content;
+ }
+ }
+
+ /**
+ * @usage
+ * ```ts
+ * const styledText = markupStyleCreator.wrapRichTextStyle([
+ * // The styles will be auto merged.
+ * {
+ * fontSize: 12,
+ * color: 'blue'
+ * },
+ * {
+ * padding: 20
+ * }
+ * ]);
+ * ```
+ */
+ wrapRichTextStyle(text: string, styles: Dictionary<unknown> | Dictionary<unknown>[]): string {
+ const finalStl = {};
+ if (isArray(styles)) {
+ each(styles, stl => extend(finalStl, stl));
+ }
+ else {
+ extend(finalStl, styles);
+ }
+ const styleName = this._generateStyleName();
+ this.richTextStyles[styleName] = finalStl;
+ return `{${styleName}|${text}}`;
+ }
+}
diff --git a/src/coord/radar/IndicatorAxis.ts b/src/coord/radar/IndicatorAxis.ts
index 116e166..f03b9a0 100644
--- a/src/coord/radar/IndicatorAxis.ts
+++ b/src/coord/radar/IndicatorAxis.ts
@@ -33,8 +33,6 @@ class IndicatorAxis extends Axis {
model: AxisBaseModel<InnerIndicatorAxisOption>;
- value?: number | string;
-
constructor(dim: string, scale: Scale, radiusExtent?: [number, number]) {
super(dim, scale, radiusExtent);
}
diff --git a/src/model/Series.ts b/src/model/Series.ts
index b631208..a082994 100644
--- a/src/model/Series.ts
+++ b/src/model/Series.ts
@@ -19,21 +19,15 @@
import * as zrUtil from 'zrender/src/core/util';
import env from 'zrender/src/core/env';
-import {
- formatTime,
- encodeHTML,
- addCommas,
- getTooltipMarker
-} from '../util/format';
import * as modelUtil from '../util/model';
import {
DataHost, DimensionName, StageHandlerProgressParams,
- SeriesOption, TooltipRenderMode, ZRColor, BoxLayoutOptionMixin,
- ScaleDataValue, Dictionary, ColorString, OptionDataItemObject, SeriesDataType
+ SeriesOption, ZRColor, BoxLayoutOptionMixin,
+ ScaleDataValue, Dictionary, OptionDataItemObject, SeriesDataType
} from '../util/types';
import ComponentModel, { ComponentModelConstructor } from './Component';
import {ColorPaletteMixin} from './mixin/colorPalette';
-import DataFormatMixin from '../model/mixin/dataFormat';
+import { DataFormatMixin } from '../model/mixin/dataFormat';
import Model from '../model/Model';
import {
getLayoutParams,
@@ -41,7 +35,6 @@ import {
fetchLayoutMode
} from '../util/layout';
import {createTask} from '../stream/task';
-import {retrieveRawValue} from '../data/helper/dataProvider';
import GlobalModel from './Global';
import { CoordinateSystem } from '../coord/CoordinateSystem';
import { ExtendableConstructor, mountExtend, Constructor } from '../util/clazz';
@@ -49,11 +42,11 @@ import { PipelineContext, SeriesTaskContext, GeneralTask, OverallTask, SeriesTas
import LegendVisualProvider from '../visual/LegendVisualProvider';
import List from '../data/List';
import Axis from '../coord/Axis';
-import { GradientObject } from 'zrender/src/graphic/Gradient';
import type { BrushCommonSelectorsForSeries, BrushSelectableArea } from '../component/brush/selector';
import makeStyleMapper from './mixin/makeStyleMapper';
import { SourceManager } from '../data/helper/sourceManager';
import { Source } from '../data/Source';
+import { defaultSeriesFormatTooltip } from '../component/tooltip/seriesFormatTooltip';
const inner = modelUtil.makeInner<{
data: List
@@ -399,7 +392,6 @@ class SeriesModel<Opt extends SeriesOption = SeriesOption> extends ComponentMode
return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();
}
- // FIXME
/**
* Default tooltip formatter
*
@@ -412,178 +404,18 @@ class SeriesModel<Opt extends SeriesOption = SeriesOption> extends ComponentMode
* 'richText' is used for rendering tooltip in rich text form, for those where
* DOM operation is not supported.
* @return formatted tooltip with `html` and `markers`
+ * Notice: The override method can also return string
*/
formatTooltip(
dataIndex: number,
multipleSeries?: boolean,
- dataType?: SeriesDataType,
- renderMode?: TooltipRenderMode
- ): {
- html: string,
- markers: Dictionary<ColorString>
- } | string { // The override method can also return string
-
- const series = this;
- renderMode = renderMode || 'html';
- const newLine = renderMode === 'html' ? '' : '\n';
- const isRichText = renderMode === 'richText';
- const markers: Dictionary<ColorString> = {};
- let markerId = 0;
-
- function formatArrayValue(value: any[]) {
- // ??? TODO refactor these logic.
- // check: category-no-encode-has-axis-data in dataset.html
- const vertially = zrUtil.reduce(value, function (vertially, val, idx) {
- const dimItem = data.getDimensionInfo(idx);
- return vertially |= (dimItem && dimItem.tooltip !== false && dimItem.displayName != null) as any;
- }, 0);
-
- const result: string[] = [];
-
- tooltipDims.length
- ? zrUtil.each(tooltipDims, function (dim) {
- setEachItem(retrieveRawValue(data, dataIndex, dim), dim);
- })
- // By default, all dims is used on tooltip.
- : zrUtil.each(value, setEachItem);
-
- function setEachItem(val: any, dim: DimensionName | number): void {
- const dimInfo = data.getDimensionInfo(dim);
- // If `dimInfo.tooltip` is not set, show tooltip.
- if (!dimInfo || dimInfo.otherDims.tooltip === false) {
- return;
- }
- const dimType = dimInfo.type;
- const markName = 'sub' + series.seriesIndex + 'at' + markerId;
- const dimHead = getTooltipMarker({
- color: colorStr,
- type: 'subItem',
- renderMode: renderMode,
- markerId: markName
- });
-
- const dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;
- const valStr = (vertially
- ? '<span style="font-size:12px;color:#6e7079;">'
- + dimHeadStr + encodeHTML(dimInfo.displayName || '-')
- + '</span>'
- : ''
- )
- // FIXME should not format time for raw data?
- + '<span style="float:right;margin-left:20px;color:#000;font-weight:900">'
- + encodeHTML(dimType === 'ordinal'
- ? val + ''
- : dimType === 'time'
- ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))
- : addCommas(val)
- )
- + '</span>';
- valStr && result.push(`<div style="margin: 11px 0 0;line-height:1;">${valStr}</div>`);
-
- if (isRichText) {
- markers[markName] = colorStr;
- ++markerId;
- }
- }
-
- const newLine = vertially ? (isRichText ? '\n' : '') : '';
- const content = newLine + result.join(newLine || '');
- return {
- renderMode: renderMode,
- content: content,
- style: markers
- };
- }
-
- function formatSingleValue(val: any) {
- // return encodeHTML(addCommas(val));
- return {
- renderMode: renderMode,
- content: encodeHTML(addCommas(val)),
- style: markers
- };
- }
-
- const data = this.getData();
- const tooltipDims = data.mapDimensionsAll('defaultedTooltip');
- const tooltipDimLen = tooltipDims.length;
- const value = this.getRawValue(dataIndex) as any;
- const isValueArr = zrUtil.isArray(value);
-
- const style = data.getItemVisual(dataIndex, 'style');
- const color = style[this.visualDrawType];
- let colorStr: ColorString;
- if (zrUtil.isString(color)) {
- colorStr = color;
- }
- else if (color && (color as GradientObject).colorStops) {
- colorStr = ((color as GradientObject).colorStops[0] || {}).color;
- }
- colorStr = colorStr || 'transparent';
-
- // Complicated rule for pretty tooltip.
- const formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))
- ? formatArrayValue(value)
- : tooltipDimLen
- ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))
- : formatSingleValue(isValueArr ? value[0] : value);
- const content = isRichText
- ? formattedValue.content
- : (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))
- ? '<div>'
- + formattedValue.content + '</div>'
- : '<span style="float:right;margin-left:20px;color:#464646;font-weight:bold">'
- + formattedValue.content + '</span>';
-
- const markName = series.seriesIndex + 'at' + markerId;
- const colorEl = getTooltipMarker({
- color: colorStr,
- type: 'item',
- renderMode,
- markerId: markName
+ dataType?: SeriesDataType
+ ): ReturnType<DataFormatMixin['formatTooltip']> {
+ return defaultSeriesFormatTooltip({
+ series: this,
+ dataIndex: dataIndex,
+ multipleSeries: multipleSeries
});
- markers[markName] = colorStr;
- ++markerId;
-
- const name = data.getName(dataIndex);
-
- let seriesName = this.name;
- if (!modelUtil.isNameSpecified(this)) {
- seriesName = '';
- }
- seriesName = seriesName
- ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ' ')
- : '';
-
- colorStr = zrUtil.isString(colorEl) ? colorEl : colorEl.content;
- let html = '';
- if (!isRichText) {
- seriesName = seriesName
- ? !multipleSeries
- ? `<div style="font-size:12px;color:#6e7079;line-height:1;margin-top:-4px;">${seriesName}</div>`
- : `<span style="font-size:12px;color:#6e7079;line-height:1">${seriesName}</span>`
- : '';
- html = !multipleSeries
- ? seriesName + `<div style="margin: ${seriesName ? 8 : 0}px 0 0;line-height:1">`
- + colorStr
- + (name
- ? `<span style="font-size:12px;color:#6e7079;">${encodeHTML(name)}</span>${content}`
- : content
- ) + '</div>'
- : `<div style="margin: 11px 0 0;line-height:1;">${colorStr}${seriesName}${content}</div>`;
- }
- else {
- html = !multipleSeries
- ? seriesName + (seriesName ? '\n' : '') + ''
- + colorStr
- + (name
- ? `${encodeHTML(name)}: ${content}`
- : content
- ) + ''
- : `${colorStr}${seriesName}: ${content}`;
- }
-
- return {html, markers};
}
isAnimationEnabled(): boolean {
@@ -842,4 +674,5 @@ function getCurrentTask(seriesModel: SeriesModel): GeneralTask {
}
}
+
export default SeriesModel;
diff --git a/src/model/mixin/dataFormat.ts b/src/model/mixin/dataFormat.ts
index f1aa9b7..83b492f 100644
--- a/src/model/mixin/dataFormat.ts
+++ b/src/model/mixin/dataFormat.ts
@@ -23,20 +23,20 @@ import {formatTpl} from '../../util/format';
import {
DataHost,
DisplayState,
- TooltipRenderMode,
CallbackDataParams,
ColorString,
ZRColor,
OptionDataValue,
- SeriesDataType,
- TooltipOrderMode
+ SeriesDataType
} from '../../util/types';
import GlobalModel from '../Global';
+import { TooltipMarkupBlockFragment } from '../../component/tooltip/tooltipMarkup';
+import { makePrintable } from '../../util/log';
const DIMENSION_LABEL_REG = /\{@(.+?)\}/g;
-interface DataFormatMixin extends DataHost {
+export interface DataFormatMixin extends DataHost {
ecModel: GlobalModel;
mainType: string;
subType: string;
@@ -46,7 +46,7 @@ interface DataFormatMixin extends DataHost {
animatedValue: OptionDataValue[];
}
-class DataFormatMixin {
+export class DataFormatMixin {
/**
* Get params for formatter
@@ -166,22 +166,75 @@ class DataFormatMixin {
* @param {number} dataIndex
* @param {boolean} [multipleSeries=false]
* @param {string} [dataType]
- * @param {string} [renderMode='html'] valid values: 'html' and 'richText'.
- * 'html' is used for rendering tooltip in extra DOM form, and the result
- * string is used as DOM HTML content.
- * 'richText' is used for rendering tooltip in rich text form, for those where
- * DOM operation is not supported.
*/
formatTooltip(
dataIndex: number,
multipleSeries?: boolean,
- dataType?: string,
- renderMode?: TooltipRenderMode,
- order?: TooltipOrderMode
- ): string | {html: string, markers: {[markName: string]: string}} {
+ dataType?: string
+ ): TooltipFormatResult {
// Empty function
return;
}
};
-export default DataFormatMixin;
+type TooltipFormatResult =
+ // If `string`, means `TooltipFormatResultLegacyObject['html']`
+ string
+ // | TooltipFormatResultLegacyObject
+ | TooltipMarkupBlockFragment;
+
+// PENDING: previously we accept this type when calling `formatTooltip`,
+// but guess little chance has been used outside. Do we need to backward
+// compat it?
+// type TooltipFormatResultLegacyObject = {
+// // `html` means the markup language text, either in 'html' or 'richText'.
+// // The name `html` is not appropriate becuase in 'richText' it is not a HTML
+// // string. But still support it for backward compat.
+// html: string;
+// markers: Dictionary<ColorString>;
+// };
+
+/**
+ * For backward compat, normalize the return from `formatTooltip`.
+ */
+export function normalizeTooltipFormatResult(
+ result: TooltipFormatResult
+ // markersExisting: Dictionary<ColorString>
+): {
+ // If `markupFragment` exists, `markupText` should be ignored.
+ markupFragment: TooltipMarkupBlockFragment;
+ // Can be `null`/`undefined`, means no tooltip.
+ markupText: string;
+ // Merged with `markersExisting`.
+ // markers: Dictionary<ColorString>;
+} {
+ let markupText;
+ // let markers: Dictionary<ColorString>;
+ let markupFragment: TooltipMarkupBlockFragment;
+ if (zrUtil.isObject(result)) {
+ if ((result as TooltipMarkupBlockFragment).type) {
+ markupFragment = result as TooltipMarkupBlockFragment;
+ }
+ else {
+ if (__DEV__) {
+ console.warn('The return type of `formatTooltip` is not supported: ' + makePrintable(result));
+ }
+ }
+ // else {
+ // markupText = (result as TooltipFormatResultLegacyObject).html;
+ // markers = (result as TooltipFormatResultLegacyObject).markers;
+ // if (markersExisting) {
+ // markers = zrUtil.merge(markersExisting, markers);
+ // }
+ // }
+ }
+ else {
+ markupText = result;
+ }
+
+ return {
+ markupText: markupText,
+ // markers: markers || markersExisting,
+ markupFragment: markupFragment
+ };
+}
diff --git a/src/util/format.ts b/src/util/format.ts
index 0298aa6..049ffb5 100644
--- a/src/util/format.ts
+++ b/src/util/format.ts
@@ -18,10 +18,12 @@
*/
import * as zrUtil from 'zrender/src/core/util';
-import { parseDate, isNumeric } from './number';
-import { TooltipRenderMode, ColorString } from './types';
+import { parseDate, isNumeric, numericToNumber } from './number';
+import { TooltipRenderMode, ColorString, ZRColor, DimensionType } from './types';
import { Dictionary } from 'zrender/src/core/types';
-import { format, pad } from './time';
+import { GradientObject } from 'zrender/src/graphic/Gradient';
+import { format as timeFormat, pad } from './time';
+import { deprecateReplaceLog } from './log';
/**
* Add a comma each three digit.
@@ -67,13 +69,58 @@ export function encodeHTML(source: string): string {
});
}
-export function concatTooltipHtml(html: string, value: unknown, dontEncodeHtml?: boolean): string {
- return (dontEncodeHtml ? html : `<span style="font-size:12px;color:#6e7079;">${encodeHTML(html)}</span>`)
- + (value ? '<span style="float:right;margin-left:20px;color:#464646;font-weight:900;font-size:14px;">' : '')
- + encodeHTML(value as string)
- + (value ? '</span>' : '');
+
+/**
+ * Make value user readable for tooltip and label.
+ * "User readable":
+ * Try to not print programmer-specific text like NaN, Infinity, null, undefined.
+ * Avoid to display an empty string, which users can not recognize there is
+ * a value and it might look like a bug.
+ */
+export function makeValueReadable(
+ value: unknown,
+ valueType?: DimensionType
+): string {
+ const USER_READABLE_DEFUALT_TIME_PATTERN = 'yyyy-MM-dd hh:mm:ss';
+
+ function stringToUserReadable(str: string): string {
+ return (str && zrUtil.trim(str)) ? str : '-';
+ }
+ function isNumberUserReadable(num: number): boolean {
+ return !!(num != null && !isNaN(num) && isFinite(num));
+ }
+
+ const isTypeTime = valueType === 'time';
+ const isValueDate = value instanceof Date;
+ if (isTypeTime || isValueDate) {
+ const date = isTypeTime ? parseDate(value) : value;
+ if (!isNaN(+date)) {
+ // PENDING: add param `useUTC`?
+ return timeFormat(date, USER_READABLE_DEFUALT_TIME_PATTERN);
+ }
+ else if (isValueDate) {
+ return '-';
+ }
+ // In other cases, continue to try to display the value in the following code.
+ }
+
+ if (valueType === 'ordinal') {
+ return zrUtil.isStringSafe(value)
+ ? stringToUserReadable(value)
+ : zrUtil.isNumber(value)
+ ? (isNumberUserReadable(value) ? value + '' : '-')
+ : '-';
+ }
+ // By default.
+ const numericResult = numericToNumber(value);
+ return isNumberUserReadable(numericResult)
+ ? addCommas(numericResult)
+ : zrUtil.isStringSafe(value)
+ ? stringToUserReadable(value)
+ : '-';
}
+
const TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
const wrapVar = function (varName: string, seriesIdx?: number): string {
@@ -105,7 +152,7 @@ export function formatTpl(
if (isTimeAxis) {
const axisValue = paramsList[0].data[paramsList[0].axisIndex];
const date = parseDate(axisValue);
- return format(date, tpl);
+ return timeFormat(date, tpl);
}
else {
const $vars = paramsList[0].$vars || [];
@@ -142,20 +189,18 @@ export function formatTplSimple(tpl: string, param: Dictionary<any>, encode?: bo
interface RichTextTooltipMarker {
renderMode: TooltipRenderMode;
content: string;
- style: {
- color: ColorString
- [key: string]: any
- };
+ style: Dictionary<unknown>;
}
export type TooltipMarker = string | RichTextTooltipMarker;
+export type TooltipMarkerType = 'item' | 'subItem';
interface GetTooltipMarkerOpt {
color?: ColorString;
extraCssText?: string;
// By default: 'item'
- type?: 'item' | 'subItem';
+ type?: TooltipMarkerType;
renderMode?: TooltipRenderMode;
// id name for marker. If only one marker is in a rich text, this can be omitted.
- // By default: 'X'
+ // By default: 'markerX'
markerId?: string;
}
// Only support color string
@@ -170,7 +215,6 @@ export function getTooltipMarker(inOpt: ColorString | GetTooltipMarkerOpt, extra
const type = opt.type;
extraCssText = opt.extraCssText;
const renderMode = opt.renderMode || 'html';
- const markerId = opt.markerId || 'X';
if (!color) {
return '';
@@ -187,13 +231,27 @@ export function getTooltipMarker(inOpt: ColorString | GetTooltipMarkerOpt, extra
+ encodeHTML(color) + ';' + (extraCssText || '') + '"></span>';
}
else {
- // Space for rich element marker
+ // Should better not to auto generate style name by auto-increment number here.
+ // Because this util is usually called in tooltip formatter, which is probably
+ // called repeatly when mouse move and the auto-increment number increases fast.
+ // Users can make their own style name by theirselves, make it unique and readable.
+ const markerId = opt.markerId || 'markerX';
return {
renderMode: renderMode,
- content: '{marker' + markerId + '|} ',
- style: {
- color: color
- }
+ content: '{' + markerId + '|} ',
+ style: type === 'subItem'
+ ? {
+ width: 4,
+ height: 4,
+ borderRadius: 2,
+ backgroundColor: color
+ }
+ : {
+ width: 10,
+ height: 10,
+ borderRadius: 5,
+ backgroundColor: color
+ }
};
}
}
@@ -209,7 +267,11 @@ export function getTooltipMarker(inOpt: ColorString | GetTooltipMarkerOpt, extra
* and `module:echarts/util/number#parseDate`.
* @inner
*/
-export function formatTime(tpl: string, value: number | string | Date, isUTC?: boolean) {
+export function formatTime(tpl: string, value: unknown, isUTC?: boolean) {
+ if (__DEV__) {
+ deprecateReplaceLog('echarts.format.formatTime', 'echarts.time.format');
+ }
+
if (tpl === 'week'
|| tpl === 'month'
|| tpl === 'quarter'
@@ -255,6 +317,21 @@ export function capitalFirst(str: string): string {
return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;
}
+/**
+ * @return Never be null/undefined.
+ */
+export function convertToColorString(color: ZRColor, defaultColor?: ColorString): ColorString {
+ defaultColor = defaultColor || 'transparent';
+ return zrUtil.isString(color)
+ ? color
+ : zrUtil.isObject(color)
+ ? (
+ (color as GradientObject).colorStops
+ && ((color as GradientObject).colorStops[0] || {}).color
+ || defaultColor
+ )
+ : defaultColor;
+}
export {truncateText} from 'zrender/src/graphic/helper/parseText';
diff --git a/src/util/log.ts b/src/util/log.ts
index cfb0bb9..4e443f6 100644
--- a/src/util/log.ts
+++ b/src/util/log.ts
@@ -77,7 +77,7 @@ export function consoleLog(...args: unknown[]) {
* @param hintInfo anything about the current execution context to hint users.
* @throws Error
*/
-export function makePrintable(...hintInfo: unknown[]) {
+export function makePrintable(...hintInfo: unknown[]): string {
let msg = '';
if (__DEV__) {
diff --git a/src/util/model.ts b/src/util/model.ts
index 83a615f..dffc341 100644
--- a/src/util/model.ts
+++ b/src/util/model.ts
@@ -47,7 +47,7 @@ import { Dictionary } from 'zrender/src/core/types';
import SeriesModel from '../model/Series';
import CartesianAxisModel from '../coord/cartesian/AxisModel';
import GridModel from '../coord/cartesian/GridModel';
-import { isNumeric } from './number';
+import { isNumeric, getRandomIdBase } from './number';
/**
* Make the name displayable. But we should
@@ -706,8 +706,7 @@ export function makeInner<T, Host extends object>() {
return (hostObj as any)[key] || ((hostObj as any)[key] = {});
};
}
-// A random start point.
-let innerUniqueIndex = Math.round(Math.random() * 5);
+let innerUniqueIndex = getRandomIdBase();
/**
* If string, e.g., 'geo', means {geoIndex: 0}.
diff --git a/src/util/number.ts b/src/util/number.ts
index 775d51a..865c4c7 100644
--- a/src/util/number.ts
+++ b/src/util/number.ts
@@ -565,3 +565,12 @@ export function numericToNumber(val: unknown): number {
export function isNumeric(val: unknown): val is number {
return !isNaN(numericToNumber(val));
}
+
+/**
+ * Use random base to prevent users hard code depending on
+ * this auto generated marker id.
+ * @return An positive integer.
+ */
+export function getRandomIdBase(): number {
+ return Math.round(Math.random() * 9);
+}
diff --git a/src/util/time.ts b/src/util/time.ts
index f7de3ae..712e396 100644
--- a/src/util/time.ts
+++ b/src/util/time.ts
@@ -106,7 +106,7 @@ export function getDefaultFormatPrecisionOfInterval(timeUnit: PrimaryTimeUnit):
}
export function format(
- time: Date | number, template: string, lang?: string | Model<LocaleOption>, isUTC?: boolean
+ time: unknown, template: string, lang?: string | Model<LocaleOption>, isUTC?: boolean
): string {
const date = numberUtil.parseDate(time);
const y = date[fullYearGetterName(isUTC)]();
diff --git a/src/util/types.ts b/src/util/types.ts
index 5ebee91..c33f0c7 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -27,7 +27,7 @@
import Group from 'zrender/src/graphic/Group';
import Element, {ElementEvent, ElementTextConfig} from 'zrender/src/Element';
-import DataFormatMixin from '../model/mixin/dataFormat';
+import { DataFormatMixin } from '../model/mixin/dataFormat';
import GlobalModel from '../model/Global';
import ExtensionAPI from '../ExtensionAPI';
import SeriesModel from '../model/Series';
@@ -275,6 +275,12 @@ export interface LoadingEffect extends Element {
resize: () => void;
}
+/**
+ * 'html' is used for rendering tooltip in extra DOM form, and the result
+ * string is used as DOM HTML content.
+ * 'richText' is used for rendering tooltip in rich text form, for those where
+ * DOM operation is not supported.
+ */
export type TooltipRenderMode = 'html' | 'richText';
export type TooltipOrderMode = 'valueAsc' | 'valueDesc' | 'seriesAsc' | 'seriesDesc';
diff --git a/test/new-tooltip.html b/test/new-tooltip.html
index 4a03f61..9de9530 100644
--- a/test/new-tooltip.html
+++ b/test/new-tooltip.html
@@ -21,6 +21,7 @@ under the License.
<head>
<meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="lib/esl.js"></script>
<script src="lib/config.js"></script>
</head>
@@ -30,67 +31,151 @@ under the License.
margin: 0;
padding: 0;
}
+ .chart {
+ width: 100vw;
+ height: 40vh;
+ margin: 30px auto 0 auto;
+ }
+ #stateConsole {
+ position: fixed;
+ top: 5px;
+ left: 5px;
+ background: #333;
+ color: #eee;
+ font-size: 18px;
+ padding: 10px;
+ font-family: Monaco, monospace;
+ box-shadow: #000 0 0 5px;
+ z-index: 99999;
+ }
+ #stateConsole input {
+ margin-left: 15px;
+ }
+ #stateConsole .checked {
+ color: yellow;
+ font-size: 30px;
+ }
+ h1 {
+ margin-top: 40px;
+ margin-left: 10px;
+ font-size: 20px;
+ font-family: Arial, Helvetica, sans-serif;
+ }
</style>
<body>
- <h1>Tooltip in Line Chart</h1>
- <div id="main1" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+
+ <div id="stateConsole">
+ <span>tooltip.renderMode: </span>
+ <span id="stateConsoleSelect"></span>
+ </div>
+ <br>
+ <br>
+ <br>
+ <br>
+
+ <h1>Hover point, show item tooltip (with arrow in renderMode 'html')</h1>
+ <div id="main1" class="chart"></div>
<h1>Tooltip in Radar Chart</h1>
- <div id="main2" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main2" class="chart"></div>
<h1>Tooltip in Pie Chart</h1>
- <div id="main3" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main3" class="chart"></div>
<h1>Tooltip in Sankey Chart</h1>
- <div id="main4" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main4" class="chart"></div>
<h1>Tooltip in Graph Chart</h1>
- <div id="main5" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main5" class="chart"></div>
+ <h1>Simple 2 value axis scatter (trigger: 'item' | 'axis')</h1>
+ <div id="main6" class="chart"></div>
<h1>Tooltip in Tree Chart</h1>
- <div id="main7" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main7" class="chart"></div>
<h1>Tooltip in Multiple Chart</h1>
- <div id="main8" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main8" class="chart"></div>
<h1>Tooltip in Line Chart axis Y is main axis</h1>
- <div id="main9" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main9" class="chart"></div>
<h1>Tooltip in Treemap Chart</h1>
- <div id="main10" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main10" class="chart"></div>
<h1>Tooltip in Bar Chart</h1>
- <div id="main11" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
- <h1>Tooltip in Stacked Line Chart</h1>
- <div id="main12" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main11" class="chart"></div>
+ <h1>Tooltip in Stacked Line Chart (and legend)</h1>
+ <div id="main12" class="chart"></div>
<h1>Tooltip in Scatter Line Chart</h1>
- <div id="main13" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
- <h1>Tooltip in Boxplot Chart</h1>
- <div id="main14" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main13" class="chart"></div>
+ <h1>Tooltip both in Candlestick (show dims vertically) and Line</h1>
+ <div id="main14" class="chart"></div>
+ <h1>Tooltip in Map Series</h1>
+ <div id="main15" class="chart"></div>
<h1>Tooltip in Continuous Heatmap Chart</h1>
- <div id="main16" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main16" class="chart"></div>
<h1>Tooltip in Piecewise Heatmap Chart</h1>
- <div id="main17" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main17" class="chart"></div>
<h1>Tooltip in Gradien Line Chart</h1>
- <div id="main18" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main18" class="chart"></div>
<h1>Tooltip in Multiple X Axis Line Chart</h1>
- <div id="main19" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main19" class="chart"></div>
<h1>Tooltip in Gradient Bar Chart</h1>
- <div id="main20" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
- <h1>Tooltip in Stacked Bar Chart</h1>
- <div id="main21" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main20" class="chart"></div>
+ <h1>Tooltip in Stacked Bar Chart (check MarkPoint)</h1>
+ <div id="main21" class="chart"></div>
<h1>Tooltip in Stacked Bar Chart Horizontal</h1>
- <div id="main22" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main22" class="chart"></div>
<h1>Tooltip in Stacked Line Chart Horizontal</h1>
- <div id="main23" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main23" class="chart"></div>
<h1>Tooltip order valueAsc</h1>
- <div id="main24" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
- <h1>Tooltip order valueDesc</h1>
- <div id="main25" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main24" class="chart"></div>
+ <h1>'value' xAxis, valueDesc</h1>
+ <div id="main25" class="chart"></div>
<h1>Tooltip order seriesDesc</h1>
- <div id="main26" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main26" class="chart"></div>
<h1>Tooltip order seriesAsc</h1>
- <div id="main27" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
- <h1>Tooltip Rich text in Radar</h1>
- <div id="main28" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
- <h1>Tooltip Rich text in Line and valueDesc</h1>
- <div id="main29" style="width: 100vw;height:40vh;margin: 0 auto;"></div>
+ <div id="main27" class="chart"></div>
+ <h1>Tooltip Radar and valueAsc</h1>
+ <div id="main28" class="chart"></div>
+ <h1>Tooltip 'category' xAxis with number value and valueDesc</h1>
+ <div id="main29" class="chart"></div>
+ <h1>Tooltip Line 'time' xAxis</h1>
+ <div id="main30" class="chart"></div>
+ <h1>tooltip.formatter callback. Markers should be displayed.</h1>
+ <div id="main31" class="chart"></div>
+
<script>
+
+ var CURRENT_RENDER_MODE;
+ function initStateConsole() {
+ var TOOLTIP_RENDER_MODE_KEY = '__EC_TEST_TOOLTIP_RENDER_MODE__';
+ var RENDER_MODE_LIST = ['html', 'richText'];
+
+ CURRENT_RENDER_MODE = window.localStorage.getItem(TOOLTIP_RENDER_MODE_KEY);
+ if (!CURRENT_RENDER_MODE) {
+ CURRENT_RENDER_MODE = RENDER_MODE_LIST[0];
+ }
+
+ var containerDom = document.getElementById('stateConsoleSelect');
+ var html = [];
+ for (var i = 0; i < RENDER_MODE_LIST.length; i++) {
+ var modeVal = RENDER_MODE_LIST[i];
+ var checkedAttr = CURRENT_RENDER_MODE === modeVal ? ' checked="checked" ' : '';
+ var checkedStyle = CURRENT_RENDER_MODE === modeVal ? ' class="checked" ' : '';
+ html.push(
+ '<input type="radio" name="renderMode" ' + checkedAttr + ' value="' + modeVal + '">',
+ '<label ' + checkedStyle + 'for="' + modeVal + '">' + modeVal + '</label>'
+ );
+ }
+ containerDom.innerHTML = html.join('');
+ containerDom.onclick = function (e) {
+ var target = e.target;
+ if (target.tagName === 'INPUT') {
+ var newRenderMode = target.value;
+ window.localStorage.setItem(TOOLTIP_RENDER_MODE_KEY, newRenderMode);
+ location.reload();
+ }
+ };
+ }
+ initStateConsole();
+
+
require([
- 'echarts'
+ 'echarts', 'map/js/province/jiangsu'
], function (echarts) {
function createChart(domId) {
// Make some of the html able to be commented.
@@ -102,6 +187,7 @@ under the License.
var chart3 = createChart('main3');
var chart4 = createChart('main4');
var chart5 = createChart('main5');
+ var chart6 = createChart('main6');
var chart7 = createChart('main7');
var chart8 = createChart('main8');
var chart9 = createChart('main9');
@@ -110,6 +196,7 @@ under the License.
var chart12 = createChart('main12');
var chart13 = createChart('main13');
var chart14 = createChart('main14');
+ var chart15 = createChart('main15');
var chart16 = createChart('main16');
var chart17 = createChart('main17');
var chart18 = createChart('main18');
@@ -124,9 +211,12 @@ under the License.
var chart27 = createChart('main27');
var chart28 = createChart('main28');
var chart29 = createChart('main29');
+ var chart30 = createChart('main30');
+ var chart31 = createChart('main31');
option1 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'item',
position: 'bottom',
axisPointer: {
@@ -167,10 +257,8 @@ under the License.
};
option2 = {
- title: {
- text: '基础雷达图'
- },
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
// attachToPoint: true
},
radar: {
@@ -227,6 +315,7 @@ under the License.
option3 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'item',
// formatter: '{a} <br/>{b}: {c} ({d}%)'
},
@@ -274,7 +363,9 @@ under the License.
};
option4 = {
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
series: {
type: 'sankey',
layout: 'none',
@@ -321,17 +412,16 @@ under the License.
};
option5 = {
- title: {
- text: 'Graph 简单示例'
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
},
- tooltip: {},
animationDurationUpdate: 1500,
animationEasingUpdate: 'quinticInOut',
series: [{
type: 'graph',
layout: 'none',
symbolSize: 50,
- roam: true,
+ roam: false,
label: {
show: true
},
@@ -402,8 +492,69 @@ under the License.
}]
};
+ option6 = {
+ xAxis: {},
+ yAxis: {
+ name: 'Should display multi-dim of an item in one line',
+ nameTextStyle: {
+ align: 'left'
+ }
+ },
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ trigger: 'axis'
+ },
+ series: [{
+ type: 'scatter',
+ encode: {
+ tooltip: [0, 1],
+ label: 2
+ },
+ label: {
+ show: true,
+ position: 'top'
+ },
+ data: [
+ [121, 1222, 'trigger: axis\nshow 2 dim value\nheader: x value']
+ ]
+ }, {
+ type: 'scatter',
+ encode: {
+ tooltip: [1],
+ label: [2]
+ },
+ label: {
+ show: true,
+ position: 'top'
+ },
+ data: [
+ [121, 3444, 'trigger: axis\nshow 1 dim value\nheader: x value'],
+ [666, 4122, 'trigger: axis\nshow 1 dim value\nheader: x value']
+ ]
+ }, {
+ type: 'scatter',
+ encode: {
+ tooltip: [0, 1],
+ label: 2
+ },
+ tooltip: {
+ trigger: 'item'
+ },
+ label: {
+ show: true,
+ position: 'top'
+ },
+ data: [
+ [321, 0, 'trigger: item\nshow 2 dim value'],
+ [466, 4122, 'trigger: item\nshow 2 dim value']
+ ]
+ }]
+ };
+
option7 = {
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
series: [{
type: "tree",
data: [{
@@ -428,7 +579,7 @@ under the License.
value: 25,
}]
}, {
- name: "Child B",
+ name: "Child B (should no value)",
children: [{
name: "Leaf G",
value: 26,
@@ -1169,12 +1320,8 @@ under the License.
});
option8 = {
- title: {
- text: '雨量流量关系图',
- subtext: '数据来自西安兰特水电测控技术有限公司',
- left: 'center'
- },
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
animation: false
@@ -1725,6 +1872,7 @@ under the License.
option9 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
type: 'cross',
@@ -1764,9 +1912,12 @@ under the License.
};
option10 = {
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
series: [{
type: 'treemap',
+ roam: false,
data: [{
name: 'nodeA', // First tree
value: 10,
@@ -1793,7 +1944,9 @@ under the License.
};
option11 = {
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
dataset: {
source: [
['product', '2015', '2016', '2017'],
@@ -1823,6 +1976,7 @@ under the License.
option12 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
type: 'cross',
@@ -1832,6 +1986,9 @@ under the License.
}
},
legend: {
+ tooltip: {
+ show: true
+ },
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
},
grid: {
@@ -1853,17 +2010,6 @@ under the License.
type: 'line',
stack: '总量',
areaStyle: {},
- // markPoint: {
- // data: [{
- // type: 'max',
- // name: '最大值'
- // },
- // {
- // type: 'min',
- // name: '最小值'
- // }
- // ]
- // },
data: [150, 232, 201, 154, 190, 330, 410]
},
{
@@ -1871,17 +2017,6 @@ under the License.
type: 'line',
stack: '总量',
areaStyle: {},
- // markPoint: {
- // data: [{
- // type: 'max',
- // name: '最大值'
- // },
- // {
- // type: 'min',
- // name: '最小值'
- // }
- // ]
- // },
data: [320, 332, 301, 334, 390, 430, 320]
},
{
@@ -2010,6 +2145,7 @@ under the License.
}
],
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
formatter: 'Group {a}: ({c})'
},
xAxis: [{
@@ -2090,24 +2226,66 @@ under the License.
};
option14 = {
- tooltip: {},
+ tooltip: {
+ trigger: 'axis',
+ renderMode: CURRENT_RENDER_MODE,
+ },
xAxis: {
data: ['2017-10-24', '2017-10-25', '2017-10-26', '2017-10-27']
},
yAxis: {},
series: [{
- type: 'k',
+ type: 'candlestick',
data: [
[20, 30, 10, 35],
[40, 35, 30, 55],
[33, 38, 33, 40],
[40, 40, 32, 42]
]
+ }, {
+ type: 'line',
+ data: [
+ 4, 5, 1, 3
+ ]
+ }]
+ };
+
+ option15 = {
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
+ legend: {},
+ series: [{
+ name: '<A>',
+ type: 'map',
+ mapType: '江苏',
+ showLegendSymbol: true,
+ selectedMap: {
+ '南京市': true
+ },
+ data: [
+ { name: '南京市', value: 100 },
+ { name: '苏州市', value: null },
+ ]
+ }, {
+ name: '<B>',
+ type: 'map',
+ mapType: '江苏',
+ showLegendSymbol: true,
+ selectedMap: {
+ '南京市': true
+ },
+ data: [
+ { name: '南京市', value: 50 },
+ { name: '苏州市', value: 30 },
+ ]
}]
};
option16 = {
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
xAxis: {
type: "category",
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
@@ -2270,7 +2448,9 @@ under the License.
}
option17 = {
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
xAxis: {
type: "category",
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
@@ -2522,6 +2702,7 @@ under the License.
text: 'Gradient along the x axis'
}],
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis'
},
xAxis: [{
@@ -2564,13 +2745,13 @@ under the License.
color: colors,
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
- data: ['2015 降水量', '2016 降水量']
},
grid: {
top: 70,
@@ -2614,8 +2795,8 @@ under the License.
axisPointer: {
label: {
formatter: function (params) {
- return '降水量 ' + params.value +
- (params.seriesData.length ? ':' + params.seriesData[0]
+ return 'precipitation ' + params.value +
+ (params.seriesData.length ? ': ' + params.seriesData[0]
.data : '');
}
}
@@ -2629,13 +2810,14 @@ under the License.
type: 'value'
}],
series: [{
- name: '2015 降水量',
+ name: '2015 precipitation',
type: 'line',
xAxisIndex: 1,
smooth: true,
data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
},
{
+ // Make the length of name different with the previous one.
name: '2016 降水量',
type: 'line',
smooth: true,
@@ -2658,7 +2840,9 @@ under the License.
}
option20 = {
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
xAxis: {
data: dataAxis,
axisLabel: {
@@ -2748,72 +2932,91 @@ under the License.
option21 = {
legend: {},
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
dataset: {
source: [
- ['product', '2012', '2013', '2014', '2015'],
+ // ['product', '2012', '2013', '2014', '2015'],
['Matcha Latte', 41.1, 130.4, 65.1, 53.3],
['Milk Tea', 86.5, 92.1, 85.7, 83.1],
['Cheese Cocoa', 124.1, 67.2, 79.5, 86.4]
- ]
+ ],
+ sourceHeader: false
},
- xAxis: {
+ grid: [{
+ right: '55%'
+ }, {
+ left: '55%'
+ }],
+ xAxis: [{
type: 'category',
- },
- yAxis: {},
+ axisLabel: { interval: 0 }
+ }, {
+ gridIndex: 1
+ }],
+ yAxis: [{
+ }, {
+ name: 'left markPoint no name, should align center',
+ nameTextStyle: { align: 'left' },
+ gridIndex: 1
+ }],
series: [{
- type: 'bar',
- seriesLayoutBy: 'row',
- stack: '1',
- markPoint: {
- data: [{
- type: 'max',
- name: '最大值'
- },
- {
- type: 'min',
- name: '最小值'
- }
- ]
- },
+ type: 'bar',
+ seriesLayoutBy: 'column',
+ stack: '1',
+ markPoint: {
+ data: [{
+ type: 'max',
+ name: '最大值'
+ },
+ {
+ type: 'min',
+ name: '最小值'
+ }
+ ]
},
- {
- type: 'bar',
- seriesLayoutBy: 'row',
- stack: '1',
- markPoint: {
- data: [{
- type: 'max',
- name: '最大值'
- },
- {
- type: 'min',
- name: '最小值'
- }
- ]
- },
+ }, {
+ type: 'bar',
+ seriesLayoutBy: 'column',
+ stack: '1',
+ markPoint: {
+ data: [{
+ type: 'max',
+ // test if no name
+ // name: '最大值'
+ },
+ {
+ type: 'min',
+ name: '最小值'
+ }
+ ]
},
- {
- type: 'bar',
- seriesLayoutBy: 'row',
- stack: '1',
- markPoint: {
- data: [{
- type: 'max',
- name: '最大值'
- },
- {
- type: 'min',
- name: '最小值'
- }
- ]
- },
- }
- ]
+ }, {
+ name: 'series long long name',
+ type: 'line',
+ encode: { x: 1, y: 2 },
+ markPoint: {
+ data: [{
+ type: 'max',
+ // test if no name
+ // name: '最大值'
+ },
+ {
+ type: 'min',
+ name: '最小值'
+ }
+ ]
+ },
+ xAxisIndex: 1,
+ yAxisIndex: 1
+ }]
}
option22 = {
- tooltip: {},
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ },
legend: {
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
},
@@ -2831,60 +3034,56 @@ under the License.
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
series: [{
- name: '直接访问',
- type: 'bar',
- stack: '总量',
- label: {
- show: true,
- position: 'insideRight'
- },
- data: [320, 302, 301, 334, 390, 330, 320]
+ name: '直接访问',
+ type: 'bar',
+ stack: '总量',
+ label: {
+ show: true,
+ position: 'insideRight'
},
- {
- name: '邮件营销',
- type: 'bar',
- stack: '总量',
- label: {
- show: true,
- position: 'insideRight'
- },
- data: [120, 132, 101, 134, 90, 230, 210]
+ data: [320, 302, 301, 334, 390, 330, 320]
+ }, {
+ name: '邮件营销',
+ type: 'bar',
+ stack: '总量',
+ label: {
+ show: true,
+ position: 'insideRight'
},
- {
- name: '联盟广告',
- type: 'bar',
- stack: '总量',
- label: {
- show: true,
- position: 'insideRight'
- },
- data: [220, 182, 191, 234, 290, 330, 310]
+ data: [120, 132, 101, 134, 90, 230, 210]
+ }, {
+ name: '联盟广告',
+ type: 'bar',
+ stack: '总量',
+ label: {
+ show: true,
+ position: 'insideRight'
},
- {
- name: '视频广告',
- type: 'bar',
- stack: '总量',
- label: {
- show: true,
- position: 'insideRight'
- },
- data: [150, 212, 201, 154, 190, 330, 410]
+ data: [220, 182, 191, 234, 290, 330, 310]
+ }, {
+ name: '视频广告',
+ type: 'bar',
+ stack: '总量',
+ label: {
+ show: true,
+ position: 'insideRight'
},
- {
- name: '搜索引擎',
- type: 'bar',
- stack: '总量',
- label: {
- show: true,
- position: 'insideRight'
- },
- data: [820, 832, 901, 934, 1290, 1330, 1320]
- }
- ]
+ data: [150, 212, 201, 154, 190, 330, 410]
+ }, {
+ name: '搜索引擎',
+ type: 'bar',
+ stack: '总量',
+ label: {
+ show: true,
+ position: 'insideRight'
+ },
+ data: [820, 832, 901, 934, 1290, 1330, 1320]
+ }]
};
option23 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
type: 'cross',
@@ -2911,42 +3110,29 @@ under the License.
type: 'value'
}],
series: [{
- name: '视频广告',
- type: 'line',
- stack: '总量',
- areaStyle: {},
- data: [150, 232, 201, 154, 190, 330, 410]
- },
- {
- name: '直接访问',
- type: 'line',
- stack: '总量',
- areaStyle: {},
- data: [320, 332, 301, 334, 390, 430, 320]
- },
- {
- name: '搜索引擎',
- type: 'line',
- stack: '总量',
- areaStyle: {},
- markPoint: {
- data: [{
- type: 'max',
- name: '最大值'
- },
- {
- type: 'min',
- name: '最小值'
- }
- ]
- },
- data: [820, 932, 901, 934, 1290, 1330, 1320]
- }
- ]
+ name: '视频广告',
+ type: 'line',
+ stack: '总量',
+ areaStyle: {},
+ data: [150, 232, 201, 154, 190, 330, 410]
+ }, {
+ name: '直接访问',
+ type: 'line',
+ stack: '总量',
+ areaStyle: {},
+ data: [320, 332, 301, 334, 390, 430, 320]
+ }, {
+ name: '搜索引擎',
+ type: 'line',
+ stack: '总量',
+ areaStyle: {},
+ data: [820, 932, 901, 934, 1290, 1330, 1320]
+ }]
};
option24 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
type: 'cross',
@@ -2995,6 +3181,7 @@ under the License.
option25 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
type: 'cross',
@@ -3005,44 +3192,49 @@ under the License.
order: 'valueDesc'
},
xAxis: [{
- type: 'category',
- boundaryGap: false,
- data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
}],
yAxis: [{
- type: 'value'
}],
- series: [
- {
- name: '邮件营销',
- type: 'line',
- data: [120, 132, 101, 134, 90, 230, 210]
- },
- {
- name: '联盟广告',
- type: 'line',
- data: [220, 182, 191, 234, 290, 630, 310]
- },
- {
- name: '视频广告',
- type: 'line',
- data: [150, 232, 201, 154, 190, 430, 410]
- },
- {
- name: '直接访问',
- type: 'line',
- data: [320, 332, 301, 334, 390, 330, 320]
- },
- {
- name: '搜索引擎',
- type: 'line',
- data: [820, 932, 901, 934, 1290, 1330, 1320]
- }
- ]
+ legend: {},
+ series: [{
+ name: 'AA',
+ type: 'scatter',
+ encode: { tooltip: [1, 2] },
+ data: [
+ [1903, 15, 0.332],
+ [2277, 231, 0.142],
+ [1000, 89, 1.552],
+ [2000, 194, 0.998],
+ [1800, 105, 1.291]
+ ]
+ }, {
+ name: 'BB',
+ type: 'scatter',
+ encode: { tooltip: [1, 2] },
+ data: [
+ [1903, 99, 0.552],
+ [2277, 23, 0.981],
+ [1000, 98, 1.455],
+ [2000, 71, 0.311],
+ [1800, 157, 0.891]
+ ]
+ }, {
+ name: 'CC',
+ type: 'scatter',
+ encode: { tooltip: [1, 2] },
+ data: [
+ [1903, 81, 0.111],
+ [2277, 71, 1.000],
+ [1000, 125, 0.998],
+ [2000, 20, 0.512],
+ [1800, 78, 1.001]
+ ]
+ }]
};
option26 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
type: 'cross',
@@ -3052,6 +3244,7 @@ under the License.
},
order: 'seriesDesc'
},
+ legend: {},
xAxis: [{
type: 'category',
boundaryGap: false,
@@ -3063,27 +3256,32 @@ under the License.
series: [
{
name: '邮件营销',
- type: 'line',
+ type: 'bar',
+ stack: 'a',
data: [120, 132, 101, 134, 90, 230, 210]
},
{
name: '联盟广告',
- type: 'line',
+ type: 'bar',
+ stack: 'a',
data: [220, 182, 191, 234, 290, 630, 310]
},
{
name: '视频广告',
- type: 'line',
+ type: 'bar',
+ stack: 'a',
data: [150, 232, 201, 154, 190, 430, 410]
},
{
name: '直接访问',
- type: 'line',
+ type: 'bar',
+ stack: 'a',
data: [320, 332, 301, 334, 390, 330, 320]
},
{
name: '搜索引擎',
- type: 'line',
+ type: 'bar',
+ stack: 'a',
data: [820, 932, 901, 934, 1290, 1330, 1320]
}
]
@@ -3091,6 +3289,7 @@ under the License.
option27 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
axisPointer: {
type: 'cross',
@@ -3100,6 +3299,7 @@ under the License.
},
order: 'seriesAsc'
},
+ legend: {},
xAxis: [{
type: 'category',
boundaryGap: false,
@@ -3112,39 +3312,46 @@ under the License.
{
name: '邮件营销',
type: 'line',
+ stack: 'a',
+ areaStyle: {},
data: [120, 132, 101, 134, 90, 230, 210]
},
{
name: '联盟广告',
type: 'line',
+ stack: 'a',
+ areaStyle: {},
data: [220, 182, 191, 234, 290, 630, 310]
},
{
name: '视频广告',
type: 'line',
+ stack: 'a',
+ areaStyle: {},
data: [150, 232, 201, 154, 190, 430, 410]
},
{
name: '直接访问',
type: 'line',
+ stack: 'a',
+ areaStyle: {},
data: [320, 332, 301, 334, 390, 330, 320]
},
{
name: '搜索引擎',
type: 'line',
+ stack: 'a',
+ areaStyle: {},
data: [820, 932, 901, 934, 1290, 1330, 1320]
}
]
};
option28 = {
- title: {
- text: '基础雷达图'
- },
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
order: 'valueAsc',
// position: 'top',
- renderMode: 'richText'
},
radar: {
// shape: 'circle',
@@ -3200,6 +3407,7 @@ under the License.
option29 = {
tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
trigger: 'axis',
position: 'top',
axisPointer: {
@@ -3209,12 +3417,12 @@ under the License.
}
},
order: 'valueDesc',
- renderMode: 'richText'
},
+ legend: {},
xAxis: [{
type: 'category',
boundaryGap: false,
- data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
+ data: [2001, 2002, 2003, 2004, 2005, 2006, 2007]
}],
yAxis: [{
type: 'value'
@@ -3248,11 +3456,113 @@ under the License.
]
};
+ option30 = {
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ trigger: 'axis',
+ position: 'top',
+ axisPointer: {
+ type: 'cross',
+ label: {
+ backgroundColor: '#6a7985'
+ }
+ }
+ },
+ xAxis: [{
+ type: 'time'
+ }],
+ yAxis: [{
+ }],
+ series: [
+ {
+ type: 'line',
+ data: [
+ ['2012-05-19', 120],
+ [new Date(2012, 4, 20), 132],
+ [+new Date(2012, 4, 21), 101],
+ ['2012-05-22 00:00:00', 134],
+ ['2012-05-23T00:00:00', 90]
+ ]
+ },
+ {
+ type: 'line',
+ data: [
+ ['2012-05-19', 220],
+ ['2012-05-21', 182],
+ ['2012-05-22', 191],
+ ['2012-05-23', 234],
+ ['2012-05-24', 290]
+ ]
+ }
+ ]
+ };
+
+ option31 = {
+ tooltip: {
+ renderMode: CURRENT_RENDER_MODE,
+ trigger: 'axis',
+ position: 'top',
+ axisPointer: {
+ type: 'cross',
+ label: {
+ backgroundColor: '#6a7985'
+ }
+ },
+ formatter: function (params) {
+ if (CURRENT_RENDER_MODE === 'richText') {
+ var content = ['Formatter Result:'];
+ for (var i = 0; i < params.length; i++) {
+ var param = params[i];
+ content.push(param.marker + ' ' + param.value.join(' '));
+ }
+ return content.join('\n');
+ }
+ else {
+ var content = ['<div>Formatter Result:</div>'];
+ for (var i = 0; i < params.length; i++) {
+ var param = params[i];
+ content.push('<div>' + param.marker + param.value.join(' ') + '</div>');
+ }
+ return content.join('');
+ }
+ }
+ },
+ xAxis: [{
+ type: 'time'
+ }],
+ yAxis: [{
+ }],
+ series: [
+ {
+ type: 'line',
+ data: [
+ ['2012-05-19', 120],
+ [new Date(2012, 4, 20), 132],
+ [+new Date(2012, 4, 21), 101],
+ ['2012-05-22 00:00:00', 134],
+ ['2012-05-23T00:00:00', 90]
+ ]
+ },
+ {
+ type: 'line',
+ data: [
+ ['2012-05-19', 220],
+ ['2012-05-21', 182],
+ ['2012-05-22', 191],
+ ['2012-05-23', 234],
+ ['2012-05-24', 290]
+ ]
+ }
+ ]
+ };
+
+
chart1 && chart1.setOption(option1);
chart2 && chart2.setOption(option2);
chart3 && chart3.setOption(option3);
chart4 && chart4.setOption(option4);
chart5 && chart5.setOption(option5);
+ chart6 && chart6.setOption(option6);
chart7 && chart7.setOption(option7);
chart8 && chart8.setOption(option8);
chart9 && chart9.setOption(option9);
@@ -3261,6 +3571,7 @@ under the License.
chart12 && chart12.setOption(option12);
chart13 && chart13.setOption(option13);
chart14 && chart14.setOption(option14);
+ chart15 && chart15.setOption(option15);
chart16 && chart16.setOption(option16);
chart17 && chart17.setOption(option17);
chart18 && chart18.setOption(option18);
@@ -3275,6 +3586,8 @@ under the License.
chart27 && chart27.setOption(option27);
chart28 && chart28.setOption(option28);
chart29 && chart29.setOption(option29);
+ chart30 && chart30.setOption(option30);
+ chart31 && chart31.setOption(option31);
});
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org