Skip to content

Commit d7ba34e

Browse files
committed
style
1 parent 3a2a26e commit d7ba34e

File tree

5 files changed

+186
-104
lines changed

5 files changed

+186
-104
lines changed

demo/components/AnimationControls.vue

Lines changed: 156 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,10 @@
9797
<select
9898
@input="updateTimingFunction"
9999
@change="
100-
(e) => {
101-
cubicBezierValues = JSON.parse(
102-
JSON.stringify(
103-
bezierPresets[
104-
(e.target as HTMLInputElement).value
105-
],
106-
),
107-
);
108-
updateTimingFunction();
109-
}
100+
(e) =>
101+
updateCubicBezierPreset(
102+
(e.target as HTMLSelectElement).value,
103+
)
110104
"
111105
>
112106
<option
@@ -119,48 +113,42 @@
119113

120114
<svg
121115
ref="svgCubicBezierEl"
122-
viewBox="-0.125 -1.125 1.25 1.25"
116+
viewBox="0 -1.5 1 2"
123117
xmlns="http://www.w3.org/2000/svg"
124-
></svg>
118+
@mousedown="startCubicBezierDragging"
119+
@mousemove="cubicBezierDrag"
120+
@mouseup="stopCubicBezierDragging"
121+
@mouseleave="stopCubicBezierDragging"
122+
>
123+
<g ref="cubicBezierPathEl"></g>
124+
<circle
125+
v-for="(point, index) in controlPoints"
126+
:key="index"
127+
:cx="point.x"
128+
:cy="point.y"
129+
:data-index="index"
130+
@mouseover="
131+
(e) => {
132+
(e.target as HTMLElement).style.setProperty(
133+
'--stroke-width',
134+
'0.15',
135+
);
136+
}
137+
"
138+
@mouseleave="
139+
(e) => {
140+
(e.target as HTMLElement).style.setProperty(
141+
'--stroke-width',
142+
'0.1',
143+
);
144+
}
145+
"
146+
/>
147+
</svg>
125148

126149
<label class="preset-label" @click="copyToClipboard"
127150
>{{ cubicBezierPreset }}
128-
<div ref="copyTextEl" class="info">Copied!</div>
129-
<font-awesome-icon :icon="['fas', 'clipboard']"
130-
/></label>
131-
132-
<input
133-
@input="updateTimingFunction"
134-
v-model.number="cubicBezierValues[0]"
135-
type="range"
136-
:min="-2"
137-
:max="2"
138-
step="0.01"
139-
/>
140-
<input
141-
@input="updateTimingFunction"
142-
v-model.number="cubicBezierValues[1]"
143-
type="range"
144-
:min="-2"
145-
:max="2"
146-
step="0.01"
147-
/>
148-
<input
149-
@input="updateTimingFunction"
150-
v-model.number="cubicBezierValues[2]"
151-
type="range"
152-
:min="-2"
153-
:max="2"
154-
step="0.01"
155-
/>
156-
<input
157-
@input="updateTimingFunction"
158-
v-model.number="cubicBezierValues[3]"
159-
type="range"
160-
:min="-2"
161-
:max="2"
162-
step="0.01"
163-
/>
151+
</label>
164152
</div>
165153
</template>
166154
</div>
@@ -326,27 +314,104 @@ let cubicBezierValues = $ref(
326314
bezierPresets[cubicBezierPreset] as [number, number, number, number],
327315
);
328316
const svgCubicBezierEl = $ref(null);
317+
const cubicBezierPathEl = $ref(null);
318+
319+
let isDragging = $ref(false);
320+
let currentPointIndex = $ref(null);
321+
let controlPoints = $ref([
322+
{ x: 0.01, y: 0 },
323+
{ x: cubicBezierValues[0], y: cubicBezierValues[1] },
324+
{ x: cubicBezierValues[2], y: cubicBezierValues[3] },
325+
{ x: 0.97, y: 1 },
326+
]);
327+
328+
const bezierPath = computed(() => {
329+
const scaledValues = cubicBezierValues.map((v) => {
330+
return v;
331+
});
332+
333+
return svgCubicBezier(...(scaledValues as [number, number, number, number]));
334+
});
335+
336+
const startCubicBezierDragging = (event: MouseEvent) => {
337+
const target = (event.target as SVGElement).closest("circle");
338+
339+
if (target) {
340+
isDragging = true;
341+
currentPointIndex = parseInt(target.getAttribute("data-index"));
342+
}
343+
};
344+
345+
const stopCubicBezierDragging = () => {
346+
isDragging = false;
347+
currentPointIndex = null;
348+
};
349+
350+
let scaleCubicBezierValues = $ref(false);
351+
352+
const cubicBezierDrag = (event: MouseEvent) => {
353+
if (isDragging && currentPointIndex !== null) {
354+
// if the current point is a boundary, exit:
355+
if (currentPointIndex === 0 || currentPointIndex === 3) {
356+
return;
357+
}
358+
359+
const svgRect = cubicBezierPathEl.getBoundingClientRect();
360+
361+
const { width, height, left, top } = svgRect;
362+
363+
const x = (event.clientX - left) / width;
364+
const y = 1 - (event.clientY - top) / height;
365+
366+
// Update the control point position
367+
controlPoints[currentPointIndex] = {
368+
x,
369+
y,
370+
};
371+
372+
// Update cubicBezierValues
373+
cubicBezierValues = [
374+
controlPoints[1].x,
375+
controlPoints[1].y,
376+
controlPoints[2].x,
377+
controlPoints[2].y,
378+
];
379+
380+
scaleCubicBezierValues = true;
381+
updateTimingFunction();
382+
}
383+
};
384+
385+
const updateCubicBezierPreset = (preset: string) => {
386+
cubicBezierPreset = preset;
387+
cubicBezierValues = JSON.parse(JSON.stringify(bezierPresets[preset]));
388+
389+
// update the control points
390+
controlPoints[1] = { x: cubicBezierValues[0], y: cubicBezierValues[1] };
391+
controlPoints[2] = { x: cubicBezierValues[2], y: cubicBezierValues[3] };
392+
393+
scaleCubicBezierValues = true;
394+
updateTimingFunction();
395+
};
329396
330397
const updateTimingFunction = () => {
331398
let timingFunction = timingFunctions[timingFunctionKey];
399+
332400
if (timingFunctionKey === "steps") {
333401
timingFunction = timingFunctions[timingFunctionKey](steps, jumpTerm);
334402
} else if (timingFunctionKey === "cubicBezier") {
403+
const scaledValues = cubicBezierValues.map((v) => {
404+
return v;
405+
});
406+
335407
timingFunction = CSSBezier(
336-
...(cubicBezierValues as [number, number, number, number]),
408+
...(scaledValues as [number, number, number, number]),
337409
);
338410
cubicBezierPreset = `cubic-bezier(${cubicBezierValues
339411
.map((v) => v.toFixed(2))
340412
.join(",")})`;
341413
342-
const path = svgCubicBezier(
343-
cubicBezierValues[0],
344-
cubicBezierValues[1],
345-
cubicBezierValues[2],
346-
cubicBezierValues[3],
347-
);
348-
349-
svgCubicBezierEl.innerHTML = path;
414+
cubicBezierPathEl.innerHTML = bezierPath.value;
350415
}
351416
352417
setTimingFunction(timingFunction);
@@ -482,6 +547,7 @@ const fadeInOut = (el) => {
482547
};
483548
484549
let copyTextEl = $ref(null);
550+
485551
const copyToClipboard = async () => {
486552
navigator.clipboard.writeText(await cssKeyframesString.value);
487553
fadeInOut(copyTextEl);
@@ -552,51 +618,58 @@ input[type="range"] {
552618
553619
.cubic-bezier-controls {
554620
grid-column: span 2;
621+
555622
display: grid;
556-
gap: 1rem 0.5rem;
557-
grid-template-columns: auto auto;
623+
624+
grid-template-columns: 25% 75%;
558625
align-items: center;
559626
627+
select {
628+
width: 100%;
629+
}
630+
560631
label {
561632
overflow: hidden;
562633
white-space: pre;
563634
grid-column: span 2;
564635
max-width: 100%;
565636
}
566637
567-
input {
568-
grid-column: span 2;
569-
margin: 0;
570-
571-
background: linear-gradient(
572-
to right,
573-
#f00 0%,
574-
#ff0 17%,
575-
#0f0 33%,
576-
#0ff 50%,
577-
#00f 67%,
578-
#f0f 83%,
579-
#f00 100%
580-
) !important;
581-
}
582-
583638
svg::v-deep {
584-
width: 200px;
639+
width: 100%;
640+
585641
aspect-ratio: 1 / 1;
586-
--stroke-width: 0.07;
642+
--stroke-width: 0.1;
643+
--circle-color: rgb(226, 61, 61);
644+
--path-color: rgb(137, 20, 239);
645+
646+
circle {
647+
r: calc(var(--stroke-width) / 2);
648+
stroke: var(--circle-color);
649+
fill: var(--circle-color);
650+
stroke-width: 0;
651+
652+
cursor: move;
653+
}
654+
655+
circle:nth-child(5),
656+
circle:nth-child(2) {
657+
--circle-color: var(--path-color);
658+
cursor: not-allowed;
659+
}
587660
588661
g {
589-
circle {
590-
r: calc(var(--stroke-width) / 2);
591-
stroke: black;
592-
stroke-width: 0;
593-
}
594662
path {
595-
stroke: rgb(93, 246, 220);
663+
stroke: rgb(137, 20, 239);
596664
stroke-width: var(--stroke-width);
597665
fill: none;
598666
}
599667
}
668+
669+
> * {
670+
--scale: 1;
671+
transform: scale(var(--scale), calc(-1 * var(--scale)));
672+
}
600673
}
601674
}
602675

demo/cube/App.vue

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,22 @@
5353

5454
<div ref="graph" class="graph">
5555
<div ref="cube" class="cube animation">
56-
<div class="cube-side side-back">3</div>
57-
<div class="cube-side side-bottom">6</div>
58-
<div class="cube-side side-right">2</div>
59-
<div class="cube-side side-left">4</div>
60-
<div class="cube-side side-front">
61-
1
56+
<div
57+
v-for="(side, index) in cubeSides"
58+
:key="index"
59+
:class="['cube-side', side.class]"
60+
>
61+
{{ side.content }}
6262
<span
63-
ref="cubeSideFront"
6463
:class="
6564
!rotationAnim.animation.playing() ? 'rainbow-wrapper' : ''
6665
"
67-
></span>
66+
:style="{
67+
animationDelay: `${Math.random() * 2}s`,
68+
}"
69+
>
70+
</span>
6871
</div>
69-
<div class="cube-side side-top">5</div>
7072
</div>
7173

7274
<p class="axis-line x"></p>
@@ -327,8 +329,17 @@ const animations = {
327329
328330
let selectedAnimation = $ref("");
329331
332+
const cubeSides = [
333+
{ class: "side-back", content: "3" },
334+
{ class: "side-bottom", content: "6" },
335+
{ class: "side-right", content: "2" },
336+
{ class: "side-left", content: "4" },
337+
{ class: "side-front", content: "1" },
338+
{ class: "side-top", content: "5" },
339+
];
340+
330341
const cube = $ref<HTMLElement>();
331-
const cubeSideFront = $ref<HTMLElement>();
342+
332343
const graph = $ref<HTMLElement>();
333344
334345
onMounted(() => {
@@ -452,7 +463,7 @@ body {
452463
color: white;
453464
454465
font-size: 2rem;
455-
border: 1px inset rgba(0, 0, 0, 0.5);
466+
border: 1px inset rgba(0, 0, 0, 0.37);
456467
}
457468
458469
.side-front {

0 commit comments

Comments
 (0)