// Входные данные: // data - исходный массив (например, buildings) // key - поле, по которому осуществляется группировка function createArrGraph(data, key) { const groupObj = d3.group(data, d => d[key]); let arrGraph = []; for (let entry of groupObj) { const minMax = d3.extent(entry[1].map(d => d['price'])); arrGraph.push({ labelX: entry[0], values: minMax }); } return arrGraph; } function drawGraph(data, keyX, drawMin, drawMax, graphtype) { // значения по оси ОХ // создаем массив для построения графика let arrGraph = createArrGraph(data, keyX); if (keyX == "release") { arrGraph = d3.sort(arrGraph, (x, y) => Number(x["labelX"]) - Number(y["labelX"])); } const svg = d3.select("svg") svg.selectAll('*').remove(); // создаем словарь с атрибутами области вывода графика const attr_area = { width: parseFloat(svg.style('width')), height: parseFloat(svg.style('height')), marginX: 50, marginY: 50 } const scaleYDomain = [ d3.min(arrGraph.map(d => d.values[drawMin? 0:1])) , d3.max(arrGraph.map(d => d.values[drawMax?1:0]))]; // создаем шкалы преобразования и выводим оси const [scX, scY] = createAxis(svg, arrGraph, attr_area,scaleYDomain); // рисуем график if (drawMin && drawMax) { createChart(svg, arrGraph, scX, scY, attr_area, "blue", 0, graphtype, 0, scaleYDomain) createChart(svg, arrGraph, scX, scY, attr_area, "red", 1, graphtype, 0, scaleYDomain) } else if (drawMin) { createChart(svg, arrGraph, scX, scY, attr_area, "blue", 0, graphtype, 1, scaleYDomain) } else if (drawMax) { createChart(svg, arrGraph, scX, scY, attr_area, "red", 1, graphtype, 1, scaleYDomain) } } function createAxis(svg, data, attr_area,scaleYDomain) { // находим интервал значений, которые нужно отложить по оси OY // максимальное и минимальное значение и максимальных высот по каждой стране const [min, max] = scaleYDomain; // функция интерполяции значений на оси // по оси ОХ текстовые значения const scaleX = d3.scaleBand() .domain(data.map(d => d.labelX)) .range([0, attr_area.width - 2 * attr_area.marginX]); const scaleY = d3.scaleLinear() .domain([min * 0.85, max * 1.1]) .range([attr_area.height - 2 * attr_area.marginY, 0]); // создание осей const axisX = d3.axisBottom(scaleX); // горизонтальная const axisY = d3.axisLeft(scaleY); // вертикальная // отрисовка осей в SVG-элементе svg.append("g") .attr("transform", `translate(${attr_area.marginX}, ${attr_area.height - attr_area.marginY})`) .call(axisX) .selectAll("text") // подписи на оси - наклонные .style("text-anchor", "end") .attr("dx", "-.8em") .attr("dy", ".15em") .attr("transform", d => "rotate(-45)"); svg.append("g") .attr("transform", `translate(${attr_area.marginX}, ${attr_area.marginY})`) .call(axisY); return [scaleX, scaleY] } function createChart(svg, data, scaleX, scaleY, attr_area, color, valueIdx, graphType, horisontalScale, scaleYDomain) { if (graphType == 1) { svg.selectAll(".dot") .data(data) .enter() .append("rect") .attr("x", d => scaleX(d.labelX) + valueIdx * 6) .attr("y", d => scaleY(d.values[valueIdx])) .attr("width", 6 * (horisontalScale + 1)) .attr("height", d => scaleY(scaleYDomain[0] * 0.85) - scaleY(d.values[valueIdx])) .attr("transform", `translate(${attr_area.marginX}, ${attr_area.marginY})`) .style("fill", color) } else if (graphType == 2) { const line = d3.line() .x(d => scaleX(d.labelX) + scaleX.bandwidth() / 2 + valueIdx * 4) .y(d => scaleY(d.values[valueIdx])); svg.append('path') .datum(data) .attr('d', line.curve(d3.curveBasis)) .attr('stroke-width',2) .attr('fill', 'none') .attr("transform", `translate(${attr_area.marginX}, ${attr_area.marginY})`) .attr('stroke', color); } else if (graphType == 0) { const r = 4; svg.selectAll(".dot") .data(data) .enter() .append("circle") .attr("r", r) .attr("cx", d => scaleX(d.labelX) + scaleX.bandwidth() / 2 + valueIdx * 4) .attr("cy", d => scaleY(d.values[valueIdx])) .attr("transform", `translate(${attr_area.marginX}, ${attr_area.marginY})`) .style("fill", color) } }