SVG on screen
Two folders work on rendered SVGGraphicsElements, whatever the groups and transforms around each element, with the browser's own SVG API (transform.baseVal, createSVGTransform, getScreenCTM, getBBox):
svg-transformmoves, turns, mirrors and scales elements, and finds their anchors;svg-shapecreates thedof gauges around elements: arcs, ticks, pies and bars.
Orders, applied one after the other
applySvgTransforms(element, orders) applies a list of orders, in order, each on what the previous ones give. Each order adds its own transform at the end of the transform list; the transforms already there stay.
applySvgTransforms(symbol, [
svgFlipTo(false), // not mirrored on screen
svgRotateTo(0), // upright on screen
svgPlaceOn(target), // its center on the center of the target, even in another group
svgTranslateBy(0, -10), // then 10 units up, along its own axes (upright now)
]);An order is created with its first values. Keep it in a constant to change its values later with set, with the same arguments as its function: only its own transform is updated, from what the element shows without it. The other orders do not move, so put them in the order you need.
const rotation = svgRotateBy(0, 'center', hub); // around the center of the hub, in another group
applySvgTransforms(needle, [svgPlaceOn(hub, 'center', 'bottom'), rotation]);
rotation.set(3, 'center', hub); // 3° from where it was drawn
rotation.set(90, 'center', hub); // 90° from where it was drawn, not 93°| Order | Effect |
|---|---|
svgRotateBy(angle, anchor?, reference?) | turns it by an angle from its position before the order, clockwise on screen |
svgRotateTo(angle, anchor?, reference?) | turns it to an absolute angle on screen: svgRotateTo(0) straightens it |
svgFlipTo(isFlipped?, axis?, anchor?) | makes it mirrored or not, as seen on screen: svgFlipTo(false) unmirrors it |
svgScaleBy(scaleX, scaleY?, anchor?) | enlarges it in its own axes, from an anchor: 'left' grows to the right |
svgTranslateBy(dx, dy) | moves it along its own axes: turned by 90°, "right" goes down |
svgPlaceOn(reference, referenceAnchor?, anchor?) | puts one of its anchors on an anchor of another element |
The rotations turn around an anchor of the element itself, or of another element in any group. clearSvgTransforms(element) empties the list.
The 9 anchors
Every element has 9 anchors: 'top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'. getSvgAnchorPoint gives one on screen, getSvgAnchorPointIn in the coordinates of another element.
Gauges drawn around elements
The createSvg…Path functions of svg-shape return the d of a path, around the center of another element or along its box, in any group. They only read the element you give them, target: the path is written in its coordinates, usually the <path> that receives it. Convert values with ratio, remap or clamp from math.
const arc = { center: hub, radius: 40, startAngle: -135, sweepAngle: 270 };
track.setAttribute('d', createSvgArcPath(track, arc)); // the track
zone.setAttribute('d', createSvgArcPath(zone, { ...arc, startAngle: 81, sweepAngle: 54 })); // a threshold zone: a thick stroke
majorTicks.setAttribute('d', createSvgArcTicksPath(majorTicks, arc, 6, 8)); // 7 ticks
remaining.setAttribute('d', createSvgPiePath(remaining, { ...arc, startAngle: 0, sweepAngle: 360 * ratio(left, total) }));
const labelPoint = getSvgArcPoint(labels, { ...arc, radius: 28 }, 0.5);
const bar = { element: barTrack, direction: 'up' } as const;
level.setAttribute('d', createSvgBarRangePath(level, bar, 0, ratio(value, max))); // the fill level
barRedZone.setAttribute('d', createSvgBarRangePath(barRedZone, bar, 0.8, 1)); // the top 20 %
barTicks.setAttribute('d', createSvgBarTicksPath(barTicks, bar, 5, 12));