[FEAT] Add eye drop to pixel editor
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
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;
|
||||
|
||||
if (currentTool.value === 'picker') {
|
||||
pickColor(x, y);
|
||||
} else {
|
||||
drawLine(lastX.value, lastY.value, x, y);
|
||||
lastX.value = x;
|
||||
lastY.value = y;
|
||||
}
|
||||
};
|
||||
|
||||
const stopDrawing = () => {
|
||||
|
||||
Reference in New Issue
Block a user