提交 c2eaa34f 编写于 作者: S susiwen8

Merge branch 'next' into tooltip

......@@ -55,8 +55,6 @@ abstract class ExtensionAPI {
// Implemented in echarts.js
abstract getCoordinateSystems(): CoordinateSystemMaster[];
// Implemented in echarts.js
abstract getComponentByElement(el: Element): ComponentModel;
}
......
......@@ -626,7 +626,6 @@ const elementCreator: {
shape: extend({}, layout),
z2: 1
});
// rect.autoBatch = true;
rect.name = 'item';
......
......@@ -38,6 +38,7 @@ import type Element from 'zrender/src/Element';
import { getDefaultLabel } from '../helper/labelHelper';
import { PathProps, PathStyleProps } from 'zrender/src/graphic/Path';
import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle';
import ZRImage from 'zrender/src/graphic/Image';
const BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'borderWidth'] as const;
......@@ -888,7 +889,18 @@ function updateCommon(
const blurScope = emphasisModel.get('blurScope');
eachPath(bar, function (path) {
path.useStyle(symbolMeta.style);
if (path instanceof ZRImage) {
const pathStyle = path.style;
path.useStyle(zrUtil.extend({
// TODO other properties like dx, dy ?
image: pathStyle.image,
x: pathStyle.x, y: pathStyle.y,
width: pathStyle.width, height: pathStyle.height
}, symbolMeta.style));
}
else {
path.useStyle(symbolMeta.style);
}
const emphasisState = path.ensureState('emphasis');
emphasisState.style = emphasisStyle;
......
......@@ -500,7 +500,7 @@ class CustomSeriesView extends ChartView {
function setIncrementalAndHoverLayer(el: Displayable) {
if (!el.isGroup) {
el.incremental = true;
el.useHoverLayer = true;
el.ensureState('emphasis').hoverLayer = true;
}
}
for (let idx = params.start; idx < params.end; idx++) {
......
......@@ -264,7 +264,9 @@ class GaugeView extends ChartView {
y: unitY * (r - splitLineLen - distance) + cy,
verticalAlign: unitY < -0.4 ? 'top' : (unitY > 0.4 ? 'bottom' : 'middle'),
align: unitX < -0.4 ? 'left' : (unitX > 0.4 ? 'right' : 'center')
}, {inheritColor: autoColor}),
}, {
inheritColor: autoColor
}),
silent: true
}));
}
......
......@@ -289,7 +289,7 @@ class HeatmapView extends ChartView {
// PENDING
if (incremental) {
// Rect must use hover layer if it's incremental.
rect.useHoverLayer = true;
rect.states.emphasis.hoverLayer = true;
}
group.add(rect);
......
......@@ -154,7 +154,8 @@ class LineDraw {
incrementalUpdate(taskParams: StageHandlerProgressParams, lineData: ListForLineDraw) {
function updateIncrementalAndHover(el: Displayable) {
if (!el.isGroup && !isEffectObject(el)) {
el.incremental = el.useHoverLayer = true;
el.incremental = true;
el.ensureState('emphasis').hoverLayer = true;
}
}
......
......@@ -68,6 +68,7 @@ class Polyline extends graphic.Group {
hoverLineStyle = itemModel.getModel(['emphasis', 'lineStyle']).getLineStyle();
}
line.useStyle(lineData.getItemVisual(idx, 'style'));
line.style.fill = null;
line.style.strokeNoScale = true;
const lineEmphasisState = line.ensureState('emphasis');
......
......@@ -29,6 +29,7 @@ import { PathProps } from 'zrender/src/graphic/Path';
import { SymbolDrawSeriesScope, SymbolDrawItemModelOption } from './SymbolDraw';
import { extend } from 'zrender/src/core/util';
import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle';
import ZRImage from 'zrender/src/graphic/Image';
type ECSymbol = ReturnType<typeof createSymbol>;
......@@ -260,18 +261,30 @@ class Symbol extends graphic.Group {
const symbolStyle = data.getItemVisual(idx, 'style');
const visualColor = symbolStyle.fill;
if (symbolPath.__isEmptyBrush) {
// fill and stroke will be swapped if it's empty.
// So we cloned a new style to avoid it affecting the original style in visual storage.
// TODO Better implementation. No empty logic!
symbolPath.useStyle(extend({}, symbolStyle));
if (symbolPath instanceof ZRImage) {
const pathStyle = symbolPath.style;
symbolPath.useStyle(extend({
// TODO other properties like x, y ?
image: pathStyle.image,
x: pathStyle.x, y: pathStyle.y,
width: pathStyle.width, height: pathStyle.height
}, symbolStyle));
}
else {
symbolPath.useStyle(symbolStyle);
}
symbolPath.setColor(visualColor, opts && opts.symbolInnerColor);
symbolPath.style.strokeNoScale = true;
if (symbolPath.__isEmptyBrush) {
// fill and stroke will be swapped if it's empty.
// So we cloned a new style to avoid it affecting the original style in visual storage.
// TODO Better implementation. No empty logic!
symbolPath.useStyle(extend({}, symbolStyle));
}
else {
symbolPath.useStyle(symbolStyle);
}
symbolPath.setColor(visualColor, opts && opts.symbolInnerColor);
symbolPath.style.strokeNoScale = true;
}
const liftZ = data.getItemVisual(idx, 'liftZ');
const z2Origin = this._z2;
if (liftZ != null) {
......
......@@ -256,7 +256,8 @@ class SymbolDraw {
function updateIncrementalAndHover(el: Displayable) {
if (!el.isGroup) {
el.incremental = el.useHoverLayer = true;
el.incremental = true;
el.ensureState('emphasis').hoverLayer = true;
}
}
for (let idx = taskParams.start; idx < taskParams.end; idx++) {
......
......@@ -388,6 +388,11 @@ export default function (
label.setStyle({
align: textAlign
});
const selectState = label.states.select;
if (selectState) {
selectState.x += label.x;
selectState.y += label.y;
}
}
sector.setTextConfig({
inside: isLabelInside
......
......@@ -29,6 +29,7 @@ import { ColorString } from '../../util/types';
import GlobalModel from '../../model/Global';
import { VectorArray } from 'zrender/src/core/vector';
import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle';
import ZRImage from 'zrender/src/graphic/Image';
function normalizeSymbolSize(symbolSize: number | number[]) {
if (!zrUtil.isArray(symbolSize)) {
......@@ -223,8 +224,19 @@ class RadarView extends ChartView {
const emphasisModel = itemModel.getModel('emphasis');
const itemHoverStyle = emphasisModel.getModel('itemStyle').getItemStyle();
symbolGroup.eachChild(function (symbolPath: RadarSymbol) {
symbolPath.useStyle(itemStyle);
symbolPath.setColor(color);
if (symbolPath instanceof ZRImage) {
const pathStyle = symbolPath.style;
symbolPath.useStyle(zrUtil.extend({
// TODO other properties like x, y ?
image: pathStyle.image,
x: pathStyle.x, y: pathStyle.y,
width: pathStyle.width, height: pathStyle.height
}, itemStyle));
}
else {
symbolPath.useStyle(itemStyle);
symbolPath.setColor(color);
}
const pathEmphasisState = symbolPath.ensureState('emphasis');
pathEmphasisState.style = zrUtil.clone(itemHoverStyle);
......
......@@ -985,6 +985,8 @@ function renderNode(
const textStyle = textEl.style;
textStyle.truncateMinChar = 2;
textStyle.width = width;
textStyle.height = height;
textStyle.lineOverflow = 'truncate';
addDrillDownIcon(textStyle, upperLabelRect, thisLayout);
const textEmphasisState = textEl.getState('emphasis');
......
......@@ -22,7 +22,7 @@ import * as modelHelper from './modelHelper';
import findPointFromSeries from './findPointFromSeries';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../ExtensionAPI';
import { Dictionary, Payload, CommonAxisPointerOption } from '../../util/types';
import { Dictionary, Payload, CommonAxisPointerOption, HighlightPayload, DownplayPayload } from '../../util/types';
import AxisPointerModel, { AxisPointerOption } from './AxisPointerModel';
import { each, curry, bind, extend, Curry1 } from 'zrender/src/core/util';
import { ZRenderType } from 'zrender/src/zrender';
......@@ -479,11 +479,19 @@ function dispatchHighDownActually(
});
toDownplay.length && api.dispatchAction({
type: 'downplay', escapeConnect: true, batch: toDownplay
});
type: 'downplay',
escapeConnect: true,
// Not blur others when highlight in axisPointer.
notBlur: true,
batch: toDownplay
} as DownplayPayload);
toHighlight.length && api.dispatchAction({
type: 'highlight', escapeConnect: true, batch: toHighlight
});
type: 'highlight',
escapeConnect: true,
// Not blur others when highlight in axisPointer.
notBlur: true,
batch: toHighlight
} as HighlightPayload);
}
function findInputAxisInfo(
......
......@@ -126,7 +126,6 @@ export function buildLabelElOption(
text: text,
textFont: font,
fill: labelModel.getTextColor(),
align: 'center',
padding: paddings,
backgroundColor: bgColor as ColorString,
borderColor: labelModel.get('borderColor') || 'transparent',
......
......@@ -53,11 +53,21 @@ export interface SliderDataZoomOption extends DataZoomOption, BoxLayoutOptionMix
*/
borderColor?: ZRColor
/**
* Border radius of the box.
*/
borderRadius?: number | number[]
dataBackground?: {
lineStyle?: LineStyleOption
areaStyle?: AreaStyleOption
}
selectedDataBackground?: {
lineStyle?: LineStyleOption
areaStyle?: AreaStyleOption
}
/**
* Color of selected area.
*/
......@@ -71,7 +81,8 @@ export interface SliderDataZoomOption extends DataZoomOption, BoxLayoutOptionMix
handleIcon?: string
/**
* Percent of the slider height
* number: height of icon. width will be calculated according to the aspect of icon.
* string: percent of the slider height. width will be calculated according to the aspect of icon.
*/
handleSize?: string | number
......@@ -88,6 +99,10 @@ export interface SliderDataZoomOption extends DataZoomOption, BoxLayoutOptionMix
zoomLock?: boolean
textStyle?: LabelOption
emphasis?: {
handleStyle?: ItemStyleOption
}
}
......@@ -108,38 +123,59 @@ class SliderZoomModel extends DataZoomModel<SliderDataZoomOption> {
left: null, // Default align to grid rect.
bottom: null, // Default align to grid rect.
borderColor: '#d2dbee',
borderRadius: 3,
backgroundColor: 'rgba(47,69,84,0)', // Background of slider zoom component.
// dataBackgroundColor: '#ddd',
dataBackground: {
lineStyle: {
color: '#2f4554',
width: 0.5,
opacity: 0.3
color: '#d2dbee',
width: 0.5
},
areaStyle: {
color: 'rgba(47,69,84,0.3)',
opacity: 0.3
color: '#d2dbee',
opacity: 0.2
}
},
borderColor: '#ddd',
fillerColor: 'rgba(167,183,204,0.4)', // Color of selected area.
// handleColor: 'rgba(89,170,216,0.95)', // Color of handle.
// eslint-disable-next-line
handleIcon: 'M8.2,13.6V3.9H6.3v9.7H3.1v14.9h3.3v9.7h1.8v-9.7h3.3V13.6H8.2z M9.7,24.4H4.8v-1.4h4.9V24.4z M9.7,19.1H4.8v-1.4h4.9V19.1z',
selectedDataBackground: {
lineStyle: {
color: '#8fb0f7',
width: 0.5
},
areaStyle: {
color: '#8fb0f7',
opacity: 0.2
}
},
fillerColor: 'rgba(135,175,274,0.2)', // Color of selected area.
handleIcon: 'path://M-9.35,34.56V42m0-40V9.5m-2,0h4a2,2,0,0,1,2,2v21a2,2,0,0,1-2,2h-4a2,2,0,0,1-2-2v-21A2,2,0,0,1-11.35,9.5Z',
// Percent of the slider height
handleSize: '100%',
handleStyle: {
color: '#a7b7cc'
color: '#fff',
borderColor: '#ACB8D1'
},
showDetail: true,
showDataShadow: 'auto', // Default auto decision.
realtime: true,
zoomLock: false, // Whether disable zoom.
textStyle: {
color: '#333'
},
emphasis: {
handleStyle: {
borderColor: '#8FB0F7',
borderWidth: 2
}
}
});
}
......
......@@ -37,6 +37,10 @@ import Axis from '../../coord/Axis';
import SeriesModel from '../../model/Series';
import { AxisBaseModel } from '../../coord/AxisBaseModel';
import { getAxisMainType, collectReferCoordSysModelInfo } from './helper';
import { enableHoverEmphasis } from '../../util/states';
import { createSymbol, symbolBuildProxies } from '../../util/symbol';
import { deprecateLog } from '../../util/log';
import { __DEV__ } from '../../config';
const Rect = graphic.Rect;
......@@ -50,11 +54,11 @@ const LABEL_GAP = 5;
const SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];
type Icon = ReturnType<typeof graphic.createIcon>;
interface Displayables {
barGroup: graphic.Group;
handles: [Icon, Icon];
sliderGroup: graphic.Group;
handles: [graphic.Path, graphic.Path];
handleLabels: [graphic.Text, graphic.Text];
dataShadowSegs: graphic.Group[];
filler: graphic.Rect;
}
class SliderZoomView extends DataZoomView {
......@@ -157,7 +161,7 @@ class SliderZoomView extends DataZoomView {
this._resetLocation();
this._resetInterval();
const barGroup = this._displayables.barGroup = new graphic.Group();
const barGroup = this._displayables.sliderGroup = new graphic.Group();
this._renderBackground();
......@@ -225,11 +229,11 @@ class SliderZoomView extends DataZoomView {
const targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();
const inverse = targetAxisModel && targetAxisModel.get('inverse');
const barGroup = this._displayables.barGroup;
const sliderGroup = this._displayables.sliderGroup;
const otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse;
// Transform barGroup.
barGroup.attr(
sliderGroup.attr(
(orient === HORIZONTAL && !inverse)
? {scaleY: otherAxisInverse ? 1 : -1, scaleX: 1 }
: (orient === HORIZONTAL && inverse)
......@@ -241,7 +245,7 @@ class SliderZoomView extends DataZoomView {
);
// Position barGroup
const rect = thisGroup.getBoundingRect([barGroup]);
const rect = thisGroup.getBoundingRect([sliderGroup]);
thisGroup.x = location.x - rect.x;
thisGroup.y = location.y - rect.y;
thisGroup.markRedraw();
......@@ -254,7 +258,7 @@ class SliderZoomView extends DataZoomView {
private _renderBackground() {
const dataZoomModel = this.dataZoomModel;
const size = this._size;
const barGroup = this._displayables.barGroup;
const barGroup = this._displayables.sliderGroup;
barGroup.add(new Rect({
silent: true,
......@@ -283,6 +287,8 @@ class SliderZoomView extends DataZoomView {
private _renderDataShadow() {
const info = this._dataShadowInfo = this._prepareDataShadowInfo();
this._displayables.dataShadowSegs = [];
if (!info) {
return;
}
......@@ -352,22 +358,35 @@ class SliderZoomView extends DataZoomView {
});
const dataZoomModel = this.dataZoomModel;
function createDataShadowGroup(isSelectedArea?: boolean) {
const model = dataZoomModel.getModel(isSelectedArea ? 'selectedDataBackground' : 'dataBackground');
const group = new graphic.Group();
const polygon = new graphic.Polygon({
shape: {points: areaPoints},
segmentIgnoreThreshold: 1,
style: model.getModel('areaStyle').getAreaStyle(),
silent: true,
z2: -20
});
const polyline = new graphic.Polyline({
shape: {points: linePoints},
segmentIgnoreThreshold: 1,
style: model.getModel('lineStyle').getLineStyle(),
silent: true,
z2: -19
});
group.add(polygon);
group.add(polyline);
return group;
}
// let dataBackgroundModel = dataZoomModel.getModel('dataBackground');
this._displayables.barGroup.add(new graphic.Polygon({
shape: {points: areaPoints},
style: defaults(
{fill: dataZoomModel.get('dataBackgroundColor' as any)},
dataZoomModel.getModel(['dataBackground', 'areaStyle']).getAreaStyle()
),
silent: true,
z2: -20
}));
this._displayables.barGroup.add(new graphic.Polyline({
shape: {points: linePoints},
style: dataZoomModel.getModel(['dataBackground', 'lineStyle']).getLineStyle(),
silent: true,
z2: -19
}));
for (let i = 0; i < 3; i++) {
const group = createDataShadowGroup(i === 1);
this._displayables.sliderGroup.add(group);
this._displayables.dataShadowSegs.push(group);
}
}
private _prepareDataShadowInfo() {
......@@ -431,11 +450,13 @@ class SliderZoomView extends DataZoomView {
const displaybles = this._displayables;
const handles: [graphic.Path, graphic.Path] = displaybles.handles = [null, null];
const handleLabels: [graphic.Text, graphic.Text] = displaybles.handleLabels = [null, null];
const barGroup = this._displayables.barGroup;
const sliderGroup = this._displayables.sliderGroup;
const size = this._size;
const dataZoomModel = this.dataZoomModel;
barGroup.add(displaybles.filler = new Rect({
const borderRadius = dataZoomModel.get('borderRadius') || 0;
sliderGroup.add(displaybles.filler = new Rect({
draggable: true,
cursor: getCursor(this._orient),
drift: bind(this._onDragMove, this, 'all'),
......@@ -452,14 +473,15 @@ class SliderZoomView extends DataZoomView {
}));
// Frame border.
barGroup.add(new Rect({
sliderGroup.add(new Rect({
silent: true,
subPixelOptimize: true,
shape: {
x: 0,
y: 0,
width: size[0],
height: size[1]
height: size[1],
r: borderRadius
},
style: {
stroke: dataZoomModel.get('dataBackgroundColor' as any) // deprecated option
......@@ -470,31 +492,47 @@ class SliderZoomView extends DataZoomView {
}));
each([0, 1] as const, function (handleIndex) {
const path = graphic.createIcon(
dataZoomModel.get('handleIcon'),
{
cursor: getCursor(this._orient),
draggable: true,
drift: bind(this._onDragMove, this, handleIndex),
ondragend: bind(this._onDragEnd, this),
onmouseover: bind(this._showDataInfo, this, true),
onmouseout: bind(this._showDataInfo, this, false)
},
{x: -1, y: 0, width: 2, height: 2}
let iconStr = dataZoomModel.get('handleIcon');
if (!symbolBuildProxies[iconStr] && iconStr.indexOf('path://') < 0) {
// Compatitable with the old icon parsers. Which can use a path string without path://
iconStr = 'path://' + iconStr;
if (__DEV__) {
deprecateLog('handleIcon now needs \'path://\' prefix when using a path string');
}
}
const path = createSymbol(
iconStr,
-1, 0, 2, 2, null, true
) as graphic.Path;
path.attr({
cursor: getCursor(this._orient),
draggable: true,
drift: bind(this._onDragMove, this, handleIndex),
ondragend: bind(this._onDragEnd, this),
onmouseover: bind(this._showDataInfo, this, true),
onmouseout: bind(this._showDataInfo, this, false)
});
const bRect = path.getBoundingRect();
this._handleHeight = parsePercent(dataZoomModel.get('handleSize'), this._size[1]);
const handleSize = dataZoomModel.get('handleSize');
this._handleHeight = parsePercent(handleSize, this._size[1]);
this._handleWidth = bRect.width / bRect.height * this._handleHeight;
path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());
path.style.strokeNoScale = true;
path.rectHover = true;
path.ensureState('emphasis').style = dataZoomModel.getModel(['emphasis', 'handleStyle']).getItemStyle();
enableHoverEmphasis(path);
const handleColor = dataZoomModel.get('handleColor' as any); // deprecated option
// Compatitable with previous version
if (handleColor != null) {
path.style.fill = handleColor;
}
barGroup.add(handles[handleIndex] = path);
sliderGroup.add(handles[handleIndex] = path);
const textStyleModel = dataZoomModel.getModel('textStyle');
......@@ -578,6 +616,25 @@ class SliderZoomView extends DataZoomView {
height: size[1]
});
// update clip path of shadow.
const dataShadowSegs = displaybles.dataShadowSegs;
const segIntervals = [0, handleInterval[0], handleInterval[1], size[0]];
for (let i = 0; i < dataShadowSegs.length; i++) {
const segGroup = dataShadowSegs[i];
let clipPath = segGroup.getClipPath();
if (!clipPath) {
clipPath = new graphic.Rect();
segGroup.setClipPath(clipPath);
}
clipPath.setShape({
x: segIntervals[i],
y: 0,
width: segIntervals[i + 1] - segIntervals[i],
height: size[1]
});
}
this._updateDataInfo(nonRealtime);
}
......@@ -687,7 +744,7 @@ class SliderZoomView extends DataZoomView {
eventTool.stop(event.event);
// Transform dx, dy to bar coordination.
const barTransform = this._displayables.barGroup.getLocalTransform();
const barTransform = this._displayables.sliderGroup.getLocalTransform();
const vertex = graphic.applyTransform([dx, dy], barTransform, true);
const changed = this._updateInterval(handleIndex, vertex[0]);
......@@ -713,7 +770,7 @@ class SliderZoomView extends DataZoomView {
private _onClickPanelClick(e: ZRElementEvent) {
const size = this._size;
const localPoint = this._displayables.barGroup.transformCoordToLocal(e.offsetX, e.offsetY);
const localPoint = this._displayables.sliderGroup.transformCoordToLocal(e.offsetX, e.offsetY);
if (localPoint[0] < 0 || localPoint[0] > size[0]
|| localPoint[1] < 0 || localPoint[1] > size[1]
......
......@@ -39,7 +39,7 @@ import {
ColorString
} from '../../util/types';
import Model from '../../model/Model';
import Displayable from 'zrender/src/graphic/Displayable';
import Displayable, { DisplayableState } from 'zrender/src/graphic/Displayable';
import { PathStyleProps } from 'zrender/src/graphic/Path';
import { parse, stringify } from 'zrender/src/tool/color';
......@@ -198,7 +198,7 @@ class LegendView extends ComponentView {
if (seriesModel) {
const data = seriesModel.getData();
const style = data.getVisual('style');
const color = style.fill;
const color = style[data.getVisual('drawType')] || style.fill;
const borderColor = style.stroke;
// Using rect symbol defaultly
......@@ -585,6 +585,17 @@ function dispatchSelectAction(
dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId);
}
function isUseHoverLayer(api: ExtensionAPI) {
const list = api.getZr().storage.getDisplayList();
let emphasisState: DisplayableState;
let i = 0;
const len = list.length;
while (!(emphasisState = list[i].states.emphasis) && i < len) {
i++;
}
return emphasisState && emphasisState.hoverLayer;
}
function dispatchHighlightAction(
seriesName: string,
dataName: string,
......@@ -592,8 +603,7 @@ function dispatchHighlightAction(
excludeSeriesId: string[]
) {
// If element hover will move to a hoverLayer.
const el = api.getZr().storage.getDisplayList()[0];
if (!(el && el.useHoverLayer)) {
if (!isUseHoverLayer(api)) {
api.dispatchAction({
type: 'highlight',
seriesName: seriesName,
......@@ -610,8 +620,7 @@ function dispatchDownplayAction(
excludeSeriesId: string[]
) {
// If element hover will move to a hoverLayer.
const el = api.getZr().storage.getDisplayList()[0];
if (!(el && el.useHoverLayer)) {
if (!isUseHoverLayer(api)) {
api.dispatchAction({
type: 'downplay',
seriesName: seriesName,
......
......@@ -48,13 +48,13 @@ class SliderTimelineModel extends TimelineModel {
trigger: 'item' // data item may also have tootip attr.
},
symbol: 'emptyCircle',
symbolSize: 10,
symbol: 'circle',
symbolSize: 12,
lineStyle: {
show: true,
width: 2,
color: '#304654'
color: '#DAE1F5'
},
label: { // 文本标签
position: 'auto', // auto left right top bottom
......@@ -66,19 +66,24 @@ class SliderTimelineModel extends TimelineModel {
rotate: 0,
// formatter: null,
// 其余属性默认使用全局文本样式,详见TEXTSTYLE
color: '#304654'
color: '#A4B1D7'
},
itemStyle: {
color: '#304654',
color: '#A4B1D7',
borderWidth: 1
},
checkpointStyle: {
symbol: 'circle',
symbolSize: 13,
color: '#c23531',
borderWidth: 5,
borderColor: 'rgba(194,53,49, 0.5)',
symbolSize: 15,
color: '#316bf3',
borderColor: '#fff',
borderWidth: 2,
shadowBlur: 2,
shadowOffsetX: 1,
shadowOffsetY: 1,
shadowColor: 'rgba(0, 0, 0, 0.3)',
// borderColor: 'rgba(194,53,49, 0.5)',
animation: true,
animationDuration: 300,
animationEasing: 'quinticInOut'
......@@ -89,36 +94,54 @@ class SliderTimelineModel extends TimelineModel {
showPlayBtn: true,
showPrevBtn: true,
showNextBtn: true,
itemSize: 22,
itemSize: 24,
itemGap: 12,
position: 'left', // 'left' 'right' 'top' 'bottom'
playIcon: 'path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z', // jshint ignore:line
stopIcon: 'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z', // jshint ignore:line
nextIcon: 'path://M18.6,50.8l22.5-22.5c0.2-0.2,0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.7L18.7,4.4c-0.1-0.1-0.2-0.3-0.2-0.5 c0-0.4,0.3-0.8,0.8-0.8c0.2,0,0.5,0.1,0.6,0.3l23.5,23.5l0,0c0.2,0.2,0.3,0.4,0.3,0.7c0,0.3-0.1,0.5-0.3,0.7l-0.1,0.1L19.7,52 c-0.1,0.1-0.3,0.2-0.5,0.2c-0.4,0-0.8-0.3-0.8-0.8C18.4,51.2,18.5,51,18.6,50.8z', // jshint ignore:line
prevIcon: 'path://M43,52.8L20.4,30.3c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.5,0.3-0.7L42.9,6.4c0.1-0.1,0.2-0.3,0.2-0.5 c0-0.4-0.3-0.8-0.8-0.8c-0.2,0-0.5,0.1-0.6,0.3L18.3,28.8l0,0c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7l0.1,0.1L41.9,54 c0.1,0.1,0.3,0.2,0.5,0.2c0.4,0,0.8-0.3,0.8-0.8C43.2,53.2,43.1,53,43,52.8z', // jshint ignore:line
nextIcon: 'M2,18.5A1.52,1.52,0,0,1,.92,18a1.49,1.49,0,0,1,0-2.12L7.81,9.36,1,3.11A1.5,1.5,0,1,1,3,.89l8,7.34a1.48,1.48,0,0,1,.49,1.09,1.51,1.51,0,0,1-.46,1.1L3,18.08A1.5,1.5,0,0,1,2,18.5Z', // jshint ignore:line
prevIcon: 'M10,.5A1.52,1.52,0,0,1,11.08,1a1.49,1.49,0,0,1,0,2.12L4.19,9.64,11,15.89a1.5,1.5,0,1,1-2,2.22L1,10.77A1.48,1.48,0,0,1,.5,9.68,1.51,1.51,0,0,1,1,8.58L9,.92A1.5,1.5,0,0,1,10,.5Z', // jshint ignore:line
prevBtnSize: 18,
nextBtnSize: 18,
color: '#304654',
borderColor: '#304654',
color: '#A4B1D7',
borderColor: '#A4B1D7',
borderWidth: 1
},
emphasis: {
label: {
show: true,
// 其余属性默认使用全局文本样式,详见TEXTSTYLE
color: '#c23531'
color: '#6f778d'
},
itemStyle: {
color: '#c23531'
color: '#316BF3'
},
controlStyle: {
color: '#c23531',
borderColor: '#c23531',
color: '#316BF3',
borderColor: '#316BF3',
borderWidth: 2
}
},
progress: {
lineStyle: {
color: '#316BF3'
},
itemStyle: {
color: '#316BF3'
},
label: {
color: '#6f778d'
}
},
data: []
});
......
......@@ -30,19 +30,21 @@ 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 } from 'zrender/src/core/util';
import { merge, each, extend, clone, isString, bind, defaults, retrieve2 } from 'zrender/src/core/util';
import SliderTimelineModel from './SliderTimelineModel';
import ComponentView from '../../view/Component';
import { LayoutOrient, ZRTextAlign, ZRTextVerticalAlign, ZRElementEvent } from '../../util/types';
import TimelineModel, { TimelineDataItemOption, TimelineCheckpointStyle } from './TimelineModel';
import { TimelineChangePayload, TimelinePlayChangePayload } from './timelineAction';
import Model from '../../model/Model';
import { PathProps } from 'zrender/src/graphic/Path';
import { PathProps, PathStyleProps } from 'zrender/src/graphic/Path';
import Scale from '../../scale/Scale';
import OrdinalScale from '../../scale/Ordinal';
import TimeScale from '../../scale/Time';
import IntervalScale from '../../scale/Interval';
import { VectorArray } from 'zrender/src/core/vector';
import { parsePercent } from 'zrender/src/contain/text';
import { makeInner } from '../../util/model';
const PI = Math.PI;
......@@ -50,8 +52,13 @@ type TimelineSymbol = ReturnType<typeof createSymbol>;
type RenderMethodName = '_renderAxisLine' | '_renderAxisTick' | '_renderControl' | '_renderCurrentPointer';
type ControlName = 'play' | 'stop' | 'next' | 'prev';
type ControlIconName = 'playIcon' | 'stopIcon' | 'nextIcon' | 'prevIcon';
const labelDataIndexStore = makeInner<{
dataIndex: number
}, graphic.Text>();
interface LayoutInfo {
viewRect: BoundingRect
mainLength: number
......@@ -89,10 +96,14 @@ class SliderTimelineView extends TimelineView {
private _currentPointer: TimelineSymbol;
private _progressLine: graphic.Line;
private _mainGroup: graphic.Group;
private _labelGroup: graphic.Group;
private _tickSymbols: graphic.Path[];
private _tickLabels: graphic.Text[];
init(ecModel: GlobalModel, api: ExtensionAPI) {
this.api = api;
......@@ -133,6 +144,8 @@ class SliderTimelineView extends TimelineView {
}
this._doPlayStop();
this._updateTicksStatus();
}
/**
......@@ -150,7 +163,7 @@ class SliderTimelineView extends TimelineView {
this._clearTimer();
}
_layout(timelineModel: SliderTimelineModel, api: ExtensionAPI): LayoutInfo {
private _layout(timelineModel: SliderTimelineModel, api: ExtensionAPI): LayoutInfo {
const labelPosOpt = timelineModel.get(['label', 'position']);
const orient = timelineModel.get('orient');
const viewRect = getViewRect(timelineModel, api);
......@@ -250,7 +263,7 @@ class SliderTimelineView extends TimelineView {
};
}
_position(layoutInfo: LayoutInfo, timelineModel: SliderTimelineModel) {
private _position(layoutInfo: LayoutInfo, timelineModel: SliderTimelineModel) {
// Position is be called finally, because bounding rect is needed for
// adapt content to fill viewRect (auto adapt offset).
......@@ -321,7 +334,7 @@ class SliderTimelineView extends TimelineView {
}
}
_createAxis(layoutInfo: LayoutInfo, timelineModel: SliderTimelineModel) {
private _createAxis(layoutInfo: LayoutInfo, timelineModel: SliderTimelineModel) {
const data = timelineModel.getData();
const axisType = timelineModel.get('axisType');
......@@ -344,13 +357,13 @@ class SliderTimelineView extends TimelineView {
return axis;
}
_createGroup(key: '_mainGroup' | '_labelGroup') {
private _createGroup(key: '_mainGroup' | '_labelGroup') {
const newGroup = this[key] = new graphic.Group();
this.group.add(newGroup);
return newGroup;
}
_renderAxisLine(
private _renderAxisLine(
layoutInfo: LayoutInfo,
group: graphic.Group,
axis: TimelineAxis,
......@@ -362,7 +375,7 @@ class SliderTimelineView extends TimelineView {
return;
}
group.add(new graphic.Line({
const line = new graphic.Line({
shape: {
x1: axisExtent[0], y1: 0,
x2: axisExtent[1], y2: 0
......@@ -373,13 +386,27 @@ class SliderTimelineView extends TimelineView {
),
silent: true,
z2: 1
}));
});
group.add(line);
const progressLine = this._progressLine = new graphic.Line({
shape: {
x1: axisExtent[0],
x2: this._currentPointer
? this._currentPointer.x : axisExtent[0],
y1: 0, y2: 0
},
style: defaults(
{ lineCap: 'round', lineWidth: line.style.lineWidth } as PathStyleProps,
timelineModel.getModel(['progress', 'lineStyle']).getLineStyle()
),
silent: true,
z2: 1
});
group.add(progressLine);
}
/**
* @private
*/
_renderAxisTick(
private _renderAxisTick(
layoutInfo: LayoutInfo,
group: graphic.Group,
axis: TimelineAxis,
......@@ -389,18 +416,24 @@ class SliderTimelineView extends TimelineView {
// Show all ticks, despite ignoring strategy.
const ticks = axis.scale.getTicks();
this._tickSymbols = [];
// The value is dataIndex, see the costomized scale.
each(ticks, function (value) {
each(ticks, (value) => {
const tickCoord = axis.dataToCoord(value);
const itemModel = data.getItemModel<TimelineDataItemOption>(value);
const itemStyleModel = itemModel.getModel('itemStyle');
const hoverStyleModel = itemModel.getModel(['emphasis', 'itemStyle']);
const progressStyleModel = itemModel.getModel(['progress', 'itemStyle']);
const symbolOpt = {
position: [tickCoord, 0],
onclick: bind(this._changeTimeline, this, value)
};
const el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt);
el.ensureState('emphasis').style = hoverStyleModel.getItemStyle();
el.ensureState('progress').style = progressStyleModel.getItemStyle();
enableHoverEmphasis(el);
const ecData = graphic.getECData(el);
......@@ -412,13 +445,11 @@ class SliderTimelineView extends TimelineView {
ecData.dataIndex = ecData.dataModel = null;
}
}, this);
this._tickSymbols.push(el);
});
}
/**
* @private
*/
_renderAxisLabel(
private _renderAxisLabel(
layoutInfo: LayoutInfo,
group: graphic.Group,
axis: TimelineAxis,
......@@ -433,13 +464,17 @@ class SliderTimelineView extends TimelineView {
const data = timelineModel.getData();
const labels = axis.getViewLabels();
each(labels, function (labelItem) {
this._tickLabels = [];
each(labels, (labelItem) => {
// The tickValue is dataIndex, see the costomized scale.
const dataIndex = labelItem.tickValue;
const itemModel = data.getItemModel<TimelineDataItemOption>(dataIndex);
const normalLabelModel = itemModel.getModel('label');
const hoverLabelModel = itemModel.getModel(['emphasis', 'label']);
const progressLabelModel = itemModel.getModel(['progress', 'label']);
const tickCoord = axis.dataToCoord(labelItem.tickValue);
const textEl = new graphic.Text({
x: tickCoord,
......@@ -455,17 +490,19 @@ class SliderTimelineView extends TimelineView {
});
textEl.ensureState('emphasis').style = createTextStyle(hoverLabelModel);
textEl.ensureState('progress').style = createTextStyle(progressLabelModel);
group.add(textEl);
enableHoverEmphasis(textEl);
}, this);
labelDataIndexStore(textEl).dataIndex = dataIndex;
this._tickLabels.push(textEl);
});
}
/**
* @private
*/
_renderControl(
private _renderControl(
layoutInfo: LayoutInfo,
group: graphic.Group,
axis: TimelineAxis,
......@@ -476,36 +513,40 @@ class SliderTimelineView extends TimelineView {
const itemStyle = timelineModel.getModel('controlStyle').getItemStyle();
const hoverStyle = timelineModel.getModel(['emphasis', 'controlStyle']).getItemStyle();
const rect = [0, -controlSize / 2, controlSize, controlSize];
const playState = timelineModel.getPlayState();
const inverse = timelineModel.get('inverse', true);
makeBtn(
layoutInfo.nextBtnPosition,
'nextIcon',
'next',
bind(this._changeTimeline, this, inverse ? '-' : '+')
);
makeBtn(
layoutInfo.prevBtnPosition,
'prevIcon',
'prev',
bind(this._changeTimeline, this, inverse ? '+' : '-')
);
makeBtn(
layoutInfo.playPosition,
(playState ? 'stopIcon' : 'playIcon'),
(playState ? 'stop' : 'play'),
bind(this._handlePlayClick, this, !playState),
true
);
function makeBtn(
position: number[],
iconPath: ControlIconName,
iconName: ControlName,
onclick: () => void,
willRotate?: boolean
) {
if (!position) {
return;
}
const iconSize = parsePercent(
retrieve2(timelineModel.get(['controlStyle', iconName + 'BtnSize' as any]), controlSize),
controlSize
);
const rect = [0, -iconSize / 2, iconSize, iconSize];
const opt = {
position: position,
origin: [controlSize / 2, 0],
......@@ -514,14 +555,14 @@ class SliderTimelineView extends TimelineView {
style: itemStyle,
onclick: onclick
};
const btn = makeControlIcon(timelineModel, iconPath, rect, opt);
const btn = makeControlIcon(timelineModel, iconName + 'Icon' as ControlIconName, rect, opt);
btn.ensureState('emphasis').style = hoverStyle;
group.add(btn);
enableHoverEmphasis(btn);
}
}
_renderCurrentPointer(
private _renderCurrentPointer(
layoutInfo: LayoutInfo,
group: graphic.Group,
axis: TimelineAxis,
......@@ -538,10 +579,10 @@ class SliderTimelineView extends TimelineView {
pointer.draggable = true;
pointer.drift = bind(me._handlePointerDrag, me);
pointer.ondragend = bind(me._handlePointerDragend, me);
pointerMoveTo(pointer, currentIndex, axis, timelineModel, true);
pointerMoveTo(pointer, me._progressLine, currentIndex, axis, timelineModel, true);
},
onUpdate(pointer: TimelineSymbol) {
pointerMoveTo(pointer, currentIndex, axis, timelineModel);
pointerMoveTo(pointer, me._progressLine, currentIndex, axis, timelineModel);
}
};
......@@ -551,7 +592,7 @@ class SliderTimelineView extends TimelineView {
);
}
_handlePlayClick(nextState: boolean) {
private _handlePlayClick(nextState: boolean) {
this._clearTimer();
this.api.dispatchAction({
type: 'timelinePlayChange',
......@@ -560,16 +601,16 @@ class SliderTimelineView extends TimelineView {
} as TimelinePlayChangePayload);
}
_handlePointerDrag(dx: number, dy: number, e: ZRElementEvent) {
private _handlePointerDrag(dx: number, dy: number, e: ZRElementEvent) {
this._clearTimer();
this._pointerChangeTimeline([e.offsetX, e.offsetY]);
}
_handlePointerDragend(e: ZRElementEvent) {
private _handlePointerDragend(e: ZRElementEvent) {
this._pointerChangeTimeline([e.offsetX, e.offsetY], true);
}
_pointerChangeTimeline(mousePos: number[], trigger?: boolean) {
private _pointerChangeTimeline(mousePos: number[], trigger?: boolean) {
let toCoord = this._toAxisCoord(mousePos)[0];
const axis = this._axis;
......@@ -581,6 +622,9 @@ class SliderTimelineView extends TimelineView {
this._currentPointer.x = toCoord;
this._currentPointer.markRedraw();
this._progressLine.shape.x2 = toCoord;
this._progressLine.dirty();
const targetDataIndex = this._findNearestTick(toCoord);
const timelineModel = this.model;
......@@ -592,7 +636,7 @@ class SliderTimelineView extends TimelineView {
}
}
_doPlayStop() {
private _doPlayStop() {
this._clearTimer();
if (this.model.getPlayState()) {
......@@ -610,12 +654,12 @@ class SliderTimelineView extends TimelineView {
}
}
_toAxisCoord(vertex: number[]) {
private _toAxisCoord(vertex: number[]) {
const trans = this._mainGroup.getLocalTransform();
return graphic.applyTransform(vertex, trans, true);
}
_findNearestTick(axisCoord: number) {
private _findNearestTick(axisCoord: number) {
const data = this.model.getData();
let dist = Infinity;
let targetDataIndex;
......@@ -633,14 +677,14 @@ class SliderTimelineView extends TimelineView {
return targetDataIndex;
}
_clearTimer() {
private _clearTimer() {
if (this._timer) {
clearTimeout(this._timer);
this._timer = null;
}
}
_changeTimeline(nextIndex: number | '+' | '-') {
private _changeTimeline(nextIndex: number | '+' | '-') {
const currentIndex = this.model.getCurrentIndex();
if (nextIndex === '+') {
......@@ -657,6 +701,23 @@ class SliderTimelineView extends TimelineView {
} as TimelineChangePayload);
}
private _updateTicksStatus() {
const currentIndex = this.model.getCurrentIndex();
const tickSymbols = this._tickSymbols;
const tickLabels = this._tickLabels;
if (!(tickSymbols || tickLabels)) {
return;
}
for (let i = 0; i < tickSymbols.length; i++) {
tickSymbols && tickSymbols[i]
&& tickSymbols[i].toggleState('progress', i < currentIndex);
}
for (let i = 0; i < tickLabels.length; i++) {
tickLabels && tickLabels[i]
&& tickLabels[i].toggleState('progress', labelDataIndexStore(tickLabels[i]).dataIndex <= currentIndex);
}
}
}
function createScaleByModel(model: SliderTimelineModel, axisType?: string): Scale {
......@@ -782,6 +843,7 @@ function giveSymbol(
function pointerMoveTo(
pointer: TimelineSymbol,
progressLine: graphic.Line,
dataIndex: number,
axis: TimelineAxis,
timelineModel: SliderTimelineModel,
......@@ -795,20 +857,28 @@ function pointerMoveTo(
const toCoord = axis.dataToCoord(timelineModel.getData().get('value', dataIndex));
if (noAnimation || !pointerModel.get('animation', true)) {
pointer.x = toCoord;
pointer.y = 0;
pointer.attr({
x: toCoord,
y: 0
});
progressLine && progressLine.attr({
shape: { x2: toCoord }
});
}
else {
const animationCfg = {
duration: pointerModel.get('animationDuration', true),
easing: pointerModel.get('animationEasing', true)
};
pointer.stopAnimation(null, true);
pointer.animateTo({
x: toCoord,
y: 0
}, {
duration: pointerModel.get('animationDuration', true),
easing: pointerModel.get('animationEasing', true)
});
}, animationCfg);
progressLine && progressLine.animateTo({
shape: { x2: toCoord }
}, animationCfg);
}
pointer.markRedraw();
}
......
......@@ -52,6 +52,12 @@ export interface TimelineControlStyle extends ItemStyleOption {
stopIcon?: string
prevIcon?: string
nextIcon?: string
// Can be a percent value relative to itemSize
playBtnSize: number | string
stopBtnSize: number | string
nextBtnSize: number | string
prevBtnSize: number | string
}
export interface TimelineCheckpointStyle extends ItemStyleOption,
......@@ -84,6 +90,13 @@ export interface TimelineDataItemOption extends SymbolOptionMixin {
checkpointStyle?: TimelineCheckpointStyle
}
// Style in progress
progress?: {
lineStyle?: TimelineLineStyleOption
itemStyle?: ItemStyleOption
label?: TimelineLabelOption
}
tooltip?: boolean
}
......@@ -139,6 +152,14 @@ export interface TimelineOption extends ComponentOption, BoxLayoutOptionMixin, S
label?: TimelineLabelOption
}
// Style in progress
progress?: {
lineStyle?: TimelineLineStyleOption
itemStyle?: ItemStyleOption
label?: TimelineLabelOption
}
data?: (OptionDataValue | TimelineDataItemOption)[]
}
class TimelineModel extends ComponentModel<TimelineOption> {
......
......@@ -23,6 +23,7 @@ import * as numberUtil from '../../util/number';
import ComponentModel from '../../model/Component';
import { VisualMappingOption } from '../../visual/VisualMapping';
import { inheritDefaultOption } from '../../util/component';
import { ItemStyleOption } from '../../util/types';
// Constant
const DEFAULT_BAR_BOUND = [20, 140];
......@@ -62,7 +63,21 @@ export interface ContinousVisualMapOption extends VisualMapOption {
* Whether trigger hoverLink when hover handle.
* If not specified, follow the value of `realtime`.
*/
hoverLinkOnHandle?: boolean
hoverLinkOnHandle?: boolean,
handleIcon?: string,
// Percent of the item width
handleSize?: string | number,
handleStyle?: ItemStyleOption
indicatorIcon?: string,
// Percent of the item width
indicatorSize?: string | number,
indicatorStyle?: ItemStyleOption
emphasis?: {
handleStyle?: ItemStyleOption
}
}
class ContinuousModel extends VisualMapModel<ContinousVisualMapOption> {
......@@ -131,7 +146,7 @@ class ContinuousModel extends VisualMapModel<ContinousVisualMapOption> {
zrUtil.each(this.stateList, function (state: VisualState) {
const symbolSize = this.option.controller[state].symbolSize;
if (symbolSize && symbolSize[0] !== symbolSize[1]) {
symbolSize[0] = 0; // For good looking.
symbolSize[0] = symbolSize[1] / 3; // For good looking.
}
}, this);
}
......@@ -264,7 +279,34 @@ class ContinuousModel extends VisualMapModel<ContinousVisualMapOption> {
align: 'auto', // 'auto', 'left', 'right', 'top', 'bottom'
calculable: false,
hoverLink: true,
realtime: true
realtime: true,
handleIcon: 'path://M-11.39,9.77h0a3.5,3.5,0,0,1-3.5,3.5h-22a3.5,3.5,0,0,1-3.5-3.5h0a3.5,3.5,0,0,1,3.5-3.5h22A3.5,3.5,0,0,1-11.39,9.77Z',
handleSize: '120%',
handleStyle: {
borderColor: '#fff',
borderWidth: 1
},
indicatorIcon: 'circle',
indicatorSize: '50%',
indicatorStyle: {
borderColor: '#fff',
borderWidth: 2,
shadowBlur: 2,
shadowOffsetX: 1,
shadowOffsetY: 1,
shadowColor: 'rgba(0,0,0,0.2)'
}
// emphasis: {
// handleStyle: {
// shadowBlur: 3,
// shadowOffsetX: 1,
// shadowOffsetY: 1,
// shadowColor: 'rgba(0,0,0,0.2)'
// }
// }
}) as ContinousVisualMapOption;
}
......
......@@ -34,6 +34,10 @@ import ExtensionAPI from '../../ExtensionAPI';
import Element, { ElementEvent } from 'zrender/src/Element';
import { TextVerticalAlign, TextAlign } from 'zrender/src/core/types';
import { ColorString, Payload } from '../../util/types';
import { parsePercent } from 'zrender/src/contain/text';
import { setAsHighDownDispatcher, enterBlur, leaveBlur } from '../../util/states';
import { createSymbol } from '../../util/symbol';
import ZRImage from 'zrender/src/graphic/Image';
const linearMap = numberUtil.linearMap;
const each = zrUtil.each;
......@@ -48,16 +52,16 @@ const HOVER_LINK_OUT = 6;
type Orient = VisualMapModel['option']['orient'];
type ShapeStorage = {
handleThumbs: graphic.Polygon[]
handleThumbs: graphic.Path[]
handleLabelPoints: number[][]
handleLabels: graphic.Text[]
inRange: graphic.Polygon
outOfRange: graphic.Polygon
barGroup: graphic.Group
mainGroup: graphic.Group
indicator: graphic.Polygon
indicator: graphic.Path
indicatorLabel: graphic.Text
indicatorLabelPoint: number[]
};
......@@ -101,6 +105,8 @@ class ContinuousView extends VisualMapView {
private _hovering: boolean;
private _firstShowIndicator: boolean;
doRender(
visualMapModel: ContinuousModel,
......@@ -159,7 +165,7 @@ class ContinuousView extends VisualMapView {
const textGap = visualMapModel.get('textGap');
const itemSize = visualMapModel.itemSize;
const barGroup = this._shapes.barGroup;
const barGroup = this._shapes.mainGroup;
const position = this._applyTransform(
[
itemSize[0] / 2,
......@@ -194,17 +200,31 @@ class ContinuousView extends VisualMapView {
const orient = this._orient;
const useHandle = this._useHandle;
const itemAlign = helper.getItemAlign(visualMapModel, this.api, itemSize);
const barGroup = shapes.barGroup = this._createBarGroup(itemAlign);
const mainGroup = shapes.mainGroup = this._createBarGroup(itemAlign);
const gradientBarGroup = new graphic.Group();
mainGroup.add(gradientBarGroup);
// Bar
barGroup.add(shapes.outOfRange = createPolygon());
barGroup.add(shapes.inRange = createPolygon(
gradientBarGroup.add(shapes.outOfRange = createPolygon());
gradientBarGroup.add(shapes.inRange = createPolygon(
null,
useHandle ? getCursor(this._orient) : null,
zrUtil.bind(this._dragHandle, this, 'all', false),
zrUtil.bind(this._dragHandle, this, 'all', true)
));
// A border radius clip.
gradientBarGroup.setClipPath(new graphic.Rect({
shape: {
x: 0,
y: 0,
width: itemSize[0],
height: itemSize[1],
r: 3
}
}));
const textRect = visualMapModel.textStyleModel.getTextRect('');
const textSize = mathMax(textRect.width, textRect.height);
......@@ -214,17 +234,18 @@ class ContinuousView extends VisualMapView {
shapes.handleLabels = [];
shapes.handleLabelPoints = [];
this._createHandle(barGroup, 0, itemSize, textSize, orient);
this._createHandle(barGroup, 1, itemSize, textSize, orient);
this._createHandle(visualMapModel, mainGroup, 0, itemSize, textSize, orient);
this._createHandle(visualMapModel, mainGroup, 1, itemSize, textSize, orient);
}
this._createIndicator(barGroup, itemSize, textSize, orient);
this._createIndicator(visualMapModel, mainGroup, itemSize, textSize, orient);
targetGroup.add(barGroup);
targetGroup.add(mainGroup);
}
private _createHandle(
barGroup: graphic.Group,
visualMapModel: ContinuousModel,
mainGroup: graphic.Group,
handleIndex: 0 | 1,
itemSize: number[],
textSize: number,
......@@ -232,14 +253,35 @@ class ContinuousView extends VisualMapView {
) {
const onDrift = zrUtil.bind(this._dragHandle, this, handleIndex, false);
const onDragEnd = zrUtil.bind(this._dragHandle, this, handleIndex, true);
const handleThumb = createPolygon(
createHandlePoints(handleIndex, textSize),
getCursor(this._orient),
onDrift,
onDragEnd
const handleSize = parsePercent(visualMapModel.get('handleSize'), itemSize[0]);
const handleThumb = createSymbol(
visualMapModel.get('handleIcon'),
-handleSize / 2, -handleSize / 2, handleSize, handleSize,
null, true
);
handleThumb.x = itemSize[0];
barGroup.add(handleThumb);
const cursor = getCursor(this._orient);
handleThumb.attr({
cursor: cursor,
draggable: true,
drift: onDrift,
ondragend: onDragEnd,
onmousemove(e) {
eventTool.stop(e.event);
}
});
handleThumb.x = itemSize[0] / 2;
handleThumb.useStyle(visualMapModel.getModel('handleStyle').getItemStyle());
(handleThumb as graphic.Path).setStyle({
strokeNoScale: true,
strokeFirst: true
});
(handleThumb as graphic.Path).style.lineWidth *= 2;
handleThumb.ensureState('emphasis').style = visualMapModel.getModel(['emphasis', 'handleStyle']).getItemStyle();
setAsHighDownDispatcher(handleThumb, true);
mainGroup.add(handleThumb);
// Text is always horizontal layout but should not be effected by
// transform (orient/inverse). So label is built separately but not
......@@ -247,6 +289,7 @@ class ContinuousView extends VisualMapView {
// group (according to handleLabelPoint) but not barGroup.
const textStyleModel = this.visualMapModel.textStyleModel;
const handleLabel = new graphic.Text({
cursor: cursor,
draggable: true,
drift: onDrift,
onmousemove(e) {
......@@ -260,16 +303,14 @@ class ContinuousView extends VisualMapView {
fill: textStyleModel.getTextColor()
}
});
handleLabel.ensureState('blur').style = {
opacity: 0.1
};
handleLabel.stateTransition = { duration: 200 };
this.group.add(handleLabel);
const handleLabelPoint = [
orient === 'horizontal'
? textSize / 2
: textSize * 1.5,
orient === 'horizontal'
? (handleIndex === 0 ? -(textSize * 1.5) : (textSize * 1.5))
: (handleIndex === 0 ? -textSize / 2 : textSize / 2)
];
const handleLabelPoint = [handleSize, 0];
const shapes = this._shapes;
shapes.handleThumbs[handleIndex] = handleThumb;
......@@ -278,15 +319,39 @@ class ContinuousView extends VisualMapView {
}
private _createIndicator(
barGroup: graphic.Group,
visualMapModel: ContinuousModel,
mainGroup: graphic.Group,
itemSize: number[],
textSize: number,
orient: Orient
) {
const indicator = createPolygon([[0, 0]], 'move');
indicator.x = itemSize[0];
indicator.attr({invisible: true, silent: true});
barGroup.add(indicator);
const scale = parsePercent(visualMapModel.get('indicatorSize'), itemSize[0]);
const indicator = createSymbol(
visualMapModel.get('indicatorIcon'),
-scale / 2, -scale / 2, scale, scale,
null, true
);
indicator.attr({
cursor: 'move',
invisible: true,
silent: true,
x: itemSize[0] / 2
});
const indicatorStyle = visualMapModel.getModel('indicatorStyle').getItemStyle();
if (indicator instanceof ZRImage) {
const pathStyle = indicator.style;
indicator.useStyle(zrUtil.extend({
// TODO other properties like x, y ?
image: pathStyle.image,
x: pathStyle.x, y: pathStyle.y,
width: pathStyle.width, height: pathStyle.height
}, indicatorStyle));
}
else {
indicator.useStyle(indicatorStyle);
}
mainGroup.add(indicator);
const textStyleModel = this.visualMapModel.textStyleModel;
const indicatorLabel = new graphic.Text({
......@@ -301,7 +366,7 @@ class ContinuousView extends VisualMapView {
this.group.add(indicatorLabel);
const indicatorLabelPoint = [
orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT + 3,
(orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT) + itemSize[0] / 2,
0
];
......@@ -309,6 +374,8 @@ class ContinuousView extends VisualMapView {
shapes.indicator = indicator;
shapes.indicatorLabel = indicatorLabel;
shapes.indicatorLabelPoint = indicatorLabelPoint;
this._firstShowIndicator = true;
}
private _dragHandle(
......@@ -326,9 +393,10 @@ class ContinuousView extends VisualMapView {
if (!isEnd) {
// Transform dx, dy to bar coordination.
const vertex = this._applyTransform([dx as number, dy], this._shapes.barGroup, true) as number[];
const vertex = this._applyTransform([dx as number, dy], this._shapes.mainGroup, true) as number[];
this._updateInterval(handleIndex, vertex[1]);
this._hideIndicator();
// Considering realtime, update view should be executed
// before dispatch action.
this._updateView();
......@@ -526,12 +594,20 @@ class ContinuousView extends VisualMapView {
const visualMapModel = this.visualMapModel;
const handleThumbs = shapes.handleThumbs;
const handleLabels = shapes.handleLabels;
const itemSize = visualMapModel.itemSize;
const dataExtent = visualMapModel.getExtent();
each([0, 1], function (handleIndex) {
const handleThumb = handleThumbs[handleIndex];
handleThumb.setStyle('fill', visualInRange.handlesColor[handleIndex]);
handleThumb.y = handleEnds[handleIndex];
const val = linearMap(handleEnds[handleIndex], [0, itemSize[1]], dataExtent, true);
const symbolSize = this.getControllerVisual(val, 'symbolSize') as number;
handleThumb.scaleX = handleThumb.scaleY = symbolSize / itemSize[0];
handleThumb.x = itemSize[0] - symbolSize / 2;
// Update handle label position.
const textPoint = graphic.applyTransform(
shapes.handleLabelPoints[handleIndex],
......@@ -542,12 +618,10 @@ class ContinuousView extends VisualMapView {
y: textPoint[1],
text: visualMapModel.formatValueText(this._dataInterval[handleIndex]),
verticalAlign: 'middle',
align: this._applyTransform(
this._orient === 'horizontal'
? (handleIndex === 0 ? 'bottom' : 'top')
: 'left',
shapes.barGroup
) as TextAlign
align: this._orient === 'vertical' ? this._applyTransform(
'left',
shapes.mainGroup
) as TextAlign : 'center'
});
}, this);
}
......@@ -562,7 +636,6 @@ class ContinuousView extends VisualMapView {
const dataExtent = visualMapModel.getExtent();
const itemSize = visualMapModel.itemSize;
const sizeExtent = [0, itemSize[1]];
const pos = linearMap(cursorValue, dataExtent, sizeExtent, true);
const shapes = this._shapes;
const indicator = shapes.indicator;
......@@ -570,17 +643,18 @@ class ContinuousView extends VisualMapView {
return;
}
indicator.y = pos;
indicator.attr('invisible', false);
indicator.setShape('points', createIndicatorPoints(
!!rangeSymbol, halfHoverLinkSize, pos, itemSize[1]
));
const opts = {convertOpacityToAlpha: true};
const color = this.getControllerVisual(cursorValue, 'color', opts) as ColorString;
indicator.setStyle('fill', color);
const symbolSize = this.getControllerVisual(cursorValue, 'symbolSize') as number;
const y = linearMap(cursorValue, dataExtent, sizeExtent, true);
const x = itemSize[0] - symbolSize / 2;
const oldIndicatorPos = { x: indicator.x, y: indicator.y };
// Update handle label position.
indicator.y = y;
indicator.x = x;
const textPoint = graphic.applyTransform(
shapes.indicatorLabelPoint,
graphic.getTransform(indicator, this.group)
......@@ -588,21 +662,60 @@ class ContinuousView extends VisualMapView {
const indicatorLabel = shapes.indicatorLabel;
indicatorLabel.attr('invisible', false);
const align = this._applyTransform('left', shapes.barGroup);
const align = this._applyTransform('left', shapes.mainGroup);
const orient = this._orient;
const isHorizontal = orient === 'horizontal';
indicatorLabel.setStyle({
text: (rangeSymbol ? rangeSymbol : '') + visualMapModel.formatValueText(textValue),
verticalAlign: isHorizontal ? align as TextVerticalAlign : 'middle',
align: isHorizontal ? 'center' : align as TextAlign,
x: textPoint[0],
y: textPoint[1]
align: isHorizontal ? 'center' : align as TextAlign
});
const indicatorNewProps = {
x: x,
y: y,
style: {
fill: color
}
};
const labelNewProps = {
style: {
x: textPoint[0],
y: textPoint[1]
}
};
if (visualMapModel.ecModel.isAnimationEnabled() && !this._firstShowIndicator) {
const animationCfg = {
duration: 100,
easing: 'cubicInOut',
additive: true
} as const;
indicator.x = oldIndicatorPos.x;
indicator.y = oldIndicatorPos.y;
indicator.animateTo(indicatorNewProps, animationCfg);
indicatorLabel.animateTo(labelNewProps, animationCfg);
}
else {
indicator.attr(indicatorNewProps);
indicatorLabel.attr(labelNewProps);
}
this._firstShowIndicator = false;
const handleLabels = this._shapes.handleLabels;
if (handleLabels) {
for (let i = 0; i < handleLabels.length; i++) {
// Fade out handle labels.
// TODO not do twice.
enterBlur(handleLabels[i]);
}
}
}
private _enableHoverLinkToSeries() {
const self = this;
this._shapes.barGroup
this._shapes.mainGroup
.on('mousemove', function (e) {
self._hovering = true;
......@@ -610,7 +723,7 @@ class ContinuousView extends VisualMapView {
if (!self._dragging) {
const itemSize = self.visualMapModel.itemSize;
const pos = self._applyTransform(
[e.offsetX, e.offsetY], self._shapes.barGroup, true, true
[e.offsetX, e.offsetY], self._shapes.mainGroup, true, true
);
// For hover link show when hover handle, which might be
// below or upper than sizeExtent.
......@@ -727,6 +840,14 @@ class ContinuousView extends VisualMapView {
const shapes = this._shapes;
shapes.indicator && shapes.indicator.attr('invisible', true);
shapes.indicatorLabel && shapes.indicatorLabel.attr('invisible', true);
const handleLabels = this._shapes.handleLabels;
if (handleLabels) {
for (let i = 0; i < handleLabels.length; i++) {
// Fade out handle labels.
leaveBlur(handleLabels[i]);
}
}
}
private _clearHoverLinkToSeries() {
......@@ -805,24 +926,6 @@ function createPolygon(
});
}
function createHandlePoints(handleIndex: 0 | 1, textSize: number) {
return handleIndex === 0
? [[0, 0], [textSize, 0], [textSize, -textSize]]
: [[0, 0], [textSize, 0], [textSize, textSize]];
}
function createIndicatorPoints(isRange: boolean, halfHoverLinkSize: number, pos: number, extentMax: number) {
return isRange
? [ // indicate range
[0, -mathMin(halfHoverLinkSize, mathMax(pos, 0))],
[HOVER_LINK_OUT, 0],
[0, mathMin(halfHoverLinkSize, mathMax(extentMax - pos, 0))]
]
: [ // indicate single value
[0, 0], [5, -5], [5, 5]
];
}
function getHalfHoverLinkSize(visualMapModel: ContinuousModel, dataExtent: number[], sizeExtent: number[]) {
let halfHoverLinkSize = HOVER_LINK_SIZE / 2;
const hoverLinkDataSize = visualMapModel.get('hoverLinkDataSize');
......
......@@ -1360,7 +1360,7 @@ class ECharts extends Eventful {
// If dispatchAction before setOption, do nothing.
ecModel && ecModel.eachComponent(condition, function (model) {
if (!excludeSeriesIdMap || excludeSeriesIdMap.get(model.id) == null) {
if (isHighDownPayload(payload)) {
if (isHighDownPayload(payload) && !payload.notBlur) {
if (model instanceof SeriesModel) {
toggleSeriesBlurStateFromPayload(model, payload, ecIns);
}
......@@ -1799,6 +1799,7 @@ class ECharts extends Eventful {
if (dispatcher) {
const ecData = getECData(dispatcher);
// Try blur all in the related series. Then emphasis the hoverred.
// TODO. progressive mode.
toggleSeriesBlurState(
ecData.seriesIndex, ecData.focus, ecData.blurScope, ecIns, true
);
......@@ -1943,8 +1944,7 @@ class ECharts extends Eventful {
// If use hover layer
// TODO
// updateHoverLayerStatus(ecIns, ecModel);
updateHoverLayerStatus(ecIns, ecModel);
// Add aria
aria(ecIns._zr.dom, ecModel);
......@@ -1968,45 +1968,50 @@ class ECharts extends Eventful {
}
ecIns.getZr().storage.traverse(function (el: ECElement) {
const newStates = [];
const oldStates = el.currentStates;
// Not applied on removed elements, it may still in fading.
if (graphic.isElementRemoved(el)) {
return;
}
// Keep other states.
for (let i = 0; i < oldStates.length; i++) {
const stateName = oldStates[i];
if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) {
newStates.push(stateName);
}
}
// Only use states when it's exists.
if (el.selected && el.states.select) {
newStates.push('select');
}
if (el.hoverState === HOVER_STATE_EMPHASIS && el.states.emphasis) {
newStates.push('emphasis');
}
else if (el.hoverState === HOVER_STATE_BLUR && el.states.blur) {
newStates.push('blur');
}
el.useStates(newStates);
applyElementStates(el);
});
ecIns[STATUS_NEEDS_UPDATE_KEY] = false;
};
function applyElementStates(el: ECElement) {
const newStates = [];
const oldStates = el.currentStates;
// Keep other states.
for (let i = 0; i < oldStates.length; i++) {
const stateName = oldStates[i];
if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) {
newStates.push(stateName);
}
}
// Only use states when it's exists.
if (el.selected && el.states.select) {
newStates.push('select');
}
if (el.hoverState === HOVER_STATE_EMPHASIS && el.states.emphasis) {
newStates.push('emphasis');
}
else if (el.hoverState === HOVER_STATE_BLUR && el.states.blur) {
newStates.push('blur');
}
el.useStates(newStates);
}
function updateHoverLayerStatus(ecIns: ECharts, ecModel: GlobalModel): void {
const zr = ecIns._zr;
const storage = zr.storage;
let elCount = 0;
storage.traverse(function (el) {
elCount++;
if (!el.isGroup) {
elCount++;
}
});
if (elCount > ecModel.get('hoverLayerThreshold') && !env.node) {
......@@ -2017,8 +2022,9 @@ class ECharts extends Eventful {
const chartView = ecIns._chartsMap[seriesModel.__viewId];
if (chartView.__alive) {
chartView.group.traverse(function (el: ECElement) {
// Don't switch back.
el.useHoverLayer = true;
if (el.states.emphasis) {
el.states.emphasis.hoverLayer = true;
}
});
}
});
......@@ -2026,7 +2032,7 @@ class ECharts extends Eventful {
};
/**
* Update chart progressive and blend.
* Update chart and blend.
*/
function updateBlend(seriesModel: SeriesModel, chartView: ChartView): void {
const blendMode = seriesModel.get('blendMode') || null;
......@@ -2158,14 +2164,7 @@ class ECharts extends Eventful {
// The use higlighted and selected flag to toggle states.
if (el.__dirty) {
const states = [];
if ((el as ECElement).selected) {
states.push('select');
}
if ((el as ECElement).hoverState) {
states.push('emphasis');
}
el.useStates(states);
applyElementStates(el);
}
}
});
......
......@@ -16,6 +16,8 @@ import {
import GlobalModel from '../model/Global';
import { isFunction, retrieve2, extend, keys, trim } from 'zrender/src/core/util';
import { SPECIAL_STATES, DISPLAY_STATES } from '../util/states';
import { __DEV__ } from '../config';
import { deprecateReplaceLog } from '../util/log';
type TextCommonParams = {
/**
......@@ -30,6 +32,11 @@ type TextCommonParams = {
defaultOutsidePosition?: LabelOption['position']
/**
* If support legacy 'auto' for 'inherit' usage.
*/
// supportLegacyAuto?: boolean
textStyle?: ZRStyleProps
};
const EMPTY_OBJ = {};
......@@ -406,7 +413,12 @@ function setTokenTextStyle(
const inheritColor = opt && opt.inheritColor;
let fillColor = textStyleModel.getShallow('color');
let strokeColor = textStyleModel.getShallow('textBorderColor');
if (fillColor === 'inherit') {
if (fillColor === 'inherit' || fillColor === 'auto') {
if (__DEV__) {
if (fillColor === 'auto') {
deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
}
}
if (inheritColor) {
fillColor = inheritColor;
}
......@@ -414,12 +426,17 @@ function setTokenTextStyle(
fillColor = null;
}
}
if (strokeColor === 'inherit' && inheritColor) {
if (strokeColor === 'inherit' || (strokeColor === 'auto')) {
if (__DEV__) {
if (strokeColor === 'auto') {
deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
}
}
if (inheritColor) {
strokeColor = inheritColor;
}
else {
strokeColor = inheritColor;
strokeColor = null;
}
}
fillColor = fillColor || globalTextStyle.color;
......@@ -465,12 +482,6 @@ function setTokenTextStyle(
}
}
if (!isBlock || !opt.disableBox) {
if (textStyle.backgroundColor === 'auto' && inheritColor) {
textStyle.backgroundColor = inheritColor;
}
if (textStyle.borderColor === 'auto' && inheritColor) {
textStyle.borderColor = inheritColor;
}
for (let i = 0; i < TEXT_PROPS_BOX.length; i++) {
const key = TEXT_PROPS_BOX[i];
const val = textStyleModel.getShallow(key);
......@@ -478,6 +489,23 @@ function setTokenTextStyle(
(textStyle as any)[key] = val;
}
}
if ((textStyle.backgroundColor === 'auto' || textStyle.backgroundColor === 'inherit') && inheritColor) {
if (__DEV__) {
if (textStyle.backgroundColor === 'auto') {
deprecateReplaceLog('backgroundColor: \'auto\'', 'backgroundColor: \'inherit\'');
}
}
textStyle.backgroundColor = inheritColor;
}
if ((textStyle.borderColor === 'auto' || textStyle.borderColor === 'inherit') && inheritColor) {
if (__DEV__) {
if (textStyle.borderColor === 'auto') {
deprecateReplaceLog('borderColor: \'auto\'', 'borderColor: \'inherit\'');
}
}
textStyle.borderColor = inheritColor;
}
}
}
export function getFont(
......
......@@ -272,8 +272,8 @@ function doCalBarWidthAndOffset(seriesInfoList: LayoutSeriesInfo[]) {
bandWidth: bandWidth,
remainedWidth: bandWidth,
autoWidthCount: 0,
categoryGap: '20%',
gap: '30%',
categoryGap: null,
gap: '20%',
stacks: {}
};
const stacks = columnsOnAxis.stacks;
......@@ -320,7 +320,15 @@ function doCalBarWidthAndOffset(seriesInfoList: LayoutSeriesInfo[]) {
const stacks = columnsOnAxis.stacks;
const bandWidth = columnsOnAxis.bandWidth;
const categoryGap = parsePercent(columnsOnAxis.categoryGap, bandWidth);
let categoryGapPercent = columnsOnAxis.categoryGap;
if (categoryGapPercent == null) {
const columnCount = zrUtil.keys(stacks).length;
// More columns in one group
// the spaces between group is smaller. Or the column will be too thin.
categoryGapPercent = Math.max((35 - columnCount * 4), 15) + '%';
}
const categoryGap = parsePercent(categoryGapPercent, bandWidth);
const barGapPercent = parsePercent(columnsOnAxis.gap, 1);
let remainedWidth = columnsOnAxis.remainedWidth;
......
/*
* 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 { Text } from '../util/graphic';
import { deprecateLog } from '../util/log';
type TextStyleProps = Text['style'];
export function getTextRect(
text: TextStyleProps['text'],
font?: TextStyleProps['font'],
align?: TextStyleProps['align'],
verticalAlign?: TextStyleProps['verticalAlign'],
padding?: TextStyleProps['padding'],
rich?: TextStyleProps['rich'],
truncate?: boolean,
lineHeight?: number
) {
deprecateLog('getTextRect is deprecated.');
const textEl = new Text({
style: {
text,
font,
align,
verticalAlign,
padding,
rich,
overflow: truncate ? 'truncate' : null,
lineHeight
}
});
return textEl.getBoundingRect();
}
\ No newline at end of file
......@@ -269,3 +269,6 @@ export function windowOpen(link: string, target: string): void {
window.open(link, target);
}
}
export {getTextRect} from '../legacy/getTextRect';
\ No newline at end of file
......@@ -186,7 +186,7 @@ export function makeImage(
rect: ZRRectLike,
layout?: 'center' | 'cover'
) {
const path = new ZRImage({
const zrImg = new ZRImage({
style: {
image: imageUrl,
x: rect.x,
......@@ -200,11 +200,11 @@ export function makeImage(
width: img.width,
height: img.height
};
path.setStyle(centerGraphic(rect, boundingRect));
zrImg.setStyle(centerGraphic(rect, boundingRect));
}
}
});
return path;
return zrImg;
}
/**
......
......@@ -5,7 +5,7 @@ import { PatternObject } from 'zrender/src/graphic/Pattern';
import { GradientObject } from 'zrender/src/graphic/Gradient';
import Element, { ElementEvent } from 'zrender/src/Element';
import Model from '../model/Model';
import { DisplayState, ECElement, ColorString, BlurScope, InnerFocus, Payload, ZRColor } from './types';
import { DisplayState, ECElement, ColorString, BlurScope, InnerFocus, Payload, ZRColor, HighlightPayload, DownplayPayload } from './types';
import { extend, indexOf, isArrayLike, isObject, keys, isArray, each } from 'zrender/src/core/util';
import { getECData } from './graphic';
import * as colorTool from 'zrender/src/tool/color';
......@@ -669,7 +669,7 @@ export function isSelectChangePayload(payload: Payload) {
|| payloadType === TOGGLE_SELECT_ACTION_TYPE;
}
export function isHighDownPayload(payload: Payload) {
export function isHighDownPayload(payload: Payload): payload is HighlightPayload | DownplayPayload {
const payloadType = payload.type;
return payloadType === HIGHLIGHT_ACTION_TYPE
|| payloadType === DOWNPLAY_ACTION_TYPE;
......
......@@ -267,7 +267,7 @@ const symbolShapeMakers: Dictionary<SymbolShapeMaker> = {
}
};
const symbolBuildProxies: Dictionary<ECSymbol> = {};
export const symbolBuildProxies: Dictionary<ECSymbol> = {};
zrUtil.each(symbolCtors, function (Ctor, name) {
symbolBuildProxies[name] = new Ctor();
});
......
......@@ -99,7 +99,6 @@ export interface ComponentTypeInfo {
}
export interface ECElement extends Element {
useHoverLayer?: boolean;
tooltip?: CommonTooltipOption<unknown> & {
content?: string;
formatterParams?: unknown;
......@@ -148,6 +147,16 @@ export interface Payload extends PayloadItem {
batch?: PayloadItem[];
}
export interface HighlightPayload extends Payload {
type: 'highlight';
notBlur?: boolean
}
export interface DownplayPayload extends Payload {
type: 'downplay';
notBlur?: boolean
}
// Payload includes override anmation info
export interface PayloadAnimationPart {
duration?: number
......
......@@ -125,7 +125,7 @@ under the License.
}
],
legend: {
data: ['line', 'line2', 'line3']
left: 'right'
},
tooltip: {
trigger: 'item',
......
......@@ -83,12 +83,12 @@ var option = {
axisType: 'category',
// realtime: false,
// loop: false,
autoPlay: true,
autoPlay: false,
// currentIndex: 2,
playInterval: 1000,
controlStyle: {
showNextBtn: false,
showPrevBtn: false,
showNextBtn: true,
showPrevBtn: true,
position: 'left'
},
data: [
......
......@@ -109,6 +109,7 @@ under the License.
calculable: true,
inverse: true,
dimension: 'value',
top: 'center',
inRange: {
symbolSize: [10, 180]
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册