UNPKG

@dartbot/dartboard

Version:

Dartboard implemented as a vanilla web component

185 lines 8.03 kB
var _Dartboard_canvas, _Dartboard_hits, _Dartboard_zoom, _Dartboard_fit, _Dartboard_centerPoint, _Dartboard_shadow, _Dartboard_board; import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib"; import { createTheme, Token } from './theme'; import { translateCoords, debounce, getPolar } from './utils'; import { createBoard, getRingIndexFromPoint, getSectorIndexFromPoint, } from './draw-board/board'; import { render } from './draw-board/render'; const RESIZE_DEBOUNCE_MS = 100; const DEFAULT_ZOOM = 0; export class Dartboard extends HTMLElement { get board() { return __classPrivateFieldGet(this, _Dartboard_board, "f"); } set board(value) { __classPrivateFieldSet(this, _Dartboard_board, value, "f"); this.render(); } get zoom() { return __classPrivateFieldGet(this, _Dartboard_zoom, "f"); } set zoom(value) { __classPrivateFieldSet(this, _Dartboard_zoom, value, "f"); this.render(); } get centerPoint() { return __classPrivateFieldGet(this, _Dartboard_centerPoint, "f"); } set centerPoint(value) { __classPrivateFieldSet(this, _Dartboard_centerPoint, value, "f"); this.render(); } get hits() { return __classPrivateFieldGet(this, _Dartboard_hits, "f"); } set hits(value) { __classPrivateFieldSet(this, _Dartboard_hits, value, "f"); this.render(); } get fit() { return __classPrivateFieldGet(this, _Dartboard_fit, "f"); } set fit(value) { __classPrivateFieldSet(this, _Dartboard_fit, value, "f"); this.render(); } static get observedAttributes() { return ['zoom', 'center-angle', 'center-radius', 'fit']; } constructor() { super(); _Dartboard_canvas.set(this, void 0); _Dartboard_hits.set(this, []); _Dartboard_zoom.set(this, DEFAULT_ZOOM); _Dartboard_fit.set(this, 'contain'); _Dartboard_centerPoint.set(this, { radius: 0, angle: 0 }); _Dartboard_shadow.set(this, void 0); _Dartboard_board.set(this, void 0); __classPrivateFieldSet(this, _Dartboard_board, createBoard(), "f"); __classPrivateFieldSet(this, _Dartboard_shadow, this.attachShadow({ mode: 'open' }), "f"); __classPrivateFieldGet(this, _Dartboard_shadow, "f").innerHTML = ` <style> :host { display: flex; width: 100%; aspect-ratio: 1 / 1; box-sizing: border-box; user-select: none; } canvas { width: 100%; height: 100%; background-color: var(${Token.canvasBg}, transparent); } </style> <canvas></canvas> `; __classPrivateFieldSet(this, _Dartboard_canvas, __classPrivateFieldGet(this, _Dartboard_shadow, "f").querySelector('canvas'), "f"); __classPrivateFieldGet(this, _Dartboard_canvas, "f").addEventListener('click', this); const resizeObserver = new ResizeObserver(debounce((entries) => { const entry = entries.find(e => e.target === this); const box = entry.devicePixelContentBoxSize?.[0]; const boxC = entry.contentBoxSize[0]; const physical = (n) => Math.round(n * devicePixelRatio); __classPrivateFieldGet(this, _Dartboard_canvas, "f").width = box?.inlineSize ?? physical(boxC.inlineSize); __classPrivateFieldGet(this, _Dartboard_canvas, "f").height = box?.blockSize ?? physical(boxC.blockSize); this.render(); }, RESIZE_DEBOUNCE_MS, { leading: true, trailing: true })); resizeObserver.observe(this, { box: 'content-box' }); } attributeChangedCallback(name, oldValue, newValue) { if (oldValue === newValue) { return; } if (name === 'zoom') { this.zoom = parseFloat(newValue); } else if (name === 'center-angle') { const angle = parseFloat(newValue); const { radius } = __classPrivateFieldGet(this, _Dartboard_centerPoint, "f"); this.centerPoint = { radius, angle }; } else if (name === 'center-radius') { const radius = parseFloat(newValue); const { angle } = __classPrivateFieldGet(this, _Dartboard_centerPoint, "f"); this.centerPoint = { radius, angle }; } else if (name === 'fit') { this.fit = newValue; } } handleEvent(event) { switch (event.type) { case 'click': case 'pointerdown': case 'pointerup': { const { offsetX, offsetY } = event; const { point, polar, sector, ring } = this.translatePoint(offsetX, offsetY); const name = `dartboard-${event.type}`; const detail = { event, point, polar, sector, ring }; const e = new CustomEvent(name, { detail, bubbles: true, cancelable: true, }); this.dispatchEvent(e); break; } default: break; } } render() { const ctx = __classPrivateFieldGet(this, _Dartboard_canvas, "f").getContext('2d'); if (ctx == null) { return; } const zoom = __classPrivateFieldGet(this, _Dartboard_zoom, "f"); const center = __classPrivateFieldGet(this, _Dartboard_centerPoint, "f"); const fit = __classPrivateFieldGet(this, _Dartboard_fit, "f"); const style = getComputedStyle(this); const theme = createTheme(style); render(__classPrivateFieldGet(this, _Dartboard_board, "f"), zoom, center, fit, __classPrivateFieldGet(this, _Dartboard_hits, "f"), theme, ctx); } /** * Translates a point from the coordinate system of the canvas. * The point is adjusted so that 0,0 is the center of the board with * the y-axis pointing up. The units are translated from pixels to * millimeters relative to the board radius. * @param x - X coordinate in canvas space * @param y - Y coordinate in canvas space */ translatePoint(x, y) { const { offsetWidth: w, offsetHeight: h } = __classPrivateFieldGet(this, _Dartboard_canvas, "f"); const { radius } = __classPrivateFieldGet(this, _Dartboard_board, "f"); const zoom = __classPrivateFieldGet(this, _Dartboard_zoom, "f"); const center = __classPrivateFieldGet(this, _Dartboard_centerPoint, "f"); const fit = __classPrivateFieldGet(this, _Dartboard_fit, "f"); const point = translateCoords(w, h, zoom, center, radius, fit, x, y); const polar = getPolar(point.x, point.y); const sector = getSectorIndexFromPoint(__classPrivateFieldGet(this, _Dartboard_board, "f"), polar); const ring = getRingIndexFromPoint(__classPrivateFieldGet(this, _Dartboard_board, "f"), polar); return { point, polar, sector, ring }; } /** * Return the image data encoded as a data URL. * @param type The image format. Default is `image/png`. * @param quality The image quality. Default is `1.0`. */ toDataURL(type, quality) { return __classPrivateFieldGet(this, _Dartboard_canvas, "f").toDataURL(type, quality); } /** * Return the image data as a Blob. * @param type The image format. Default is `image/png`. * @param quality The image quality. Default is `1.0`. */ toBlob(type, quality) { return new Promise(resolve => { __classPrivateFieldGet(this, _Dartboard_canvas, "f").toBlob(blob => { resolve(blob); }, type, quality); }); } } _Dartboard_canvas = new WeakMap(), _Dartboard_hits = new WeakMap(), _Dartboard_zoom = new WeakMap(), _Dartboard_fit = new WeakMap(), _Dartboard_centerPoint = new WeakMap(), _Dartboard_shadow = new WeakMap(), _Dartboard_board = new WeakMap(); //# sourceMappingURL=Dartboard.js.map