Skip to content

Commit 5724bba

Browse files
committed
fix brush cursor visibility
1 parent 3b81651 commit 5724bba

File tree

4 files changed

+65
-72
lines changed

4 files changed

+65
-72
lines changed

html/index.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ <h3>墨水屏日历</h3>
2222
</div>
2323
<div class="flex-group right debug">
2424
<label for="epddriver">驱动</label>
25-
<select id="epddriver">
25+
<select id="epddriver" onchange="updateDitcherOptions()">
2626
<option value="01" data-color="blackWhiteColor" data-size="4.2_400_300">4.2寸 (黑白, UC8176)</option>
2727
<option value="03" data-color="threeColor" data-size="4.2_400_300">4.2寸 (三色, UC8176)</option>
2828
<option value="04" data-color="blackWhiteColor" data-size="4.2_400_300">4.2寸 (黑白, SSD1619)</option>
@@ -62,12 +62,12 @@ <h3>墨水屏日历</h3>
6262
<fieldset>
6363
<legend>蓝牙传图</legend>
6464
<div class="flex-container">
65-
<input type="file" id="imageFile" accept=".png,.jpg,.bmp,.webp,.jpeg">
65+
<input type="file" id="imageFile" accept=".png,.jpg,.bmp,.webp,.jpeg" onchange="updateImage()">
6666
</div>
6767
<div class="flex-container options">
6868
<div class="flex-group debug">
6969
<label for="canvasSize">画布尺寸:</label>
70-
<select id="canvasSize">
70+
<select id="canvasSize" onchange="updateCanvasSize()">
7171
<option value="1.54_152_152">1.54 (152x152)</option>
7272
<option value="1.54_200_200">1.54 (200x200)</option>
7373
<option value="2.13_212_104">2.13 (212x104)</option>
@@ -94,7 +94,7 @@ <h3>墨水屏日历</h3>
9494
</div>
9595
<div class="flex-group debug">
9696
<label for="ditherMode">颜色模式:</label>
97-
<select id="ditherMode">
97+
<select id="ditherMode" onchange="applyDither()">
9898
<option value="blackWhiteColor">双色(黑白)</option>
9999
<option value="threeColor">三色(黑白红)</option>
100100
<option value="fourColor">四色(黑白红黄)</option>
@@ -103,7 +103,7 @@ <h3>墨水屏日历</h3>
103103
</div>
104104
<div class="flex-group">
105105
<label for="ditherAlg">抖动算法:</label>
106-
<select id="ditherAlg">
106+
<select id="ditherAlg" onchange="applyDither()">
107107
<option value="floydSteinberg">Floyd-Steinberg</option>
108108
<option value="atkinson">Atkinson</option>
109109
<option value="bayer">Bayer</option>
@@ -217,7 +217,7 @@ <h3>墨水屏日历</h3>
217217
<button id="crop-move-up" title="上移"></button>
218218
<button id="crop-move-down" title="下移"></button>
219219
<button id="crop-move-right" title="右移"></button>
220-
<button class="primary" onclick="cropManager.finishCrop()">完成</button>
220+
<button class="primary" onclick="applyDither()">完成</button>
221221
</div>
222222
</div>
223223
</div>

html/js/crop.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
class CropManager {
2-
constructor(canvas, ctx, paintManager) {
2+
constructor(canvas, ctx) {
33
this.canvas = canvas;
44
this.ctx = ctx;
5-
this.paintManager = paintManager;
65
this.backgroundZoom = 1;
76
this.backgroundPanX = 0;
87
this.backgroundPanY = 0;
@@ -84,7 +83,7 @@ class CropManager {
8483
this.canvas.parentNode.classList.add('crop-mode');
8584
}
8685

87-
finishCrop() {
86+
finishCrop(callback) {
8887
const imageFile = document.getElementById('imageFile');
8988
if (imageFile.files.length == 0) return;
9089

@@ -103,12 +102,8 @@ class CropManager {
103102
fillCanvas('white');
104103
this.ctx.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, this.canvas.width, this.canvas.height);
105104

106-
this.paintManager.redrawTextElements();
107-
this.paintManager.redrawLineSegments();
108-
convertDithering();
109-
110105
this.exitCropMode();
111-
this.paintManager.saveToHistory(); // Save after finishing crop
106+
if (callback) callback();
112107
};
113108
image.src = URL.createObjectURL(imageFile.files[0]);
114109
}

html/js/main.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,7 @@ function updateImage() {
492492
if (image.width / image.height == canvas.width / canvas.height) {
493493
if (cropManager.isCropMode()) cropManager.exitCropMode();
494494
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height);
495-
paintManager.redrawTextElements();
496-
paintManager.redrawLineSegments();
497495
convertDithering();
498-
paintManager.saveToHistory(); // Save after loading image
499496
} else {
500497
alert(`图片宽高比例与画布不匹配,将进入裁剪模式。\n请放大图片后移动图片使其充满画布, 再点击"完成"按钮。`);
501498
paintManager.setActiveTool(null, '');
@@ -548,6 +545,9 @@ function clearCanvas() {
548545
}
549546

550547
function convertDithering() {
548+
paintManager.redrawTextElements();
549+
paintManager.redrawLineSegments();
550+
551551
const contrast = parseFloat(document.getElementById('ditherContrast').value);
552552
const currentImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
553553
const imageData = new ImageData(
@@ -564,22 +564,23 @@ function convertDithering() {
564564
const processedData = processImageData(ditherImage(imageData, alg, strength, mode), mode);
565565
const finalImageData = decodeProcessedData(processedData, canvas.width, canvas.height, mode);
566566
ctx.putImageData(finalImageData, 0, 0);
567+
568+
paintManager.saveToHistory(); // Save dithered image to history
569+
}
570+
571+
function applyDither() {
572+
cropManager.finishCrop(() => convertDithering());
567573
}
568574

569575
function initEventHandlers() {
570-
document.getElementById("epddriver").addEventListener("change", updateDitcherOptions);
571-
document.getElementById("imageFile").addEventListener("change", updateImage);
572-
document.getElementById("ditherMode").addEventListener("change", () => cropManager.finishCrop());
573-
document.getElementById("ditherAlg").addEventListener("change", () => cropManager.finishCrop());
574-
document.getElementById("ditherStrength").addEventListener("input", function () {
575-
cropManager.finishCrop();
576-
document.getElementById("ditherStrengthValue").innerText = parseFloat(this.value).toFixed(1);
576+
document.getElementById("ditherStrength").addEventListener("input", (e) => {
577+
document.getElementById("ditherStrengthValue").innerText = parseFloat(e.target.value).toFixed(1);
578+
applyDither();
577579
});
578-
document.getElementById("ditherContrast").addEventListener("input", function () {
579-
cropManager.finishCrop();
580-
document.getElementById("ditherContrastValue").innerText = parseFloat(this.value).toFixed(1);
580+
document.getElementById("ditherContrast").addEventListener("input", (e) => {
581+
document.getElementById("ditherContrastValue").innerText = parseFloat(e.target.value).toFixed(1);
582+
applyDither();
581583
});
582-
document.getElementById("canvasSize").addEventListener("change", updateCanvasSize);
583584
}
584585

585586
function checkDebugMode() {

html/js/paint.js

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,6 @@ class PaintManager {
218218

219219
// Cancel any pending text placement
220220
this.cancelTextPlacement();
221-
222-
// Update brush cursor visibility
223-
this.updateBrushCursorVisibility();
224221
}
225222

226223
createBrushCursor() {
@@ -259,54 +256,54 @@ class PaintManager {
259256
this.brushCursor.style.height = size + 'px';
260257
}
261258

262-
updateBrushCursorVisibility() {
263-
if (!this.brushCursor) return;
264-
265-
if (this.currentTool === 'brush' || this.currentTool === 'eraser') {
266-
this.brushCursor.style.display = 'block';
267-
this.canvas.style.cursor = 'none';
268-
} else {
269-
this.brushCursor.style.display = 'none';
270-
this.canvas.style.cursor = 'default';
271-
}
272-
}
273-
274259
updateBrushCursor(e) {
275260
if (!this.brushCursor) return;
276261

277262
if (this.currentTool === 'brush' || this.currentTool === 'eraser') {
278-
this.brushCursor.style.display = 'block';
279-
this.canvas.style.cursor = 'none';
280-
281-
// Store the pending position
282-
this.pendingCursorX = e.clientX;
283-
this.pendingCursorY = e.clientY;
284-
285-
// Schedule update using requestAnimationFrame for smooth movement
286-
if (!this.cursorUpdateScheduled) {
287-
this.cursorUpdateScheduled = true;
288-
requestAnimationFrame(() => {
289-
this.brushCursor.style.transform = `translate(${this.pendingCursorX}px, ${this.pendingCursorY}px) translate(-50%, -50%)`;
290-
this.cursorUpdateScheduled = false;
291-
});
292-
}
263+
// Check if mouse is within canvas bounds
264+
const rect = this.canvas.getBoundingClientRect();
265+
const isInCanvas = e.clientX >= rect.left &&
266+
e.clientX <= rect.right &&
267+
e.clientY >= rect.top &&
268+
e.clientY <= rect.bottom;
269+
270+
if (isInCanvas) {
271+
this.brushCursor.style.display = 'block';
272+
this.canvas.style.cursor = 'none';
273+
274+
// Store the pending position
275+
this.pendingCursorX = e.clientX;
276+
this.pendingCursorY = e.clientY;
277+
278+
// Schedule update using requestAnimationFrame for smooth movement
279+
if (!this.cursorUpdateScheduled) {
280+
this.cursorUpdateScheduled = true;
281+
requestAnimationFrame(() => {
282+
this.brushCursor.style.transform = `translate(${this.pendingCursorX}px, ${this.pendingCursorY}px) translate(-50%, -50%)`;
283+
this.cursorUpdateScheduled = false;
284+
});
285+
}
293286

294-
// Update color to match brush or show white for eraser (only needs to happen once or when tool changes)
295-
if (this.currentTool === 'eraser') {
296-
if (this.brushCursor.getAttribute('data-tool') !== 'eraser') {
297-
this.brushCursor.style.border = '2px solid rgba(255, 0, 0, 0.7)';
298-
this.brushCursor.style.backgroundColor = 'rgba(255, 255, 255, 0.2)';
299-
this.brushCursor.style.boxShadow = 'none';
300-
this.brushCursor.setAttribute('data-tool', 'eraser');
287+
// Update color to match brush or show white for eraser (only needs to happen once or when tool changes)
288+
if (this.currentTool === 'eraser') {
289+
if (this.brushCursor.getAttribute('data-tool') !== 'eraser') {
290+
this.brushCursor.style.border = '2px solid rgba(255, 0, 0, 0.7)';
291+
this.brushCursor.style.backgroundColor = 'rgba(255, 255, 255, 0.2)';
292+
this.brushCursor.style.boxShadow = 'none';
293+
this.brushCursor.setAttribute('data-tool', 'eraser');
294+
}
295+
} else {
296+
if (this.brushCursor.getAttribute('data-tool') !== 'brush') {
297+
// Use a contrasting border - white with black outline for visibility
298+
this.brushCursor.style.border = '1px solid white';
299+
this.brushCursor.style.boxShadow = '0 0 0 1px black, inset 0 0 0 1px black';
300+
this.brushCursor.style.backgroundColor = 'transparent';
301+
this.brushCursor.setAttribute('data-tool', 'brush');
302+
}
301303
}
302304
} else {
303-
if (this.brushCursor.getAttribute('data-tool') !== 'brush') {
304-
// Use a contrasting border - white with black outline for visibility
305-
this.brushCursor.style.border = '1px solid white';
306-
this.brushCursor.style.boxShadow = '0 0 0 1px black, inset 0 0 0 1px black';
307-
this.brushCursor.style.backgroundColor = 'transparent';
308-
this.brushCursor.setAttribute('data-tool', 'brush');
309-
}
305+
// Hide cursor when outside canvas
306+
this.brushCursor.style.display = 'none';
310307
}
311308
}
312309
}

0 commit comments

Comments
 (0)