Skip to content

Instantly share code, notes, and snippets.

@rakibulalam
Created November 15, 2020 11:45
Show Gist options
  • Save rakibulalam/658ad640c4d5cb7501979bf411506f17 to your computer and use it in GitHub Desktop.
Save rakibulalam/658ad640c4d5cb7501979bf411506f17 to your computer and use it in GitHub Desktop.
Line chart , D3, React, TypeScript
import { extent, group, max } from 'd3-array';
import {
ScaleLinear,
scaleLinear,
ScaleOrdinal,
scaleOrdinal,
ScaleTime,
scaleTime
} from 'd3-scale';
import { select } from 'd3-selection';
import { curveBasis, line } from 'd3-shape';
import React, {
CSSProperties,
Fragment,
MutableRefObject,
useEffect,
useRef
} from 'react';
import './line-chart.scss';
export type LineChartDataType = {
label?: string;
value: number;
dateTime: string;
borderColor?: string;
borderWidth?: number;
backgroundColor?: string;
};
/* eslint-disable-next-line */
export interface LineChartProps {
data: LineChartDataType[]; // 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
strokeWidth?:number; //
}
const LineChartDataTypeDefault: LineChartDataType[] = [
{
label: '12/12/2002',
value: 1,
borderColor: '#fff',
borderWidth: 2,
backgroundColor: '#555',
dateTime: '10/10/2002',
},
];
/**
*
* @param LineChartProps
* @component LineChart
* @description Its line chart based on days and hours.
* @author Md. Rakibul Alam
* @contact https://github.com/rakibulalam71
*/
export const LineChart = ({
data = LineChartDataTypeDefault,
size = [200, 200],
strokeWidth = 1.5,
style,
}: LineChartProps) => {
const chartRef: MutableRefObject<undefined> = useRef();
const tooltipRef: MutableRefObject<undefined> = useRef();
const [width, height] = size;
useEffect(() => {
const node = chartRef.current;
/** dataGroupByday is divided the data into two parts yestarday and today etc. it can possible to add mulitple days data */
/** Map<number, LineChartDataType[]> =Map<days, LineChartDataType[] */
const dataGroupByDay:Map<number, LineChartDataType[]> = group(data, ({ dateTime }) =>
new Date(dateTime).getDay()
);
/** find the max value of the data */
const valueMax: number = max(data.map(({ value }) => value));
/** xScale is maintain the time consistency of each hours */
const xScale:ScaleTime<number, number, never> = scaleTime()
.domain(
extent(
data.map(({ dateTime }: LineChartDataType) => {
return new Date(dateTime).getHours();
})
)
)
.range([0, width]);
/** yScale actualy is keeping height consistency based on max domain value */
const yScale: ScaleLinear<number, number, never> = scaleLinear()
.domain([0, valueMax])
.range([height, 0]);
/** days belongs of every keys of map methods */
const days: string[] = [...dataGroupByDay.keys()].map(String);
/** ordinal scale for line color for each key of map. key is actualy treated here each days */
const colorScale:ScaleOrdinal<string, unknown, never> = scaleOrdinal()
.domain(days)
.range([
'#26b1bb',
'#377eb8',
'#4daf4a',
'#984ea3',
'#ff7f00',
'#ffff33',
'#a65628',
'#f781bf',
'#999999',
]);
select(node)
.selectAll('path')
.data(dataGroupByDay)
.enter()
.append('path')
.attr('fill', 'none')
.attr('stroke', ([key]:Map<number, LineChartDataType[]>): string => {
return colorScale(key.toString()) as string;
})
.attr('stroke-width', strokeWidth)
.attr('d', ([, values]: Map<number, LineChartDataType[]>) => {
return line()
.x(({ dateTime }: LineChartDataType) => {
return xScale(new Date(dateTime).getHours());
})
.y(({ value }: LineChartDataType) => {
return yScale(value);
})
.curve(curveBasis)(values as []);
});
}, []);
return (
<Fragment>
<svg style={style} ref={chartRef} width={width} height={height}></svg>
</Fragment>
);
};
export default LineChart;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment