[FEAT] Add eye drop to pixel editor

This commit is contained in:
2026-01-03 18:25:24 +01:00
parent e290eb21a4
commit 8e71d7379a
2 changed files with 52 additions and 11 deletions

View File

@@ -56,6 +56,11 @@
<i class="fas fa-eraser text-gray-600 dark:text-gray-300"></i>
</button>
</Tooltip>
<Tooltip text="Eyedropper (I)">
<button @click="editor.currentTool.value = 'picker'" :class="editor.currentTool.value === 'picker' ? 'bg-white dark:bg-gray-600 shadow-sm' : 'hover:bg-gray-200 dark:hover:bg-gray-600'" class="p-2 rounded-md transition-all">
<i class="fas fa-eye-dropper text-gray-600 dark:text-gray-300"></i>
</button>
</Tooltip>
</div>
<!-- Color Picker & History -->
@@ -130,15 +135,15 @@
<span class="text-xs text-gray-600 dark:text-gray-400 select-none">Grid</span>
</label>
<label class="flex items-center gap-2 cursor-pointer">
<input type="checkbox" v-model="editor.showPointerLocation.value" class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" />
<span class="text-xs text-gray-600 dark:text-gray-400 select-none">Coords</span>
<input type="checkbox" v-model="showPixelHighlight" class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" />
<span class="text-xs text-gray-600 dark:text-gray-400 select-none">Highlight</span>
</label>
<!-- Pointer Location Display -->
<div v-if="editor.showPointerLocation.value" class="text-xs font-mono text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded min-w-[60px] text-center">{{ editor.pointerX.value }}, {{ editor.pointerY.value }}</div>
<!-- Canvas Size -->
<div class="text-xs font-mono text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">{{ editor.canvasWidth.value }} × {{ editor.canvasHeight.value }}</div>
<div class="text-xs font-mono text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">W: {{ editor.canvasWidth.value }} H: {{ editor.canvasHeight.value }}</div>
</div>
</div>
@@ -182,6 +187,18 @@
backgroundSize: `${editor.zoom.value}px ${editor.zoom.value}px`,
}"
></div>
<!-- Active Pixel Highlight -->
<div
v-if="showPixelHighlight"
class="absolute pointer-events-none z-30 border border-indigo-500/80 bg-indigo-500/20"
:style="{
left: `${editor.pointerX.value * editor.zoom.value}px`,
top: `${editor.pointerY.value * editor.zoom.value}px`,
width: `${editor.zoom.value}px`,
height: `${editor.zoom.value}px`,
}"
></div>
</div>
</div>
</div>
@@ -269,6 +286,7 @@
const resizeWidth = ref(32);
const resizeHeight = ref(32);
const resizeAnchor = ref('top-left');
const showPixelHighlight = ref(true);
const recentColors = ref<string[]>(['#ffffff', '#000000', '#ff0000', '#00ff00', '#0000ff']);
@@ -425,6 +443,8 @@
editor.currentTool.value = 'pencil';
} else if (event.key === 'e' || event.key === 'E') {
editor.currentTool.value = 'eraser';
} else if (event.key === 'i' || event.key === 'I') {
editor.currentTool.value = 'picker';
}
// Undo/Redo

View File

@@ -20,7 +20,7 @@ export const usePixelEditor = (options: PixelEditorOptions = {}) => {
const canvasWidth = ref(options.initialWidth || 32);
const canvasHeight = ref(options.initialHeight || 32);
const currentTool = ref<'pencil' | 'eraser'>('pencil');
const currentTool = ref<'pencil' | 'eraser' | 'picker'>('pencil');
const currentColor = ref('#000000');
const brushSize = ref(1);
const zoom = ref(1);
@@ -31,7 +31,7 @@ export const usePixelEditor = (options: PixelEditorOptions = {}) => {
const pointerX = ref(0);
const pointerY = ref(0);
const showPointerLocation = ref(false);
const showPointerLocation = ref(true);
const showCheckerboard = ref(false);
// History management
@@ -185,14 +185,31 @@ export const usePixelEditor = (options: PixelEditorOptions = {}) => {
}
};
const pickColor = (x: number, y: number) => {
if (!ctx.value) return;
const p = ctx.value.getImageData(x, y, 1, 1).data;
// Ignore if fully transparent
if (p[3] === 0) return;
const hex = '#' + ('00' + p[0].toString(16)).slice(-2) + ('00' + p[1].toString(16)).slice(-2) + ('00' + p[2].toString(16)).slice(-2);
currentColor.value = hex;
};
const startDrawing = (event: MouseEvent) => {
if (!canvas.value) return;
isDrawing.value = true;
const { x, y } = getPixelCoords(event, canvas.value);
lastX.value = x;
lastY.value = y;
drawPixel(x, y);
if (currentTool.value === 'picker') {
pickColor(x, y);
} else {
lastX.value = x;
lastY.value = y;
drawPixel(x, y);
}
};
const continueDrawing = (event: MouseEvent) => {
@@ -204,9 +221,13 @@ export const usePixelEditor = (options: PixelEditorOptions = {}) => {
if (!isDrawing.value) return;
drawLine(lastX.value, lastY.value, x, y);
lastX.value = x;
lastY.value = y;
if (currentTool.value === 'picker') {
pickColor(x, y);
} else {
drawLine(lastX.value, lastY.value, x, y);
lastX.value = x;
lastY.value = y;
}
};
const stopDrawing = () => {