d3#event TypeScript Examples

The following examples show how to use d3#event. 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: 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 #2
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 #3
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 #4
Source File: render.ts    From fe-v5 with Apache License 2.0 4 votes vote down vote up
function renderHoneyComb(svgGroup, data, { width, height, fontAutoScale = true, fontSize = 12 }) {
  const t = transition().duration(750);
  const { columns: mapColumns, rows: mapRows } = getMapColumnsAndRows(width, height, data.length);
  const hexRadius = Math.floor(min([width / ((mapColumns + 0.5) * Math.sqrt(3)), height / ((mapRows + 1 / 3) * 1.5), width / 7]));
  const hexbinWidth = Math.sin((60 * Math.PI) / 180) * hexRadius * 2;
  const points = getPlaceHolderElems(mapRows, mapColumns, data.length, hexRadius);
  let adjustedOffSetX = (width - hexbinWidth * mapColumns) / 2 + hexbinWidth / 2;
  if (points.length >= mapColumns * 2) {
    adjustedOffSetX = (width - hexbinWidth * mapColumns - hexbinWidth / 2) / 2 + hexbinWidth / 2;
  }
  const offSetY = hexRadius;
  const hexbin = d3Hexbin().radius(hexRadius);
  const translateX = adjustedOffSetX;
  const translateY = offSetY;
  const hexbinPoints = hexbin(points);
  const textAreaHeight = hexRadius;
  const textAreaWidth = hexbinWidth * 0.9;
  let activeLabelFontSize = fontSize;
  let activeValueFontSize = fontSize;
  let isShowEllipses = false;
  let numOfChars = 0;

  if (fontAutoScale) {
    let maxLabel = '';
    let maxValue = '';
    for (let i = 0; i < data.length; i++) {
      if (data[i].name.length > maxLabel.length) {
        maxLabel = data[i].name;
      }
      if (_.toString(data[i].value).length > maxValue.length) {
        maxValue = _.toString(data[i].value);
      }
    }
    activeLabelFontSize = computeTextFontSize(maxLabel, 2, textAreaWidth, textAreaHeight);
    activeValueFontSize = computeTextFontSize(maxValue, 2, textAreaWidth, textAreaHeight);
    if (activeLabelFontSize < minFont) {
      isShowEllipses = true;
      numOfChars = 18;
      maxLabel = maxLabel.substring(0, numOfChars + 2);
      activeLabelFontSize = computeTextFontSize(maxLabel, 2, textAreaWidth, textAreaHeight);
      if (activeLabelFontSize < minFont) {
        numOfChars = 10;
        maxLabel = maxLabel.substring(0, numOfChars + 2);
        activeLabelFontSize = computeTextFontSize(maxLabel, 2, textAreaWidth, textAreaHeight);
        if (activeLabelFontSize < minFont) {
          numOfChars = 6;
          maxLabel = maxLabel.substring(0, numOfChars + 2);
          activeLabelFontSize = computeTextFontSize(maxLabel, 2, textAreaWidth, textAreaHeight);
        }
      }
    }
    if (activeValueFontSize > activeLabelFontSize) {
      activeValueFontSize = activeLabelFontSize;
    }
  }

  const valueWithLabelTextAlignment = textAreaHeight / 2 / 2 + activeValueFontSize / 2;
  const labelWithValueTextAlignment = -(textAreaHeight / 2 / 2) + activeLabelFontSize / 2;

  svgGroup.attr('width', width).attr('height', height).attr('transform', `translate(${translateX},${translateY})`);

  const hexagons = svgGroup.selectAll('.hexagon').data(hexbinPoints);
  const removeSelection = hexagons.exit().remove();

  hexagons
    .enter()
    .append(function () {
      const nodeToAdd = document.createElementNS(xmlns, 'path');
      return nodeToAdd;
    })
    .attr('class', 'hexagon')
    // TODO: 进入动画暂时关闭
    // .attr("d", function(d) {
    //   return "M" + d.x + "," + d.y + zeroHexBin.hexagon();
    // })
    .on('mousemove', function (_d, i) {
      const metricObj = data[i]?.metric;
      const metricName = metricObj?.__name__ || 'value';
      const metricNameRow = `<div><strong>${metricName}: ${data[i]?.value}</strong></div>`;
      const labelsRows = _.map(_.omit(metricObj, '__name__'), (val, key) => {
        return `<div>${key}: ${val}</div>`;
      });
      const content = `${metricNameRow}${labelsRows.join('')}`;
      div.style('opacity', 0.9);
      div
        .html(content)
        .style('left', event.pageX + 10 + 'px')
        .style('top', event.pageY - 28 + 'px');
    })
    .on('mouseout', function () {
      div.style('opacity', 0);
    })
    .attr('stroke', 'white')
    .attr('stroke-width', '1px')
    .style('fill', (_d, i) => {
      return data[i]?.color;
    })
    .style('fill-opacity', 1)
    .transition(t)
    .attr('d', function (d) {
      return 'M' + d.x + ',' + d.y + hexbin.hexagon();
    });

  hexagons
    .enter()
    .append('text')
    .attr('x', function (d) {
      return d.x;
    })
    .attr('y', function (d) {
      return d.y + labelWithValueTextAlignment;
    })
    .text(function (_d, i) {
      let name = data[i]?.name;
      if (isShowEllipses) {
        name = name.substring(0, numOfChars) + '...';
        return name;
      }
      return name;
    })
    .attr('text-anchor', 'middle')
    .attr('alignment-baseline', 'central')
    .style('pointer-events', 'none')
    .style('font-size', activeLabelFontSize + 'px')
    .style('fill', 'white')
    .each(function (this, d) {
      d.bbox = this.getBBox();
    });

  if (activeLabelFontSize) {
    hexagons
      .enter()
      .insert('rect', 'text')
      .attr('x', function (d) {
        return d.bbox.x - 4;
      })
      .attr('y', function (d) {
        return d.bbox.y - 4;
      })
      .attr('rx', 2)
      .attr('ry', 2)
      .attr('width', function (d) {
        return d.bbox.width + 8;
      })
      .attr('height', function (d) {
        return d.bbox.height + 8;
      })
      .attr('fill-opacity', '0.2')
      .style('fill', '#000')
      .style('pointer-events', 'none');
  }

  hexagons
    .enter()
    .append('text')
    .attr('x', function (d) {
      return d.x;
    })
    .attr('y', function (d) {
      return d.y + valueWithLabelTextAlignment;
    })
    .text(function (_d, i) {
      const value = data[i]?.value;
      return value;
    })
    .attr('text-anchor', 'middle')
    .attr('alignment-baseline', 'central')
    .style('font-size', activeValueFontSize + 'px')
    .style('fill', 'white')
    .style('pointer-events', 'none')
    .each(function (this, d) {
      d.bbox = this.getBBox();
    });

  if (activeValueFontSize) {
    hexagons
      .enter()
      .insert('rect', 'text')
      .attr('x', function (d) {
        return d.bbox.x - 4;
      })
      .attr('y', function (d) {
        return d.bbox.y - 4;
      })
      .attr('rx', 2)
      .attr('ry', 2)
      .attr('width', function (d) {
        return d.bbox.width + 8;
      })
      .attr('height', function (d) {
        return d.bbox.height + 8;
      })
      .attr('fill-opacity', '0.2')
      .style('fill', '#000')
      .style('pointer-events', 'none');
  }

  return [...removeSelection.nodes()];
}