Chart
Example:
Code example:
from typing import Any
from htmy import ComponentType, html
from htmui.basecoat import chart
def example() -> ComponentType:
return html.div(
chart.chart(id="linux-market-share-chart", config=_chart_config),
class_="w-full max-w-2xl",
)
_chart_config: dict[str, Any] = {
"type": "line",
"labelKey": "year",
"legend": True,
"data": [
{"year": "2016", "share": 1.2},
{"year": "2017", "share": 1.4},
{"year": "2018", "share": 1.3},
{"year": "2019", "share": 1.6},
{"year": "2020", "share": 1.8},
{"year": "2021", "share": 1.5},
{"year": "2022", "share": 2.0},
{"year": "2023", "share": 3.0},
{"year": "2024", "share": 4.5},
{"year": "2025", "share": 6.5},
{"year": "2026", "share": 9.0},
{"year": "2027", "share": 11.5},
{"year": "2028", "share": 13.5},
{"year": "2029", "share": 15.5},
],
"series": {
"share": {
"label": "Linux desktop market share",
"color": "var(--chart-1)",
"surface": "gradient",
"dataset": {
"borderWidth": 1.5,
"tension": 0.35,
"pointRadius": 0,
},
},
},
}
Component implementation:
For more details, see the BasecoatUI documentation.
import json
from typing import Any, Protocol
from htmy import ComponentType, Fragment, PropertyValue, SafeStr, html
__version__ = "0.2.0"
__framework__ = "BasecoatUI"
__framework_version__ = "1"
__framework_url__ = "https://basecoatui.com/components/chart/"
js = SafeStr(
'<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1/dist/js/chart.min.js" defer></script>'
)
chart_js = SafeStr('<script src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.umd.min.js"></script>')
"""Chart.js CDN script."""
class ChartInitScriptFactory(Protocol):
"""
Callable protocol for building a chart initialization script element
from a canvas ID and a chart config.
"""
def __call__(self, id: str, config: dict[str, Any], /) -> ComponentType:
"""
Returns the script element that initializes the chart for
the given ID with the given chart config.
"""
...
class handle_chart_init:
@staticmethod
def default(id: str, config: dict[str, Any], /) -> ComponentType:
"""
Default `ChartInitScriptFactory` which initializes the chart once
the Basecoat runtime is ready.
"""
config_json = json.dumps(config, separators=(",", ":")).replace("</", "<\\/")
return html.script(
SafeStr(
f"""(() => {{
const canvas = document.getElementById({json.dumps(id)});
if (!canvas) return;
const init = () => window.basecoat?.chart?.(canvas, {config_json});
if (document.readyState === "loading") {{
document.addEventListener("DOMContentLoaded", init, {{ once: true }});
}} else {{
init();
}}
}})();"""
)
)
def chart(
*,
id: str,
config: dict[str, Any] | None = None,
class_: str | None = None,
script: ChartInitScriptFactory | None = handle_chart_init.default,
**kwargs: PropertyValue,
) -> ComponentType:
"""
Chart.js canvas themed with Basecoat defaults.
Arguments:
id: Canvas element ID.
config: Optional JSON-serializable config for `basecoat.chart()`.
See the Basecoat Chart documentation for details.
class_: Extra CSS classes for the canvas element.
script: Optional callback that receives the canvas ID and `config` and
returns the initialization script element. Defaults to
`handle_chart_init.default`.
**kwargs: Extra attributes for the canvas element.
"""
canvas = html.canvas(
id=id,
class_=class_,
**kwargs,
)
if config is None or script is None:
return canvas
return Fragment(canvas, script(id, config))