diff --git a/package-lock.json b/package-lock.json index 004f09105c..7e1a599523 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "Apache-2.0", "dependencies": { "tslib": "2.3.0", - "zrender": "5.3.2" + "zrender": "npm:zrender-nightly@^5.3.3-dev.20220820" }, "devDependencies": { "@babel/code-frame": "7.10.4", @@ -13424,9 +13424,10 @@ } }, "node_modules/zrender": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.2.tgz", - "integrity": "sha512-8IiYdfwHj2rx0UeIGZGGU4WEVSDEdeVCaIg/fomejg1Xu6OifAL1GVzIPHg2D+MyUkbNgPWji90t0a8IDk+39w==", + "name": "zrender-nightly", + "version": "5.3.3-dev.20220820", + "resolved": "https://registry.npmjs.org/zrender-nightly/-/zrender-nightly-5.3.3-dev.20220820.tgz", + "integrity": "sha512-/4hBgw+X1EAZ+wE/4VYfOJEkOD+FWJ+GUEMYVNUoo8FWpU97avPhcTVMupP2w6qjuDY8178ivDs8PMBL7igdxQ==", "dependencies": { "tslib": "2.3.0" } @@ -24353,9 +24354,9 @@ } }, "zrender": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.2.tgz", - "integrity": "sha512-8IiYdfwHj2rx0UeIGZGGU4WEVSDEdeVCaIg/fomejg1Xu6OifAL1GVzIPHg2D+MyUkbNgPWji90t0a8IDk+39w==", + "version": "npm:zrender-nightly@5.3.3-dev.20220820", + "resolved": "https://registry.npmjs.org/zrender-nightly/-/zrender-nightly-5.3.3-dev.20220820.tgz", + "integrity": "sha512-/4hBgw+X1EAZ+wE/4VYfOJEkOD+FWJ+GUEMYVNUoo8FWpU97avPhcTVMupP2w6qjuDY8178ivDs8PMBL7igdxQ==", "requires": { "tslib": "2.3.0" } diff --git a/package.json b/package.json index 5acf86a154..320b0f6925 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ }, "dependencies": { "tslib": "2.3.0", - "zrender": "5.3.2" + "zrender": "npm:zrender-nightly@^5.3.3-dev.20220820" }, "devDependencies": { "@babel/code-frame": "7.10.4", diff --git a/src/chart/bar/BarView.ts b/src/chart/bar/BarView.ts index a5c99d0bd3..3cbad98de3 100644 --- a/src/chart/bar/BarView.ts +++ b/src/chart/bar/BarView.ts @@ -1146,6 +1146,7 @@ function createLarge( const el = new LargePath({ shape: {points: data.getLayout('largePoints')}, incremental: !!incremental, + ignoreCoarsePointer: true, z2: 1 }); el.baseDimIdx = baseDimIdx; diff --git a/src/chart/candlestick/CandlestickView.ts b/src/chart/candlestick/CandlestickView.ts index 3fa95f39d8..ed4f6660c6 100644 --- a/src/chart/candlestick/CandlestickView.ts +++ b/src/chart/candlestick/CandlestickView.ts @@ -358,12 +358,14 @@ function createLarge( const elP = new LargeBoxPath({ shape: {points: largePoints}, - __sign: 1 + __sign: 1, + ignoreCoarsePointer: true }); group.add(elP); const elN = new LargeBoxPath({ shape: {points: largePoints}, - __sign: -1 + __sign: -1, + ignoreCoarsePointer: true }); group.add(elN); @@ -397,4 +399,3 @@ function setLargeStyle(sign: number, el: LargeBoxPath, seriesModel: CandlestickS export default CandlestickView; - diff --git a/src/chart/graph/GraphView.ts b/src/chart/graph/GraphView.ts index 37d0086927..bd5b9669cc 100644 --- a/src/chart/graph/GraphView.ts +++ b/src/chart/graph/GraphView.ts @@ -37,6 +37,9 @@ import SeriesData from '../../data/SeriesData'; import Line from '../helper/Line'; import { getECData } from '../../util/innerStore'; +import { simpleLayoutEdge } from './simpleLayoutHelper'; +import { circularLayout, rotateNodeLabel } from './circularLayoutHelper'; + function isViewCoordSys(coordSys: CoordinateSystem): coordSys is View { return coordSys.type === 'view'; } @@ -122,6 +125,8 @@ class GraphView extends ChartView { this._startForceLayoutIteration(forceLayout, layoutAnimation); } + const layout = seriesModel.get('layout'); + data.graph.eachNode((node) => { const idx = node.dataIndex; const el = node.getGraphicEl() as Symbol; @@ -135,14 +140,31 @@ class GraphView extends ChartView { el.off('drag').off('dragend'); const draggable = itemModel.get('draggable'); if (draggable) { - el.on('drag', () => { - if (forceLayout) { - forceLayout.warmUp(); - !this._layouting - && this._startForceLayoutIteration(forceLayout, layoutAnimation); - forceLayout.setFixed(idx); - // Write position back to layout - data.setItemLayout(idx, [el.x, el.y]); + el.on('drag', (e) => { + switch (layout) { + case 'force': + forceLayout.warmUp(); + !this._layouting + && this._startForceLayoutIteration(forceLayout, layoutAnimation); + forceLayout.setFixed(idx); + // Write position back to layout + data.setItemLayout(idx, [el.x, el.y]); + break; + case 'circular': + data.setItemLayout(idx, [el.x, el.y]); + // mark node fixed + node.setLayout({ fixed: true }, true); + // recalculate circular layout + circularLayout(seriesModel, 'symbolSize', node, [e.offsetX, e.offsetY]); + this.updateLayout(seriesModel); + break; + case 'none': + default: + data.setItemLayout(idx, [el.x, el.y]); + // update edge + simpleLayoutEdge(seriesModel.getGraph(), seriesModel); + this.updateLayout(seriesModel); + break; } }).on('dragend', () => { if (forceLayout) { @@ -179,37 +201,8 @@ class GraphView extends ChartView { && seriesModel.get(['circular', 'rotateLabel']); const cx = data.getLayout('cx'); const cy = data.getLayout('cy'); - data.eachItemGraphicEl(function (el: Symbol, idx) { - const itemModel = data.getItemModel(idx); - let labelRotate = itemModel.get(['label', 'rotate']) || 0; - const symbolPath = el.getSymbolPath(); - if (circularRotateLabel) { - const pos = data.getItemLayout(idx); - let rad = Math.atan2(pos[1] - cy, pos[0] - cx); - if (rad < 0) { - rad = Math.PI * 2 + rad; - } - const isLeft = pos[0] < cx; - if (isLeft) { - rad = rad - Math.PI; - } - const textPosition = isLeft ? 'left' as const : 'right' as const; - - symbolPath.setTextConfig({ - rotation: -rad, - position: textPosition, - origin: 'center' - }); - const emphasisState = symbolPath.ensureState('emphasis'); - zrUtil.extend(emphasisState.textConfig || (emphasisState.textConfig = {}), { - position: textPosition - }); - } - else { - symbolPath.setTextConfig({ - rotation: labelRotate *= Math.PI / 180 - }); - } + data.graph.eachNode((node) => { + rotateNodeLabel(node, circularRotateLabel, cx, cy); }); this._firstRender = false; diff --git a/src/chart/graph/circularLayoutHelper.ts b/src/chart/graph/circularLayoutHelper.ts index 91265bea62..af01fb0f8c 100644 --- a/src/chart/graph/circularLayoutHelper.ts +++ b/src/chart/graph/circularLayoutHelper.ts @@ -20,8 +20,9 @@ import * as vec2 from 'zrender/src/core/vector'; import {getSymbolSize, getNodeGlobalScale} from './graphHelper'; -import GraphSeriesModel, { GraphEdgeItemOption } from './GraphSeries'; -import Graph from '../../data/Graph'; +import GraphSeriesModel, { GraphEdgeItemOption, GraphNodeItemOption } from './GraphSeries'; +import Graph, { GraphNode } from '../../data/Graph'; +import Symbol from '../helper/Symbol'; import SeriesData from '../../data/SeriesData'; import * as zrUtil from 'zrender/src/core/util'; import {getCurvenessForEdge} from '../helper/multipleGraphEdgeHelper'; @@ -51,7 +52,9 @@ const _symbolRadiansHalf: number[] = []; */ export function circularLayout( seriesModel: GraphSeriesModel, - basedOn: 'value' | 'symbolSize' + basedOn: 'value' | 'symbolSize', + draggingNode?: GraphNode, + pointer?: [number, number] ) { const coordSys = seriesModel.coordinateSystem; if (coordSys && coordSys.type !== 'view') { @@ -77,6 +80,17 @@ export function circularLayout( return; } + if (draggingNode) { + const [tempX, tempY] = coordSys.pointToData(pointer) as [number, number]; + const v = [tempX - cx, tempY - cy]; + vec2.normalize(v, v); + vec2.scale(v, v, r); + draggingNode.setLayout([cx + v[0], cy + v[1]], true); + + const circularRotateLabel = seriesModel.get(['circular', 'rotateLabel']); + rotateNodeLabel(draggingNode, circularRotateLabel, cx, cy); + } + _layoutNodesBasedOn[basedOn](seriesModel, graph, nodeData, r, cx, cy, count); graph.eachEdge(function (edge, index) { @@ -163,7 +177,11 @@ const _layoutNodesBasedOn: Record<'value' | 'symbolSize', LayoutNode> = { const radianHalf = halfRemainRadian + _symbolRadiansHalf[node.dataIndex]; angle += radianHalf; - node.setLayout([ + // init circular layout for + // 1. layout undefined node + // 2. not fixed node + (!node.getLayout() || !node.getLayout().fixed) + && node.setLayout([ r * Math.cos(angle) + cx, r * Math.sin(angle) + cy ]); @@ -171,3 +189,46 @@ const _layoutNodesBasedOn: Record<'value' | 'symbolSize', LayoutNode> = { }); } }; + +export function rotateNodeLabel( + node: GraphNode, + circularRotateLabel: boolean, + cx: number, + cy: number +) { + const el = node.getGraphicEl() as Symbol; + // need to check if el exists. '-' value may not create node element. + if (!el) { + return; + } + const nodeModel = node.getModel(); + let labelRotate = nodeModel.get(['label', 'rotate']) || 0; + const symbolPath = el.getSymbolPath(); + if (circularRotateLabel) { + const pos = node.getLayout(); + let rad = Math.atan2(pos[1] - cy, pos[0] - cx); + if (rad < 0) { + rad = Math.PI * 2 + rad; + } + const isLeft = pos[0] < cx; + if (isLeft) { + rad = rad - Math.PI; + } + const textPosition = isLeft ? 'left' as const : 'right' as const; + + symbolPath.setTextConfig({ + rotation: -rad, + position: textPosition, + origin: 'center' + }); + const emphasisState = symbolPath.ensureState('emphasis'); + zrUtil.extend(emphasisState.textConfig || (emphasisState.textConfig = {}), { + position: textPosition + }); + } + else { + symbolPath.setTextConfig({ + rotation: labelRotate *= Math.PI / 180 + }); + } +} diff --git a/src/chart/helper/EffectLine.ts b/src/chart/helper/EffectLine.ts index 412b27297c..f368d83ac0 100644 --- a/src/chart/helper/EffectLine.ts +++ b/src/chart/helper/EffectLine.ts @@ -47,6 +47,8 @@ class EffectLine extends graphic.Group { private _loop: boolean; + private _roundTrip: boolean; + private _symbolScale: number[]; constructor(lineData: SeriesData, idx: number, seriesScope: LineDrawSeriesScope) { @@ -121,6 +123,7 @@ class EffectLine extends graphic.Group { let period = effectModel.get('period') * 1000; const loop = effectModel.get('loop'); + const roundTrip = effectModel.get('roundTrip'); const constantSpeed = effectModel.get('constantSpeed'); const delayExpr = zrUtil.retrieve(effectModel.get('delay'), function (idx) { return idx / lineData.count() * period / 3; @@ -135,7 +138,7 @@ class EffectLine extends graphic.Group { period = this._getLineLength(symbol) / constantSpeed * 1000; } - if (period !== this._period || loop !== this._loop) { + if (period !== this._period || loop !== this._loop || roundTrip !== this._roundTrip) { symbol.stopAnimation(); let delayNum: number; if (zrUtil.isFunction(delayExpr)) { @@ -149,21 +152,23 @@ class EffectLine extends graphic.Group { } this._animateSymbol( - symbol, period, delayNum, loop + symbol, period, delayNum, loop, roundTrip ); } this._period = period; this._loop = loop; + this._roundTrip = roundTrip; } - private _animateSymbol(symbol: ECSymbolOnEffectLine, period: number, delayNum: number, loop: boolean) { + private _animateSymbol( + symbol: ECSymbolOnEffectLine, period: number, delayNum: number, loop: boolean, roundTrip: boolean) { if (period > 0) { symbol.__t = 0; const self = this; const animator = symbol.animate('', loop) - .when(period, { - __t: 1 + .when(roundTrip ? period * 2 : period, { + __t: roundTrip ? 2 : 1 }) .delay(delayNum) .during(function () { @@ -202,7 +207,7 @@ class EffectLine extends graphic.Group { const p1 = symbol.__p1; const p2 = symbol.__p2; const cp1 = symbol.__cp1; - const t = symbol.__t; + const t = symbol.__t < 1 ? symbol.__t : 2 - symbol.__t; const pos = [symbol.x, symbol.y]; const lastPos = pos.slice(); const quadraticAt = curveUtil.quadraticAt; @@ -211,8 +216,11 @@ class EffectLine extends graphic.Group { pos[1] = quadraticAt(p1[1], cp1[1], p2[1], t); // Tangent - const tx = quadraticDerivativeAt(p1[0], cp1[0], p2[0], t); - const ty = quadraticDerivativeAt(p1[1], cp1[1], p2[1], t); + const tx = symbol.__t < 1 ? quadraticDerivativeAt(p1[0], cp1[0], p2[0], t) + : quadraticDerivativeAt(p2[0], cp1[0], p1[0], 1 - t); + const ty = symbol.__t < 1 ? quadraticDerivativeAt(p1[1], cp1[1], p2[1], t) + : quadraticDerivativeAt(p2[1], cp1[1], p1[1], 1 - t); + symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2; // enable continuity trail for 'line', 'rect', 'roundRect' symbolType @@ -247,4 +255,4 @@ class EffectLine extends graphic.Group { this._updateEffectAnimation(lineData, effectModel, idx); } } -export default EffectLine; \ No newline at end of file +export default EffectLine; diff --git a/src/chart/helper/EffectPolyline.ts b/src/chart/helper/EffectPolyline.ts index a250cb590a..389dbe4d83 100644 --- a/src/chart/helper/EffectPolyline.ts +++ b/src/chart/helper/EffectPolyline.ts @@ -67,7 +67,7 @@ class EffectPolyline extends EffectLine { // Override protected _updateSymbolPosition(symbol: ECSymbolOnEffectLine) { - const t = symbol.__t; + const t = symbol.__t < 1 ? symbol.__t : 2 - symbol.__t; const points = this._points; const offsets = this._offsets; const len = points.length; @@ -107,8 +107,8 @@ class EffectPolyline extends EffectLine { symbol.x = p0[0] * (1 - p) + p * p1[0]; symbol.y = p0[1] * (1 - p) + p * p1[1]; - const tx = p1[0] - p0[0]; - const ty = p1[1] - p0[1]; + const tx = symbol.__t < 1 ? p1[0] - p0[0] : p0[0] - p1[0]; + const ty = symbol.__t < 1 ? p1[1] - p0[1] : p0[1] - p1[1]; symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2; this._lastFrame = frame; @@ -119,4 +119,4 @@ class EffectPolyline extends EffectLine { } -export default EffectPolyline; \ No newline at end of file +export default EffectPolyline; diff --git a/src/chart/helper/LargeLineDraw.ts b/src/chart/helper/LargeLineDraw.ts index 62f5b6d14b..88afd6b4c0 100644 --- a/src/chart/helper/LargeLineDraw.ts +++ b/src/chart/helper/LargeLineDraw.ts @@ -293,7 +293,8 @@ class LargeLineDraw { private _create() { const lineEl = new LargeLinesPath({ - cursor: 'default' + cursor: 'default', + ignoreCoarsePointer: true }); this._newAdded.push(lineEl); this.group.add(lineEl); diff --git a/src/chart/helper/LargeSymbolDraw.ts b/src/chart/helper/LargeSymbolDraw.ts index 22614b29f5..2aafb9d13c 100644 --- a/src/chart/helper/LargeSymbolDraw.ts +++ b/src/chart/helper/LargeSymbolDraw.ts @@ -315,6 +315,7 @@ class LargeSymbolDraw { const symbolEl = new LargeSymbolPath({ cursor: 'default' }); + symbolEl.ignoreCoarsePointer = true; this.group.add(symbolEl); this._newAdded.push(symbolEl); return symbolEl; diff --git a/src/chart/helper/LineDraw.ts b/src/chart/helper/LineDraw.ts index d96595395b..94c417f4f7 100644 --- a/src/chart/helper/LineDraw.ts +++ b/src/chart/helper/LineDraw.ts @@ -73,6 +73,7 @@ export interface LineDrawModelOption extends LineDrawStateOption, symbol?: string symbolSize?: number | number[] loop?: boolean + roundTrip?: boolean /** * Length of trail, 0 - 1 */ diff --git a/src/component/helper/RoamController.ts b/src/component/helper/RoamController.ts index edff61052d..874865ebee 100644 --- a/src/component/helper/RoamController.ts +++ b/src/component/helper/RoamController.ts @@ -173,12 +173,19 @@ class RoamController extends Eventful<{ } private _mousedownHandler(e: ZRElementEvent) { - if (eventTool.isMiddleOrRightButtonOnMouseUpDown(e) - || (e.target && e.target.draggable) - ) { + if (eventTool.isMiddleOrRightButtonOnMouseUpDown(e)) { return; } + let el = e.target; + while (el) { + if (el.draggable) { + return; + } + // check if host is draggable + el = el.__hostTarget || el.parent; + } + const x = e.offsetX; const y = e.offsetY; diff --git a/src/core/echarts.ts b/src/core/echarts.ts index 500dbe9ddd..538c819707 100644 --- a/src/core/echarts.ts +++ b/src/core/echarts.ts @@ -34,7 +34,8 @@ import { isDom, isArray, noop, - isString + isString, + retrieve2 } from 'zrender/src/core/util'; import env from 'zrender/src/core/env'; import timsort from 'zrender/src/core/timsort'; @@ -324,6 +325,8 @@ type EChartsInitOpts = { renderer?: RendererType, devicePixelRatio?: number, useDirtyRect?: boolean, + useCoarsePointer?: boolean, + pointerSize?: number, ssr?: boolean, width?: number, height?: number @@ -409,6 +412,7 @@ class ECharts extends Eventful { this._dom = dom; let defaultRenderer = 'canvas'; + let defaultCoarsePointer: 'auto' | boolean = 'auto'; let defaultUseDirtyRect = false; if (__DEV__) { const root = ( @@ -418,6 +422,8 @@ class ECharts extends Eventful { defaultRenderer = root.__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer; + defaultCoarsePointer = retrieve2(root.__ECHARTS__DEFAULT__COARSE_POINTER, defaultCoarsePointer); + const devUseDirtyRect = root.__ECHARTS__DEFAULT__USE_DIRTY_RECT__; defaultUseDirtyRect = devUseDirtyRect == null ? defaultUseDirtyRect @@ -430,7 +436,9 @@ class ECharts extends Eventful { width: opts.width, height: opts.height, ssr: opts.ssr, - useDirtyRect: opts.useDirtyRect == null ? defaultUseDirtyRect : opts.useDirtyRect + useDirtyRect: retrieve2(opts.useDirtyRect, defaultUseDirtyRect), + useCoarsePointer: retrieve2(opts.useCoarsePointer, defaultCoarsePointer), + pointerSize: opts.pointerSize }); this._ssr = opts.ssr; diff --git a/src/util/format.ts b/src/util/format.ts index ce85f6c83a..8aa00685ad 100644 --- a/src/util/format.ts +++ b/src/util/format.ts @@ -18,6 +18,7 @@ */ import * as zrUtil from 'zrender/src/core/util'; +import { encodeHTML } from 'zrender/src/core/dom'; import { parseDate, isNumeric, numericToNumber } from './number'; import { TooltipRenderMode, ColorString, ZRColor, DimensionType } from './types'; import { Dictionary } from 'zrender/src/core/types'; @@ -51,24 +52,7 @@ export function toCamelCase(str: string, upperCaseFirst?: boolean): string { export const normalizeCssArray = zrUtil.normalizeCssArray; - -const replaceReg = /([&<>"'])/g; -const replaceMap: Dictionary = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - '\'': ''' -}; - -export function encodeHTML(source: string): string { - return source == null - ? '' - : (source + '').replace(replaceReg, function (str, c) { - return replaceMap[c]; - }); -} - +export { encodeHTML }; /** * Make value user readable for tooltip and label. diff --git a/test/coarse-pointer.html b/test/coarse-pointer.html new file mode 100644 index 0000000000..959d8babfd --- /dev/null +++ b/test/coarse-pointer.html @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + +

__ECHARTS__DEFAULT__COARSE_POINTER:

+ +
+
+
+ + + + + + + + + + + + diff --git a/test/graph-draggable.html b/test/graph-draggable.html new file mode 100644 index 0000000000..d681e98e19 --- /dev/null +++ b/test/graph-draggable.html @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/lib/caseFrame.js b/test/lib/caseFrame.js index fb2a1703da..bd3e193377 100644 --- a/test/lib/caseFrame.js +++ b/test/lib/caseFrame.js @@ -207,6 +207,17 @@ var matchResult = (pageURL || '').match(/[?&]__RENDERER__=(canvas|svg)(&|$)/); return matchResult && matchResult[1] || 'canvas'; }, + // true, false, 'auto' + useCoarsePointer: function (pageURL) { + var matchResult = (pageURL || '').match(/[?&]__USE_COARSE_POINTER__=(true|false|auto)(&|$)/); + return matchResult && matchResult[1] + ? matchResult[1] === 'true' + ? true + : matchResult[1] === 'false' + ? false + : 'auto' + : 'auto'; + }, // true, false useDirtyRect: function (pageURL) { var matchResult = (pageURL || '').match(/[?&]__USE_DIRTY_RECT__=(true|false)(&|$)/); diff --git a/test/lib/config.js b/test/lib/config.js index 1c99b359ac..bc36037e79 100644 --- a/test/lib/config.js +++ b/test/lib/config.js @@ -30,6 +30,21 @@ if (params.__RENDERER__) { window.__ECHARTS__DEFAULT__RENDERER__ = params.__RENDERER__; } + if (params.__COARSE__POINTER__) { + switch (params.__COARSE__POINTER__) { + case 'true': + window.__ECHARTS__COARSE__POINTER__ = true; + break; + + case 'false': + window.__ECHARTS__COARSE__POINTER__ = false; + break; + + default: + window.__ECHARTS__COARSE__POINTER__ = 'auto'; + break; + } + } if (params.__USE_DIRTY_RECT__) { window.__ECHARTS__DEFAULT__USE_DIRTY_RECT__ = params.__USE_DIRTY_RECT__ === 'true'; } diff --git a/test/lib/testHelper.js b/test/lib/testHelper.js index 93fb9bbb60..6df2c44a6e 100644 --- a/test/lib/testHelper.js +++ b/test/lib/testHelper.js @@ -262,6 +262,8 @@ * @param {boolean|number} opt If number, means height * @param {boolean} opt.lazyUpdate * @param {boolean} opt.notMerge + * @param {boolean} opt.useCoarsePointer + * @param {boolean} opt.pointerSize * @param {number} opt.width * @param {number} opt.height * @param {boolean} opt.draggable @@ -284,7 +286,10 @@ dom.style.height = opt.height + 'px'; } - var chart = echarts.init(dom); + var chart = echarts.init(dom, null, { + useCoarsePointer: opt.useCoarsePointer, + pointerSize: opt.pointerSize + }); if (opt.draggable) { if (!window.draggable) { diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index 172669683e..42f3d8e2ef 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -50,6 +50,7 @@ "candlestick-large2": 1, "candlestickConnect": 4, "clip": 12, + "coarse-pointer": 3, "color-mix-aqi": 2, "connect": 1, "connect-dynamic": 2, diff --git a/test/runTest/actions/coarse-pointer.json b/test/runTest/actions/coarse-pointer.json new file mode 100644 index 0000000000..4b7d7ed09b --- /dev/null +++ b/test/runTest/actions/coarse-pointer.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousemove","time":427,"x":507,"y":250},{"type":"mousemove","time":627,"x":469,"y":258},{"type":"mousemove","time":830,"x":403,"y":272},{"type":"mousemove","time":1042,"x":365,"y":279},{"type":"mousemove","time":1242,"x":345,"y":306},{"type":"mousemove","time":1446,"x":338,"y":330},{"type":"mousemove","time":1626,"x":337,"y":330},{"type":"mousemove","time":1827,"x":304,"y":339},{"type":"mousemove","time":2027,"x":303,"y":338},{"type":"mousemove","time":2231,"x":298,"y":331},{"type":"mousemove","time":2447,"x":298,"y":330},{"type":"mousedown","time":2686,"x":298,"y":330},{"type":"mouseup","time":2831,"x":298,"y":330},{"time":2832,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4028,"x":298,"y":333},{"type":"mousemove","time":4230,"x":330,"y":386},{"type":"mousemove","time":4446,"x":339,"y":395},{"type":"mousemove","time":4692,"x":339,"y":395},{"type":"mousemove","time":4892,"x":344,"y":402}],"scrollY":0,"scrollX":0,"timestamp":1657770168133},{"name":"Action 2","ops":[{"type":"mousemove","time":777,"x":394,"y":369},{"type":"mousemove","time":977,"x":351,"y":337},{"type":"mousemove","time":1178,"x":322,"y":311},{"type":"mousemove","time":1378,"x":312,"y":297},{"type":"mousemove","time":1578,"x":305,"y":292},{"type":"mousemove","time":1779,"x":304,"y":291},{"type":"mousedown","time":2165,"x":304,"y":291},{"type":"mouseup","time":2308,"x":304,"y":291},{"time":2309,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3131,"x":304,"y":292},{"type":"mousemove","time":3333,"x":335,"y":337},{"type":"mousemove","time":3545,"x":354,"y":365},{"type":"mousemove","time":3749,"x":357,"y":369}],"scrollY":512,"scrollX":0,"timestamp":1657770178748},{"name":"Action 3","ops":[{"type":"mousemove","time":351,"x":589,"y":312},{"type":"mousemove","time":551,"x":481,"y":373},{"type":"mousemove","time":755,"x":446,"y":397},{"type":"mousemove","time":967,"x":417,"y":416},{"type":"mousemove","time":1168,"x":410,"y":420},{"type":"mousemove","time":1401,"x":409,"y":420},{"type":"mousemove","time":1408,"x":408,"y":420},{"type":"mousemove","time":1608,"x":375,"y":433},{"type":"mousemove","time":1818,"x":353,"y":433},{"type":"mousemove","time":2018,"x":352,"y":433},{"type":"mousemove","time":2618,"x":352,"y":433},{"type":"mousemove","time":2823,"x":406,"y":439},{"type":"mousemove","time":3035,"x":467,"y":431},{"type":"mousemove","time":3237,"x":467,"y":431}],"scrollY":870.5,"scrollX":0,"timestamp":1657770187725}] \ No newline at end of file diff --git a/test/runTest/cli.js b/test/runTest/cli.js index 582fa9928f..7b7755fda0 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -41,6 +41,7 @@ program .option('--expected ', 'Expected version') .option('--actual ', 'Actual version') .option('--renderer ', 'svg/canvas renderer') + .option('--use-coarse-pointer ', '"auto" (by default) or "true" or "false"') .option('--threads ', 'How many threads to run concurrently') .option('--no-save', 'Don\'t save result') .option('--dir ', 'Out dir'); @@ -51,6 +52,7 @@ program.speed = +program.speed || 1; program.actual = program.actual || 'local'; program.threads = +program.threads || 1; program.renderer = (program.renderer || 'canvas').toLowerCase(); +program.useCoarsePointer = (program.useCoarsePointer || 'auto').toLowerCase(); program.dir = program.dir || (__dirname + '/tmp'); if (!program.tests) { @@ -265,7 +267,7 @@ async function runTestPage(browser, testOpt, version, runtimeCode, isExpected) { width: 800, height: 600 }); - await page.goto(`${origin}/test/${fileUrl}?__RENDERER__=${program.renderer}`, { + await page.goto(`${origin}/test/${fileUrl}?__RENDERER__=${program.renderer}&__COARSE__POINTER__=${program.useCoarsePointer}`, { waitUntil: 'networkidle2', timeout: 10000 }); @@ -384,6 +386,7 @@ async function runTest(browser, testOpt, runtimeCode, expectedVersion, actualVer testOpt.actualVersion = actualVersion; testOpt.expectedVersion = expectedVersion; testOpt.useSVG = program.renderer === 'svg'; + testOpt.useCoarsePointer = program.useCoarsePointer; testOpt.lastRun = Date.now(); } else { @@ -407,7 +410,7 @@ async function runTests(pendingTests) { }); async function eachTask(testOpt) { - console.log(`Running test: ${testOpt.name}, renderer: ${program.renderer}`); + console.log(`Running test: ${testOpt.name}, renderer: ${program.renderer}, useCoarsePointer: ${program.useCoarsePointer}`); try { await runTest(browser, testOpt, runtimeCode, program.expected, program.actual); } diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css index dcb6956374..1cce88083b 100644 --- a/test/runTest/client/client.css +++ b/test/runTest/client/client.css @@ -71,7 +71,6 @@ } .nav-toolbar, .test-run-controls { - padding: 10px 10px; background: #fff; position: fixed; width: 330px; @@ -84,17 +83,14 @@ z-index: 1; position: sticky; width: 100%; - padding: 5px 40px; top: 0px; - background: #896bda; box-shadow: 0 0 20px rgb(0 0 0 / 20%); border-bottom: none; } -.test-run-controls>* { - display: inline-block; - vertical-align: middle; +.test-run-row { + padding: 5px 20px; } .nav-toolbar .el-button { @@ -106,6 +102,8 @@ margin: 0 5px; color: #fff; font-size: 12px; + display: inline-block; + vertical-align: middle; } .run-config-item>* { display: inline-block; diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js index f110fbd3f1..0c34e0ff0e 100644 --- a/test/runTest/client/client.js +++ b/test/runTest/client/client.js @@ -137,6 +137,7 @@ const app = new Vue({ expectedVersion: null, renderer: 'canvas', + useCoarsePointer: 'auto', threads: 4 }, urlRunConfig) }, @@ -344,6 +345,9 @@ const app = new Vue({ if (test.useSVG) { searches.push('__RENDERER__=svg'); } + if (test.useCoarsePointer) { + searches.push('__COARSE__POINTER__=true'); + } let src = test.fileUrl; if (searches.length) { src = src + '?' + searches.join('&'); @@ -366,6 +370,7 @@ const app = new Vue({ this.runConfig.isExpectedNightly = runResult.expectedVersion.includes('-dev.'); this.runConfig.isActualNightly = runResult.actualVersion.includes('-dev.'); this.runConfig.renderer = runResult.renderer; + this.runConfig.useCoarsePointer = runResult.useCoarsePointer; this.showRunsDialog = false; }, @@ -418,6 +423,7 @@ function runTests(tests, noHeadless) { actualVersion: app.runConfig.actualVersion, threads: app.runConfig.threads, renderer: app.runConfig.renderer, + useCoarsePointer: app.runConfig.useCoarsePointer, noHeadless, replaySpeed: noHeadless ? 5 : 5 }); diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index 9d52c1ae12..e8978f8e43 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -101,83 +101,94 @@

Visual Regression Testing Tool

-
- -
- - ALL RUNS -
-
-
- -
- - RUN ({{selectedTests.length}}) - - Run unfinished ({{unfinishedTests.length}}) - Run failed ({{failedTests.length}}) - Run all ({{fullTests.length}}) - - +
+
+ +
+ + LIST OF RUNNING RESULTS +
+
+
- - Stop - - +
+ + RUN ({{selectedTests.length}}) + + Run unfinished ({{unfinishedTests.length}}) + Run failed ({{failedTests.length}}) + Run all ({{fullTests.length}}) + + - - - -
+ + Stop + + -
- - Expected - - - - - - - - - - Actual - - + + - - - - -
-
- Renderer - - - - +
-
- Threads +
+
+ + Expected + + + + + + + + + + Actual + + + + + + + +
+
+ Renderer + + + + +
+
+ Coarse Pointer + + + + + +
+
+ Threads - - - - + + + + +
diff --git a/test/runTest/server.js b/test/runTest/server.js index f74b001956..f7b598f6fc 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -131,6 +131,7 @@ function startTests(testsNameList, socket, { actualVersion, expectedVersion, renderer, + useCoarsePointer, noSave }) { console.log('Received: ', testsNameList.join(',')); @@ -190,6 +191,7 @@ function startTests(testsNameList, socket, { '--actual', actualVersion, '--expected', expectedVersion, '--renderer', renderer || '', + '--use-coarse-pointer', useCoarsePointer, '--threads', Math.min(threadsCount, CLI_FIXED_THREADS_COUNT), '--dir', getResultBaseDir(), ...(noHeadless ? ['--no-headless'] : []), @@ -339,6 +341,7 @@ async function start() { actualVersion: data.actualVersion, expectedVersion: data.expectedVersion, renderer: data.renderer, + useCoarsePointer: data.useCoarsePointer, noSave: false } ); @@ -399,6 +402,7 @@ async function start() { actualVersion: data.actualVersion, expectedVersion: data.expectedVersion, renderer: data.renderer || '', + useCoarsePointer: data.useCoarsePointer, noSave: true }); } diff --git a/test/runTest/store.js b/test/runTest/store.js index 5eb3e1dd10..3430bd47e8 100644 --- a/test/runTest/store.js +++ b/test/runTest/store.js @@ -80,7 +80,8 @@ function getRunHash(params) { return [ params.expectedVersion, params.actualVersion, - params.renderer + params.renderer, + params.useCoarsePointer ].join(TEST_HASH_SPLITTER); } @@ -92,7 +93,8 @@ function parseRunHash(str) { return { expectedVersion: parts[0], actualVersion: parts[1], - renderer: parts[2] + renderer: parts[2], + useCoarsePointer: parts[3] }; } @@ -111,7 +113,8 @@ module.exports.checkStoreVersion = function (runParams) { console.log('Store ', _runHash); return storeParams.expectedVersion === runParams.expectedVersion && storeParams.actualVersion === runParams.actualVersion - && storeParams.renderer === runParams.renderer; + && storeParams.renderer === runParams.renderer + && storeParams.useCoarsePointer === runParams.useCoarsePointer; } function getResultFilePath() {