Skip to content

Instantly share code, notes, and snippets.

@rakibulalam
Created November 13, 2020 10:29
Show Gist options
  • Save rakibulalam/28fc9beec6cb273f0ea03facd4ec95ef to your computer and use it in GitHub Desktop.
Save rakibulalam/28fc9beec6cb273f0ea03facd4ec95ef to your computer and use it in GitHub Desktop.
Bar Chart Using D3 Scale Typescript React.js
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