UNPKG

@obliczeniowo/elementary

Version:
242 lines (236 loc) 11.7 kB
import * as i0 from '@angular/core'; import { Input, ViewChild, Component, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { DrawingPdfInterface } from '@obliczeniowo/elementary/drawing-pdf'; import { TextAlign, DrawingSvgInterface, Rect } from '@obliczeniowo/elementary/drawing'; import { ColorHSV, Point2D } from '@obliczeniowo/elementary/classes'; import { ElementaryMath } from '@obliczeniowo/elementary/math'; import { keys } from '@obliczeniowo/elementary/objects'; import * as i1 from '@obliczeniowo/elementary/buttons'; import { ButtonsModule } from '@obliczeniowo/elementary/buttons'; class FlatPieDiagram { dc; areaRect; keyValues = {}; dr = 0; ray = 100; valueKeyFormat = (index, value, sum, key) => `${value} (${(value / sum * 100).toFixed(2)}%)`; colors = (index, value, max, count) => ({ fill: ColorHSV.createColorHSV(((360 / count) * 2 * index) / 2, 0.5, 255).convertToRGB().getHexColorBase, stroke: ColorHSV.createColorHSV(((360 / count) * 2 * index) / 2, 0.35, 255).convertToRGB().getHexColorBase, line: ColorHSV.createColorHSV(((360 / count) * 2 * index) / 2, 0.35, 150).convertToRGB().getHexColorBase, text: ColorHSV.createColorHSV(((360 / count) * 2 * index) / 2, 0.65, 200).convertToRGB().getHexColorBase }); constructor(dc, area) { this.dc = dc; this.areaRect = area; } sum() { let sum = 0; keys(this.keyValues).forEach((key) => sum += this.keyValues[key]); return sum; } minMax() { const minMax = { min: 0, max: 0 }; return keys(this.keyValues).reduce((prev, curr) => (prev = prev ? { min: Math.min(prev.min, this.keyValues[curr]), max: Math.max(prev.max, this.keyValues[curr]) } : { min: this.keyValues[curr], max: this.keyValues[curr] }, prev), minMax); } draw(dc = this.dc) { dc.clear(); const sum = this.sum(); let start = 0; let da = 0; const center = new Point2D(this.areaRect.width / 2, this.areaRect.height / 2); this.ray = Math.min(this.areaRect.width, this.areaRect.height) / 3; const minMax = this.minMax(); const length = keys(this.keyValues).length; if (sum) { const options = []; let leftTopIndex = 0; let rightTopIndex = 0; let leftBottomIndex = 0; let rightBottomIndex = 0; const dk = ElementaryMath.degreesToRadians(10); keys(this.keyValues).forEach((key, oIndex) => { da = this.keyValues[key] / sum * Math.PI * 2; const right = start + da / 2 < Math.PI / 2 || start + da / 2 > 3 * Math.PI / 2; const bottom = start + da / 2 < Math.PI; let index = 0; if (da < dk) { if (!right && !bottom) { leftTopIndex += 1; index = leftTopIndex; } else if (right && !bottom) { rightTopIndex += 1; index = rightTopIndex; } else if (!right && bottom) { leftBottomIndex += 1; index = leftBottomIndex; } else if (right && bottom) { rightBottomIndex += 1; index = rightBottomIndex; } } options.push({ start, da, right, bottom, index, colors: this.colors(oIndex, this.keyValues[key], minMax, length) }); start += da; }); start = 0; keys(this.keyValues).forEach((key, index) => { da = this.keyValues[key] / sum * Math.PI * 2; const rotatedPoint = center.add(new Point2D(this.dr, 0).rotate(start + da / 2)); dc.drawPie(rotatedPoint, this.ray, this.ray, start, start + da > Math.PI * 2 ? Math.PI * 2 : start + da, 1, options[index].colors.stroke, options[index].colors.fill); start += da; }); start = 0; keys(this.keyValues).forEach((key, index) => { da = this.keyValues[key] / sum * Math.PI * 2; const text = this.valueKeyFormat(index, this.keyValues[key], sum, key); const startPoint = center.add(new Point2D(this.dr + this.ray * 0.9).rotate(start + da / 2)); dc.setFontSize(8); if (da < dk) { let dy = 0; const angle = options[index]; if (!angle.right && !angle.bottom) { dy = leftTopIndex * 12; } else if (angle.right && !angle.bottom) { dy = (angle.index * 2 - 1) * 12; } else if (!angle.right && angle.bottom) { dy = (angle.index * 2 - 1) * 12; } else if (angle.right && angle.bottom) { dy = rightBottomIndex * 12; } dy = this.ray - dy; const end = center.add(new Point2D(options[index].right ? (this.ray * 1.2) : -this.ray * 1.2, options[index].bottom ? options[index].index * 12 + dy : -options[index].index * 12 - dy)); dc.drawLine(startPoint, end, 1, options[index].colors.line) .setTextAlign(angle.right && TextAlign.LEFT || TextAlign.RIGHT) .drawText(text, end.add(new Point2D(angle.right && 2 || -2, 2)), options[index].colors.text, 0); } else { const textAngle = -180 / Math.PI * (start + da / 2); dc.setTextAlign(options[index].right ? TextAlign.RIGHT : TextAlign.LEFT) .drawText(text, startPoint, options[index].colors.text, textAngle < -90 && textAngle > -270 ? textAngle + 180 : textAngle); } start += da; }); } } } class FlatPieDiagramComponent { renderer; drawing; width = 800; height = 528; pData = {}; get data() { return this.pData; } set data(value) { this.pData = value; if (this.drawing) { this.drawing.keyValues = this.pData; this.drawing.draw(); } } svg; _colors; _valueKeyFormat = (index, value, sum, key) => `${value} (${(value / sum * 100).toFixed(2)}%)`; set valueKeyFormat(valueKeyFormat) { if (valueKeyFormat) { this._valueKeyFormat = valueKeyFormat; if (this.drawing) { this.drawing.valueKeyFormat = valueKeyFormat; this.drawing.draw(); } } } set colors(colors) { if (colors) { this._colors = colors; if (this.drawing) { this.drawing.colors = colors; this.drawing.draw(); } } } constructor(renderer) { this.renderer = renderer; } ngAfterViewInit() { this.drawing = new FlatPieDiagram(new DrawingSvgInterface(this.svg.nativeElement, this.renderer), new Rect(new Point2D(0, 0), new Point2D(this.width, this.height))); this.drawing.keyValues = this.pData; if (this._valueKeyFormat) { this.drawing.valueKeyFormat = this._valueKeyFormat; } if (this._colors) { this.drawing.colors = this._colors; } this.drawing.draw(); } pdf() { const dc = new DrawingPdfInterface(this.drawing.areaRect); this.drawing.draw(dc); dc.save('flat-pie-diagram'); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FlatPieDiagramComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: FlatPieDiagramComponent, isStandalone: false, selector: "obl-flat-pie-diagram", inputs: { data: "data", valueKeyFormat: "valueKeyFormat", colors: "colors" }, viewQueries: [{ propertyName: "svg", first: true, predicate: ["diagram"], descendants: true }], ngImport: i0, template: "<div class=\"svgContainer\">\n <svg #diagram [attr.viewBox]=\"'0 0 ' + width + ' ' + height\"></svg>\n\n <button class=\"pdf-button\" oblButton icon=\"file\" (click)=\"pdf()\">\n </button>\n</div>\n", styles: [":host .svgContainer{overflow:auto;max-width:100%;position:relative}:host .svgContainer .pdf-button{position:absolute;right:20px;top:20px;display:none}:host .svgContainer:hover .pdf-button{display:block}\n"], dependencies: [{ kind: "directive", type: i1.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FlatPieDiagramComponent, decorators: [{ type: Component, args: [{ selector: 'obl-flat-pie-diagram', standalone: false, template: "<div class=\"svgContainer\">\n <svg #diagram [attr.viewBox]=\"'0 0 ' + width + ' ' + height\"></svg>\n\n <button class=\"pdf-button\" oblButton icon=\"file\" (click)=\"pdf()\">\n </button>\n</div>\n", styles: [":host .svgContainer{overflow:auto;max-width:100%;position:relative}:host .svgContainer .pdf-button{position:absolute;right:20px;top:20px;display:none}:host .svgContainer:hover .pdf-button{display:block}\n"] }] }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { data: [{ type: Input }], svg: [{ type: ViewChild, args: ['diagram'] }], valueKeyFormat: [{ type: Input }], colors: [{ type: Input }] } }); class FlatPieDiagramModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FlatPieDiagramModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: FlatPieDiagramModule, declarations: [FlatPieDiagramComponent], imports: [CommonModule, ButtonsModule], exports: [FlatPieDiagramComponent] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FlatPieDiagramModule, imports: [CommonModule, ButtonsModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FlatPieDiagramModule, decorators: [{ type: NgModule, args: [{ declarations: [ FlatPieDiagramComponent ], imports: [ CommonModule, ButtonsModule ], exports: [ FlatPieDiagramComponent ] }] }] }); /** * Generated bundle index. Do not edit. */ export { FlatPieDiagram, FlatPieDiagramComponent, FlatPieDiagramModule }; //# sourceMappingURL=obliczeniowo-elementary-flat-pie-diagram.mjs.map