mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat(trace-viewer): show screenshot pointer (#32514)
Follow-up to https://github.com/microsoft/playwright/pull/32248. Adds a glowing red circle that shows the click position. I made it glowing to show that its position is inaccurate. <img width="964" alt="Screenshot 2024-09-09 at 11 33 45" src="https://github.com/user-attachments/assets/1903071d-6dc0-46c7-9951-844e49a51f35">
This commit is contained in:
parent
ae02331d00
commit
31e269ad06
48
packages/trace-viewer/src/ui/clickPointer.tsx
Normal file
48
packages/trace-viewer/src/ui/clickPointer.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function ClickPointer({ point }: { point: { x: number; y: number } }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'fixed',
|
||||||
|
backgroundColor: '#f44336',
|
||||||
|
width: '20px',
|
||||||
|
height: '20px',
|
||||||
|
borderRadius: '10px',
|
||||||
|
margin: '-10px 0 0 -10px',
|
||||||
|
zIndex: 2147483646,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
left: `${point.x}px`,
|
||||||
|
top: `${point.y}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: '19px',
|
||||||
|
color: 'white',
|
||||||
|
marginTop: '-3.5px',
|
||||||
|
userSelect: 'none'
|
||||||
|
}}
|
||||||
|
title='Click positions on screenshots are inaccurate.'
|
||||||
|
>
|
||||||
|
⚠
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -29,6 +29,7 @@ import type { Language } from '@isomorphic/locatorGenerators';
|
|||||||
import { locatorOrSelectorAsSelector } from '@isomorphic/locatorParser';
|
import { locatorOrSelectorAsSelector } from '@isomorphic/locatorParser';
|
||||||
import { TabbedPaneTab } from '@web/components/tabbedPane';
|
import { TabbedPaneTab } from '@web/components/tabbedPane';
|
||||||
import { BrowserFrame } from './browserFrame';
|
import { BrowserFrame } from './browserFrame';
|
||||||
|
import { ClickPointer } from './clickPointer';
|
||||||
|
|
||||||
function findClosest<T extends { timestamp: number }>(items: T[], target: number) {
|
function findClosest<T extends { timestamp: number }>(items: T[], target: number) {
|
||||||
return items.find((item, index) => {
|
return items.find((item, index) => {
|
||||||
@ -73,7 +74,7 @@ export const SnapshotTab: React.FunctionComponent<{
|
|||||||
return { snapshots: { action: actionSnapshot, before: beforeSnapshot, after: afterSnapshot } };
|
return { snapshots: { action: actionSnapshot, before: beforeSnapshot, after: afterSnapshot } };
|
||||||
}, [action]);
|
}, [action]);
|
||||||
|
|
||||||
const { snapshotInfoUrl, snapshotUrl, popoutUrl } = React.useMemo(() => {
|
const { snapshotInfoUrl, snapshotUrl, popoutUrl, point } = React.useMemo(() => {
|
||||||
const snapshot = snapshots[snapshotTab];
|
const snapshot = snapshots[snapshotTab];
|
||||||
if (!snapshot)
|
if (!snapshot)
|
||||||
return { snapshotUrl: kBlankSnapshotUrl };
|
return { snapshotUrl: kBlankSnapshotUrl };
|
||||||
@ -96,7 +97,7 @@ export const SnapshotTab: React.FunctionComponent<{
|
|||||||
popoutParams.set('pointY', String(snapshot.point.y));
|
popoutParams.set('pointY', String(snapshot.point.y));
|
||||||
}
|
}
|
||||||
const popoutUrl = new URL(`snapshot.html?${popoutParams.toString()}`, window.location.href).toString();
|
const popoutUrl = new URL(`snapshot.html?${popoutParams.toString()}`, window.location.href).toString();
|
||||||
return { snapshots, snapshotInfoUrl, snapshotUrl, popoutUrl };
|
return { snapshots, snapshotInfoUrl, snapshotUrl, popoutUrl, point: snapshot.point };
|
||||||
}, [snapshots, snapshotTab]);
|
}, [snapshots, snapshotTab]);
|
||||||
|
|
||||||
const iframeRef0 = React.useRef<HTMLIFrameElement>(null);
|
const iframeRef0 = React.useRef<HTMLIFrameElement>(null);
|
||||||
@ -230,7 +231,12 @@ export const SnapshotTab: React.FunctionComponent<{
|
|||||||
transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})`,
|
transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})`,
|
||||||
}}>
|
}}>
|
||||||
<BrowserFrame url={snapshotInfo.url} />
|
<BrowserFrame url={snapshotInfo.url} />
|
||||||
{(showScreenshotInsteadOfSnapshot && screencastFrame) && <img alt={`Screenshot of ${action?.apiName} > ${renderTitle(snapshotTab)}`} src={`sha1/${screencastFrame.sha1}`} width={screencastFrame.width} height={screencastFrame.height} />}
|
{(showScreenshotInsteadOfSnapshot && screencastFrame) && (
|
||||||
|
<>
|
||||||
|
{point && <ClickPointer point={point} />}
|
||||||
|
<img alt={`Screenshot of ${action?.apiName} > ${renderTitle(snapshotTab)}`} src={`sha1/${screencastFrame.sha1}`} width={screencastFrame.width} height={screencastFrame.height} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className='snapshot-switcher' style={showScreenshotInsteadOfSnapshot ? { display: 'none' } : undefined}>
|
<div className='snapshot-switcher' style={showScreenshotInsteadOfSnapshot ? { display: 'none' } : undefined}>
|
||||||
<iframe ref={iframeRef0} name='snapshot' title='DOM Snapshot' className={clsx(loadingRef.current.visibleIframe === 0 && 'snapshot-visible')}></iframe>
|
<iframe ref={iframeRef0} name='snapshot' title='DOM Snapshot' className={clsx(loadingRef.current.visibleIframe === 0 && 'snapshot-visible')}></iframe>
|
||||||
<iframe ref={iframeRef1} name='snapshot' title='DOM Snapshot' className={clsx(loadingRef.current.visibleIframe === 1 && 'snapshot-visible')}></iframe>
|
<iframe ref={iframeRef1} name='snapshot' title='DOM Snapshot' className={clsx(loadingRef.current.visibleIframe === 1 && 'snapshot-visible')}></iframe>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user