Skip to content

Commit 6c5e693

Browse files
authored
fix: output a responsive SVG (#30)
1 parent db6c373 commit 6c5e693

4 files changed

Lines changed: 84 additions & 19 deletions

File tree

bin/lts.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
const Path = require('path');
44
const { parseArgs } = require('util');
55
const Lib = require('../lib');
6+
const { writeFileSync } = require('node:fs');
7+
const Svg2png = require('svg2png');
8+
69
const now = new Date();
710
const nowString = now.toISOString().slice(0, 10);
811

@@ -104,13 +107,22 @@ const options = {
104107
data: require(Path.resolve(args.data)),
105108
queryStart: new Date(args.start),
106109
queryEnd: new Date(args.end),
107-
html: args.html ? Path.resolve(args.html) : null,
108-
svg: args.svg ? Path.resolve(args.svg) : null,
109-
png: args.png ? Path.resolve(args.png) : null,
110110
animate: args.animate,
111111
excludeMain: args.excludeMain,
112112
projectName: args.projectName,
113113
currentDateMarker: args.currentDateMarker
114114
};
115115

116-
Lib.create(options);
116+
const d3n = Lib.create(options);
117+
118+
if (args.html) {
119+
writeFileSync(Path.resolve(args.html), d3n.html());
120+
}
121+
122+
if (args.svg) {
123+
writeFileSync(Path.resolve(args.svg), d3n.svgString());
124+
}
125+
126+
if (args.png) {
127+
writeFileSync(Path.resolve(args.png), Svg2png.sync(Buffer.from(d3n.svgString())));
128+
}

lib/index.d.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { JSDOM } from "d3-node";
2+
3+
export interface VersionData {
4+
/** Start date of the version */
5+
start: string;
6+
/** LTS start date */
7+
lts?: string;
8+
/** Maintenance start date */
9+
maintenance?: string;
10+
/** End of life date */
11+
end: string;
12+
/** Codename */
13+
codename?: string;
14+
}
15+
16+
export interface ScheduleData {
17+
[version: string]: VersionData;
18+
}
19+
20+
export interface Margin {
21+
top: number;
22+
right: number;
23+
bottom: number;
24+
left: number;
25+
}
26+
27+
export interface CreateOptions {
28+
/** The schedule data object with version keys */
29+
data: ScheduleData;
30+
/** Start date for the chart query range */
31+
queryStart: Date;
32+
/** End date for the chart query range */
33+
queryEnd: Date;
34+
/** Whether to animate the bars (default: false) */
35+
animate?: boolean;
36+
/** Whether to exclude the "Main" row (default: false) */
37+
excludeMain?: boolean;
38+
/** Project name to prefix version labels */
39+
projectName: string;
40+
/** Chart margins (default: { top: 30, right: 30, bottom: 30, left: 110 }) */
41+
margin?: Margin;
42+
/** Color for the current date marker line (e.g., 'red', '#ff0000') */
43+
currentDateMarker?: string;
44+
}
45+
46+
export interface D3NodeResult {
47+
/** Get the SVG element */
48+
svgString(): string;
49+
/** Get the HTML string */
50+
html(): string;
51+
}
52+
53+
/**
54+
* Creates an D3 chart representing the Node.js LTS schedule
55+
*
56+
* @param options - Configuration options for the chart
57+
* @returns A D3Node instance
58+
*/
59+
export function create(options: CreateOptions): D3NodeResult;

lib/index.js

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
'use strict';
2-
const Fs = require('fs');
32
const D3 = require('d3');
43
const { D3Node } = require('d3-node');
54

65
const styles = `
6+
svg {
7+
width: 100%;
8+
height: auto;
9+
}
710
.current {
811
fill: #5fa04e;
912
}
@@ -92,7 +95,7 @@ function parseInput (data, queryStart, queryEnd, excludeMain, projectName) {
9295

9396

9497
function create (options) {
95-
const { queryStart, queryEnd, html, svg: svgFile, png, animate, excludeMain, projectName, margin: marginInput, currentDateMarker } = options;
98+
const { queryStart, queryEnd, animate, excludeMain, projectName, margin: marginInput, currentDateMarker } = options;
9699
const data = parseInput(options.data, queryStart, queryEnd, excludeMain, projectName);
97100
const d3n = new D3Node({ styles, d3Module: D3 });
98101
const margin = marginInput || { top: 30, right: 30, bottom: 30, left: 110 };
@@ -113,6 +116,8 @@ function create (options) {
113116
const svg = d3n.createSVG()
114117
.attr('width', width + margin.left + margin.right)
115118
.attr('height', height + margin.top + margin.bottom)
119+
.attr('viewBox', `0 0 ${width + margin.left + margin.right} ${height + margin.top + margin.bottom}`)
120+
.attr('preserveAspectRatio', 'xMinYMin meet')
116121
.append('g')
117122
.attr('id', 'bar-container')
118123
.attr('transform', `translate(${margin.left}, ${margin.top})`);
@@ -220,19 +225,7 @@ function create (options) {
220225
return +(calculateWidth(data) >= min);
221226
});
222227

223-
if (typeof html === 'string') {
224-
Fs.writeFileSync(html, d3n.html());
225-
}
226-
227-
if (typeof svgFile === 'string') {
228-
Fs.writeFileSync(svgFile, d3n.svgString());
229-
}
230-
231-
if (typeof png === 'string') {
232-
const Svg2png = require('svg2png'); // Load this lazily.
233-
234-
Fs.writeFileSync(png, Svg2png.sync(Buffer.from(d3n.svgString())));
235-
}
228+
return d3n;
236229
}
237230

238231
module.exports.create = create;

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "2.0.0",
44
"description": "Generate the Node.js LTS schedule",
55
"main": "lib/index.js",
6+
"types": "lib/index.d.ts",
67
"homepage": "https://github.com/nodejs/lts-schedule",
78
"repository": {
89
"type": "git",

0 commit comments

Comments
 (0)