UNPKG

@seismo/core

Version:

This is the package for the core library of Seismo, a JavaScript library for seismic data processing and visualization. It provides utilities for handling seismic data, including FDSN web services, waveform processing, and event handling. The library is d

480 lines (479 loc) 14.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AlignmentLinkedTimeScale = exports.LinkedTimeScale = exports.FixedHalfWidthAmplitudeScale = exports.IndividualAmplitudeScale = exports.LinkedAmplitudeScale = exports.TimeScalable = exports.AmplitudeScalable = exports.MinMaxable = exports.AMPLITUDE_MODE = void 0; const utils_1 = require("../utils"); const luxon_1 = require("luxon"); /** enum for amplitude modes, RAW, ZERO, MINMAX, MEAN */ var AMPLITUDE_MODE; (function (AMPLITUDE_MODE) { AMPLITUDE_MODE["Raw"] = "raw"; AMPLITUDE_MODE["Zero"] = "zero"; AMPLITUDE_MODE["MinMax"] = "minmax"; AMPLITUDE_MODE["Mean"] = "mean"; })(AMPLITUDE_MODE || (exports.AMPLITUDE_MODE = AMPLITUDE_MODE = {})); let _lastId = 0; class MinMaxable { min; max; constructor(min, max) { this.min = min; this.max = max; } get middle() { return (this.min + this.max) / 2; } get halfWidth() { return this.fullWidth / 2; } get fullWidth() { return this.max - this.min; } union(omm) { if (omm) { return new MinMaxable(Math.min(this.min, omm.min), Math.max(this.max, omm.max)); } else { return this; } } expandPercentage(percent) { return MinMaxable.fromMiddleHalfWidth(this.middle, this.halfWidth * percent); } /** * This as a d3 style 2 element array. * * @returns length 2 array of min then max */ asArray() { return [this.min, this.max]; } toString() { return `${this.min} to ${this.max}, mid: ${this.middle} hw: ${this.halfWidth}`; } /** * Create MinMaxable from a d3 style two element array. * * @param minmax array of min then max * @returns new MinMaxable */ static fromArray(minmax) { if (minmax.length < 2) { throw new Error(`array must have lenght 2, ${minmax.length}`); } return new MinMaxable(minmax[0], minmax[1]); } static fromMiddleHalfWidth(mid, halfWidth) { return new MinMaxable(mid - halfWidth, mid + halfWidth); } } exports.MinMaxable = MinMaxable; class AmplitudeScalable { minMax; constructor(minMax) { if (minMax) { this.minMax = minMax; } else { this.minMax = new MinMaxable(0, 0); } } // eslint-disable-next-line no-unused-vars notifyAmplitudeChange(_middle, _halfWidth) { // no-op } get middle() { return this.minMax.middle; } get halfWidth() { return this.minMax.halfWidth; } get fullWidth() { return this.minMax.fullWidth; } get min() { return this.minMax.min; } get max() { return this.minMax.max; } toString() { return this.minMax.toString(); } } exports.AmplitudeScalable = AmplitudeScalable; class TimeScalable { alignmentTimeOffset; duration; constructor(alignmentTimeOffset, duration) { this.alignmentTimeOffset = alignmentTimeOffset; this.duration = duration; } // eslint-disable-next-line no-unused-vars notifyTimeRangeChange(_alignmentTimeOffset, _duration) { // no-op } } exports.TimeScalable = TimeScalable; /** * Links amplitude scales across multiple seismographs, respecting doRmean. * * @param graphList optional list of AmplitudeScalable to link */ class LinkedAmplitudeScale { /** * @private */ _graphSet; _halfWidth; _recalcTimeoutID; _scaleId; constructor(graphList) { this._scaleId = ++_lastId; const glist = graphList ? graphList : []; // in case null this._halfWidth = 0; this._graphSet = new Set(glist); this._recalcTimeoutID = null; } get halfWidth() { return this._halfWidth; } set halfWidth(val) { if (this._halfWidth !== val) { this._halfWidth = val; this.notifyAll().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc halfWidth: ${m}`); }); } } /** * Links new Seismograph with this amplitude scale. * * @param graphList Array of AmplitudeScalable to link */ linkAll(graphList) { graphList.forEach((graph) => { if ("notifyAmplitudeChange" in graph) { this._graphSet.add(graph); } else if ("amp_scalable" in graph) { this._graphSet.add(graph.amp_scalable); } else { // graph does not have notifyAmplitudeChange method or amp_scalable field, skipping } }); this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc linkAll: ${m}`); }); } /** * Link new Seismograph with this amplitude scale. * * @param graph AmplitudeScalable to link */ link(graph) { this.linkAll([graph]); } /** * Unlink Seismograph with this amplitude scale. * * @param graph AmplitudeScalable to unlink */ unlink(graph) { this._graphSet.delete(graph); this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc unlink: ${m}`); }); } /** * Recalculate the best amplitude scale for all Seismographs. Causes a redraw. * * @returns array of promise of best amp scales */ recalculate() { const maxHalfRange = this.graphList.reduce((acc, cur) => { return acc > cur.halfWidth ? acc : cur.halfWidth; }, 0); let promiseOut; if (this.halfWidth !== maxHalfRange) { this.halfWidth = maxHalfRange; promiseOut = this._internalNotifyAll(); } else { // no change promiseOut = Promise.all(this.graphList.map((g) => Promise.resolve(g))); } return promiseOut; } _internalNotifyAll() { const hw = this.halfWidth; return Promise.all(this.graphList.map((g) => { return new Promise((resolve) => { setTimeout(() => { g.notifyAmplitudeChange(g.middle, hw); resolve(g); }, 10); }); })); } notifyAll() { return this._internalNotifyAll(); } get graphList() { return Array.from(this._graphSet.values()); } } exports.LinkedAmplitudeScale = LinkedAmplitudeScale; class IndividualAmplitudeScale extends LinkedAmplitudeScale { constructor(graphList) { super(graphList); } recalculate() { // no-op, just notify return this.notifyAll(); } notifyAll() { return Promise.all(this.graphList.map((g) => { return new Promise((resolve) => { setTimeout(() => { g.notifyAmplitudeChange(g.middle, g.halfWidth); resolve(g); }, 10); }); })); } } exports.IndividualAmplitudeScale = IndividualAmplitudeScale; class FixedHalfWidthAmplitudeScale extends LinkedAmplitudeScale { constructor(halfWidth, graphList) { super(graphList); this.halfWidth = halfWidth; } recalculate() { // no-op, just notify return this.notifyAll(); } notifyAll() { const hw = this.halfWidth; return Promise.all(this.graphList.map((g) => { return new Promise((resolve) => { setTimeout(() => { g.notifyAmplitudeChange(g.middle, hw); resolve(g); }, 10); }); })); } } exports.FixedHalfWidthAmplitudeScale = FixedHalfWidthAmplitudeScale; /** * Links time scales across multiple seismographs. * * @param graphList optional list of TimeScalables to link */ class LinkedTimeScale { /** * @private */ _graphSet; _originalDuration; _originalOffset; _zoomedDuration; _zoomedOffset; _scaleId; constructor(graphList, originalDuration, originalOffset, scaleId) { if (scaleId) { this._scaleId = scaleId; } else { this._scaleId = -1; } const glist = graphList ? graphList : []; // in case null this._graphSet = new Set(glist); this._originalDuration = luxon_1.Duration.fromMillis(0); this._originalOffset = luxon_1.Duration.fromMillis(0); this._zoomedDuration = null; this._zoomedOffset = null; if ((0, utils_1.isDef)(originalDuration)) { this._originalDuration = originalDuration; // so know that duration passed in instead of calculated // this prevents future links from causeing recalc this._zoomedDuration = originalDuration; } else if (glist.length > 0) { this._originalDuration = glist.reduce((acc, cur) => { return acc > cur.duration ? acc : cur.duration; }, luxon_1.Duration.fromMillis(0)); } if (originalOffset) { this._originalOffset = originalOffset; } else { this._originalOffset = luxon_1.Duration.fromMillis(0); } this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc constructor: ${m}`); }); } /** * Link new TimeScalable with this time scale. * * @param graph TimeScalable to link */ link(graph) { this.linkAll([graph]); } /** * Links TimeScalable with this time scale. Each * object in the array should either be a TimeScalable * or have a time_scalable field that is a TimeScalable. * * @param graphList Array of TimeScalable to link */ linkAll(graphList) { graphList.forEach((graph) => { if ("notifyTimeRangeChange" in graph) { this._graphSet.add(graph); } else if ("time_scalable" in graph) { this._graphSet.add(graph.time_scalable); } else { //graph does not have notifyTimeRangeChange method or time_scalable field, skipping } }); this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc linkAll: ${m}`); }); } /** * Unlink TimeScalable with this amplitude scale. * * @param graph TimeScalable to unlink */ unlink(graph) { this._graphSet.delete(graph); this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc unlink: ${m}`); }); } zoom(startOffset, duration) { this._zoomedDuration = duration; this._zoomedOffset = startOffset; this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc zoom: ${m}`); }); } unzoom() { this._zoomedDuration = null; this._zoomedOffset = null; this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc unzoom: ${m}`); }); } get offset() { return this._zoomedOffset ? this._zoomedOffset : this._originalOffset; } set offset(offset) { this._originalOffset = offset; this._zoomedOffset = offset; this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc set offset: ${m}`); }); } get duration() { return (0, utils_1.isDef)(this._zoomedDuration) ? this._zoomedDuration : this._originalDuration; } set duration(duration) { if (!(0, utils_1.isDef)(duration)) { throw new Error(`Duration must be defined`); } this._originalDuration = duration; this._zoomedDuration = duration; this.recalculate().catch((m) => { // eslint-disable-next-line no-console console.warn(`problem recalc set duration: ${m}`); }); } get origOffset() { return this._originalOffset; } get origDuration() { return this._originalDuration; } /** * Recalculate the best time scale for all Seismographs. Causes a redraw. * @returns promise to array of all linked items */ recalculate() { if (!(0, utils_1.isDef)(this._zoomedDuration) || this._originalDuration.toMillis() === 0) { this.graphList.forEach((graph) => { if (graph && graph.duration > this._originalDuration) { this._originalDuration = graph.duration; } }); } return this.notifyAll(); } notifyAll() { return Promise.all(this.graphList.map((g) => { return new Promise((resolve) => { setTimeout(() => { if (g != null) { g.notifyTimeRangeChange(this.offset, this.duration); } resolve(g); }, 10); }); })); } get graphList() { return Array.from(this._graphSet.values()); } } exports.LinkedTimeScale = LinkedTimeScale; /** * Linked Time Scale that only modifies the alignment via the offset. The * duration of the linked TimeScalable is reused. * @param graphList [description] * @param originalDuration [description] * @param originalOffset [description] * @param scaleId [description] */ class AlignmentLinkedTimeScale extends LinkedTimeScale { constructor(graphList, originalDuration, originalOffset, scaleId) { super(graphList, originalDuration, originalOffset, scaleId); } /** * Does no calculation, just causes a redraw. * @returns promise to all linked items */ recalculate() { return this.notifyAll(); } notifyAll() { return Promise.all(this.graphList.map((g) => { return new Promise((resolve) => { setTimeout(() => { if (g != null) { g.notifyTimeRangeChange(this.offset, this.duration); } resolve(g); }, 10); }); })); } } exports.AlignmentLinkedTimeScale = AlignmentLinkedTimeScale;