├── .eslintrc.cjs ├── .gitattributes ├── .gitignore ├── .npmignore ├── .prettierrc ├── CITATION.cff ├── LICENSE ├── README.md ├── VERSION ├── build.mjs ├── createApiDocs.sh ├── docs ├── api │ ├── animatedseismograph.html │ ├── areautil.html │ ├── assets │ │ ├── anchor.js │ │ ├── bass-addons.css │ │ ├── bass.css │ │ ├── github.css │ │ ├── site.js │ │ ├── split.css │ │ ├── split.js │ │ └── style.css │ ├── axisutil.html │ ├── components.html │ ├── cssutil.html │ ├── datalink.html │ ├── dataset.html │ ├── datechooser.html │ ├── distaz.html │ ├── fdsnavailability.html │ ├── fdsncommon.html │ ├── fdsndatacenters.html │ ├── fdsndataselect.html │ ├── fdsnevent.html │ ├── fdsneventcomponent.html │ ├── fdsnsourceid.html │ ├── fdsnstation.html │ ├── fdsnstationcomponent.html │ ├── fft.html │ ├── filter.html │ ├── handlebarshelpers.html │ ├── helicorder.html │ ├── index.html │ ├── infotable.html │ ├── irisfedcatalog.html │ ├── leaflet_css.html │ ├── leafletutil.html │ ├── miniseed.html │ ├── ms3ehtypes.html │ ├── mseed3.html │ ├── mseed3eh.html │ ├── mseedarchive.html │ ├── oregondsputil.html │ ├── organizeddisplay.html │ ├── particlemotion.html │ ├── quakeml.html │ ├── ringserverweb.html │ ├── sacpolezero.html │ ├── scale.html │ ├── seedcodec.html │ ├── seedlink.html │ ├── seedlink4.html │ ├── seismogram.html │ ├── seismogramloader.html │ ├── seismogramsegment.html │ ├── seismograph.html │ ├── seismographconfig.html │ ├── seismographconfigeditor.html │ ├── seismographmarker.html │ ├── seismographutil.html │ ├── sorting.html │ ├── spectraplot.html │ ├── spelement.html │ ├── stationxml.html │ ├── taper.html │ ├── textformat.html │ ├── transfer.html │ ├── traveltime.html │ ├── usgsgeojson.html │ ├── util.html │ ├── vector.html │ └── version.html ├── bass.css ├── examples │ ├── firDesign │ │ ├── firDesign.js │ │ ├── index.html │ │ ├── style.css │ │ └── testData │ │ │ └── XX.PI04.RW.HNZ.2019.070.18 │ ├── helicorder │ │ ├── controls.js │ │ ├── doplot.js │ │ ├── heli.js │ │ ├── index.html │ │ └── style.css │ ├── index.html │ ├── instResponse │ │ └── index.html │ ├── mseed3 │ │ ├── index.html │ │ └── mseed3_example.js │ ├── response │ │ ├── channel_chooser.js │ │ ├── index.html │ │ ├── response_parse.js │ │ ├── response_plot.js │ │ ├── sis_filtercascade_15242.xml │ │ └── style.css │ ├── ringserver │ │ ├── index.html │ │ ├── rsweb.js │ │ └── stream_chooser.js │ └── style.css ├── flavicon.png ├── flavicon.svg ├── gallery │ ├── channelchooser.html │ ├── channelsearch.html │ ├── colors.html │ ├── dataset.zip │ ├── datetime.html │ ├── earthquakesearch.html │ ├── helicorder.html │ ├── index.html │ ├── infotable.html │ ├── latlon.html │ ├── map.html │ ├── minmaxinput.html │ ├── organizeddisplay.html │ ├── particlemotion.html │ ├── seisconfigeditor.html │ ├── seismograph.html │ ├── spectra.html │ └── style.css ├── index.html ├── prism.css ├── prism.js ├── seisplotjs_3.1.4_standalone.mjs ├── seisplotjs_3.1.5-SNAPSHOT_standalone.mjs ├── split.css └── tutorial │ ├── 2_realdata.html │ ├── 3_quakesandchannels.html │ ├── 4_arrivaltimes.html │ ├── 5_filter.html │ ├── 6_helicorder.html │ ├── 7_realtime.html │ ├── 8_andmore.html │ ├── 8_andmore_part.html │ ├── index.html │ ├── style.css │ ├── tutorial1.html │ ├── tutorial1.js │ ├── tutorial2.html │ ├── tutorial2.js │ ├── tutorial3.html │ ├── tutorial3.js │ ├── tutorial4.html │ ├── tutorial4.js │ ├── tutorial5.html │ ├── tutorial5.js │ ├── tutorial6.html │ ├── tutorial6.js │ ├── tutorial7.html │ ├── tutorial7.js │ ├── tutorial7_sl4.html │ ├── tutorial7_sl4.js │ └── tutorial_template.html ├── global.d.ts ├── jest.config.js ├── jest.setup.ts ├── jest_remote.config.js ├── package-lock.json ├── package.json ├── replaceInHtml.py ├── replaceVersion.py ├── rollup.config.js ├── snippetToTutorial.py ├── src ├── animatedseismograph.ts ├── areautil.ts ├── axisutil.ts ├── components.ts ├── cssutil.ts ├── datalink.ts ├── dataset.ts ├── datechooser.ts ├── distaz.ts ├── fdsnavailability.ts ├── fdsncommon.ts ├── fdsndatacenters.ts ├── fdsndataselect.ts ├── fdsnevent.ts ├── fdsneventcomponent.ts ├── fdsnsourceid.ts ├── fdsnstation.ts ├── fdsnstationcomponent.ts ├── fft.ts ├── filter.ts ├── handlebarshelpers.ts ├── helicorder.ts ├── index.ts ├── index_node.ts ├── infotable.ts ├── irisfedcatalog.ts ├── leaflet_css.ts ├── leafletutil.ts ├── miniseed.ts ├── ms3ehtypes.ts ├── mseed3.ts ├── mseed3eh.ts ├── mseedarchive.ts ├── oregondsputil.ts ├── organizeddisplay.ts ├── particlemotion.ts ├── quakeml.ts ├── ringserverweb.ts ├── sacpolezero.ts ├── scale.ts ├── seedcodec.ts ├── seedlink.ts ├── seedlink4.ts ├── seismogram.ts ├── seismogramloader.ts ├── seismogramsegment.ts ├── seismograph.ts ├── seismographconfig.ts ├── seismographconfigeditor.ts ├── seismographmarker.ts ├── seismographutil.ts ├── sorting.ts ├── spectraplot.ts ├── spelement.ts ├── stationxml.ts ├── taper.ts ├── textformat.ts ├── transfer.ts ├── traveltime.ts ├── usgsgeojson.ts ├── util.ts ├── vector.ts └── version.ts ├── test ├── badspike.ms3 ├── checkProtocol.test.ts ├── distaz.spec.ts ├── fdsnavailability.test.ts ├── fdsndatacenters.test.ts ├── fdsndataselect │ └── fdsndataselect.test.ts ├── fdsnevent │ └── fdsnevent.test.ts ├── fdsnsourceid.test.ts ├── fdsnstation │ ├── fdsnstation.test.ts │ └── util.test.ts ├── filter │ ├── cut.test.ts │ ├── data │ │ ├── 1_rmean.sac │ │ ├── 2_taper.sac │ │ ├── 3_transfer.sac │ │ ├── IU.HRV.__.BHE.SAC │ │ ├── IU.HRV.__.BHE_fft.sac.am │ │ ├── IU.HRV.__.BHE_fft.sac.ph │ │ ├── const100.sac │ │ ├── hrv.bhe.sacpz │ │ ├── impulse.sac │ │ ├── impulse_corrected.sac │ │ ├── impulse_onezero.sac │ │ ├── impulse_onezero_fftam.sac.am │ │ ├── onezero.sacpz │ │ └── taper100.sac │ ├── differentiate.test.ts │ ├── fft.test.ts │ ├── filter.test.ts │ ├── hilbert.test.ts │ ├── integrate.test.ts │ ├── rtrend.test.ts │ ├── sacfile.ts │ ├── sacpolezero.test.ts │ ├── taper.test.ts │ └── transfer.test.ts ├── irisfedcatalog.test.ts ├── jestRatioMatchers.ts ├── metatest.test.ts ├── miniseed │ ├── CO_JSC.mseed │ ├── headerTimes.test.ts │ └── miniseed_file.test.ts ├── mseed3 │ ├── bag_eh.json │ ├── bird_jsc.ms3 │ ├── mseed3_file.test.ts │ ├── mseed3eh.test.ts │ ├── one_record_HODGE_HHZ.ms2 │ ├── one_record_HODGE_HHZ.ms3 │ └── testeh.ms3 ├── quakeml │ ├── data │ │ ├── obspy_catalog.xml │ │ └── usgs.xml │ └── quakeml.test.ts ├── ringserverweb.test.ts ├── scale.test.ts ├── seismogram.test.ts ├── seismographconfig.test.ts ├── seismographutil.test.ts ├── stationxml │ ├── data │ │ └── co_jsc.staxml │ ├── network.test.ts │ ├── parsestationxml.test.ts │ └── station.test.ts ├── traveltime │ ├── data │ │ └── hodge_eq_tt.json │ └── formUrl.test.ts ├── usgs_geojson.test.ts ├── util.test.ts └── vector.test.ts ├── testremotes ├── fdsnavailability_livetest.ts ├── fdsnstation_livetest.ts ├── irisfedcatalog_livetest.ts ├── ringserver_livetest.ts ├── seismogramload_livetest.ts ├── traveltime.livetest.ts └── usgsgeojson_livetest.ts ├── tsconfig.json └── watch.sh /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "@typescript-eslint/parser", 4 | plugins: ["@typescript-eslint", "promise", "jest", "jsdoc"], 5 | extends: [ 6 | "eslint:recommended", 7 | "plugin:@typescript-eslint/recommended", 8 | "plugin:jest/recommended", 9 | "plugin:jsdoc/recommended", 10 | "plugin:@typescript-eslint/recommended", 11 | "plugin:@typescript-eslint/recommended-requiring-type-checking", 12 | ], 13 | env: { 14 | es6: true, 15 | browser: true, 16 | "jest/globals": true, 17 | }, 18 | parserOptions: { 19 | ecmaVersion: 6, 20 | sourceType: "module", 21 | tsconfigRootDir: __dirname, 22 | project: ["./tsconfig.json"], 23 | }, 24 | rules: { 25 | semi: ["error", "always"], 26 | "no-var": ["error"], 27 | "no-console": ["error"], 28 | "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_.*" }], 29 | "@typescript-eslint/restrict-template-expressions": [ 30 | "error", 31 | { 32 | allowNumber: true, 33 | allowNullish: true, 34 | allowBoolean: true, 35 | }, 36 | ], 37 | eqeqeq: ["error", "smart"], 38 | "jsdoc/require-param-type": ["off"], 39 | "jsdoc/require-returns-type": ["off"], 40 | "jsdoc/no-types": ["error"], 41 | "jsdoc/require-jsdoc": ["off", { require: { MethodDefinition: true } }], 42 | "jsdoc/tag-lines": ["off"], 43 | // above are rule configs I think should be different from std eslint 44 | // 45 | // below are errors rules should be fixed in code, but haven't gotten to yet 46 | "@typescript-eslint/no-explicit-any": ["off"], 47 | "@typescript-eslint/no-unsafe-assignment": ["off"], 48 | "@typescript-eslint/no-unsafe-member-access": ["off"], 49 | "@typescript-eslint/no-unsafe-argument": ["off"], 50 | "@typescript-eslint/no-unnecessary-type-assertion": ["off"], 51 | "@typescript-eslint/no-this-alias": ["off"], 52 | "jest/no-done-callback": ["off"], 53 | "@typescript-eslint/no-unsafe-return": ["off"], 54 | "@typescript-eslint/no-unsafe-call": ["off"], 55 | "@typescript-eslint/no-namespace": ["off"], 56 | }, 57 | }; 58 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | docs/seisplotjs_*_standalone.mjs binary 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | docs/module 3 | seisplotjs_1.2.0_standalone.js 4 | node_modules 5 | example/**/seisplotjs_*_standalone.js 6 | web_modules 7 | docs/api/assets/fonts 8 | pkg 9 | test/mseed3/reference-data 10 | example/huddle 11 | example/simpleHttp.sh 12 | jsonSchema 13 | es6example 14 | README_part.md 15 | __pycache__ 16 | .DS_Store 17 | jest_html_reporters.html 18 | jest-html-reporters-attach 19 | savedExamples 20 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example/ 2 | .DS_Store 3 | .git/ 4 | seisplotjs_*_standalone.js 5 | src/handlebarsimport.esbuild 6 | src/handlebarsimport.typescript 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | # This CITATION.cff file was generated with cffinit. 2 | # Visit https://bit.ly/cffinit to generate yours today! 3 | 4 | cff-version: 1.2.0 5 | title: Seisplotjs 6 | message: >- 7 | If you use this software, please cite it using the 8 | metadata from this file. 9 | type: software 10 | authors: 11 | - family-names: Crotwell 12 | given-names: H. Philip 13 | email: crotwell@seis.sc.edu 14 | affiliation: University of South Carolina 15 | orcid: 'https://orcid.org/0000-0001-6231-4847' 16 | repository-code: 'https://github.com/crotwell/seisplotjs' 17 | url: 'https://crotwell.github.io/seisplotjs/' 18 | repository: 'http://www.seis.sc.edu/downloads/seisplotjs/' 19 | repository-artifact: 'https://www.npmjs.com/package/seisplotjs' 20 | abstract: >- 21 | Javascript modules for parsing, manipulating and plotting 22 | seismic data. 23 | keywords: 24 | - seismology 25 | - earthquake 26 | - miniseed 27 | - seismograph 28 | - stationxml 29 | - quakeml 30 | - fdsn web services 31 | license: MIT 32 | commit: 13b0244fe88f601de4cd29544dfd75050897dc1e 33 | version: 3.1.1 34 | date-released: '2023-09-11' 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Philip Crotwell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 3.1.5-SNAPSHOT 2 | -------------------------------------------------------------------------------- /build.mjs: -------------------------------------------------------------------------------- 1 | // modify from https://souporserious.com/bundling-typescript-with-esbuild-for-npm/ 2 | 3 | //const { build } = require('esbuild') 4 | //const { Generator } = require('npm-dts') 5 | //const { dependencies, peerDependencies } = require('./package.json') 6 | 7 | import { build } from "esbuild"; 8 | //import {Generator} from 'npm-dts' 9 | import * as fs from "fs"; 10 | const loadJSON = (path) => 11 | JSON.parse(fs.readFileSync(new URL(path, import.meta.url))); 12 | const mypackage = loadJSON("./package.json"); 13 | const dependencies = mypackage.dependencies; 14 | //import {dependencies, peerDependencies } from './package.json' assert { type: "json" }; 15 | 16 | const entryFile = "src/index.ts"; 17 | const entryPoints = [entryFile]; 18 | const shared = { 19 | entryPoints: [entryFile], 20 | bundle: true, 21 | external: Object.keys(dependencies), 22 | define: { global: "window" }, 23 | }; 24 | 25 | build({ 26 | ...shared, 27 | outfile: "dist/index.js", 28 | }); 29 | 30 | build({ 31 | ...shared, 32 | outfile: "dist/index.mjs", 33 | format: "esm", 34 | }); 35 | 36 | // build separate files for each module for easier use of part of sp and 37 | // help with tree shaking??? 38 | const nonEntryPoints = [ 39 | "handlebarshelpers", 40 | "leaflet_css", 41 | "oregondsputil", 42 | "scale", 43 | "seismogramsegment", 44 | "seismographconfig", 45 | "seismographconfigeditor", 46 | "sorting", 47 | "spelement", 48 | "util", 49 | "vector", 50 | "version", 51 | ].map((f) => `${f}.ts`); 52 | const srcFiles = fs 53 | .readdirSync("./src") 54 | .filter((k) => k.endsWith(".ts")) 55 | .filter((k) => !k.startsWith("index")) 56 | .filter((k) => !nonEntryPoints.includes(k)) 57 | .map((f) => `src/${f}`); 58 | console.log(`src files: ${srcFiles}`); 59 | build({ 60 | entryPoints: srcFiles, 61 | bundle: true, 62 | platform: "neutral", 63 | external: Object.keys(dependencies), 64 | outdir: "dist/esm", 65 | format: "esm", 66 | }); 67 | 68 | // without leaflet for node (leaflet requires window global) 69 | const nodeEntryFile = "src/index_node.ts"; 70 | const nodeDependencies = Object.keys(dependencies).filter( 71 | (k) => k !== "leaflet" && k !== "leafletutil", 72 | ); 73 | console.log(`deps: ${nodeDependencies}`); 74 | build({ 75 | entryPoints: [nodeEntryFile], 76 | bundle: true, 77 | external: nodeDependencies, 78 | outfile: "dist/index_node.mjs", 79 | format: "esm", 80 | }); 81 | 82 | // new Generator({ 83 | // entry: entryFile, 84 | // output: 'dist/index.d.ts', 85 | // }).generate() 86 | -------------------------------------------------------------------------------- /docs/api/assets/bass-addons.css: -------------------------------------------------------------------------------- 1 | .input { 2 | font-family: inherit; 3 | display: block; 4 | width: 100%; 5 | height: 2rem; 6 | padding: .5rem; 7 | margin-bottom: 1rem; 8 | border: 1px solid #ccc; 9 | font-size: .875rem; 10 | border-radius: 3px; 11 | box-sizing: border-box; 12 | } 13 | -------------------------------------------------------------------------------- /docs/api/assets/github.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | color: #333; 12 | background: #f8f8f8; 13 | -webkit-text-size-adjust: none; 14 | } 15 | 16 | .hljs-comment, 17 | .diff .hljs-header, 18 | .hljs-javadoc { 19 | color: #998; 20 | font-style: italic; 21 | } 22 | 23 | .hljs-keyword, 24 | .css .rule .hljs-keyword, 25 | .hljs-winutils, 26 | .nginx .hljs-title, 27 | .hljs-subst, 28 | .hljs-request, 29 | .hljs-status { 30 | color: #1184CE; 31 | } 32 | 33 | .hljs-number, 34 | .hljs-hexcolor, 35 | .ruby .hljs-constant { 36 | color: #ed225d; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-tag .hljs-value, 41 | .hljs-phpdoc, 42 | .hljs-dartdoc, 43 | .tex .hljs-formula { 44 | color: #ed225d; 45 | } 46 | 47 | .hljs-title, 48 | .hljs-id, 49 | .scss .hljs-preprocessor { 50 | color: #900; 51 | font-weight: bold; 52 | } 53 | 54 | .hljs-list .hljs-keyword, 55 | .hljs-subst { 56 | font-weight: normal; 57 | } 58 | 59 | .hljs-class .hljs-title, 60 | .hljs-type, 61 | .vhdl .hljs-literal, 62 | .tex .hljs-command { 63 | color: #458; 64 | font-weight: bold; 65 | } 66 | 67 | .hljs-tag, 68 | .hljs-tag .hljs-title, 69 | .hljs-rules .hljs-property, 70 | .django .hljs-tag .hljs-keyword { 71 | color: #000080; 72 | font-weight: normal; 73 | } 74 | 75 | .hljs-attribute, 76 | .hljs-variable, 77 | .lisp .hljs-body { 78 | color: #008080; 79 | } 80 | 81 | .hljs-regexp { 82 | color: #009926; 83 | } 84 | 85 | .hljs-symbol, 86 | .ruby .hljs-symbol .hljs-string, 87 | .lisp .hljs-keyword, 88 | .clojure .hljs-keyword, 89 | .scheme .hljs-keyword, 90 | .tex .hljs-special, 91 | .hljs-prompt { 92 | color: #990073; 93 | } 94 | 95 | .hljs-built_in { 96 | color: #0086b3; 97 | } 98 | 99 | .hljs-preprocessor, 100 | .hljs-pragma, 101 | .hljs-pi, 102 | .hljs-doctype, 103 | .hljs-shebang, 104 | .hljs-cdata { 105 | color: #999; 106 | font-weight: bold; 107 | } 108 | 109 | .hljs-deletion { 110 | background: #fdd; 111 | } 112 | 113 | .hljs-addition { 114 | background: #dfd; 115 | } 116 | 117 | .diff .hljs-change { 118 | background: #0086b3; 119 | } 120 | 121 | .hljs-chunk { 122 | color: #aaa; 123 | } 124 | -------------------------------------------------------------------------------- /docs/api/assets/split.css: -------------------------------------------------------------------------------- 1 | .gutter { 2 | background-color: #f5f5f5; 3 | background-repeat: no-repeat; 4 | background-position: 50%; 5 | } 6 | 7 | .gutter.gutter-vertical { 8 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII='); 9 | cursor: ns-resize; 10 | } 11 | 12 | .gutter.gutter-horizontal { 13 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=='); 14 | cursor: ew-resize; 15 | } 16 | -------------------------------------------------------------------------------- /docs/api/assets/style.css: -------------------------------------------------------------------------------- 1 | .documentation { 2 | font-family: Helvetica, sans-serif; 3 | color: #666; 4 | line-height: 1.5; 5 | background: #f5f5f5; 6 | } 7 | 8 | .black { 9 | color: #666; 10 | } 11 | 12 | .bg-white { 13 | background-color: #fff; 14 | } 15 | 16 | h4 { 17 | margin: 20px 0 10px 0; 18 | } 19 | 20 | .documentation h3 { 21 | color: #000; 22 | } 23 | 24 | .border-bottom { 25 | border-color: #ddd; 26 | } 27 | 28 | a { 29 | color: #1184ce; 30 | text-decoration: none; 31 | } 32 | 33 | .documentation a[href]:hover { 34 | text-decoration: underline; 35 | } 36 | 37 | a:hover { 38 | cursor: pointer; 39 | } 40 | 41 | .py1-ul li { 42 | padding: 5px 0; 43 | } 44 | 45 | .max-height-100 { 46 | max-height: 100%; 47 | } 48 | 49 | .height-viewport-100 { 50 | height: 100vh; 51 | } 52 | 53 | section:target h3 { 54 | font-weight: 700; 55 | } 56 | 57 | .documentation td, 58 | .documentation th { 59 | padding: 0.25rem 0.25rem; 60 | } 61 | 62 | h1:hover .anchorjs-link, 63 | h2:hover .anchorjs-link, 64 | h3:hover .anchorjs-link, 65 | h4:hover .anchorjs-link { 66 | opacity: 1; 67 | } 68 | 69 | .fix-3 { 70 | width: 25%; 71 | max-width: 244px; 72 | } 73 | 74 | .fix-3 { 75 | width: 25%; 76 | max-width: 244px; 77 | } 78 | 79 | @media (min-width: 52em) { 80 | .fix-margin-3 { 81 | margin-left: 25%; 82 | } 83 | } 84 | 85 | .pre, 86 | pre, 87 | code, 88 | .code { 89 | font-family: Source Code Pro, Menlo, Consolas, Liberation Mono, monospace; 90 | font-size: 14px; 91 | } 92 | 93 | .fill-light { 94 | background: #f9f9f9; 95 | } 96 | 97 | .width2 { 98 | width: 1rem; 99 | } 100 | 101 | .input { 102 | font-family: inherit; 103 | display: block; 104 | width: 100%; 105 | height: 2rem; 106 | padding: 0.5rem; 107 | margin-bottom: 1rem; 108 | border: 1px solid #ccc; 109 | font-size: 0.875rem; 110 | border-radius: 3px; 111 | box-sizing: border-box; 112 | } 113 | 114 | table { 115 | border-collapse: collapse; 116 | } 117 | 118 | .prose table th, 119 | .prose table td { 120 | text-align: left; 121 | padding: 8px; 122 | border: 1px solid #ddd; 123 | } 124 | 125 | .prose table th:nth-child(1) { 126 | border-right: none; 127 | } 128 | .prose table th:nth-child(2) { 129 | border-left: none; 130 | } 131 | 132 | .prose table { 133 | border: 1px solid #ddd; 134 | } 135 | 136 | .prose-big { 137 | font-size: 18px; 138 | line-height: 30px; 139 | } 140 | 141 | .quiet { 142 | opacity: 0.7; 143 | } 144 | 145 | .minishadow { 146 | box-shadow: 2px 2px 10px #f3f3f3; 147 | } 148 | -------------------------------------------------------------------------------- /docs/api/leaflet_css.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | seisplotjs 3.1.4 | Documentation 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

seisplotjs

18 |
3.1.4
19 | 27 |
28 | 41 |
42 | 45 |
46 |
47 |
48 | 49 | 50 |
51 | 52 | 53 |
54 | 55 |

56 | leaflet_css 57 |

58 | 59 | 60 | 61 | src/leaflet_css.ts 62 | 63 | 64 |
65 | 66 | 67 | 68 |
leaflet_css
69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
99 | 100 | 101 | 102 |
103 |
104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/api/version.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | seisplotjs 3.1.4 | Documentation 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

seisplotjs

18 |
3.1.4
19 | 27 |
28 | 41 |
42 | 45 |
46 |
47 |
48 | 49 | 50 |
51 | 52 | 53 |
54 | 55 |

56 | version 57 |

58 | 59 | 60 | 61 | src/version.ts 62 | 63 | 64 |
65 | 66 | 67 | 68 |
version
69 | 70 |

71 | Type: 72 | string 73 |

74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 |
104 | 105 | 106 | 107 |
108 |
109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /docs/examples/firDesign/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | Seisplotjs - 11 | Examples - FIR Design 12 |
13 | 14 |

15 | OregonDSP 16 | Equiripple Lowpass FIR filter design 17 |

18 |

19 | Calculate a FIR filter. N is the half size of the filter, so the resulting 20 | filter will have 2N+1 points. OmegaP is the end of the pass band, the 21 | ripple in the pass band is weighted with Wp. OmegaS is the beginning of 22 | the stop band, the stop band is weighted with Ws. Data npts just controls 23 | the number of points to create the FFT for display, it does not effect the 24 | filter. 25 |

26 |
27 |
28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 | 36 | 37 |
38 | 39 |
40 |
41 | 43 | 46 |
47 |
48 | 49 |

FFT FIR plot

50 |
51 | 52 |
53 | 54 |

55 |
56 |
57 |
58 |
59 | Generated with 60 | Seisplotjs version 3. 63 |
64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /docs/examples/firDesign/style.css: -------------------------------------------------------------------------------- 1 | div.fftfir { 2 | height: 500px; 3 | } 4 | 5 | sp-spectra { 6 | height: 250px; 7 | } 8 | 9 | sp-seismograph { 10 | height: 300px; 11 | } 12 | -------------------------------------------------------------------------------- /docs/examples/firDesign/testData/XX.PI04.RW.HNZ.2019.070.18: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crotwell/seisplotjs/203bc8e9516b68afadf2aa12c40b8a1177489469/docs/examples/firDesign/testData/XX.PI04.RW.HNZ.2019.070.18 -------------------------------------------------------------------------------- /docs/examples/helicorder/style.css: -------------------------------------------------------------------------------- 1 | #heli { 2 | height: 600px; 3 | } 4 | sp-seismograph { 5 | height: 300px; 6 | } 7 | div form span { 8 | margin-right: 10px; 9 | } 10 | div span span { 11 | margin-right: 10px; 12 | } 13 | .sectionlabel { 14 | color: darkgrey; 15 | margin-right: 5px; 16 | margin-left: 10px; 17 | } 18 | #messages { 19 | color: red; 20 | } 21 | 22 | input.smallnum { 23 | width: 6em; 24 | } 25 | 26 | input#percentAmpSlider { 27 | vertical-align: middle; 28 | } 29 | 30 | text.sublabel { 31 | font-size: x-small; 32 | } 33 | 34 | .tooltip { 35 | display: inline; 36 | position: relative; 37 | } 38 | 39 | .tooltip:hover:after { 40 | background: #333; 41 | background: rgba(255, 255, 255, 0.8); 42 | border-radius: 5px; 43 | bottom: 26px; 44 | color: #fff; 45 | content: attr(title); 46 | left: 20%; 47 | padding: 5px 15px; 48 | position: absolute; 49 | z-index: 98; 50 | width: 220px; 51 | } 52 | 53 | .tooltip:hover:before { 54 | border: solid; 55 | border-color: #333 transparent; 56 | border-width: 6px 6px 0 6px; 57 | bottom: 20px; 58 | content: ""; 59 | left: 50%; 60 | position: absolute; 61 | z-index: 99; 62 | } 63 | -------------------------------------------------------------------------------- /docs/examples/mseed3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Miniseed3 6 | 11 | 12 | 13 | 14 |
15 | Seisplotjs - 16 | Examples - MSeed3 17 |
18 | 19 |

Miniseed3:

20 |
21 |

As a seismograph:

22 | 23 |

Miniseed 3 Records:

24 |
25 | 26 |
27 | Generated with 28 | Seisplotjs version 3. 31 |
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/examples/mseed3/mseed3_example.js: -------------------------------------------------------------------------------- 1 | import * as sp from "../../seisplotjs_3.1.5-SNAPSHOT_standalone.mjs"; 2 | let timeWindow = new sp.util.startDuration("2019-07-06T03:19:53Z", 1800); 3 | let dsQuery = new sp.fdsndataselect.DataSelectQuery(); 4 | console.log(`miniseed3: ${sp.fdsndataselect.FORMAT_MINISEED_THREE}`); 5 | dsQuery 6 | .networkCode("CO") 7 | .stationCode("HODGE") 8 | .locationCode("00") 9 | .channelCode("LHZ") 10 | .format(sp.fdsndataselect.FORMAT_MINISEED_THREE) 11 | .timeRange(timeWindow); 12 | // snip start queryseis 13 | // this is better way to get seismograms 14 | //dsQuery.querySeismograms().then(seisArray => { 15 | // but this allows us to see the individual records 16 | dsQuery 17 | .queryMS3Records() 18 | .then((ms3Records) => { 19 | let urldiv = document.querySelector("div#dataselecturl"); 20 | let ds_url = dsQuery.formURL(); 21 | urldiv.innerHTML = `

Dataselect URL: ${ds_url}

`; 22 | let div = document.querySelector("div#mseed3astext"); 23 | ms3Records.forEach((ms3rec) => { 24 | const pre = div.appendChild(document.createElement("pre")); 25 | pre.textContent = ms3rec.toString(); 26 | }); 27 | 28 | return sp.mseed3.seismogramPerChannel(ms3Records); 29 | }) 30 | .then((seisArray) => { 31 | // only plot the first seismogram 32 | let seismogram = seisArray[0]; 33 | let graph = document.querySelector("sp-seismograph"); 34 | graph.seisData = [ 35 | sp.seismogram.SeismogramDisplayData.fromSeismogram(seismogram), 36 | ]; 37 | }) 38 | .catch(function (error) { 39 | const pre = document 40 | .querySelector("div#myseismograph") 41 | .appendChild(document.createElement("pre")); 42 | pre.textContent = "Error loading data." + error; 43 | console.assert(false, error); 44 | }); 45 | -------------------------------------------------------------------------------- /docs/examples/response/channel_chooser.js: -------------------------------------------------------------------------------- 1 | const ATTR_LIST = ["Network", "Station", "Location", "Channel"]; 2 | 3 | class ChannelCodeInput extends HTMLElement { 4 | constructor() { 5 | super(); 6 | const shadow = this.attachShadow({ mode: "open" }); 7 | const wrapper = document.createElement("span"); 8 | wrapper.setAttribute("class", "wrapper"); 9 | const default_vals = { 10 | Network: "CO", 11 | Station: "CASEE", 12 | Location: "00", 13 | Channel: "HHZ", 14 | }; 15 | let inputs = {}; 16 | for (const x of ATTR_LIST) { 17 | const ndiv = wrapper.appendChild(document.createElement("span")); 18 | const nlabel = ndiv.appendChild(document.createElement("label")); 19 | nlabel.textContent = x; 20 | const ntext = ndiv.appendChild(document.createElement("input")); 21 | ntext.setAttribute("class", x); 22 | ntext.setAttribute("type", "text"); 23 | ntext.setAttribute("name", x); 24 | ntext.setAttribute("value", default_vals[x]); 25 | inputs[x] = ntext; 26 | } 27 | 28 | // Create some CSS to apply to the shadow dom 29 | const style = document.createElement("style"); 30 | 31 | style.textContent = ` 32 | .wrapper { 33 | position: relative; 34 | } 35 | input { 36 | width: 50px; 37 | } 38 | `; 39 | shadow.appendChild(style); 40 | shadow.appendChild(wrapper); 41 | } 42 | attributeChangedCallback(name, oldValue, newValue) {} 43 | static get observedAttributes() { 44 | return ATTR_LIST; 45 | } 46 | get network() { 47 | return this.shadowRoot.querySelector("input.Network").value; 48 | } 49 | get station() { 50 | return this.shadowRoot.querySelector("input.Station").value; 51 | } 52 | get location() { 53 | return this.shadowRoot.querySelector("input.Location").value; 54 | } 55 | get channel() { 56 | return this.shadowRoot.querySelector("input.Channel").value; 57 | } 58 | } 59 | 60 | class ChannelListChooser extends HTMLElement { 61 | constructor() { 62 | super(); 63 | this.channels = []; 64 | const shadow = this.attachShadow({ mode: "open" }); 65 | this.draw_element(shadow); 66 | } 67 | draw_element(shadow) { 68 | const that = this; 69 | while (shadow.firstChild) { 70 | shadow.removeChild(shadow.lastChild); 71 | } 72 | const wrapper = document.createElement("div"); 73 | wrapper.setAttribute("class", "wrapper"); 74 | const label = wrapper.appendChild(document.createElement("label")); 75 | label.textContent = "Channels:"; 76 | this.channels.forEach((c) => { 77 | const div = wrapper.appendChild(document.createElement("div")); 78 | const cb = div.appendChild(document.createElement("input")); 79 | cb.setAttribute("type", "radio"); 80 | cb.setAttribute("name", "radiogroup"); 81 | cb.addEventListener("change", (event) => { 82 | if (that.callback) { 83 | that.callback(c); 84 | } 85 | }); 86 | const nlabel = div.appendChild(document.createElement("label")); 87 | nlabel.textContent = `${c.codes()} ${c.startDate.toISO()}`; 88 | }); 89 | shadow.appendChild(wrapper); 90 | } 91 | setChannels(channels) { 92 | this.channels = channels; 93 | this.draw_element(this.shadowRoot); 94 | } 95 | appendChannels(channels) { 96 | this.channels = this.channels.concat(channels); 97 | this.draw_element(this.shadowRoot); 98 | } 99 | attributeChangedCallback(name, oldValue, newValue) {} 100 | setCallback(callback) { 101 | this.callback = callback; 102 | } 103 | } 104 | 105 | customElements.define("channel-code-input", ChannelCodeInput); 106 | customElements.define("channel-list-chooser", ChannelListChooser); 107 | -------------------------------------------------------------------------------- /docs/examples/response/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
Seisplotjs - Examples - Response
10 | 11 |

Input:

12 |

The sis_filtercascade_15242.xml stationxml file 13 | is an example of a filter cascade from SIS 14 | where the symmetry of the FIR filter was wrong, generating a response that 15 | is not correct. Note the large ripple in the passband. 16 | Choosing a channel from IRIS hopefully shows other 17 | more correct responses. You may also paste a URL to a stationxml, 18 | IRIS stationxml-resp from the NRL, 19 | or SIS extended stationxml file into the box to plot it. 20 |

21 |
22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 | 30 |
31 |
32 | 33 | 34 | 35 |
36 | 37 |
38 | 39 | Phase 40 |
41 |

Response Stage plot

42 |
43 |
44 |
45 |
46 |
47 |

Caveats:

48 |

Not all responses types are plotted currently, including:

49 | 59 | 60 |
Generated with Seisplotjs version 3.
61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/examples/response/response_parse.js: -------------------------------------------------------------------------------- 1 | import * as sp from "../../seisplotjs_3.1.5-SNAPSHOT_standalone.mjs"; 2 | 3 | export const SIS_NS = "http://anss-sis.scsn.org/xml/ext-stationxml/3.0"; 4 | export const STAML_NS = sp.stationxml.STAML_NS; 5 | 6 | /* SIS uses a different style of metadata, based on StationXML, but with 7 | * additions. So a separate parsing is needed to find the response. 8 | */ 9 | export function parse_sis_xml(sisxml) { 10 | const parser = new DOMParser(); 11 | const dom = parser.parseFromString(sisxml, "application/xml"); 12 | const top = sisxml.documentElement; 13 | if (!top) { 14 | throw new Error("No documentElement in XML"); 15 | } 16 | let hard_resp = top.getElementsByTagNameNS(SIS_NS, "HardwareResponse"); 17 | let resp_dict_group = hard_resp[0].getElementsByTagNameNS( 18 | SIS_NS, 19 | "ResponseDictGroup", 20 | ); 21 | let stages = []; 22 | let resp_dict = new Map(); 23 | let rd_array = Array.from( 24 | resp_dict_group[0].getElementsByTagNameNS(SIS_NS, "ResponseDict"), 25 | ); 26 | rd_array.forEach((rdict) => { 27 | const resp_el = rdict.firstElementChild; 28 | let name = resp_el.getAttribute("name"); 29 | if (resp_el.localName === "FIR") { 30 | // add fake Gain 31 | let gain = sisxml.createElementNS(STAML_NS, "StageGain"); 32 | let gval = sisxml.createElementNS(STAML_NS, "Value"); 33 | gval.append(sisxml.createTextNode("1.0")); 34 | gain.append(gval); 35 | let gfreq = sisxml.createElementNS(STAML_NS, "Frequency"); 36 | gfreq.append(sisxml.createTextNode("0.0")); 37 | gain.append(gfreq); 38 | resp_el.append(gain); 39 | let stage = sp.stationxml.convertToStage(rdict); 40 | resp_dict.set(name, stage.filter); 41 | } else if (resp_el.localName === "FilterSequence") { 42 | let s_array = Array.from( 43 | resp_el.getElementsByTagNameNS(SIS_NS, "FilterStage"), 44 | ); 45 | s_array.forEach((fs) => { 46 | let seqNum = fs.getElementsByTagNameNS(SIS_NS, "SequenceNumber")[0] 47 | .textContent; 48 | let sis_filter_ref = fs.getElementsByTagNameNS(SIS_NS, "Filter")[0]; 49 | let fname = sis_filter_ref.getElementsByTagNameNS(SIS_NS, "Name")[0] 50 | .textContent; 51 | 52 | let sis_filter = resp_dict.get(fname); 53 | let decimationXml = fs.getElementsByTagNameNS(SIS_NS, "Decimation"); 54 | let decimation = null; 55 | if (decimationXml.length > 0) { 56 | decimation = sp.stationxml.convertToDecimation(decimationXml[0]); 57 | } 58 | let gainXml = fs.getElementsByTagNameNS(SIS_NS, "Gain"); 59 | let gain = null; 60 | if (gainXml.length > 0) { 61 | gain = sp.stationxml.convertToGain(gainXml[0]); 62 | } else { 63 | throw new Error( 64 | "Did not find Gain in stage number " + seqNum + " " + fname, 65 | ); 66 | } 67 | stages.push(new sp.stationxml.Stage(sis_filter, decimation, gain)); 68 | }); 69 | } 70 | }); 71 | return stages; 72 | } 73 | -------------------------------------------------------------------------------- /docs/examples/response/style.css: -------------------------------------------------------------------------------- 1 | sp-spectra { 2 | height: 300px; 3 | } 4 | 5 | #stationxml_url { 6 | width: 300px; 7 | } 8 | -------------------------------------------------------------------------------- /docs/examples/ringserver/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SCSN Ringserver 7 | 12 | 13 | 14 | 15 |
Seisplotjs - Examples - Ringserver
16 | 17 |

Ringserver Web interface:

18 | 19 |
20 | 21 |
22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 |
30 |
31 | 32 | Packets: 0 33 |
34 |
35 |
36 | 37 |
38 |
39 |

40 |   
41 | 42 |
Generated with Seisplotjs version 3.
43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/examples/ringserver/stream_chooser.js: -------------------------------------------------------------------------------- 1 | class StreamListChooser extends HTMLElement { 2 | constructor() { 3 | super(); 4 | this.streams = []; 5 | const shadow = this.attachShadow({ mode: "open" }); 6 | this.draw_element(shadow); 7 | } 8 | draw_element(shadow) { 9 | const that = this; 10 | while (shadow.firstChild) { 11 | shadow.removeChild(shadow.lastChild); 12 | } 13 | const details = document.createElement("details"); 14 | const wrapper = document.createElement("div"); 15 | wrapper.setAttribute("class", "wrapper"); 16 | const label = wrapper.appendChild(document.createElement("summary")); 17 | label.textContent = "Channels:"; 18 | details.appendChild(label); 19 | details.appendChild(wrapper); 20 | this.streams.forEach((c) => { 21 | const div = wrapper.appendChild(document.createElement("div")); 22 | const cb = div.appendChild(document.createElement("input")); 23 | cb.setAttribute("type", "radio"); 24 | cb.setAttribute("name", "radiogroup"); 25 | cb.addEventListener("change", (event) => { 26 | if (that.callback) { 27 | that.callback(c); 28 | } 29 | }); 30 | const nlabel = div.appendChild(document.createElement("label")); 31 | nlabel.textContent = `${c.key} ${c.calcLatency().toHuman()}`; 32 | }); 33 | shadow.appendChild(details); 34 | } 35 | setStreamStats(streams) { 36 | this.streams = streams; 37 | this.draw_element(this.shadowRoot); 38 | } 39 | attributeChangedCallback(name, oldValue, newValue) { 40 | console.log("attributes changed."); 41 | } 42 | setCallback(callback) { 43 | this.callback = callback; 44 | } 45 | } 46 | 47 | customElements.define("stream-list-chooser", StreamListChooser); 48 | -------------------------------------------------------------------------------- /docs/examples/style.css: -------------------------------------------------------------------------------- 1 | .sp_version { 2 | float: right; 3 | font-size: small; 4 | } 5 | -------------------------------------------------------------------------------- /docs/flavicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crotwell/seisplotjs/203bc8e9516b68afadf2aa12c40b8a1177489469/docs/flavicon.png -------------------------------------------------------------------------------- /docs/flavicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 39 | 41 | 45 | S 57 | P 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/gallery/channelchooser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Channel Choosers 8 | 9 | 10 |
11 | Seisplotjs - 12 | Gallery 13 | 3.1.5-SNAPSHOT 14 |
15 | 16 |
<sp-channel-code-input>
17 |
18 | 20 |
21 |
<sp-channel-list>
22 |
23 |
24 |
Output:
25 |

26 |
27 | 28 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /docs/gallery/channelsearch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Channel Search 6 | 7 | 8 | 14 | 15 | 16 |
17 | Seisplotjs - 18 | Gallery 19 | 3.1.5-SNAPSHOT 20 |
21 | 22 |
23 |

24 |
25 |

Channel query:

26 | 27 | 36 | 37 | 38 | 39 |
40 |

41 |
42 | 43 |
44 | 45 |
46 | Generated with 47 | Seisplotjs version 3. 50 |
51 | 52 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /docs/gallery/colors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Seismograph 8 | 23 | 24 | 25 |
26 | Seisplotjs - 27 | Gallery 28 | 3.1.5-SNAPSHOT 29 |
30 | 31 |

Default Colors:

32 |

The default color list for seismograph, etc.

33 |
34 | 35 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/gallery/dataset.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crotwell/seisplotjs/203bc8e9516b68afadf2aa12c40b8a1177489469/docs/gallery/dataset.zip -------------------------------------------------------------------------------- /docs/gallery/datetime.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Date and Time Choosers 8 | 9 | 10 |
11 | Seisplotjs - 12 | Gallery 13 | 3.1.5-SNAPSHOT 14 |
15 | 16 |

Dates and Times:

17 |
18 |
<sp-hourmin>
19 | 20 |
21 |
22 |
<sp-datetime>
23 | 24 |
25 |
26 |
<sp-timerange>
27 | 28 |
29 |
30 | 31 |
<sp-timerange prev-next="true">
32 | 33 |
34 |
35 |
Output:
36 |

37 |
38 | 39 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /docs/gallery/earthquakesearch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Earthquake Search 6 | 7 | 8 | 9 | 10 |
11 | Seisplotjs - 12 | Gallery 13 | 3.1.5-SNAPSHOT 14 |
15 | 16 |
17 |

18 |
19 |

Earthquake query:

20 | 21 | 35 | 36 | 37 |
38 |

39 |
40 | 41 |
42 | 43 |
44 | Generated with 45 | Seisplotjs version 3. 48 |
49 | 50 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /docs/gallery/helicorder.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Helicorder 8 | 15 | 16 | 17 |
18 | Seisplotjs - 19 | Gallery 20 | 3.1.5-SNAPSHOT 21 |
22 | 23 |

Helicorder:

24 |
<sp-helicorder>
25 |
26 | 27 |
28 | 29 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/gallery/infotable.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Info Table 8 | 18 | 19 | 20 |
21 | Seisplotjs - 22 | Gallery 23 | 3.1.5-SNAPSHOT 24 |
25 | 26 |

Earthquake Table:

27 |
<sp-quake-table>
28 |
29 | 30 |
31 | 32 |

Station Table:

33 |
<sp-station-table>
34 |
35 | 36 |
37 | 38 |

Channel Table:

39 |
<sp-channel-table>
40 |
41 | 42 |
43 | 44 |

Seismogram Table:

45 |
<sp-seismogram-table>
46 |
47 | 48 |
49 | 50 |

Station-Event Table:

51 |
52 |
<sp-station-quake-table>
53 | 54 |
55 | 56 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /docs/gallery/latlon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Lat Lon Choosers 8 | 9 | 10 |
11 | Seisplotjs - 12 | Gallery 13 | 3.1.5-SNAPSHOT 14 |
15 | 16 |

Lat Lon:

17 |
18 |
Box:
19 |
<sp-latlon-box>
20 | 26 |
27 |
28 |
Radius:
29 |
<sp-latlon-radius>
30 | 31 |
32 |
33 |
Choice:
34 |
<sp-latlon-choice>
35 | 36 |
37 |
38 |
Output:
39 |

40 |
41 | 42 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/gallery/minmaxinput.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Min-max input 8 | 9 | 10 |
11 | Seisplotjs - 12 | Gallery 13 | 3.1.5-SNAPSHOT 14 |
15 | 16 |

Min Max:

17 |
<sp-minmax>
18 | 19 |
20 | 22 |
23 |
24 |
Output:
25 |

26 |
27 | 28 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/gallery/organizeddisplay.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Organized Display 8 | 17 | 18 | 19 |
20 | Seisplotjs - 21 | Gallery 22 | 3.1.5-SNAPSHOT 23 |
24 | 25 |

Organized Display:

26 |
<sp-organized-display>
27 |
28 | 35 |
36 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/gallery/particlemotion.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Particle Motion 8 | 15 | 16 | 17 |
18 | Seisplotjs - 19 | Gallery 20 | 3.1.5-SNAPSHOT 21 |
22 |
<sp-particle-motion>
23 | 24 |

Particle Motion:

25 |
26 | 27 | 28 | 29 |
30 | 31 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /docs/gallery/seisconfigeditor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Seismograph Config Editor 8 | 15 | 16 | 17 |
18 | Seisplotjs - 19 | Gallery 20 | 3.1.5-SNAPSHOT 21 |
22 | 23 |

Seismograph Config Editor:

24 |
25 | 26 | 27 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/gallery/seismograph.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Seismograph 8 | 13 | 14 | 15 |
16 | Seisplotjs - 17 | Gallery 18 | 3.1.5-SNAPSHOT 19 |
20 |
<sp-seismograph>
21 |
22 | Mouse Time: time Click: 23 | time 24 |
25 |

Seismograph:

26 |
27 | 28 | 29 | 30 |
31 | 32 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /docs/gallery/spectra.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Spectra 8 | 13 | 14 | 15 |
16 | Seisplotjs - 17 | Gallery 18 | 3.1.5-SNAPSHOT 19 |
20 |
<sp-spectra>
21 | 22 |

Spectra:

23 |

Amplitude:

24 | 25 | 26 |

Phase:

27 | 28 | 29 | 30 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /docs/gallery/style.css: -------------------------------------------------------------------------------- 1 | .sp_version { 2 | float: right; 3 | font-size: small; 4 | } 5 | -------------------------------------------------------------------------------- /docs/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.17.1 2 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript&plugins=normalize-whitespace */ 3 | /** 4 | * prism.js default theme for JavaScript, CSS and HTML 5 | * Based on dabblet (http://dabblet.com) 6 | * @author Lea Verou 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: black; 12 | background: none; 13 | text-shadow: 0 1px white; 14 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 15 | font-size: 1em; 16 | text-align: left; 17 | white-space: pre; 18 | word-spacing: normal; 19 | word-break: normal; 20 | word-wrap: normal; 21 | line-height: 1.5; 22 | 23 | -moz-tab-size: 4; 24 | -o-tab-size: 4; 25 | tab-size: 4; 26 | 27 | -webkit-hyphens: none; 28 | -moz-hyphens: none; 29 | -ms-hyphens: none; 30 | hyphens: none; 31 | } 32 | 33 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 34 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 35 | text-shadow: none; 36 | background: #b3d4fc; 37 | } 38 | 39 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 40 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 41 | text-shadow: none; 42 | background: #b3d4fc; 43 | } 44 | 45 | @media print { 46 | code[class*="language-"], 47 | pre[class*="language-"] { 48 | text-shadow: none; 49 | } 50 | } 51 | 52 | /* Code blocks */ 53 | pre[class*="language-"] { 54 | padding: 1em; 55 | margin: .5em 0; 56 | overflow: auto; 57 | } 58 | 59 | :not(pre) > code[class*="language-"], 60 | pre[class*="language-"] { 61 | background: #f5f2f0; 62 | } 63 | 64 | /* Inline code */ 65 | :not(pre) > code[class*="language-"] { 66 | padding: .1em; 67 | border-radius: .3em; 68 | white-space: normal; 69 | } 70 | 71 | .token.comment, 72 | .token.prolog, 73 | .token.doctype, 74 | .token.cdata { 75 | color: slategray; 76 | } 77 | 78 | .token.punctuation { 79 | color: #999; 80 | } 81 | 82 | .namespace { 83 | opacity: .7; 84 | } 85 | 86 | .token.property, 87 | .token.tag, 88 | .token.boolean, 89 | .token.number, 90 | .token.constant, 91 | .token.symbol, 92 | .token.deleted { 93 | color: #905; 94 | } 95 | 96 | .token.selector, 97 | .token.attr-name, 98 | .token.string, 99 | .token.char, 100 | .token.builtin, 101 | .token.inserted { 102 | color: #690; 103 | } 104 | 105 | .token.operator, 106 | .token.entity, 107 | .token.url, 108 | .language-css .token.string, 109 | .style .token.string { 110 | color: #9a6e3a; 111 | background: hsla(0, 0%, 100%, .5); 112 | } 113 | 114 | .token.atrule, 115 | .token.attr-value, 116 | .token.keyword { 117 | color: #07a; 118 | } 119 | 120 | .token.function, 121 | .token.class-name { 122 | color: #DD4A68; 123 | } 124 | 125 | .token.regex, 126 | .token.important, 127 | .token.variable { 128 | color: #e90; 129 | } 130 | 131 | .token.important, 132 | .token.bold { 133 | font-weight: bold; 134 | } 135 | .token.italic { 136 | font-style: italic; 137 | } 138 | 139 | .token.entity { 140 | cursor: help; 141 | } 142 | 143 | -------------------------------------------------------------------------------- /docs/split.css: -------------------------------------------------------------------------------- 1 | .gutter { 2 | background-color: #f5f5f5; 3 | background-repeat: no-repeat; 4 | background-position: 50%; 5 | } 6 | 7 | .gutter.gutter-vertical { 8 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII='); 9 | cursor: ns-resize; 10 | } 11 | 12 | .gutter.gutter-horizontal { 13 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=='); 14 | cursor: ew-resize; 15 | } 16 | -------------------------------------------------------------------------------- /docs/tutorial/style.css: -------------------------------------------------------------------------------- 1 | li.sub { 2 | margin-left: 1em; 3 | } 4 | 5 | .sp_version { 6 | float: right; 7 | font-size: small; 8 | } 9 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial 1: Sine Wave 6 | 7 | 13 | 14 | 15 | 16 |

Tutorial 1: Sine Wave 3.1.5-SNAPSHOT

17 |

A Seismograph!

18 | 19 |

Another Seismograph!

20 |
21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial1.js: -------------------------------------------------------------------------------- 1 | // snip start createseis 2 | import * as sp from "../seisplotjs_3.1.5-SNAPSHOT_standalone.mjs"; 3 | sp.util.updateVersionText(".sp_version"); 4 | 5 | let sampleRate = 20; 6 | const sinePeriod = 5 * sampleRate; // 5 second period 7 | const amp = 100; // 100 count amplitude 8 | let dataArray = new Float32Array(10 * sinePeriod).map(function (d, i) { 9 | return Math.sin((2 * Math.PI * i) / sinePeriod) * amp; 10 | }); 11 | let start = sp.util.isoToDateTime("2019-07-04T05:46:23"); 12 | let myseismogram = sp.seismogram.Seismogram.fromContiguousData( 13 | dataArray, 14 | sampleRate, 15 | start, 16 | ); 17 | // snip start draw 18 | let seisData = sp.seismogram.SeismogramDisplayData.fromSeismogram(myseismogram); 19 | const graph = document.querySelector("sp-seismograph"); 20 | graph.seismographConfig.title = "A sine wave!"; 21 | graph.seismographConfig.margin.top = 25; 22 | graph.seisData = [seisData]; 23 | // snip start divdraw 24 | const div = document.querySelector("div#sinewave"); 25 | const seisConfig = new sp.seismographconfig.SeismographConfig(); 26 | seisConfig.title = "Another sine wave!"; 27 | seisConfig.margin.top = 25; 28 | const div_graph = new sp.seismograph.Seismograph([seisData], seisConfig); 29 | div.appendChild(div_graph); 30 | // snip start timescale 31 | graph.seismographConfig.linkedTimeScale.link(div_graph); 32 | // snip end 33 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial 2: Real Data 6 | 7 | 12 | 13 | 14 | 15 |

Tutorial 2: Real Data 3.1.5-SNAPSHOT

16 |

A Seismograph!

17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial2.js: -------------------------------------------------------------------------------- 1 | // snip start querystation 2 | import * as sp from "../seisplotjs_3.1.5-SNAPSHOT_standalone.mjs"; 3 | sp.util.updateVersionText(".sp_version"); 4 | 5 | let timeWindow = sp.util.startDuration("2019-07-06T03:19:53Z", 1800); 6 | let dsQuery = new sp.fdsndataselect.DataSelectQuery(); 7 | dsQuery 8 | .networkCode("CO") 9 | .stationCode("HODGE") 10 | .locationCode("00") 11 | .channelCode("LH?") 12 | .timeRange(timeWindow); 13 | // snip start queryseis 14 | dsQuery 15 | .querySeismograms() 16 | .then((seisArray) => { 17 | const div = document.querySelector("div#myseismograph"); 18 | let seisConfig = new sp.seismographconfig.SeismographConfig(); 19 | let seisData = []; 20 | for (let s of seisArray) { 21 | seisData.push(sp.seismogram.SeismogramDisplayData.fromSeismogram(s)); 22 | } 23 | let graph = new sp.seismograph.Seismograph(seisData, seisConfig); 24 | div.appendChild(graph); 25 | }) 26 | .catch(function (error) { 27 | const div = document.querySelector("div#myseismograph"); 28 | div.innerHTML = ` 29 |

Error loading data. ${error}

30 | `; 31 | console.assert(false, error); 32 | }); 33 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial 3: Quakes and Channels 6 | 7 | 16 | 17 | 18 | 19 |

20 | Tutorial 3: Quakes and Channels 21 | 3.1.5-SNAPSHOT 22 |

23 |

Map

24 |
25 | 33 | 34 |
35 |

36 | A Seismograph recorded at for the 37 | earthquake! 38 |

39 |
40 | 41 |
42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial3.js: -------------------------------------------------------------------------------- 1 | // snip start map 2 | import * as sp from "../seisplotjs_3.1.5-SNAPSHOT_standalone.mjs"; 3 | sp.util.updateVersionText(".sp_version"); 4 | 5 | // snip start mapcss 6 | const mymap = document.querySelector("sp-station-quake-map"); 7 | 8 | mymap.addStyle(` 9 | div.stationMapMarker { 10 | color: rebeccapurple; 11 | } 12 | path.quakeMapMarker { 13 | fill: orange; 14 | stroke: yellow; 15 | fill-opacity: 0.25; 16 | } 17 | `); 18 | 19 | // snip start quakechan 20 | let queryTimeWindow = sp.util.startEnd("2019-07-01", "2019-07-31"); 21 | let eventQuery = new sp.fdsnevent.EventQuery() 22 | .timeRange(queryTimeWindow) 23 | .minMag(7) 24 | .latitude(35) 25 | .longitude(-118) 26 | .maxRadius(3); 27 | let stationQuery = new sp.fdsnstation.StationQuery() 28 | .networkCode("CO") 29 | .stationCode("HODGE") 30 | .locationCode("00") 31 | .channelCode("LH?") 32 | .timeRange(queryTimeWindow); 33 | // snip start promise 34 | let stationsPromise = stationQuery.queryChannels(); 35 | let quakePromise = eventQuery.query(); 36 | // snip start seismogramload 37 | Promise.all([quakePromise, stationsPromise]) 38 | .then(([quakeList, networkList]) => { 39 | document.querySelector("span#stationCode").textContent = 40 | networkList[0].stations[0].codes(); 41 | document.querySelector("span#earthquakeDescription").textContent = 42 | quakeList[0].description; 43 | let seismogramDataList = []; 44 | for (const q of quakeList) { 45 | const timeWindow = sp.util.startDuration(q.time, 2400); 46 | for (const c of sp.stationxml.allChannels(networkList)) { 47 | let sdd = sp.seismogram.SeismogramDisplayData.fromChannelAndTimeWindow( 48 | c, 49 | timeWindow, 50 | ); 51 | sdd.addQuake(q); 52 | seismogramDataList.push(sdd); 53 | } 54 | } 55 | mymap.seisData = seismogramDataList; 56 | let dsQuery = new sp.fdsndataselect.DataSelectQuery(); 57 | return dsQuery.postQuerySeismograms(seismogramDataList); 58 | // snip start seismogramplot 59 | }) 60 | .then((seismogramDataList) => { 61 | seismogramDataList.forEach((sdd) => { 62 | sdd.seismogram = sp.filter.rMean(sdd.seismogram); 63 | }); 64 | let graph = document.querySelector("sp-seismograph"); 65 | 66 | let seisConfigGain = new sp.seismographconfig.SeismographConfig(); 67 | seisConfigGain.doGain = true; 68 | seisConfigGain.amplitudeMode = "mean"; 69 | graph.seismographConfig = seisConfigGain; 70 | graph.seisData = seismogramDataList; 71 | }) 72 | .catch(function (error) { 73 | const div = document.querySelector("div#myseismograph"); 74 | div.innerHTML = ` 75 |

Error loading data. ${error}

76 | `; 77 | console.assert(false, error); 78 | }); 79 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial 4: Arrival Times 6 | 7 | 24 | 25 | 26 | 27 |

28 | Tutorial 4: Arrival Times 3.1.5-SNAPSHOT 29 |

30 |
31 | 37 | 38 |
39 |

40 | A Seismograph recorded at for the 41 | earthquake! 42 |

43 |
44 |
45 |
46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial 5: Filtering 6 | 7 | 15 | 16 | 17 | 18 |

19 | Tutorial 5: Filtering, Deconvolution and FFT 20 | 3.1.5-SNAPSHOT 21 |

22 |

23 | A Seismograph recorded at for the 24 | ! 25 |

26 |
27 |
28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial5.js: -------------------------------------------------------------------------------- 1 | import * as sp from "../seisplotjs_3.1.5-SNAPSHOT_standalone.mjs"; 2 | sp.util.updateVersionText(".sp_version"); 3 | 4 | // snip start eventandstation 5 | let queryTimeWindow = sp.util.startEnd("2019-07-01", "2019-07-31"); 6 | let eventQuery = new sp.fdsnevent.EventQuery() 7 | .timeRange(queryTimeWindow) 8 | .minMag(7) 9 | .latitude(35) 10 | .longitude(-118) 11 | .maxRadius(3); 12 | let stationQuery = new sp.fdsnstation.StationQuery() 13 | .networkCode("CO") 14 | .stationCode("HODGE") 15 | .locationCode("00") 16 | .channelCode("HH?") 17 | .timeRange(queryTimeWindow); 18 | // snip start loaderinit 19 | let loader = new sp.seismogramloader.SeismogramLoader(stationQuery, eventQuery); 20 | loader.startOffset = -30; 21 | loader.endOffset = 270; 22 | loader.markedPhaseList = "origin,PP,pP"; 23 | loader.withResponse = true; 24 | loader 25 | .load() 26 | .then((dataset) => { 27 | // snip start map 28 | let staText = ""; 29 | for (let s of sp.stationxml.allStations(dataset.inventory)) { 30 | staText += s.codes(); 31 | } 32 | document.querySelector("span#stationCode").textContent = staText; 33 | 34 | let quakeText = ""; 35 | for (const q of dataset.catalog) { 36 | quakeText += q.description + " "; 37 | } 38 | document.querySelector("span#earthquakeDescription").textContent = 39 | quakeText; 40 | 41 | // snip start filter 42 | dataset.processedWaveforms = dataset.waveforms.map((sdd) => { 43 | let butterworth = sp.filter.createButterworth( 44 | 2, // poles 45 | sp.filter.BAND_PASS, 46 | 0.5, // low corner 47 | 10, // high corner 48 | 1 / sdd.seismogram.sampleRate, // delta (period) 49 | ); 50 | let rmeanSeis = sp.filter.rMean(sdd.seismogram); 51 | let filteredSeis = sp.filter.applyFilter(butterworth, rmeanSeis); 52 | let taperSeis = sp.taper.taper(filteredSeis); 53 | let correctedSeis = sp.transfer.transfer( 54 | taperSeis, 55 | sdd.channel.response, 56 | 0.001, 57 | 0.02, 58 | 250, 59 | 500, 60 | ); 61 | sdd.seismogram = correctedSeis; 62 | return sdd; 63 | }); 64 | // snip start seisconfig 65 | let div = document.querySelector("div#myseismograph"); 66 | let seisConfig = new sp.seismographconfig.SeismographConfig(); 67 | seisConfig.linkedTimeScale = new sp.scale.LinkedTimeScale(); 68 | seisConfig.linkedAmplitudeScale = new sp.scale.LinkedAmplitudeScale(); 69 | seisConfig.wheelZoom = false; 70 | // snip start gain 71 | seisConfig.doGain = false; 72 | for (let sdd of dataset.processedWaveforms) { 73 | let graph = new sp.seismograph.Seismograph([sdd], seisConfig); 74 | div.appendChild(graph); 75 | } 76 | // snip start fft 77 | let fftList = dataset.processedWaveforms 78 | .map((sdd) => { 79 | if (sdd.seismogram.isContiguous()) { 80 | return sp.fft.fftForward(sdd.seismogram); 81 | } else { 82 | return null; // can't do fft for non-contiguouus 83 | } 84 | }) 85 | .filter((x) => x); // to remove nulls 86 | let fftSeisConfig = new sp.seismographconfig.SeismographConfig(); 87 | let fftPlot = new sp.spectraplot.SpectraPlot(fftList, fftSeisConfig); 88 | document.querySelector("div#fftplot").appendChild(fftPlot); 89 | return dataset; 90 | }) 91 | .catch(function (error) { 92 | const div = document.querySelector("div#myseismograph"); 93 | div.innerHTML = `

Error loading data. ${error}

`; 94 | console.assert(false, error); 95 | }); 96 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial 6: Helicorder 6 | 7 | 8 | 9 | 10 |

11 | Tutorial 6: Helicorder 3.1.5-SNAPSHOT 12 |

13 |

A Helicorder for !

14 |
From to
15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial6.js: -------------------------------------------------------------------------------- 1 | import * as sp from "../seisplotjs_3.1.5-SNAPSHOT_standalone.mjs"; 2 | sp.util.updateVersionText(".sp_version"); 3 | 4 | // snip start window 5 | const plotEnd = sp.luxon.DateTime.utc().endOf("hour").plus({ milliseconds: 1 }); 6 | if (plotEnd.hour % 2 === 1) { 7 | plotEnd.plus({ hours: 1 }); 8 | } 9 | const oneDay = sp.luxon.Duration.fromISO("P1D"); 10 | const timeWindow = sp.util.durationEnd(oneDay, plotEnd); 11 | const luxOpts = { 12 | suppressMilliseconds: true, 13 | suppressSeconds: true, 14 | }; 15 | document.querySelector("span#starttime").textContent = 16 | timeWindow.start.toISO(luxOpts); 17 | document.querySelector("span#endtime").textContent = 18 | timeWindow.end.toISO(luxOpts); 19 | new sp.fdsndatacenters.DataCentersQuery() 20 | .findFdsnDataSelect("IRISDMC") 21 | // snip start seismogram 22 | .then((dataSelectArray) => { 23 | return dataSelectArray[0] 24 | .networkCode("CO") 25 | .stationCode("JSC") 26 | .locationCode("00") 27 | .channelCode("LHZ") 28 | .timeRange(timeWindow) 29 | .querySeismograms(); 30 | // snip start heli 31 | }) 32 | .then((seisArray) => { 33 | document.querySelector("span#channel").textContent = seisArray[0].codes(); 34 | let heliConfig = new sp.helicorder.HelicorderConfig(timeWindow); 35 | 36 | heliConfig.title = `Helicorder for ${seisArray[0].codes()}`; 37 | let seisData = sp.seismogram.SeismogramDisplayData.fromSeismogram( 38 | seisArray[0], 39 | ); 40 | seisData.addMarkers([ 41 | { markertype: "predicted", name: "now", time: sp.luxon.DateTime.utc() }, 42 | ]); 43 | let helicorder = new sp.helicorder.Helicorder(seisData, heliConfig); 44 | document.querySelector("div#helicorder").append(helicorder); 45 | helicorder.draw(); 46 | }) 47 | .catch(function (error) { 48 | const p = document.createElement("p"); 49 | document.querySelector("div#helicorder").appendChild(p); 50 | p.textContent = "Error loading data." + error; 51 | console.assert(false, error); 52 | }); 53 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial 7: Realtime 6 | 7 | 8 | 9 | 10 | 11 |

Tutorial 7: Realtime 3.1.5-SNAPSHOT

12 |

Realtime display for

13 |
14 | 15 | 16 | Packets: 0 17 |
18 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial7_sl4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tutorial 7: Realtime 6 | 7 | 12 | 13 | 14 | 15 |

Tutorial 7: Realtime 3.1.5-SNAPSHOT

16 |

Realtime display for

17 | 18 | 19 | 20 | Packets: 0 21 |
22 | 23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/tutorial/tutorial_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | seisplotjs 2.0 Tutorial, p000000000 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 | 56 |
57 |
58 |
59 |
60 |
61 |
62 |

63 | Seisplotjs Tutorial 3.1.5-SNAPSHOT 64 |

65 | 66 |

TEMPLATE

67 |
See it live in tutorial2.html.
68 | 69 |

blaa blaa blaa

70 |

71 |             let code = "here";
72 |           
73 | 74 |

See it live in tutorial2.html.

75 |

76 | Previous: Let's get some real data 77 |

78 |

Next: Let's get some real data

79 |
80 |
81 |
82 |
83 | 84 | 85 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /global.d.ts: -------------------------------------------------------------------------------- 1 | import 'jest-extended'; 2 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | export default { 3 | preset: "ts-jest", 4 | testEnvironment: "jsdom", 5 | setupFilesAfterEnv: ["/jest.setup.ts", "jest-expect-message"], 6 | transform: { 7 | "^.+\\.ts?$": "ts-jest", 8 | }, 9 | moduleNameMapper: { 10 | "^d3-(.*)$": `/node_modules/d3-$1/dist/d3-$1.min.js`, 11 | }, 12 | reporters: ["default", "jest-html-reporters"], 13 | }; 14 | -------------------------------------------------------------------------------- /jest.setup.ts: -------------------------------------------------------------------------------- 1 | 2 | import "jest-extended/all"; 3 | import ResizeObserver from 'resize-observer-polyfill'; 4 | global.ResizeObserver = ResizeObserver 5 | -------------------------------------------------------------------------------- /jest_remote.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | export default { 3 | testMatch: ["/testremotes/**/*_livetest.ts"], 4 | preset: "ts-jest", 5 | testEnvironment: "jsdom", 6 | setupFilesAfterEnv: ["/jest.setup.ts", "jest-expect-message"], 7 | transform: { 8 | "^.+\\.ts?$": "ts-jest", 9 | }, 10 | moduleNameMapper: { 11 | "^d3-(.*)$": `/node_modules/d3-$1/dist/d3-$1.min.js`, 12 | }, 13 | reporters: ["default", "jest-html-reporters"], 14 | }; 15 | -------------------------------------------------------------------------------- /replaceInHtml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os.path 4 | 5 | replaceItems = { 6 | "

seisplotjs.":"

seisplotjs.", 7 | "https://git@github.com/:crotwell": "https://github.com/crotwell" 8 | } 9 | 10 | for dirpath, dirs, files in os.walk('docs/api'): 11 | for filename in files: 12 | if filename.endswith('.html') and filename != "index.html": 13 | # Read in the file 14 | filepath = os.path.join(dirpath, filename) 15 | with open(filepath, 'r') as file : 16 | filedata = file.read() 17 | 18 | # Replace the target string 19 | for k, v in replaceItems.items(): 20 | filedata = filedata.replace(k, v) 21 | 22 | # Write the file out again 23 | with open(filepath, 'w') as file: 24 | file.write(filedata) 25 | -------------------------------------------------------------------------------- /replaceVersion.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | from pathlib import Path 5 | import json 6 | 7 | with Path("package.json").open() as infile: 8 | npmPackage = json.load(infile) 9 | 10 | 11 | old="3.1.4" 12 | ver=npmPackage["version"] 13 | print(f"Update {old} to {ver}") 14 | 15 | replaceItems = { 16 | f"seisplotjs_{old}_standalone.mjs": f"seisplotjs_{ver}_standalone.mjs", 17 | "seisplotjs 3.0": f"seisplotjs 3.1", 18 | "Seisplotjs 3.0": f"Seisplotjs 3.1", 19 | old: ver, 20 | } 21 | 22 | def replaceInFile(dirpath, filename): 23 | # Read in the file 24 | filepath = Path(dirpath, filename) 25 | try: 26 | with open(filepath, 'r') as file : 27 | filedata = file.read() 28 | except: 29 | return 30 | 31 | changed = False 32 | # Replace the target string 33 | for k, v in replaceItems.items(): 34 | if k in filedata: 35 | changed = True 36 | filedata = filedata.replace(k, v) 37 | 38 | # Write the file out again 39 | if changed: 40 | with open(filepath, 'w') as file: 41 | file.write(filedata) 42 | print(f"Update {dirpath}/{filename}") 43 | 44 | stuffToChange = ['docs/tutorial/*.html', 'docs/tutorial/*.js', 45 | 'docs/examples', 'docs/index.html', 46 | 'docs/gallery/*.html','docs/api/*.html', 47 | 'src', 'test', 'testremotes', 'createApiDocs.sh' 48 | 'VERSION'] 49 | for stuff in stuffToChange: 50 | for toppath in Path('.').glob(stuff): 51 | if toppath.is_dir(): 52 | for dirpath, dirs, files in os.walk(toppath): 53 | for filename in files: 54 | if (filename.endswith('.html') or filename.endswith('.ts') or filename.endswith('.js')): 55 | print(f"{dirpath}/{filename}") 56 | replaceInFile(dirpath, filename) 57 | else: 58 | print(f"{toppath}") 59 | replaceInFile(".", toppath) 60 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import * as pkg from "./package.json"; 2 | import babel from '@rollup/plugin-babel'; 3 | import json from '@rollup/plugin-json'; 4 | import ts from "rollup-plugin-ts"; 5 | 6 | export default [{ 7 | input: 'src/index.ts', 8 | //preserveModules: true, 9 | output: [ 10 | { 11 | dir: "dist/module", 12 | //file: pkg.module, 13 | format: 'es', 14 | sourcemap: true, 15 | } 16 | ], 17 | external: [ 18 | ...Object.keys(pkg.dependencies || {}), 19 | ...Object.keys(pkg.peerDependencies || {}), 20 | '@babel/runtime/helpers/classCallCheck', 21 | '@babel/runtime/helpers/createClass', 22 | '@babel/runtime/helpers/typeof', 23 | '@babel/runtime/helpers/possibleConstructorReturn', 24 | '@babel/runtime/helpers/getPrototypeOf', 25 | '@babel/runtime/helpers/inherits', 26 | '@babel/runtime/helpers/slicedToArray', 27 | '@babel/runtime/helpers/wrapNativeSuper', 28 | '@babel/runtime/regenerator', 29 | ], 30 | plugins: [ 31 | ts(), 32 | json(), 33 | babel({ 34 | exclude: 'node_modules/**', 35 | babelHelpers: 'runtime', 36 | }) 37 | ] 38 | } 39 | ]; 40 | -------------------------------------------------------------------------------- /src/areautil.ts: -------------------------------------------------------------------------------- 1 | export interface Location { 2 | latitude: number; 3 | longitude: number; 4 | } 5 | 6 | export function inArea(bounds: Array, point: Location): boolean { 7 | let lonA: number; 8 | let latA: number; 9 | let lonB: number; 10 | let latB: number; 11 | let inside = 0; 12 | for (let i = 0; i < bounds.length; i++) { 13 | lonA = bounds[i].longitude - point.longitude; 14 | latA = bounds[i].latitude - point.latitude; 15 | lonB = bounds[(i + 1) % bounds.length].longitude - point.longitude; 16 | latB = bounds[(i + 1) % bounds.length].latitude - point.latitude; 17 | const check = polygonPointCheck(lonA, latA, lonB, latB); 18 | if (check === 4) { 19 | return true; 20 | } 21 | inside += check; 22 | } 23 | return inside !== 0; 24 | } 25 | 26 | export function polygonPointCheck( 27 | lonA: number, 28 | latA: number, 29 | lonB: number, 30 | latB: number, 31 | ): number { 32 | if (latA * latB > 0) { 33 | return 0; 34 | } 35 | if (lonA * latB !== lonB * latA || lonA * lonB > 0) { 36 | if (latA * latB < 0) { 37 | if (latA > 0) { 38 | if (latA * lonB >= lonA * latB) { 39 | return 0; 40 | } 41 | return -2; 42 | } 43 | if (lonA * latB >= latA * lonB) { 44 | return 0; 45 | } 46 | return 2; 47 | } 48 | if (latB === 0) { 49 | if (latA === 0) { 50 | return 0; 51 | } else if (lonB > 0) { 52 | return 0; 53 | } else if (latA > 0) { 54 | return -1; 55 | } 56 | return 1; 57 | } else if (lonA > 0) { 58 | return 0; 59 | } else if (latB > 0) { 60 | return 1; 61 | } 62 | return -1; 63 | } 64 | return 4; 65 | } 66 | -------------------------------------------------------------------------------- /src/cssutil.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Philip Crotwell 3 | * University of South Carolina, 2019 4 | * https://www.seis.sc.edu 5 | */ 6 | export const AUTO_CLASSED = "autoseisplotjs"; 7 | export const AUTO_COLOR_SELECTOR = "seisplotjsautocolor"; 8 | export const G_DATA_SELECTOR = "seisplotjsdata"; 9 | 10 | /** 11 | * Inserts text as css into the head of an html document. No checking 12 | * as to validity of the css is done, just inserts a style 13 | * element at the beginning of the head. 14 | * 15 | * @param cssText textual css for insertion 16 | * @param id optional id for style element 17 | * @returns the style html element inserted 18 | */ 19 | export function insertCSS(cssText: string, id: string): HTMLElement { 20 | const head = document.head; 21 | 22 | if (head === null) { 23 | throw new Error("document.head is null"); 24 | } 25 | 26 | if (id) { 27 | for (const c of Array.from(head.children)) { 28 | // only remove if a