Angular Mountain Chart Draggable Thresholds

Demonstrates interaction by dragging vertical and horizontal line thresholds on a mountain chart. As the thresholds move, the chart colour updates. The vertical mountain fill is done using a separate renderableSeries and a dataFilter which reshapes the data to draw only the portion above the threshold.

Fullscreen

Edit

 Edit

Docs

drawExample.ts

angular.ts

ExampleDataProvider.ts

theme.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    BaseDataSeries,
3    ECoordinateMode,
4    EFillPaletteMode,
5    EHorizontalAnchorPoint,
6    ELabelPlacement,
7    EStrokePaletteMode,
8    EVerticalAnchorPoint,
9    FastMountainRenderableSeries,
10    GradientParams,
11    HorizontalLineAnnotation,
12    IFillPaletteProvider,
13    IRenderableSeries,
14    IStrokePaletteProvider,
15    MouseWheelZoomModifier,
16    NumberRange,
17    NumericAxis,
18    parseColorToUIntArgb,
19    Point,
20    SciChartSurface,
21    TextAnnotation,
22    VerticalLineAnnotation,
23    XyDataSeries,
24    XyFilterBase,
25    XyyFilterBase,
26    ZoomExtentsModifier,
27    ZoomPanModifier,
28} from "scichart";
29import { ExampleDataProvider } from "../../../ExampleData/ExampleDataProvider";
30import { appTheme } from "../../../theme";
31
32// tslint:disable:no-empty
33// tslint:disable:max-line-length
34
35class ThresholdFilter extends XyFilterBase {
36    private thresholdProperty = 1;
37
38    constructor(originalSeries: BaseDataSeries, threshold: number, dataSeriesName: string) {
39        super(originalSeries, { dataSeriesName });
40        this.thresholdProperty = threshold;
41        this.filterAll();
42    }
43
44    public get threshold() {
45        return this.thresholdProperty;
46    }
47
48    public set threshold(value: number) {
49        this.thresholdProperty = value;
50        this.filterAll();
51    }
52
53    protected filterAll() {
54        this.clear();
55        this.filter(0, this.getOriginalCount());
56    }
57
58    protected filterOnAppend(count: number): void {
59        // Overriding this so we do not have to reprocess the entire series on append
60        this.filter(this.getOriginalCount() - count, count);
61    }
62
63    protected filter(start: number, count: number): void {
64        const xValues: number[] = [];
65        const yValues: number[] = [];
66        for (let i = start; i < start + count; i++) {
67            xValues.push(this.getOriginalXValues().get(i));
68            const y = this.getOriginalYValues().get(i);
69            if (this.threshold > 0 && y < this.threshold) {
70                yValues.push(NaN);
71            } else if (y < 0) {
72                yValues.push(Math.max(y, this.threshold));
73            } else {
74                yValues.push(y);
75            }
76        }
77        this.appendRange(xValues, yValues);
78    }
79
80    protected onClear() {
81        this.clear();
82    }
83}
84
85export const drawExample = async (rootElement: string | HTMLDivElement) => {
86    const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
87        theme: appTheme.SciChartJsTheme,
88    });
89
90    // Add an XAxis, YAxis
91    sciChartSurface.xAxes.add(new NumericAxis(wasmContext));
92    sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { growBy: new NumberRange(0.1, 0.1) }));
93
94    // Create a paletteprovider to colour the series depending on a threshold value
95    const thresholdPalette = new XThresholdPaletteProvider(8, appTheme.VividTeal);
96
97    // Add a Column series with some values to the chart
98    const { xValues, yValues } = ExampleDataProvider.getDampedSinewave(0, 10, 0, 0.001, 3000, 10);
99    const dataSeries = new XyDataSeries(wasmContext, {
100        xValues,
101        yValues,
102    });
103    sciChartSurface.renderableSeries.add(
104        new FastMountainRenderableSeries(wasmContext, {
105            stroke: appTheme.PaleSkyBlue,
106            strokeThickness: 5,
107            zeroLineY: 0.0,
108            dataSeries,
109            fillLinearGradient: new GradientParams(new Point(0, 0), new Point(0, 1), [
110                { color: appTheme.VividSkyBlue, offset: 0 },
111                { color: appTheme.VividSkyBlue + "77", offset: 1 },
112            ]),
113            paletteProvider: thresholdPalette,
114        })
115    );
116
117    const thresholdFilter = new ThresholdFilter(dataSeries, 4.0, "TopFill");
118    const topFill = new FastMountainRenderableSeries(wasmContext, {
119        stroke: appTheme.PaleSkyBlue,
120        strokeThickness: 5,
121        zeroLineY: 4.0,
122        dataSeries: thresholdFilter,
123        fill: appTheme.MutedOrange,
124        paletteProvider: thresholdPalette,
125    });
126    sciChartSurface.renderableSeries.add(topFill);
127
128    // Add a label to tell user what to do
129    const textAnnotation = new TextAnnotation({
130        verticalAnchorPoint: EVerticalAnchorPoint.Bottom,
131        xCoordinateMode: ECoordinateMode.Relative,
132        x1: 0.5,
133        y1: 4.2,
134        fontSize: 22,
135        text: "Drag the lines!",
136        textColor: "White",
137    });
138    // Add a horizontal threshold at Y=5
139    const horizontalLine = new HorizontalLineAnnotation({
140        y1: 4.0,
141        isEditable: true,
142        showLabel: true,
143        stroke: appTheme.VividOrange,
144        strokeThickness: 3,
145        axisLabelFill: appTheme.VividOrange,
146        axisLabelStroke: appTheme.ForegroundColor,
147        labelPlacement: ELabelPlacement.Axis,
148        onDrag: (args) => {
149            // When the horizontal line is dragged, update the
150            // threshold palette and redraw the SciChartSurface
151            topFill.zeroLineY = Math.max(0, horizontalLine.y1);
152            thresholdFilter.threshold = horizontalLine.y1;
153            textAnnotation.y1 = horizontalLine.y1 + 0.2;
154            sciChartSurface.invalidateElement();
155        },
156    });
157    sciChartSurface.annotations.add(horizontalLine);
158    sciChartSurface.annotations.add(textAnnotation);
159
160    // Add a vertical line
161    const verticalLine = new VerticalLineAnnotation({
162        x1: 8,
163        strokeThickness: 3,
164        isEditable: true,
165        showLabel: true,
166        stroke: appTheme.VividTeal,
167        axisLabelFill: appTheme.VividTeal,
168        axisLabelStroke: appTheme.ForegroundColor,
169        labelPlacement: ELabelPlacement.Axis,
170        onDrag: (args) => {
171            // When the vertical line is dragged, update the
172            // threshold palette and redraw the SciChartSurface
173            thresholdPalette.xThresholdValue = verticalLine.x1;
174            sciChartSurface.invalidateElement();
175        },
176    });
177    sciChartSurface.annotations.add(verticalLine);
178
179    // Add instructions
180    sciChartSurface.annotations.add(
181        new TextAnnotation({
182            x1: 0,
183            y1: 0,
184            xAxisId: "history",
185            xCoordinateMode: ECoordinateMode.Relative,
186            yCoordinateMode: ECoordinateMode.Relative,
187            horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
188            verticalAnchorPoint: EVerticalAnchorPoint.Top,
189            text: "SciChart.js supports editable, draggable annotations and dynamic color/fill rules. Drag a threshold line!",
190            textColor: appTheme.ForegroundColor + "77",
191        })
192    );
193
194    // Optional: Add some interactivity modifiers
195    sciChartSurface.chartModifiers.add(new ZoomPanModifier({ enableZoom: true }));
196    sciChartSurface.chartModifiers.add(new ZoomExtentsModifier());
197    sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier());
198
199    return { sciChartSurface, wasmContext };
200};
201
202/**
203 * A paletteprovider which colours a series if X value over a threshold, else use default colour
204 */
205export class XThresholdPaletteProvider implements IFillPaletteProvider {
206    public readonly fillPaletteMode: EFillPaletteMode = EFillPaletteMode.GRADIENT;
207    public readonly strokePaletteMode: EStrokePaletteMode = EStrokePaletteMode.GRADIENT;
208    public xThresholdValue: number;
209    private readonly xColor: number;
210
211    constructor(xThresholdValue: number, xColor: string) {
212        this.xThresholdValue = xThresholdValue;
213        this.xColor = parseColorToUIntArgb(xColor);
214    }
215
216    onAttached(parentSeries: IRenderableSeries): void {}
217
218    onDetached(): void {}
219
220    overrideFillArgb(xValue: number, yValue: number, index: number, opacity?: number): number {
221        // When the x-value of the series is greater than the x threshold
222        // fill with the xColor
223        if (xValue > this.xThresholdValue) {
224            return this.xColor;
225        }
226        // Undefined means use default color
227        return undefined;
228    }
229}
230

See Also: Chart Annotations (6 Demos)

Angular Chart Annotations | SciChart.js Demo

Angular Chart Annotations

Demonstrates how to place Annotations (lines, arrows, markers, text) over a Angular Chart using SciChart.js Annotations API

Coloring Series per-point using the PaletteProvider | SciChart.js Demo

Coloring Series per-point using the PaletteProvider

Demonstrates per-point coloring in JavaScript chart types with SciChart.js PaletteProvider API

Angular Chart Hoverable Buy Sell Marker Annotations | SciChart.js Demo

Angular Chart Hoverable Buy Sell Marker Annotations

Demonstrates how to place Buy/Sell arrow markers on a Angular Stock Chart using SciChart.js - Annotations API

Angular Chart Editable Annotations | SciChart.js Demo

Angular Chart Editable Annotations

Demonstrates how to edit Annotations (shapes, boxes, lines, text, horizontal and vertical line) over a Angular Chart using SciChart.js Annotations API

Angular Quadrant Chart using Background Annotations | SciChart.js Demo

Angular Quadrant Chart using Background Annotations

Demonstrates how to color areas of the chart surface using background Annotations using SciChart.js Annotations API

Angular Chart Annotation Layers | SciChart.js Demo

Angular Chart Annotation Layers

Demonstrates how layering works a Angular Chart using SciChart.js Annotations API

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.