import * as d3 from ‘d3’
import { cloneDeep } from ‘lodash-es’
import { FC, MouseEventHandler, useCallback, useEffect, useRef, useState } from ‘react’
import charArr from ‘./TempData.json’
export type ChartData = {
id?: number
start?: number
temperatureY?: number
temperature?: number
date?: string
}
const TempGraphChart: FC = () => {
let chart = undefined
const [initChartData, setChartData] = useState(cloneDeep(charArr))
const [pinGraph, setPinGraph] = useState([])
const [chartDrawn, setChartDrawn] = useState(false)
const date = initChartData.data[0].map(item => item.date)
const [dateAxle, setDateAxle] = useState(date)
const selectorRef = useRef(null)
const yScrollRef = useRef(null)
const chartDate = (chart: any, width: number, height: number) => {
const parseTime = d3.timeParse(‘%H:%M:%S’)
const formatTime = d3.timeFormat(‘%H:%M:%S’)
const margin = 25
const dataWithValues = initChartData.data.filter(d => d.length > 0)
if (dataWithValues.length < 1) return
//创建线性比例尺,使用坐标轴必备
const xScale = d3
.scaleTime()
.domain(d3.extent(dateAxle, d => parseTime(d)) as [Date, Date])
.range([0, width - margin * 2])
//创建底部的x的坐标轴
const xAxis = d3.axisBottom(xScale).tickFormat(formatTime)
//使坐标轴插入svg中
const xGrooup = chart
.append('g')
.attr('class', 'x-axis', 'line')
.attr('transform', function () {
//让平移到底部x对的位置,咱们还要绘制y轴呢
return `translate(${margin}, ${height - margin})`
})
.call(xAxis)
.style('stroke', '#fff')
const sum = ([] as any).concat(...initChartData.data)
const ymin = Math.min(...sum.map((item: any) => item.temperatureY))
const ymax = Math.max(...sum.map((item: any) => item.temperatureY))
//创建线性比例尺,使用坐标轴必备
const yScale = d3
.scaleLinear()
.domain([ymin, ymax])
.range([height, margin + 4])
//创建底部的x的坐标轴
const yAxis = d3.axisLeft(yScale).tickValues(yScale.ticks().concat(ymax).concat(ymin)) // 将最小值展示出来
//使坐标轴插入svg中
chart
.append('g')
.attr('class', 'y-axis', 'line')
.attr('transform', function () {
//让平移到底部x对的位置,咱们还要绘制y轴呢
return `translate(${margin}, ${-margin})`
})
.call(yAxis)
.style('stroke', '#fff')
const line = d3
.line()
.x(function (d) {
//这个d就是咱们的data[0] 遍历的数据了 return也就是坐标 相当于帮咱们生成了一个 M0,0 L 1,2.....这个样
return xScale(parseTime(d.date))
})
.y(function (d) {
return yScale(d.temperatureY)
})
.curve(d3.curveCardinal)
const randomColor = () => Math.floor(Math.random() * 16777215).toString(16)
// 画线
chart
.selectAll('path.path')
.data(initChartData.data)
.enter()
.append('path')
.attr('class', 'line')
.attr('d', function (d) {
return line(d)
})
.attr('stroke', function () {
return '#' + randomColor()
})
.attr('fill', 'none')
.attr('transform', `translate(${margin}, ${-margin})`)
//更改轴线颜色
d3.select('.x-axis').selectAll('path, line').style('stroke', '#fff')
d3.select('.y-axis').selectAll('path, line').style('stroke', '#fff')
function zoomed(e) {
//定义缩放方向
const t = e.transform.rescaleX(xScale)
//缩放坐标轴
xGrooup.call(xAxis.scale(t))
chart.selectAll('.line').attr('d', d => line.x(datum => t(parseTime(datum.date)))(d))
}
const zoom = d3
.zoom()
.scaleExtent([1, 100]) //缩放比例范围
.translateExtent([
[0, 0],
[width, height],
])
.on('zoom', zoomed)
chart.call(zoom)
}
useEffect(() => {
if (chartDrawn) return
const fetch = async () => {
setChartDrawn(true)
d3.select(‘#temp-graph svg’).remove()
const dom = document.getElementById(‘temp-graph’)
const width = dom?.offsetWidth ?? 0
const height = dom?.offsetHeight ?? 0
chart = d3.select(dom).append(‘svg’).attr(‘width’, width).attr(‘height’, height)
await chartDate(chart, width, height)
}
fetch()
}, [chartDrawn, initChartData])
return (
<div
className=‘absolute border-1px border-[var(–semi-color-info)] z-10 border-solid’
style={{ background: ‘rgba(var(–semi-grey-2), 0.5)’ }}
ref={selectorRef}
>
<div id=‘temp-graph’ ref={yScrollRef} style={{ height: ‘100%’ }} onMouseDown={handleMouseDown}>
)
}
export default TempGraphChart