Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use 160 lines of code to achieve a dynamic and cool visual chart?

2025-01-21 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/02 Report--

Prepare general tool functions

GetRandomColor: random color

Const getRandomColor = () = > {

Const letters = '0123456789ABCDEF'

Let color ='#'

For (let I = 0; I

< 6; i++) { color += letters[Math.floor(Math.random() * 16)] } return color; }; translateY:填充Y轴偏移量 const translateY = (value) =>

{

Return translateY (${value} px)

}

Declare state variables using useState Hook

Let's start writing component DynamicBarChart

Const DynamicBarChart = (props) = > {

Const [dataQueue, setDataQueue] = useState ([])

Const [activeItemIdx, setActiveItemIdx] = useState (0)

Const [highestValue, setHighestValue] = useState (0)

Const [currentValues, setCurrentValues] = useState ({})

Const [firstRun, setFirstRun] = useState (false)

/ other code.

}

Simple understanding of useState:

Const [attribute, method for manipulating attributes] = useState (default); variable parsing

DataQueue: the raw data array of the current operation

ActiveItemIdx: the "frame"

HighestValue: the data value of "number one"

CurrentValues: an array of processed data for rendering

FirstRun: first dynamic rendering time

Internal operation method and corresponding useEffect

Please use it with comments:

/ / run dynamically ~

Function start () {

If (activeItemIdx > 1) {

Return

}

NextStep (true)

}

/ / A pair of data to be processed in the next frame

Function setNextValues () {

/ / stop rendering when there is no number of frames (that is, it is over)

If (! dataQueue [activeItemIdx]) {

IterationTimeoutHolder = null

Return

}

/ / data array for each frame

Const roundData = dataQueue [activeItemIdx] .values

Const nextValues = {}

Let highestValue = 0

/ / process data for final rendering (various styles, colors)

RoundData.map ((c) = > {

NextValues [c.id] = {

... c

Color: c.color | | (currentValues [c.id] | | {}) .color | | getRandomColor ()

}

If (Math.abs (c.value) > highestValue) {highestValue = Math.abs (c.value);} return c

});

/ / the operation of the attribute, which triggers useEffect

SetCurrentValues (nextValues)

SetHighestValue (highestValue)

SetActiveItemIdx (activeItemIdx + 1)

}

/ / trigger the next step, cycle

Function nextStep (firstRun = false) {

SetFirstRun (firstRun)

SetNextValues ()

}

Corresponding useEffect:

/ / fetch the original data

UseEffect () = > {

SetDataQueue (props.data)

}, [])

/ / trigger dynamics

UseEffect () = > {

Start ()

}, [dataQueue])

/ / set the trigger dynamic interval

UseEffect () = > {

IterationTimeoutHolder = window.setTimeout (nextStep, 1000)

Return () = > {

If (iterationTimeoutHolder) {

Window.clearTimeout (iterationTimeoutHolder)

}

}

}, [activeItemIdx])

UseEffect example:

UseEffect () = > {

Document.title = You clicked ${count} times

}, [count]); / / update only when count changes

Why return a function in effect?

This is the optional cleanup mechanism for effect. Each effect can return a cleanup function. This puts the logic of adding and removing subscriptions together.

Collate the data used to render the page

Const keys = Object.keys (currentValues)

Const {barGapSize, barHeight, showTitle} = props

Const maxValue = highestValue / 0.85

Const sortedCurrentValues = keys.sort ((a, b) = > currentValues.value-currentValues.value)

Const currentItem = dataQueue [activeItemIdx-1] | | {}

Keys: the index of each set of data

MaxValue: maximum width of chart

SortedCurrentValues: sorts each set of data, which affects dynamic rendering.

CurrentItem: raw data for each group

Start rendering the page

The general logic is:

According to different Props, the data after circular arrangement: sortedCurrentValues

Calculate the width and return the label, bar, value of each item

Based on the calculated height, transform is triggered.

{

{

ShowTitle & &

{currentItem.name}

}

{

SortedCurrentValues.map ((key, idx) = > {

Const currentValueData = currentValues [key]

Const value = currentValueData.value

Let width = Math.abs ((value / maxValue))

Let widthStr

If (isNaN (width) | |! width) {

WidthStr = '1px'

} else {

WidthStr = ${width}%

}

Return ({! currentValueData.label? Key: currentValueData.label} {currentValueData.value});)}

}

Define regular propTypes and defaultProps

DynamicBarChart.propTypes = {

ShowTitle: PropTypes.bool

IterationTimeout: PropTypes.number

Data: PropTypes.array

StartRunningTimeout: PropTypes.number

BarHeight: PropTypes.number

BarGapSize: PropTypes.number

Baseline: PropTypes.number

}

DynamicBarChart.defaultProps = {

ShowTitle: true

IterationTimeout: 200

Data: []

StartRunningTimeout: 0

BarHeight: 50

BarGapSize: 20

Baseline: null

}

Export {

DynamicBarChart

}

How to use

Import React, {Component} from "react"

Import {DynamicBarChart} from ". / DynamicBarChart"

Import helpers from ". / helpers"

Import mocks from ". / mocks"

Import "react-dynamic-charts/dist/index.css"

Export default class App extends Component {

Render () {

Return (

)

}

}

Batch generation of Mock data

Helpers.js:

Function getRandomNumber (min, max) {

Return Math.floor (Math.random () * (max-min + 1) + min)

}

Function generateData (iterations = 100, defaultValues = [], namePrefix = {}, maxJump = 100) {

Const arr = []

For (let I = 0; I {

If (I = 0 & & typeof v.value = 'number') {

Return v

}

Return {

... v

Value: I = 0? This.getRandomNumber (1, 1000): arr [I-1] .values [IDX] .value + this.getRandomNumber (0, maxJump)

}

});

Arr.push ({

Name: ${namePrefix.prefix | |''} ${(namePrefix.initialValue | | 0) + I}

Values

});

}

Return arr

}

Export default {

GetRandomNumber

GenerateData

}

Mocks.js:

Import helpers from'. / helpers'

Const defaultChart = [

{

Id: 1

Label: 'Google'

Value: helpers.getRandomNumber (0,50)

}

{

Id: 2

Label: 'Facebook'

Value: helpers.getRandomNumber (0,50)

}

{

Id: 3

Label: 'Outbrain'

Value: helpers.getRandomNumber (0,50)

}

{

Id: 4

Label: 'Apple'

Value: helpers.getRandomNumber (0,50)

}

{

Id: 5

Label: 'Amazon'

Value: helpers.getRandomNumber (0,50)

}

]

Export default {

DefaultChart

}

A beggar version of the dynamic ranking visualization is done.

Complete code

Import React, {useState, useEffect} from 'react'

Import PropTypes from 'prop-types'

Import'. / styles.scss'

Const getRandomColor = () = > {

Const letters = '0123456789ABCDEF'

Let color ='#'

For (let I = 0; I

< 6; i++) { color += letters[Math.floor(Math.random() * 16)] } return color; }; const translateY = (value) =>

{

Return translateY (${value} px)

}

Const DynamicBarChart = (props) = > {

Const [dataQueue, setDataQueue] = useState ([])

Const [activeItemIdx, setActiveItemIdx] = useState (0)

Const [highestValue, setHighestValue] = useState (0)

Const [currentValues, setCurrentValues] = useState ({})

Const [firstRun, setFirstRun] = useState (false)

Let iterationTimeoutHolder = null

Function start () {

If (activeItemIdx > 1) {

Return

}

NextStep (true)

}

Function setNextValues () {

If (! dataQueue [activeItemIdx]) {

IterationTimeoutHolder = null

Return

}

Const roundData = dataQueue [activeItemIdx] .values; const nextValues = {}; let highestValue = 0 [c.id] = {... c, color: c.color | | (currentValues [c.id] | | {}). Color | | getRandomColor ()}; if (Math.abs (c.value) > highestValue) {highestValue = Math.abs (c.value);} return c;}); console.table (highestValue); www.kaifx.cnsetCurrentValues (nextValues) SetHighestValue (highestValue); setActiveItemIdx (activeItemIdx + 1)

}

Function nextStep (firstRun = false) {

SetFirstRun (firstRun)

SetNextValues ()

}

UseEffect () = > {

SetDataQueue (props.data)

}, [])

UseEffect () = > {

Start ()

}, [dataQueue])

UseEffect () = > {

IterationTimeoutHolder = window.setTimeout (nextStep, 1000)

Return () = > {

If (iterationTimeoutHolder) {

Window.clearTimeout (iterationTimeoutHolder)

}

}

}, [activeItemIdx])

Const keys = Object.keys (currentValues)

Const {barGapSize, barHeight, showTitle, data} = props

Console.table ('data', data)

Const maxValue = highestValue / 0.85

Const sortedCurrentValues = keys.sort ((a, b) = > currentValues.value-currentValues.value)

Const currentItem = dataQueue [activeItemIdx-1] | | {}

Return (

{

{

ShowTitle & &

{currentItem.name}

}

{

SortedCurrentValues.map ((key, idx) = > {

Const currentValueData = currentValues [key]

Const value = currentValueData.value

Let width = Math.abs ((value / maxValue))

Let widthStr

If (isNaN (width) | |! width) {

WidthStr = '1px'

} else {

WidthStr = ${width}%

}

Return ({! currentValueData.label? Key: currentValueData.label} {currentValueData.value});})}

);

}

DynamicBarChart.propTypes = {

ShowTitle: PropTypes.bool

IterationTimeout: PropTypes.number

Data: PropTypes.array

StartRunningTimeout: PropTypes.number

BarHeight: PropTypes.number

BarGapSize: PropTypes.number

Baseline: PropTypes.number

}

DynamicBarChart.defaultProps = {

ShowTitle: true

IterationTimeout: 200

Data: []

StartRunningTimeout: 0

BarHeight: 50

BarGapSize: 20

Baseline: null

}

Export {

DynamicBarChart

}

Styles.scss

. live-chart {

Width: 100%

Padding: 20px

Box-sizing: border-box

Position: relative

Text-align: center

H2 {

Font-weight: 700

Font-size: 60px

Text-transform: uppercase

Text-align: center

Padding: 20px 10px

Margin: 0

}

.chart {

Position: relative

Margin: 20px auto

}

. chart-bars {

Position: relative

Width: 100%

}

. bar-wrapper {

Display: flex

Flex-wrap: wrap

Align-items: center

Position: absolute

Top: 0

Left: 0

Transform: translateY (0)

Transition: transform 0.5s linear

Padding-left: 200px

Box-sizing: border-box

Width: 100%

Justify-content: flex-start

Label {position: absolute; height: 100%; width: 200px; left: 0; padding: 0 10px; box-sizing: border-box; text-align: right; top: 50%; transform: translateY (- 50%); font-size: 16px; font-weight: 700; display: flex; justify-content: flex-end; align-items: center;}. Value {font-size: 16px; font-weight: 700; margin-left: 10px;}. Bar {width: 0% Transition: width 0.5s linear;}

}

}

Conclusion

I have always been interested in the visualization of dynamic rankings, but most of them are based on D3 or echarts.

This library is not only separated from the graphics library, but also uses the new features of React 16. It also made me fully understand the wonderful use of React Hook.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report