Skip to content

Instantly share code, notes, and snippets.

@rakibulalam
Created November 13, 2020 10:29
Show Gist options
  • Select an option

  • Save rakibulalam/28fc9beec6cb273f0ea03facd4ec95ef to your computer and use it in GitHub Desktop.

Select an option

Save rakibulalam/28fc9beec6cb273f0ea03facd4ec95ef to your computer and use it in GitHub Desktop.

Revisions

  1. rakibulalam created this gist Nov 13, 2020.
    108 changes: 108 additions & 0 deletions BarChartD3TypeScriptReact.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,108 @@
    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;