2018-12-22 22:09:27 +01:00
|
|
|
<!--
|
|
|
|
https://eugenkiss.github.io/7guis/tasks#circle
|
|
|
|
|
|
|
|
Click on the canvas to draw a circle. Click on a circle
|
|
|
|
to select it. Right-click on the canvas to adjust the
|
|
|
|
radius of the selected circle.
|
|
|
|
-->
|
|
|
|
|
|
|
|
<script>
|
|
|
|
let i = 0;
|
|
|
|
let undoStack = [[]];
|
|
|
|
let circles = [];
|
|
|
|
let selected;
|
|
|
|
let adjusting = false;
|
|
|
|
let adjusted = false;
|
|
|
|
|
|
|
|
function handleClick(event) {
|
|
|
|
if (adjusting) {
|
|
|
|
adjusting = false;
|
|
|
|
|
|
|
|
// if circle was adjusted,
|
|
|
|
// push to the stack
|
|
|
|
if (adjusted) push();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const circle = {
|
|
|
|
cx: event.clientX,
|
|
|
|
cy: event.clientY,
|
|
|
|
r: 50
|
|
|
|
};
|
|
|
|
|
|
|
|
circles = circles.concat(circle);
|
|
|
|
selected = circle;
|
|
|
|
|
|
|
|
push();
|
|
|
|
}
|
|
|
|
|
|
|
|
function adjust(event) {
|
|
|
|
selected.r = +event.target.value;
|
|
|
|
circles = circles;
|
|
|
|
adjusted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function select(circle, event) {
|
|
|
|
if (!adjusting) {
|
|
|
|
event.stopPropagation();
|
|
|
|
selected = circle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function push() {
|
|
|
|
const newUndoStack = undoStack.slice(0, ++i);
|
|
|
|
newUndoStack.push(clone(circles));
|
|
|
|
undoStack = newUndoStack;
|
|
|
|
}
|
|
|
|
|
|
|
|
function travel(d) {
|
2023-05-14 07:50:43 +02:00
|
|
|
circles = clone(undoStack[(i += d)]);
|
2018-12-22 22:09:27 +01:00
|
|
|
adjusting = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function clone(circles) {
|
|
|
|
return circles.map(({ cx, cy, r }) => ({ cx, cy, r }));
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
2021-04-22 18:05:13 +02:00
|
|
|
<div class="controls">
|
2023-05-14 07:50:43 +02:00
|
|
|
<button on:click={() => travel(-1)} disabled={i === 0}>undo</button>
|
|
|
|
<button on:click={() => travel(+1)} disabled={i === undoStack.length - 1}>redo</button>
|
2021-04-22 18:05:13 +02:00
|
|
|
</div>
|
|
|
|
|
2023-05-14 07:50:43 +02:00
|
|
|
<svg on:click={handleClick}>
|
2021-04-22 18:05:13 +02:00
|
|
|
{#each circles as circle}
|
2023-05-14 07:50:43 +02:00
|
|
|
<circle
|
|
|
|
cx={circle.cx}
|
|
|
|
cy={circle.cy}
|
|
|
|
r={circle.r}
|
|
|
|
on:click={(event) => select(circle, event)}
|
|
|
|
on:contextmenu|stopPropagation|preventDefault={() => {
|
2021-04-22 18:05:13 +02:00
|
|
|
adjusting = !adjusting;
|
|
|
|
if (adjusting) selected = circle;
|
2023-05-14 07:50:43 +02:00
|
|
|
}}
|
|
|
|
fill={circle === selected ? '#ccc' : 'white'}
|
2021-04-22 18:05:13 +02:00
|
|
|
/>
|
|
|
|
{/each}
|
|
|
|
</svg>
|
|
|
|
|
|
|
|
{#if adjusting}
|
|
|
|
<div class="adjuster">
|
|
|
|
<p>adjust diameter of circle at {selected.cx}, {selected.cy}</p>
|
2023-05-14 07:50:43 +02:00
|
|
|
<input type="range" value={selected.r} on:input={adjust} />
|
2021-04-22 18:05:13 +02:00
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
|
2018-12-22 22:09:27 +01:00
|
|
|
<style>
|
|
|
|
.controls {
|
|
|
|
position: absolute;
|
|
|
|
width: 100%;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
svg {
|
|
|
|
background-color: #eee;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
circle {
|
|
|
|
stroke: black;
|
|
|
|
}
|
|
|
|
|
|
|
|
.adjuster {
|
|
|
|
position: absolute;
|
|
|
|
width: 80%;
|
|
|
|
top: 50%;
|
|
|
|
left: 50%;
|
2023-05-14 07:50:43 +02:00
|
|
|
transform: translate(-50%, -50%);
|
2018-12-22 22:09:27 +01:00
|
|
|
padding: 1em;
|
|
|
|
text-align: center;
|
2023-05-14 07:50:43 +02:00
|
|
|
background-color: rgba(255, 255, 255, 0.7);
|
2018-12-22 22:09:27 +01:00
|
|
|
border-radius: 4px;
|
|
|
|
}
|
|
|
|
|
|
|
|
input[type='range'] {
|
|
|
|
width: 100%;
|
|
|
|
}
|
2023-05-14 07:50:43 +02:00
|
|
|
</style>
|