import * as d3 from "d3"; import { useEffect, useRef, useState } from "react"; function drawGraph(data, keyX, drawMin, drawMax, graphtype) { // значения по оси ОХ // создаем массив для построения графика // console.log(keyX) if(keyX=="release" || keyX=="size"){ data = d3.sort(data, (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 [scX, scY] = createAxis(svg, data, attr_area,[drawMin,drawMax]); // рисуем график const scaleYDomain = d3.extent(data.map(d => d.values[1])); if (drawMin && drawMax){ createChart(svg, data, scX, scY, attr_area, "blue", 0,graphtype,0,scaleYDomain) createChart(svg, data, scX, scY, attr_area, "red", 1,graphtype,0,scaleYDomain) } else if (drawMin) { createChart(svg, data, scX, scY, attr_area, "blue", 0,graphtype,1,scaleYDomain) } else if (drawMax) { createChart(svg, data, scX, scY, attr_area, "red", 1,graphtype,1,scaleYDomain) } } function createAxis(svg, data, attr_area, selections) { // находим интервал значений, которые нужно отложить по оси OY // максимальное и минимальное значение и максимальных высот по каждой стране const max = d3.max(data,d => d.values[Number(selections[1])]); const min = d3.min(data,d => d.values[Number(1-selections[0])]); // console.log(max,min,data) // функция интерполяции значений на оси // по оси ОХ текстовые значения 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,isHistogram,horisontalScale,scaleYDomain) { if (isHistogram){ 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{ 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) } } const ChartDraw = (props) => { const chartRef = useRef(null); const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); // заносим в состояния ширину и высоту svg-элемента useEffect(() => { const svg = d3.select(chartRef.current); setWidth(parseFloat(svg.style('width'))); setHeight(parseFloat(svg.style('height'))); }); // задаем отступы в svg-элементе const margin = { top:10, bottom:60, left:40, right:10 }; // вычисляем ширину и высоту области для вывода графиков const boundsWidth = width - margin.left - margin.right; const boundsHeight = height - margin.top - margin.bottom; useEffect(() => { if(boundsWidth<0||boundsHeight<0){ return; } const svg = d3.select(chartRef.current); // выводим прямоугольник, svg .append("rect") .attr("x", margin.left) .attr("y", margin.top) .attr("width", boundsWidth) .attr("height", boundsHeight) .style("fill", "lightgrey"); // console.log(props) drawGraph(props.data,props.ox,props.minMax[0],props.minMax[1],Number(props.graphType)) }); return ( ) } export default ChartDraw;