From 11edb1890b59728fb92083cb516b15542cd5e8fd Mon Sep 17 00:00:00 2001 From: Chris Burnell Date: Tue, 6 Feb 2024 19:03:35 +0800 Subject: [PATCH] improve a11y of SVG elements; support server-rendered hydration; allow for attributes to override set CSS variables --- demo.html | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- svg-sparkline.js | 66 ++++++++++++++++++++++++++++----------------- 3 files changed, 112 insertions(+), 26 deletions(-) diff --git a/demo.html b/demo.html index e2d85e8..ae04143 100644 --- a/demo.html +++ b/demo.html @@ -80,5 +80,75 @@

Defined width and height

+

Server-rendered and hydrated

+

+ + Start + + Sparkline ranging from 1 to 10. + + + + End + +

+ diff --git a/package.json b/package.json index 573219a..214f360 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chrisburnell/svg-sparkline", - "version": "1.0.4", + "version": "1.0.5", "description": "A Web Component that builds an SVG Sparkline.", "main": "svg-sparkline.js", "scripts": { diff --git a/svg-sparkline.js b/svg-sparkline.js index ab33f80..1e8cc8b 100644 --- a/svg-sparkline.js +++ b/svg-sparkline.js @@ -19,6 +19,9 @@ class SVGSparkline extends HTMLElement { padding: var(--svg-sparkline-padding, 0.375rem); overflow: visible; } + svg[aria-hidden] { + pointer-events: none; + } span { padding-inline: var(--svg-sparkline-padding, 0.375rem); } @@ -82,18 +85,22 @@ class SVGSparkline extends HTMLElement { this.values = this.getAttribute("values").split(",") this.width = parseFloat(this.getAttribute("width")) || 200 this.height = parseFloat(this.getAttribute("height")) || 36 - this.color = this.getAttribute("color") || "currentColor" - this.curve = this.getAttribute("curve") === "true" + this.color = this.getAttribute("color") + this.curve = this.hasAttribute("curve") && this.getAttribute("curve") !== "false" this.endpoint = this.getAttribute("endpoint") !== "false" - this.endpointColor = this.getAttribute("endpoint-color") || this.color + this.endpointColor = this.getAttribute("endpoint-color") this.endpointWidth = parseFloat(this.getAttribute("endpoint-width")) || 6 - this.fill = this.getAttribute("fill") === "true" - this.gradient = this.getAttribute("gradient") === "true" - this.gradientColor = this.getAttribute("gradient-color") || this.getAttribute("fill-color") || this.color + this.fill = this.hasAttribute("fill") && this.getAttribute("fill") !== "false" + this.gradient = this.hasAttribute("gradient") && this.getAttribute("gradient") !== "false" + this.gradientColor = this.getAttribute("fill-color") || this.getAttribute("gradient-color") this.lineWidth = parseFloat(this.getAttribute("line-width")) || 2 this.startLabel = this.getAttribute("start-label") this.endLabel = this.getAttribute("end-label") + const color = this.color || `var(--svg-sparkline-color, currentColor)` + const endpointColor = this.endpointColor || `var(--svg-sparkline-endpoint-color, ${color})` + const gradientColor = this.gradientColor || `var(--svg-sparkline-fill-color, var(--svg-sparkline-gradient-color, ${color}))` + let content = [] if (this.startLabel) { @@ -101,7 +108,8 @@ class SVGSparkline extends HTMLElement { } content.push(` - + + Sparkline ranging from ${this.getMinY(this.values)} to ${this.getMaxY(this.values)}. `) if (this.gradient || this.fill) { @@ -109,13 +117,13 @@ class SVGSparkline extends HTMLElement { content.push(` - + `) @@ -124,7 +132,7 @@ class SVGSparkline extends HTMLElement { content.push(` - + `) } @@ -181,7 +189,12 @@ class SVGSparkline extends HTMLElement { initTemplate() { if (this.shadowRoot) { - this.shadowRoot.innerHTML = this.render() + if (this.innerHTML.trim() === "") { + this.shadowRoot.innerHTML = this.render() + } else { + this.shadowRoot.innerHTML = this.innerHTML + this.innerHTML = "" + } return } @@ -283,20 +296,23 @@ class SVGSparkline extends HTMLElement { return Math.max(...values) - values[values.length - 1] + 1 } - getHighestY(values) { - return Math.max(...values) + 2 + getMinY(values) { + return Math.min(...values) + } + + getMaxY(values) { + return Math.max(...values) + } + + getAdjustedMaxY(values) { + return this.getMaxY(values) + 2 } makeID(length) { - let result = "" - const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - const charactersLength = characters.length - let counter = 0 - while (counter < length) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)) - counter += 1 - } - return result + const SEQUENCE = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + return Array.from({ length: length }).reduce((id, _) => { + return id + SEQUENCE.charAt(Math.floor(Math.random() * SEQUENCE.length)) + }, "") } }