Add some wip stub for HSV color picker
parent
309aebdc8e
commit
988e171f22
|
@ -4,7 +4,7 @@
|
|||
import Importer from './sections/Importer.svelte';
|
||||
import PaletteSection from './sections/Palette.svelte'
|
||||
import FloatingPanel from './components/FloatingPanel.svelte'
|
||||
import { Palette, PaletteEntry, defaultPalette } from './types/palette'
|
||||
import { Palette, PaletteEntry, defaultPalette, type Color } from './types/palette'
|
||||
|
||||
import { LoadedFile, PixelsPlaceUndoable, SelectionClearUndoable, SelectionSetUndoable } from './types/file'
|
||||
|
||||
|
@ -23,12 +23,19 @@
|
|||
import Shortcuts from './components/Shortcuts.svelte'
|
||||
import { CopyPaste } from './types/copypaste'
|
||||
import type { PixelPosition } from './types/shapes.js';
|
||||
import ColorSelector from './components/ColorSelector.svelte';
|
||||
|
||||
let theme: 'white'|'g10'|'g80'|'g90'|'g100' = 'g90'
|
||||
|
||||
let palette: Palette = defaultPalette()
|
||||
let primaryColorIndex: number = 1
|
||||
let secondaryColorIndex: number = 0
|
||||
|
||||
let primaryColor: Color = {r: 0, g: 0, b: 0, a: 0}
|
||||
let secondaryColor: Color = {r: 0, g: 0, b: 0, a: 0}
|
||||
|
||||
$: primaryColor = palette?.[primaryColorIndex]
|
||||
$: secondaryColor = palette?.[secondaryColorIndex]
|
||||
|
||||
// Oh no, what are you doing, step palette~
|
||||
function stepPalette(step: number, primary: boolean) {
|
||||
|
@ -163,6 +170,7 @@
|
|||
<section class='content'>
|
||||
<section class='left'>
|
||||
<PaletteSection bind:palette bind:primaryColorIndex bind:secondaryColorIndex file={focusedFile} />
|
||||
<ColorSelector />
|
||||
</section>
|
||||
<menu class='toolbar'>
|
||||
<Button isSelected={currentTool === toolMove} kind="ghost" size="small" icon={Move} iconDescription="move" tooltipPosition="right" on:click={()=>swapTool(toolMove)}></Button>
|
||||
|
@ -271,8 +279,9 @@
|
|||
}
|
||||
.left {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<script lang='ts'>
|
||||
export let red: number = 255
|
||||
export let green: number = 0
|
||||
export let blue: number = 0
|
||||
export let alpha: number = 0
|
||||
|
||||
let hue: number = 0
|
||||
let saturation: number = 0
|
||||
let value: number = 0
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<div class="hsv">
|
||||
<div class='hsv_hue' style="background: rgb({red}, {green}, {blue})"></div>
|
||||
<div class='hsv_saturation'></div>
|
||||
<div class='hsv_value'></div>
|
||||
</div>
|
||||
<div class='sv'>
|
||||
</div>
|
||||
<div class='slider'>
|
||||
<div class='hue' style='width: 100%; height: 1em;'></div>
|
||||
</div>
|
||||
<div class='slider'>
|
||||
<span class="checkerboard"></span>
|
||||
<div class='alpha' style='width: 100%; height: 1em;'></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.slider {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
.hsv {
|
||||
min-height: 9em;
|
||||
width: 100%;
|
||||
border: 1px solid red;
|
||||
}
|
||||
.hue {
|
||||
background-image: linear-gradient(to left,
|
||||
#ff0000, #ff0080,
|
||||
#ff00ff, #8000ff,
|
||||
#0000ff, #0080ff,
|
||||
#00ffff, #00ff80,
|
||||
#00ff00, #80ff00,
|
||||
#ffff00, #ff8000,
|
||||
#ff0000
|
||||
);
|
||||
}
|
||||
.alpha {
|
||||
background-image: linear-gradient(to right,
|
||||
transparent 0%,
|
||||
rgba(255, 0, 0, 1) 100%
|
||||
);
|
||||
z-index: 0;
|
||||
}
|
||||
.checkerboard {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: linear-gradient(45deg, #808080 25%, transparent 25%), linear-gradient(-45deg, #808080 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #808080 75%), linear-gradient(-45deg, transparent 75%, #808080 75%);
|
||||
background-size: 10px 10px;
|
||||
background-position: 0 0, 0 5px, 5px -5px, -5px 0px;
|
||||
}
|
||||
</style>
|
|
@ -1,4 +1,5 @@
|
|||
<script lang='ts'>
|
||||
import type { Color } from '../types/palette'
|
||||
import type { LoadedFile } from '../types/file'
|
||||
|
||||
export let file: LoadedFile
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
function floatsToBytes(colors: number[]): number[] {
|
||||
if (colors.length <= 0) return colors
|
||||
if (colors[0] <= 1.0) {
|
||||
colors[0] = colors[0] * 255
|
||||
colors[1] = colors[1] * 255
|
||||
colors[2] = colors[2] * 255
|
||||
}
|
||||
return colors
|
||||
}
|
||||
|
||||
function bytesToFloats(colors: number[]): number[] {
|
||||
if (colors.length <= 0) return colors
|
||||
if (colors[0] > 1.0) {
|
||||
colors[0] = colors[0] / 255
|
||||
colors[1] = colors[1] / 255
|
||||
colors[2] = colors[2] / 255
|
||||
}
|
||||
return colors
|
||||
}
|
||||
|
||||
export function HSV2RGB(hsv: number[]): number[] {
|
||||
let hh: number, p: number, q: number, t: number, ff: number, i: number
|
||||
let rgb: number[] = []
|
||||
|
||||
if (hsv[1] <= 0.0) {
|
||||
rgb[0] = hsv[2]
|
||||
rgb[1] = hsv[2]
|
||||
rgb[2] = hsv[2]
|
||||
return floatsToBytes(rgb)
|
||||
}
|
||||
hh = hsv[0]
|
||||
if (hh >= 360.0) {
|
||||
hh = 0.0
|
||||
}
|
||||
hh /= 60.0
|
||||
i = Math.floor(hh)
|
||||
ff = hh - i
|
||||
p = hsv[2] * (1.0 - hsv[1])
|
||||
q = hsv[2] * (1.0 - (hsv[1] * ff))
|
||||
t = hsv[2] * (1.0 - (hsv[1] * (1.0 - ff)))
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
rgb[0] = hsv[2]
|
||||
rgb[1] = t
|
||||
rgb[2] = p
|
||||
break
|
||||
case 1:
|
||||
rgb[0] = q
|
||||
rgb[1] = hsv[2]
|
||||
rgb[2] = p
|
||||
break
|
||||
case 2:
|
||||
rgb[0] = p
|
||||
rgb[1] = hsv[2]
|
||||
rgb[2] = t
|
||||
break
|
||||
case 3:
|
||||
rgb[0] = p
|
||||
rgb[1] = q
|
||||
rgb[2] = hsv[2]
|
||||
break
|
||||
case 4:
|
||||
rgb[0] = t
|
||||
rgb[1] = p
|
||||
rgb[2] = hsv[2]
|
||||
break
|
||||
case 5:
|
||||
default:
|
||||
rgb[0] = hsv[2]
|
||||
rgb[1] = p
|
||||
rgb[2] = q
|
||||
break
|
||||
}
|
||||
return floatsToBytes(rgb)
|
||||
}
|
||||
|
||||
export function RGB2HSV(rgb: number[]): number[] {
|
||||
rgb = bytesToFloats(rgb)
|
||||
|
||||
let min: number, max: number, delta: number
|
||||
let hsv: number[] = []
|
||||
|
||||
min = rgb[0] < rgb[1] ? rgb[0] : rgb[1]
|
||||
min = min < rgb[2] ? min : rgb[2]
|
||||
|
||||
max = rgb[0] > rgb[1] ? rgb[0] : rgb[1]
|
||||
max = max > rgb[2] ? max : rgb[2]
|
||||
|
||||
hsv[2] = max
|
||||
delta = max - min
|
||||
|
||||
if (delta < 0.00001) {
|
||||
hsv[1] = 0
|
||||
hsv[0] = 0
|
||||
return hsv
|
||||
}
|
||||
|
||||
if (max > 0.0) {
|
||||
hsv[1] = delta / max
|
||||
} else {
|
||||
hsv[1] = 0.0
|
||||
hsv[0] = NaN
|
||||
return hsv
|
||||
}
|
||||
|
||||
if (rgb[0] >= max) {
|
||||
hsv[0] = ( rgb[1] - rgb[2] ) / delta
|
||||
} else if (rgb[1] >= max) {
|
||||
hsv[0] = 2.0 + ( rgb[2] - rgb[0] ) / delta
|
||||
} else {
|
||||
hsv[0] = 4.0 + ( rgb[0] - rgb[1] ) / delta
|
||||
}
|
||||
|
||||
hsv[0] *= 60.0;
|
||||
|
||||
if (hsv[0] < 0.0) {
|
||||
hsv[0] += 360.0
|
||||
}
|
||||
return hsv
|
||||
}
|
||||
|
|
@ -15,3 +15,10 @@ export const defaultPalette = (): Palette => {
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
export interface Color {
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
a: number;
|
||||
}
|
Loading…
Reference in New Issue