/*
|
* 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.
|
*/
|
|
const {waitTime} = require('./util');
|
|
module.exports = class Timeline {
|
|
constructor(page) {
|
this._page = page;
|
|
this._timer = 0;
|
this._current = 0;
|
|
this._ops = [];
|
this._currentOpIndex = 0;
|
|
this._client;
|
|
this._isLastOpMousewheel = false;
|
}
|
|
_reset() {
|
this._currentOpIndex = 0;
|
this._current = Date.now();
|
this._elapsedTime = 0;
|
this._isLastOpMousewheel = false;
|
}
|
|
|
async runAction(action, takeScreenshot, playbackSpeed) {
|
if (!this._client) {
|
this._client = await this._page.target().createCDPSession();
|
}
|
|
this.stop();
|
|
playbackSpeed = playbackSpeed || 1;
|
|
if (!action.ops.length) {
|
return;
|
}
|
|
this._ops = action.ops.slice().sort((a, b) => {
|
return a.time - b.time;
|
});
|
let firstOp = this._ops[0];
|
this._ops.forEach(op => {
|
op.time -= firstOp.time;
|
});
|
|
this._reset();
|
|
let self = this;
|
|
return new Promise(resolve => {
|
async function tick() {
|
let current = Date.now();
|
let dTime = current - self._current;
|
self._elapsedTime += dTime * playbackSpeed;
|
self._current = current;
|
|
await self._update(takeScreenshot, playbackSpeed);
|
if (self._currentOpIndex >= self._ops.length) {
|
// Finished
|
resolve();
|
}
|
else {
|
self._timer = setTimeout(tick, 16);
|
}
|
}
|
tick();
|
});
|
}
|
|
|
stop() {
|
if (this._timer) {
|
clearTimeout(this._timer);
|
this._timer = 0;
|
}
|
}
|
|
async _update(takeScreenshot, playbackSpeed) {
|
let op = this._ops[this._currentOpIndex];
|
|
if (op.time > this._elapsedTime) {
|
// Not yet.
|
return;
|
}
|
|
let page = this._page;
|
let takenScreenshot = false;
|
switch (op.type) {
|
case 'mousedown':
|
await page.mouse.move(op.x, op.y);
|
await page.mouse.down();
|
break;
|
case 'mouseup':
|
await page.mouse.move(op.x, op.y);
|
await page.mouse.up();
|
break;
|
case 'mousemove':
|
await page.mouse.move(op.x, op.y);
|
break;
|
case 'mousewheel':
|
await page.evaluate((x, y, deltaX, deltaY) => {
|
let element = document.elementFromPoint(x, y);
|
// Here dispatch mousewheel event because echarts used it.
|
// TODO Consider upgrade?
|
let event = new WheelEvent('mousewheel', {
|
// PENDING
|
// Needs inverse delta?
|
deltaY,
|
clientX: x, clientY: y,
|
// Needs bubble to parent container
|
bubbles: true
|
});
|
|
element.dispatchEvent(event);
|
}, op.x, op.y, op.deltaX || 0, op.deltaY);
|
this._isLastOpMousewheel = true;
|
// console.log('mousewheel', op.x, op.y, op.deltaX, op.deltaY);
|
// await this._client.send('Input.dispatchMouseEvent', {
|
// type: 'mouseWheel',
|
// x: op.x,
|
// y: op.y,
|
// deltaX: op.deltaX,
|
// deltaY: op.deltaY
|
// });
|
break;
|
case 'screenshot':
|
await takeScreenshot();
|
takenScreenshot = true;
|
break;
|
case 'valuechange':
|
if (op.target === 'select') {
|
await page.select(op.selector, op.value);
|
}
|
break;
|
}
|
|
this._currentOpIndex++;
|
|
// If next op is an auto screenshot
|
let nextOp = this._ops[this._currentOpIndex];
|
if (nextOp && nextOp.type === 'screenshot-auto') {
|
let delay = nextOp.delay == null ? 400 : nextOp.delay;
|
// TODO Configuration time
|
await waitTime(delay / playbackSpeed);
|
await takeScreenshot();
|
takenScreenshot = true;
|
this._currentOpIndex++;
|
}
|
|
if (this._isLastOpMousewheel && op.type !== 'mousewheel') {
|
// Only take screenshot after mousewheel finished
|
if (!takenScreenshot) {
|
takeScreenshot();
|
}
|
this._isLastOpMousewheel = false;
|
}
|
}
|
};
|