| /* | |
| * 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 seedrandom from 'seedrandom'; | |
| import { ActionPlayback } from './ActionPlayback'; | |
| import * as timeline from './timeline'; | |
| let myRandom = new seedrandom('echarts-random'); | |
| // Random for echarts code. | |
| // In case different echarts version called random different times. | |
| // It will cause following random number all wrong. | |
| let myRandom2 = new seedrandom('echarts-random-inner'); | |
| // Fixed random generator | |
| Math.random = function () { | |
| const val = myRandom(); | |
| return val; | |
| }; | |
| window.__random__inner__ = function () { | |
| const val = myRandom2(); | |
| return val; | |
| }; | |
| let vstStarted = false; | |
| window.__VRT_START__ = function () { | |
| if (vstStarted) { | |
| return; | |
| } | |
| vstStarted = true; | |
| timeline.start(); | |
| // TODO not support reload without simpleRequire | |
| if (window.__VRT_RUN_CONTEXT__) { | |
| // Restore from previous run | |
| setTimeout(async () => { | |
| await __VRT_RUN_ACTIONS__( | |
| window.__VRT_RUN_CONTEXT__.actions, | |
| window.__VRT_RUN_CONTEXT__.currentActionIndex, | |
| window.__VRT_RUN_CONTEXT__.currentActionContext | |
| ) | |
| }, 1000); | |
| } | |
| else { | |
| // Screenshot after 1000ms (200ms if 5x speed), wait the animation to be finished | |
| setTimeout(async () => { | |
| // Pause timeline until run actions. | |
| timeline.pause(); | |
| await __VRT_FULL_SCREENSHOT__(); | |
| }, 1000); | |
| } | |
| } | |
| function saveRunningContext(actions, actionIndex, playback) { | |
| localStorage.setItem('vstRunContext', JSON.stringify({ | |
| actions: actions, | |
| currentActionIndex: actionIndex, | |
| currentActionContext: playback.getContext() | |
| })); | |
| } | |
| window.__VRT_RUN_ACTIONS__ = async function (actions, restoredActionIndex, restoredActionContext) { | |
| // Actions can only bu runned once. | |
| timeline.resume(); | |
| const actionPlayback = new ActionPlayback(); | |
| const nativeLocation = window.location; | |
| let currentActionIndex = 0; | |
| // Some test cases change the params through reload(). | |
| // We need to save the running info and keep running after reload. | |
| // window.location seems can't be redefined anymore. So we can only provide helper functions. | |
| window.__VRT_RELOAD__ = function () { | |
| // Mark reload triggered and let ActionPlayback stop. | |
| window.__VRT_RELOAD_TRIGGERED__ = true; | |
| saveRunningContext(actions, currentActionIndex, actionPlayback); | |
| timeline.nativeSetTimeout(() => { | |
| // CDPSession pay be disconnected if reload immediately. | |
| nativeLocation.reload(); | |
| }, 100); | |
| } | |
| for (const [index, action] of actions.entries()) { | |
| currentActionIndex = index; | |
| if (index < restoredActionIndex) { | |
| continue; | |
| } | |
| window.scrollTo(action.scrollX, action.scrollY); | |
| await actionPlayback.runAction(action, index === restoredActionIndex ? restoredActionContext : null); | |
| } | |
| actionPlayback.stop(); | |
| __VRT_FINISH_ACTIONS__(); | |
| } | |
| window.addEventListener('DOMContentLoaded', () => { | |
| let style = document.createElement('style'); | |
| // Disable all css animation since it will cause screenshot inconsistent. | |
| // PENDING Only tooltip? div[_echarts_instance_]>div | |
| style.innerHTML = ` | |
| * { | |
| transition-delay: 0s !important; | |
| transition-duration: 0s !important; | |
| animation-delay: -0.0001s !important; | |
| animation-duration: 0s !important; | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| // Prevent triggered mouseout event when mouse move out of window. | |
| // DON"T know why, but it happens occasionally and cause hover state/ tooltip wrong before screenshot. | |
| document.body.addEventListener('mouseout', e => { | |
| if (!e.relatedTarget) { | |
| e.stopPropagation(); | |
| e.stopImmediatePropagation(); | |
| } | |
| }, true); | |
| // Draw mouse | |
| const box = document.createElement('puppeteer-mouse-pointer'); | |
| const styleElement = document.createElement('style'); | |
| styleElement.innerHTML = ` | |
| puppeteer-mouse-pointer { | |
| pointer-events: none; | |
| position: absolute; | |
| top: 0; | |
| z-index: 10000; | |
| left: 0; | |
| width: 20px; | |
| height: 20px; | |
| background: rgba(0,0,0,.4); | |
| border: 1px solid white; | |
| border-radius: 10px; | |
| margin: -10px 0 0 -10px; | |
| padding: 0; | |
| transition: background .2s, border-radius .2s, border-color .2s; | |
| } | |
| puppeteer-mouse-pointer.button-1 { | |
| transition: none; | |
| background: rgba(0,0,0,0.9); | |
| } | |
| puppeteer-mouse-pointer.button-2 { | |
| transition: none; | |
| border-color: rgba(0,0,255,0.9); | |
| } | |
| puppeteer-mouse-pointer.button-3 { | |
| transition: none; | |
| border-radius: 4px; | |
| } | |
| puppeteer-mouse-pointer.button-4 { | |
| transition: none; | |
| border-color: rgba(255,0,0,0.9); | |
| } | |
| puppeteer-mouse-pointer.button-5 { | |
| transition: none; | |
| border-color: rgba(0,255,0,0.9); | |
| } | |
| `; | |
| document.head.appendChild(styleElement); | |
| document.body.appendChild(box); | |
| document.addEventListener('mousemove', event => { | |
| box.style.left = event.pageX + 'px'; | |
| box.style.top = event.pageY + 'px'; | |
| updateButtons(event.buttons); | |
| }, true); | |
| document.addEventListener('mousedown', event => { | |
| updateButtons(event.buttons); | |
| box.classList.add('button-' + event.which); | |
| }, true); | |
| document.addEventListener('mouseup', event => { | |
| updateButtons(event.buttons); | |
| box.classList.remove('button-' + event.which); | |
| }, true); | |
| function updateButtons(buttons) { | |
| for (let i = 0; i < 5; i++) { | |
| box.classList.toggle('button-' + i, buttons & (1 << i)); | |
| } | |
| } | |
| }); |