Skip to content

Commit d9152f3

Browse files
authored
Merge pull request #5 from comatory/comatory/fix-cursor-offset
Fix cursor offset
2 parents f8d12f4 + 8e5b1c6 commit d9152f3

File tree

5 files changed

+81
-23
lines changed

5 files changed

+81
-23
lines changed

js/canvas-utils.mjs

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,82 @@
11
import { COLOR } from "./state/constants.mjs";
2-
import { getCursorCanvas } from "./dom.mjs";
2+
import { getCursorCanvas, getCanvas } from "./dom.mjs";
3+
import { getPanel } from "./dom.mjs";
4+
import { isCursorWithinPanelBounds } from "./ui-utils.mjs";
35

46
const ctx = getCursorCanvas().getContext("2d");
5-
const CURSOR_SIZE = 20;
7+
const canvasCtx = getCanvas().getContext("2d");
8+
const CURSOR_SIZE = 10;
9+
const CURSOR_PART_SIZE = CURSOR_SIZE / 2;
10+
const GAP = CURSOR_SIZE / 2;
11+
const LINE_WIDTH = 5;
12+
13+
/**
14+
* Inverts color to avoid invisible cursor.
15+
*
16+
* @param {number} r - Red color.
17+
* @param {number} g - Green color.
18+
* @param {number} b - Blue color.
19+
*
20+
* @returns {number[]} - Inverted color in r, g,b order.
21+
*/
22+
function invertColor(r, g, b, a) {
23+
const rgb = [r, g, b, a];
24+
for (var i = 0; i < rgb.length; i++) rgb[i] = (i === 3 ? 1 : 255) - rgb[i];
25+
return rgb;
26+
}
27+
28+
/**
29+
* Returns color on given canvas area in RGBA format.
30+
*
31+
* @param {number} x - X coordinate.
32+
* @param {number} y - Y coordinate.
33+
*
34+
* @returns {string} - RGBA color.
35+
*/
36+
function getPixelRGBAColor(x, y) {
37+
const panel = getPanel();
38+
const rect = panel.getBoundingClientRect();
39+
40+
if (isCursorWithinPanelBounds(x, y, rect)) {
41+
return COLOR.BLACK;
42+
}
43+
44+
const pixel = canvasCtx.getImageData(x, y, GAP, GAP);
45+
const [r, g, b, a] = invertColor(...pixel.data);
46+
47+
return `rgb(${r}, ${g}, ${b}, ${Math.abs(a)})`;
48+
}
649

750
export function drawCursor(x, y) {
851
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
9-
const half = CURSOR_SIZE / 2;
10-
11-
ctx.lineWidth = 5;
52+
ctx.lineWidth = LINE_WIDTH;
1253
ctx.lineCap = "round";
13-
ctx.strokeStyle = COLOR.BLACK;
54+
ctx.strokeStyle = getPixelRGBAColor(x, y);
1455

56+
/* --- Cursor --- */
57+
// Draw top line
1558
ctx.beginPath();
16-
ctx.moveTo(x, y);
17-
ctx.lineTo(x + CURSOR_SIZE, y);
59+
ctx.moveTo(x, y - GAP);
60+
ctx.lineTo(x, y - CURSOR_PART_SIZE - GAP - CURSOR_SIZE);
1861
ctx.stroke();
1962

63+
// Draw bottom line
2064
ctx.beginPath();
21-
ctx.moveTo(x + half, y - half);
22-
ctx.lineTo(x + half, y + half);
65+
ctx.moveTo(x, y + GAP);
66+
ctx.lineTo(x, y + CURSOR_PART_SIZE + GAP + CURSOR_SIZE);
2367
ctx.stroke();
2468

25-
ctx.closePath();
69+
// Draw left line
70+
ctx.beginPath();
71+
ctx.moveTo(x - GAP, y);
72+
ctx.lineTo(x - CURSOR_PART_SIZE - GAP - CURSOR_SIZE, y);
73+
ctx.stroke();
2674

27-
ctx.moveTo(x + half, y + half);
28-
ctx.strokeStyle = COLOR.WHITE;
29-
ctx.fillStyle = COLOR.WHITE;
75+
// Draw right line
3076
ctx.beginPath();
31-
ctx.arc(x + half, y, 3, 0, Math.PI * 2);
32-
ctx.fill();
77+
ctx.moveTo(x + GAP, y);
78+
ctx.lineTo(x + CURSOR_PART_SIZE + GAP + CURSOR_SIZE, y);
79+
ctx.stroke();
80+
81+
ctx.closePath();
3382
}

js/ui-utils.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Is cursor located on UI panel?
3+
*
4+
* @param {number} x - Cursor x coordinate.
5+
* @param {number} y - Cursor y coordinate.
6+
* @param {DOMRect} rect - Panel bounds.
7+
*
8+
* @returns {boolean} - Is cursor located on UI panel?
9+
*/
10+
export function isCursorWithinPanelBounds(x, y, rect) {
11+
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
12+
}

js/ui/panel.mjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ import {
33
isPrimaryGamepadButtonPressed,
44
} from "../controls/gamepad.mjs";
55
import { getPanel } from "../dom.mjs";
6-
7-
function isCursorWithinPanelBounds(x, y, rect) {
8-
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
9-
}
6+
import { isCursorWithinPanelBounds } from "../ui-utils.mjs";
107

118
function getPanelButtonByCoordinates(x, y, panel) {
129
const buttons = panel.querySelectorAll("button");

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sdraw",
3-
"version": "0.1.2",
3+
"version": "0.1.3",
44
"description": "Simple drawing application for kids, can be controlled via mouse, keyboard or gamepad.",
55
"private": true,
66
"main": "index.mjs",

0 commit comments

Comments
 (0)