first commt
This commit is contained in:
45
resources/js/components/rainfall/AddRainfall.tsx
Normal file
45
resources/js/components/rainfall/AddRainfall.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import React, {Dispatch, FC, FormEvent, SetStateAction, useState} from "react"
|
||||
import useAxiosTools from "../../hooks/AxiosTools";
|
||||
import Field from "../Field";
|
||||
|
||||
const AddRainfall: FC<AddRainfallProps> = ({reload}) => {
|
||||
|
||||
const {axiosPost} = useAxiosTools()
|
||||
const [date, setDate] = useState((new Date()).toSQLDate())
|
||||
const [value, setValue] = useState(0)
|
||||
|
||||
const handleSubmit = async (event: FormEvent) => {
|
||||
event.preventDefault()
|
||||
try {
|
||||
await axiosPost('/api/rainfalls', {date, value})
|
||||
setDate((new Date()).toSQLDate())
|
||||
setValue(0)
|
||||
reload(new Date())
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return <form onSubmit={handleSubmit}>
|
||||
<h2>Ajout d'une mesure</h2>
|
||||
<Field type="date"
|
||||
name="date"
|
||||
placeholder="Email"
|
||||
value={date}
|
||||
onChange={event => setDate(event.target.value)}
|
||||
autoFocus>Date</Field>
|
||||
<Field type="number"
|
||||
name="value"
|
||||
placeholder="10"
|
||||
value={value}
|
||||
onChange={event => setValue(Number(event.target.value))}>Mesure</Field>
|
||||
|
||||
<button type="submit" className="mt-3 w-full bg-blue-700 rounded">Valider</button>
|
||||
</form>
|
||||
}
|
||||
|
||||
export default AddRainfall
|
||||
|
||||
interface AddRainfallProps {
|
||||
reload: Dispatch<SetStateAction<Date>>
|
||||
}
|
||||
44
resources/js/components/rainfall/LastFiveMesure.tsx
Normal file
44
resources/js/components/rainfall/LastFiveMesure.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import React, {FC, useEffect, useState} from "react"
|
||||
import useAxiosTools from "../../hooks/AxiosTools";
|
||||
import {rainfall} from "../../types";
|
||||
import {AxiosError} from "axios";
|
||||
|
||||
const LastFiveMesure: FC<LastFiveMesureProps> = ({loadedAt}) => {
|
||||
|
||||
const {error, setError, axiosGet} = useAxiosTools()
|
||||
const [data, setData] = useState<rainfall[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
fetchData()
|
||||
}, [loadedAt])
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const res = await axiosGet('/api/rainfalls/last')
|
||||
setData(res.data)
|
||||
} catch (e) {
|
||||
if (e instanceof AxiosError) {
|
||||
setError(e.message)
|
||||
} else {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return <div>
|
||||
<h1>5 dernières mesures</h1>
|
||||
{error && <div>{error}</div>}
|
||||
<ul>
|
||||
{data.map(line => <li key={line.id} className="w-36 flex justify-between">
|
||||
<span>{(new Date(line.date)).toLocaleDateString()}</span>
|
||||
<span>{line.value}</span>
|
||||
</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default LastFiveMesure
|
||||
|
||||
interface LastFiveMesureProps {
|
||||
loadedAt: Date,
|
||||
}
|
||||
100
resources/js/components/rainfall/RainfallGraph.tsx
Normal file
100
resources/js/components/rainfall/RainfallGraph.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
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
|
||||
console.log('data', data)
|
||||
|
||||
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,
|
||||
}
|
||||
Reference in New Issue
Block a user