@obliczeniowo/elementary
Version:
Library made in Angular version 20
258 lines (252 loc) • 11.3 kB
JavaScript
import * as i0 from '@angular/core';
import { input, EventEmitter, effect, ViewChild, Output, Input, Component, NgModule } from '@angular/core';
import * as i1 from '@angular/common';
import { CommonModule, DatePipe } from '@angular/common';
import { TextAlign, DrawingSvgInterface } from '@obliczeniowo/elementary/drawing';
import { keys } from '@obliczeniowo/elementary/objects';
import { Point2D } from '@obliczeniowo/elementary/classes';
class DaypartsStatistics {
dc;
statistics;
datePipe;
events;
max = 0;
fontSize = 12;
ray = 12;
textOffset = 100;
constructor(dc, statistics, datePipe, events) {
this.dc = dc;
this.statistics = statistics;
this.datePipe = datePipe;
this.events = events;
this.setMax();
}
getWidth() {
return this.textOffset + 2 * this.ray * 24;
}
getHeight() {
return this.ray * 2 * 7 + this.fontSize * 2;
}
updateMax(max) {
this.max = max;
}
setStatistics(statistics) {
this.statistics = statistics;
this.setMax();
this.draw();
}
draw(dc = this.dc) {
const { statistics, ray, fontSize, textOffset } = this;
const offset = new Point2D(textOffset, ray);
dc.clear();
keys(statistics).forEach((day) => {
keys(statistics[day]).forEach((hour) => {
const hourData = statistics[day][hour];
const start = new Point2D(2 * ray * hour, 2 * ray * day);
dc
.group({
svgOnly: {
events: {
click: () => this.events.clicked(hourData),
mouseover: () => this.events.mouseover && this.events.mouseover(hourData)
}
}
})
.drawRect(start.x + textOffset - ray, start.y, 2 * ray, 2 * ray, 0, 'none', '#ffffff', {
svgOnly: {
attributes: { opacity: 0.1 },
}
})
.drawCircle(start.add(offset), ray * hourData.value / this.max, 0, '#000000', '#00aad4', {
svgOnly: {
classes: ['obl-dayparts-statistics', 'scale-up'],
},
style: {
'transform-origin': `${start.x + offset.x}px ${start.y + offset.y}px`
}
})
.endGroup();
});
});
const date = new Date();
date.setTime(100);
dc.setFontSize(fontSize);
dc.setTextAlign(TextAlign.LEFT);
for (let day = 0; day < 7; day++) {
date.setTime((day + 4) * 24 * 3600 * 1000);
dc.drawText(this.datePipe.transform(date, 'EEEE') || '', new Point2D(10, ray + fontSize * 0.3 + day * 2 * ray), 'var(--default-text-color)', 0);
}
const hoursOffset = new Point2D(offset.x, 7 * 2 * ray + 1.5 * fontSize);
dc.setTextAlign(TextAlign.CENTER);
for (let hour = 0; hour < 24; hour++) {
dc.drawText(hour < 10 ? '0' + hour : hour.toString(), hoursOffset.add(new Point2D(hour * 2 * ray, 0)), 'var(--default-text-color)', 0);
}
}
setMax() {
const { statistics } = this;
this.max = 0;
keys(statistics).forEach((key) => {
const value = statistics[key];
keys(value).forEach((key) => {
const count = value[key].value;
if (this.max < count) {
this.max = count;
}
});
});
}
}
class DaypartsStatisticsComponent {
datePipe;
renderer;
/**
* Do not use this one together with statistics
*/
data = input([]);
/**
* Under DaypartsData you can put any kind of key: value fields and now here you can specify field
* name to make it representable on diagram
*/
valueKey = input();
/**
* Do not use this one together with data
*/
set statistics(statistics) {
this._statistics = statistics;
this._daypartsStatistics?.setStatistics(statistics);
}
translations = input({
value: 'Value'
});
clicked = new EventEmitter();
svg;
dc;
_statistics = {};
max = 0;
_daypartsStatistics;
current;
constructor(datePipe, renderer) {
this.datePipe = datePipe;
this.renderer = renderer;
effect(() => {
if (this.data().length) {
this.transform();
}
});
effect(() => {
this.setMax();
this.draw();
});
}
ngAfterViewInit() {
this.dc = new DrawingSvgInterface(this.svg.nativeElement, this.renderer);
setTimeout(() => this.draw());
}
draw() {
if (this.dc) {
if (!this._daypartsStatistics) {
this._daypartsStatistics = new DaypartsStatistics(this.dc, this._statistics, this.datePipe, {
clicked: (value) => this.clicked.emit(value),
mouseover: (value) => {
this.current = value;
}
});
}
this._daypartsStatistics?.setStatistics(this._statistics);
}
}
transform() {
this._statistics = {};
const { _statistics: statistics } = this;
this.data().forEach(item => {
const hours = item.date.getHours();
const day = item.date.getDay();
const data = statistics[day];
const hoursObj = () => ({
data: [item],
value: 1
});
if (data) {
const hour = data[hours];
if (hour) {
hour.value++;
hour.data.push(item);
}
else {
data[hours] = hoursObj();
}
}
else {
statistics[day] = {
[hours]: hoursObj()
};
}
});
this.setMax();
this.draw();
}
setMax() {
const { _statistics: statistics } = this;
let max = 0;
const valueKey = this.valueKey();
if (valueKey) {
keys(statistics).forEach((key) => {
const value = statistics[key];
keys(value).forEach((key) => {
const data = value[key].data;
const v = (valueKey && data?.[0][valueKey] &&
(data.reduce((p, c) => p += c[valueKey], 0) / data.length)) ?? (data?.length || 0);
value[key].value = v;
max = max < v ? v : max;
});
});
if (max === 0) {
max = 1;
}
this.max = max;
this._daypartsStatistics?.updateMax(max);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DaypartsStatisticsComponent, deps: [{ token: i1.DatePipe }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: DaypartsStatisticsComponent, isStandalone: false, selector: "obl-dayparts-statistics", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, valueKey: { classPropertyName: "valueKey", publicName: "valueKey", isSignal: true, isRequired: false, transformFunction: null }, statistics: { classPropertyName: "statistics", publicName: "statistics", isSignal: false, isRequired: false, transformFunction: null }, translations: { classPropertyName: "translations", publicName: "translations", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, viewQueries: [{ propertyName: "svg", first: true, predicate: ["svg"], descendants: true }], ngImport: i0, template: "<svg\n [attr.width]=\"_daypartsStatistics?.getWidth() || 0\"\n [attr.height]=\"_daypartsStatistics?.getHeight() || 0\"\n #svg\n></svg>\n<div class=\"current\">\n @if (current) {\n {{ translations().value }}: {{ current.value }}\n }\n</div>\n", styles: ["svg::ng-deep .obl-dayparts-statistics{cursor:pointer;fill:#00aad4;stroke:none}svg::ng-deep .obl-dayparts-statistics:hover{opacity:.8}svg::ng-deep .obl-dayparts-statistics-text{fill:var(--default-text-color)}.current{font-size:12px;padding-left:95px;min-height:20px}\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DaypartsStatisticsComponent, decorators: [{
type: Component,
args: [{ selector: 'obl-dayparts-statistics', standalone: false, template: "<svg\n [attr.width]=\"_daypartsStatistics?.getWidth() || 0\"\n [attr.height]=\"_daypartsStatistics?.getHeight() || 0\"\n #svg\n></svg>\n<div class=\"current\">\n @if (current) {\n {{ translations().value }}: {{ current.value }}\n }\n</div>\n", styles: ["svg::ng-deep .obl-dayparts-statistics{cursor:pointer;fill:#00aad4;stroke:none}svg::ng-deep .obl-dayparts-statistics:hover{opacity:.8}svg::ng-deep .obl-dayparts-statistics-text{fill:var(--default-text-color)}.current{font-size:12px;padding-left:95px;min-height:20px}\n"] }]
}], ctorParameters: () => [{ type: i1.DatePipe }, { type: i0.Renderer2 }], propDecorators: { statistics: [{
type: Input
}], clicked: [{
type: Output
}], svg: [{
type: ViewChild,
args: ['svg']
}] } });
class DaypartsStatisticsModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DaypartsStatisticsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: DaypartsStatisticsModule, declarations: [DaypartsStatisticsComponent], imports: [CommonModule], exports: [DaypartsStatisticsComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DaypartsStatisticsModule, providers: [
DatePipe
], imports: [CommonModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DaypartsStatisticsModule, decorators: [{
type: NgModule,
args: [{
declarations: [
DaypartsStatisticsComponent
],
providers: [
DatePipe
],
imports: [
CommonModule
],
exports: [
DaypartsStatisticsComponent
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { DaypartsStatistics, DaypartsStatisticsComponent, DaypartsStatisticsModule };
//# sourceMappingURL=obliczeniowo-elementary-dayparts-statistics.mjs.map