d3缩放 zoom

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值