Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 7x 7x 7x | import type { ElementRef } from '@angular/core'; import * as d3 from 'd3'; import type { IPieChartDataNode, IPieChartOptions } from '../interfaces/pie-chart.interface'; import { generateConfiguration } from './configuration.util'; /** * The pie chart default configuration. */ export const defaultPieChartConfig: IPieChartOptions = Object.freeze({ chartTitle: '', width: 600, height: 600, margin: { top: 20, right: 20, bottom: 20, left: 20, }, innerRadius: 0, // increase inner radius to render a donut chart showLabels: true, labelRadiusModifier: 50, labelTextWrapWidth: 60, transitionDuration: 1000, color: d3.scaleOrdinal(d3.schemeCategory10), } as IPieChartOptions); /** * Creates a container for the pie chart. * @param container the chart container * @param config the chart configuration * @returns the object with the svg element and the g element */ const createContainer = (container: ElementRef<HTMLDivElement>, config: IPieChartOptions) => { const id = container.nativeElement.id ?? 'pie-0'; d3.select(`#${id}`).select('svg').remove(); const svg = d3 .select(`#${id}`) .append('svg') .attr('width', config.width + config.margin.left + config.margin.right) .attr('height', config.height + config.margin.top + config.margin.bottom) .attr('class', id); const g = svg .append('g') .attr('transform', `translate(${config.width / 2 + config.margin.left},${config.height / 2 + config.margin.top})`); return { svg, g }; }; /** * Draws the pie chart. * @param container the chart container * @param data the chart data * @param options the chart options * @returns the chart configuration */ export const drawPieChart = (container: ElementRef<HTMLDivElement>, data: IPieChartDataNode[], options?: Partial<IPieChartOptions>) => { const config: IPieChartOptions = generateConfiguration<IPieChartOptions>(defaultPieChartConfig, options, {}); const { g } = createContainer(container, config); const pie = d3.pie<IPieChartDataNode>().value(datum => datum.y); const radius = Math.min(config.width, config.height) / 2; const arc = d3.arc<d3.PieArcDatum<IPieChartDataNode>>().innerRadius(config.innerRadius).outerRadius(radius); const arcs = g .selectAll('arc') .data(pie(data)) .enter() .append('g') .attr('class', 'arc') .on('mouseover', function (this, event: MouseEvent, d) { this.style.opacity = '0.8'; const tooltipText = `${d.data.key}: ${d.data.y}`; g.append('text') .attr('class', 'chart-tooltip') .style('opacity', 0) .attr('dx', -config.width / (2 * 2 * 2)) .attr('dy', config.height / 2 + config.margin.top) .text(tooltipText) .transition() .duration(config.transitionDuration) .style('opacity', 1); }) .on('mouseout', function (this, event, d) { this.style.opacity = 'unset'; d3.selectAll('.chart-tooltip') .transition() .duration(config.transitionDuration / 2) .style('opacity', 0) .remove(); }); arcs .append('path') .attr('fill', (d, i) => config.color(i.toString())) .attr('d', arc); if (config.showLabels) { const label = d3 .arc<d3.PieArcDatum<IPieChartDataNode>>() .innerRadius(radius) .outerRadius(radius + config.labelRadiusModifier); const textDy = 5; arcs .append('text') .attr('class', 'legend') .attr('text-anchor', 'middle') .attr('dy', textDy) .attr('transform', d => `translate(${label.centroid(d)})`) .style('font-size', '12px') .text(d => d.data.y); } return config; }; |