UNPKG

@obliczeniowo/elementary

Version:
1,160 lines 63.9 kB
import * as i0 from '@angular/core';
import { ContentChild, HostBinding, Component, input, effect, Input, ViewChild, ChangeDetectionStrategy, EventEmitter, Output, NgModule } from '@angular/core';
import * as i1 from '@angular/common';
import { DecimalPipe, CommonModule } from '@angular/common';
import * as i1$1 from '@obliczeniowo/elementary/buttons';
import { ButtonsModule } from '@obliczeniowo/elementary/buttons';
import * as i5 from '@obliczeniowo/elementary/text-pipes';
import { TranslationPipe, TextPipesModule } from '@obliczeniowo/elementary/text-pipes';
import * as i3 from '@obliczeniowo/elementary/input';
import { InputModule } from '@obliczeniowo/elementary/input';
import * as i2 from '@obliczeniowo/elementary/numeric-pipes';
import { AbsPipe, MinPipe } from '@obliczeniowo/elementary/numeric-pipes';
import { ElementaryMath } from '@obliczeniowo/elementary/math';
import { Point2D, LinearFunction2D } from '@obliczeniowo/elementary/classes';
import { TextAlign, LinePattern, TextBaseline, Rect, DrawingSvgInterface } from '@obliczeniowo/elementary/drawing';
import { Subject } from 'rxjs';
import { ns } from '@obliczeniowo/elementary/svg';
import { DrawingPdfInterface } from '@obliczeniowo/elementary/drawing-pdf';
import { keysValues } from '@obliczeniowo/elementary/objects';
import * as i1$2 from '@obliczeniowo/elementary/files';

/**
 * Create hover over element on obl-linear-diagram-2d element by ng-content
 *
 * example with own template
 *
 * <obl-linear-diagram-2d [points]="points">
 *   <ng-template #xyTemplate let-x="x" let-y="y">
 *    <div class="xy-template">
 *      <div>x = {{ x | number: '0.5-5' }}</div>
 *      <div>y = {{ y | number: '0.5-5' }}</div>
 *    </div>
 *  </ng-template>
 * </obl-linear-diagram-2d>
 */
class DiagramPointHoverComponent {
    x;
    y;
    pOnMouseOver;
    set onMouseOver(value) {
        if (this.pOnMouseOver && !this.pOnMouseOver.closed) {
            this.pOnMouseOver.unsubscribe();
        }
        if (value) {
            this.pOnMouseOver = value.subscribe((element) => {
                const point = JSON.parse(element.dataset.point);
                const pointSvg = JSON.parse(element.dataset.pointSvg);
                this.x = point.x;
                this.y = point.y;
                const rect = element.getBoundingClientRect();
                const svgHeight = element.ownerSVGElement?.clientHeight;
                const svgWidth = element.ownerSVGElement?.clientWidth;
                const viewBox = (element.ownerSVGElement?.getAttribute('viewBox')).split(' ').slice(2).map(v => parseFloat(v));
                this.left = pointSvg.x / viewBox[0] * svgWidth + rect.width / 2;
                this.top = pointSvg.y / viewBox[1] * svgHeight + rect.height / 2;
                this.over = '';
            });
        }
    }
    pOnMouseOut;
    set onMouseOut(value) {
        if (this.pOnMouseOut && !this.pOnMouseOut.closed) {
            this.pOnMouseOut.unsubscribe();
        }
        if (value) {
            this.pOnMouseOut = value.subscribe(() => {
                this.over = 'none';
            });
        }
    }
    over = 'none';
    top = 0;
    left = 0;
    xyTemplate;
    ngOnDestroy() {
        this.onMouseOut = undefined;
        this.onMouseOver = undefined;
        if (this.pOnMouseOut && !this.pOnMouseOut.closed) {
            this.pOnMouseOut.unsubscribe();
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DiagramPointHoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: DiagramPointHoverComponent, isStandalone: false, selector: "obl-diagram-point-hover", host: { properties: { "style.display": "this.over", "style.top.px": "this.top", "style.left.px": "this.left" } }, queries: [{ propertyName: "xyTemplate", first: true, predicate: ["xyTemplate"], descendants: true }], ngImport: i0, template: "@if (!xyTemplate) {\n  <div>\n    <p>x: {{ x }}</p>\n    <p>y: {{ y }}</p>\n  </div>\n}\n\n<ng-container *ngTemplateOutlet=\"xyTemplate; context: { x: x, y: y }\"></ng-container>\n\n<ng-content></ng-content>", styles: [":root{--obl-spinner-width: 30px;--obl-font-size: 14px}:host{position:absolute;top:0;left:0}:host div{min-width:100px;background-color:#000;border-radius:5px;opacity:.8;padding:6px}:host div p{margin:4px;font-size:14px;color:#fff}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DiagramPointHoverComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-diagram-point-hover', standalone: false, template: "@if (!xyTemplate) {\n  <div>\n    <p>x: {{ x }}</p>\n    <p>y: {{ y }}</p>\n  </div>\n}\n\n<ng-container *ngTemplateOutlet=\"xyTemplate; context: { x: x, y: y }\"></ng-container>\n\n<ng-content></ng-content>", styles: [":root{--obl-spinner-width: 30px;--obl-font-size: 14px}:host{position:absolute;top:0;left:0}:host div{min-width:100px;background-color:#000;border-radius:5px;opacity:.8;padding:6px}:host div p{margin:4px;font-size:14px;color:#fff}\n"] }]
        }], propDecorators: { over: [{
                type: HostBinding,
                args: ['style.display']
            }], top: [{
                type: HostBinding,
                args: ['style.top.px']
            }], left: [{
                type: HostBinding,
                args: ['style.left.px']
            }], xyTemplate: [{
                type: ContentChild,
                args: ['xyTemplate']
            }] } });

class YAxisI {
    textAlign = TextAlign.RIGHT;
    /** pipe used for formatting x/y axis text */
    decimalPipe = new DecimalPipe('en-US');
    /**
     * Function that give you control over format of y axis values
     * this function can be overrided let programmer use whatever he want
     * @param y value on scale to draw
     * @param yK y * pow(10, yK) - power of 10 that provide  number into n.xxxx format
     * @returns formatted string value of y scale
     */
    yFormatter = (y, yK) => this.decimalPipe.transform(y * Math.pow(10, yK), '0.3-3') || 'NaN';
}
class YAxis extends YAxisI {
    draw(dc, startPoint, startScale, dY, minMax, yScale, yK, diagramArea, yLabel, yOptions) {
        dc.group({ name: 'yAxis' });
        const color = yOptions?.color;
        this.textAlign = yOptions?.textAlign || this.textAlign;
        if (this.textAlign !== TextAlign.RIGHT) {
            const m = new Point2D(diagramArea.width, 0);
            startPoint = startPoint.add(m);
            startScale = startScale.add(m);
        }
        let posy = new Point2D(startPoint.x, startScale.y);
        const eP = startPoint.add(new Point2D(0, -diagramArea.height));
        dc.drawArrow(startPoint, eP, yOptions?.stroke || 1, color || '#000000', !!yOptions?.arrow);
        dc.setTextAlign(this.textAlign);
        let lengthYLabel = 0;
        let yText = '';
        dc.group({ name: 'values' });
        const dm = new Point2D(this.textAlign === TextAlign.RIGHT ? -2 : 4, 1.5);
        const dsc = new Point2D(0, -dY * yScale);
        if (minMax.min !== minMax.max) {
            for (let y = Math.ceil(minMax.min / dY) * dY; y <= minMax.max; y += dY) {
                yText = this.yFormatter(y, yK);
                const tw = dc.getTextWidth(yText);
                lengthYLabel = tw > lengthYLabel ? tw : lengthYLabel;
                dc.drawText(yText, posy.add(dm), color || '#000000', 0);
                posy = posy.add(dsc);
                if (posy.y < eP.y) {
                    break;
                }
            }
        }
        dc.setTextAlign(TextAlign.LEFT);
        dc.endGroup();
        dc.endGroup();
        if (yLabel) {
            const textWidth = dc.getTextWidth(yLabel);
            const offset = this.textAlign === TextAlign.RIGHT
                ? new Point2D(diagramArea.x, diagramArea.y + diagramArea.height * 0.5).add(new Point2D(-lengthYLabel - 10, textWidth / 2))
                : new Point2D(diagramArea.x + diagramArea.width, diagramArea.y + diagramArea.height * 0.5).add(new Point2D(lengthYLabel + 20, textWidth / 2));
            dc.drawText(yLabel, offset, color || '#009900', 90);
        }
        if (yK) {
            const offset = this.textAlign === TextAlign.RIGHT
                ? new Point2D(diagramArea.x, diagramArea.y).add(new Point2D(-lengthYLabel - 10, 0))
                : new Point2D(diagramArea.x + diagramArea.width, diagramArea.y).add(new Point2D(lengthYLabel + 20, 0));
            dc.setTextAlign(TextAlign.RIGHT);
            dc.drawText(`×e${-yK}`, offset, color || '#009900', 90);
        }
        return lengthYLabel;
    }
}

var PointType;
(function (PointType) {
    PointType["NONE"] = "none";
    PointType["CIRCLE"] = "circle";
    PointType["X"] = "x";
    PointType["STAR"] = "star";
})(PointType || (PointType = {}));
class LinearDiagram2D {
    static drawingPoints = new Map();
    options;
    /** min max for x */
    xMinMax;
    /** min max for y */
    yMinMax;
    /** */
    yAxis = new YAxis();
    /** */
    xScale;
    /** */
    yScale;
    xCursorLine;
    yCursorLine;
    xyCursor;
    selectionRange;
    /** diagram area rect (area where diagram data will be drawn) */
    diagramArea;
    pPoints = [[]];
    /** diagram title text */
    title = '';
    /** x label description */
    xLabel = '';
    /** y label description */
    yLabel = '';
    /** legend description table */
    legend = [];
    /** pipe used for formatting x/y axis text */
    decimalPipe = new DecimalPipe('en-US');
    /**  */
    xK = 0;
    /** */
    yK = 0;
    redraw = new Subject();
    onPointMouseOver = new Subject();
    onPointMouseOut = new Subject();
    static registerDrawingPointFu(name, fu) {
        if (LinearDiagram2D.drawingPoints.has(name)) {
            return false;
        }
        LinearDiagram2D.drawingPoints.set(name, fu);
        return true;
    }
    /**
     * Function that give you control over format of x axis values
     * this function can be overridden let programmer use whatever he want
     * @param x value on scale to draw
     * @param xK x * pow(10, xK) - power of 10 that provide  number into n.xxxx format
     * @returns formatted string value of x scale
     */
    xFormatter = (x, xK) => this.decimalPipe.transform(x * Math.pow(10, xK), '0.2-2') || 'NaN';
    set yFormatter(fu) {
        this.yAxis.yFormatter = fu;
    }
    /**
     * set points vector and recalculate xMinMax & yMinMax values for diagram
     */
    set points(points) {
        this.pPoints = points;
        this.xMinMax = this.getXMinMax();
        this.xK = -Math.floor(Math.log10(Math.max(Math.abs(this.xMinMax.max), Math.abs(this.xMinMax.min))));
        this.yMinMax = this.getYMinMax();
        this.yK = -Math.floor(Math.log10(Math.max(Math.abs(this.yMinMax.max), Math.abs(this.yMinMax.min))));
    }
    /**
     * @param area diagram area
     * @param points points vectors as table of Point2D
     * @param options options settings for diagram (most of them override default one)
     */
    constructor(area, points, options) {
        if (!LinearDiagram2D.drawingPoints.has(PointType.CIRCLE)) {
            LinearDiagram2D.drawingPoints.set(PointType.CIRCLE, (point, dc, stroke, color) => dc.drawCircle(point, 2, stroke, color, 'none'));
            LinearDiagram2D.drawingPoints.set(PointType.STAR, (point, dc, stroke, color) => [0, 1, 2, 3, 4, 5].forEach((i) => dc.drawLine(point, new Point2D(0, 5)
                .rotate(ElementaryMath.degreesToRadians(60) * i)
                .add(point), stroke, color)));
            LinearDiagram2D.drawingPoints.set(PointType.X, (point, dc, stroke, color) => [0, 1, 2, 3].forEach((i) => dc.drawLine(point, new Point2D(0, 5)
                .rotate((Math.PI / 2) * i + Math.PI / 4)
                .add(point), stroke, color)));
        }
        this.diagramArea = area;
        this.options = {
            xAxis: {
                display: true,
                arrow: true,
                color: '#ff0000',
                stroke: 1,
            },
            yAxis: {
                display: true,
                arrow: true,
                color: '#009900',
                stroke: 1,
            },
            greed: {
                display: true,
                color: {
                    hex: '#777777',
                    html: 'var(--obl-linear-diagram-greed-color)',
                },
                stroke: 0.25,
                linePattern: LinePattern.DASHED,
            },
        };
        this.setOptions(options);
        this.points = points;
    }
    normalizeMinMax(min, max) {
        if (min === max) {
            if (min && max) {
                if (min > 0) {
                    min = 0;
                }
                else {
                    max = 0;
                }
            }
            else {
                max = 1;
            }
        }
        return {
            min,
            max,
        };
    }
    filterByRange() {
        const { selectionRange } = this;
        const { min, max } = selectionRange || { min: 0, max: 1 };
        const check = (p) => p && p.x >= min && p.x <= max;
        const between = (p1, p2) => p1 && p1.x < min && p2 && p2.x > max;
        return selectionRange
            ? this.pPoints.map((points) => points.filter((p, index) => check(p) ||
                check(points[index - 1]) ||
                check(points[index + 1]) ||
                between(p, points[index + 1]) ||
                between(points[index + 1], p) ||
                between(p, points[index - 1]) ||
                between(points[index - 1], p)))
            : this.pPoints;
    }
    /**
     * Get min and max of x axis
     * @returns return min & max for x axis
     */
    getXMinMax() {
        let min;
        let max;
        const filtered = this.filterByRange();
        filtered.forEach((points) => {
            points.forEach((point, index) => {
                if (min === undefined || min > point.x) {
                    min = point.x;
                }
                if (max === undefined || max < point.x) {
                    max = point.x;
                }
            });
        });
        if (!this.selectionRange) {
            if (min === undefined ||
                (this.options?.xMinMax?.min !== undefined &&
                    min > this.options?.xMinMax?.min)) {
                min = this.options?.xMinMax?.min || 0;
            }
            if (max === undefined ||
                (this.options?.xMinMax?.max !== undefined &&
                    max < this.options?.xMinMax?.max)) {
                max = this.options?.xMinMax?.max || min + 1;
            }
        }
        else {
            return this.normalizeMinMax(this.selectionRange.min, this.selectionRange.max);
        }
        return this.normalizeMinMax(min, max);
    }
    /**
     * Find minimum & maximum for y axis
     * @returns MinMax interface of displayed values
     */
    getYMinMax() {
        let min;
        let max;
        const filtered = this.filterByRange();
        const { selectionRange } = this;
        filtered.forEach((points) => {
            if (selectionRange && points.length > 1) {
                let fu = LinearFunction2D.fromTwoPoints(points[0], points[1]);
                if (fu) {
                    const calculated = Math.max(Math.min(points[0].x, points[1].x), selectionRange.min);
                    if (min !== undefined) {
                        min = Math.min(fu.yPoint(calculated), min);
                        max = Math.max(min, max);
                    }
                    else {
                        min = fu.yPoint(calculated);
                        max = min;
                    }
                }
                const fp = points[points.length - 2];
                const lp = points[points.length - 1];
                fu = LinearFunction2D.fromTwoPoints(fp, lp);
                if (fu) {
                    const calculated = Math.min(Math.max(lp.x, fp.x), selectionRange.max);
                    if (min !== undefined) {
                        min = Math.min(fu.yPoint(calculated), min);
                        max = Math.max(fu.yPoint(calculated), max);
                    }
                    else {
                        min = fu.yPoint(calculated);
                        max = min;
                    }
                }
            }
            points.forEach((point, index) => {
                if ((index === 0 || index === points.length - 1) && selectionRange) {
                    return;
                }
                if (min === undefined || min > point.y) {
                    min = point.y;
                }
                if (max === undefined || max < point.y) {
                    max = point.y;
                }
            });
        });
        if (min === undefined ||
            (this.options?.yMinMax?.min !== undefined &&
                min > this.options?.yMinMax?.min)) {
            min = this.options?.yMinMax?.min || 0;
        }
        if (max === undefined ||
            (this.options?.yMinMax?.max !== undefined &&
                max < this.options?.yMinMax?.max)) {
            max = this.options?.yMinMax?.max || min + 1;
        }
        return this.normalizeMinMax(min, max);
    }
    /**
     * Convert point diagram pos to SVG pos
     * @param point point to transform
     * @param startPoint diagram start point
     * @param xScale x scale
     * @param yScale y scale
     * @returns Point2D instance
     */
    diagramPosToSVG(point, startPoint) {
        return new Point2D((point.x - this.xMinMax.min) * this.xScale + startPoint.x, -(point.y - this.yMinMax.min) * this.yScale + startPoint.y);
    }
    svgPosToDiagram(point, startPoint, xScale, yScale) {
        return new Point2D((point.x - startPoint.x) / xScale + this.xMinMax.min, (startPoint.y - point.y) / yScale + this.yMinMax.min);
    }
    getDAxis(range, autoIncreaseDecrease, dp) {
        if (!dp) {
            dp = range;
        }
        if (autoIncreaseDecrease) {
            while (range / dp > 10) {
                dp *= 2;
            }
            while (range / dp < 5) {
                dp /= 2;
            }
        }
        return dp;
    }
    getDx() {
        const range = this.xMinMax.max - this.xMinMax.min;
        return this.getDAxis(this.xMinMax.max - this.xMinMax.min, !this.options?.xAxis?.autoIncreaseDecrease, (this.options.xAxis?.dp && this.options.xAxis.dp) ||
            this.recalcDScale(range, this.options.xAxis?.precision !== undefined &&
                this.options.xAxis?.precision >= 0
                ? this.options.xAxis.precision
                : 2));
    }
    getDy() {
        const range = this.yMinMax.max - this.yMinMax.min;
        return this.getDAxis(range, !this.options?.yAxis?.autoIncreaseDecrease, (this.options.yAxis?.dp && this.options.yAxis.dp) ||
            this.recalcDScale(range, this.options.yAxis?.precision && this.options.yAxis?.precision >= 0
                ? this.options.yAxis.precision
                : 2));
    }
    drawGreed(dc, startPoint) {
        if (!this.options.greed?.display) {
            return;
        }
        dc.group({ name: 'greed' }).setLinePattern(this.options.greed?.linePattern);
        const dx = this.getDx();
        const dy = this.getDy();
        const startScale = this.diagramPosToSVG(new Point2D(Math.ceil(this.xMinMax.min / dx) * dx, Math.ceil(this.yMinMax.min / dy) * dy), startPoint);
        const dxy = new Point2D(dx * this.xScale, dy * this.yScale);
        let posX = new Point2D(startScale.x, startPoint.y);
        let posY = new Point2D(startPoint.x, startScale.y);
        while (posX.x <=
            posY.x + (this.xMinMax.max - this.xMinMax.min) * this.xScale) {
            dc.drawLine(posX, new Point2D(posX.x, posX.y - (this.yMinMax.max - this.yMinMax.min) * this.yScale), this.options?.greed?.stroke || 0, this.options?.greed?.color || '#000000');
            posX = posX.add(new Point2D(dxy.x, 0));
        }
        while (posY.y >=
            posX.y - (this.yMinMax.max - this.yMinMax.min) * this.yScale) {
            dc.drawLine(posY, new Point2D(posY.x + (this.xMinMax.max - this.xMinMax.min) * this.xScale, posY.y), this.options.greed?.stroke || 0, this.options.greed?.color || '#000000');
            posY = posY.add(new Point2D(0, -dxy.y));
        }
        dc.setLinePattern(LinePattern.NONE).endGroup();
    }
    /**
     * Calc scale elementary increase value with given precision
     * @param value (max - min)
     * @param precision integer number should be >= 0
     * @returns scale elementary increase value
     */
    recalcDScale(value, precision = 2) {
        const power = Math.floor(Math.log10(value));
        return +(Math.ceil((Math.pow(10, -power + precision) * value) / 10) *
            Math.pow(10, power - precision)).toFixed(precision);
    }
    drawXAxis(dc, startPoint) {
        if (!this.options.xAxis?.display) {
            return 0;
        }
        dc.group({ name: 'xAxis' });
        const dx = this.getDx();
        const startScale = this.diagramPosToSVG(new Point2D(Math.ceil(this.xMinMax.min / dx) * dx, 0), startPoint);
        let posX = new Point2D(startScale.x, startPoint.y);
        const bP = this.diagramPosToSVG(new Point2D(this.xMinMax.min, this.yMinMax.min), startPoint);
        const eP = this.diagramPosToSVG(new Point2D(this.xMinMax.max, this.yMinMax.min), startPoint);
        dc.drawArrow(bP, eP, this.options.xAxis?.stroke || 0, this.options.xAxis?.color || '#000000', !!this.options?.xAxis?.arrow);
        let xText = '';
        let textWidth = 0;
        dc.group({ name: 'values' });
        for (let x = Math.ceil(this.xMinMax.min / dx) * dx; x <= this.xMinMax.max; x += dx) {
            xText = this.xFormatter(x, this.xK);
            textWidth = dc.getTextWidth(xText) + 5;
            dc.drawText(xText, posX.add(new Point2D(1.5, textWidth)), this.options.xAxis?.color || '#000000', 90);
            posX = posX.add(new Point2D(dx * this.xScale, 0));
            if (posX.x > eP.x) {
                break;
            }
        }
        dc.endGroup().endGroup();
        return textWidth;
    }
    drawYAxis(dc, startPoint) {
        if (!this.options.yAxis?.display) {
            return 0;
        }
        const dy = this.getDy();
        const startScale = this.diagramPosToSVG(new Point2D(0, Math.ceil(this.yMinMax.min / dy) * dy), startPoint);
        return this.yAxis.draw(dc, startPoint, startScale, dy, this.yMinMax, this.yScale, this.yK, this.diagramArea, this.yLabel, this.options.yAxis);
    }
    drawLegend(dc) {
        if (this.legend?.length &&
            this.pPoints &&
            this.legend.length <= this.pPoints.length &&
            this.options?.set?.length) {
            dc.setFontSize(8);
            const maxTextWidth = this.legend
                .map((text) => dc.getTextWidth(text))
                .reduce((prev, current) => ((prev = prev < current ? current : prev), prev), 0);
            const padding = 5;
            const keyHeight = 10;
            const keyWidth = 15;
            const totalWidth = keyWidth + padding * 3 + maxTextWidth;
            const totalHeight = padding + (keyHeight + padding) * this.legend.length;
            const pc = new Point2D(this.diagramArea.x + this.diagramArea.width - padding - totalWidth, this.diagramArea.y + padding);
            dc.group({ name: 'legend' }).drawRect(pc.x, pc.y, totalWidth, totalHeight, 1, '#aaaaaa', '#ffffff', { opacity: 0.6 });
            this.legend.forEach((text, index) => {
                const pt = new Point2D(padding, padding + index * (keyHeight + padding) + keyHeight / 2).add(pc);
                const styles = this.options.set
                    ? this.options.set[index % this.options.set.length]
                    : {};
                dc.group({ name: `key-${index + 1}` }).setLinePattern(styles.linePattern);
                if (styles.linePattern !== LinePattern.DISABLED) {
                    dc.drawLine(pt, pt.add(new Point2D(keyWidth, 0)), styles.stroke || 1, styles.color || '#000000');
                }
                dc.setLinePattern(undefined);
                this.getDrawPointFu(styles.drawPoint || PointType.NONE)(pt.add(new Point2D(keyWidth / 2, 0)), dc, styles.stroke || 1, styles.color || '#000000', 0, 0);
                dc.endGroup()
                    .setFontSize(8)
                    .setTextAlign(TextAlign.LEFT)
                    .drawText(text, pc.add(new Point2D(padding * 2 + keyWidth, padding + index * (keyHeight + padding) + keyHeight * 0.75)), '#000000', 0);
            });
            dc.endGroup();
        }
    }
    drawVectors(dc, startPoint) {
        const pos = new Point2D(this.diagramArea.x, this.diagramArea.y - 2);
        const width = this.diagramArea.width;
        const height = this.diagramArea.height + 2;
        dc.group({
            name: 'vectors-tables',
            clipRect: {
                pos,
                width,
                height,
            },
        });
        this.pPoints.forEach((points, index) => {
            const setIndex = (this.options.set && index % this.options.set.length) || 0;
            const stroke = this.options?.set?.[setIndex].stroke || 2;
            const color = this.options?.set?.[setIndex].color || '#000000';
            const linePattern = this.options?.set?.[setIndex].linePattern;
            dc.setLinePattern(this.options?.set?.[setIndex].linePattern).group({
                name: `vectors-${index + 1}`,
            });
            points = points.map((point) => this.diagramPosToSVG(point, startPoint));
            points = points.map((point, i) => {
                const prev = points[i - 1];
                const next = points[i + 1];
                if (point.isPtInRect(pos.x, pos.y, width, height) || // current in rect
                    prev?.isPtInRect(pos.x, pos.y, width, height) || // prev in rect
                    next?.isPtInRect(pos.x, pos.y, width, height) || // next in rect
                    (prev && prev.x <= pos.x && point.x >= pos.x + width) || // prev outside left and current outside of right
                    (next && point.x <= pos.x && next.x >= pos.x + width) // current outside left and next outside of right
                ) {
                    return point;
                }
                return undefined;
            })
                .filter(pt => pt);
            if (linePattern !== LinePattern.DISABLED) {
                dc.drawPolyline(points, stroke, color);
            }
            if (this.options.set) {
                if (this.options.set[setIndex].drawPoint &&
                    this.options.set[setIndex].drawPoint !== PointType.NONE) {
                    const pointType = this.options.set[setIndex].drawPoint || PointType.NONE;
                    if (pointType !== PointType.NONE) {
                        const drawPointFu = this.getDrawPointFu(pointType);
                        dc.group({ name: 'points-marks' });
                        points.forEach((point, pIndex) => {
                            dc.group({
                                data: {
                                    point: JSON.stringify(point),
                                    pointSvg: JSON.stringify(point),
                                },
                                onMouseOver: (g) => this.onPointMouseOver.next(g),
                                onMouseOut: () => this.onPointMouseOut.next(),
                            });
                            drawPointFu(point, dc, stroke, color, pIndex, point.y);
                            dc.endGroup();
                        });
                        dc.endGroup();
                    }
                }
            }
            dc.endGroup();
        });
        dc.endGroup();
    }
    draw(dc) {
        dc.clear();
        this.xCursorLine = undefined;
        this.yCursorLine = undefined;
        this.xyCursor = undefined;
        this.xScale =
            this.diagramArea.width / (this.xMinMax.max - this.xMinMax.min);
        this.yScale =
            this.diagramArea.height / (this.yMinMax.max - this.yMinMax.min);
        const startPoint = new Point2D(this.diagramArea.x, this.diagramArea.y + this.diagramArea.height);
        dc.setFontSize(10);
        this.drawGreed(dc, startPoint);
        this.drawVectors(dc, startPoint);
        dc.setLinePattern(LinePattern.NONE);
        dc.setTextAlign(TextAlign.CENTER);
        dc.setTextBaseline(TextBaseline.ALPHABETIC);
        if (this.title) {
            dc.setFontSize(30);
            dc.drawText(this.title, this.diagramPosToSVG(new Point2D((this.xMinMax.max + this.xMinMax.min) * 0.5, this.yMinMax.max), startPoint).add(new Point2D(0, -20)), '#ff0000', 0);
            dc.setFontSize(15);
        }
        dc.setTextBaseline(TextBaseline.ALPHABETIC)
            .setTextAlign(TextAlign.LEFT)
            .setFontSize(10);
        const lengthXLabel = this.drawXAxis(dc, startPoint);
        this.drawYAxis(dc, startPoint);
        dc.setTextAlign(TextAlign.CENTER);
        if (this.options.xAxis?.display) {
            if (this.xLabel) {
                dc.drawText(this.xLabel, this.diagramPosToSVG(new Point2D((this.xMinMax.max + this.xMinMax.min) * 0.5, this.yMinMax.min), startPoint).add(new Point2D(0, lengthXLabel + 20)), this.options.xAxis?.color || '#000000', 0);
            }
            if (this.xK) {
                dc.setTextAlign(TextAlign.RIGHT).drawText(`×e${-this.xK}`, this.diagramPosToSVG(new Point2D(this.xMinMax.max, this.yMinMax.min), startPoint).add(new Point2D(0, lengthXLabel + 20)), this.options.xAxis?.color || '#000000', 0);
            }
        }
        dc.setTextAlign(TextAlign.LEFT).setTextBaseline(TextBaseline.ALPHABETIC);
        this.drawLegend(dc);
        this.redraw.next();
    }
    setOptions(options) {
        if (!options) {
            options = {};
        }
        this.options = {
            displayCursor: options.displayCursor,
            xAxis: {
                ...this.options.xAxis,
                ...options?.xAxis,
            },
            yAxis: {
                ...this.options.yAxis,
                ...options?.yAxis,
            },
            xMinMax: {
                ...this.options.xMinMax,
                ...options?.xMinMax,
            },
            yMinMax: {
                ...this.options.xMinMax,
                ...options?.yMinMax,
            },
            greed: {
                ...this.options.greed,
                ...options?.greed,
            },
            set: options?.set ||
                this.options.set || [
                {
                    color: '#37abc8',
                    stroke: 2,
                    linePattern: LinePattern.NONE,
                    drawPoint: PointType.NONE,
                },
                {
                    color: '#ab37c8',
                    stroke: 2,
                    linePattern: LinePattern.NONE,
                    drawPoint: PointType.NONE,
                },
                {
                    color: '#ffc837',
                    stroke: 2,
                    linePattern: LinePattern.NONE,
                    drawPoint: PointType.NONE,
                },
            ],
        };
    }
    drawCursor(mousePos, svg) {
        if (!this.options?.displayCursor ||
            !mousePos ||
            this.xScale === undefined ||
            this.yScale === undefined) {
            return;
        }
        const legend = svg.querySelector('.legend');
        const vectors = svg.querySelector('.vectors-tables');
        const append = (element, before) => {
            if (before) {
                svg.insertBefore(element, before);
            }
            else {
                svg.appendChild(element);
            }
        };
        if (!this.xCursorLine) {
            this.xCursorLine = document.createElementNS(ns, 'polyline');
            append(this.xCursorLine, vectors || legend);
            this.xCursorLine.style.stroke = '#ff0000';
            this.xCursorLine.style.strokeWidth = '.2';
        }
        if (!this.yCursorLine) {
            this.yCursorLine = document.createElementNS(ns, 'polyline');
            append(this.yCursorLine, vectors || legend);
            this.yCursorLine.style.stroke = '#ff0000';
            this.yCursorLine.style.strokeWidth = '.2';
        }
        if (!this.xyCursor) {
            this.xyCursor = document.createElementNS(ns, 'text');
            append(this.xyCursor, legend);
            this.xyCursor.style.fill = '#ff0000';
            this.xyCursor.style.textAnchor = 'left';
            this.xyCursor.style.fontSize = '8px';
        }
        if (!this.diagramArea.isPtInRect(mousePos)) {
            this.yCursorLine.style.display = 'none';
            this.xCursorLine.style.display = 'none';
            this.xyCursor.style.display = 'none';
        }
        else {
            this.yCursorLine.style.display = '';
            this.xCursorLine.style.display = '';
            this.xyCursor.style.display = '';
        }
        const startPoint = new Point2D(this.diagramArea.x, this.diagramArea.y + this.diagramArea.height);
        const diagramPos = this.svgPosToDiagram(mousePos, startPoint, this.xScale, this.yScale);
        this.xyCursor.textContent = `${this.decimalPipe.transform(diagramPos.x, '0.3-3')}; ${this.decimalPipe.transform(diagramPos.y, '0.3-3')}`;
        this.xyCursor.setAttribute('x', (mousePos.x + 2).toString());
        this.xyCursor.setAttribute('y', (mousePos.y - 2).toString());
        this.xCursorLine.setAttribute('points', `${this.diagramArea.x},${mousePos.y} ${this.diagramArea.x + this.diagramArea.width},${mousePos.y}`);
        this.yCursorLine.setAttribute('points', `${mousePos.x},${this.diagramArea.y} ${mousePos.x},${this.diagramArea.y + this.diagramArea.height}`);
    }
    svgToDiagram(point) {
        const startPoint = new Point2D(this.diagramArea.x, this.diagramArea.y + this.diagramArea.height);
        return this.svgPosToDiagram(point, startPoint, this.xScale, this.yScale);
    }
    getDrawPointFu(pointType) {
        const fu = LinearDiagram2D.drawingPoints.get(pointType);
        // eslint-disable-next-line no-unneeded-ternary
        return fu
            ? fu
            : (point, dc, stroke, color) => { };
    }
}

class LinearDiagram2DComponent {
    renderer;
    dc;
    diagram2d;
    mousePos = new Point2D();
    selectArea;
    width = 800;
    height = 528;
    diagram;
    legend = input([]);
    points = input([]);
    xFormatter = input();
    yFormatter = input();
    pOptions;
    get options() {
        return this.pOptions;
    }
    set options(value) {
        this.pOptions = value;
        if (this.diagram2d && this.dc) {
            this.diagram2d.setOptions(value);
            this.diagram2d.draw(this.dc);
        }
    }
    pLabels = {
        x: '',
        y: '',
        title: '',
    };
    set labels(labels) {
        this.pLabels = labels;
        if (this.diagram2d) {
            this.diagram2d.draw(this.dc);
        }
    }
    diagramPointHover;
    subscriptions = [];
    constructor(renderer) {
        this.renderer = renderer;
        effect(() => {
            this.points();
            this.legend();
            this.draw();
        });
    }
    ngOnDestroy() {
        this.subscriptions.forEach((subscription) => {
            if (!subscription.closed) {
                subscription.unsubscribe();
            }
        });
    }
    ngAfterContentInit() {
        if (this.diagramPointHover && this.diagram2d) {
            this.diagramPointHover.onMouseOut = this.diagram2d.onPointMouseOut;
            this.diagramPointHover.onMouseOver = this.diagram2d.onPointMouseOver;
        }
    }
    ngAfterViewInit() {
        this.draw();
    }
    pdf() {
        const dc = new DrawingPdfInterface(new Rect(new Point2D(0, 0), new Point2D(800, 600), 20, 20));
        this.draw(dc);
        dc.save(this.diagram2d?.title.length ? this.diagram2d.title : 'Diagram 2D');
    }
    draw(dc = this.dc) {
        if (!dc) {
            if (!this.diagram) {
                return;
            }
            this.dc = new DrawingSvgInterface(this.diagram.nativeElement, this.renderer);
            dc = this.dc;
        }
        if (!this.diagram2d) {
            this.diagram2d = new LinearDiagram2D(new Rect(new Point2D(120, 50), new Point2D(700, 400)), this.points(), this.options);
            if (this.diagramPointHover) {
                this.diagramPointHover.onMouseOut = this.diagram2d.onPointMouseOut;
                this.diagramPointHover.onMouseOver = this.diagram2d.onPointMouseOver;
            }
        }
        else {
            this.diagram2d.points = this.points();
        }
        this.diagram2d.legend = this.legend();
        this.diagram2d.xLabel = this.pLabels.x;
        this.diagram2d.yLabel = this.pLabels.y;
        this.diagram2d.title = this.pLabels.title;
        const xFormatter = this.xFormatter();
        if (xFormatter) {
            this.diagram2d.xFormatter = xFormatter;
        }
        const yFormatter = this.yFormatter();
        if (yFormatter) {
            this.diagram2d.yFormatter = yFormatter;
        }
        this.diagram2d.draw(dc);
        if (dc instanceof DrawingSvgInterface) {
            this.diagram2d.drawCursor(this.mousePos, dc.svgContainer);
        }
    }
    move(event) {
        const rect = this.diagram.nativeElement.getBoundingClientRect();
        this.mousePos = new Point2D(((event.clientX - rect.left) / rect.width) * this.width, ((event.clientY - rect.top) / rect.height) * this.height);
        if (!this.diagram2d) {
            return;
        }
        this.diagram2d.drawCursor(this.mousePos, this.diagram.nativeElement);
        const area = this.diagram2d.diagramArea;
        if (event.buttons === 1 &&
            this.mousePos.isPtInRect(area.x, area.y, area.width, area.height)) {
            if (this.selectArea) {
                this.selectArea.width = this.mousePos.x - this.selectArea.x;
            }
            else {
                const startPoint = new Point2D(this.mousePos.x, this.diagram2d.diagramArea.y);
                const endPoint = new Point2D(Math.min(this.mousePos.x, this.diagram2d.diagramArea.x + this.diagram2d.diagramArea.width), this.diagram2d.diagramArea.y + this.diagram2d.diagramArea.height);
                this.selectArea = new Rect(startPoint, endPoint);
            }
        }
    }
    keyup(event) {
        if (!this.diagram2d) {
            return;
        }
        const { selectArea } = this;
        if (selectArea) {
            const xMin = selectArea.x < selectArea.x + selectArea.width ? selectArea.x : selectArea.x + selectArea.width;
            const xMax = selectArea.x < selectArea.x + selectArea.width ? selectArea.x + selectArea.width : selectArea.x;
            this.diagram2d.selectionRange = {
                min: this.diagram2d.svgToDiagram(new Point2D(xMin, selectArea.y)).x,
                max: this.diagram2d.svgToDiagram(new Point2D(xMax, selectArea.y)).x,
            };
            this.selectArea = undefined;
            this.draw();
        }
    }
    left() {
        if (!this.diagram2d) {
            return;
        }
        const { selectionRange } = this.diagram2d;
        if (selectionRange) {
            this.diagram2d.selectionRange = undefined;
            const range = selectionRange.max - selectionRange.min;
            const minMax = this.diagram2d.getXMinMax();
            selectionRange.min = Math.max(selectionRange.min - range, minMax.min);
            selectionRange.max = selectionRange.min + range;
            this.diagram2d.selectionRange = selectionRange;
            this.draw();
        }
    }
    right() {
        if (!this.diagram2d) {
            return;
        }
        const { selectionRange } = this.diagram2d;
        if (selectionRange) {
            this.diagram2d.selectionRange = undefined;
            const range = selectionRange.max - selectionRange.min;
            const minMax = this.diagram2d.getXMinMax();
            selectionRange.max = Math.min(selectionRange.max + range, minMax.max);
            selectionRange.min = selectionRange.max - range;
            this.diagram2d.selectionRange = selectionRange;
            this.draw();
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: LinearDiagram2DComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: LinearDiagram2DComponent, isStandalone: false, selector: "obl-linear-diagram-2d", inputs: { legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: false, transformFunction: null }, xFormatter: { classPropertyName: "xFormatter", publicName: "xFormatter", isSignal: true, isRequired: false, transformFunction: null }, yFormatter: { classPropertyName: "yFormatter", publicName: "yFormatter", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: false, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: false, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "diagramPointHover", first: true, predicate: DiagramPointHoverComponent, descendants: true }], viewQueries: [{ propertyName: "diagram", first: true, predicate: ["diagram"], descendants: true }], ngImport: i0, template: "<div class=\"svgContainer\">\n  <svg\n    #diagram\n    [attr.viewBox]=\"'0 0 ' + width + ' ' + height\"\n    (mousemove)=\"move($event)\"\n    (mouseup)=\"keyup($event)\"\n  >\n    @if (selectArea) {\n      <rect\n        [attr.x]=\"[selectArea.x, selectArea.x + selectArea.width] | oblMin\"\n        [attr.y]=\"selectArea.y\"\n        [attr.width]=\"([selectArea.width] | oblAbs)[0]\"\n        [attr.height]=\"([selectArea.height] | oblAbs)[0]\"\n      ></rect>\n    }\n    <g class=\"root\"></g>\n  </svg>\n  <div class=\"buttons\">\n    <button class=\"pdf-button\" oblButton icon=\"file\" (click)=\"pdf()\"></button>\n    @if (diagram2d?.selectionRange) {\n      <button\n        oblButton\n        icon=\"cancel\"\n        (click)=\"diagram2d && diagram2d.selectionRange = undefined; this.draw()\"\n      ></button>\n      <button oblButton icon=\"left\" (click)=\"left()\"></button>\n      <button oblButton icon=\"right\" (click)=\"right()\"></button>\n    }\n  </div>\n  <ng-content></ng-content>\n</div>\n", styles: [":host .svgContainer{overflow:auto;max-width:100%;position:relative}:host .svgContainer .buttons{position:absolute;right:20px;top:20px;--obl-default-button-padding: 5px;display:flex}:host .svgContainer .pdf-button{display:none}:host .svgContainer:hover .pdf-button{display:block}svg>rect{fill:var(--obl-linear-2d-select-area-color, #a7f5ff)}svg::ng-deep text{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: i1$1.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }, { kind: "pipe", type: i2.AbsPipe, name: "oblAbs" }, { kind: "pipe", type: i2.MinPipe, name: "oblMin" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: LinearDiagram2DComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-linear-diagram-2d', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div class=\"svgContainer\">\n  <svg\n    #diagram\n    [attr.viewBox]=\"'0 0 ' + width + ' ' + height\"\n    (mousemove)=\"move($event)\"\n    (mouseup)=\"keyup($event)\"\n  >\n    @if (selectArea) {\n      <rect\n        [attr.x]=\"[selectArea.x, selectArea.x + selectArea.width] | oblMin\"\n        [attr.y]=\"selectArea.y\"\n        [attr.width]=\"([selectArea.width] | oblAbs)[0]\"\n        [attr.height]=\"([selectArea.height] | oblAbs)[0]\"\n      ></rect>\n    }\n    <g class=\"root\"></g>\n  </svg>\n  <div class=\"buttons\">\n    <button class=\"pdf-button\" oblButton icon=\"file\" (click)=\"pdf()\"></button>\n    @if (diagram2d?.selectionRange) {\n      <button\n        oblButton\n        icon=\"cancel\"\n        (click)=\"diagram2d && diagram2d.selectionRange = undefined; this.draw()\"\n      ></button>\n      <button oblButton icon=\"left\" (click)=\"left()\"></button>\n      <button oblButton icon=\"right\" (click)=\"right()\"></button>\n    }\n  </div>\n  <ng-content></ng-content>\n</div>\n", styles: [":host .svgContainer{overflow:auto;max-width:100%;position:relative}:host .svgContainer .buttons{position:absolute;right:20px;top:20px;--obl-default-button-padding: 5px;display:flex}:host .svgContainer .pdf-button{display:none}:host .svgContainer:hover .pdf-button{display:block}svg>rect{fill:var(--obl-linear-2d-select-area-color, #a7f5ff)}svg::ng-deep text{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}\n"] }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { diagram: [{
                type: ViewChild,
                args: ['diagram']
            }], options: [{
                type: Input
            }], labels: [{
                type: Input
            }], diagramPointHover: [{
                type: ContentChild,
                args: [DiagramPointHoverComponent]
            }] } });

/* eslint-disable @typescript-eslint/no-dynamic-delete */
class DiagramDataFilterComponent {
    file;
    models = {
        smooth: {
            filter: (data, options) => {
                const tolerance = options?.tolerance.value ?? 0.5;
                const sampleSize = options?.sampleSize.value ?? 10;
                data.forEach((r, index) => {
                    const sample = data.slice(index, index + sampleSize).map((d) => d.y);
                    const max = Math.max(...sample);
                    const min = Math.min(...sample);
                    if (max - min < tolerance && sample.length) {
                        r.y = ElementaryMath.average(sample);
                    }
                });
                return data;
            },
            options: {
                tolerance: { value: 0.5, min: 0, max: 5, step: 0.1 },
                sampleSize: { value: 10, min: 2, max: 25, step: 1 },
            },
        },
        'index-range': {
            filter: (data, options) => {
                const start = ElementaryMath.minmax(options?.start?.value ?? 0, 0, data.length - 1);
                const end = ElementaryMath.minmax(options?.end?.value ?? data.length, 0, data.length - 1);
                return data.slice(start, end);
            },
            options: {
                start: { value: 0 },
                end: { value: 20 },
            },
        },
        'x-range': {
            filter: (data, options) => {
                const start = options?.start?.value || 0;
                const end = options?.end?.value || data.length;
                return data.filter((v) => v.x >= start && v.x <= end);
            },
            options: {
                start: { value: 0 },
                end: { value: 20 },
            },
        },
        'y-range': {
            filter: (data, options) => {
                const y = data.map(p => p.y);
                const start = options?.start?.value ?? Math.min(...y);
                const end = options?.end?.value ?? Math.max(...y);
                return data.filter((v) => v.y >= start && v.y <= end);
            },
            options: {
                start: { value: 0 },
                end: { value: 20, step: 0.1 },
            },
        },
        diff: {
            filter: (data, options) => {
                const points = [];
                data.forEach((p, index) => {
                    if (index < data.length - 1) {
                        const pt = data[index + 1].copy();
                        pt.y = (pt.y - p.y) / (pt.x - p.x);
                        points.push(pt);
                    }
                });
                return points;
            },
            options: {},
        },
        'nth-filter': {
            filter: (data, options) => {
                const nth = options?.nth?.value ?? 1;
                return data.filter((_, index) => index % nth === 0);
            },
            options: {
                nth: { value: 1, min: 1, max: 100, step: 1 },
            },
        },
        multiply: {
            filter: (data, options) => {
                const k = options?.k?.value ?? 1;
                return data.map((v) => new Point2D(v.x, v.y * k));
            },
            options: {
                k: { value: 1, step: 0 },
            },
        },
        add: {
            filter: (data, options) => {
                const add = options?.adding?.value ?? 1;
                return data.map((v) => new Point2D(v.x, v.y + add));
            },
            options: {
                adding: { value: 1, step: 0 },
            },
        },
    };
    _filters = {};
    selected;
    lastData;
    set filters(filters) {
        this._filters = filters;
        keysValues(filters).forEach(([name, value]) => (this.models[name].options = value));
    }
    get filters() {
        return this._filters;
    }
    translations = {};
    allow;
    filtersChanged = new EventEmitter();
    constructor(file) {
        this.file = file;
    }
    filtering(data) {
        this.lastData = data;
        let copy = data.map((d) => d.copy());
        const filters = this.models;
        keysValues(this._filters).forEach(([name, value]) => {
            filters[name] = { ...value, ...filters[name] };
            const filter = filters[name];
            copy = filter.filter(copy, filter);
        });
        return copy;
    }
    remove(name) {
        delete this._filters[name];
        this.selected = undefined;
        this.changed();
    }
    changed() {
        const filters = keysValues(this.models)
            .filter(([name]) => this._filters[name])
            .map(([name, value]) => {
            return { [name]: { ...value.options } };
        })
            .reduce((p, c) => ({ ...p, ...c }), {});
        this.filtersChanged.emit(filters);
    }
    compare = (f, s) => {
        return 0;
    };
    download() {
        const translationPipe = new TranslationPipe();
        if (this.lastData) {
            return this.file.saveTextFile(JSON.stringify(this.filtering(this.lastData)), translationPipe.transform('filtered data', this.translations), 'application/json');
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DiagramDataFilterComponent, deps: [{ token: i1$2.OblFileService }], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: DiagramDataFilterComponent, isStandalone: false, selector: "obl-diagram-data-filter", inputs: { filters: "filters", translations: "translations", allow: "allow" }, outputs: { filtersChanged: "filtersChanged" }, ngImport: i0, template: "@if ((filters | keyvalue).length) {\n  <fieldset class=\"filters\">\n    <legend>{{ 'Chosen' | oblTranslation : translations }}</legend>\n    <div class=\"items\">\n      @for (filter of filters | keyvalue : compare; track filter.key) {\n        <div\n          class=\"filter\"\n          (click)=\"selected = filter.key\"\n        >\n          <span>{{ filter.key | oblTranslation : translations }}</span>\n          <button oblButton icon=\"cancel\" (click)=\"remove(filter.key); $event.stopPropagation()\"></button>\n        </div>\n      }\n    </div>\n    <div class=\"buttons\">\n      <button oblButton icon=\"save\" (click)=\"download()\"></button>\n      <ng-content></ng-content>\n    </div>\n  </fieldset>\n}\n\n@if ((filters | keyvalue).length !== (allow?.length || (models | keyvalue).length)) {\n  <fieldset class=\"filters\">\n    <legend>{{ 'Others' | oblTranslation : translations }}</legend>\n    <div class=\"items\">\n      @for (filter of models | keyvalue : compare; track filter.key) {\n        @if (!filters[filter.key] && (!allow || allow.includes(filter.key))) {\n          <div\n            class=\"filter\"\n            (click)=\"filters[filter.key] = filter.value.options; changed()\"\n          >\n            <span>{{ filter.key | oblTranslation : translations }}</span>\n          </div>\n        }\n      }\n    </div>\n  </fieldset>\n}\n\n@if (selected && (models[selected].options | keyvalue).length) {\n  <div>\n    <div class=\"head\">\n      {{ 'Edit filter option of name:' | oblTranslation : translations }}\n      {{ selected | oblTranslation : translations }}\n    </div>\n    @for(filter of models[selected].options | keyvalue : compare; track filter.key) {\n      <div class=\"filter-option-control\">\n        <obl-input-wrapper [label]=\"filter.key | oblTranslation : translations\">\n          <input\n            oblInput\n            type=\"number\"\n            [value]=\"filter.value.value\"\n            (change)=\"\n              models[selected].options[filter.key].value = input.valueAsNumber;\n              changed()\n            \"\n            [step]=\"filter.value.step\"\n            [min]=\"filter.value.min\"\n            [max]=\"filter.value.max\"\n            #input\n          />\n        </obl-input-wrapper>\n      </div>\n    }\n  </div>\n}", styles: [":root{--obl-primary: #00afaf;--obl-secondary: #008caf;--default-border-color: gray;--default-focus-color: gray;--default-border-outline-color: #080808;--default-disabled-color: gray;--default-background-color: white;--default-hover-color: #eeeeee;--obl-default-error-color: red;--obl-dialog-background: #d3d3d3;--default-radio-color: black;--disabled-color: gray;--default-hex-button-border-color: #008caf;--default-hex-button-hover-border-color: #00afaf;--select-item-background-color: #e4e4e4;--select-item-text-color: #5a5a5a;--default-text-color: black;--obl-default-button-text-color: black;--obl-default-icon-color: black;--equalizer-background-bar-color: #575656;--equalizer-value-bar-color: #e6e6e6;--diagram-3d-background-color: black;--slider-value-container-color: gray;--slider-value-color: #d1d1d1;--slider-hover-value-color: white;--digit-fill-color: #cccccc;--digit-lighted-color: black;--horizontal-progress-bar-value-color: #504f4f;--horizontal-progress-bar-background-pattern-color: #dddddd;--horizontal-progress-bar-value-pattern-color: #b3b3b3;--horizontal-progress-bar-border-rect-color: #cccccc;--temperature-text-color: black;--temperature-path-stroke-color: black;--post-diagram-scale-line-color: #c8c8c8;--volume-channel-secondary-color: gray;--volume-channel-primary-color: #f2f2f2;--arch-progress-secondary-color: #eeeeee;--obl-linear-diagram-greed-color: gray;--obl-rating-selected-color: gold;--obl-rating-color: #cccccc}.filters{display:flex;gap:5px;border:1px solid var(--default-border-color);border-radius:5px;padding:5px;align-items:center;justify-content:space-between}.filters .items{display:flex;flex-wrap:wrap;gap:5px}.filters .filter{background-color:var(--obl-filter-background, #e2e2e2);color:var(--obl-filter-color, gray);padding:5px;border-radius:5px;display:flex;align-items:center;gap:5px;cursor:pointer}.filters .filter:hover{background-color:var(--obl-filter-background-hover, #ebebeb)}.filters .filter button{padding:5px}legend{font-size:12px}.head{padding:10px 10px 5px;font-size:12px}\n"], dependencies: [{ kind: "directive", type: i1$1.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }, { kind: "directive", type: i3.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i3.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: i5.TranslationPipe, name: "oblTranslation" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DiagramDataFilterComponent, decorators: [{
            type: Component,
            args: [{ selector: 'obl-diagram-data-filter', standalone: false, template: "@if ((filters | keyvalue).length) {\n  <fieldset class=\"filters\">\n    <legend>{{ 'Chosen' | oblTranslation : translations }}</legend>\n    <div class=\"items\">\n      @for (filter of filters | keyvalue : compare; track filter.key) {\n        <div\n          class=\"filter\"\n          (click)=\"selected = filter.key\"\n        >\n          <span>{{ filter.key | oblTranslation : translations }}</span>\n          <button oblButton icon=\"cancel\" (click)=\"remove(filter.key); $event.stopPropagation()\"></button>\n        </div>\n      }\n    </div>\n    <div class=\"buttons\">\n      <button oblButton icon=\"save\" (click)=\"download()\"></button>\n      <ng-content></ng-content>\n    </div>\n  </fieldset>\n}\n\n@if ((filters | keyvalue).length !== (allow?.length || (models | keyvalue).length)) {\n  <fieldset class=\"filters\">\n    <legend>{{ 'Others' | oblTranslation : translations }}</legend>\n    <div class=\"items\">\n      @for (filter of models | keyvalue : compare; track filter.key) {\n        @if (!filters[filter.key] && (!allow || allow.includes(filter.key))) {\n          <div\n            class=\"filter\"\n            (click)=\"filters[filter.key] = filter.value.options; changed()\"\n          >\n            <span>{{ filter.key | oblTranslation : translations }}</span>\n          </div>\n        }\n      }\n    </div>\n  </fieldset>\n}\n\n@if (selected && (models[selected].options | keyvalue).length) {\n  <div>\n    <div class=\"head\">\n      {{ 'Edit filter option of name:' | oblTranslation : translations }}\n      {{ selected | oblTranslation : translations }}\n    </div>\n    @for(filter of models[selected].options | keyvalue : compare; track filter.key) {\n      <div class=\"filter-option-control\">\n        <obl-input-wrapper [label]=\"filter.key | oblTranslation : translations\">\n          <input\n            oblInput\n            type=\"number\"\n            [value]=\"filter.value.value\"\n            (change)=\"\n              models[selected].options[filter.key].value = input.valueAsNumber;\n              changed()\n            \"\n            [step]=\"filter.value.step\"\n            [min]=\"filter.value.min\"\n            [max]=\"filter.value.max\"\n            #input\n          />\n        </obl-input-wrapper>\n      </div>\n    }\n  </div>\n}", styles: [":root{--obl-primary: #00afaf;--obl-secondary: #008caf;--default-border-color: gray;--default-focus-color: gray;--default-border-outline-color: #080808;--default-disabled-color: gray;--default-background-color: white;--default-hover-color: #eeeeee;--obl-default-error-color: red;--obl-dialog-background: #d3d3d3;--default-radio-color: black;--disabled-color: gray;--default-hex-button-border-color: #008caf;--default-hex-button-hover-border-color: #00afaf;--select-item-background-color: #e4e4e4;--select-item-text-color: #5a5a5a;--default-text-color: black;--obl-default-button-text-color: black;--obl-default-icon-color: black;--equalizer-background-bar-color: #575656;--equalizer-value-bar-color: #e6e6e6;--diagram-3d-background-color: black;--slider-value-container-color: gray;--slider-value-color: #d1d1d1;--slider-hover-value-color: white;--digit-fill-color: #cccccc;--digit-lighted-color: black;--horizontal-progress-bar-value-color: #504f4f;--horizontal-progress-bar-background-pattern-color: #dddddd;--horizontal-progress-bar-value-pattern-color: #b3b3b3;--horizontal-progress-bar-border-rect-color: #cccccc;--temperature-text-color: black;--temperature-path-stroke-color: black;--post-diagram-scale-line-color: #c8c8c8;--volume-channel-secondary-color: gray;--volume-channel-primary-color: #f2f2f2;--arch-progress-secondary-color: #eeeeee;--obl-linear-diagram-greed-color: gray;--obl-rating-selected-color: gold;--obl-rating-color: #cccccc}.filters{display:flex;gap:5px;border:1px solid var(--default-border-color);border-radius:5px;padding:5px;align-items:center;justify-content:space-between}.filters .items{display:flex;flex-wrap:wrap;gap:5px}.filters .filter{background-color:var(--obl-filter-background, #e2e2e2);color:var(--obl-filter-color, gray);padding:5px;border-radius:5px;display:flex;align-items:center;gap:5px;cursor:pointer}.filters .filter:hover{background-color:var(--obl-filter-background-hover, #ebebeb)}.filters .filter button{padding:5px}legend{font-size:12px}.head{padding:10px 10px 5px;font-size:12px}\n"] }]
        }], ctorParameters: () => [{ type: i1$2.OblFileService }], propDecorators: { filters: [{
                type: Input
            }], translations: [{
                type: Input
            }], allow: [{
                type: Input
            }], filtersChanged: [{
                type: Output
            }] } });

class LinearDiagramModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: LinearDiagramModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: LinearDiagramModule, declarations: [LinearDiagram2DComponent,
            DiagramPointHoverComponent,
            DiagramDataFilterComponent], imports: [CommonModule, ButtonsModule, TextPipesModule, InputModule, AbsPipe, MinPipe], exports: [LinearDiagram2DComponent,
            DiagramPointHoverComponent,
            DiagramDataFilterComponent] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: LinearDiagramModule, imports: [CommonModule, ButtonsModule, TextPipesModule, InputModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: LinearDiagramModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        LinearDiagram2DComponent,
                        DiagramPointHoverComponent,
                        DiagramDataFilterComponent,
                    ],
                    imports: [CommonModule, ButtonsModule, TextPipesModule, InputModule, AbsPipe, MinPipe],
                    exports: [
                        LinearDiagram2DComponent,
                        DiagramPointHoverComponent,
                        DiagramDataFilterComponent,
                    ],
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { DiagramDataFilterComponent, DiagramPointHoverComponent, LinearDiagram2D, LinearDiagram2DComponent, LinearDiagramModule, PointType };
//# sourceMappingURL=obliczeniowo-elementary-linear-diagram.mjs.map