d3#select TypeScript Examples

The following examples show how to use d3#select. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: render.ts    From fe-v5 with Apache License 2.0 7 votes vote down vote up
export function renderFn(data, { width, height, parentGroupEl }) {
  const parentGroup = select(parentGroupEl).attr('width', width).attr('height', height);
  const countPerRow = bestFitElemCountPerRow(1, width, height);
  const unitWidth = Math.floor(width / countPerRow);
  const rowCount = Math.ceil(1 / countPerRow);
  const unitHeight = height / rowCount;

  renderHoneyComb(parentGroup, data, {
    width: unitWidth,
    height: unitHeight,
  });
}
Example #2
Source File: visualize.ts    From covid19-visualized with MIT License 5 votes vote down vote up
indonesia = async (id: string, data: IDProvince[]): Promise<void> => {
    const tooltipHtml = (data: IDProvince): string => {
        return `
            <div id="covid19-tooltip">
                <h3 class="text-center my-2">${data.provinsi}</h3>
                <h5>Positif: ${data.kasusPosi}</h5>
                <h5>Aktif: ${getActiveCaseID(data)} (${getPercentage(getActiveCaseID(data), data.kasusPosi)})</h5>
                <h5>Sembuh: ${data.kasusSemb} (${getPercentage(data.kasusSemb, data.kasusPosi)})</h5>
                <h5>Meninggal: ${data.kasusMeni} (${getPercentage(data.kasusMeni, data.kasusPosi)})</h5>
            </div>
        `
    }

    const tooltip = select('.tooltip')
    
    const svg = select(`#${id}`)
        .append('svg')
        .attr('width', 960)
        .attr('height', 350)

    const path = geoPath().projection(
        geoEquirectangular()
            .scale(1050)
            .rotate([-120, 0])
            .translate([1050 / 2, 300 / 2])
    )

    const provinces = (await window.fetch('/indonesia-provinces.json')
        .then(response => response.json()) as IDProvince[])
        .map(province => {
            const covid19Data = data.find(({ kodeProvi }) => kodeProvi === province.kodeProvi)
            return {
                ...province,
                ...covid19Data,
                legend: indonesiaLegends.find(({ value }) => !!covid19Data.kasusPosi
                    ? covid19Data.kasusPosi > (value - 1)
                    : value === 0
                ).color
            }
        }) as any[]
    
        svg.selectAll('path')
            .data(provinces)
            .enter()
            .append('path')
            .attr('stroke', 'black')
            .attr('stroke-width', .75)
            .attr('d', path)
            .attr('fill', (data: IDProvince) => data.legend)
            .on('mouseover', function(data: IDProvince) {
                tooltip.style('hidden', false).html(tooltipHtml(data))
                select(this)
                    .attr('fill', '#ddd')
                    .attr('stroke', 'white')
                    .attr('stroke-width', 2.5)
            })
            .on('mousemove', (data: IDProvince) => {
                tooltip.classed('hidden', false)
                    .style('top', event.pageY + 'px')
                    .style('left', (event.pageX + 10) + 'px')
                    .html(tooltipHtml(data))
            })
            .on('mouseout', function(data: IDProvince) {
                tooltip.classed('hidden', true)
                select(this)
                    .attr('fill', data.legend)
                    .attr('stroke', 'black')
                    .attr('stroke-width', .75)
            })
            
}
Example #3
Source File: render.ts    From fe-v5 with Apache License 2.0 5 votes vote down vote up
div = select('body')
  .append(function () {
    return document.createElement('div');
  })
  .attr('class', 'hexbin-tooltip')
  .style('opacity', 0)
Example #4
Source File: PieChart.tsx    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
draw() {
    const { values, pieType, strokeWidth } = this.props;

    if (values.length === 0) {
      return;
    }

    const data = values.map(datapoint => datapoint.numeric);
    const names = values.map(datapoint => formattedValueToString(datapoint));
    const colors = values.map((p, idx) => {
      if (p.color) {
        return p.color;
      }
      return grafana_colors[idx % grafana_colors.length];
    });

    const total = sum(data) || 1;
    const percents = data.map((item: number) => (item / total) * 100);

    const width = this.containerElement.offsetWidth;
    const height = this.containerElement.offsetHeight;
    const radius = Math.min(width, height) / 2;

    const outerRadius = radius - radius / 10;
    const innerRadius = pieType === PieChartType.PIE ? 0 : radius - radius / 3;

    const svg = select(this.svgElement)
      .html('')
      .attr('width', width)
      .attr('height', height)
      .append('g')
      .attr('transform', `translate(${width / 2},${height / 2})`);

    const pieChart = pie();

    const customArc = arc()
      .outerRadius(outerRadius)
      .innerRadius(innerRadius)
      .padAngle(0);

    svg
      .selectAll('path')
      .data(pieChart(data))
      .enter()
      .append('path')
      .attr('d', customArc as any)
      .attr('fill', (d: any, idx: number) => colors[idx])
      .style('fill-opacity', 0.15)
      .style('stroke', (d: any, idx: number) => colors[idx])
      .style('stroke-width', `${strokeWidth}px`)
      .on('mouseover', (d: any, idx: any) => {
        select(this.tooltipElement).style('opacity', 1);
        select(this.tooltipValueElement).text(`${names[idx]} (${percents[idx].toFixed(2)}%)`);
      })
      .on('mousemove', () => {
        select(this.tooltipElement)
          .style('top', `${event.pageY - height / 2}px`)
          .style('left', `${event.pageX}px`);
      })
      .on('mouseout', () => {
        select(this.tooltipElement).style('opacity', 0);
      });
  }
Example #5
Source File: Bars.tsx    From covid19-trend-map with Apache License 2.0 5 votes vote down vote up
Bar: React.FC<BarProps> = ({
    data,
    fillColor,
    svgContainerData,
    scales,
}) => {
    const containerG = React.useRef<SVGGElement>();

    const initContainer = () => {
        const { g } = svgContainerData;

        containerG.current = select(g).append('g').node();
    };

    const draw = () => {
        const { dimension } = svgContainerData;

        const { height } = dimension;

        const { x, y } = scales;

        remove();

        select(containerG.current)
            .append('g')
            .attr('class', BarRectGroupClassName)
            // .attr("clip-path", `url(#${clipPathId})`)
            .selectAll(`.${BarRectClassName}`)
            .data(data)
            .enter()
            .append('rect')
            .attr('class', BarRectClassName)
            .style('fill', fillColor)
            .attr('x', (d) => x(d.x))
            .attr('width', x.bandwidth())
            .attr('y', (d) => y(d.y))
            .attr('height', (d) => {
                return height - y(d.y);
            });
    };

    const remove = () => {
        const existingBars = select(containerG.current).selectAll(
            `.${BarRectGroupClassName}`
        );

        if (existingBars.size()) {
            existingBars.remove();
        }
    };

    React.useEffect(() => {
        if (svgContainerData) {
            initContainer();
        }
    }, [svgContainerData]);

    React.useEffect(() => {
        if (svgContainerData && scales && data) {
            draw();
        }
    }, [scales, data]);

    return null;
}
Example #6
Source File: Line.tsx    From covid19-trend-map with Apache License 2.0 5 votes vote down vote up
Line: React.FC<LineProps> = ({
    data,
    strokeColor,
    svgContainerData,
    scales,
}) => {
    const containerG = React.useRef<SVGGElement>();

    const initContainer = () => {
        const { g } = svgContainerData;

        containerG.current = select(g).append('g').node();
    };

    const draw = () => {
        const containerGroup = select(containerG.current);

        const { x, y } = scales;

        const xOffset = x.bandwidth() / 2;

        const valueline = line<ChartDataItem>()
            // .curve(curveMonotoneX)
            .x((d) => x(d.x) + xOffset)
            .y((d) => y(d.y));

        remove();

        containerGroup
            .append('path')
            .data([data])
            .attr('class', LinePathClassName)
            .attr('d', valueline)
            .style('fill', 'none')
            .style('stroke', strokeColor)
            .style('stroke-width', 2);
    };

    const remove = () => {
        const lines = select(containerG.current).selectAll(
            `.${LinePathClassName}`
        );

        // check the number of existing lines, if greater than 0; remove all existing ones
        if (lines.size()) {
            lines.remove().exit();
        }
    };

    React.useEffect(() => {
        if (svgContainerData) {
            initContainer();
        }
    }, [svgContainerData]);

    React.useEffect(() => {
        if (svgContainerData && scales && data) {
            draw();
        }
    }, [scales, data]);

    return null;
}
Example #7
Source File: visualize.ts    From covid19-visualized with MIT License 4 votes vote down vote up
world = async (id: string, data: Country[]): Promise<void> => {
    const tooltipHtml = (data: Country): string => `
        <div id="covid19-tooltip">
            <h3 class="text-center my-2">${data.name}</h3>
            <h5>Confirmed: ${data.confirmed}</h5>
            <h5>Active: ${getActiveCase(data)} (${getPercentage(getActiveCase(data), data.confirmed)})</h5>
            <h5>Recovered: ${data.recovered} (${getPercentage(data.recovered, data.confirmed)})</h5>
            <h5>Deaths: ${data.deaths} (${getPercentage(data.deaths, data.confirmed)})</h5>
        </div>
    `

    const mergeSummary = (country: Country) => (
        (acc: Country, cur: Country): Country => {
            country.iso3 === cur.iso3 && (
                acc.countryRegion = cur.countryRegion,
                acc.confirmed += cur.confirmed,
                acc.recovered += cur.recovered,
                acc.deaths += cur.deaths
            )
            return acc
        }
    )

    const tooltip = select('.tooltip')
    
    const svg = select(`#${id}`)
        .append('svg')
        .attr('width', 960)
        .attr('height', 520)
    
    const path = geoPath().projection(
        (geoNaturalEarth1() 
            .rotate([-9, 0]) as any)
            .scale([1300 / (2 * Math.PI)])
            .translate([450, 300])
    )

    const worlds = (await window.fetch('/world-countries-110m.json')
        .then(response => response.json()) as Country[])
        .map(country => {
            const covid19Data = data.reduce(mergeSummary(country), {
                countryRegion: '',
                confirmed: 0,
                recovered: 0,
                deaths: 0
            } as Country)

            return {
                ...country,
                confirmed: covid19Data.confirmed,
                recovered: covid19Data.recovered,
                deaths: covid19Data.deaths,
                name: covid19Data.countryRegion || country.name,
                legend: worldLegends.find(({ value }) => !!covid19Data.countryRegion
                    ? covid19Data.confirmed > (value - 1)
                    : value === 0
                ).color
            }
        }) as any[]
    
    svg.selectAll('path')
        .data(worlds)
        .enter()
        .append('path')
        .attr('stroke', 'black')
        .attr('stroke-width', .75)
        .attr('d', path)
        .attr('fill', (data: Country) => data.legend)
        .on('mouseover', function(data: Country) {
            tooltip.style('hidden', false).html(tooltipHtml(data))
            select(this)
                .attr('fill', '#ddd')
                .attr('stroke', 'white')
                .attr('stroke-width', 2.5)
        })
        .on('mousemove', (data: Country) => {
            tooltip.classed('hidden', false)
                .style('top', event.pageY + 'px')
                .style('left', (event.pageX + 10) + 'px')
                .html(tooltipHtml(data))
        })
        .on('mouseout', function(data: Country) {
            tooltip.classed('hidden', true)
            select(this)
                .attr('fill', data.legend)
                .attr('stroke', 'black')
                .attr('stroke-width', .75)
        })
}
Example #8
Source File: Axis.tsx    From covid19-trend-map with Apache License 2.0 4 votes vote down vote up
Axis: React.FC<Props> = ({ svgContainerData, scales }) => {
    const drawXAxis = () => {
        const { dimension, g } = svgContainerData;

        const { height, width } = dimension;

        const mainGroup = select(g);

        const { x } = scales;

        const domain = x.domain();
        const startDateParts = domain[0].split('-').map((d) => +d);
        const startDate = new Date(
            startDateParts[0],
            startDateParts[1] - 1,
            startDateParts[2]
        );

        const endDateParts = domain[domain.length - 1]
            .split('-')
            .map((d) => +d);
        const endDate = new Date(
            endDateParts[0],
            endDateParts[1] - 1,
            endDateParts[2]
        );

        const xScale = scaleTime()
            .range([0, width])
            .domain([startDate, endDate]);

        const xAxis = axisBottom(xScale)
            // .ticks(timeMonth)
            .tickFormat((date: Date) => {
                return formatTime(date);
            });
        // .tickValues(d=>{})
        // .tickSizeInner(-(height))
        // .tickPadding(9)

        const xAxisLabel = mainGroup.selectAll('.x.axis');

        if (!xAxisLabel.size()) {
            mainGroup
                .append('g')
                .attr('class', 'x axis')
                .attr('transform', 'translate(0,' + height + ')')
                .call(xAxis);
        } else {
            xAxisLabel
                .attr('transform', 'translate(0,' + height + ')')
                .call(xAxis);
        }
    };

    const drawYAxis = () => {
        const { g, dimension } = svgContainerData;

        const { width } = dimension;

        const { y } = scales;

        const mainGroup = select(g);

        const yAxis = axisLeft(y)
            .ticks(3)
            .tickSizeInner(-width)
            .tickPadding(5)
            .tickFormat((num) => {
                return numberFns.abbreviateNumber(+num, 0);
            });

        const yAxisLabel = mainGroup.selectAll('.y.axis');

        if (!yAxisLabel.size()) {
            mainGroup.append('g').attr('class', 'y axis').call(yAxis);
        } else {
            yAxisLabel.call(yAxis);
        }
    };

    React.useEffect(() => {
        if (svgContainerData && scales) {
            drawXAxis();
            drawYAxis();
        }
    }, [svgContainerData, scales]);

    React.useEffect(()=>{
        console.log('draw axis')
    })

    return null;
}
Example #9
Source File: MouseEventsRect.tsx    From covid19-trend-map with Apache License 2.0 4 votes vote down vote up
MouseEventsRect: React.FC<Props> = ({
    data,
    svgContainerData,
    scales,

    onHover,
}) => {
    const containerG = React.useRef<SVGGElement>();

    const itemOnHover = React.useRef<Covid19CasesByTimeFeature>();

    const init = () => {
        const { g, dimension } = svgContainerData;

        const { height, width } = dimension;

        containerG.current = select(g).append('g').node();

        const container = select(containerG.current);

        container
            .append('line')
            .attr('class', VerticalRefLineClassName)
            .attr('x1', 0)
            .attr('y1', 0)
            .attr('x2', 0)
            .attr('y2', height)
            .style('opacity', 0)
            .attr('stroke-width', 0.5)
            .attr('stroke', 'rgba(255,255,255,.75)')
            .style('fill', 'none');

        container
            .append('rect')
            // .attr("class", ClassNames.BackgroundRect)
            .attr('width', width)
            .attr('height', height)
            .attr('fill', 'rgba(0,0,0,0)')
            .on('mouseleave', () => {
                setItemOnHover(null);
            })
            .on('mousemove', function () {
                const mousePosX = mouse(this)[0];
                setItemOnHover(getItemByMousePos(mousePosX));
            });
    };

    const setItemOnHover = (item?: Covid19CasesByTimeFeature) => {
        itemOnHover.current = item;
        updateVerticalRefLinePos();
        onHover(item);
    };

    const updateVerticalRefLinePos = (): void => {
        const { x } = scales;

        const item = itemOnHover.current;

        const vRefLine = select(containerG.current).select(
            `.${VerticalRefLineClassName}`
        );

        const xPos = item ? x(item.attributes.dt) + x.bandwidth() / 2 : 0;

        const opacity = item ? 1 : 0;

        vRefLine.attr('x1', xPos).attr('x2', xPos).style('opacity', opacity);
    };

    const getItemByMousePos = (
        mousePosX: number
    ): Covid19CasesByTimeFeature => {
        let itemIndex = -1;
        const { x } = scales;

        for (let i = 0, len = data.length; i < len; i++) {
            const currItem = data[i];
            const currItemPos = x(currItem.attributes.dt);

            const nextItemIndex = data[i + 1] ? i + 1 : i;
            const nextItem = data[nextItemIndex];
            const nextItemPos = x(nextItem.attributes.dt);

            if (mousePosX >= currItemPos && mousePosX <= nextItemPos) {
                const distToCurrItem = Math.abs(mousePosX - currItemPos);
                const distToNextItem = Math.abs(mousePosX - nextItemPos);

                itemIndex = distToCurrItem < distToNextItem ? i : nextItemIndex;

                break;
            }
        }

        return data[itemIndex];
    };

    useEffect(() => {
        if (svgContainerData && data.length) {
            init();
        }
    }, [svgContainerData, data]);

    useEffect(() => {
        if (svgContainerData && scales) {
            const { dimension } = svgContainerData;
            const { width } = dimension;

            select(containerG.current).select('rect').attr('width', width);
        }
    }, [scales]);

    return null;
}
Example #10
Source File: SvgContainer.tsx    From covid19-trend-map with Apache License 2.0 4 votes vote down vote up
SvgContainer: React.FC<Props> = ({
    // data,
    xDomain,
    yDomain,
    children,
}: Props) => {
    const windowSize = useWindowSize();

    const containerRef = useRef<HTMLDivElement>();
    const dimensionRef = useRef<Dimension>();

    const [svgContainerData, setSvgContainerData] = React.useState<
        SvgContainerData
    >();

    const [scales, setScales] = React.useState<Scales>();

    const init = () => {
        const container = containerRef.current;
        const width = container.offsetWidth - margin.left - margin.right;
        const height = container.offsetHeight - margin.top - margin.bottom;

        dimensionRef.current = {
            height,
            width,
        };

        select(container)
            .append('svg')
            .attr('width', '100%')
            .attr('height', height + margin.top + margin.bottom)
            .append('g')
            .attr('transform', `translate(${margin.left}, ${margin.top})`);

        const svgSelector = select(container).select<SVGElement>('svg');

        const svg = svgSelector.node();

        const g = svgSelector.select<SVGGElement>('g').node();

        const xScale = scaleBand<string>()
            .paddingInner(0.2)
            .range([0, width])
            .domain(xDomain);

        const yScale = scaleLinear().range([height, 0]).domain(yDomain).nice();

        setSvgContainerData({
            svg,
            g,
            margin,
            dimension: dimensionRef.current,
        });

        setScales({
            x: xScale,
            y: yScale,
        });
    };

    const scalesOnUpdateEndHandler = () => {
        setScales((scales) => {
            return {
                ...scales,
                // change last update time so the children components know scales have changed
                lastUpdateTime: new Date(),
            };
        });
    };

    const resizeHandler = () => {
        const container = containerRef.current;

        if (!container || !svgContainerData || !scales) {
            return;
        }

        // const { svg } = svgContainerData;
        const { x } = scales;

        // const newContainerWidth = window.innerWidth - 720;
        const newWidth = container.offsetWidth - margin.left - margin.right;

        dimensionRef.current.width = newWidth;

        x.range([0, newWidth]);

        scalesOnUpdateEndHandler();
    };

    useEffect(() => {
        init();
    }, []);

    useEffect(() => {
        if (scales && yDomain) {
            scales.y.domain(yDomain).nice();
            scalesOnUpdateEndHandler();
        }
    }, [yDomain]);

    React.useEffect(() => {
        resizeHandler();
    }, [windowSize]);

    return (
        <>
            <div
                ref={containerRef}
                style={{
                    position: 'relative',
                    width: '100%',
                    height: '100%',
                }}
            >
                {React.Children.map(children, (child) => {
                    return React.cloneElement(
                        child as React.ReactElement<any>,
                        {
                            svgContainerData,
                            scales,
                        }
                    );
                })}
            </div>
        </>
    );
}