Теперь, вооружившись материалом прошлых тем, создадим простейший график или линейную диаграмму. Фактически нам надо соединить координатные оси с построением путей из отдельных линий:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://d3js.org/d3.v3.min.js"> </script> <style> .axis path, .axis line { fill: none; stroke: #333; } .axis .grid-line { stroke: #000; stroke-opacity: 0.2; } .axis text { font: 10px Verdana; } </style> <body> <script type="text/javascript"> var height = 500, width = 500, margin=30, rawData = [ {x: 10, y: 67}, {x: 20, y: 74},{x: 30, y: 63}, {x: 40, y: 56}, {x: 50, y: 24}, {x: 60, y: 26}, {x: 70, y: 19}, {x: 80, y: 42}, {x: 90, y: 88} ], data=[]; // создание объекта svg var svg = d3.select("body").append("svg") .attr("class", "axis") .attr("width", width) .attr("height", height); // длина оси X= ширина контейнера svg - отступ слева и справа var xAxisLength = width - 2 * margin; // длина оси Y = высота контейнера svg - отступ сверху и снизу var yAxisLength = height - 2 * margin; // функция интерполяции значений на ось Х var scaleX = d3.scale.linear() .domain([0, 100]) .range([0, xAxisLength]); // функция интерполяции значений на ось Y var scaleY = d3.scale.linear() .domain([100, 0]) .range([0, yAxisLength]); // масштабирование реальных данных в данные для нашей координатной системы for(i=0; i<rawData.length; i++) data.push({x: scaleX(rawData[i].x)+margin, y: scaleY(rawData[i].y) + margin}); // создаем ось X var xAxis = d3.svg.axis() .scale(scaleX) .orient("bottom"); // создаем ось Y var yAxis = d3.svg.axis() .scale(scaleY) .orient("left"); // отрисовка оси Х svg.append("g") .attr("class", "x-axis") .attr("transform", // сдвиг оси вниз и вправо "translate(" + margin + "," + (height - margin) + ")") .call(xAxis); // отрисовка оси Y svg.append("g") .attr("class", "y-axis") .attr("transform", // сдвиг оси вниз и вправо на margin "translate(" + margin + "," + margin + ")") .call(yAxis); // создаем набор вертикальных линий для сетки d3.selectAll("g.x-axis g.tick") .append("line") .classed("grid-line", true) .attr("x1", 0) .attr("y1", 0) .attr("x2", 0) .attr("y2", - (yAxisLength)); // рисуем горизонтальные линии координатной сетки d3.selectAll("g.y-axis g.tick") .append("line") .classed("grid-line", true) .attr("x1", 0) .attr("y1", 0) .attr("x2", xAxisLength) .attr("y2", 0); // функция, создающая по массиву точек линии var line = d3.svg.line() .x(function(d){return d.x;}) .y(function(d){return d.y;}); // добавляем путь svg.append("g").append("path") .attr("d", line(data)) .style("stroke", "steelblue") .style("stroke-width", 2); </script> </body> </html>
Для создания линейного графика нам потребуется два набора данных - в данном случае это массивы rawData и data. rawData представляет собственно те данные, которые надо визуализировать, а массива data представляет те же данные, но уже адаптированные к координатной сетке со всеми масштабированиями и смещениями. Если бы мы напрямую визуализировали данные как есть, то второй массив бы не понадобился. Но в реальности без адаптации имеющихся данных к координатной сетке не обойтись, особенно когда одно из измерений данных представляет нечисловые данные, например, даты.
Для интерполяции данных используются две функции scaleX
и scaleY
. Для перевода реальных данных в координатные
применяем цикл по всем элементам массива rawData:
for(i=0; i<rawData.length; i++) data.push({x: scaleX(rawData[i].x)+margin, y: scaleY(rawData[i].y) + margin});
Так как координатные оси вместе со всей сеткой будут начинаться не сразу с границ элемента svg, а будут сдвинуты на отступ, задаваемый переменной margin, то все точки графика также надо сдвинуть на тот же отступ.
Далее строится координатная сетка и путь, представляющий график:
var line = d3.svg.line() .x(function(d){return d.x;}) .y(function(d){return d.y;}); svg.append("g").append("path") .attr("d", line(data)) .style("stroke", "steelblue") .style("stroke-width", 2);