1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | import type {ResetData} from './common.js';
|
32 | import {Overlay} from './common.js';
|
33 | import type {Delegate} from './drag_resize_handler.js';
|
34 | import {DragResizeHandler, ResizerType} from './drag_resize_handler.js';
|
35 | import type {ContainerQueryHighlight} from './highlight_container_query.js';
|
36 | import {drawContainerQueryHighlight} from './highlight_container_query.js';
|
37 | import type {FlexContainerHighlight} from './highlight_flex_common.js';
|
38 | import {drawLayoutFlexContainerHighlight} from './highlight_flex_common.js';
|
39 | import type {GridHighlight} from './highlight_grid_common.js';
|
40 | import {drawLayoutGridHighlight} from './highlight_grid_common.js';
|
41 | import type {IsolatedElementHighlight} from './highlight_isolated_element.js';
|
42 | import {drawIsolatedElementHighlight} from './highlight_isolated_element.js';
|
43 | import type {ScrollSnapHighlight} from './highlight_scroll_snap.js';
|
44 | import {drawScrollSnapHighlight} from './highlight_scroll_snap.js';
|
45 |
|
46 | export type PersistentToolMessage = {
|
47 | highlightType: string,
|
48 | highlightIndex: number,
|
49 | newWidth: string,
|
50 | newHeight: string,
|
51 | resizerType: ResizerType,
|
52 | };
|
53 |
|
54 | interface DraggableMetadata {
|
55 | type: ResizerType;
|
56 | highlightIndex: number;
|
57 | initialWidth?: number;
|
58 | initialHeight?: number;
|
59 | }
|
60 |
|
61 | function makeDraggableDelegate(overlay: PersistentOverlay): Delegate {
|
62 | return {
|
63 | getDraggable: (x, y) => {
|
64 | const result = overlay.isPointInDraggablePath(x, y);
|
65 | if (!result) {
|
66 | return;
|
67 | }
|
68 |
|
69 | return {
|
70 | type: result.type,
|
71 | initialWidth: result.initialWidth,
|
72 | initialHeight: result.initialHeight,
|
73 | id: result.highlightIndex,
|
74 | update: ({width, height}: {width?: number, height?: number}) => {
|
75 | window.InspectorOverlayHost.send({
|
76 | highlightType: 'isolatedElement',
|
77 | highlightIndex: result.highlightIndex,
|
78 | newWidth: `${width}px`,
|
79 | newHeight: `${height}px`,
|
80 | resizerType: result.type,
|
81 | });
|
82 | },
|
83 | };
|
84 | },
|
85 | };
|
86 | }
|
87 |
|
88 | export class PersistentOverlay extends Overlay {
|
89 | private gridLabelState = {gridLayerCounter: 0};
|
90 |
|
91 | private gridLabels!: HTMLElement;
|
92 | private draggableBorders: Map<number, {
|
93 | widthPath: Path2D,
|
94 | heightPath: Path2D,
|
95 | bidirectionPath: Path2D,
|
96 | highlightIndex: number,
|
97 | initialWidth: number,
|
98 | initialHeight: number,
|
99 | }> = new Map();
|
100 | private dragHandler?: DragResizeHandler;
|
101 |
|
102 | reset(data: ResetData) {
|
103 | super.reset(data);
|
104 | this.gridLabelState.gridLayerCounter = 0;
|
105 | this.gridLabels.innerHTML = '';
|
106 | }
|
107 |
|
108 | renderGridMarkup() {
|
109 | const gridLabels = this.document.createElement('div');
|
110 | gridLabels.id = 'grid-label-container';
|
111 | this.document.body.append(gridLabels);
|
112 | this.gridLabels = gridLabels;
|
113 | }
|
114 |
|
115 | install() {
|
116 | this.document.body.classList.add('fill');
|
117 |
|
118 | const canvas = this.document.createElement('canvas');
|
119 | canvas.id = 'canvas';
|
120 | canvas.classList.add('fill');
|
121 | this.document.body.append(canvas);
|
122 |
|
123 | this.renderGridMarkup();
|
124 |
|
125 | this.setCanvas(canvas);
|
126 |
|
127 | super.install();
|
128 | this.dragHandler?.install();
|
129 | }
|
130 |
|
131 | uninstall() {
|
132 | this.document.body.classList.remove('fill');
|
133 | this.document.body.innerHTML = '';
|
134 | this.draggableBorders = new Map();
|
135 | super.uninstall();
|
136 | this.dragHandler?.uninstall();
|
137 | }
|
138 |
|
139 | drawGridHighlight(highlight: GridHighlight) {
|
140 | this.context.save();
|
141 | drawLayoutGridHighlight(
|
142 | highlight, this.context, this.deviceScaleFactor, this.canvasWidth, this.canvasHeight, this.emulationScaleFactor,
|
143 | this.gridLabelState);
|
144 | this.context.restore();
|
145 | }
|
146 |
|
147 | drawFlexContainerHighlight(highlight: FlexContainerHighlight) {
|
148 | this.context.save();
|
149 | drawLayoutFlexContainerHighlight(
|
150 | highlight, this.context, this.deviceScaleFactor, this.canvasWidth, this.canvasHeight,
|
151 | this.emulationScaleFactor);
|
152 | this.context.restore();
|
153 | }
|
154 |
|
155 | drawScrollSnapHighlight(highlight: ScrollSnapHighlight) {
|
156 | this.context.save();
|
157 | drawScrollSnapHighlight(highlight, this.context, this.emulationScaleFactor);
|
158 | this.context.restore();
|
159 | }
|
160 |
|
161 | drawContainerQueryHighlight(highlight: ContainerQueryHighlight) {
|
162 | this.context.save();
|
163 | drawContainerQueryHighlight(highlight, this.context, this.emulationScaleFactor);
|
164 | this.context.restore();
|
165 | }
|
166 |
|
167 | drawIsolatedElementHighlight(highlight: IsolatedElementHighlight) {
|
168 | if (!this.dragHandler) {
|
169 | this.dragHandler = new DragResizeHandler(this.document, makeDraggableDelegate(this));
|
170 | this.dragHandler.install();
|
171 | }
|
172 |
|
173 | this.context.save();
|
174 | const {widthPath, heightPath, bidirectionPath, currentWidth, currentHeight, highlightIndex} =
|
175 | drawIsolatedElementHighlight(
|
176 | highlight, this.context, this.canvasWidth, this.canvasHeight, this.emulationScaleFactor);
|
177 |
|
178 | this.draggableBorders.set(highlightIndex, {
|
179 | widthPath,
|
180 | heightPath,
|
181 | bidirectionPath,
|
182 | highlightIndex,
|
183 | initialWidth: currentWidth,
|
184 | initialHeight: currentHeight,
|
185 | });
|
186 | this.context.restore();
|
187 | }
|
188 |
|
189 | isPointInDraggablePath(x: number, y: number): DraggableMetadata|undefined {
|
190 | for (const {widthPath, heightPath, bidirectionPath, highlightIndex, initialWidth, initialHeight} of this
|
191 | .draggableBorders.values()) {
|
192 | if (this.context.isPointInPath(widthPath, x, y)) {
|
193 | return {
|
194 | type: ResizerType.WIDTH,
|
195 | highlightIndex,
|
196 | initialWidth,
|
197 | };
|
198 | }
|
199 | if (this.context.isPointInPath(heightPath, x, y)) {
|
200 | return {
|
201 | type: ResizerType.HEIGHT,
|
202 | highlightIndex,
|
203 | initialHeight,
|
204 | };
|
205 | }
|
206 | if (this.context.isPointInPath(bidirectionPath, x, y)) {
|
207 | return {
|
208 | type: ResizerType.BIDIRECTION,
|
209 | highlightIndex,
|
210 | initialWidth,
|
211 | initialHeight,
|
212 | };
|
213 | }
|
214 | }
|
215 |
|
216 | return;
|
217 | }
|
218 | }
|