提交 1f04ff69 编写于 作者: 1 100pah

Merge branch 'next' into custom-morph2

......@@ -25,13 +25,11 @@ import {
Sector,
updateProps,
initProps,
updateLabel,
initLabel,
removeElementWithFadeOut
} from '../../util/graphic';
import { getECData } from '../../util/innerStore';
import { enableHoverEmphasis, setStatesStylesFromModel } from '../../util/states';
import { setLabelStyle, getLabelStatesModels, labelInner } from '../../label/labelStyle';
import { setLabelStyle, getLabelStatesModels, labelInner, setLabelValueAnimation } from '../../label/labelStyle';
import {throttle} from '../../util/throttle';
import {createClipPath} from '../helper/createClipPathFromCoordSys';
import Sausage from '../../util/shape/sausage';
......@@ -291,16 +289,10 @@ class BarView extends ChartView {
el, data, dataIndex, itemModel, layout,
seriesModel, isHorizontalOrRadial, coord.type === 'polar'
);
initLabel(
el, data, dataIndex, itemModel.getModel('label'), seriesModel, animationModel, defaultTextGetter
);
if (isInitSort) {
(el as Rect).attr({ shape: layout });
}
else if (realtimeSort) {
(el as unknown as ECElement).disableLabelAnimation = true;
updateRealtimeAnimation(
seriesModel,
axis2DModel,
......@@ -381,17 +373,12 @@ class BarView extends ChartView {
el, data, newIndex, itemModel, layout,
seriesModel, isHorizontalOrRadial, coord.type === 'polar'
);
updateLabel(
el, data, newIndex, itemModel.getModel('label'), seriesModel, animationModel, defaultTextGetter
);
}
if (isInitSort) {
(el as Rect).attr({ shape: layout });
}
else if (realtimeSort) {
(el as unknown as ECElement).disableLabelAnimation = true;
updateRealtimeAnimation(
seriesModel,
axis2DModel,
......@@ -863,9 +850,10 @@ function updateStyle(
const labelPositionOutside = isHorizontal
? ((layout as RectLayout).height > 0 ? 'bottom' as const : 'top' as const)
: ((layout as RectLayout).width > 0 ? 'left' as const : 'right' as const);
const labelStatesModels = getLabelStatesModels(itemModel);
setLabelStyle(
el, getLabelStatesModels(itemModel),
el, labelStatesModels,
{
labelFetcher: seriesModel,
labelDataIndex: dataIndex,
......@@ -876,11 +864,13 @@ function updateStyle(
);
const label = el.getTextContent();
if (label) {
const obj = labelInner(label);
obj.prevValue = obj.value;
obj.value = seriesModel.getRawValue(dataIndex) as ParsedValue | ParsedValue[];
}
setLabelValueAnimation(
label,
labelStatesModels,
seriesModel.getRawValue(dataIndex) as ParsedValue,
(value: number) => getDefaultInterpolatedLabel(data, value)
);
}
const emphasisModel = itemModel.getModel(['emphasis']);
......
......@@ -40,14 +40,63 @@ interface LabelFormatter {
}
interface PointerOption {
icon?: string
show?: boolean
keepAspect?: boolean
itemStyle?: ItemStyleOption
/**
* Can be percent
*/
offsetCenter?: (number | string)[]
length?: number | string
width?: number
}
interface AnchorOption {
show?: boolean
showAbove?: boolean
size?: number
icon?: string
offsetCenter?: (number | string)[]
keepAspect?: boolean
itemStyle?: ItemStyleOption
}
interface ProgressOption {
show?: boolean
overlap?: boolean
width?: number
roundCap?: boolean
clip?: boolean
itemStyle?: ItemStyleOption
}
interface TitleOption extends LabelOption {
/**
* [x, y] offset
*/
offsetCenter?: (number | string)[]
formatter?: LabelFormatter | string
/**
* If do value animtion.
*/
valueAnimation?: boolean
}
interface DetailOption extends LabelOption {
/**
* [x, y] offset
*/
offsetCenter?: (number | string)[]
formatter?: LabelFormatter | string
/**
* If do value animtion.
*/
valueAnimation?: boolean
}
export interface GaugeStateOption {
itemStyle?: ItemStyleOption
}
......@@ -56,6 +105,9 @@ export interface GaugeDataItemOption extends GaugeStateOption, StatesOptionMixin
name?: string
value?: OptionDataValueNumeric
pointer?: PointerOption
progress?: ProgressOption
title?: TitleOption
detail?: DetailOption
}
export interface GaugeSeriesOption extends SeriesOption<GaugeStateOption>, GaugeStateOption,
CircleLayoutOptionMixin {
......@@ -73,19 +125,25 @@ export interface GaugeSeriesOption extends SeriesOption<GaugeStateOption>, Gauge
splitNumber?: number
itemStyle?: ItemStyleOption
axisLine?: {
show?: boolean
roundCap?: boolean
lineStyle: Omit<LineStyleOption, 'color'> & {
color: GaugeColorStop[]
}
},
progress?: ProgressOption
splitLine?: {
show?: boolean
/**
* Can be percent
*/
length?: number
distance?: number
lineStyle?: LineStyleOption
}
......@@ -96,6 +154,7 @@ export interface GaugeSeriesOption extends SeriesOption<GaugeStateOption>, Gauge
* Can be percent
*/
length?: number | string
distance?: number
lineStyle?: LineStyleOption
}
......@@ -104,21 +163,10 @@ export interface GaugeSeriesOption extends SeriesOption<GaugeStateOption>, Gauge
}
pointer?: PointerOption
anchor?: AnchorOption
title?: LabelOption & {
/**
* [x, y] offset
*/
offsetCenter?: (number | string)[]
formatter?: LabelFormatter | string
}
detail?: LabelOption & {
/**
* [x, y] offset
*/
offsetCenter?: (number | string)[]
formatter?: LabelFormatter | string
}
title?: TitleOption
detail?: DetailOption
data?: (OptionDataValueNumeric | GaugeDataItemOption)[]
}
......@@ -128,6 +176,9 @@ class GaugeSeriesModel extends SeriesModel<GaugeSeriesOption> {
static type = 'series.gauge' as const;
type = GaugeSeriesModel.type;
visualStyleAccessPath = 'itemStyle';
useColorPaletteOnData = true;
getInitialData(option: GaugeSeriesOption, ecModel: GlobalModel): List {
return createListSimply(this, ['value']);
}
......@@ -152,21 +203,32 @@ class GaugeSeriesModel extends SeriesModel<GaugeSeriesOption> {
axisLine: {
// 默认显示,属性show控制显示与否
show: true,
roundCap: false,
lineStyle: { // 属性lineStyle控制线条样式
color: [[0.2, '#91c7ae'], [0.8, '#63869e'], [1, '#c23531']],
width: 30
color: [[1, '#E6EBF8']],
width: 10
}
},
// 坐标轴线
progress: {
// 默认显示,属性show控制显示与否
show: false,
overlap: true,
width: 10,
roundCap: false,
clip: true
},
// 分隔线
splitLine: {
// 默认显示,属性show控制显示与否
show: true,
// 属性length控制线长
length: 30,
length: 10,
distance: 10,
// 属性lineStyle(详见lineStyle)控制线条样式
lineStyle: {
color: '#eee',
width: 2,
color: '#63677A',
width: 3,
type: 'solid'
}
},
......@@ -177,35 +239,52 @@ class GaugeSeriesModel extends SeriesModel<GaugeSeriesOption> {
// 每份split细分多少段
splitNumber: 5,
// 属性length控制线长
length: 8,
length: 6,
distance: 10,
// 属性lineStyle控制线条样式
lineStyle: {
color: '#eee',
color: '#63677A',
width: 1,
type: 'solid'
}
},
axisLabel: {
show: true,
distance: 5,
distance: 15,
// formatter: null,
color: 'auto'
color: '#464646',
fontSize: 12
},
pointer: {
icon: null,
offsetCenter: [0, 0],
show: true,
length: '80%',
width: 8
length: '60%',
width: 6,
keepAspect: false
},
itemStyle: {
color: 'auto'
anchor: {
show: false,
showAbove: false,
size: 6,
icon: 'circle',
offsetCenter: [0, 0],
keepAspect: false,
itemStyle: {
color: '#fff',
borderWidth: 0,
borderColor: '#5470c6'
}
},
title: {
show: true,
// x, y,单位px
offsetCenter: [0, '-40%'],
offsetCenter: [0, '20%'],
// 其余属性默认使用全局文本样式,详见TEXTSTYLE
color: '#333',
fontSize: 15
color: '#464646',
fontSize: 16,
valueAnimation: true
},
detail: {
show: true,
......@@ -219,8 +298,11 @@ class GaugeSeriesModel extends SeriesModel<GaugeSeriesOption> {
offsetCenter: [0, '40%'],
// formatter: null,
// 其余属性默认使用全局文本样式,详见TEXTSTYLE
color: 'auto',
fontSize: 30
color: '#464646',
fontSize: 30,
fontWeight: 'bold',
lineHeight: 30,
valueAnimation: true
}
};
}
......
此差异已折叠。
......@@ -177,20 +177,24 @@ class Symbol extends graphic.Group {
if (isInit) {
const symbolPath = this.childAt(0) as ECSymbol;
const target: PathProps = {
scaleX: this._sizeX,
scaleY: this._sizeY,
style: {
// Always fadeIn. Because it has fadeOut animation when symbol is removed..
opacity: symbolPath.style.opacity
}
};
symbolPath.scaleX = symbolPath.scaleY = 0;
symbolPath.style.opacity = 0;
if (!disableAnimation) {
const target: PathProps = {
scaleX: this._sizeX,
scaleY: this._sizeY,
style: {
// Always fadeIn. Because it has fadeOut animation when symbol is removed..
opacity: symbolPath.style.opacity
}
};
symbolPath.scaleX = symbolPath.scaleY = 0;
symbolPath.style.opacity = 0;
graphic.initProps(symbolPath, target, seriesModel, idx);
}
}
disableAnimation ? symbolPath.attr(target)
: graphic.initProps(symbolPath, target, seriesModel, idx);
if (disableAnimation) {
// Must stop remove animation manually if don't call initProps or updateProps.
this.childAt(0).stopAnimation('remove');
}
this._seriesModel = seriesModel;
......@@ -335,7 +339,6 @@ class Symbol extends graphic.Group {
emphasisState.scaleX = this._sizeX * scaleRatio;
emphasisState.scaleY = this._sizeY * scaleRatio;
}
this.setSymbolScale(1);
enableHoverEmphasis(this, focus, blurScope);
......
......@@ -49,7 +49,7 @@ export function getDefaultLabel(
export function getDefaultInterpolatedLabel(
data: List,
interpolatedValue: ParsedValue | ParsedValue[]
) {
): string {
const labelDims = data.mapDimensionsAll('defaultedLabel');
if (!isArray(interpolatedValue)) {
return interpolatedValue + '';
......
......@@ -136,7 +136,7 @@ class LineSeriesModel extends SeriesModel<LineSeriesOption> {
static defaultOption: LineSeriesOption = {
zlevel: 0,
z: 2,
z: 3,
coordinateSystem: 'cartesian2d',
legendHoverLink: true,
......
......@@ -171,7 +171,7 @@ function turnPointsIntoStep(
stepPt[1 - baseIndex] = pt[1 - baseIndex];
stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];
stepPoints.push(stepPt[0], stepPt[1]);
stepPoints.push(stepPt2[0], stepPt[1]);
stepPoints.push(stepPt2[0], stepPt2[1]);
break;
default:
// default is start
......@@ -1008,16 +1008,18 @@ class LineView extends ChartView {
const delay = typeof seriesDalay === 'function' ? seriesDalay(idx)
: (seriesDuration * ratio) + seriesDalayValue;
el.animateFrom({
scaleX: 0,
scaleY: 0
const symbolPath = el.getSymbolPath();
const text = symbolPath.getTextContent();
el.attr({ scaleX: 0, scaleY: 0});
el.animateTo({
scaleX: 1,
scaleY: 1
}, {
duration: 200,
delay: delay
});
const symbolPath = el.getSymbolPath();
const text = symbolPath.getTextContent();
if (text) {
text.animateFrom({
style: {
......
......@@ -205,7 +205,7 @@ class ScrollableLegendView extends LegendView {
selector && (processMaxSize[wh] = maxSize[wh] - selectorRect[wh] - selectorButtonGap);
const mainRect = this._layoutContentAndController(legendModel, isFirstRender,
processMaxSize, orientIdx, wh, hw, yx
processMaxSize, orientIdx, wh, hw, yx, xy
);
if (selector) {
......@@ -238,7 +238,8 @@ class ScrollableLegendView extends LegendView {
orientIdx: 0 | 1,
wh: 'width' | 'height',
hw: 'width' | 'height',
yx: 'x' | 'y'
yx: 'x' | 'y',
xy: 'y' | 'x'
) {
const contentGroup = this.getContentGroup();
const containerGroup = this._containerGroup;
......@@ -264,12 +265,13 @@ class ScrollableLegendView extends LegendView {
const controllerRect = controllerGroup.getBoundingRect();
const showController = this._showController = contentRect[wh] > maxSize[wh];
// In case that the inner elements of contentGroup layout do not based on [0, 0]
const contentPos = [-contentRect.x, -contentRect.y];
// Remain contentPos when scroll animation perfroming.
// If first rendering, `contentGroup.position` is [0, 0], which
// does not make sense and may cause unexepcted animation if adopted.
if (!isFirstRender) {
contentPos[orientIdx] = contentGroup[yx];
contentPos[orientIdx] = contentGroup[xy];
}
// Layout container group based on 0.
......
......@@ -298,12 +298,14 @@ class TooltipHTMLContent {
}
};
el.onmouseleave = function () {
// set `_inContent` to `false` before `hideLater`
self._inContent = false;
if (self._enterable) {
if (self._show) {
self.hideLater(self._hideDelay);
}
}
self._inContent = false;
};
}
......
......@@ -38,7 +38,7 @@ import CoordinateSystemManager from '../../CoordinateSystem';
import {ParsedModelFinder, SINGLE_REFERRING} from '../../util/model';
// Depends on GridModel, AxisModel, which performs preprocess.
import GridModel from './GridModel';
import GridModel, {defaultGridLayoutWithoutLabel, defaultGridLayoutWithLabel} from './GridModel';
import CartesianAxisModel from './AxisModel';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../ExtensionAPI';
......@@ -118,8 +118,11 @@ class Grid implements CoordinateSystemMaster {
*/
resize(gridModel: GridModel, api: ExtensionAPI, ignoreContainLabel?: boolean): void {
const boxLayoutParams = gridModel.getBoxLayoutParams();
const isContainLabel = !ignoreContainLabel && gridModel.get('containLabel');
const gridRect = getLayoutRect(
gridModel.getBoxLayoutParams(), {
boxLayoutParams, {
width: api.getWidth(),
height: api.getHeight()
});
......@@ -131,7 +134,7 @@ class Grid implements CoordinateSystemMaster {
adjustAxes();
// Minus label size
if (!ignoreContainLabel && gridModel.get('containLabel')) {
if (isContainLabel) {
each(axesList, function (axis) {
if (!axis.model.get(['axisLabel', 'inside'])) {
const labelUnionRect = estimateLabelUnionRect(axis);
......
......@@ -54,7 +54,7 @@ class GridModel extends ComponentModel<GridOption> implements CoordinateSystemHo
left: '10%',
top: 60,
right: '10%',
bottom: 60,
bottom: 70,
// If grid size contain label
containLabel: false,
// width: {totalWidth} - left - right,
......
......@@ -354,6 +354,7 @@ class ECharts extends Eventful {
locale?: string | LocaleOption,
renderer?: RendererType,
devicePixelRatio?: number,
useDirtyRect?: boolean,
width?: number,
height?: number
}
......@@ -369,18 +370,27 @@ class ECharts extends Eventful {
this._dom = dom;
const root = (
typeof window === 'undefined' ? global : window
) as any;
let defaultRenderer = 'canvas';
let defaultUseDirtyRect = false;
if (__DEV__) {
defaultRenderer = ((
typeof window === 'undefined' ? global : window
) as any).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;
defaultRenderer = root.__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;
const devUseDirtyRect = root.__ECHARTS__DEFAULT__USE_DIRTY_RECT__;
defaultUseDirtyRect = devUseDirtyRect == null
? defaultUseDirtyRect
: devUseDirtyRect;
}
const zr = this._zr = zrender.init(dom, {
renderer: opts.renderer || defaultRenderer,
devicePixelRatio: opts.devicePixelRatio,
width: opts.width,
height: opts.height
height: opts.height,
useDirtyRect: opts.useDirtyRect == null ? defaultUseDirtyRect : opts.useDirtyRect
});
// Expect 60 fps.
......@@ -2182,8 +2192,8 @@ class ECharts extends Eventful {
const stateTransition = duration > 0 ? {
duration,
delay: stateAnimationModel.get('delay'),
easing: stateAnimationModel.get('easing'),
additive: stateAnimationModel.get('additive')
easing: stateAnimationModel.get('easing')
// additive: stateAnimationModel.get('additive')
} : null;
view.group.traverse(function (el: Displayable) {
if (el.states && el.states.emphasis) {
......
......@@ -51,6 +51,7 @@ import { retrieve2, each, keys, isFunction, filter, indexOf } from 'zrender/src/
import { PathStyleProps } from 'zrender/src/graphic/Path';
import Model from '../model/Model';
import { prepareLayoutList, hideOverlap, shiftLayoutOnX, shiftLayoutOnY } from './labelLayoutHelper';
import { labelInner, animateLabelValue } from './labelStyle';
interface LabelDesc {
label: ZRText
......@@ -393,7 +394,8 @@ class LabelManager {
label.draggable = true;
label.cursor = 'move';
if (hostEl) {
let hostModel: Model<LabelLineOptionMixin> = labelItem.seriesModel as SeriesModel<LabelLineOptionMixin>;
let hostModel: Model<LabelLineOptionMixin> =
labelItem.seriesModel as SeriesModel<LabelLineOptionMixin>;
if (labelItem.dataIndex != null) {
const data = labelItem.seriesModel.getData(labelItem.dataType);
hostModel = data.getItemModel<LabelLineOptionMixin>(labelItem.dataIndex);
......@@ -494,20 +496,26 @@ class LabelManager {
if (textEl && !textEl.ignore && !textEl.invisible && !(el as ECElement).disableLabelAnimation) {
const layoutStore = labelLayoutInnerStore(textEl);
const oldLayout = layoutStore.oldLayout;
const dataIndex = getECData(el).dataIndex;
const ecData = getECData(el);
const dataIndex = ecData.dataIndex;
const newProps = {
x: textEl.x,
y: textEl.y,
rotation: textEl.rotation
};
const data = seriesModel.getData(ecData.dataType);
if (!oldLayout) {
textEl.attr(newProps);
const oldOpacity = retrieve2(textEl.style.opacity, 1);
// Fade in animation
textEl.style.opacity = 0;
initProps(textEl, {
style: { opacity: oldOpacity }
}, seriesModel, dataIndex);
// Disable fade in animation if value animation is enabled.
if (!labelInner(textEl).valueAnimation) {
const oldOpacity = retrieve2(textEl.style.opacity, 1);
// Fade in animation
textEl.style.opacity = 0;
initProps(textEl, {
style: { opacity: oldOpacity }
}, seriesModel, dataIndex);
}
}
else {
textEl.attr(oldLayout);
......@@ -537,6 +545,8 @@ class LabelManager {
extendWithKeys(layoutEmphasis, newProps, LABEL_LAYOUT_PROPS);
extendWithKeys(layoutEmphasis, textEl.states.emphasis, LABEL_LAYOUT_PROPS);
}
animateLabelValue(textEl, dataIndex, data, seriesModel);
}
if (guideLine && !guideLine.ignore && !guideLine.invisible) {
......
......@@ -17,7 +17,10 @@ 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 { deprecateReplaceLog } from '../util/log';
import { makeInner } from '../util/model';
import { makeInner, interpolateRawValues } from '../util/model';
import List from '../data/List';
import SeriesModel from '../model/Series';
import { initProps, updateProps } from '../util/graphic';
type TextCommonParams = {
/**
......@@ -585,8 +588,88 @@ export const labelInner = makeInner<{
* Current value stored used for label.
*/
value?: ParsedValue | ParsedValue[]
/**
* If enable value animation
*/
valueAnimation?: boolean
/**
* Label value precision during animation.
*/
precision?: number | 'auto'
/**
* If enable value animation
*/
statesModels?: LabelStatesModels<LabelModelForText>
/**
* Default text getter during interpolation
*/
defaultInterpolatedText?: (value: ParsedValue[] | ParsedValue) => string
/**
* Change label text from interpolated text during animation
*/
setLabelText?(overrideValue?: ParsedValue | ParsedValue[]): void
}, ZRText>();
\ No newline at end of file
}, ZRText>();
export function setLabelValueAnimation(
label: ZRText,
labelStatesModels: LabelStatesModels<LabelModelForText>,
value: ParsedValue | ParsedValue[],
getDefaultText: (value: ParsedValue[] | ParsedValue) => string
) {
if (!label) {
return;
}
const obj = labelInner(label);
obj.prevValue = obj.value;
obj.value = value;
const normalLabelModel = labelStatesModels.normal;
obj.valueAnimation = normalLabelModel.get('valueAnimation');
if (obj.valueAnimation) {
obj.precision = normalLabelModel.get('precision');
obj.defaultInterpolatedText = getDefaultText;
obj.statesModels = labelStatesModels;
}
}
export function animateLabelValue(
textEl: ZRText,
dataIndex: number,
data: List,
seriesModel: SeriesModel
) {
const labelInnerStore = labelInner(textEl);
if (!labelInnerStore.valueAnimation) {
return;
}
const defaultInterpolatedText = labelInnerStore.defaultInterpolatedText;
const prevValue = labelInnerStore.prevValue;
const currentValue = labelInnerStore.value;
function during(percent: number) {
const interpolated = interpolateRawValues(
data,
labelInnerStore.precision,
prevValue,
currentValue,
percent
);
const labelText = getLabelText({
labelDataIndex: dataIndex,
// labelFetcher: seriesModel,
defaultText: defaultInterpolatedText
? defaultInterpolatedText(interpolated)
: interpolated + ''
}, labelInnerStore.statesModels, interpolated);
setLabelText(textEl, labelText);
}
(prevValue == null ? initProps
: updateProps)(textEl, {}, seriesModel, dataIndex, null, during);
}
\ No newline at end of file
......@@ -75,8 +75,7 @@ export default {
stateAnimation: {
duration: 300,
easing: 'cubicOut',
additive: true
easing: 'cubicOut'
},
animation: 'auto',
......
......@@ -184,9 +184,18 @@ const theme = {
},
gauge: {
title: {
textStyle: {
color: contrastColor
color: contrastColor
},
axisLine: {
lineStyle: {
color: [[1, 'rgba(207,212,219,0.2)']]
}
},
axisLabel: {
color: contrastColor
},
detail: {
color: '#EEF1FA'
}
},
candlestick: {
......
......@@ -45,15 +45,13 @@ import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';
import * as subPixelOptimizeUtil from 'zrender/src/graphic/helper/subPixelOptimize';
import { Dictionary } from 'zrender/src/core/types';
import Displayable, { DisplayableProps } from 'zrender/src/graphic/Displayable';
import Element, { ElementProps } from 'zrender/src/Element';
import Element from 'zrender/src/Element';
import Model from '../model/Model';
import {
AnimationOptionMixin,
LabelOption,
AnimationDelayCallbackParam,
ZRRectLike,
ZRStyleProps,
ParsedValue,
PayloadAnimationPart
} from './types';
import {
......@@ -63,12 +61,8 @@ import {
defaults,
isObject
} from 'zrender/src/core/util';
import SeriesModel from '../model/Series';
import List from '../data/List';
import { getLabelText, setLabelText, labelInner } from '../label/labelStyle';
import { AnimationEasing } from 'zrender/src/animation/easing';
import { getECData } from './innerStore';
import {interpolateRawValues} from './model';
const mathMax = Math.max;
......@@ -337,6 +331,11 @@ function animateOrSetProps<Props>(
}
const animationEnabled = animatableModel && animatableModel.isAnimationEnabled();
if (!isRemove) {
// Must stop the remove animation.
el.stopAnimation('remove');
}
if (animationEnabled) {
let duration: number | Function;
let animationEasing: AnimationEasing;
......@@ -374,11 +373,6 @@ function animateOrSetProps<Props>(
}
}
if (!isRemove) {
// Must stop the remove animation.
el.stopAnimation('remove');
}
duration > 0
? (
isFrom
......@@ -541,76 +535,6 @@ export function isElementRemoved(el: Element) {
return false;
}
function animateOrSetLabel<Props extends PathProps>(
animationType: 'init' | 'update' | 'remove',
el: Element<Props>,
data: List,
dataIndex: number,
labelModel: Model<LabelOption>,
seriesModel: SeriesModel,
animatableModel?: Model<AnimationOptionMixin>,
getDefaultText?: (value: ParsedValue[] | ParsedValue) => string
) {
const valueAnimationEnabled = labelModel && labelModel.get('valueAnimation');
const label = el.getTextContent();
if (valueAnimationEnabled && label) {
const precision = labelModel ? labelModel.get('precision') : null;
const host = labelInner(label);
const sourceValue = host.prevValue;
const targetValue = host.value;
const during = (percent: number) => {
const text = el.getTextContent();
if (!text || !host) {
return;
}
const interpolated = interpolateRawValues(data, precision, sourceValue, targetValue, percent);
const labelText = getLabelText({
labelDataIndex: dataIndex,
labelFetcher: seriesModel,
defaultText: getDefaultText
? getDefaultText(interpolated)
: interpolated + ''
}, {normal: labelModel}, interpolated);
setLabelText(text, labelText);
};
host.prevValue = targetValue;
const props: ElementProps = {};
animateOrSetProps(animationType, el, props, animatableModel, dataIndex, null, during);
}
}
export function updateLabel<Props>(
el: Element<Props>,
data: List,
dataIndex: number,
labelModel: Model<LabelOption>,
seriesModel: SeriesModel,
animatableModel?: Model<AnimationOptionMixin>,
defaultTextGetter?: (value: ParsedValue[] | ParsedValue) => string
) {
animateOrSetLabel('update', el, data, dataIndex, labelModel, seriesModel, animatableModel, defaultTextGetter);
}
export function initLabel<Props>(
el: Element<Props>,
data: List,
dataIndex: number,
labelModel: Model<LabelOption>,
seriesModel: SeriesModel,
animatableModel?: Model<AnimationOptionMixin>,
defaultTextGetter?: (value: ParsedValue[] | ParsedValue) => string
) {
animateOrSetLabel('init', el, data, dataIndex, labelModel, seriesModel, animatableModel, defaultTextGetter);
}
/**
* Get transform matrix of target (param target),
* in coordinate of its ancestor (param ancestor)
......
......@@ -1019,6 +1019,10 @@ export function interpolateRawValues(
): (string | number)[] | string | number {
const isAutoPrecision = precision == null || precision === 'auto';
if (targetValue == null) {
return targetValue;
}
if (typeof targetValue === 'number') {
const value = interpolateNumber(
sourceValue as number || 0,
......
......@@ -728,7 +728,7 @@ export interface AnimationOption {
duration?: number
easing?: AnimationEasing
delay?: number
additive?: boolean
// additive?: boolean
}
/**
* Mixin of option set to control the animation of series.
......
......@@ -126,7 +126,7 @@ under the License.
currentSeriesIndices.pop(); // remove custom series;
var barLayout = api.barLayout({
barGap: '30%', barCategoryGap: '20%', count: currentSeriesIndices.length
count: currentSeriesIndices.length
});
var nameTexts = echarts.util.map(currentSeriesIndices, function (serIdx, index) {
......
......@@ -739,7 +739,7 @@ under the License.
var xValue = api.value(0);
var currentSeriesIndices = api.currentSeriesIndices();
var barLayout = api.barLayout({
barGap: '30%', barCategoryGap: '20%', count: currentSeriesIndices.length - 1
count: currentSeriesIndices.length - 1
});
var points = [];
......@@ -1380,7 +1380,7 @@ under the License.
currentSeriesIndices.pop(); // remove custom series;
var barLayout = api.barLayout({
barGap: '30%', barCategoryGap: '20%', count: currentSeriesIndices.length
count: currentSeriesIndices.length
});
var nameTexts = echarts.util.map(currentSeriesIndices, function (serIdx, index) {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
<!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="main0"></div>
<div id="main1"></div>
<div id="main2"></div>
<div id="main3"></div>
<div id="main4"></div>
<div id="main5"></div>
<div id="main6"></div>
<script>
require(['echarts'/*, 'map/js/china' */], function (echarts) {
// $.getJSON('./data/nutrients.json', function (data) {});
var option0 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
pointer: {
icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z'
},
progress: {
show: true, // 坐标轴线
},
data: [
{value: 20, name: '完成率'}
],
detail: {
formatter: '{value}%'
},
}
]
};
var chart0 = testHelper.create(echarts, 'main0', {
title: [
'axisLine.roundCap: false, progress.roundCap: false, data.length: 1'
],
option: option0
});
setInterval(function () {
option0.series[0].data[0].value = (Math.random() * 100).toFixed(2) - 0;
chart0.setOption(option0, true);
}, 2000);
var option1 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
pointer: {
icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z'
},
progress: {
show: true, // 坐标轴线
roundCap: true
},
axisLine: {
roundCap: true
},
data: [
{value: 20, name: '完成率'}
],
detail: {
formatter: '{value}%'
},
}
]
};
var chart1 = testHelper.create(echarts, 'main1', {
title: [
'axisLine.roundCap: true, progress.roundCap: true, data.length: 1'
],
option: option1
});
setInterval(function () {
option1.series[0].data[0].value = (Math.random() * 100).toFixed(2) - 0;
chart1.setOption(option1, true);
}, 2000);
var option2 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
pointer: {
icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z'
},
progress: {
show: true, // 坐标轴线
overlap: true,
roundCap: true
},
axisLine: {
roundCap: true
},
data: [
{value: 20, name: '完成率'},
{value: 40, name: '达标率'},
{value: 60, name: '优秀率'}
],
title: {
show: false
},
detail: {
show: false,
formatter: '{value}%'
},
}
]
};
var chart2 = testHelper.create(echarts, 'main2', {
title: [
'axisLine.roundCap: true, progress.roundCap: true, overlap: true, data.length: 3, detail.show: false'
],
option: option2
});
setInterval(function () {
option2.series[0].data[0].value = (Math.random() * 100).toFixed(2) - 0;
option2.series[0].data[1].value = (Math.random() * 100).toFixed(2) - 0;
option2.series[0].data[2].value = (Math.random() * 100).toFixed(2) - 0;
chart2.setOption(option2, true);
}, 2000);
var option3 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
progress: {
show: true, // 坐标轴线
overlap: false,
roundCap: true
},
data: [
{value: 20, name: '完成率'},
{value: 40, name: '达标率'},
{value: 60, name: '优秀率'}
],
title: {
show: false
},
detail: {
show: false,
formatter: '{value}%'
},
}
]
};
var chart3 = testHelper.create(echarts, 'main3', {
title: [
'axisLine.roundCap: false, progress.roundCap: true, overlap: false, data.length: 3, detail.show: false'
],
option: option3
});
setInterval(function () {
option3.series[0].data[0].value = (Math.random() * 100).toFixed(2) - 0;
option3.series[0].data[1].value = (Math.random() * 100).toFixed(2) - 0;
option3.series[0].data[2].value = (Math.random() * 100).toFixed(2) - 0;
chart3.setOption(option3, true);
}, 2000);
var option4 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
pointer: {
icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z'
},
progress: {
show: true, // 坐标轴线
overlap: false,
roundCap: true
},
axisLine: {
roundCap: true
},
data: [
{value: 20, name: '完成率'},
{value: 40, name: '达标率'},
{value: 60, name: '优秀率'}
],
title: {
show: false
},
detail: {
show: false,
formatter: '{value}%'
},
}
]
};
var chart4 = testHelper.create(echarts, 'main4', {
title: [
'axisLine.roundCap: true, progress.roundCap: true, overlap: false, data.length: 3, detail.show: false, title.show: false'
],
option: option4
});
setInterval(function () {
option4.series[0].pointer.show = false;
option4.series[0].data[0].value = (Math.random() * 100).toFixed(2) - 0;
option4.series[0].data[1].value = (Math.random() * 100).toFixed(2) - 0;
option4.series[0].data[2].value = (Math.random() * 100).toFixed(2) - 0;
chart4.setOption(option4, true);
}, 2000);
var option5 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
startAngle: 90,
endAngle: -270,
pointer: {
show: false
},
progress: {
show: true,
clip: false,
roundCap: true,
itemStyle: {
color: '#ff9933',
borderColor: '#7e0023',
borderWidth: 1
}
},
data: [
{value: 120, name: '本月跑步'}
],
detail: {
formatter: '{value} km'
},
}
]
};
var chart5 = testHelper.create(echarts, 'main5', {
title: [
'progress.roundCap: true, click the button to change progress.clip'
],
option: option5,
buttons: [{text: 'change progress.clip', onclick: function () {
option5.series[0].progress.clip = !option5.series[0].progress.clip;
chart5.setOption(option5, true);
}}]
});
});
</script>
</body>
</html>
......@@ -140,7 +140,7 @@ under the License.
{
name: 'Pressure',
type: 'gauge',
data: []
data: [{}]
}
]
};
......
......@@ -30,10 +30,139 @@ under the License.
<style>
html, body, #main {
width: 100%;
height: 100%;
height: 600;
}
</style>
<div id="main"></div>
<div style="position: relative; height: 600px;" id="main"></div>
<div style="position: relative; height: 500px;" id="main1"></div>
<div style="position: relative; height: 500px;" id="main2"></div>
<script>
require([
'echarts'
// 'echarts/chart/gauge',
// 'echarts/component/legend',
// 'echarts/component/tooltip'
], function (echarts) {
var chart1 = echarts.init(document.getElementById('main1'), 'dark', {});
var option1 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
progress: {
show: true
},
anchor:{
showAbove: true,
show: true
},
roundCap: true,
detail: {formatter: '{value}%'},
data: [{value: 58.46, name: '完成率'}]
}
]
};
chart1.setOption(option1);
})
</script>
<script>
require([
'echarts'
// 'echarts/chart/gauge',
// 'echarts/component/legend',
// 'echarts/component/tooltip'
], function (echarts) {
var chart2 = echarts.init(document.getElementById('main2'), 'dark', {});
var option2 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
pointer: {
icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z'
},
roundCap: true,
progress: {
show: true, // 坐标轴线
overlap: false,
color: ['#f00', '#0f0']
},
anchor: {
show: true,
showAbove: true
},
detail: {
formatter: '{value}%'
},
data: [
{
value: 20,
name: '完成率',
title: {
offsetCenter: ['-40%', '20%']
},
detail: {
offsetCenter: ['-40%', '35%']
}
},
{
value: 40,
name: '达标率',
title: {
offsetCenter: ['0%', '20%']
},
detail: {
offsetCenter: ['0%', '35%']
}
},
{
value: 60,
name: '优秀率',
title: {
offsetCenter: ['40%', '20%']
},
detail: {
offsetCenter: ['40%', '35%']
}
}
],
title: {
fontSize: 14
},
detail: {
width: 30,
height: 12,
fontSize: 12,
color: 'auto',
borderColor: 'auto',
borderWidth: 1,
borderRadius: 3,
formatter: '{value}%',
}
}
],
};
chart2.setOption(option2);
})
</script>
<script>
require([
......@@ -43,7 +172,7 @@ under the License.
// 'echarts/component/tooltip'
], function (echarts) {
var chart = echarts.init(document.getElementById('main'), null, {
var chart = echarts.init(document.getElementById('main'), {
});
......@@ -77,12 +206,14 @@ under the License.
},
axisTick: { // 坐标轴小标记
length :15, // 属性length控制线长
distance: 10,
lineStyle: { // 属性lineStyle控制线条样式
color: 'auto'
}
},
splitLine: { // 分隔线
length :20, // 属性length控制线长
distance: 10,
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
color: 'auto'
}
......@@ -208,12 +339,14 @@ under the License.
},
axisTick: { // 坐标轴小标记
length :12, // 属性length控制线长
distance: 10,
lineStyle: { // 属性lineStyle控制线条样式
color: 'auto'
}
},
splitLine: { // 分隔线
length :20, // 属性length控制线长
distance: 10,
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
color: 'auto'
}
......@@ -252,6 +385,7 @@ under the License.
axisTick: { // 坐标轴小标记
splitNumber:5,
length :10, // 属性length控制线长
distance: 10,
lineStyle: { // 属性lineStyle控制线条样式
color: 'auto'
}
......@@ -267,6 +401,7 @@ under the License.
},
splitLine: { // 分隔线
length :15, // 属性length控制线长
distance: 10,
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
color: 'auto'
}
......
......@@ -40,6 +40,7 @@ under the License.
<div id="main0"></div>
<div id="main1"></div>
......@@ -134,11 +135,92 @@ under the License.
// buttons: [{text: 'btn-txt', onclick: function () {}}],
// recordCanvas: true,
});
setTimeout(function () {
option.legend.type = 'plain';
chart.setOption(option);
}, 3000);
var option1 = {
legend: {
data: [
'邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎',
'邮件营销1', '联盟广告1', '视频广告1', '直接访问1', '搜索引擎1'
],
type: 'scroll'
},
xAxis: [{
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
}],
yAxis: [{
type: 'value'
}],
series: [
{
name: '邮件营销',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '联盟广告',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '视频广告',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '直接访问',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '搜索引擎',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '邮件营销1',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '联盟广告1',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '视频广告1',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '直接访问1',
type: 'line',
data: [null, null, null, null, null, null, null]
},
{
name: '搜索引擎1',
type: 'line',
data: [null, null, null, null, null, null, null]
}
]
};
var chart1 = testHelper.create(echarts, 'main1', {
title: [
'Test Case Description of main1',
'Legend scroll animation'
],
option: option1,
width: 300,
// buttons: [{text: 'btn-txt', onclick: function () {}}],
// recordCanvas: true,
});
chart1.setOption(option1);
});
</script>
......
......@@ -35,7 +35,7 @@
}
.case-frame .cases-list ul {
padding-left: 32px;
margin-top: 130px;
margin-top: 170px;
list-style-type: decimal;
}
.case-frame .info-panel {
......@@ -54,10 +54,7 @@
text-decoration: underline;
}
.case-frame .info-panel .renderer-selector {
height: 40px;
line-height: 40px;
}
.case-frame .info-panel .dist-selector {
margin: 10px;
}
.case-frame .info-panel .list-filter {
margin: 10px 0;
......
......@@ -40,8 +40,15 @@
' <div class="info-panel">',
' <input class="current" />',
' <div class="renderer-selector">',
' <input type="radio" value="canvas" name="renderer" /> CANVAS ',
' <input type="radio" value="svg" name="renderer" /> SVG ',
' <div class="render-selector-item">',
' <input type="radio" value="canvas" name="renderer" /> CANVAS ',
' </div>',
' <div class="render-selector-item">',
' <input type="radio" value="dirty-rect" name="renderer" /> CANVAS (dirty rect) ',
' </div>',
' <div class="render-selector-item">',
' <input type="radio" value="svg" name="renderer" /> SVG ',
' </div>',
' </div>',
' <div class="list-filter"></div>',
' <select class="dist-selector">',
......@@ -107,13 +114,23 @@
});
rendererSelector.off('click').on('click', function (e) {
setState('renderer', e.target.value);
if (e.target.value === 'dirty-rect') {
setState('renderer', 'canvas');
setState('useDirtyRect', true);
}
else {
setState('renderer', e.target.value);
setState('useDirtyRect', false);
}
});
var renderer = getState('renderer');
var useDirtyRect = getState('useDirtyRect');
rendererSelector.each(function (index, el) {
el.checked = el.value === renderer;
el.checked = el.value === 'dirty-rect'
? useDirtyRect
: el.value === renderer;
});
}
......@@ -190,6 +207,11 @@
var matchResult = (pageURL || '').match(/[?&]__RENDERER__=(canvas|svg)(&|$)/);
return matchResult && matchResult[1] || 'canvas';
},
// true, false
useDirtyRect: function (pageURL) {
var matchResult = (pageURL || '').match(/[?&]__USE_DIRTY_RECT__=(true|false)(&|$)/);
return matchResult && matchResult[1] === 'true';
},
// 'dist', 'webpack', 'webpackold'
dist: function (pageURL) {
var matchResult = (pageURL || '').match(/[?&]__ECDIST__=(webpack-req-ec|webpack-req-eclibec|webpackold-req-ec|webpackold-req-eclibec)(&|$)/);
......@@ -223,6 +245,7 @@
function setState(prop, value) {
var curr = {
renderer: getState('renderer'),
useDirtyRect: getState('useDirtyRect'),
dist: getState('dist'),
pagePath: getState('pagePath'),
listFilterName: getState('listFilterName')
......@@ -237,6 +260,7 @@
function makePageURL(curr) {
return curr.pagePath + '?' + [
'__RENDERER__=' + curr.renderer,
'__USE_DIRTY_RECT__=' + curr.useDirtyRect,
'__ECDIST__=' + curr.dist,
'__FILTER__=' + curr.listFilterName
].join('&');
......
......@@ -35,6 +35,9 @@
if (params.__RENDERER__) {
window.__ECHARTS__DEFAULT__RENDERER__ = params.__RENDERER__;
}
if (params.__USE_DIRTY_RECT__) {
window.__ECHARTS__DEFAULT__USE_DIRTY_RECT__ = params.__USE_DIRTY_RECT__ === 'true';
}
// Set echarts source code.
var ecDistPath;
......
[{"name":"Action 1","ops":[{"type":"screenshot","time":3170}],"scrollY":0,"scrollX":0,"timestamp":1602246267936},{"name":"Action 2","ops":[{"type":"screenshot","time":2585}],"scrollY":714,"scrollX":0,"timestamp":1602246285822},{"name":"Action 3","ops":[{"type":"screenshot","time":2051}],"scrollY":1693,"scrollX":0,"timestamp":1602246296183},{"name":"Action 4","ops":[{"type":"screenshot","time":1388}],"scrollY":2476,"scrollX":0,"timestamp":1602246309308},{"name":"Action 5","ops":[{"type":"screenshot","time":1445}],"scrollY":3584,"scrollX":0,"timestamp":1602246320327},{"name":"Action 6","ops":[{"type":"screenshot","time":1831}],"scrollY":4544,"scrollX":0,"timestamp":1602246332115}]
\ No newline at end of file
[{"name":"Action 1","ops":[{"type":"screenshot","time":3413}],"scrollY":0,"scrollX":0,"timestamp":1602246421396},{"name":"Action 2","ops":[{"type":"screenshot","time":1686}],"scrollY":458,"scrollX":0,"timestamp":1602246432833},{"name":"Action 3","ops":[{"type":"screenshot","time":1853}],"scrollY":911,"scrollX":0,"timestamp":1602246445097},{"name":"Action 4","ops":[{"type":"screenshot","time":1876}],"scrollY":1374,"scrollX":0,"timestamp":1602246452846},{"name":"Action 5","ops":[{"type":"screenshot","time":1764}],"scrollY":1832,"scrollX":0,"timestamp":1602246460967},{"name":"Action 6","ops":[{"type":"screenshot","time":2066}],"scrollY":2148,"scrollX":0,"timestamp":1602246468649}]
\ No newline at end of file
[{"name":"Action 1","ops":[{"type":"screenshot","time":1824}],"scrollY":0,"scrollX":0,"timestamp":1602246538416},{"name":"Action 2","ops":[{"type":"screenshot","time":1348}],"scrollY":481,"scrollX":0,"timestamp":1602246547107},{"name":"Action 3","ops":[{"type":"screenshot","time":1242}],"scrollY":952,"scrollX":0,"timestamp":1602246555653},{"name":"Action 4","ops":[{"type":"screenshot","time":1149}],"scrollY":1432,"scrollX":0,"timestamp":1602246561913},{"name":"Action 5","ops":[{"type":"screenshot","time":1278}],"scrollY":1925,"scrollX":0,"timestamp":1602246567775},{"name":"Action 6","ops":[{"type":"screenshot","time":1155}],"scrollY":2292,"scrollX":0,"timestamp":1602246574297}]
\ No newline at end of file
[{"name":"Action 1","ops":[{"type":"screenshot","time":1573}],"scrollY":0,"scrollX":0,"timestamp":1602246699614},{"name":"Action 2","ops":[{"type":"screenshot","time":1145}],"scrollY":460,"scrollX":0,"timestamp":1602246707775},{"name":"Action 3","ops":[{"type":"screenshot","time":1198}],"scrollY":910,"scrollX":0,"timestamp":1602246714393},{"name":"Action 4","ops":[{"type":"screenshot","time":1279}],"scrollY":1378,"scrollX":0,"timestamp":1602246720625},{"name":"Action 5","ops":[{"type":"screenshot","time":1430}],"scrollY":1708,"scrollX":0,"timestamp":1602246726107}]
\ No newline at end of file
[{"name":"Action 1","ops":[{"type":"screenshot","time":3972}],"scrollY":0,"scrollX":0,"timestamp":1602245762818},{"name":"Action 2","ops":[{"type":"screenshot","time":2806}],"scrollY":605,"scrollX":0,"timestamp":1602246030112},{"name":"Action 3","ops":[{"type":"screenshot","time":2428}],"scrollY":1008,"scrollX":0,"timestamp":1602246050732}]
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册