UNPKG

@thi.ng/hiccup-svg

Version:

SVG element functions for @thi.ng/hiccup & related tooling

316 lines (243 loc) 16.9 kB
<!-- This file is generated - DO NOT EDIT! --> <!-- Please see: https://codeberg.org/thi.ng/umbrella/src/branch/develop/CONTRIBUTING.md#changes-to-readme-files --> # ![@thi.ng/hiccup-svg](https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/banners/thing-hiccup-svg.svg?b89d2384) [![npm version](https://img.shields.io/npm/v/@thi.ng/hiccup-svg.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-svg) ![npm downloads](https://img.shields.io/npm/dm/@thi.ng/hiccup-svg.svg) [![Mastodon Follow](https://img.shields.io/mastodon/follow/109331703950160316?domain=https%3A%2F%2Fmastodon.thi.ng&style=social)](https://mastodon.thi.ng/@toxi) > [!NOTE] > This is one of 216 standalone projects. LLM-free, human-made and > cared for software, maintained as part of the > [@thi.ng/umbrella](https://codeberg.org/thi.ng/umbrella/) ecosystem and > anti-framework. > > 🚀 Please help me to work full-time on these projects by [sponsoring > me](https://codeberg.org/thi.ng/umbrella/src/branch/develop/CONTRIBUTING.md#donations). > Thank you! ❤️ - [About](#about) - [Important](#important) - [SVG conversion of @thi.ng/geom & @thi.ng/hiccup-canvas shape trees](#svg-conversion-of-thinggeom--thinghiccup-canvas-shape-trees) - [Automatic attribute conversions](#automatic-attribute-conversions) - [Colors](#colors) - [Transforms](#transforms) - [Status](#status) - [Installation](#installation) - [Dependencies](#dependencies) - [Usage examples](#usage-examples) - [API](#api) - [Authors](#authors) - [License](#license) ## About SVG element functions for [@thi.ng/hiccup](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/hiccup) & related tooling. ### Important The functions provided here do produce valid hiccup elements, but since none of them make use of (or support) the global hiccup / hdom context object, they can ONLY be invoked directly, i.e. they MUST be called like: ```ts import { circle, svg } from "@thi.ng/hiccup-svg"; // correct (direct invocation) svg({}, circle([0, 0], 100, { fill: "red" })); // incorrect / unsupported (lazy evaluation) [svg, {}, [circle, [0, 0], 100, { fill: "red" }]] ``` ### SVG conversion of @thi.ng/geom & @thi.ng/hiccup-canvas shape trees Since v2.0.0 this package provides a conversion utility to translate the more compact syntax used by [@thi.ng/geom](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/geom) and [@thi.ng/hiccup-canvas](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/hiccup-canvas) shape trees (designed for more performant realtime / canvas drawing) into a SVG serializable hiccup format. The [`convertTree()`](https://docs.thi.ng/umbrella/hiccup-svg/functions/convertTree.html) function takes a pre-normalized hiccup tree of geom/hiccup-canvas shape definitions and recursively converts it into an hiccup flavor which is ready for SVG serialization (i.e. using stringified geometry attribs). This conversion also involves translation & re-organization of various attributes. This function returns a new tree. The original remains untouched, as will any unrecognized tree / shape nodes (those will be transferred as-is to the result tree). Conversion can be explicitly disabled for individual elements (tree branches) by setting the `__convert: false` control attribute. See example below. Tree conversion can be implicitly triggered by providing a `__convert: true` attribute to the root `svg()` element. This conversion also supports the `__prec` control attribute which can be used (on a per-shape basis) to control the formatting used for various floating point values (except color conversions). Child shapes (of a group) inherit the precision setting of their parent. ```ts import { svg } from "@thi.ng/hiccup-svg"; // create SVG root element and convert body svg( { width: 100, height: 100, __convert: true, __prec: 3 }, ["rect", { fill: [1, 0, 0] }, [1.2345, -1.2345], 100, 100] ) // [ // 'svg', // { // version: '1.1', // xmlns: 'http://www.w3.org/2000/svg', // 'xmlns:xlink': 'http://www.w3.org/1999/xlink', // width: 100, // height: 100 // }, // ['rect', { fill: '#ff0000', x: '1.234', y: '-1.234', width: '100', height: '100' }] // ] ``` ### Automatic attribute conversions #### Colors Since v3.1.0: Color conversions are only applied to `fill` and `stroke` attributes and color stops provided to `linearGradient()`, `radialGradient()` ##### String String color attribs prefixed with `$` are replaced with `url(#...)` refs (e.g. to refer to gradients), else used as is (untransformed) ##### Number Interpreted as ARGB hex value: `{ fill: 0xffaabbcc }` => `{ fill: "#aabbcc" }` ##### Array Interpreted as float RGB(A): `{ fill: [1, 0.8, 0.6, 0.4] }` => `{ fill: "rgba(255,204,153,0.40)" }` ##### [@thi.ng/color](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/color) values Converted to CSS color strings: `{ fill: hcya(0.1666, 1, 0.8859) }` => `{ fill: "#ffff00" }` #### Transforms (i.e. `transform`, `rotate`, `scale`, `translate`) If an element has a `transform` attrib, conversion of the other transformation attribs will be skipped, else the values are assumed to be either strings or: - `transform`: 6-element numeric array ([2x3 matrix in column major order](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform#Matrix)) - `translate`: 2-element array - `rotate`: number (angle in radians) - `scale`: number (uniform scale) or 2-elem array If no `transform`, but others are given, the resulting transformation order will always be TRS. Any string values will be used as-is and therefore need to be complete, e.g. `{ rotate: "rotate(60)" }` ## Status **STABLE** - used in production [Search or submit any issues for this package](https://codeberg.org/thi.ng/umbrella/issues?q=%5Bhiccup-svg%5D) ## Installation ```bash yarn add @thi.ng/hiccup-svg ``` ESM import: ```ts import * as svg from "@thi.ng/hiccup-svg"; ``` Browser ESM import: ```html <script type="module" src="https://esm.run/@thi.ng/hiccup-svg"></script> ``` [JSDelivr documentation](https://www.jsdelivr.com/) For Node.js REPL: ```js const svg = await import("@thi.ng/hiccup-svg"); ``` Package sizes (brotli'd, pre-treeshake): ESM: 2.53 KB ## Dependencies - [@thi.ng/api](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/api) - [@thi.ng/checks](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/checks) - [@thi.ng/color](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/color) - [@thi.ng/prefixes](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/prefixes) Note: @thi.ng/api is in _most_ cases a type-only import (not used at runtime) ## Usage examples 17 projects in this repo's [/examples](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples) directory are using this package: | Screenshot | Description | Live demo | Source | |:-------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:---------------------------------------------------------|:----------------------------------------------------------------------------------------------| | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/color-contrast.avif" width="240"/> | Tool to interactively compute & visualize color contrasts against WCAG threshold | [Demo](https://demo.thi.ng/umbrella/color-contrast/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/color-contrast) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/color-themes.png" width="240"/> | Probabilistic color theme generator | [Demo](https://demo.thi.ng/umbrella/color-themes/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/color-themes) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/commit-heatmap.png" width="240"/> | Heatmap visualization of this mono-repo's commits | | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/commit-heatmap) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/crypto-chart.png" width="240"/> | Basic crypto-currency candle chart with multiple moving averages plots | [Demo](https://demo.thi.ng/umbrella/crypto-chart/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/crypto-chart) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/dominant-colors.png" width="240"/> | Color palette generation via dominant color extraction from uploaded images | [Demo](https://demo.thi.ng/umbrella/dominant-colors/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/dominant-colors) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/gesture-analysis.png" width="240"/> | Mouse gesture / stroke analysis, simplification, corner detection | [Demo](https://demo.thi.ng/umbrella/gesture-analysis/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/gesture-analysis) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/hdom-canvas/hdom-canvas-shapes-results.png" width="240"/> | Various hdom-canvas shape drawing examples & SVG conversion / export | [Demo](https://demo.thi.ng/umbrella/hdom-canvas-shapes/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/hdom-canvas-shapes) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/package-stats.png" width="240"/> | CLI util to visualize umbrella pkg stats | | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/package-stats) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/pointfree-svg.png" width="240"/> | Generate SVG using pointfree DSL | | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/pointfree-svg) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/poly-spline.png" width="240"/> | Polygon to cubic curve conversion & visualization | [Demo](https://demo.thi.ng/umbrella/poly-spline/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/poly-spline) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/rdom-reactive-svg.jpg" width="240"/> | Animated SVG elements with reactive attributes | [Demo](https://demo.thi.ng/umbrella/rdom-reactive-svg/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/rdom-reactive-svg) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/rdom-svg-nodes.png" width="240"/> | rdom powered SVG graph with draggable nodes | [Demo](https://demo.thi.ng/umbrella/rdom-svg-nodes/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/rdom-svg-nodes) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/rstream-grid.jpg" width="240"/> | Interactive grid generator, SVG generation & export, undo/redo support | [Demo](https://demo.thi.ng/umbrella/rstream-grid/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/rstream-grid) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/svg-resample.png" width="240"/> | SVG path parsing & dynamic resampling | [Demo](https://demo.thi.ng/umbrella/svg-resample/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/svg-resample) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/svg-waveform.jpg" width="240"/> | Additive waveform synthesis & SVG visualization with undo/redo | [Demo](https://demo.thi.ng/umbrella/svg-waveform/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/svg-waveform) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/viz-ridge-lines.avif" width="240"/> | Interactive ridge-line plot | [Demo](https://demo.thi.ng/umbrella/viz-ridge-lines/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/viz-ridge-lines) | | <img src="https://codeberg.org/thi.ng/umbrella/media/branch/develop/assets/examples/viz-scatter-plot.avif" width="240"/> | Interactive scatter & line plot of low-discrepancy samples | [Demo](https://demo.thi.ng/umbrella/viz-scatter-plot/) | [Source](https://codeberg.org/thi.ng/umbrella/src/branch/develop/examples/viz-scatter-plot) | ## API [Generated API docs](https://docs.thi.ng/umbrella/hiccup-svg/) ```ts import * as svg from "@thi.ng/hiccup-svg"; import { serialize } from "@thi.ng/hiccup"; import * as fs "node:fs"; fs.writeFileSync( "hello.svg", serialize( svg.svg( { width: 100, height: 100 }, svg.defs(svg.linearGradient("grad", [0, 0], [0, 1], [[0, "red"], [1, "blue"]])), svg.circle([50, 50], 50, { fill: "url(#grad)" }), svg.text([50, 55], "Hello", { fill: "white", "text-anchor": "middle" }) ) )); ``` Minimal example showing SVG conversion of a hiccup-canvas scene (also see [@thi.ng/geom](https://codeberg.org/thi.ng/umbrella/src/branch/develop/packages/geom) for another compatible approach): ```ts import { svg } from "@thi.ng/hiccup-svg"; import { serialize } from "@thi.ng/hiccup"; import { writeFileSync } from "node:fs"; // scene tree defined for hiccup-canvas const scene = [ ["defs", {}, ["radialGradient", { id: "bg", from: [150, 280], to: [150, 300], r1: 300, r2: 100 }, [[0, "#07f"], [0.5, "#0ef"], [0.8, "#efe"], [1, "#af0"]]], ["radialGradient", { id: "sun", from: [110, 120], to: [110, 120], r1: 5, r2: 50 }, [[0, "#fff"], [1, "rgba(255,255,192,0)"]]] ], ["circle", { fill: "$bg" }, [150, 150], 130], ["circle", { fill: "$sun" }, [110, 120], 50], ]; writeFileSync( "radialgradient.svg", serialize( svg({ width: 300, height: 300, __convert: true }, scene) ) ); ``` Result: ```xml <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300"> <defs> <radialGradient id="bg" fx="150.00" fy="280.00" cx="150.00" cy="300.00" fr="300.00" r="100.00" gradientUnits="userSpaceOnUse"> <stop offset="0" stop-color="#07f"/> <stop offset="0.5" stop-color="#0ef"/> <stop offset="0.8" stop-color="#efe"/> <stop offset="1" stop-color="#af0"/> </radialGradient> <radialGradient id="sun" fx="110.00" fy="120.00" cx="110.00" cy="120.00" fr="5.00" r="50.00" gradientUnits="userSpaceOnUse"> <stop offset="0" stop-color="#fff"/> <stop offset="1" stop-color="rgb(255,255,192)" stop-opacity="0"/> </radialGradient> </defs> <circle cx="150.00" cy="150.00" r="130.00" fill="url(#bg)"/> <circle cx="110.00" cy="120.00" r="50.00" fill="url(#sun)"/> </svg> ``` ## Authors - [Karsten Schmidt](https://thi.ng) If this project contributes to an academic publication, please cite it as: ```bibtex @misc{thing-hiccup-svg, title = "@thi.ng/hiccup-svg", author = "Karsten Schmidt", note = "https://thi.ng/hiccup-svg", year = 2016 } ``` ## License &copy; 2016 - 2026 Karsten Schmidt // Apache License 2.0