Beispiel:SVG-10-arcs.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

<!DOCTYPE html> <html lang="de" > <head>

 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <link rel="stylesheet" media="screen" href="./Beispiel:Grundlayout.css">
 <title>Arc Bogen-Generator</title>

<style>

  1. code {
 display: block;
 font: bold 2em monospace;
 padding: 1em 2em;
 color: #333;

}

  1. code::selection {
 background: steelblue;
 color: #fff;

} .variant { fill:none;

 stroke: #337599;
 stroke-width: 1;
 stroke-dasharray: 1 1;

}

.current {

 stroke-width: 5;
 stroke: #c82f04;
 stroke-linecap: round;
 fill: none;

}

  1. grid path {

stroke:steelblue; stroke-dasharray:1 1; stroke-width:0.5; }

circle {

 stroke-width: 1;
 stroke: steelblue;
 fill: hsl(201 50% 75%);

} circle:hover {

 fill: steelblue;
 cursor: move;

}

  1. p1 {

fill:gold; }

  1. p1:hover {fill:orange;}


output { color:steelBlue; }

text {font-family:sans-serif;text-anchor:middle;font-size:12px;}

.inputs { display: grid; grid-template-columns: 30em 15em; gap: 1em; } fieldset { display: grid; grid-template-columns: 8em 1fr; gap: 1em; }


label { vertical-align:middle; display: inline-block; }

label::after { content: ":"; }

</style>

</head>

<body>

 <path d="<output id="path" contenteditable>M100,100 A100,100 0 1,1 200,200</output>"/>
   <form class="inputs">
   	<fieldset>
       <label for="rx">Radius X</label><input id="rx" type="range" min="0" max="150"/>
       <label for="ry">Radius Y</label><input id="ry" type="range" min="0" max="150"/>
     </fieldset>
     <fieldset>  
       <label for="laf">Large arc flag</label><input id="laf" type="checkbox"/>
       <label for="sf">Sweep flag</label><input id="sf" type="checkbox"/>
     </fieldset>  
   </form>  
    <label> 
 <input type="checkbox" id="relative">
 Relative Pfad-Kommandos

</label>

<svg id="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 999 599" > <defs> <pattern id="grid" patternUnits="userSpaceOnUse" width="10" height="10" x="0" y="0"> <path d="M0,0 v10 h10" fill="none" /> </pattern> </defs> <rect id="background" width="100%" height="100%" fill="url(#grid)"></rect> <g id="main"> <g class="handle-group" data-label="P1" transform="translate(100 100)">

 		<circle id="p1" class="handle" r="9" />
 		<text dx="-2em" dy="-1.5em">Startpunkt</text>

</g> <g class="handle-group" data-label="P2" transform="translate(200 200)">

 		<circle id="p2" class="handle" r="9" />
 		<text dx="3em" dy="1.5em">Endpunkt</text>

</g>

<g class="arc-variants" aria-hidden="true"> <path class="arc variant" data-laf="0" data-sf="0" /> <path class="arc variant" data-laf="0" data-sf="1" /> <path class="arc variant" data-laf="1" data-sf="0" /> <path class="arc variant" data-laf="1" data-sf="1" /> </g> <path id="arc" class="arc current" d="M100,100 A100,100 0 1,1 200,200" />

</g> </svg>

<script> const svg = document.getElementById('svg');

const output = document.getElementById('path'); const relativeToggle = document.getElementById('relative');

const rxInput = document.getElementById('rx'); const ryInput = document.getElementById('ry'); const lafInput = document.getElementById('laf'); const sfInput = document.getElementById('sf');

const p1 = document.querySelector('#p1').parentElement; const p2 = document.querySelector('#p2').parentElement;

const arc = document.getElementById('arc'); const variants = document.querySelectorAll('.arc.variant');

let dragging = null;

/* --------------------------------------------------

  Helpers

*/

function getPos(g) {

 const t = g.transform.baseVal.consolidate().matrix;
 return { x: Math.round(t.e), y: Math.round(t.f) };

}

function setPos(g, x, y) {

 g.setAttribute('transform', `translate(${x} ${y})`);

}

function buildArc({ p1, p2, rx, ry, laf, sf, relative }) {

 if (relative) {
   return `m${p1.x},${p1.y} a${rx},${ry} 0 ${laf},${sf} ${p2.x - p1.x},${p2.y - p1.y}`;
 }
 return `M${p1.x},${p1.y} A${rx},${ry} 0 ${laf},${sf} ${p2.x},${p2.y}`;

}

/* --------------------------------------------------

  Update everything

*/

function update() {

 const start = getPos(p1);
 const end   = getPos(p2);
 const rx  = +rxInput.value;
 const ry  = +ryInput.value;
 const laf = lafInput.checked ? 1 : 0;
 const sf  = sfInput.checked  ? 1 : 0;
 const rel = relativeToggle.checked;
 // main arc
 const d = buildArc({ p1: start, p2: end, rx, ry, laf, sf, relative: rel });
 arc.setAttribute('d', d);
 output.textContent = d;
 // variants
 variants.forEach(v => {
   const vLaf = v.dataset.laf;
   const vSf  = v.dataset.sf;
   v.setAttribute(
     'd',
     buildArc({
       p1: start,
       p2: end,
       rx, ry,
       laf: vLaf,
       sf: vSf,
       relative: false
     })
   );
 });

}

/* --------------------------------------------------

  Drag handling

*/

svg.addEventListener('pointerdown', e => {

 const g = e.target.closest('.handle-group');
 if (!g) return;
 dragging = g;
 svg.setPointerCapture(e.pointerId);

});

svg.addEventListener('pointermove', e => {

 if (!dragging) return;
 const pt = svg.createSVGPoint();
 pt.x = e.clientX;
 pt.y = e.clientY;
 const svgPt = pt.matrixTransform(svg.getScreenCTM().inverse());
 setPos(dragging, Math.round(svgPt.x), Math.round(svgPt.y));
 update();

});

svg.addEventListener('pointerup', () => dragging = null); svg.addEventListener('pointerleave', () => dragging = null);

/* --------------------------------------------------

  Inputs

*/

[rxInput, ryInput, lafInput, sfInput, relativeToggle]

 .forEach(el => el.addEventListener('input', update));

/* --------------------------------------------------

  Output editing

*/

output.addEventListener('input', () => {

 const d = output.textContent.trim();
 arc.setAttribute('d', d);
 const match = d.match(
   /[Mm]\s*([\d.-]+),([\d.-]+)\s*[Aa]\s*([\d.-]+),([\d.-]+)\s*0\s*([01]),([01])\s*([\d.-]+),([\d.-]+)/
 );
 if (!match) return;
 const [, x1, y1, rx, ry, laf, sf, x2, y2] = match.map(Number);
 setPos(p1, x1, y1);
 setPos(p2, x2, y2);
 rxInput.value = rx;
 ryInput.value = ry;
 lafInput.checked = !!laf;
 sfInput.checked  = !!sf;
 update();

});

update(); </script>


</body></html>