The chart widget
The chart widget draws an SVG bar or line chart from a JSON file. One line of markup puts it on a page: the module script and a div with the path of the config. Every chart carries its values, the source of the numbers with the day they were read, and a copy of the data as a real table under a details block.
How a chart is put on a page
The widget is a module and a div. The script finds every div with the data-chart attribute, reads the JSON config behind it and draws the chart in place. Nothing is sent anywhere and nothing is asked of the reader: there is no form and no data is collected.
<script type="module" src="assets/chart/chart.js"></script>
<div class="ts-chart" data-chart="assets/chart/data/prices-usd.json"></div>
A page of the factory gets the same chart with one line in its data file:
"chart": "assets/chart/data/prices-usd.json"
Three charts, three real sets of numbers
The numbers below are the numbers of the research of this repository, read on 21 October 2026: the prices of the market table, the count of the locales of every interface and the price of a minute of audio in the Russian services. Every chart carries its source and a copy of the data as a table.
What a chart file has to carry
| Key | What it is |
|---|---|
type |
"bar" or "line" |
orientation |
"horizontal" (the default) or "vertical" |
xScale |
"linear" (the default) or "log" — a log axis for sizes that grow by times |
title, subtitle, description |
the head of the chart; the description is what a screen reader reads |
unit, unitPosition |
the unit of the values and where it stands: "before" or "after" |
decimals, trim |
how many decimals the values have; trim drops the zeros at the end |
locale |
the language of the numbers: "en-US", "ru-RU" |
xLabel, yLabel |
the names of the two axes |
source, accessed |
where the numbers come from and the day they were read — both are required |
table |
the caption and the columns of the table copy |
series |
the name, the color and the points of every series |
A whole config of a bar chart, with the numbers of the first chart of this page:
{
"type": "bar",
"orientation": "horizontal",
"title": "The cheapest paid plan of each service, in dollars a month",
"unit": "$",
"unitPosition": "before",
"decimals": 2,
"trim": true,
"locale": "en-US",
"xLabel": "US dollars per month",
"yLabel": "Service",
"source": "the public pricing page of every service",
"accessed": "2026-10-21",
"table": {
"caption": "The cheapest paid plan of each service, paid yearly",
"columns": ["Service", "Price a month", "Note"]
},
"series": [
{
"name": "Price a month",
"points": [
{ "label": "Notta", "value": 8.17, "note": "Pro, paid yearly" }
]
}
]
}
What the widget promises
- The chart is an SVG with role="img", a title and a description; the numbers are written in the drawing and not only in the colors.
- Every chart has a copy of its data in a real table with a caption, under a details block. The table is in the DOM, so it is read by a screen reader and by the search engines.
- The source of the numbers and the day they were read are printed under the chart and under the table: "Source: …, accessed 2026-10-21".
- A chart without a source and without a date is not drawn at all: the widget refuses it and says why.
- The bars grow when the chart comes into the window, with a transform and an opacity. Nothing else moves.
- With prefers-reduced-motion: reduce the animation is off and the chart is drawn at once. The widget also listens for the change of the setting while the page is open.
Where the numbers of this page come from
| File of the config | Built from |
|---|---|
assets/chart/data/prices-usd.json |
research/comparison-table.csv — the column price_per_month of every service |
assets/chart/data/locales.json |
research/geo/data/international-players.json — ui_locales_count of every service |
assets/chart/data/price-per-minute.json |
research/competitors/data/players.json — the price plans of the Russian services |
The builder reads the research files and stops when a number cannot be found in them: a number that leaves the research without the charts being rebuilt does not reach the page. The files of the research are in the repository of the project, under research/.
Questions about the widget
How do I put a chart on a page?
One line of markup: the module script and a div with the path of the JSON config. The widget finds every div with the data-chart attribute on the page and draws it. A page of the factory gets the same chart with one line in its data file.
Where do the numbers of the charts come from?
From the JSON config of the chart. On this page they are built by tools/chart/build_data.py from the research of this repository: the market table, the price plans of the Russian services and the count of the locales of every interface.
Is the chart readable without JavaScript?
The numbers are in the DOM: the table under the details block is a real table with a caption. The drawing needs JavaScript; without it the page keeps the text, the source line and the numbers of the table.
Does the chart move?
The bars grow when the chart comes into the window and the lines draw themselves. With prefers-reduced-motion: reduce there is no movement at all: the chart is drawn at once, in its final shape.