Created
November 13, 2020 10:29
-
-
Save rakibulalam/28fc9beec6cb273f0ea03facd4ec95ef to your computer and use it in GitHub Desktop.
Bar Chart Using D3 Scale Typescript React.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { max } from 'd3-array'; | |
import { | |
ScaleBand, | |
scaleBand, | |
ScaleLinear, | |
scaleLinear | |
} from 'd3-scale'; | |
import { select } from 'd3-selection'; | |
import React, { CSSProperties, Fragment, MutableRefObject, useEffect, useRef } from 'react'; | |
import ChartTooltip from '../chart-tooltip/chart-tooltip'; | |
import './bar-chart.scss'; | |
export type barChartDataType = { | |
label?: string; | |
value: number; | |
date: string; | |
borderColor?: string; | |
borderWidth?: number; | |
backgroundColor?: string; | |
}; | |
/* eslint-disable-next-line */ | |
export interface BarChartProps { | |
data: barChartDataType[]; // data is collection of array | |
size: number[]; // size represents here width and height of the bar chart | |
paddingInner?: number; // its consider to distance between bars | |
style?: CSSProperties; // its consider to add style to change svg | |
} | |
const barChartDataTypeDefault: barChartDataType[] = [ | |
{ | |
label: '12/12/2002', | |
value: 1, | |
borderColor: '#fff', | |
borderWidth: 2, | |
backgroundColor: '#555', | |
date: '10/10/2002', | |
}, | |
]; | |
/** | |
* | |
* @param BarChartProps; | |
* @component BarChart; | |
* @description its dynamic and responsive bar chart | |
* @created by Md. Rakibul Alam | |
*/ | |
export const BarChart = ({ | |
data = barChartDataTypeDefault, | |
size = [200, 200], | |
paddingInner = 0.1, | |
style, | |
}: BarChartProps) => { | |
const chartRef: MutableRefObject<undefined> = useRef(); | |
const tooltipRef: MutableRefObject<undefined> = useRef(); | |
const [width, height] = size; | |
useEffect(() => { | |
const node = chartRef.current; // current ref dom as here is node | |
const tooltipNode = tooltipRef.current; // current ref dom as here is tooltip | |
const sortDataByDate = data.sort( | |
(a: barChartDataType, b: barChartDataType): any => | |
(new Date(a.date) as any) - (new Date(b.date) as any) | |
); | |
// const dataLenght = sortDataByDate.length; // take the data length for the optimize performance | |
const valueMax: number = max(sortDataByDate.map(({ value }) => value)); | |
// const dateMax: Date = max(data.map(({ date }) => new Date(date))); | |
// const dateMin: Date = min(data.map(({ date }) => new Date(date))); | |
const xScaleBand: ScaleBand<string> = scaleBand() | |
.domain(sortDataByDate.map((d) => d.date)) | |
.rangeRound([0, width]) | |
.paddingInner(paddingInner) | |
.paddingOuter(0); | |
const yScale: ScaleLinear<number, number, never> = scaleLinear() | |
.domain([0, valueMax]) | |
.range([0, height]); | |
select(node).selectAll('rect').data(sortDataByDate).enter().append('rect'); | |
select(node).selectAll('rect').data(sortDataByDate).exit().remove(); | |
// const deltaWidth: number = (dataLenght - 1) * barGap; // its consider to fix the bar witdh removing extra width from the current width. its always be considered total width minus one | |
// const barWidth: number = (width - deltaWidth) / dataLenght; // find the exact bar witdh | |
const tooltip = select(tooltipNode) | |
// .style("position", "absolute") | |
// .style("z-index", "10") | |
// .style("visibility", "hidden"); | |
select(node) | |
.selectAll('rect') | |
.data(sortDataByDate) | |
.style('fill', ({ backgroundColor }) => backgroundColor || '#000') | |
.attr('x', ({ date }) => xScaleBand(date)) // added barWidth for change x position from the current position first time i=0, so there is no need to change first positions | |
.attr('y', ({ value }) => height - yScale(value)) | |
.attr('height', ({ value }) => yScale(value)) | |
.attr('width', xScaleBand.bandwidth()) | |
.on("mouseover", () => tooltip.style("visibility", "visible")) | |
.on("mousemove", (event, { label }) => tooltip.style("top", (event.pageY - 10) + "px").style("left", (event.pageX + 10) + "px").text(label)) | |
.on("mouseout", () => tooltip.style("visibility", "hidden")); | |
}, []); | |
return <Fragment> | |
<svg style={style} ref={chartRef} width={width} height={height}></svg> | |
<ChartTooltip ref={tooltipRef} /> | |
</Fragment> | |
}; | |
export default BarChart; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment