
Description
This interactive SVG chart visualizes time series data as a line chart, bar chart, or both.
It features:
- Chart type switching (Line, Bar, Both)
- Polynomial trend line (degree selectable)
- Customizable decimal places
- Adjustable chart offsets (left, right, y)
- Show/hide data point circles and adjust their size
- Custom date formats for X-axis labels
- Dynamic X-axis label spacing
- Tooltip on hover
- Min/Max/Avg stats with corresponding dates
- Responsive design
- Manual and auto update options
Download
Demo
Description of Function Variables
Variable / Option | Type | Description |
---|---|---|
container | Element | The DOM element where the chart and controls will be rendered. |
data | Array | The main data array, typically an array of [timestamp, value] pairs. |
N | Number | Number of data points (often data.length ). |
now | Number | The base timestamp (e.g., Date.now() ). |
chartType | String | Type of chart to display: "line" , "bar" , or "both" . |
leftOffset | Number | Space (in px) between the left edge and the chart area. |
rightOffset | Number | Space (in px) between the right edge and the chart area. |
yOffset | Number | Vertical offset (in px) for the chart area. |
polyDegree | Number | Degree of the polynomial for the trend line (1=linear, 2=quadratic, etc.). |
decimals | Number | Number of decimal places to show for values and axis labels. |
showCircles | Boolean | Whether to display circles at data points. |
circleSize | Number | Radius of the data point circles. |
dateFormatMode | String | Format for X-axis labels: "datetime" , "date" , "month" , "year" , etc. |
headerLabel | String | Title or label for the chart (e.g., “Living Room”). |
units | String | Units for the Y-axis and tooltips (e.g., "°C" ). |
frontColorStops | Array | Array of {value, color} objects for gradient coloring based on value. |
minVal, maxVal, avgVal | Number | Minimum, maximum, and average values in the data. |
minTime, maxTime, avgTime | Number | Timestamps corresponding to min, max, and avg values. |
tooltipId | String | The ID of the tooltip element for mouseover events. |
renderChart() | Function | The function that draws or updates the chart based on current settings and data. |
Example Usage in a Function
function createAdvancedChart(container, options) {
// options.data: array of [timestamp, value]
// options.chartType: "line", "bar", or "both"
// options.leftOffset, options.rightOffset, options.yOffset
// options.polyDegree, options.decimals, options.showCircles, options.circleSize
// options.dateFormatMode, options.headerLabel, options.units, options.frontColorStops
// ...etc.
// Use these options to render the chart and controls
}
Typical Data Structure Example
let data = [
[timestamp1, value1],
[timestamp2, value2],
...
];
Summary Table
Variable | Example Value | Description |
---|---|---|
data | [[ts1, 12], [ts2, 15]] | Chart data points |
chartType | "line" | Chart type |
leftOffset | 60 | Left margin in px |
rightOffset | 24 | Right margin in px |
yOffset | 0 | Vertical offset in px |
polyDegree | 2 | Polynomial trend degree |
decimals | 1 | Number of decimals |
showCircles | true | Show data point circles |
circleSize | 7 | Circle radius |
dateFormatMode | "datetime" | X-axis label format |
headerLabel | "Living Room" | Chart title |
units | "°C" | Y-axis units |
frontColorStops | [{value:-7,color:"#2196f3"}, ...] | Value-based color stops |
Demo Snippet
A minimal working example with chart type, offsets, and update button:
<!DOCTYPE html>
<html>
<head>
<title>Chart Demo</title>
<style>
.chart-controls { text-align: center; margin-bottom: 24px; }
.chart-container { background: #fff; border-radius: 18px; box-shadow: 0 4px 24px 0 rgba(0,0,0,0.10); margin: 0 auto; max-width: 900px; padding: 20px; }
.update-btn { font-size:18px; padding:6px 24px; border-radius:6px; border:1px solid #2196f3; background:#2196f3; color:#fff; cursor:pointer; margin-bottom: 32px; }
</style>
</head>
<body>
<div class="chart-controls">
<button id="btn-line" class="active">Line Chart</button>
<button id="btn-bar">Bar Chart</button>
<button id="btn-both">Both</button>
<label>Left offset: <input id="x-offset" type="number" value="60" min="0" max="200" style="width:50px;"></label>
<label>Right offset: <input id="right-offset" type="number" value="24" min="0" max="200" style="width:50px;"></label>
<label>Y offset: <input id="y-offset" type="number" value="0" min="0" max="200" style="width:50px;"></label>
</div>
<div style="text-align:center;">
<button id="update-chart" class="update-btn">Update Chart</button>
</div>
<div class="chart-container">
<div id="chart"></div>
</div>
<script>
// Demo data
const N = 30;
const now = Date.now();
const data = Array.from({length: N}, (_, i) => [
now + i * 3600 * 1000,
10 + 5 * Math.sin(i/10) + (Math.random()-0.5)
]);
function renderChart() {
const leftOffset = parseInt(document.getElementById('x-offset').value, 10);
const rightOffset = parseInt(document.getElementById('right-offset').value, 10);
const yOffset = parseInt(document.getElementById('y-offset').value, 10);
let type = 'line';
if (document.getElementById('btn-bar').classList.contains('active')) type = 'bar';
if (document.getElementById('btn-both').classList.contains('active')) type = 'both';
const width = 700, height = 300, chartX = leftOffset, chartW = width - leftOffset - rightOffset, chartY = 40 + yOffset, chartH = height - chartY - 40;
const values = data.map(d => d[1]);
const min = Math.min(...values), max = Math.max(...values);
const getX = i => chartX + (i / (N-1)) * chartW;
const getY = v => chartY + chartH - ((v - min) / (max - min)) * chartH;
let svg = `<svg viewBox="0 0 ${width} ${height}" width="100%" height="100%">`;
svg += `<rect x="0" y="0" width="${width}" height="${height}" fill="#e3e7ed" rx="18"/>`;
svg += `<line x1="${chartX}" y1="${chartY}" x2="${chartX}" y2="${chartY+chartH}" stroke="#888" stroke-width="2"/>`;
svg += `<line x1="${chartX}" y1="${chartY+chartH}" x2="${chartX+chartW}" y2="${chartY+chartH}" stroke="#888" stroke-width="2"/>`;
if(type === "line" || type === "both") {
svg += `<polyline fill="none" stroke="#2196f3" stroke-width="3" points="`;
for(let i=0;i<N;i++) svg += `${getX(i)},${getY(values[i])} `;
svg += `"/>`;
}
if(type === "bar" || type === "both") {
const barW = chartW/N*0.7;
for(let i=0;i<N;i++) {
svg += `<rect x="${getX(i)-barW/2}" y="${getY(values[i])}" width="${barW}" height="${chartY+chartH-getY(values[i])}" fill="#2196f3" fill-opacity="0.7"/>`;
}
}
svg += `</svg>`;
document.getElementById('chart').innerHTML = svg;
}
// Chart type button logic
['btn-line', 'btn-bar', 'btn-both'].forEach(id => {
document.getElementById(id).onclick = function() {
['btn-line', 'btn-bar', 'btn-both'].forEach(i => document.getElementById(i).classList.remove('active'));
this.classList.add('active');
renderChart();
};
});
document.getElementById('update-chart').onclick = renderChart;
document.getElementById('x-offset').oninput =
document.getElementById('right-offset').oninput =
document.getElementById('y-offset').oninput = renderChart;
renderChart();
</script>
</body>
</html>
Update Snippet (Programmatic Update Example)
If you want to update the chart programmatically (for example, after changing a setting in code), just call the renderChart()
function:
<!DOCTYPE html>
<html>
<head>
<title>Update Chart by Values Demo</title>
<style>
.chart-container { background: #fff; border-radius: 18px; box-shadow: 0 4px 24px 0 rgba(0,0,0,0.10); margin: 0 auto; max-width: 700px; padding: 20px; }
</style>
</head>
<body>
<div class="chart-container">
<div id="chart"></div>
</div>
<div style="text-align:center; margin-top:20px;">
<button onclick="updateWithRandomData()">Update with Random Data</button>
<button onclick="updateWithSineData()">Update with Sine Data</button>
</div>
<script>
// 1. Store your data in a variable
let N = 30;
let now = Date.now();
let data = Array.from({length: N}, (_, i) => [
now + i * 3600 * 1000,
10 + 5 * Math.sin(i/10) + (Math.random()-0.5)
]);
function renderChart() {
const width = 700, height = 300, chartX = 60, chartW = width - 60 - 24, chartY = 40, chartH = height - chartY - 40;
const values = data.map(d => d[1]);
const min = Math.min(...values), max = Math.max(...values);
const getX = i => chartX + (i / (N-1)) * chartW;
const getY = v => chartY + chartH - ((v - min) / (max - min)) * chartH;
let svg = `<svg viewBox="0 0 ${width} ${height}" width="100%" height="100%">`;
svg += `<rect x="0" y="0" width="${width}" height="${height}" fill="#e3e7ed" rx="18"/>`;
svg += `<polyline fill="none" stroke="#2196f3" stroke-width="3" points="`;
for(let i=0;i<N;i++) svg += `${getX(i)},${getY(values[i])} `;
svg += `"/>`;
svg += `</svg>`;
document.getElementById('chart').innerHTML = svg;
}
// 2. Update the data variable and call renderChart()
function updateWithRandomData() {
data = Array.from({length: N}, (_, i) => [
now + i * 3600 * 1000,
10 + Math.random()*10
]);
renderChart();
}
function updateWithSineData() {
data = Array.from({length: N}, (_, i) => [
now + i * 3600 * 1000,
10 + 5 * Math.sin(i/5)
]);
renderChart();
}
renderChart();
</script>
</body>
</html>