d3.js 重新设计仪表图表,带有实心圆圆边提示

问题描述 投票:0回答:1

我有一个仪表图表,当前有一个刻度盘 - 如何修改它以使其进一步向后弯曲并使边缘变圆,并在弧的尖端创建一个实心圆?

https://codesandbox.io/s/blissful-framework-chlptz?file=/src/GaugeChart.js

目前我的图表看起来像这样,带有表盘。重新设计当前图表代码。

import React from 'react'
import * as d3 from 'd3'

class GaugeChart extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
    this.state = {
      data: [],
      theme: this.props.theme
        ? this.props.theme
        : ['#bde0fe', '#2698f9', '#71bcfd', '#f1f8fe'],
    }
  }

  componentDidMount() {
    var $this = this.myRef.current

    d3.select($this).selectAll('svg').remove()

    const value = this.props.value
    const data = [
      {
        label: 'Completed',
        value: value,
      },
      {
        label: 'Remaining',
        value: 100 - value,
      },
    ]

    const width = parseInt(this.props.width, 10),
      height = parseInt(this.props.height, 10),
      radius = parseInt(this.props.r, 10),
      innerradius = parseInt(this.props.ir, 10)

    var color = d3.scaleOrdinal().range(this.state.theme)

    var arc = d3.arc().outerRadius(radius).innerRadius(innerradius)

    data.forEach(function (d) {
      d.total = +d.value
    })

    var pie = d3
      .pie()
      .startAngle(-90 * (Math.PI / 180))
      .endAngle(90 * (Math.PI / 180))
      .padAngle(0.02) // some space between slices
      .sort(null)
      .value(function (d) {
        return d.total
      })

    var svg = d3
      .select($this)
      .append('svg')
      .attr('width', width)
      .attr('height', height + 5)
      .append('g')
      .attr('class', 'piechart')
      .attr('transform', 'translate(' + width / 2 + ',' + height + ')')

    var segments = svg.append('g').attr('class', 'segments')

    var slices = segments
      .selectAll('.arc')
      .data(pie(data))
      .enter()
      .append('g')
      .attr('class', 'arc')

    slices
      .append('path')
      .attr('d', arc)
      .attr('fill', function (d, i) {
        return color(i)
      })
    /*.transition()
          .attrTween('d', function(d) {
            var i = d3.interpolate(d.startAngle + 0.1, d.endAngle);
            return function(t) {
              d.endAngle = i(t);
              return arc(d);
            }
          } )*/

    var arrow = svg.append('g').attr('transform', 'rotate( 0  )')

    arrow
      .append('path')
      .attr('fill', '#ef7e60')
      .attr(
        'd',
        `M -${innerradius - 5},0 -${innerradius - 12},-5 -${
          innerradius - 12
        },5`,
      ) // draw triangle

    var text = svg
      .append('text')
      .attr('text-anchor', 'middle')
      .attr('dy', 0)
      .attr('fill', '#ef7e60')

    function update(data) {
      text.text(`${Math.round(data[0].value)}%`) // set % text

      arrow.transition().attr('transform', `rotate( ${data[0].value * 1.8}  )`) //rotate to desired qantity ( i put to 60% of 180 deg )
    }
    update(data)
  }

  render() {
    return <div ref={this.myRef} className="GaugeChart" />
  }
}
export default GaugeChart
d3.js
1个回答
0
投票

import React from 'react'
import * as d3 from 'd3'

class GaugeChart extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
    this.state = {
      data: [],
      theme: this.props.theme
        ? this.props.theme
        : ['#bde0fe', '#2698f9', '#71bcfd', '#f1f8fe'],
    }
  }

  componentDidMount() {
    var $this = this.myRef.current

    d3.select($this).selectAll('svg').remove()

    const value = this.props.value
    const data = [
      {
        sortIndex: 0,
        value: value,
        fill: 'blue',
      },
      {
        sortIndex: 0,
        value: 100 - value,
        fill: '#EAEDF6',
      },
    ]
    let arcThickness = 4
    let size = 50
    let transitionDuration = 750

    const t = d3.transition().duration(350)
    const arc = d3
      .arc()
      .innerRadius(size / 2 - arcThickness)
      .outerRadius(size / 2)
      .cornerRadius(arcThickness)
    const pie = d3
      .pie()
      .value((d) => d.value)
      .startAngle(-Math.PI / 1.45)
      .endAngle(Math.PI / 1.45)
      .sort((a, b) => d3.ascending(a.sortIndex, b.sortIndex))

    const initData = pie(JSON.parse(JSON.stringify(data)))
    const arcs = pie(data)

    function arcTween(d, bIsLastArc) {
      var interpolateStart = d3.interpolate(-Math.PI / 1.45, d.startAngle)
      var interpolateEnd = d3.interpolate(
        bIsLastArc ? d.endAngle : -Math.PI / 1.45,
        d.endAngle,
      )

      return function (t) {
        d.startAngle = interpolateStart(t)
        d.endAngle = interpolateEnd(t)
        return arc(d)
      }
    }
    const svg = d3
      .select($this)
      .append('svg')
      .attr('viewBox', [-size / 2, -size / 2, size, size])
    // add def and drop shadow for the value dot
    svg.append('defs')
      .html(`<filter id="dot-shadow" x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox">
      <feDropShadow dx="3" dy="3" stdDeviation="8" flood-color="${initData[0].data.fill}" flood-opacity="0.25" />
    </filter>`)

    const gauges = svg
      .selectAll('path')
      .data(arcs)
      .join('path')
      .attr('fill', (d) => d.data.fill)
      .attr('d', arc)

    gauges
      .transition()
      .duration(transitionDuration)
      .attrTween('d', (d, i) => arcTween(d, i == arcs.length - 1))

    // Add a dot to mark the end of the first arc
    const dot = svg
      .selectAll('circle')
      .data([
        Object.assign(initData[0], {
          startAngle: initData[0].endAngle,
          endAngle: initData[1].startAngle,
          stroke: initData[initData.length - 1].data.fill,
        }),
      ])
      .join('circle')
      .attr('fill', '#fff')
      .attr('r', arcThickness * 0.7)
      .attr('stroke', (d) => d.stroke)
      .attr('stroke-width', 0.1)
      .attr('style', 'filter:url(#dot-shadow)')
      .attr('transform', (d) => `translate(${arc.centroid(d)})`)

    dot
      .transition()
      .duration(transitionDuration)
      .attrTween('transform', (d) => {
        const interpolateStart = d3.interpolate(-Math.PI / 1.45, d.startAngle)
        const interpolateEnd = d3.interpolate(-Math.PI / 1.45, d.endAngle)
        return function (t) {
          d.startAngle = interpolateStart(t)
          d.endAngle = interpolateEnd(t)
          return `translate(${arc.centroid(d)})`
        }
      })


    svg
      .append('text')
      .attr('transform', `translate(0, ${(0.1 * size) / 2})`)
      .attr('font-size', '0.7rem')
      .attr('text-anchor', 'middle')
      .attr('fill', "black")
      .text(data[0].value)

      svg
      .append('text')
      .attr('transform', `translate(0, ${(0.15 * size)})`)
      .attr('font-size', '0.2rem')
      .attr('text-anchor', 'middle')
      .attr('fill', "grey")
      .text("Volts")
  }

  render() {
    return <div ref={this.myRef} className="GaugeChart" />
  }
}
export default GaugeChart

根据上面的代码片段更新您的 GaugeChart 组件

© www.soinside.com 2019 - 2024. All rights reserved.