go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/generic_libs/components/drag_tracker.ts (about) 1 // Copyright 2021 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import { html, LitElement } from 'lit'; 16 import { customElement } from 'lit/decorators.js'; 17 18 export interface DragEventDetails { 19 // relative to the start. 20 dx: number; 21 dy: number; 22 } 23 24 export type DragEvent = CustomEvent<DragEventDetails>; 25 26 /** 27 * A element that tracks the dragging event. 28 * Comparing to the native HTML drag event, this has higher resolution, and 29 * fires dragend event consistently when dragging stopped. 30 */ 31 @customElement('milo-drag-tracker') 32 export class DragTrackerElement extends LitElement { 33 constructor() { 34 super(); 35 36 this.addEventListener('mousedown', (startEvent: MouseEvent) => { 37 const x = startEvent.pageX; 38 const y = startEvent.pageY; 39 40 const dispatchEvent = (e: MouseEvent, type: string) => { 41 const dx = e.pageX - x; 42 const dy = e.pageY - y; 43 this.dispatchEvent( 44 new CustomEvent<DragEventDetails>(type, { detail: { dx, dy } }), 45 ); 46 }; 47 48 const onMouseMove = (dragEvent: MouseEvent) => { 49 dragEvent.preventDefault(); 50 dispatchEvent(dragEvent, 'drag'); 51 }; 52 document.addEventListener('mousemove', onMouseMove); 53 54 document.addEventListener( 55 'mouseup', 56 (endEvent: MouseEvent) => { 57 dispatchEvent(endEvent, 'dragend'); 58 document.removeEventListener('mousemove', onMouseMove); 59 }, 60 { once: true }, 61 ); 62 63 dispatchEvent(startEvent, 'dragstart'); 64 }); 65 } 66 67 protected render() { 68 return html``; 69 } 70 }