Skip to content

Commit

Permalink
remove rotate from scatter, restore it as a left panel control
Browse files Browse the repository at this point in the history
  • Loading branch information
mcnuttandrew committed Feb 6, 2024
1 parent 946bda0 commit b03a47c
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 189 deletions.
2 changes: 1 addition & 1 deletion src/components/Tooltip.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
>
{#if allowDrag}
<div
class="absolute cursor-move w-12 h-12 bg-stone-600 rounded-full grab-handle"
class="absolute cursor-move w-12 h-12 bg-stone-300 rounded-full grab-handle"
use:draggable
on:dragmove|preventDefault={(e) => {
e.preventDefault();
Expand Down
2 changes: 2 additions & 0 deletions src/content-modules/Controls.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import AdjustColor from "../controls/AdjustColor.svelte";
import AddColor from "../controls/AddColor.svelte";
import ColorChannelPicker from "../components/ColorChannelPicker.svelte";
import Rotate from "../controls/Rotate.svelte";
$: currentPal = $colorStore.palettes[$colorStore.currentPal];
$: colors = currentPal.colors;
Expand All @@ -34,6 +35,7 @@

<DistributePoints />
<AlignSelection />
<Rotate />
<!-- <ModifySelection /> -->

<InterpolatePoints />
179 changes: 179 additions & 0 deletions src/controls/Rotate.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<script lang="ts">
import { Color } from "../lib/Color";
import colorStore from "../stores/color-store";
import focusStore from "../stores/focus-store";
import { avgColors } from "../lib/utils";
import { buttonStyle, buttonStyleSelected } from "../lib/styles";
import Tooltip from "../components/Tooltip.svelte";
let axis = "z" as "x" | "y" | "z";
$: focusedColors = $focusStore.focusedColors;
$: currentPal = $colorStore.palettes[$colorStore.currentPal];
$: colors = currentPal.colors;
$: angle = 0;
$: colorSpace = currentPal.colorSpace;
$: angle, rotatePoints();
$: memorizedColors = false as false | Color[];
let rotationPoint = "zero " as number | "avg" | "zero";
function rotatePoints() {
if (focusedColors.length === 0) {
// memorizedColors = false;
return;
}
if (memorizedColors && focusedColors.length !== memorizedColors.length) {
memorizedColors = [...colors];
}
if (!memorizedColors) {
memorizedColors = [...colors];
angle = 0;
}
let localColors = memorizedColors;
let centerChannels = [0, 0, 0];
if (rotationPoint === "avg") {
const clrs = focusedColors.map((x) => localColors[x]);
// @ts-ignore
let center = avgColors(clrs, colorSpace);
centerChannels = center.toChannels();
} else if (rotationPoint === "zero") {
centerChannels = [0, 0, 0];
} else if (localColors[rotationPoint]) {
centerChannels = localColors[rotationPoint].toChannels();
} else {
centerChannels = [0, 0, 0];
}
const rotated = Object.fromEntries(
focusedColors
.map((x) => localColors[x])
.map((localColor) => {
const color = Color.toColorSpace(localColor, colorSpace);
const channels = color.toChannels();
// https://math.stackexchange.com/questions/4354438/how-to-rotate-a-point-on-a-cartesian-plane-around-something-other-than-the-origi
const channelMap = {
x: [0, 2],
y: [0, 1],
z: [1, 2],
};
const channelA = channelMap[axis][0];
const channelB = channelMap[axis][1];
const x1 = channels[channelA];
const y1 = channels[channelB];
const xc = centerChannels[channelA];
const yc = centerChannels[channelB];
const radAngle = (angle / 360) * Math.PI * 2;
const x3 =
Math.cos(radAngle) * (x1 - xc) -
Math.sin(radAngle) * (y1 - yc) +
xc;
const y3 =
Math.sin(radAngle) * (x1 - xc) +
Math.cos(radAngle) * (y1 - yc) +
yc;
let newChannels = [0, 0, 0] as [number, number, number];
switch (axis) {
case "x":
newChannels = [x3, channels[1], y3];
break;
case "y":
newChannels = [x3, y3, channels[2]];
break;
case "z":
newChannels = [channels[0], x3, y3];
break;
}
return Color.colorFromChannels(newChannels, colorSpace);
})
.map((x, y) => [y, x])
);
const newColors = localColors.map((x, idx) =>
focusedColors.includes(idx) ? rotated[focusedColors.indexOf(idx)] : x
);
colorStore.setCurrentPalColors(newColors);
}
function setRotatePoint(point: typeof rotationPoint) {
rotationPoint = point;
}
const zeroRotationSpaces = new Set(["lab"]);
{
if (!zeroRotationSpaces.has(colorSpace) && rotationPoint === "zero") {
rotationPoint = "avg";
}
}
</script>

{#if focusedColors.length > 0 && colorSpace !== "hsl" && colorSpace !== "hsv" && colorSpace !== "lch"}
<div class="w-full border-t-2 border-black my-2"></div>
<div class="flex justify-between w-full">
<div class="font-bold">Rotate</div>
<Tooltip>
<button slot="target" let:toggle on:click={toggle}>⚙</button>
<div slot="content">
<div class="flex flex-col">
<div>Around which point?</div>
<div class="flex flex-wrap">
<button
on:click={() => setRotatePoint("avg")}
class={`${buttonStyle} mb-2 ${
rotationPoint === "avg" ? buttonStyleSelected : ""
}`}
>
An average of the selected colors
</button>
{#if zeroRotationSpaces.has(colorSpace)}
<button
on:click={() => setRotatePoint("zero")}
class={`${buttonStyle} mb-2 ${
rotationPoint === "zero" ? buttonStyleSelected : ""
}`}
>
Around zero
</button>
{/if}

{#each focusedColors as colorIdx}
<button
class={`${buttonStyle} flex justify-center items-center ${
rotationPoint === colorIdx ? buttonStyleSelected : ""
}`}
on:click={() => setRotatePoint(colorIdx)}
>
{colors[colorIdx].toHex()}
<span
style={`background-color: ${colors[colorIdx].toHex()}`}
class="rounded-full w-3 h-3 ml-2"
></span>
</button>
{/each}
</div>
<div class="flex">
Rotate about the
<select bind:value={axis} class="mx-1">
{#each ["x", "y", "z"] as axis}
<option value={axis}>{axis}</option>
{/each}
</select>
Axis
</div>
</div>
</div>
</Tooltip>
</div>
<div class="flex flex-col">
<div class="w-full flex justify-between">
<input min={0} max={360} step={1} type="range" bind:value={angle} />
<input
min={0}
max={360}
step={1}
type="number"
bind:value={angle}
class="w-16 text-sm"
/>
</div>
</div>
{/if}
6 changes: 3 additions & 3 deletions src/controls/SetColorSpace.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
export let colorSpace: string;
export let onChange: (e: any) => void;
// const notAllowed = new Set(["rgb", "hsv", "hsl", "srgb", "lch", "oklch"]);
const notAllowed = new Set(["rgb", "lch", "oklch", "srgb"]);
// const notAllowed = new Set(["rgb", "lch", "oklch", "srgb"]);
const notAllowed = new Set(["rgb", "oklch", "srgb", "jzazbz", "oklab"]);
// const onChange = (e: any) => colorStore.setColorSpace(e);
$: options = Object.keys(colorPickerConfig)
.filter((x) => !notAllowed.has(x))
.sort();
Expand All @@ -23,7 +23,7 @@
class:font-bold={space === colorSpace}
on:click={() => onChange(space)}
>
{space}
{space.toUpperCase()}
</button>
{/each}
</div>
Expand Down
1 change: 1 addition & 0 deletions src/lib/Color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ class LCH extends Color {
domains = { l: [100, 0], c: [0, 150], h: [360, 0] } as Domain;
stepSize: Channels = [1, 1, 1];
dimensionToChannel = { x: "c", y: "h", z: "l" };
isPolar = true;
axisLabel = (num: number) => `${Math.round(num)}`;
}

Expand Down
Loading

0 comments on commit b03a47c

Please sign in to comment.