diff --git a/js/canvas-utils.mjs b/js/canvas-utils.mjs index 978a572..24dc175 100644 --- a/js/canvas-utils.mjs +++ b/js/canvas-utils.mjs @@ -1,33 +1,82 @@ import { COLOR } from "./state/constants.mjs"; -import { getCursorCanvas } from "./dom.mjs"; +import { getCursorCanvas, getCanvas } from "./dom.mjs"; +import { getPanel } from "./dom.mjs"; +import { isCursorWithinPanelBounds } from "./ui-utils.mjs"; const ctx = getCursorCanvas().getContext("2d"); -const CURSOR_SIZE = 20; +const canvasCtx = getCanvas().getContext("2d"); +const CURSOR_SIZE = 10; +const CURSOR_PART_SIZE = CURSOR_SIZE / 2; +const GAP = CURSOR_SIZE / 2; +const LINE_WIDTH = 5; + +/** + * Inverts color to avoid invisible cursor. + * + * @param {number} r - Red color. + * @param {number} g - Green color. + * @param {number} b - Blue color. + * + * @returns {number[]} - Inverted color in r, g,b order. + */ +function invertColor(r, g, b, a) { + const rgb = [r, g, b, a]; + for (var i = 0; i < rgb.length; i++) rgb[i] = (i === 3 ? 1 : 255) - rgb[i]; + return rgb; +} + +/** + * Returns color on given canvas area in RGBA format. + * + * @param {number} x - X coordinate. + * @param {number} y - Y coordinate. + * + * @returns {string} - RGBA color. + */ +function getPixelRGBAColor(x, y) { + const panel = getPanel(); + const rect = panel.getBoundingClientRect(); + + if (isCursorWithinPanelBounds(x, y, rect)) { + return COLOR.BLACK; + } + + const pixel = canvasCtx.getImageData(x, y, GAP, GAP); + const [r, g, b, a] = invertColor(...pixel.data); + + return `rgb(${r}, ${g}, ${b}, ${Math.abs(a)})`; +} export function drawCursor(x, y) { ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); - const half = CURSOR_SIZE / 2; - - ctx.lineWidth = 5; + ctx.lineWidth = LINE_WIDTH; ctx.lineCap = "round"; - ctx.strokeStyle = COLOR.BLACK; + ctx.strokeStyle = getPixelRGBAColor(x, y); + /* --- Cursor --- */ + // Draw top line ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(x + CURSOR_SIZE, y); + ctx.moveTo(x, y - GAP); + ctx.lineTo(x, y - CURSOR_PART_SIZE - GAP - CURSOR_SIZE); ctx.stroke(); + // Draw bottom line ctx.beginPath(); - ctx.moveTo(x + half, y - half); - ctx.lineTo(x + half, y + half); + ctx.moveTo(x, y + GAP); + ctx.lineTo(x, y + CURSOR_PART_SIZE + GAP + CURSOR_SIZE); ctx.stroke(); - ctx.closePath(); + // Draw left line + ctx.beginPath(); + ctx.moveTo(x - GAP, y); + ctx.lineTo(x - CURSOR_PART_SIZE - GAP - CURSOR_SIZE, y); + ctx.stroke(); - ctx.moveTo(x + half, y + half); - ctx.strokeStyle = COLOR.WHITE; - ctx.fillStyle = COLOR.WHITE; + // Draw right line ctx.beginPath(); - ctx.arc(x + half, y, 3, 0, Math.PI * 2); - ctx.fill(); + ctx.moveTo(x + GAP, y); + ctx.lineTo(x + CURSOR_PART_SIZE + GAP + CURSOR_SIZE, y); + ctx.stroke(); + + ctx.closePath(); } diff --git a/js/ui-utils.mjs b/js/ui-utils.mjs new file mode 100644 index 0000000..f4b5b99 --- /dev/null +++ b/js/ui-utils.mjs @@ -0,0 +1,12 @@ +/** + * Is cursor located on UI panel? + * + * @param {number} x - Cursor x coordinate. + * @param {number} y - Cursor y coordinate. + * @param {DOMRect} rect - Panel bounds. + * + * @returns {boolean} - Is cursor located on UI panel? + */ +export function isCursorWithinPanelBounds(x, y, rect) { + return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom; +} diff --git a/js/ui/panel.mjs b/js/ui/panel.mjs index 521bbe9..2ad51ca 100644 --- a/js/ui/panel.mjs +++ b/js/ui/panel.mjs @@ -3,10 +3,7 @@ import { isPrimaryGamepadButtonPressed, } from "../controls/gamepad.mjs"; import { getPanel } from "../dom.mjs"; - -function isCursorWithinPanelBounds(x, y, rect) { - return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom; -} +import { isCursorWithinPanelBounds } from "../ui-utils.mjs"; function getPanelButtonByCoordinates(x, y, panel) { const buttons = panel.querySelectorAll("button"); diff --git a/package-lock.json b/package-lock.json index 2e7180b..935b4c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sdraw", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sdraw", - "version": "0.1.2", + "version": "0.1.3", "license": "MIT", "devDependencies": { "eslint": "^8.52.0", diff --git a/package.json b/package.json index d351db6..a2eef95 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sdraw", - "version": "0.1.2", + "version": "0.1.3", "description": "Simple drawing application for kids, can be controlled via mouse, keyboard or gamepad.", "private": true, "main": "index.mjs",