Add Arc component
This commit is contained in:
parent
0db5ab19ed
commit
e36914714f
2 changed files with 199 additions and 0 deletions
168
src/lib/Arc.svelte
Normal file
168
src/lib/Arc.svelte
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import DietProgress from "./DietProgress.svelte";
|
||||||
|
import P from "./svg-path";
|
||||||
|
import { gym, cardio, diet } from "./store";
|
||||||
|
|
||||||
|
export const DEG_TO_RAD = Math.PI / 180;
|
||||||
|
export const RAD_TO_DEG = 180 / Math.PI;
|
||||||
|
export const FULL_CIRCLE_IN_RADIANS = 2 * Math.PI;
|
||||||
|
|
||||||
|
const size = 400;
|
||||||
|
const segmentHeight = 16;
|
||||||
|
const span = 0.8 * FULL_CIRCLE_IN_RADIANS;
|
||||||
|
const startAngle = 0.25 * FULL_CIRCLE_IN_RADIANS + span / 2;
|
||||||
|
|
||||||
|
const perimiterWidth = size * Math.PI * (span / FULL_CIRCLE_IN_RADIANS);
|
||||||
|
const pixelToRadians = span / perimiterWidth;
|
||||||
|
const x = 0;
|
||||||
|
const y = 0;
|
||||||
|
|
||||||
|
const points = (radius: number, radLength: number, thickness: number) => {
|
||||||
|
const borderRadius = thickness / 2;
|
||||||
|
const outerRadius = radius;
|
||||||
|
const innerRadius = outerRadius - thickness;
|
||||||
|
const radEndAngle = startAngle - radLength;
|
||||||
|
const borderRadiusAngle =
|
||||||
|
(borderRadius / (outerRadius * FULL_CIRCLE_IN_RADIANS)) *
|
||||||
|
FULL_CIRCLE_IN_RADIANS;
|
||||||
|
const isLongTrack = radLength - 2 * borderRadiusAngle > Math.PI;
|
||||||
|
|
||||||
|
return P()
|
||||||
|
.moveTo(
|
||||||
|
-Math.sin(startAngle) * (outerRadius - borderRadius),
|
||||||
|
Math.cos(startAngle) * (outerRadius - borderRadius),
|
||||||
|
)
|
||||||
|
.arcTo(
|
||||||
|
borderRadius,
|
||||||
|
borderRadius,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
-Math.sin(startAngle - borderRadiusAngle) * outerRadius,
|
||||||
|
Math.cos(startAngle - borderRadiusAngle) * outerRadius,
|
||||||
|
)
|
||||||
|
.arcTo(
|
||||||
|
outerRadius,
|
||||||
|
outerRadius,
|
||||||
|
isLongTrack,
|
||||||
|
true,
|
||||||
|
-Math.sin(radEndAngle + borderRadiusAngle) * outerRadius,
|
||||||
|
Math.cos(radEndAngle + borderRadiusAngle) * outerRadius,
|
||||||
|
)
|
||||||
|
.arcTo(
|
||||||
|
borderRadius,
|
||||||
|
borderRadius,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
-Math.sin(radEndAngle) * (outerRadius - borderRadius),
|
||||||
|
Math.cos(radEndAngle) * (outerRadius - borderRadius),
|
||||||
|
)
|
||||||
|
.lineTo(
|
||||||
|
-Math.sin(radEndAngle) * (innerRadius + borderRadius),
|
||||||
|
Math.cos(radEndAngle) * (innerRadius + borderRadius),
|
||||||
|
)
|
||||||
|
.arcTo(
|
||||||
|
borderRadius,
|
||||||
|
borderRadius,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
-Math.sin(radEndAngle + borderRadiusAngle) * innerRadius,
|
||||||
|
Math.cos(radEndAngle + borderRadiusAngle) * innerRadius,
|
||||||
|
)
|
||||||
|
.arcTo(
|
||||||
|
innerRadius,
|
||||||
|
innerRadius,
|
||||||
|
isLongTrack,
|
||||||
|
false,
|
||||||
|
-Math.sin(startAngle - borderRadiusAngle) * innerRadius,
|
||||||
|
Math.cos(startAngle - borderRadiusAngle) * innerRadius,
|
||||||
|
)
|
||||||
|
.arcTo(
|
||||||
|
borderRadius,
|
||||||
|
borderRadius,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
-Math.sin(startAngle) * (innerRadius + borderRadius),
|
||||||
|
Math.cos(startAngle) * (innerRadius + borderRadius),
|
||||||
|
)
|
||||||
|
.close()
|
||||||
|
.stringify();
|
||||||
|
};
|
||||||
|
|
||||||
|
let items = [
|
||||||
|
{
|
||||||
|
c: "gym",
|
||||||
|
progress: $gym.filter((c) => c.completed).length / $gym.length,
|
||||||
|
level: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "cardio",
|
||||||
|
progress: $diet.filter((c) => !c.excluded).length / $cardio.length,
|
||||||
|
level: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "diet",
|
||||||
|
progress:
|
||||||
|
$cardio.filter((c) => c.completed).length /
|
||||||
|
$diet.filter((c) => !c.excluded).length,
|
||||||
|
level: 2,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<svg viewBox="0 0 {size} {size}" role="presentation">
|
||||||
|
<g transform="${`translate(${x},${y})`}" fill="none">
|
||||||
|
<g transform={`translate(${size / 2},${size / 2})`}>
|
||||||
|
{#each items as { c, progress, level }}
|
||||||
|
<path
|
||||||
|
fill="#fff"
|
||||||
|
opacity="0.066"
|
||||||
|
d={points(
|
||||||
|
size / 2 - level * (segmentHeight + 4),
|
||||||
|
span,
|
||||||
|
segmentHeight,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class={c}
|
||||||
|
fill="currentColor"
|
||||||
|
d={points(
|
||||||
|
size / 2 - level * (segmentHeight + 4),
|
||||||
|
progress * span,
|
||||||
|
segmentHeight,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
max-width: 80%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
place-content: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 2rem 0 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardio {
|
||||||
|
color: #5dc5f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gym {
|
||||||
|
color: #f62b5a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diet {
|
||||||
|
color: #35d450;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
31
src/lib/svg-path.ts
Normal file
31
src/lib/svg-path.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
export default function () {
|
||||||
|
const commands: string[] = [];
|
||||||
|
return {
|
||||||
|
stringify() {
|
||||||
|
return `${commands.join("\n")}`;
|
||||||
|
},
|
||||||
|
arcTo(
|
||||||
|
ry: number,
|
||||||
|
rx: number,
|
||||||
|
long: boolean,
|
||||||
|
cw: boolean,
|
||||||
|
y: number,
|
||||||
|
x: number,
|
||||||
|
) {
|
||||||
|
commands.push(`A ${rx} ${ry} 0 ${long ? 1 : 0} ${cw ? 1 : 0} ${x} ${y}`);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
moveTo(y: number, x: number) {
|
||||||
|
commands.push(`M ${x} ${y}`);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
lineTo(y: number, x: number) {
|
||||||
|
commands.push(`L ${x} ${y}`);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
commands.push("z");
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue