const server1 = [
{ date: '2019-06-15T00:22:25.000Z', online: 451 },
{ date: '2019-06-15T01:08:58.000Z', online: 499 },
{ date: '2019-06-15T02:25:35.000Z', online: 464 },
{ date: '2019-06-15T13:25:42.000Z', online: 252 },
{ date: '2019-06-15T15:45:24.000Z', online: 247 },
{ date: '2019-06-15T17:02:09.000Z', online: 254 },
{ date: '2019-06-15T20:11:00.000Z', online: 300 },
{ date: '2019-06-15T21:22:33.000Z', online: 296 },
{ date: '2019-06-15T22:24:58.000Z', online: 298 },
{ date: '2019-06-15T22:58:18.000Z', online: 270 }
];
const server2 = [
{ date: '2019-06-15T00:14:18.000Z', online: 599 },
{ date: '2019-06-15T00:58:56.000Z', online: 554 },
{ date: '2019-06-15T02:15:13.000Z', online: 505 },
{ date: '2019-06-15T13:32:19.000Z', online: 221 },
{ date: '2019-06-15T15:19:08.000Z', online: 265 },
{ date: '2019-06-15T16:04:55.000Z', online: 277 },
{ date: '2019-06-15T17:31:16.000Z', online: 275 },
{ date: '2019-06-15T18:41:16.000Z', online: 303 },
{ date: '2019-06-15T20:05:41.000Z', online: 333 },
{ date: '2019-06-15T21:39:44.000Z', online: 288 },
{ date: '2019-06-15T22:46:01.000Z', online: 277 },
{ date: '2019-06-15T23:29:16.000Z', online: 264 }
];
const server3 = [
{ date: '2019-06-15T00:10:18.000Z', online: 321 },
{ date: '2019-06-15T00:54:56.000Z', online: 300 },
{ date: '2019-06-15T02:11:13.000Z', online: 280 },
{ date: '2019-06-15T13:28:19.000Z', online: 110 },
{ date: '2019-06-15T15:15:08.000Z', online: 130 },
{ date: '2019-06-15T16:01:55.000Z', online: 133 },
{ date: '2019-06-15T17:25:16.000Z', online: 140 },
{ date: '2019-06-15T18:37:16.000Z', online: 172 },
{ date: '2019-06-15T20:01:41.000Z', online: 180 },
{ date: '2019-06-15T21:35:44.000Z', online: 201 },
{ date: '2019-06-15T22:41:01.000Z', online: 210 },
{ date: '2019-06-15T23:23:16.000Z', online: 197 }
];
var x_list = [].concat(server1, server2, server3)
.map(d => new Date(d.date))
.sort(d3.ascending);
var servers_scales = [server1, server2, server3].map(s => {
return d3.scaleLinear()
.domain(s.map(d => new Date(d.date)))
.range(s.map(d => d.online));
});
var combinedData = x_list.map(x => {
var val = 0;
for (var i = 0; i < servers_scales.length; i++)
val += servers_scales[i](x);
return {
date: x,
online: val
};
});
const combined = [].concat(server1, server2, server3);
const margin = {top: 50, right: 50, bottom: 50, left: 50};
const width = window.innerWidth - margin.left - margin.right;
const height = window.innerHeight - margin.top - margin.bottom;
const dateMin = d3.min(combined, d => new Date(d.date));
const dateMax = d3.max(combined, d => new Date(d.date));
const onlineMin = d3.min(combined, d => d.online);
const onlineMax = d3.max(combined, d => d.online);
const xScale = d3
.scaleTime()
.domain([dateMin, dateMax])
.range([0, width]);
const yScale = d3
.scaleLinear()
.domain([0, onlineMax * 3])
.range([height, 0]);
const line = d3
.line()
.x(d => xScale(new Date(d.date)))
.y(d => yScale(d.online))
.curve(d3.curveMonotoneX);
const svg = d3
.select('body')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg
.append('path')
.datum(server1)
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', 'blue')
.attr('d', line);
svg
.append('path')
.datum(server2)
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', 'red')
.attr('d', line);
svg
.append('path')
.datum(server3)
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', 'green')
.attr('d', line);
svg
.append('path')
.datum(combinedData)
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', 'orange')
.attr('d', line);
svg
.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>