UNPKG

dasf-web

Version:

Web frontend components for the data analytics software framework (DASF)

202 lines (162 loc) 6.2 kB
import createLinearGradient from 'color-mapper/lib/index'; import LinearGradient from 'color-mapper/lib/index'; import { Observable } from 'typescript-observable/dist/observable' import { IObservableEvent } from 'typescript-observable/dist/interfaces/observable-event'; import ColorUtils from './ColorUtils'; export class ColorRamp { public constructor(public readonly name: string, public readonly colors: string[]) { } } // ['red', 'orange', 'yellow', 'lime', 'aqua', 'blue'] ; // const SpectralColors: string[] = ['#d7191c', '#fdae61', '#ffffbf', '#abdda4', '#2b83ba']; // const TravelTest: string[] = ['#feebe2', '#fbb4b9', '#f768a1', '#c51b8a', '#7a0177']; const Spectral: ColorRamp = new ColorRamp('Spectral', ['#d7191c', '#fdae61', '#ffffbf', '#abdda4', '#2b83ba']); const YellowOrRed: ColorRamp = new ColorRamp('YellowOrRed', ['#ffffb2', '#fecc5c', '#fd8d3c', '#f03b20', '#bd0026']); const Magma: ColorRamp = new ColorRamp('Magma', ['#000004', '#4a1079', '#a1307e', '#f1605d', '#feaa74', '#fcfdbf']); const RedOrBlue: ColorRamp = new ColorRamp('RedOrBlue', ['#ca0020', '#f4a582', '#f7f7f7', '#92c5de', '#0571b0']); const ColdToHot: ColorRamp = new ColorRamp('ColdToHot', ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']); const Precipitation: ColorRamp = new ColorRamp('Pr', ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']); // pre-defined color ramps const PredefinedColorRamps: ColorRamp[] = [ Spectral, ColdToHot, YellowOrRed, Magma, RedOrBlue, Precipitation ]; export { PredefinedColorRamps, Spectral, YellowOrRed, Magma, RedOrBlue, ColdToHot, Precipitation } class SingleColor { public constructor(private color: string) { } public getColor(value: number): string { return this.color; } } export interface HasGradient { getGradient(): Gradient | undefined; setGradient(gradient: Gradient): void; } /** * Simple wrapper around the gradient provided by color-mapper */ export default class Gradient extends Observable { private static DEFAULT_COLOR = "#0000ff"; private colorRamp: ColorRamp; private gradient: LinearGradient; private min: number; private max: number; private minColorRgba: number[]; private maxColorRgba: number[]; private readonly changeEvent: IObservableEvent = { parent: null, name: 'changed' }; public constructor(colorRamp: ColorRamp, min: number, max: number) { super(); this.colorRamp = colorRamp; this.updateMinMaxColors(); this.min = min; this.max = max; this.updateMinMax(min, max); } private updateMinMaxColors(): void { this.minColorRgba = ColorUtils.hex2Rgb(this.colorRamp.colors[0]); this.minColorRgba.push(255); this.maxColorRgba = ColorUtils.hex2Rgb(this.colorRamp.colors[this.colorRamp.colors.length - 1]); this.maxColorRgba.push(255); } public setColorRamp(colorRamp: ColorRamp): void { let changed = colorRamp !== this.colorRamp; this.colorRamp = colorRamp; this.updateMinMaxColors(); // update the underlying linear gradient this.updateMinMax(this.min, this.max); if (changed) { this.changed(); } } public updateMinMax(min?: number, max?: number): void { let minChanged = false; let maxChanged = false; if (min !== undefined && this.min != min) { this.min = min; minChanged = true; } if (max !== undefined && this.max != max) { this.max = max; maxChanged = true; } if (this.min !== this.max) { this.gradient = createLinearGradient(min, max); // equal steps between colors let step = 1.0 / (this.colorRamp.colors.length - 1); let value = 0.0; // set color stops for (let color of this.colorRamp.colors) { this.gradient.addColorStop(value, color); value += step; } } else { // this is no gradient because the range is zero (min == max) this.gradient = new SingleColor(this.colorRamp.colors[0]); } if (minChanged || maxChanged) { this.changed(); } } private changed(): void { this.notify(this.changeEvent, this); } public getColor(value: number): string { if (value !== undefined) { // auto tune min max values if (value < this.min) { this.updateMinMax(value, this.max); } if (value > this.max) { this.updateMinMax(this.min, value); } return this.gradient.getColor(value); } else if (this.min == this.max) { // we have no real gradient anyway - return single color return this.gradient.getColor(value); } else { return Gradient.DEFAULT_COLOR; } } public getColorRGBA(value: number): number[] { if (value !== undefined) { // auto tune min max values if (value < this.min) { this.updateMinMax(value, this.max); } if (value > this.max) { this.updateMinMax(this.min, value); } if (value === this.max) { return this.maxColorRgba; } else if (value === this.min) { return this.minColorRgba; } try { let rgba = this.gradient.getColor(value); rgba[3] = 255; return rgba; } catch (e) { console.error('error in gradient', this.gradient, value); // console.log(e); } } return [0, 0, 0, 255]; } public getColorRamp(): ColorRamp { return this.colorRamp; } public getMin(): number { return this.min; } public getMax(): number { return this.max; } }