Files
lara-bermite/resources/js/components/rainfall/RainfallGraph.tsx
2023-09-24 16:13:28 +02:00

100 lines
3.3 KiB
TypeScript

import * as d3 from "d3"
import React, {FC, LegacyRef, useEffect, useRef} from "react"
import {rainfall} from "../../types";
const RainfallGraph: FC<RainfallGraphProps> = ({width, height, data, start_date, end_date}) => {
const svgRef = useRef<SVGSVGElement|null>(null)
useEffect(() => {
renderSVG()
}, [width, height, data])
const renderSVG = () => {
const margin = {top: 10, right: 30, bottom: 30, left: 20}
const gWidth = width - margin.left - margin.right
const gHeight = height - margin.top - margin.bottom
d3.select(svgRef.current).selectAll("*").remove()
const svg = d3.select(svgRef.current)
.attr('width', gWidth + margin.left + margin.right)
.attr('height', gHeight + margin.top + margin.bottom)
.attr('class', 'relative')
.append('g')
.attr('transform', "translate(" + margin.left + "," + margin.top + ")")
const yMax = data.reduce((result, item) => item.value > result ? item.value : result, 0)
const y = d3.scaleLinear()
.domain([0, yMax + 10])
.range([gHeight, 0])
const x = d3.scaleUtc()
.domain([(new Date(start_date)), (new Date(end_date))])
.range([margin.left, width - margin.right])
const yAxis = svg.append('g')
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(height / 80))
.call(g => g.select('.domain').remove())
.call(g => g.append('text')
.attr('x', -margin.left)
.attr('y', 10)
.attr('fill', 'currentColor')
.attr('text-anchor', 'start')
)
svg.append("g")
.attr("transform", "translate(0," + gHeight + ")")
.call(d3.axisBottom(x)
.tickFormat(
// @ts-ignore
d3.timeFormat("%d/%m/%Y")
)
, 0)
if (data.length === 0) {
// no values text
const titleBox = svg.append("g")
.attr("x", (width))
.attr("y", height)
titleBox.append("text")
.attr("x", (width / 2))
.attr("y", height / 2)
.attr("text-anchor", "middle")
.style("font-size", "20px")
.text('Aucune Donnée')
} else {
yAxis.call(g => g.selectAll(".tick line").clone()
.attr("x2", width - margin.left - margin.right)
.attr("stroke-opacity", 0.1))
}
svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("fill", "steelblue")
.attr("x", d => x(new Date(d.date)) * (1 - (100 / data.length)/100))
.attr("y", d => y(d.value))
.attr("width", (width - 44 + ((width - 44) / (data.length + 1))) / (data.length + 1) - 2)
.attr("height", d => height - margin.bottom - 10 - y(d.value))
.append('title')
.text(d => `${(new Date(d.date)).toLocaleDateString()} : ${d.value}`)
}
return <svg ref={svgRef} />
}
export default RainfallGraph
interface RainfallGraphProps {
width: number,
height: number,
data: rainfall[],
start_date: string,
end_date: string,
}