This is an automated email from the ASF dual-hosted git repository. ovilia pushed a commit to branch fix-legend-style in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
commit 796b981b2dfe858cb46cb4b6be185a4f0efce166 Author: Ovilia <zwl.s...@gmail.com> AuthorDate: Thu Apr 16 11:48:50 2020 +0800 feat(legend): more intuitove legend design --- src/chart/line.ts | 16 ++++ src/chart/line/LineSeries.ts | 13 +++- src/component/legend/LegendModel.ts | 2 +- src/component/legend/LegendView.ts | 50 ++++++++---- src/data/List.ts | 3 +- src/util/symbol.ts | 24 +++--- src/visual/style.ts | 10 ++- test/legend-style.html | 146 ++++++++++++++++++++++++++++++++++++ 8 files changed, 230 insertions(+), 34 deletions(-) diff --git a/src/chart/line.ts b/src/chart/line.ts index 541b481..b70fd23 100644 --- a/src/chart/line.ts +++ b/src/chart/line.ts @@ -27,9 +27,25 @@ import dataSample from '../processor/dataSample'; // In case developer forget to include grid component import '../component/gridSimple'; +import LineSeriesModel from './line/LineSeries'; echarts.registerLayout(layoutPoints('line')); +echarts.registerVisual({ + seriesType: 'line', + reset: function (seriesModel: LineSeriesModel) { + // Visual coding for legend + const lineStyle = seriesModel.getModel('lineStyle'); + console.log(lineStyle.get('color'), lineStyle.get('width')) + if (lineStyle) { + seriesModel.getData().setVisual('legendSymbolStyle', { + color: lineStyle.get('color'), + borderWidth: lineStyle.get('width') + }); + } + } +}); + // Down sample after filter echarts.registerProcessor( echarts.PRIORITY.PROCESSOR.STATISTIC, diff --git a/src/chart/line/LineSeries.ts b/src/chart/line/LineSeries.ts index 1fcb748..8383aad 100644 --- a/src/chart/line/LineSeries.ts +++ b/src/chart/line/LineSeries.ts @@ -36,6 +36,9 @@ import { import List from '../../data/List'; import type Cartesian2D from '../../coord/cartesian/Cartesian2D'; import type Polar from '../../coord/polar/Polar'; +import makeStyleMapper from '../../model/mixin/makeStyleMapper'; +import {ITEM_STYLE_KEY_MAP} from '../../model/mixin/itemStyle'; +import {LINE_STYLE_KEY_MAP} from '../../model/mixin/lineStyle'; type LineDataValue = OptionDataValue | OptionDataValue[]; @@ -106,6 +109,8 @@ class LineSeriesModel extends SeriesModel<LineSeriesOption> { hasSymbolVisual = true; legendSymbol = 'line'; + visualDrawType = 'stroke' as const; + getInitialData(option: LineSeriesOption): List { if (__DEV__) { const coordSys = option.coordinateSystem; @@ -132,6 +137,12 @@ class LineSeriesModel extends SeriesModel<LineSeriesOption> { position: 'top' }, + itemStyle: { + color: 'white', + borderColor: 'auto', + borderWidth: 1 + }, + lineStyle: { width: 2, type: 'solid' @@ -149,7 +160,7 @@ class LineSeriesModel extends SeriesModel<LineSeriesOption> { // Disabled if step is true smooth: false, smoothMonotone: null, - symbol: 'emptyCircle', + symbol: 'circle', symbolSize: 4, symbolRotate: null, diff --git a/src/component/legend/LegendModel.ts b/src/component/legend/LegendModel.ts index 290b7b3..fa4298a 100644 --- a/src/component/legend/LegendModel.ts +++ b/src/component/legend/LegendModel.ts @@ -391,7 +391,7 @@ class LegendModel<Ops extends LegendOption = LegendOption> extends ComponentMode inactiveBorderColor: '#ccc', itemStyle: { - borderWidth: 0 + // borderWidth: 0 }, textStyle: { diff --git a/src/component/legend/LegendView.ts b/src/component/legend/LegendView.ts index dafa108..dbefd0e 100644 --- a/src/component/legend/LegendView.ts +++ b/src/component/legend/LegendView.ts @@ -34,12 +34,17 @@ import { ZRRectLike, ECElement, CommonTooltipOption, - ColorString + ColorString, + SeriesOption, + SymbolOptionMixin } from '../../util/types'; import Model from '../../model/Model'; import Displayable from 'zrender/src/graphic/Displayable'; import { PathStyleProps } from 'zrender/src/graphic/Path'; import { parse, stringify } from 'zrender/src/tool/color'; +import SeriesModel from '../../model/Series'; +import {LineStyleMixin} from '../../model/mixin/lineStyle'; +import {LineDrawModelOption} from '../../chart/helper/LineDraw'; const curry = zrUtil.curry; const each = zrUtil.each; @@ -184,7 +189,8 @@ class LegendView extends ComponentView { } // Representitive series. - const seriesModel = ecModel.getSeriesByName(name)[0]; + const seriesModel = ecModel.getSeriesByName(name)[0] as + SeriesModel<SeriesOption & SymbolOptionMixin>; if (legendDrawnMap.get(name)) { // Have been drawed @@ -197,16 +203,19 @@ class LegendView extends ComponentView { const style = data.getVisual('style'); const color = style.fill; const borderColor = style.stroke; + const borderWidth = style.lineWidth; // Using rect symbol defaultly const legendSymbolType = data.getVisual('legendSymbol') || 'roundRect'; + const legendSymbolStyle = data.getVisual('legendSymbolStyle') || {}; const symbolType = data.getVisual('symbol'); + const symbolSize = seriesModel.get('symbolSize'); const itemGroup = this._createItem( name, dataIndex, itemModel, legendModel, - legendSymbolType, symbolType, - itemAlign, color, borderColor, - selectMode + legendSymbolType, symbolType, symbolSize, + itemAlign, color, borderColor, borderWidth, + legendSymbolStyle, selectMode ); itemGroup.on('click', curry(dispatchSelectAction, name, null, api, excludeSeriesId)) @@ -234,6 +243,7 @@ class LegendView extends ComponentView { const style = provider.getItemVisual(idx, 'style') as PathStyleProps; const borderColor = style.stroke; + const borderWidth = style.lineWidth; let color = style.fill; const colorArr = parse(style.fill as ColorString); // Color may be set to transparent in visualMap when data is out of range. @@ -248,9 +258,9 @@ class LegendView extends ComponentView { const itemGroup = this._createItem( name, dataIndex, itemModel, legendModel, - legendSymbolType, null, - itemAlign, color, borderColor, - selectMode + legendSymbolType, null, null, + itemAlign, color, borderColor, borderWidth, + {}, selectMode ); // FIXME: consider different series has items with the same name. @@ -328,11 +338,19 @@ class LegendView extends ComponentView { legendModel: LegendModel, legendSymbolType: string, symbolType: string, + symbolSize: number | number[], itemAlign: LegendOption['align'], color: ZRColor, borderColor: ZRColor, + borderWidth: number, + legendSymbolStyle: ItemStyleOption, selectMode: LegendOption['selectedMode'] ) { + if (symbolSize != null && typeof symbolSize === 'object') { + // Use symbol height as symbol size if it's an array + symbolSize = symbolSize[1]; + } + const itemWidth = legendModel.get('itemWidth'); const itemHeight = legendModel.get('itemHeight'); const inactiveColor = legendModel.get('inactiveColor'); @@ -365,7 +383,8 @@ class LegendView extends ComponentView { itemGroup.add( setSymbolStyle( legendSymbol, legendSymbolType, legendModelItemStyle, - borderColor, inactiveBorderColor, isSelected + legendSymbolStyle.color || borderColor, legendSymbolStyle.borderWidth || borderWidth, + inactiveBorderColor, isSelected ) ); @@ -375,7 +394,9 @@ class LegendView extends ComponentView { // At least show one symbol, can't be all none && ((symbolType !== legendSymbolType) || symbolType === 'none') ) { - const size = itemHeight * 0.8; + const size = symbolSize == null + ? itemHeight * 0.8 + : Math.min(itemHeight, symbolSize as number); if (symbolType === 'none') { symbolType = 'circle'; } @@ -393,7 +414,7 @@ class LegendView extends ComponentView { itemGroup.add( setSymbolStyle( legendSymbolCenter, symbolType, legendModelItemStyle, - borderColor, inactiveBorderColor, isSelected + borderColor, borderWidth, inactiveBorderColor, isSelected ) ); } @@ -547,13 +568,16 @@ function setSymbolStyle( symbolType: string, legendModelItemStyle: Model<ItemStyleOption>, borderColor: ZRColor, + borderWidth: number, inactiveBorderColor: ZRColor, isSelected: boolean ) { let itemStyle; - if (symbolType !== 'line' && symbolType.indexOf('empty') < 0) { + if (symbolType.indexOf('empty') < 0) { itemStyle = legendModelItemStyle.getItemStyle(); - (symbol as graphic.Path).style.stroke = borderColor; + itemStyle.lineWidth = borderWidth; + // itemStyle. + itemStyle.stroke = borderColor; if (!isSelected) { itemStyle.stroke = inactiveBorderColor; } diff --git a/src/data/List.ts b/src/data/List.ts index 1a0c93b..a8656b2 100644 --- a/src/data/List.ts +++ b/src/data/List.ts @@ -35,7 +35,7 @@ import {ArrayLike, Dictionary, FunctionPropertyNames} from 'zrender/src/core/typ import Element from 'zrender/src/Element'; import { DimensionIndex, DimensionName, DimensionLoose, OptionDataItem, - ParsedValue, ParsedValueNumeric, OrdinalNumber, DimensionUserOuput, ModelOption + ParsedValue, ParsedValueNumeric, OrdinalNumber, DimensionUserOuput, ModelOption, ItemStyleOption, LineStyleOption } from '../util/types'; import {parseDate} from '../util/number'; import {isDataItemOption} from '../util/model'; @@ -136,6 +136,7 @@ export interface DefaultDataVisual { liftZ?: number // For legend. legendSymbol?: string + legendSymbolStyle?: ItemStyleOption // visualMap will inject visualMeta data visualMeta?: VisualMeta[] diff --git a/src/util/symbol.ts b/src/util/symbol.ts index a0bedde..64daf12 100644 --- a/src/util/symbol.ts +++ b/src/util/symbol.ts @@ -174,9 +174,7 @@ const Arrow = graphic.Path.extend({ */ // TODO Use function to build symbol path. const symbolCtors: Dictionary<SymbolCtor> = { - // Use small height rect to simulate line. - // Avoid using stroke. - line: graphic.Rect as unknown as SymbolCtor, + line: graphic.Line as unknown as SymbolCtor, rect: graphic.Rect as unknown as SymbolCtor, @@ -195,17 +193,13 @@ const symbolCtors: Dictionary<SymbolCtor> = { triangle: Triangle as unknown as SymbolCtor }; - -// NOTICE Only use fill. No line! const symbolShapeMakers: Dictionary<SymbolShapeMaker> = { - line: function (x, y, w, h, shape: graphic.Rect['shape']) { - const thickness = 2; - // A thin line - shape.x = x; - shape.y = y + h / 2 - thickness / 2; - shape.width = w; - shape.height = thickness; + line: function (x, y, w, h, shape: graphic.Line['shape']) { + shape.x1 = x; + shape.y1 = y + h / 2; + shape.x2 = x + w; + shape.y2 = y + h / 2; }, rect: function (x, y, w, h, shape: graphic.Rect['shape']) { @@ -317,8 +311,6 @@ function symbolPathSetColor(this: ECSymbol, color: ZRColor, innerColor?: string) if (this.__isEmptyBrush) { symbolStyle.stroke = color; symbolStyle.fill = innerColor || '#fff'; - // TODO Same width with lineStyle in LineView. - symbolStyle.lineWidth = 2; } else { symbolStyle.fill = color; @@ -344,7 +336,9 @@ export function createSymbol( const isEmpty = symbolType.indexOf('empty') === 0; if (isEmpty) { - symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6); + const realSymbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6); + console.warn(`[DEPRECATED] Shape "${symbolType}" is deprecated. Please use "${realSymbolType}" with "fill" as "white" instead.`); + symbolType = realSymbolType; } let symbolPath: ECSymbol | graphic.Image; diff --git a/src/visual/style.ts b/src/visual/style.ts index 78f2d56..837d6a7 100644 --- a/src/visual/style.ts +++ b/src/visual/style.ts @@ -18,7 +18,7 @@ */ import { isFunction, extend, createHashMap } from 'zrender/src/core/util'; -import { StageHandler, CallbackDataParams, ZRColor, Dictionary } from '../util/types'; +import { StageHandler, CallbackDataParams, ZRColor, Dictionary, SeriesOption, SymbolOptionMixin } from '../util/types'; import makeStyleMapper from '../model/mixin/makeStyleMapper'; import { ITEM_STYLE_KEY_MAP } from '../model/mixin/itemStyle'; import { LINE_STYLE_KEY_MAP } from '../model/mixin/lineStyle'; @@ -83,11 +83,15 @@ const seriesStyleTask: StageHandler = { // TODO style callback const colorCallback = isFunction(color) ? color as unknown as ColorCallback : null; // Default - if ((!globalStyle[colorKey] || colorCallback) && !seriesModel.useColorPaletteOnData) { - globalStyle[colorKey] = seriesModel.getColorFromPalette( + if ((!globalStyle[colorKey] || colorCallback || globalStyle.fill === 'auto' || globalStyle.stroke) + && !seriesModel.useColorPaletteOnData + ) { + var colorPalette = seriesModel.getColorFromPalette( // TODO series count changed. seriesModel.name, null, ecModel.getSeriesCount() ); + globalStyle.fill = globalStyle.fill === 'auto' ? colorPalette : globalStyle.fill; + globalStyle.stroke = globalStyle.stroke === 'auto' ? colorPalette : globalStyle.stroke; } data.setVisual('style', globalStyle); diff --git a/test/legend-style.html b/test/legend-style.html new file mode 100644 index 0000000..3022a5c --- /dev/null +++ b/test/legend-style.html @@ -0,0 +1,146 @@ +<!DOCTYPE html> +<!-- +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. +--> + + +<html> + <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> + <script src="lib/jquery.min.js"></script> + <script src="lib/facePrint.js"></script> + <script src="lib/testHelper.js"></script> + <!-- <script src="ut/lib/canteen.js"></script> --> + <link rel="stylesheet" href="lib/reset.css" /> + </head> + <body> + <style> + </style> + + + <div id="main1"></div> + + <script> + require(['echarts'], function (echarts) { + var getData = function (seriesId) { + var data = []; + for (var i = 0; i < 7; ++i) { + data.push(Math.random() * 100 + (seriesId + 1) * 200); + } + return data; + }; + + var option = { + xAxis: { + type: 'category', + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] + }, + yAxis: { + type: 'value' + }, + legend: { + data: ['Default Line', 'Line with emptyCircle', 'Line with emptyCircle and color', 'Line with style', 'Line with visualMap', 'Pie A', 'Pie B', 'Pie C'] + }, + series: [{ + data: getData(0), + type: 'line', + name: 'Default Line' + }, { + data: getData(1), + type: 'line', + name: 'Line with emptyCircle', + symbol: 'emptyCircle' + }, { + data: getData(2), + type: 'line', + name: 'Line with emptyCircle and color', + symbol: 'emptyCircle', + itemStyle: { + color: 'auto' + } + }, { + data: getData(3), + type: 'line', + name: 'Line with style', + symbolSize: 12, + itemStyle: { + color: 'auto', + borderColor: 'blue', + borderWidth: 2, + symbolSize: 25 + }, + lineStyle: { + color: 'red', + width: 4 + } + }, { + data: getData(4), + type: 'line', + name: 'Line with visualMap', + symbolSize: 30, + itemStyle: { + borderColor: 'green' + } + }, { + type: 'pie', + data: [{ + name: 'Pie A', + value: 10 + }, { + name: 'Pie B', + value: 8 + }, { + name: 'Pie C', + value: 14, + itemStyle: { + color: 'blue' + } + }], + center: ['80%', '50%'] + }], + grid: { + left: 60, + width: '55%' + }, + visualMap: { + type: 'continuous', + min: 1000, + max: 1100, + inRange: { + color: ['green', 'yellow', 'red'] + }, + show: false, + seriesIndex: 4 + } + }; + + var chart = testHelper.create(echarts, 'main1', { + title: [ + 'Legend icon being more intuitive' + ], + option: option + }); + }); + </script> + + + </body> +</html> --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org For additional commands, e-mail: commits-h...@echarts.apache.org