├── .babelrc ├── .eslintrc ├── .github └── ISSUE_TEMPLATE │ ├── --bug-report.md │ ├── --feature-request.md │ └── -question.md ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGES.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── asset-manifest.json ├── favicon.ico ├── index.html ├── precache-manifest.af72a8770d7e1a73c3d4d9e8b7bdb457.js ├── service-worker.js └── static │ ├── css │ ├── 1.f8d9c008.chunk.css │ ├── 1.f8d9c008.chunk.css.map │ ├── main.dd59e73f.chunk.css │ └── main.dd59e73f.chunk.css.map │ ├── js │ ├── 1.adebdc21.chunk.js │ ├── 1.adebdc21.chunk.js.map │ ├── main.f4675af6.chunk.js │ ├── main.f4675af6.chunk.js.map │ ├── runtime~main.171b61a2.js │ └── runtime~main.171b61a2.js.map │ └── media │ ├── 1_introduction.4b96f9a1.md │ ├── 2_getting_started.906a806a.md │ ├── 3_styling.22c4a365.md │ ├── 4_annotations.7e00e29b.md │ ├── barchart_docs.c7b1c427.md │ ├── baselines_docs.af746eac.md │ ├── baselines_thumbnail.ab4808c9.png │ ├── climate_docs.c7298675.md │ ├── continents_docs.219ed683.md │ ├── continents_thumbnail.398a3ca9.png │ ├── currency_docs.eacba985.md │ ├── currency_thumbnail.b569b92b.png │ ├── cycling_docs.0abc2bf7.md │ ├── cycling_thumbnail.7e08437f.png │ ├── ddos_docs.ef0eb60c.md │ ├── ddos_thumbnail.7d2af225.png │ ├── logo.9f83357c.png │ ├── logo.fe7ba602.png │ ├── nyc_docs.a559ddde.md │ ├── nyc_thumbnail.72af0cc8.png │ ├── outages_docs.71f0cb04.md │ ├── outages_thumbnail.d50e76c7.png │ ├── realtime_docs.e85adf2e.md │ ├── realtime_thumbnail.033c51ee.png │ ├── stockchart_docs.d41d8cd9.md │ ├── stockchart_thumbnail.2974a0cb.png │ ├── traffic_docs.eef1502a.md │ ├── traffic_thumbnail.3a9ee161.png │ ├── trend_docs.7ece7c4f.md │ ├── volume_docs.0abb4165.md │ ├── volume_thumbnail.2104f5f8.png │ ├── weather_docs.1ee86e74.md │ ├── weather_thumbnail.f8d6f622.png │ ├── wind_docs.71db1cf6.md │ └── wind_thumbnail.1936c918.png ├── lib ├── components │ ├── AreaChart.js │ ├── BandChart.js │ ├── BarChart.js │ ├── Baseline.js │ ├── BoxChart.js │ ├── Brush.js │ ├── ChartContainer.js │ ├── ChartRow.js │ ├── Charts.js │ ├── EventChart.js │ ├── EventHandler.js │ ├── EventMarker.js │ ├── Label.js │ ├── LabelAxis.js │ ├── Legend.js │ ├── LineChart.js │ ├── MultiBrush.js │ ├── Resizable.js │ ├── ScatterChart.js │ ├── TimeAxis.js │ ├── TimeMarker.js │ ├── TimeRangeMarker.js │ ├── ValueAxis.js │ ├── ValueList.js │ └── YAxis.js ├── entry.js └── js │ ├── curve.js │ ├── interpolators.js │ ├── styler.js │ └── util.js ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── components │ ├── AreaChart.js │ ├── BandChart.js │ ├── BarChart.js │ ├── Baseline.js │ ├── BoxChart.js │ ├── Brush.js │ ├── ChartContainer.js │ ├── ChartRow.js │ ├── Charts.js │ ├── EventChart.js │ ├── EventHandler.js │ ├── EventMarker.js │ ├── Label.js │ ├── LabelAxis.js │ ├── Legend.js │ ├── LineChart.js │ ├── MultiBrush.js │ ├── Resizable.js │ ├── ScatterChart.js │ ├── TimeAxis.js │ ├── TimeMarker.js │ ├── TimeRangeMarker.js │ ├── ValueAxis.js │ ├── ValueList.js │ └── YAxis.js ├── entry.js ├── index.css ├── index.js ├── js │ ├── curve.js │ ├── interpolators.js │ ├── styler.js │ └── util.js ├── registerServiceWorker.js └── website │ ├── App.css │ ├── App.js │ ├── components │ ├── API.js │ ├── APIDoc.js │ ├── Example.js │ ├── Guide.js │ └── highlighter.js │ ├── img │ ├── github.png │ └── logo.png │ ├── index.css │ └── packages │ └── charts │ ├── api │ └── docs.json │ ├── examples │ ├── barchart │ │ ├── Index.js │ │ ├── barchart_docs.md │ │ └── barchart_thumbnail.png │ ├── baselines │ │ ├── Index.js │ │ ├── baselines_docs.md │ │ ├── baselines_thumbnail.png │ │ ├── usd_vs_aud.json │ │ └── usd_vs_euro.json │ ├── climate │ │ ├── Index.js │ │ ├── Index.png │ │ ├── climate_data.json │ │ ├── climate_docs.md │ │ └── climate_thumbnail.png │ ├── continents │ │ ├── Index.js │ │ ├── continents_docs.md │ │ ├── continents_thumbnail.png │ │ └── stacked.json │ ├── currency │ │ ├── Index.js │ │ ├── currency_docs.md │ │ ├── currency_thumbnail.png │ │ ├── usd_vs_aud.json │ │ └── usd_vs_euro.json │ ├── cycling │ │ ├── Index.js │ │ ├── bike.json │ │ ├── cycling.css │ │ ├── cycling_docs.md │ │ ├── cycling_thumbnail.png │ │ └── latlong.json │ ├── ddos │ │ ├── Index.js │ │ ├── data.json │ │ ├── ddos_docs.md │ │ └── ddos_thumbnail.png │ ├── examples.js │ ├── examples.json │ ├── nyc │ │ ├── Index.js │ │ ├── knyc.csv │ │ ├── knyc.json │ │ ├── nyc_docs.md │ │ └── nyc_thumbnail.png │ ├── outages │ │ ├── Index.js │ │ ├── outages_docs.md │ │ └── outages_thumbnail.png │ ├── realtime │ │ ├── Index.js │ │ ├── realtime_docs.md │ │ └── realtime_thumbnail.png │ ├── stockchart │ │ ├── Index.js │ │ ├── aapl_historical.csv │ │ ├── aapl_historical.json │ │ ├── stockchart_docs.md │ │ └── stockchart_thumbnail.png │ ├── traffic │ │ ├── Index.js │ │ ├── link-traffic.json │ │ ├── traffic_docs.md │ │ └── traffic_thumbnail.png │ ├── trend │ │ ├── Index.js │ │ ├── data.json │ │ ├── trend_docs.md │ │ └── trend_thumbnail.png │ ├── volume │ │ ├── Index.js │ │ ├── interface-traffic.json │ │ ├── total_traffic_6mo.csv │ │ ├── total_traffic_6mo.json │ │ ├── volume_docs.md │ │ └── volume_thumbnail.png │ ├── weather │ │ ├── Index.js │ │ ├── weather.json │ │ ├── weather_docs.md │ │ ├── weather_raw.txt │ │ └── weather_thumbnail.png │ └── wind │ │ ├── Index.js │ │ ├── weather.json │ │ ├── wind_docs.md │ │ └── wind_thumbnail.png │ ├── guides │ ├── 1_introduction.md │ ├── 2_getting_started.md │ ├── 3_styling.md │ ├── 4_annotations.md │ └── guides.js │ └── logo.png ├── yarn.lock └── zooming.gif /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-app", 3 | "rules": { 4 | "import/no-webpack-loader-syntax": "off" 5 | } 6 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41BBug report" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 🐛Bug report 11 | 12 | **Describe the bug** 13 | A clear and concise description of what the bug is. 14 | 15 | **To Reproduce** 16 | Steps to reproduce the behavior: 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Desktop (please complete the following information):** 29 | - OS: [e.g. iOS] 30 | - Browser [e.g. chrome, safari] 31 | - Version [e.g. 22] 32 | 33 | **Smartphone (please complete the following information):** 34 | - Device: [e.g. iPhone6] 35 | - OS: [e.g. iOS8.1] 36 | - Browser [e.g. stock browser, safari] 37 | - Version [e.g. 22] 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F308Feature request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 🌈Feature request 11 | 12 | **What is this feature?** 13 | 14 | **How should the feature work?** 15 | 16 | **Do you have examples or an idea of how it can be implemented?** 17 | 18 | **Additional context** 19 | (Add any other context or screenshots about the feature request here) 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "❔Question" 3 | about: Have any questions? 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # ❔Question 11 | 12 | **Provide your question, code sample Or other information that will help in solving here** 13 | 14 | #### Your Environment 15 | | Software | Name/Version| 16 | | ---------------- | ---------- | 17 | | react-timeseries-charts | 18 | | Browser | 19 | | Operating System | 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | npm-debug.log 5 | build 6 | .idea 7 | /.vscode/ 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | examples/ 3 | screenshots/ 4 | docs/ 5 | bin/ 6 | node_modules/ 7 | build/global 8 | index.html 9 | .eslintrc 10 | .gitignore 11 | CONTRIBUTING.md 12 | examples-bundle.js 13 | examples-bundle.js.map 14 | *.config.js 15 | .DS_Store 16 | npm-debug.log 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "8.10.0" 5 | notifications: 6 | email: false 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute to react-timeseries-charts 2 | 3 | In general we follow the "fork & pull" model as outlined in the 4 | [GitHub docs](https://help.github.com/articles/using-pull-requests/). 5 | 6 | Here are a few additional thoughts on how to make the contribution process as 7 | painless as possible for yourself and for the developers. 8 | 9 | 1. *Communicate.* please create an GitHub issue in the appropriate GitHub 10 | project communicating your plans. This allows coordination -- it's possible 11 | someone else has ideas about this topic and it can save a lot of time if 12 | things are disucssed before you dive in. When you submit your pull request 13 | please include the issue number with the discussion relevant to this pull 14 | request. 15 | 16 | 2. *Work on a branch.* Work on a branch in a fork of the project code. *DO NOT 17 | WORK ON `master` or `develop`.* 18 | 19 | 3. *Follow the style of the code.* All code must follow the style of the 20 | project. We generally adhere to the [Google JavaScript style 21 | guide](https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml). 22 | Please lint your code with a reasonable linting tool. 23 | 24 | 4. *Create examples.* All new features must have appropriate examples in the 25 | examples directory. If you are adding a major feature you may wish to create a 26 | new example page. If you are adding a smaller feature you may just wish to 27 | augment one of the existing examples. 28 | 29 | 5. *Tests.* We currently evaluating how to test this library. In the mean time 30 | please be sure to check that all of the examples continue to work before 31 | submitting your pull request. If you have suggestions on how to build tests 32 | we'd love to hear them. 33 | 34 | The [jQuery guidlines](http://contribute.jquery.org/commits-and-pull-requests/) 35 | have some good suggestions for rectifying common Git mistakes 36 | 37 | Once you have you are ready to share your code go ahead and follow the 38 | instructions in the [GitHub 39 | docs](https://help.github.com/articles/using-pull-requests/) to submit your 40 | pull request. 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | "ESnet React Timeseries Charts, Copyright (c) 2015, The Regents of the 2 | University of California, through Lawrence Berkeley National Laboratory 3 | (subject to receipt of any required approvals from the U.S. Dept. of Energy). 4 | All rights reserved." 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | (1) Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | (2) Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation and/ 14 | or other materials provided with the distribution. 15 | 16 | (3) Neither the name of the University of California, Lawrence Berkeley 17 | National Laboratory, U.S. Dept. of Energy nor the names of its contributors may 18 | be used to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | You are under no obligation whatsoever to provide any bug fixes, patches, or 33 | upgrades to the features, functionality or performance of the source code 34 | ("Enhancements") to anyone; however, if you choose to make your Enhancements 35 | available either publicly, or directly to Lawrence Berkeley National 36 | Laboratory, without imposing a separate written license agreement for such 37 | Enhancements, then you hereby grant the following license: a non-exclusive, 38 | royalty-free perpetual license to install, use, modify, prepare derivative 39 | works, incorporate into other computer software, distribute, and sublicense 40 | such enhancements or derivative works thereof, in binary and source code form. -------------------------------------------------------------------------------- /docs/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.css": "/react-timeseries-charts/static/css/main.dd59e73f.chunk.css", 3 | "main.js": "/react-timeseries-charts/static/js/main.f4675af6.chunk.js", 4 | "main.js.map": "/react-timeseries-charts/static/js/main.f4675af6.chunk.js.map", 5 | "static/css/1.f8d9c008.chunk.css": "/react-timeseries-charts/static/css/1.f8d9c008.chunk.css", 6 | "static/js/1.adebdc21.chunk.js": "/react-timeseries-charts/static/js/1.adebdc21.chunk.js", 7 | "static/js/1.adebdc21.chunk.js.map": "/react-timeseries-charts/static/js/1.adebdc21.chunk.js.map", 8 | "runtime~main.js": "/react-timeseries-charts/static/js/runtime~main.171b61a2.js", 9 | "runtime~main.js.map": "/react-timeseries-charts/static/js/runtime~main.171b61a2.js.map", 10 | "static/media/traffic_thumbnail.png": "/react-timeseries-charts/static/media/traffic_thumbnail.3a9ee161.png", 11 | "static/media/logo.png": "/react-timeseries-charts/static/media/logo.fe7ba602.png", 12 | "static/media/1_introduction.md": "/react-timeseries-charts/static/media/1_introduction.4b96f9a1.md", 13 | "static/media/2_getting_started.md": "/react-timeseries-charts/static/media/2_getting_started.906a806a.md", 14 | "static/media/3_styling.md": "/react-timeseries-charts/static/media/3_styling.22c4a365.md", 15 | "static/media/4_annotations.md": "/react-timeseries-charts/static/media/4_annotations.7e00e29b.md", 16 | "static/media/baselines_docs.md": "/react-timeseries-charts/static/media/baselines_docs.af746eac.md", 17 | "static/media/baselines_thumbnail.png": "/react-timeseries-charts/static/media/baselines_thumbnail.ab4808c9.png", 18 | "static/media/barchart_docs.md": "/react-timeseries-charts/static/media/barchart_docs.c7b1c427.md", 19 | "static/media/realtime_docs.md": "/react-timeseries-charts/static/media/realtime_docs.e85adf2e.md", 20 | "static/media/realtime_thumbnail.png": "/react-timeseries-charts/static/media/realtime_thumbnail.033c51ee.png", 21 | "static/media/continents_docs.md": "/react-timeseries-charts/static/media/continents_docs.219ed683.md", 22 | "static/media/continents_thumbnail.png": "/react-timeseries-charts/static/media/continents_thumbnail.398a3ca9.png", 23 | "static/media/currency_docs.md": "/react-timeseries-charts/static/media/currency_docs.eacba985.md", 24 | "static/media/currency_thumbnail.png": "/react-timeseries-charts/static/media/currency_thumbnail.b569b92b.png", 25 | "static/media/cycling_docs.md": "/react-timeseries-charts/static/media/cycling_docs.0abc2bf7.md", 26 | "static/media/cycling_thumbnail.png": "/react-timeseries-charts/static/media/cycling_thumbnail.7e08437f.png", 27 | "static/media/ddos_docs.md": "/react-timeseries-charts/static/media/ddos_docs.ef0eb60c.md", 28 | "static/media/ddos_thumbnail.png": "/react-timeseries-charts/static/media/ddos_thumbnail.7d2af225.png", 29 | "static/media/outages_docs.md": "/react-timeseries-charts/static/media/outages_docs.71f0cb04.md", 30 | "static/media/outages_thumbnail.png": "/react-timeseries-charts/static/media/outages_thumbnail.d50e76c7.png", 31 | "static/media/stockchart_docs.md": "/react-timeseries-charts/static/media/stockchart_docs.d41d8cd9.md", 32 | "static/media/stockchart_thumbnail.png": "/react-timeseries-charts/static/media/stockchart_thumbnail.2974a0cb.png", 33 | "static/media/traffic_docs.md": "/react-timeseries-charts/static/media/traffic_docs.eef1502a.md", 34 | "static/media/weather_docs.md": "/react-timeseries-charts/static/media/weather_docs.1ee86e74.md", 35 | "static/media/weather_thumbnail.png": "/react-timeseries-charts/static/media/weather_thumbnail.f8d6f622.png", 36 | "static/media/wind_docs.md": "/react-timeseries-charts/static/media/wind_docs.71db1cf6.md", 37 | "static/media/wind_thumbnail.png": "/react-timeseries-charts/static/media/wind_thumbnail.1936c918.png", 38 | "static/media/volume_docs.md": "/react-timeseries-charts/static/media/volume_docs.0abb4165.md", 39 | "static/media/volume_thumbnail.png": "/react-timeseries-charts/static/media/volume_thumbnail.2104f5f8.png", 40 | "static/media/nyc_docs.md": "/react-timeseries-charts/static/media/nyc_docs.a559ddde.md", 41 | "static/media/nyc_thumbnail.png": "/react-timeseries-charts/static/media/nyc_thumbnail.72af0cc8.png", 42 | "static/media/climate_docs.md": "/react-timeseries-charts/static/media/climate_docs.c7298675.md", 43 | "static/media/trend_docs.md": "/react-timeseries-charts/static/media/trend_docs.7ece7c4f.md", 44 | "static/css/main.dd59e73f.chunk.css.map": "/react-timeseries-charts/static/css/main.dd59e73f.chunk.css.map", 45 | "static/css/1.f8d9c008.chunk.css.map": "/react-timeseries-charts/static/css/1.f8d9c008.chunk.css.map", 46 | "index.html": "/react-timeseries-charts/index.html", 47 | "precache-manifest.af72a8770d7e1a73c3d4d9e8b7bdb457.js": "/react-timeseries-charts/precache-manifest.af72a8770d7e1a73c3d4d9e8b7bdb457.js", 48 | "service-worker.js": "/react-timeseries-charts/service-worker.js" 49 | } -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | React Timeseries Charts
-------------------------------------------------------------------------------- /docs/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js"); 15 | 16 | importScripts( 17 | "/react-timeseries-charts/precache-manifest.af72a8770d7e1a73c3d4d9e8b7bdb457.js" 18 | ); 19 | 20 | workbox.clientsClaim(); 21 | 22 | /** 23 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 24 | * requests for URLs in the manifest. 25 | * See https://goo.gl/S9QRab 26 | */ 27 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 28 | workbox.precaching.suppressWarnings(); 29 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 30 | 31 | workbox.routing.registerNavigationRoute("/react-timeseries-charts/index.html", { 32 | 33 | blacklist: [/^\/_/,/\/[^\/]+\.[^\/]+$/], 34 | }); 35 | -------------------------------------------------------------------------------- /docs/static/css/main.dd59e73f.chunk.css: -------------------------------------------------------------------------------- 1 | body{margin:0;padding:0;font-family:sans-serif}pre{display:block;margin:0 0 10px;font-size:13px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f8f8f8;border-style:none;border-radius:0;border-left:3px solid #64a0af;padding:0 0 0 10px}.chartcontainer.chartrow{background:none}body{padding-top:100px}p{overflow:hidden;line-height:1.6;word-wrap:break-word;letter-spacing:.2px;font-size:1.6rem}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6,p{color:#333;font-family:Helvetica Neue,Helvetica,Arial,sans-serif}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-weight:700}.navbar-fixed-top{background:#000!important;border-bottom:5px solid #2db3d1!important}.navbar-brand{margin-top:8px;font-size:24px}.docs-sidenav{margin-top:20px;margin-bottom:20px}.docs-sidebar .nav>li>a{color:#ccc;background:#fff;display:block;padding:4px 20px;font-size:15px;font-weight:500}.docs-sidebar .nav>li>a.active{color:#000;font-weight:600;background:#fff;border-bottom-style:solid;border-bottom-color:#2db3d1}.sub-header{padding-bottom:10px;border-bottom:1px solid #eee}.navbar-fixed-top{border:0}.sidebar{display:none}@media (min-width:768px){.sidebar{position:fixed;top:51px;bottom:0;left:0;z-index:1000;display:block;padding:20px;overflow-x:hidden;overflow-y:auto;background-color:#f5f5f5;border-right:1px solid #eee}}.nav-sidebar{margin-right:-21px;margin-bottom:20px;margin-left:-20px}.nav-sidebar>li>a{padding-right:20px;padding-left:27px}.nav-sidebar>li>a.active{padding-left:20px;border-left:#2db3d1;border-left-style:solid;border-left-width:7px;background:#ececec}.nav-sidebar>.active>a,.nav-sidebar>.active>a:focus,.nav-sidebar>.active>a:hover{color:#fff;background-color:#428bca}.sidebar-heading{padding-left:0;text-transform:uppercase;font-weight:800}.main{padding:20px}@media (min-width:768px){.main{padding-right:40px;padding-left:40px}}.main .page-header{margin-top:0} 2 | /*# sourceMappingURL=main.dd59e73f.chunk.css.map */ -------------------------------------------------------------------------------- /docs/static/js/runtime~main.171b61a2.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(r){for(var n,i,f=r[0],l=r[1],a=r[2],p=0,s=[];p 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | ``` 25 | 26 | ### 1.1 Why another chart library? 27 | 28 | This charts library was built using React from the ground up, specifically to visualize TimeSeries data and network traffic data in particular. We recognized early that we could combine the composability of React with the drawing primitives of d3, to meet our visualization needs. Other libraries have also come to the same conclusion. 29 | 30 | For us, initial key drivers in the build our own equation were: 31 | 32 | * Time series use cases first, not an after thought 33 | * Built on an underlying timeseries abstraction (pond.js) 34 | * Pan and zoom, with enough control to dynamically load in data 35 | * Ability to visualize network traffic data using stacked and up/down area charts 36 | 37 | Since then the library has grown to form the basis of visualization throughout the public facing [ESnet Portal](http://my.es.net). 38 | 39 | ### 1.2 Features 40 | 41 | Current features of the library include: 42 | 43 | * Declarative layout of charts using JSX 44 | * Composition into multiple axis and multiple rows and overlays 45 | * Interactivity, including pan and zoom, selection and highlighting 46 | * Easily add your own chart types or overlays 47 | * Line, area, scatter, bar, boxplot and event charts 48 | * Brushing for interactive chart region selection 49 | * Chart pan and zoom constraints 50 | * Legends 51 | * Baselines 52 | * Markers 53 | 54 | Please continue to read the documentation to see how to get started, or browse the examples for a feel for the library. 55 | 56 | -------------------------------------------------------------------------------- /docs/static/media/2_getting_started.906a806a.md: -------------------------------------------------------------------------------- 1 | 2 | ## 2. Getting started 3 | 4 | --- 5 | 6 | ### 2.1 How to Install 7 | 8 | This charts library is intended to be installed with [npm](https://www.npmjs.com/) and the built into your project with a tool like [Webpack](https://webpack.github.io/). It expects React to be present, as well as our TimeSeries abstraction library, [pond.js](http://software.es.net/pond). More on this below. To install: 9 | 10 | npm install react-timeseries-charts pondjs --save 11 | 12 | ### 2.2 Imports 13 | 14 | Once installed, you can import the necessary components from the library: 15 | 16 | ```js 17 | import { 18 | Charts, 19 | ChartContainer, 20 | ChartRow, 21 | YAxis, 22 | LineChart 23 | } from "react-timeseries-charts"; 24 | ``` 25 | 26 | ### 2.3 Rendering 27 | 28 | With the charts library, we construct our chart or charts in the `render()` function of our component. For a simple example here we create a visualization two line charts along with two axes, specified in JSX: 29 | 30 | ```jsx 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ``` 42 | 43 | At the outer most layer, we add a `` which contains our time range for the x-axis. All charts within a ChartContainer share the same x-axis. In this case we get the TimeRange from the TimeSeries itself, but you could specify one yourself. You also need to provide a width for the chart, or wrap the chart in a `` component and that will inject a width for you. 44 | 45 | For the next layer of the layout we make a ``. We can have multiple charts stacked on top of each other by using more than one row. In this case we just have one row. Each row has a specific height in the layout, so we specify that as 200px high here. 46 | 47 | Next up we want to put something in our row. Rows contain two parts: 48 | * A central flexible sized area in which charts can be added 49 | * Axes on either the left or right of the central area. 50 | 51 | This central area is surrounded in the JSX by the `` tag. Each chart in this area is composited on top of each other. In this case we are adding two ``s, one for each of our timeseries. As a result they will be drawn on top of each other. (Note that as of v0.9, it is also possible to draw multiple channels of a TimeSeries as multiple line charts using a single ). For scaling each chart will reference an axis that will define the scale as well as display that scale visually as the y-axis. 52 | 53 | Finally, we specify the axes that the charts reference. These go either before or after the `` group, depending on if you want the axis before (to the left) or after the charts (to the right). You can specify any number of axes on either side. For each `` you specify the `id` so that a chart can reference it, the `label` you want displayed alongside the axis and, importantly, the scale using `min` and `max`. You can also specify the `type` of the axis (`linear`, `log`, etc), a non-default `width` and the `format`. Axes are optional, but if you don't link a Chart to and Axis, you should supply the scale yourself (as a d3 scale like `scaleLinear` to the `yScale` prop passed to the specific chart). 54 | -------------------------------------------------------------------------------- /docs/static/media/barchart_docs.c7b1c427.md: -------------------------------------------------------------------------------- 1 | 2 | In this example we have a day's worth of rainfall data from Hilo, HI: 3 | 4 | ``` 5 | const data = [ 6 | ["2017-01-24T00:00", 0.01], 7 | ["2017-01-24T01:00", 0.13], 8 | ["2017-01-24T02:00", 0.07], 9 | ["2017-01-24T03:00", 0.04], 10 | ["2017-01-24T04:00", 0.33], 11 | ["2017-01-24T05:00", 0.2], 12 | ["2017-01-24T06:00", 0.08], 13 | ["2017-01-24T07:00", 0.54], 14 | ["2017-01-24T08:00", 0.95], 15 | ["2017-01-24T09:00", 1.12], 16 | ["2017-01-24T10:00", 0.66], 17 | ["2017-01-24T11:00", 0.06], 18 | ["2017-01-24T12:00", 0.3], 19 | ["2017-01-24T13:00", 0.05], 20 | ["2017-01-24T14:00", 0.5], 21 | ["2017-01-24T15:00", 0.24], 22 | ["2017-01-24T16:00", 0.02], 23 | ["2017-01-24T17:00", 0.98], 24 | ["2017-01-24T18:00", 0.46], 25 | ["2017-01-24T19:00", 0.8], 26 | ["2017-01-24T20:00", 0.39], 27 | ["2017-01-24T21:00", 0.4], 28 | ["2017-01-24T22:00", 0.39], 29 | ["2017-01-24T23:00", 0.28] 30 | ]; 31 | ``` 32 | 33 | We want to take that data and make a simple BarChart from it. 34 | 35 | This isn't the exact format we need for our chart. Firstly, like other charts, it needs to be a [Pond TimeSeries](http://software.es.net/pond/#/timeseries). Secondly, the TimeSeries is constructed from IndexedEvents. That is, each point in the TimeSeries is referenced not by a timestamp but by an "index". Each index is a string that represents a range of time. In this case each index will represent a specific hour. 36 | 37 | Note that often you will either pass the indexed data from the server, or a more dense timeseries will be aggregated with Pond to these indexed events (see the realtime example). 38 | 39 | In this case we can use Pond do do a simple transform from dates to index string: 40 | 41 | ``` 42 | const series = new TimeSeries({ 43 | name: "hilo_rainfall", 44 | columns: ["index", "precip"], 45 | points: data.map(([d, value]) => [ 46 | Index.getIndexString("1h", new Date(d)), 47 | value 48 | ]) 49 | }); 50 | ``` 51 | 52 | The resulting TimeSeries looks like this: 53 | 54 | ``` 55 | series = { 56 | "name": "HI_ASOS", 57 | "utc": true, 58 | "columns": ["index", "precip"], 59 | "points": [ 60 | ["1h-412568", 0.01], 61 | ["1h-412569", 0.13], 62 | ["1h-412570", 0.07], 63 | ["1h-412571", 0.04], 64 | ["1h-412572", 0.33], 65 | ["1h-412573", 0.2, 66 | ["1h-412574", 0.08], 67 | ["1h-412575", 0.54], 68 | ["1h-412576", 0.95], 69 | ["1h-412577", 1.12], 70 | ["1h-412578", 0.66], 71 | ["1h-412579", 0.06], 72 | ["1h-412580", 0.3, 73 | ["1h-412581", 0.05], 74 | ["1h-412582", 0.5, 75 | ["1h-412583", 0.24], 76 | ["1h-412584", 0.02], 77 | ["1h-412585", 0.98], 78 | ["1h-412586", 0.46], 79 | ["1h-412587", 0.8, 80 | ["1h-412588", 0.39], 81 | ["1h-412589", 0.4, 82 | ["1h-412590", 0.39], 83 | ["1h-412591", 0.28] 84 | ] 85 | } 86 | ``` 87 | 88 | The index strings you see here, such as "1h-412568", refer to the specific hour in a way that the BarChart will understand. (The string means that this hour is the 412568th hour since the Jan 1, 1970 UTC). 89 | 90 | Now that we have a series we can render that: 91 | 92 | ``` 93 | const Example = React.createClass({ 94 | displayName: "BarChartExample", 95 | render() { 96 | const style = styler([ 97 | { key: "precip", color: "#A5C8E1"}, 98 | ]); 99 | 100 | return ( 101 |
102 |
103 |
104 | BarChart 105 |
106 |
107 |
108 |
109 |
110 | 111 | 112 | 113 | 122 | 123 | 130 | 131 | 132 | 133 | 134 |
135 |
136 |
137 | ); 138 | } 139 | }); 140 | ``` 141 | -------------------------------------------------------------------------------- /docs/static/media/baselines_docs.af746eac.md: -------------------------------------------------------------------------------- 1 | 2 | In this simple `BaseLine` example we have a `TimeSeries` that we plot with a `LineChart`. Using pond.js we can easily extract statistic for the plot, such as max, min, avg and stdev. This example then uses the `Baseline` to overlay this information on top of the `LineChart`. This example also shows custom TimeAxis formatting, by passing in a d3 time format string to the `ChartContainer`. 3 | 4 | ```js 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ``` 23 | 24 | ## Styling 25 | 26 | The baseline can also be styled 27 | 28 | -------------------------------------------------------------------------------- /docs/static/media/baselines_thumbnail.ab4808c9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/baselines_thumbnail.ab4808c9.png -------------------------------------------------------------------------------- /docs/static/media/climate_docs.c7298675.md: -------------------------------------------------------------------------------- 1 | 2 | [http://climate.nasa.gov/vital-signs/global-temperature/ 3 | ](http://climate.nasa.gov/vital-signs/global-temperature/) 4 | 5 | Data source: NASA's Goddard Institute for Space Studies (GISS). 6 | -------------------------------------------------------------------------------- /docs/static/media/continents_docs.219ed683.md: -------------------------------------------------------------------------------- 1 | This example shows a stacked area chart. Stacking can be configured both above and below the axis, but in this example we just stack up. 2 | 3 | This example also shows the use of the `Styler` to build the `AreaChart` style given a list of `columnNames` and a `scheme`: 4 | 5 | const styler = Styler(columnNames, scheme); 6 | 7 | The `scheme` is a string corresponding to one of the color brewer sets. In this example, it is selected by the user with the pull down. 8 | 9 | Alternatively, the styler could be set with a custom list of colors like this: 10 | 11 | const customColorsList = [ 12 | "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", 13 | "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", 14 | "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", 15 | "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" 16 | ]; 17 | const styler = Styler(columnNames.map((c, i) => ({ 18 | key: c, 19 | color: customColorsList[i] 20 | }))); 21 | 22 | This example also shows how to set the interpolation to any of D3's interpolate functions, in this case `curveBasis`. 23 | 24 | Here is the chart defined in the component `render()` function: 25 | 26 | 27 | 28 | 34 | 35 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/static/media/continents_thumbnail.398a3ca9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/continents_thumbnail.398a3ca9.png -------------------------------------------------------------------------------- /docs/static/media/currency_docs.eacba985.md: -------------------------------------------------------------------------------- 1 | This example shows multiple `LineCharts` built from multiple columns in a single `TimeSeries` using the `columns` prop. 2 | 3 | This example also shows the use of the `Styler` to build the `LineChart` and `Legend` style for the two columns ("aud" and "euro"): 4 | 5 | const styler = Styler([ 6 | {key: "aud", color: "steelblue", width: 1, dashed: true}, 7 | {key: "euro", color: "#F68B24", width: 2} 8 | ]); 9 | 10 | The `Legend` is rendered as follows, supporting highlighting and selection. In this way these states are synchronized between the `Legend` and the `LineChart`: 11 | 12 | this.setState({highlight})} 18 | selection={this.state.selection} 19 | onSelectionChange={selection => this.setState({selection})} 20 | categories={[ 21 | {key: "aud", label: "AUD", value: audValue}, 22 | {key: "euro", label: "Euro", value: euroValue} 23 | ]} /> 24 | 25 | The LineChart itself is rendered like this: 26 | 27 | this.setState({ selection: null })} 36 | enablePanZoom={true} 37 | onTimeRangeChanged={this.handleTimeRangeChange} 38 | onMouseMove={(x, y) => this.handleMouseMove(x, y)} 39 | minDuration={1000 * 60 * 60 * 24 * 30} 40 | > 41 | 42 | 51 | 52 | 61 | this.setState({ highlight }) 62 | } 63 | selection={this.state.selection} 64 | onSelectionChange={selection => 65 | this.setState({ selection }) 66 | } 67 | /> 68 | 69 | 75 | 76 | 77 | 78 | 79 | The `CrossHairs` component isn't part of react-timeseries-charts. It is defined like this: 80 | 81 | ``` 82 | class CrossHairs extends React.Component { 83 | render() { 84 | const { x, y } = this.props; 85 | const style = { pointerEvents: "none", stroke: "#ccc" }; 86 | if (!_.isNull(x) && !_.isNull(y)) { 87 | return ( 88 | 89 | 90 | 91 | 92 | ); 93 | } else { 94 | return ; 95 | } 96 | } 97 | } 98 | ``` 99 | 100 | You can create any chart you want like this. The important thing about this is that a set of props will be supplied to the component when it is rendered. Those include the dimensions of the chart with `width` and `height`, and the scales `yScale` and `timeScale`. 101 | -------------------------------------------------------------------------------- /docs/static/media/currency_thumbnail.b569b92b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/currency_thumbnail.b569b92b.png -------------------------------------------------------------------------------- /docs/static/media/cycling_docs.0abc2bf7.md: -------------------------------------------------------------------------------- 1 | In this example we display this data in two ways: 2 | 1. as two overlaid line charts using two separate axes, or 3 | 2. as a channel display where the user instead scrubs the data to see the value. 4 | 5 | It demonstrates: 6 | * Broken lines for missing data 7 | * Pan and zoom over the dataset: Drag to pan, scrollwheel to zoom 8 | * Brushing over an elevation chart: drag and resize the blue rectangle to pan and zoom 9 | * Hover info boxes, in the multi-axis mode 10 | * Channel display using LabelAxis and ValueAxis 11 | -------------------------------------------------------------------------------- /docs/static/media/cycling_thumbnail.7e08437f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/cycling_thumbnail.7e08437f.png -------------------------------------------------------------------------------- /docs/static/media/ddos_thumbnail.7d2af225.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/ddos_thumbnail.7d2af225.png -------------------------------------------------------------------------------- /docs/static/media/logo.9f83357c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/logo.9f83357c.png -------------------------------------------------------------------------------- /docs/static/media/logo.fe7ba602.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/logo.fe7ba602.png -------------------------------------------------------------------------------- /docs/static/media/nyc_docs.a559ddde.md: -------------------------------------------------------------------------------- 1 | ## Box chart example 2 | 3 | A box chart is capable of displaying two ranges and a center marker. The classic example is to use the inner range to display the interquartile range, the outer range to display the min to max extent of the data (though there's other definitions too), and the center marker to show the median. 4 | 5 | You can map data to these ranges in two ways, either by passing in a continuous series and letting the chart build up the aggregations necessary (percentiles for example) for a given interval (5 min for example), or, predefining them as an array for the data column under consideration. 6 | 7 | In this example we want to do something a little different. We have data that shows the maximum and minimum temperature in New York for each day, along with the historical maximum and minimum temperatures. Our visualization will map the outer range to the historical extremes and the inner range to the actual temperature range for that day. 8 | 9 | First we need to import out data, which is in a CSV file that we read in as `weather`. We use Pond to make an array of `IndexedEvents`, one for each day. For the data of each event, we have a single field `temp` that contains an array of our values. 10 | 11 | ``` 12 | const events = weather.map(item => { 13 | const timestamp = moment(new Date(item.date)); 14 | 15 | const { 16 | date, 17 | actual_min_temp, 18 | actual_max_temp, 19 | record_min_temp, 20 | record_max_temp, 21 | } = item; 22 | 23 | return new IndexedEvent(date, { 24 | temp: [ 25 | +record_min_temp, 26 | +actual_min_temp, 27 | +actual_max_temp, 28 | +record_max_temp, 29 | ] 30 | }, false); 31 | }); 32 | 33 | const series = new TimeSeries({ name, new Collection(events) }); 34 | ``` 35 | 36 | We can then render our `series`. Note that this example also demonstrates the ability to pass a function, rather than a d3 format string, as the `YAxis` format property. 37 | 38 | ``` 39 | render() { 40 | return ( 41 | ... 42 | 46 | 47 | 48 | 53 | 54 | Number(n).toFixed() + "°F" } /> 60 | 61 | 62 | ... 63 | ); 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/static/media/nyc_thumbnail.72af0cc8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/nyc_thumbnail.72af0cc8.png -------------------------------------------------------------------------------- /docs/static/media/outages_docs.71f0cb04.md: -------------------------------------------------------------------------------- 1 | This example shows a short list of network outages as an `EventChart`. `EventCharts` are currently experimental and don't yet conform to the style guidelines. 2 | 3 | Here we build an `EventChart`. 4 | 5 | 9 | 10 | 11 | e.get("title")} /> 15 | 16 | 17 | 18 | 19 | ### Styling 20 | 21 | Styling is currently performed with a callback function. In the above example `outageEventStyleCB` is a function implemented as follows: 22 | 23 | function outageEventStyleCB(event, state) { 24 | const color = event.get("type") === "Planned" ? "#998ec3" : "#f1a340"; 25 | switch (state) { 26 | case "normal": 27 | return { 28 | fill: color 29 | }; 30 | case "hover": 31 | return { 32 | fill: color, 33 | opacity: 0.4 34 | }; 35 | case "selected": 36 | return { 37 | fill: color 38 | }; 39 | } 40 | } 41 | 42 | The purpose of the function is to set a different color depending on if our event outage was planned or not. 43 | 44 | **Note: This form of style setting is similar, but not the same, as the API style guide, so will likely change in the near future.** 45 | -------------------------------------------------------------------------------- /docs/static/media/outages_thumbnail.d50e76c7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/outages_thumbnail.d50e76c7.png -------------------------------------------------------------------------------- /docs/static/media/realtime_docs.e85adf2e.md: -------------------------------------------------------------------------------- 1 | 2 | In this example we have an simulated incoming stream of measurements, represented by the dots. The visualization you see shows the 5 min aggregations (both 50th and 90th percentile) of the incoming stream as a green bar chart. We calculate this as described below. 3 | 4 | ### Events 5 | 6 | To do this, each event is generated semi-randomly, but they could be coming from a real source. We add a new Event for each minute, but emit 5 per second to speed up the simulation. Essentially we do this: 7 | 8 | ```js 9 | import { Event } from "pondjs"; 10 | 11 | const value = getRandomValue(); 12 | const time = getNextTime(); 13 | const event = new Event(time, value); 14 | ``` 15 | 16 | Now we want to do some things with that Event: 17 | 18 | * Store it, so we can show the scatter plot 19 | * Aggregate it to give us our 5 min average and maximum values 20 | 21 | To store it, we put it into a circle buffer that keeps the last n Events. Otherwise we'll eventually kill the browser. The circle buffer is placed in the React component's state. 22 | 23 | ### Aggregation 24 | 25 | For the more interesting part, the aggregation, we need to setup up a couple of Pond Pipelines to do the work. Here's the 5 min aggregation pipeline that we setup: 26 | 27 | ```js 28 | 29 | import { Stream, Pipeline, EventOut, percentile } from "pondjs"; 30 | 31 | ... 32 | 33 | const stream = new Stream(); 34 | 35 | Pipeline() 36 | .from(stream) 37 | .windowBy("5m") 38 | .emitOn("discard") 39 | .aggregate({ 40 | value: {value: percentile(90)} 41 | }) 42 | .to(EventOut, event => { 43 | // store the output events in our component state 44 | }); 45 | ``` 46 | 47 | The Pipeline now just needs a feed of events added to its stream in order to process them into a new aggregated events. Each time one of these new events is emitted we take that from the callback defined in `to()` and place it into the component's state. 48 | 49 | 50 | ```js 51 | stream.addEvent(event); 52 | ``` 53 | 54 | ### Visualization 55 | 56 | The first thing we need to do is turn our three event lists (the original events along with the two aggregated event streams) into TimeSeries objects which can then be passed to our charting code. Since we can construct a pond.js TimeSeries object from a list of events, this is simply a matter of pulling the list from the circle buffer and giving it to the TimeSeries constructor. 57 | 58 | For example, our 5 min 50th percentiles: 59 | 60 | ```js 61 | const name = "5m-percentile-50"; 62 | const events = this.state.perc50Out.toArray(); // <- from circle buffer 63 | const avgSeries = new TimeSeries({name, events}); 64 | ``` 65 | 66 | Next we figure out the begin and end times for the chart. The chart expands outward until it gets to 3 hours and then pans with the new data. Once we calculate the beginTime and endTime we make a TimeRange to represent this range: 67 | 68 | ```js 69 | const timeRange = new TimeRange(beginTime, endTime); 70 | ``` 71 | 72 | Finally we render() the chart: 73 | 74 | ```js 75 | render() { 76 | return ( 77 | 78 | 79 | 84 | 85 | 89 | 93 | 96 | 97 | 98 | 99 | ); 100 | } 101 | ``` 102 | -------------------------------------------------------------------------------- /docs/static/media/realtime_thumbnail.033c51ee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/realtime_thumbnail.033c51ee.png -------------------------------------------------------------------------------- /docs/static/media/stockchart_docs.d41d8cd9.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/stockchart_docs.d41d8cd9.md -------------------------------------------------------------------------------- /docs/static/media/stockchart_thumbnail.2974a0cb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/stockchart_thumbnail.2974a0cb.png -------------------------------------------------------------------------------- /docs/static/media/traffic_thumbnail.3a9ee161.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/traffic_thumbnail.3a9ee161.png -------------------------------------------------------------------------------- /docs/static/media/trend_docs.7ece7c4f.md: -------------------------------------------------------------------------------- 1 | 2 | In this example we have more than a months's worth of data showing loading times across releases of a hypothetical web application: 3 | 4 | ``` 5 | const data = [ 6 | { 7 | "date": "2014-08-01", 8 | "pct05": 5350, 9 | "pct25": 6756, 10 | "pct50": 7819, 11 | "pct75": 9284, 12 | "pct95": 13835 13 | }, 14 | { 15 | "date": "2014-08-02", 16 | "pct05": 4439, 17 | "pct25": 5584, 18 | "pct50": 6554, 19 | "pct75": 8016, 20 | "pct95": 12765 21 | }, 22 | { 23 | "date": "2014-08-03", 24 | "pct05": 4247, 25 | "pct25": 5419, 26 | "pct50": 6332, 27 | "pct75": 7754, 28 | "pct95": 12236 29 | }, 30 | { 31 | "date": "2014-08-04", 32 | "pct05": 3293, 33 | "pct25": 4414, 34 | "pct50": 5191, 35 | "pct75": 6491, 36 | "pct95": 10325 37 | }, 38 | .... 39 | ]; 40 | ``` 41 | 42 | We want to take that data and make a Trend Chart, a mixture of a line chart and area chart from it. 43 | 44 | This isn't the exact format we need for our chart. Firstly, like other charts, it needs to be a [Pond TimeSeries](http://software.es.net/pond/#/timeseries). Secondly, the TimeSeries is constructed from points where the first column refers to the index, the second column is an array of values representing the 5th, 25th, 75th and 95th percentile. Finally, the third column represents the median value. 45 | 46 | Note that often you will either pass the indexed data from the server, or a more dense timeseries will be aggregated with Pond to these indexed events (see the realtime example). 47 | 48 | ``` 49 | const series = new TimeSeries({ 50 | name: "series", 51 | columns: ["index", "t", "median"], 52 | points: data.map(({ date, pct05, pct25, pct50, pct75, pct95 }) => [ 53 | date, 54 | [ 55 | pct05 / 1000, 56 | pct25 / 1000, 57 | pct75 / 1000, 58 | pct95 / 1000 59 | ], 60 | pct50 / 1000 61 | ]) 62 | }); 63 | ``` 64 | 65 | To style the trend chart, we pass in the values to the styler object where the key refers to the column in the series 66 | 67 | ``` 68 | const style = styler([ 69 | { key: "t", color: "steelblue", width: 1, opacity: 1 }, 70 | { key: "median", color: "#333", width: 1 } 71 | ]); 72 | ``` 73 | 74 | Now that we have a series and style object, we can render the chart as follows: 75 | 76 | ``` 77 | class trend extends React.Component { 78 | render() { 79 | return ( 80 |
81 |
82 |
83 | BarChart 84 |
85 |
86 |
87 |
88 |
89 | 90 | 91 | 92 | 101 | 102 | 110 | 118 | 119 | 120 | 121 | 122 |
123 |
124 |
125 | ); 126 | } 127 | }; 128 | ``` 129 | -------------------------------------------------------------------------------- /docs/static/media/volume_docs.0abb4165.md: -------------------------------------------------------------------------------- 1 | This simple example of a bar chart displays a pan and zoom chart that shows traffic levels for each day of October 2014. The original data used here was captured to debug a measurement error (seen clearly in Oct 10th). 2 | 3 | To begin with we converted the original data into Pond's TimeSeries data structure as `octoberTraffic`: 4 | 5 | import { TimeSeries } from "pondjs"; 6 | 7 | const octoberTraffic = new TimeSeries({ 8 | name: "Traffic", 9 | utc: false, 10 | columns: ["time", "in", "out"], 11 | points: trafficPoints 12 | }); 13 | 14 | Points are simply an array of tuples, each of which is `[index, value1, value2, ...]`. In this case this looks like `['2014-10-DD', volIn, volOut]`. An index can be of several forms, but is a string that represents a time range (e.g. 2014-10-08 represents the time range spanning October 8th 2014). 15 | 16 | We also set `utc` to false here so that the index time ranges are defined in local time. Visualizations of time series data default to showing local time (though UTC is also possible), while `IndexedEvents` default to being in UTC. 17 | 18 | Now we can render a the chart. The `` element does the rendering of the chart itself. As with other chart types, the vertical scale is provided by referencing the `` (`axis='traffic'`). 19 | 20 | 28 | 29 | 34 | 35 | this.setState({highlight})} 43 | selection={this.state.selection} 44 | onSelectionChange={selection => this.setState({selection})} /> 45 | 50 | 51 | 56 | 57 | 58 | 59 | The style provides the coloring, relating each channel to styles for "normal", "highlight" (hover), "selected" and "muted". Muted is the style shown on bars which are not selected: 60 | 61 | const style = { 62 | in: { 63 | normal: {fill: "#A5C8E1"}, 64 | highlighted: {fill: "#bfdff6"}, 65 | selected: {fill: "#5aa2d5"}, 66 | muted: {fill: "#A5C8E1", opacity: 0.4} 67 | } 68 | }; 69 | 70 | Side note: this chart can also be zoomed in and then panned with constraints. This is controlled using the `` props. Drag to pan, scroll wheel to zoom. 71 | -------------------------------------------------------------------------------- /docs/static/media/volume_thumbnail.2104f5f8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/volume_thumbnail.2104f5f8.png -------------------------------------------------------------------------------- /docs/static/media/weather_docs.1ee86e74.md: -------------------------------------------------------------------------------- 1 | This example uses three rows to create stacked chart: 2 | 3 | this.setState({tracker})} > 11 | 12 | 14 | 15 | 20 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 39 | { return event.get("radius"); }}/> 45 | 46 | 48 | 49 | 50 | 51 | 52 | 59 | 64 | 65 | 67 | 68 | -------------------------------------------------------------------------------- /docs/static/media/weather_thumbnail.f8d6f622.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/weather_thumbnail.f8d6f622.png -------------------------------------------------------------------------------- /docs/static/media/wind_docs.71db1cf6.md: -------------------------------------------------------------------------------- 1 | The ScatterChart takes a TimeSeries as its `series` prop, 2 | along with a list of `columns` to plot. 3 | 4 | Here we style each point with a function passed to the `style` prop, 5 | rather than passing an object, though you can do that too. However, 6 | it is common for a scatter plot to need to style per point, so we 7 | demonstrate that here. 8 | 9 | This style function is passed the `column` and `event` to style and returns 10 | an object with the style for each state the point could be in: 11 | normal, highlighted, selected or muted. Be aware that this is called 12 | for every point on every render, so be gentle. 13 | 14 | ``` 15 | const perEventStyle = (column, event) => { 16 | const color = heat[ 17 | Math.floor((1 - event.get("station1") / 40) * 11) 18 | ]; 19 | return { 20 | normal: { 21 | fill: color, 22 | opacity: 1.0 23 | }, 24 | highlighted: { 25 | fill: color, 26 | stroke: "none", 27 | opacity: 1.0 28 | }, 29 | selected: { 30 | fill: "none", 31 | stroke: "#2CB1CF", 32 | strokeWidth: 3, 33 | opacity: 1.0 34 | }, 35 | muted: { 36 | stroke: "none", 37 | opacity: 0.4, 38 | fill: color 39 | } 40 | }; 41 | }; 42 | ``` 43 | 44 | Similarly we can control the radius of each point with a function 45 | passed to the `radius` prop: 46 | 47 | ``` 48 | radius={(event, column) => 49 | column === "station1" ? 3 : 2} 50 | ``` 51 | 52 | In this case we just say that if the column we're rendering is 53 | "station1" we render a radius of 3, otherwise a radius of 2. But 54 | alternatively it would be easy to use a value in the event to render 55 | a radius based on magnitude, allowing you to create a bubble plot. 56 | 57 | Other parts of this example are similar to other examples, such as the 58 | use of timerange state to control pan and zoom, and handling of selection. 59 | Note the use of `onBackgroundClick` on the ChartContainer to deselect any selection. 60 | 61 | We also render a `BandChart` to show the outer range from the 5th percentile to the 95th, 62 | along with an inner range for the interquantile. 63 | 64 | Here is the render code: 65 | 66 | ``` 67 | 71 | this.setState({ selection: null })} 72 | onTimeRangeChanged={timerange => 73 | this.setState({ timerange })} 74 | > 75 | 76 | 78 | 79 | 92 | 112 | column === "station1" ? 3 : 2} 113 | /> 114 | 115 | 116 | 117 | ``` 118 | -------------------------------------------------------------------------------- /docs/static/media/wind_thumbnail.1936c918.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/docs/static/media/wind_thumbnail.1936c918.png -------------------------------------------------------------------------------- /lib/components/Label.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require("react"); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | var _propTypes = require("prop-types"); 12 | 13 | var _propTypes2 = _interopRequireDefault(_propTypes); 14 | 15 | var _merge = require("merge"); 16 | 17 | var _merge2 = _interopRequireDefault(_merge); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | var defaultBoxStyle = { 22 | fill: "#FEFEFE", 23 | stroke: "#DDD", 24 | opacity: 0.8 25 | }; /** 26 | * Copyright (c) 2016, The Regents of the University of California, 27 | * through Lawrence Berkeley National Laboratory (subject to receipt 28 | * of any required approvals from the U.S. Dept. of Energy). 29 | * All rights reserved. 30 | * 31 | * This source code is licensed under the BSD-style license found in the 32 | * LICENSE file in the root directory of this source tree. 33 | */ 34 | 35 | var defaultTextStyle = { 36 | fontSize: 11, 37 | textAnchor: "left", 38 | fill: "#b0b0b0", 39 | pointerEvents: "none" 40 | }; 41 | 42 | var defaultTextStyleCentered = { 43 | fontSize: 11, 44 | textAnchor: "middle", 45 | fill: "#bdbdbd", 46 | pointerEvents: "none" 47 | }; 48 | 49 | function mergeStyles(style, isCentered) { 50 | return { 51 | boxStyle: (0, _merge2.default)(true, defaultBoxStyle, style.box ? style.box : {}), 52 | labelStyle: (0, _merge2.default)(true, isCentered ? defaultTextStyleCentered : defaultTextStyle, style.label ? style.label : {}) 53 | }; 54 | } 55 | 56 | /** 57 | * Renders a simple label surrounded by a box within in svg 58 | * 59 | * +----------------+ 60 | * | My label | 61 | * | | 62 | * +----------------+ 63 | */ 64 | 65 | var Label = function Label(_ref) { 66 | var label = _ref.label, 67 | style = _ref.style, 68 | align = _ref.align, 69 | width = _ref.width, 70 | height = _ref.height; 71 | 72 | var _mergeStyles = mergeStyles(style, align === "center"), 73 | boxStyle = _mergeStyles.boxStyle, 74 | labelStyle = _mergeStyles.labelStyle; 75 | 76 | var posx = align === "center" ? parseInt(width / 2, 10) : 10; 77 | 78 | var text = _react2.default.createElement( 79 | "text", 80 | { x: posx, y: 5, dy: "1.2em", style: labelStyle }, 81 | label 82 | ); 83 | 84 | var box = _react2.default.createElement("rect", { x: 0, y: 0, style: boxStyle, width: width, height: height }); 85 | 86 | return _react2.default.createElement( 87 | "g", 88 | null, 89 | box, 90 | text 91 | ); 92 | }; 93 | 94 | Label.defaultProps = { 95 | align: "center", 96 | width: 100, 97 | height: 100, 98 | pointerEvents: "none" 99 | }; 100 | 101 | Label.propTypes = { 102 | /** 103 | * Where to position the label, either "left" or "center" within the box 104 | */ 105 | align: _propTypes2.default.oneOf(["center", "left"]), 106 | 107 | /** 108 | * The label to render 109 | */ 110 | label: _propTypes2.default.string.isRequired, 111 | 112 | /** 113 | * The style of the label. This is the inline CSS applied directly 114 | * to the label box 115 | */ 116 | style: _propTypes2.default.object, // eslint-disable-line 117 | 118 | /** 119 | * The width of the rectangle to render into 120 | */ 121 | width: _propTypes2.default.number, 122 | 123 | /** 124 | * The height of the rectangle to render into 125 | */ 126 | height: _propTypes2.default.number 127 | }; 128 | 129 | exports.default = Label; -------------------------------------------------------------------------------- /lib/components/ValueAxis.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require("react"); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | var _propTypes = require("prop-types"); 12 | 13 | var _propTypes2 = _interopRequireDefault(_propTypes); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | /** 18 | * Renders a 'axis' that display a label for a current tracker value: 19 | * ``` 20 | * ----+----------------+ 21 | * | 56.2G | 22 | * | bps | 23 | * | | 24 | * ----+----------------+ 25 | * ``` 26 | * This would be used when you have many rows of data and the user is required 27 | * to interact with the data to see actual values. You would use this at the 28 | * end of the row and supply it with the current value. See the cycling example 29 | * for how that would all work. 30 | */ 31 | /** 32 | * Copyright (c) 2015-present, The Regents of the University of California, 33 | * through Lawrence Berkeley National Laboratory (subject to receipt 34 | * of any required approvals from the U.S. Dept. of Energy). 35 | * All rights reserved. 36 | * 37 | * This source code is licensed under the BSD-style license found in the 38 | * LICENSE file in the root directory of this source tree. 39 | */ 40 | 41 | var ValueAxis = function ValueAxis(_ref) { 42 | var width = _ref.width, 43 | height = _ref.height, 44 | value = _ref.value, 45 | detail = _ref.detail; 46 | 47 | var labelStyle = { 48 | fill: "#666", 49 | fontSize: 20, 50 | textAnchor: "middle" 51 | }; 52 | var detailStyle = { 53 | fontSize: 12, 54 | textAnchor: "middle", 55 | fill: "#9a9a9a" 56 | }; 57 | return _react2.default.createElement( 58 | "g", 59 | null, 60 | _react2.default.createElement("rect", { 61 | key: "background", 62 | x: "0", 63 | y: "0", 64 | width: width, 65 | height: height, 66 | style: { fill: "none", stroke: "none" } 67 | }), 68 | _react2.default.createElement( 69 | "text", 70 | { key: "value", x: parseInt(width / 2, 10), y: height / 2, style: labelStyle }, 71 | value 72 | ), 73 | _react2.default.createElement( 74 | "text", 75 | { 76 | key: "detail", 77 | x: parseInt(width / 2, 10), 78 | y: height / 2, 79 | dy: "1.2em", 80 | style: detailStyle 81 | }, 82 | detail 83 | ) 84 | ); 85 | }; 86 | 87 | ValueAxis.propTypes = { 88 | /** 89 | * Show or hide this 90 | */ 91 | visible: _propTypes2.default.bool, 92 | 93 | /** 94 | * If values are numbers, use this format string 95 | */ 96 | value: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]), 97 | 98 | /** 99 | * Use this to show what units are being used. It will appear below 100 | * the value. 101 | */ 102 | detail: _propTypes2.default.string, 103 | 104 | /** 105 | * The width of the axis 106 | */ 107 | width: _propTypes2.default.number, 108 | 109 | /** 110 | * [Internal] The height of the axis 111 | */ 112 | height: _propTypes2.default.number 113 | }; 114 | 115 | ValueAxis.defaultProps = { 116 | visible: true 117 | }; 118 | 119 | exports.default = ValueAxis; -------------------------------------------------------------------------------- /lib/js/curve.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _d3Shape = require("d3-shape"); 8 | 9 | exports.default = { 10 | curveBasisClosed: _d3Shape.curveBasisClosed, 11 | curveBasisOpen: _d3Shape.curveBasisOpen, 12 | curveBasis: _d3Shape.curveBasis, 13 | curveBundle: _d3Shape.curveBundle, 14 | curveCardinalClosed: _d3Shape.curveCardinalClosed, 15 | curveCardinalOpen: _d3Shape.curveCardinalOpen, 16 | curveCardinal: _d3Shape.curveCardinal, 17 | curveCatmullRomClosed: _d3Shape.curveCatmullRomClosed, 18 | curveCatmullRomOpen: _d3Shape.curveCatmullRomOpen, 19 | curveCatmullRom: _d3Shape.curveCatmullRom, 20 | curveLinearClosed: _d3Shape.curveLinearClosed, 21 | curveLinear: _d3Shape.curveLinear, 22 | curveMonotoneX: _d3Shape.curveMonotoneX, 23 | curveMonotoneY: _d3Shape.curveMonotoneY, 24 | curveNatural: _d3Shape.curveNatural, 25 | curveStep: _d3Shape.curveStep, 26 | curveStepAfter: _d3Shape.curveStepAfter, 27 | curveStepBefore: _d3Shape.curveStepBefore 28 | }; /** 29 | * Copyright (c) 2017, The Regents of the University of California, 30 | * through Lawrence Berkeley National Laboratory (subject to receipt 31 | * of any required approvals from the U.S. Dept. of Energy). 32 | * All rights reserved. 33 | * 34 | * This source code is licensed under the BSD-style license found in the 35 | * LICENSE file in the root directory of this source tree. 36 | */ -------------------------------------------------------------------------------- /lib/js/util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.scaleAsString = scaleAsString; 7 | exports.getElementOffset = getElementOffset; 8 | /** 9 | * Copyright (c) 2016, The Regents of the University of California, 10 | * through Lawrence Berkeley National Laboratory (subject to receipt 11 | * of any required approvals from the U.S. Dept. of Energy). 12 | * All rights reserved. 13 | * 14 | * This source code is licensed under the BSD-style license found in the 15 | * LICENSE file in the root directory of this source tree. 16 | */ 17 | 18 | function scaleAsString(scale) { 19 | return scale.domain() + "-" + scale.range(); 20 | } 21 | 22 | // http://stackoverflow.com/a/28857255 23 | function getElementOffset(element) { 24 | var de = document.documentElement; 25 | var box = element.getBoundingClientRect(); 26 | var top = box.top + window.pageYOffset - de.clientTop; 27 | var left = box.left + window.pageXOffset - de.clientLeft; 28 | return { top: top, left: left }; 29 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-timeseries-charts", 3 | "version": "0.16.0", 4 | "description": "Declarative timeseries charts", 5 | "keywords": [ 6 | "d3", 7 | "charts", 8 | "react", 9 | "timeseries" 10 | ], 11 | "homepage": "http://software.es.net/react-timeseries-charts", 12 | "main": "lib/entry", 13 | "author": "ESnet Tools Team ", 14 | "repository": "esnet/react-timeseries-charts", 15 | "bugs": { 16 | "url": "https://github.com/esnet/react-timeseries-charts/issues" 17 | }, 18 | "scripts": { 19 | "docs": "echo \"*** Building API docs\n\" && react-docgen src/components -x js -o src/website/packages/charts/api/docs.json --pretty", 20 | "lint": "eslint src/components/*.js", 21 | "test": "npm run lint", 22 | "build": "echo \"*** Building lib\n\" && rm -rf lib/* && babel src/components --optional runtime --stage 0 --out-dir lib/components && babel src/js --optional runtime --stage 0 --out-dir lib/js && babel src/entry.js --optional runtime --stage 0 --out-file lib/entry.js", 23 | "start-website": "react-scripts start", 24 | "build-website": "echo \"*** Building website\n\" && rm -rf docs && react-scripts build && mv build docs", 25 | "precommit": "lint-staged" 26 | }, 27 | "lint-staged": { 28 | "src/**/*.js": [ 29 | "prettier --print-width 100 --tab-width 4 --write 'src/**/*.js'", 30 | "git add" 31 | ] 32 | }, 33 | "license": "BSD-3-Clause-LBNL", 34 | "dependencies": { 35 | "array.prototype.fill": "^1.0.1", 36 | "babel-runtime": "^6.23.0", 37 | "colorbrewer": "^1.0.0", 38 | "d3-axis": "^1.0.8", 39 | "d3-ease": "^1.0.3", 40 | "d3-format": "^1.2.0", 41 | "d3-interpolate": "^1.1.5", 42 | "d3-scale": "^1.0.6", 43 | "d3-scale-chromatic": "^1.1.1", 44 | "d3-selection": "^1.1.0", 45 | "d3-selection-multi": "^1.0.1", 46 | "d3-shape": "^1.2.0", 47 | "d3-time": "^1.0.7", 48 | "d3-time-format": "^2.0.5", 49 | "d3-transition": "^1.1.0", 50 | "dom-resize": "^1.0.3", 51 | "invariant": "^2.1.1", 52 | "merge": "^1.2.0", 53 | "moment": "^2.18.1", 54 | "moment-duration-format": "^1.3.0", 55 | "prop-types": "^15.5.10", 56 | "react-hot-loader": "4.1.2", 57 | "underscore": "^1.8.3" 58 | }, 59 | "devDependencies": { 60 | "babel-cli": "^6.5.1", 61 | "babel-core": "^6.25.0", 62 | "babel-eslint": "9.0.0", 63 | "babel-polyfill": "^6.23.0", 64 | "babel-preset-es2015": "^6.24.1", 65 | "babel-preset-react": "^6.24.1", 66 | "babel-preset-stage-0": "^6.24.1", 67 | "create-react-class": "^15.6.2", 68 | "dsv-loader": "^2.0.0", 69 | "eslint": "5.6.0", 70 | "eslint-config-react-app": "^1.0.5", 71 | "eslint-plugin-flowtype": "^2.33.0", 72 | "eslint-plugin-import": "^2.2.0", 73 | "eslint-plugin-jsx-a11y": "^5.0.3", 74 | "eslint-plugin-react": "^7.0.1", 75 | "husky": "^1.1.3", 76 | "lint-staged": "^3.4.0", 77 | "pondjs": "^0.8.8", 78 | "prettier": "^1.9.2", 79 | "raw-loader": "^0.5.1", 80 | "react": "^16.2.0", 81 | "react-docgen": "^4.1.0", 82 | "react-dom": "^16.2.0", 83 | "react-markdown": "^2.4.4", 84 | "react-router": "^3.2.0", 85 | "react-scripts": "^2.1.1", 86 | "react-select": "^1.1.0", 87 | "ringjs": "0.0.1" 88 | }, 89 | "peerDependencies": { 90 | "pondjs": "^0.8.0", 91 | "react": "^15.3.1 || ^16.0" 92 | }, 93 | "browserslist": [ 94 | ">0.2%", 95 | "not dead", 96 | "not ie <= 11", 97 | "not op_mini all" 98 | ] 99 | } 100 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | React Timeseries Charts 16 | 17 | 18 | 19 | 20 | 29 | 30 | 31 | 32 | 33 | 36 | 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/components/Charts.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import React from "react"; 12 | 13 | /** 14 | * 15 | * The `` element is a grouping for charts within a row. 16 | * It takes no props. Each chart within the group will be overlaid 17 | * on top of each other. 18 | * 19 | * Here is an example of two line charts within a `` group: 20 | * 21 | * ```xml 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * ``` 33 | * 34 | * ## Making your own chart 35 | * 36 | * Anything within this grouping is considered a chart, meaning it will have 37 | * certain props injected into it. As a result you can easily implement your own chart 38 | * by simply expecting to have these props available and rendering as such. 39 | * 40 | * For your own chart, the render() method should return a SVG group `` at the 41 | * top level, and then your chart rendering within that. 42 | * 43 | * In addition to any props you add to your chart, the following props are passed into 44 | * each chart automatically: 45 | * 46 | * #### timeScale 47 | * 48 | * A d3 scale for the time axis which you can use to transform your data in the x direction 49 | * 50 | * #### yScale 51 | * 52 | * A d3 scale for the y-axis which you can use to transform your data in the y direction 53 | * 54 | * #### width 55 | * 56 | * A the width your chart will render into 57 | */ 58 | export default class Charts extends React.Component { 59 | render() { 60 | return `${this.constructor.name} elements are for configuration only 61 | and should not be rendered`; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/components/Label.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import React from "react"; 12 | import PropTypes from "prop-types"; 13 | import merge from "merge"; 14 | 15 | const defaultBoxStyle = { 16 | fill: "#FEFEFE", 17 | stroke: "#DDD", 18 | opacity: 0.8 19 | }; 20 | 21 | const defaultTextStyle = { 22 | fontSize: 11, 23 | textAnchor: "left", 24 | fill: "#b0b0b0", 25 | pointerEvents: "none" 26 | }; 27 | 28 | const defaultTextStyleCentered = { 29 | fontSize: 11, 30 | textAnchor: "middle", 31 | fill: "#bdbdbd", 32 | pointerEvents: "none" 33 | }; 34 | 35 | function mergeStyles(style, isCentered) { 36 | return { 37 | boxStyle: merge(true, defaultBoxStyle, style.box ? style.box : {}), 38 | labelStyle: merge( 39 | true, 40 | isCentered ? defaultTextStyleCentered : defaultTextStyle, 41 | style.label ? style.label : {} 42 | ) 43 | }; 44 | } 45 | 46 | /** 47 | * Renders a simple label surrounded by a box within in svg 48 | * 49 | * +----------------+ 50 | * | My label | 51 | * | | 52 | * +----------------+ 53 | */ 54 | 55 | const Label = ({ label, style, align, width, height }) => { 56 | const { boxStyle, labelStyle } = mergeStyles(style, align === "center"); 57 | 58 | const posx = align === "center" ? parseInt(width / 2, 10) : 10; 59 | 60 | const text = ( 61 | 62 | {label} 63 | 64 | ); 65 | 66 | const box = ; 67 | 68 | return ( 69 | 70 | {box} 71 | {text} 72 | 73 | ); 74 | }; 75 | 76 | Label.defaultProps = { 77 | align: "center", 78 | width: 100, 79 | height: 100, 80 | pointerEvents: "none" 81 | }; 82 | 83 | Label.propTypes = { 84 | /** 85 | * Where to position the label, either "left" or "center" within the box 86 | */ 87 | align: PropTypes.oneOf(["center", "left"]), 88 | 89 | /** 90 | * The label to render 91 | */ 92 | label: PropTypes.string.isRequired, 93 | 94 | /** 95 | * The style of the label. This is the inline CSS applied directly 96 | * to the label box 97 | */ 98 | style: PropTypes.object, // eslint-disable-line 99 | 100 | /** 101 | * The width of the rectangle to render into 102 | */ 103 | width: PropTypes.number, 104 | 105 | /** 106 | * The height of the rectangle to render into 107 | */ 108 | height: PropTypes.number 109 | }; 110 | 111 | export default Label; 112 | -------------------------------------------------------------------------------- /src/components/Resizable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import React from "react"; 12 | import PropTypes from "prop-types"; 13 | 14 | /** 15 | * This takes a single child and inserts a prop 'width' on it that is the 16 | * current width of the this container. This is handy if you want to surround 17 | * a chart or other svg diagram and have this drive the chart width. 18 | */ 19 | export default class Resizable extends React.Component { 20 | constructor(props) { 21 | super(props); 22 | this.state = { width: 0 }; 23 | this.handleResize = this.handleResize.bind(this); 24 | } 25 | 26 | componentDidMount() { 27 | window.addEventListener("resize", this.handleResize); 28 | this.handleResize(); 29 | } 30 | 31 | componentWillUnmount() { 32 | window.removeEventListener("resize", this.handleResize); 33 | } 34 | 35 | handleResize() { 36 | if (this.container) { 37 | this.setState({ 38 | width: this.container.offsetWidth 39 | }); 40 | } 41 | } 42 | 43 | render() { 44 | const child = React.Children.only(this.props.children); 45 | const childElement = this.state.width 46 | ? React.cloneElement(child, { width: this.state.width }) 47 | : null; 48 | return ( 49 |
{ 51 | this.container = c; 52 | }} 53 | {...this.props} 54 | > 55 | {childElement} 56 |
57 | ); 58 | } 59 | } 60 | 61 | Resizable.propTypes = { 62 | children: PropTypes.node 63 | }; 64 | -------------------------------------------------------------------------------- /src/components/TimeRangeMarker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import React from "react"; 12 | import PropTypes from "prop-types"; 13 | import { TimeRange } from "pondjs"; 14 | 15 | /** 16 | * Renders a band with extents defined by the supplied TimeRange. This 17 | * is a super simple component right now which just renders a simple 18 | * rectangle, in the style of the prop `style` across the timerange 19 | * specified. However, this is useful for highlighting a timerange to 20 | * correspond with another part of the your UI. 21 | * 22 | * See also the Brush component for a TimeRange marker that you can 23 | * resize interactively. 24 | */ 25 | export default class TimeRangeMarker extends React.Component { 26 | renderBand() { 27 | const timerange = this.props.timerange; 28 | const timeScale = this.props.timeScale; 29 | 30 | // Viewport bounds 31 | const viewBeginTime = timeScale.invert(0); 32 | const viewEndTime = timeScale.invert(this.props.width); 33 | const viewport = new TimeRange(viewBeginTime, viewEndTime); 34 | 35 | let bandStyle; 36 | if (this.props.style) { 37 | bandStyle = this.props.style; 38 | } else { 39 | bandStyle = { fill: "steelblue" }; 40 | } 41 | 42 | if (!viewport.disjoint(timerange)) { 43 | const range = timerange.intersection(viewport); 44 | const begin = range.begin(); 45 | const end = range.end(); 46 | const beginPos = timeScale(begin); 47 | const endPos = timeScale(end); 48 | let width = endPos - beginPos; 49 | if (width < 1) { 50 | width = 1; 51 | } 52 | return ( 53 | 60 | ); 61 | } 62 | return ; 63 | } 64 | 65 | render() { 66 | return {this.renderBand()}; 67 | } 68 | } 69 | 70 | TimeRangeMarker.propTypes = { 71 | /** 72 | * Show or hide this marker 73 | */ 74 | visible: PropTypes.bool, 75 | 76 | /** 77 | * The timerange to mark. This is in the form of a 78 | * [Pond TimeRange](https://esnet-pondjs.appspot.com/#/timerange) 79 | */ 80 | timerange: PropTypes.instanceOf(TimeRange).isRequired, 81 | 82 | /** 83 | * The style of the rect that will be rendered as a SVG . This 84 | * object is the inline CSS for that rect. 85 | */ 86 | style: PropTypes.object, // eslint-disable-line 87 | 88 | /** 89 | * [Internal] The timeScale supplied by the surrounding ChartContainer 90 | */ 91 | timeScale: PropTypes.func.isRequired, 92 | 93 | /** 94 | * [Internal] The width supplied by the surrounding ChartContainer 95 | */ 96 | width: PropTypes.number.isRequired, 97 | 98 | /** 99 | * [Internal] The height supplied by the surrounding ChartContainer 100 | */ 101 | height: PropTypes.number.isRequired 102 | }; 103 | 104 | TimeRangeMarker.defaultProps = { 105 | visible: true, 106 | spacing: 1, 107 | offset: 0, 108 | style: { fill: "rgba(70, 130, 180, 0.25);" } 109 | }; 110 | -------------------------------------------------------------------------------- /src/components/ValueAxis.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import React from "react"; 12 | import PropTypes from "prop-types"; 13 | 14 | /** 15 | * Renders a 'axis' that display a label for a current tracker value: 16 | * ``` 17 | * ----+----------------+ 18 | * | 56.2G | 19 | * | bps | 20 | * | | 21 | * ----+----------------+ 22 | * ``` 23 | * This would be used when you have many rows of data and the user is required 24 | * to interact with the data to see actual values. You would use this at the 25 | * end of the row and supply it with the current value. See the cycling example 26 | * for how that would all work. 27 | */ 28 | const ValueAxis = ({ width, height, value, detail }) => { 29 | const labelStyle = { 30 | fill: "#666", 31 | fontSize: 20, 32 | textAnchor: "middle" 33 | }; 34 | const detailStyle = { 35 | fontSize: 12, 36 | textAnchor: "middle", 37 | fill: "#9a9a9a" 38 | }; 39 | return ( 40 | 41 | 49 | 50 | {value} 51 | 52 | 59 | {detail} 60 | 61 | 62 | ); 63 | }; 64 | 65 | ValueAxis.propTypes = { 66 | /** 67 | * Show or hide this 68 | */ 69 | visible: PropTypes.bool, 70 | 71 | /** 72 | * If values are numbers, use this format string 73 | */ 74 | value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 75 | 76 | /** 77 | * Use this to show what units are being used. It will appear below 78 | * the value. 79 | */ 80 | detail: PropTypes.string, 81 | 82 | /** 83 | * The width of the axis 84 | */ 85 | width: PropTypes.number, 86 | 87 | /** 88 | * [Internal] The height of the axis 89 | */ 90 | height: PropTypes.number 91 | }; 92 | 93 | ValueAxis.defaultProps = { 94 | visible: true 95 | }; 96 | 97 | export default ValueAxis; 98 | -------------------------------------------------------------------------------- /src/components/ValueList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import React from "react"; 12 | import PropTypes from "prop-types"; 13 | import merge from "merge"; 14 | 15 | const defaultBoxStyle = { 16 | fill: "#FEFEFE", 17 | stroke: "#DDD", 18 | opacity: 0.8 19 | }; 20 | 21 | const defaultTextStyle = { 22 | fontSize: 11, 23 | textAnchor: "left", 24 | fill: "#b0b0b0", 25 | pointerEvents: "none" 26 | }; 27 | 28 | const defaultTextStyleCentered = { 29 | fontSize: 11, 30 | textAnchor: "middle", 31 | fill: "#bdbdbd", 32 | pointerEvents: "none" 33 | }; 34 | 35 | function mergeStyles(style, isCentered) { 36 | return { 37 | boxStyle: merge(true, defaultBoxStyle, style.box ? style.box : {}), 38 | labelStyle: merge( 39 | true, 40 | isCentered ? defaultTextStyleCentered : defaultTextStyle, 41 | style.label ? style.label : {} 42 | ) 43 | }; 44 | } 45 | 46 | /** 47 | * Renders a list of values in svg 48 | * 49 | * +----------------+ 50 | * | Max 100 Gbps | 51 | * | Avg 26 Gbps | 52 | * +----------------+ 53 | */ 54 | const ValueList = props => { 55 | const { align, style, width, height } = props; 56 | const { boxStyle, labelStyle } = mergeStyles(style, align === "center"); 57 | 58 | if (!props.values.length) { 59 | return ; 60 | } 61 | 62 | const values = props.values.map((item, i) => { 63 | if (align === "left") { 64 | return ( 65 | 66 | 67 | {`${item.label}: `} 68 | {`${item.value}`} 69 | 70 | 71 | ); 72 | } 73 | 74 | const posx = parseInt(props.width / 2, 10); 75 | return ( 76 | 77 | 78 | {`${item.label}: `} 79 | {`${item.value}`} 80 | 81 | 82 | ); 83 | }); 84 | 85 | const box = ; 86 | 87 | return ( 88 | 89 | {box} 90 | {values} 91 | 92 | ); 93 | }; 94 | 95 | ValueList.defaultProps = { 96 | align: "center", 97 | width: 100, 98 | height: 100, 99 | pointerEvents: "none", 100 | style: { fill: "#FEFEFE", stroke: "#DDD", opacity: 0.8 } 101 | }; 102 | 103 | ValueList.propTypes = { 104 | /** 105 | * Where to position the label, either "left" or "center" within the box 106 | */ 107 | align: PropTypes.oneOf(["center", "left"]), 108 | 109 | /** 110 | * An array of label value pairs to render 111 | */ 112 | values: PropTypes.arrayOf( 113 | PropTypes.shape({ 114 | label: PropTypes.string, // eslint-disable-line 115 | value: PropTypes.oneOfType([ 116 | // eslint-disable-line 117 | PropTypes.number, 118 | PropTypes.string 119 | ]) 120 | }) 121 | ).isRequired, 122 | 123 | /** 124 | * CSS object to be applied to the ValueList surrounding box and the label (text). 125 | */ 126 | style: PropTypes.object, // eslint-disable-line 127 | 128 | /** 129 | * The width of the rectangle to render into 130 | */ 131 | width: PropTypes.number, 132 | 133 | /** 134 | * The height of the rectangle to render into 135 | */ 136 | height: PropTypes.number 137 | }; 138 | 139 | export default ValueList; 140 | -------------------------------------------------------------------------------- /src/entry.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | export AreaChart from "./components/AreaChart"; 12 | export BandChart from "./components/BandChart"; 13 | export BarChart from "./components/BarChart"; 14 | export Baseline from "./components/Baseline"; 15 | export BoxChart from "./components/BoxChart"; 16 | export Brush from "./components/Brush"; 17 | export ChartContainer from "./components/ChartContainer"; 18 | export ChartRow from "./components/ChartRow"; 19 | export Charts from "./components/Charts"; 20 | export EventChart from "./components/EventChart"; 21 | export EventMarker from "./components/EventMarker"; 22 | export LabelAxis from "./components/LabelAxis"; 23 | export Legend from "./components/Legend"; 24 | export LineChart from "./components/LineChart"; 25 | export MultiBrush from "./components/MultiBrush"; 26 | export Resizable from "./components/Resizable"; 27 | export ScatterChart from "./components/ScatterChart"; 28 | export styler from "./js/styler"; 29 | export TimeAxis from "./components/TimeAxis"; 30 | export TimeMarker from "./components/TimeMarker"; 31 | export TimeRangeMarker from "./components/TimeRangeMarker"; 32 | export ValueAxis from "./components/ValueAxis"; 33 | export ValueList from "./components/ValueList"; 34 | export YAxis from "./components/YAxis"; 35 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { Router, IndexRoute, Route, hashHistory } from "react-router"; 4 | 5 | import "./website/index.css"; 6 | import "react-select/dist/react-select.css"; 7 | 8 | import App from "./website/App"; 9 | import Guide from "./website/components/Guide"; 10 | import Example from "./website/components/Example"; 11 | import API from "./website/components/API"; 12 | 13 | import registerServiceWorker from "./registerServiceWorker"; 14 | 15 | ReactDOM.render( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | , 24 | document.getElementById("root") 25 | ); 26 | 27 | registerServiceWorker(); 28 | -------------------------------------------------------------------------------- /src/js/curve.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import { 12 | curveBasisClosed, 13 | curveBasisOpen, 14 | curveBasis, 15 | curveBundle, 16 | curveCardinalClosed, 17 | curveCardinalOpen, 18 | curveCardinal, 19 | curveCatmullRomClosed, 20 | curveCatmullRomOpen, 21 | curveCatmullRom, 22 | curveLinearClosed, 23 | curveLinear, 24 | curveMonotoneX, 25 | curveMonotoneY, 26 | curveNatural, 27 | curveStep, 28 | curveStepAfter, 29 | curveStepBefore 30 | } from "d3-shape"; 31 | 32 | export default { 33 | curveBasisClosed, 34 | curveBasisOpen, 35 | curveBasis, 36 | curveBundle, 37 | curveCardinalClosed, 38 | curveCardinalOpen, 39 | curveCardinal, 40 | curveCatmullRomClosed, 41 | curveCatmullRomOpen, 42 | curveCatmullRom, 43 | curveLinearClosed, 44 | curveLinear, 45 | curveMonotoneX, 46 | curveMonotoneY, 47 | curveNatural, 48 | curveStep, 49 | curveStepAfter, 50 | curveStepBefore 51 | }; 52 | -------------------------------------------------------------------------------- /src/js/interpolators.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import _ from "underscore"; 12 | 13 | export default class ScaleInterpolator { 14 | constructor(transition, ease, observer) { 15 | this.id = _.uniqueId("scaler"); 16 | this.ease = ease; 17 | this.transitionTime = transition; 18 | this.observer = observer; 19 | 20 | this.sourceScale = null; 21 | this.targetScale = null; 22 | this.cachedScaler = null; 23 | this.cacheKey = null; 24 | } 25 | 26 | update() { 27 | let animationTime = 0; 28 | 29 | if (!this.initialTimestamp) { 30 | this.initialTimestamp = window.performance.now(); 31 | } else { 32 | animationTime = window.performance.now() - this.initialTimestamp; 33 | } 34 | 35 | const animationPosition = this.transitionTime 36 | ? Math.min(animationTime / this.transitionTime, 1.0) 37 | : 1.0; 38 | 39 | if (!this.targetScale) { 40 | return; 41 | } 42 | 43 | if (this.observer) { 44 | const func1 = this.sourceScale; 45 | const func2 = this.targetScale; 46 | const te = this.ease(animationPosition); 47 | const scaler = x => { 48 | const a = func1(x); 49 | const b = func2(x); 50 | return a + (b - a) * te; 51 | }; 52 | this.observer(scaler); 53 | } 54 | 55 | if (animationPosition < 1.0) { 56 | // keep animating 57 | setTimeout(() => this.update(), 20); 58 | } else { 59 | // reset 60 | this.sourceScale = this.targetScale; 61 | this.targetScale = null; 62 | this.initialTimestamp = null; 63 | } 64 | } 65 | 66 | /** 67 | * A new (or initial) scale is set on the interpolator 68 | */ 69 | setScale(key, scale) { 70 | // Initial scale 71 | if (!this.sourceScale) { 72 | this.sourceScale = scale; 73 | return; 74 | } 75 | 76 | // 77 | // If there was already a scale, and a new scale is set 78 | // the this begins an animation across between the two 79 | // scales, assuming a transition time is provided. To do 80 | // this we set the new scale as the target and reset the 81 | // t to 0. (if there's no transition, jump to t = 1) 82 | // 83 | 84 | if (key !== this.cacheKey) { 85 | this.targetScale = scale; 86 | this.cachedScaler = null; 87 | this.initialTimestamp = null; 88 | setTimeout(() => this.update(), 0); 89 | } 90 | 91 | this.cacheKey = key; 92 | } 93 | 94 | /** 95 | * Returns a scaler, which is a function that scales the value 96 | * supplied to it. This return the scaler corresponding to the 97 | * source scale. Note that if a target scale is defined and the 98 | * interpolator is animating towards that target, the observer 99 | * callback will be called with the transitional scaler that can 100 | * be used to scale data to the intermediate state. 101 | */ 102 | scaler() { 103 | if (_.isNull(this.cachedScaler)) { 104 | this.cachedScaler = v => this.sourceScale(v); 105 | } 106 | return this.cachedScaler; 107 | } 108 | 109 | /** 110 | * Returns the d3 scale. It will return the target scale if present 111 | * otherwise the source scale. Note: this is the d3 internal scale. To 112 | * scale values, use the scaler. 113 | */ 114 | latestScale() { 115 | return this.targetScale ? this.targetScale : this.sourceScale; 116 | } 117 | 118 | /** 119 | * Returns the transition, as set in the constructor 120 | */ 121 | transition() { 122 | return this.transitionTime; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/js/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | export function scaleAsString(scale) { 12 | return `${scale.domain()}-${scale.range()}`; 13 | } 14 | 15 | // http://stackoverflow.com/a/28857255 16 | export function getElementOffset(element) { 17 | const de = document.documentElement; 18 | const box = element.getBoundingClientRect(); 19 | const top = box.top + window.pageYOffset - de.clientTop; 20 | const left = box.left + window.pageXOffset - de.clientLeft; 21 | return { top, left }; 22 | } 23 | -------------------------------------------------------------------------------- /src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === "localhost" || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === "[::1]" || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) 17 | ); 18 | 19 | export default function register() { 20 | if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { 21 | // The URL constructor is available in all browsers that support SW. 22 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 23 | if (publicUrl.origin !== window.location.origin) { 24 | // Our service worker won't work if PUBLIC_URL is on a different origin 25 | // from what our page is served on. This might happen if a CDN is used to 26 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 27 | return; 28 | } 29 | 30 | window.addEventListener("load", () => { 31 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 32 | 33 | if (!isLocalhost) { 34 | // Is not local host. Just register service worker 35 | registerValidSW(swUrl); 36 | } else { 37 | // This is running on localhost. Lets check if a service worker still exists or not. 38 | checkValidServiceWorker(swUrl); 39 | } 40 | }); 41 | } 42 | } 43 | 44 | function registerValidSW(swUrl) { 45 | navigator.serviceWorker 46 | .register(swUrl) 47 | .then(registration => { 48 | registration.onupdatefound = () => { 49 | const installingWorker = registration.installing; 50 | installingWorker.onstatechange = () => { 51 | if (installingWorker.state === "installed") { 52 | if (navigator.serviceWorker.controller) { 53 | // At this point, the old content will have been purged and 54 | // the fresh content will have been added to the cache. 55 | // It's the perfect time to display a "New content is 56 | // available; please refresh." message in your web app. 57 | console.log("New content is available; please refresh."); 58 | } else { 59 | // At this point, everything has been precached. 60 | // It's the perfect time to display a 61 | // "Content is cached for offline use." message. 62 | console.log("Content is cached for offline use."); 63 | } 64 | } 65 | }; 66 | }; 67 | }) 68 | .catch(error => { 69 | console.error("Error during service worker registration:", error); 70 | }); 71 | } 72 | 73 | function checkValidServiceWorker(swUrl) { 74 | // Check if the service worker can be found. If it can't reload the page. 75 | fetch(swUrl) 76 | .then(response => { 77 | // Ensure service worker exists, and that we really are getting a JS file. 78 | if ( 79 | response.status === 404 || 80 | response.headers.get("content-type").indexOf("javascript") === -1 81 | ) { 82 | // No service worker found. Probably a different app. Reload the page. 83 | navigator.serviceWorker.ready.then(registration => { 84 | registration.unregister().then(() => { 85 | window.location.reload(); 86 | }); 87 | }); 88 | } else { 89 | // Service worker found. Proceed as normal. 90 | registerValidSW(swUrl); 91 | } 92 | }) 93 | .catch(() => { 94 | console.log("No internet connection found. App is running in offline mode."); 95 | }); 96 | } 97 | 98 | export function unregister() { 99 | if ("serviceWorker" in navigator) { 100 | navigator.serviceWorker.ready.then(registration => { 101 | registration.unregister(); 102 | }); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/website/App.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | 12 | .chartcontainer.chartrow { 13 | background: none; 14 | } 15 | 16 | 17 | /* Examples navigation */ 18 | body { 19 | padding-top: 100px; 20 | } 21 | 22 | p { 23 | color: #333; 24 | overflow: hidden; 25 | line-height: 1.6; 26 | word-wrap: break-word; 27 | letter-spacing: .2px; 28 | font-size: 1.6rem; 29 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 30 | } 31 | 32 | h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { 33 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 34 | font-weight: bold; 35 | color: #333; 36 | } 37 | 38 | .navbar-fixed-top { 39 | background: #000000 !important; 40 | border-bottom-style: solid !important; 41 | border-bottom-color: #2DB3D1 !important; 42 | border-bottom-width: 5px !important; 43 | } 44 | 45 | .navbar-brand { 46 | margin-top: 8px; 47 | font-size: 24px; 48 | } 49 | 50 | .docs-sidenav { 51 | margin-top: 20px; 52 | margin-bottom: 20px; 53 | } 54 | 55 | .docs-sidebar .nav > li > a { 56 | color: #CCC; 57 | background: #FFF; 58 | display: block; 59 | padding: 4px 20px; 60 | font-size: 15px; 61 | font-weight: 500; 62 | } 63 | 64 | .docs-sidebar .nav > li > a.active { 65 | color: #000; 66 | font-weight: 600; 67 | background: #FFF; 68 | border-bottom-style: solid; 69 | border-bottom-color: #2DB3D1; 70 | } 71 | 72 | /* 73 | * Global add-ons 74 | */ 75 | 76 | .sub-header { 77 | padding-bottom: 10px; 78 | border-bottom: 1px solid #eee; 79 | } 80 | 81 | /* 82 | * Top navigation 83 | * Hide default border to remove 1px line. 84 | */ 85 | .navbar-fixed-top { 86 | border: 0; 87 | } 88 | 89 | /* 90 | * Sidebar 91 | */ 92 | 93 | /* Hide for mobile, show later */ 94 | .sidebar { 95 | display: none; 96 | } 97 | @media (min-width: 768px) { 98 | .sidebar { 99 | position: fixed; 100 | top: 51px; 101 | bottom: 0; 102 | left: 0; 103 | z-index: 1000; 104 | display: block; 105 | padding: 20px; 106 | overflow-x: hidden; 107 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 108 | background-color: #f5f5f5; 109 | border-right: 1px solid #eee; 110 | } 111 | } 112 | 113 | /* Sidebar navigation */ 114 | .nav-sidebar { 115 | margin-right: -21px; /* 20px padding + 1px border */ 116 | margin-bottom: 20px; 117 | margin-left: -20px; 118 | } 119 | .nav-sidebar > li > a { 120 | padding-right: 20px; 121 | padding-left: 27px; 122 | } 123 | .nav-sidebar > li > a.active { 124 | padding-left: 20px; 125 | border-left: #2DB3D1; 126 | border-left-style: solid; 127 | border-left-width: 7px; 128 | background: #ECECEC; 129 | } 130 | 131 | .nav-sidebar > .active > a, 132 | .nav-sidebar > .active > a:hover, 133 | .nav-sidebar > .active > a:focus { 134 | color: #fff; 135 | background-color: #428bca; 136 | } 137 | 138 | .sidebar-heading { 139 | padding-left: 0px; 140 | text-transform: uppercase; 141 | font-weight: 800; 142 | } 143 | 144 | /* 145 | * Main content 146 | */ 147 | 148 | .main { 149 | padding: 20px; 150 | } 151 | @media (min-width: 768px) { 152 | .main { 153 | padding-right: 40px; 154 | padding-left: 40px; 155 | } 156 | } 157 | .main .page-header { 158 | margin-top: 0; 159 | } 160 | -------------------------------------------------------------------------------- /src/website/components/API.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | /* eslint max-len:0 */ 12 | 13 | import React from "react"; 14 | import createReactClass from "create-react-class"; 15 | import { Link } from "react-router"; 16 | import _ from "underscore"; 17 | 18 | import Highlighter from "./highlighter"; 19 | import APIDoc from "./APIDoc"; 20 | 21 | import Meta from "../packages/charts/examples/examples.json"; 22 | import Examples from "../packages/charts/examples/examples.js"; 23 | import docsFile from "../packages/charts/api/docs.json"; 24 | 25 | class Example extends React.Component { 26 | render() { 27 | const style = { 28 | display: "inline-block", 29 | margin: 5, 30 | padding: 20, 31 | borderStyle: "solid", 32 | borderWidth: 1, 33 | borderColor: "#DDD", 34 | width: 160, 35 | height: 160 36 | }; 37 | const { example } = this.props; 38 | const name = example.key; 39 | const imgName = `${name}_thumbnail`; 40 | const img = Examples[imgName]; 41 | const link = {example.value.title}; 42 | return ( 43 |
50 |
51 | {`${name}`} 52 |
53 |
{link}
54 |
55 | ); 56 | } 57 | } 58 | 59 | class TaggedExamples extends React.Component { 60 | render() { 61 | const exampleList = []; 62 | _.forEach(Meta, (value, key) => { 63 | const tags = value.tags; 64 | if (_.contains(tags, this.props.tag)) { 65 | exampleList.push({ key, value }); 66 | } 67 | }); 68 | const examples = exampleList.map((example, i) => { 69 | return ; 70 | }); 71 | 72 | if (examples.length > 0) { 73 | return ( 74 |
75 |

Examples

76 |
83 | {examples} 84 |
85 |
86 | ); 87 | } else { 88 | return
; 89 | } 90 | } 91 | } 92 | 93 | export default createReactClass({ 94 | displayName: "API", 95 | mixins: [Highlighter], 96 | 97 | render() { 98 | const component = this.props.params.component; 99 | const path = `src/components/${component}.js`; 100 | 101 | if (!_.has(docsFile, path)) { 102 | return
API could not be found
; 103 | } 104 | const title = component; 105 | return ( 106 |
107 |

{title}

108 |
109 |
110 | 111 |
112 |
113 |
114 |
115 |
116 | 117 |
118 |
119 |
120 | ); 121 | } 122 | }); 123 | -------------------------------------------------------------------------------- /src/website/components/APIDoc.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import _ from "underscore"; 3 | import Markdown from "react-markdown"; 4 | 5 | import chartsDocs from "../packages/charts/api/docs.json"; 6 | 7 | /** 8 | * Displays API data from the docs.json file 9 | */ 10 | export default class extends React.Component { 11 | renderArrayOf(value) { 12 | if (value.name === "shape") { 13 | return ( 14 | "shape {" + 15 | _.map(value.value, (value, key) => { 16 | return key; 17 | }).join(", ") + 18 | "}" 19 | ); 20 | } else { 21 | return `array of ${value.name}s`; 22 | } 23 | } 24 | 25 | renderPropType(type) { 26 | if (!type) { 27 | return "unknown type"; 28 | } 29 | if (type.name === "enum") { 30 | return ( 31 | "enum (" + 32 | _.map(type.value, value => { 33 | return value.value; 34 | }).join(", ") + 35 | ")" 36 | ); 37 | } 38 | if (type.name === "union") { 39 | return ( 40 | "one of (" + 41 | _.map(type.value, value => { 42 | return this.renderPropType(value); 43 | }).join(", ") + 44 | ")" 45 | ); 46 | } 47 | if (type.name === "instanceOf") { 48 | return `instance of a ${type.value}`; 49 | } 50 | if (type.name === "arrayOf") { 51 | return `array of ${this.renderArrayOf(type.value)}`; 52 | } 53 | if (type.name === "shapes") { 54 | return ( 55 | `shape of {` + 56 | _.map(type.value, (value, key) => { 57 | return key; 58 | }).join(", ") + 59 | "}" 60 | ); 61 | } else { 62 | return `${type.name}`; 63 | } 64 | } 65 | 66 | renderProps(props) { 67 | const propNameStyle = { 68 | padding: 3, 69 | marginRight: 5, 70 | borderRadius: 2, 71 | fontFamily: "'Fira Mono',Menlo,monospace", 72 | color: "#c7254e", 73 | background: "#f9f2f4", 74 | letterSpacing: -0.015 75 | }; 76 | 77 | const infoStyle = { 78 | color: "#626466", 79 | fontFamily: "Fira Sans,Helvetica Neue,Helvetica,Arial,sans-serif", 80 | fontSize: 16, 81 | lineHeight: 1.625 82 | }; 83 | 84 | const typeStyle = { 85 | color: "#626466", 86 | background: "#F5F4F4", 87 | fontFamily: "Fira Sans,Helvetica Neue,Helvetica,Arial,sans-serif", 88 | fontSize: 16, 89 | lineHeight: 1.625 90 | }; 91 | 92 | return _.map(props, (prop, propName) => ( 93 |
94 | {propName} 95 | {prop.defaultValue ? ` = ${prop.defaultValue.value}` : ""} 96 | {prop.required ? "Required" : ""} 97 |
98 | 99 |
100 | Type: {this.renderPropType(prop.type)} 101 |
102 |
103 | )); 104 | } 105 | 106 | render() { 107 | const file = this.props.file; 108 | const docs = chartsDocs[file]; 109 | return ( 110 |
111 |

{docs.displayName} API

112 | 113 |
114 |

{docs.displayName} Props

115 |
116 | {docs.props ? this.renderProps(docs.props) : "none"} 117 |
118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/website/components/Example.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import React from "react"; 12 | import createReactClass from "create-react-class"; 13 | import Markdown from "react-markdown"; 14 | import Highlighter from "./highlighter"; 15 | import Examples from "../packages/charts/examples/examples.js"; 16 | import Meta from "../packages/charts/examples/examples.json"; 17 | 18 | export default createReactClass({ 19 | displayName: "Example", 20 | mixins: [Highlighter], 21 | 22 | getInitialState() { 23 | return { 24 | markdown: null 25 | }; 26 | }, 27 | 28 | fetchMarkdownForProps(props) { 29 | window.scrollTo(0, 0); 30 | const exampleName = props.params.example; 31 | const markdownFile = Examples[`${exampleName}_docs`]; 32 | fetch(markdownFile) 33 | .then(response => { 34 | return response.text(); 35 | }) 36 | .then(markdown => { 37 | this.setState({ markdown }); 38 | }); 39 | }, 40 | 41 | componentDidMount() { 42 | this.fetchMarkdownForProps(this.props); 43 | }, 44 | 45 | componentWillReceiveProps(nextProps) { 46 | this.fetchMarkdownForProps(nextProps); 47 | }, 48 | 49 | renderMarkdown() { 50 | if (this.state.markdown) { 51 | return ( 52 |
53 |
54 | 55 |
56 |
57 | ); 58 | } else { 59 | return ( 60 |
61 |
Loading...
62 |
63 | ); 64 | } 65 | }, 66 | 67 | render() { 68 | const exampleName = this.props.params.example; 69 | const ExampleMetaData = Meta[exampleName]; 70 | const Component = Examples[exampleName]; 71 | const sourceCode = `https://github.com/esnet/react-timeseries-charts/tree/master/src/website/packages/charts/examples/${exampleName}/Index.js`; 72 | 73 | return ( 74 |
75 |
76 |
77 |
78 |
79 |

{ExampleMetaData.title}

80 |

81 | 87 | Source Code » 88 | 89 |

90 |

{ExampleMetaData.description}

91 |
92 |
93 |
94 | 95 |
96 | {this.renderMarkdown()} 97 |
98 |
99 |
100 | ); 101 | } 102 | }); 103 | -------------------------------------------------------------------------------- /src/website/components/Guide.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import React from "react"; 12 | import createReactClass from "create-react-class"; 13 | import Highlighter from "./highlighter"; 14 | import Markdown from "react-markdown"; 15 | 16 | import Guides from "../packages/charts/guides/guides"; 17 | import logo from "../packages/charts/logo.png"; 18 | 19 | export default createReactClass({ 20 | displayName: "Guide", 21 | mixins: [Highlighter], 22 | 23 | getInitialState() { 24 | return { 25 | markdown: null 26 | }; 27 | }, 28 | 29 | componentDidMount() { 30 | window.scrollTo(0, 0); 31 | const guideName = this.props.params.doc || "intro"; 32 | console.log(guideName); 33 | const markdownFile = Guides[guideName]; 34 | fetch(markdownFile) 35 | .then(response => { 36 | return response.text(); 37 | }) 38 | .then(markdown => { 39 | this.setState({ markdown }); 40 | }); 41 | this.setState({ markdown: null }); 42 | }, 43 | 44 | componentWillReceiveProps(nextProps) { 45 | window.scrollTo(0, 0); 46 | const guideName = nextProps.params.doc || "intro"; 47 | const markdownFile = Guides[guideName]; 48 | fetch(markdownFile) 49 | .then(response => { 50 | return response.text(); 51 | }) 52 | .then(markdown => { 53 | this.setState({ markdown }); 54 | }); 55 | this.setState({ markdown: null }); 56 | }, 57 | 58 | render() { 59 | if (this.state.markdown !== null) { 60 | return ( 61 |
62 |
63 |
64 | ESnet 65 |
66 |
67 | 68 |
69 |
70 |
71 | ); 72 | } else { 73 | return ( 74 |
75 |
76 | ESnet 77 |
78 |
79 |
80 | ); 81 | } 82 | } 83 | }); 84 | -------------------------------------------------------------------------------- /src/website/components/highlighter.js: -------------------------------------------------------------------------------- 1 | export default { 2 | highlightCodeBlocks() { 3 | const els = document.querySelectorAll("pre code"); 4 | for (let i = 0; i < els.length; i++) { 5 | if (!els[i].classList.contains("hljs")) { 6 | window.hljs.highlightBlock(els[i]); 7 | } 8 | } 9 | }, 10 | componentDidMount() { 11 | this.highlightCodeBlocks(); 12 | }, 13 | componentDidUpdate() { 14 | this.highlightCodeBlocks(); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /src/website/img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/img/github.png -------------------------------------------------------------------------------- /src/website/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/img/logo.png -------------------------------------------------------------------------------- /src/website/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | 7 | pre { 8 | display: block; 9 | margin: 0 0 10px; 10 | padding: 0px; 11 | font-size: 13px; 12 | line-height: 1.42857143; 13 | word-break: break-all; 14 | word-wrap: break-word; 15 | color: #333333; 16 | background-color: #f8f8f8; 17 | border-style: none; 18 | border-radius: 0px; 19 | border-left-color: #64a0af; 20 | border-left-style: solid; 21 | border-left-width: 3px; 22 | padding-left: 10px; 23 | } -------------------------------------------------------------------------------- /src/website/packages/charts/examples/barchart/Index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | /* eslint max-len:0 */ 12 | 13 | import React from "react"; 14 | 15 | // Pond 16 | import { TimeSeries, Index } from "pondjs"; 17 | 18 | // Imports from the charts library 19 | import ChartContainer from "../../../../../components/ChartContainer"; 20 | import ChartRow from "../../../../../components/ChartRow"; 21 | import Charts from "../../../../../components/Charts"; 22 | import YAxis from "../../../../../components/YAxis"; 23 | import BarChart from "../../../../../components/BarChart"; 24 | import Resizable from "../../../../../components/Resizable"; 25 | import styler from "../../../../../js/styler"; 26 | 27 | /// Ignore these next two lines 28 | import barchart_docs from "./barchart_docs.md"; 29 | import barchart_thumbnail from "./barchart_thumbnail.png"; 30 | /// 31 | 32 | const data = [ 33 | ["2017-01-24T00:00", 0.01], 34 | ["2017-01-24T01:00", 0.13], 35 | ["2017-01-24T02:00", 0.07], 36 | ["2017-01-24T03:00", 0.04], 37 | ["2017-01-24T04:00", 0.33], 38 | ["2017-01-24T05:00", 0], 39 | ["2017-01-24T06:00", 0], 40 | ["2017-01-24T07:00", 0], 41 | ["2017-01-24T08:00", 0.95], 42 | ["2017-01-24T09:00", 1.12], 43 | ["2017-01-24T10:00", 0.66], 44 | ["2017-01-24T11:00", 0.06], 45 | ["2017-01-24T12:00", 0.3], 46 | ["2017-01-24T13:00", 0.05], 47 | ["2017-01-24T14:00", 0.5], 48 | ["2017-01-24T15:00", 0.24], 49 | ["2017-01-24T16:00", 0.02], 50 | ["2017-01-24T17:00", 0.98], 51 | ["2017-01-24T18:00", 0.46], 52 | ["2017-01-24T19:00", 0.8], 53 | ["2017-01-24T20:00", 0.39], 54 | ["2017-01-24T21:00", 0.4], 55 | ["2017-01-24T22:00", 0.39], 56 | ["2017-01-24T23:00", 0.28] 57 | ]; 58 | 59 | const series = new TimeSeries({ 60 | name: "hilo_rainfall", 61 | columns: ["index", "precip"], 62 | points: data.map(([d, value]) => [Index.getIndexString("1h", new Date(d)), value]) 63 | }); 64 | 65 | class barchart extends React.Component { 66 | static displayName = "BarChartExample"; 67 | 68 | render() { 69 | const style = styler([{ key: "precip", color: "#A5C8E1", selected: "#2CB1CF" }]); 70 | 71 | return ( 72 |
73 |
74 |
75 | BarChart 76 |
77 |
78 |
79 |
80 |
81 | 82 | 83 | 84 | 93 | 94 | 102 | 103 | 104 | 105 | 106 |
107 |
108 |
109 | ); 110 | } 111 | } 112 | 113 | // Export example 114 | export default { barchart, barchart_docs, barchart_thumbnail }; 115 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/barchart/barchart_docs.md: -------------------------------------------------------------------------------- 1 | 2 | In this example we have a day's worth of rainfall data from Hilo, HI: 3 | 4 | ``` 5 | const data = [ 6 | ["2017-01-24T00:00", 0.01], 7 | ["2017-01-24T01:00", 0.13], 8 | ["2017-01-24T02:00", 0.07], 9 | ["2017-01-24T03:00", 0.04], 10 | ["2017-01-24T04:00", 0.33], 11 | ["2017-01-24T05:00", 0.2], 12 | ["2017-01-24T06:00", 0.08], 13 | ["2017-01-24T07:00", 0.54], 14 | ["2017-01-24T08:00", 0.95], 15 | ["2017-01-24T09:00", 1.12], 16 | ["2017-01-24T10:00", 0.66], 17 | ["2017-01-24T11:00", 0.06], 18 | ["2017-01-24T12:00", 0.3], 19 | ["2017-01-24T13:00", 0.05], 20 | ["2017-01-24T14:00", 0.5], 21 | ["2017-01-24T15:00", 0.24], 22 | ["2017-01-24T16:00", 0.02], 23 | ["2017-01-24T17:00", 0.98], 24 | ["2017-01-24T18:00", 0.46], 25 | ["2017-01-24T19:00", 0.8], 26 | ["2017-01-24T20:00", 0.39], 27 | ["2017-01-24T21:00", 0.4], 28 | ["2017-01-24T22:00", 0.39], 29 | ["2017-01-24T23:00", 0.28] 30 | ]; 31 | ``` 32 | 33 | We want to take that data and make a simple BarChart from it. 34 | 35 | This isn't the exact format we need for our chart. Firstly, like other charts, it needs to be a [Pond TimeSeries](http://software.es.net/pond/#/timeseries). Secondly, the TimeSeries is constructed from IndexedEvents. That is, each point in the TimeSeries is referenced not by a timestamp but by an "index". Each index is a string that represents a range of time. In this case each index will represent a specific hour. 36 | 37 | Note that often you will either pass the indexed data from the server, or a more dense timeseries will be aggregated with Pond to these indexed events (see the realtime example). 38 | 39 | In this case we can use Pond do do a simple transform from dates to index string: 40 | 41 | ``` 42 | const series = new TimeSeries({ 43 | name: "hilo_rainfall", 44 | columns: ["index", "precip"], 45 | points: data.map(([d, value]) => [ 46 | Index.getIndexString("1h", new Date(d)), 47 | value 48 | ]) 49 | }); 50 | ``` 51 | 52 | The resulting TimeSeries looks like this: 53 | 54 | ``` 55 | series = { 56 | "name": "HI_ASOS", 57 | "utc": true, 58 | "columns": ["index", "precip"], 59 | "points": [ 60 | ["1h-412568", 0.01], 61 | ["1h-412569", 0.13], 62 | ["1h-412570", 0.07], 63 | ["1h-412571", 0.04], 64 | ["1h-412572", 0.33], 65 | ["1h-412573", 0.2, 66 | ["1h-412574", 0.08], 67 | ["1h-412575", 0.54], 68 | ["1h-412576", 0.95], 69 | ["1h-412577", 1.12], 70 | ["1h-412578", 0.66], 71 | ["1h-412579", 0.06], 72 | ["1h-412580", 0.3, 73 | ["1h-412581", 0.05], 74 | ["1h-412582", 0.5, 75 | ["1h-412583", 0.24], 76 | ["1h-412584", 0.02], 77 | ["1h-412585", 0.98], 78 | ["1h-412586", 0.46], 79 | ["1h-412587", 0.8, 80 | ["1h-412588", 0.39], 81 | ["1h-412589", 0.4, 82 | ["1h-412590", 0.39], 83 | ["1h-412591", 0.28] 84 | ] 85 | } 86 | ``` 87 | 88 | The index strings you see here, such as "1h-412568", refer to the specific hour in a way that the BarChart will understand. (The string means that this hour is the 412568th hour since the Jan 1, 1970 UTC). 89 | 90 | Now that we have a series we can render that: 91 | 92 | ``` 93 | const Example = React.createClass({ 94 | displayName: "BarChartExample", 95 | render() { 96 | const style = styler([ 97 | { key: "precip", color: "#A5C8E1"}, 98 | ]); 99 | 100 | return ( 101 |
102 |
103 |
104 | BarChart 105 |
106 |
107 |
108 |
109 |
110 | 111 | 112 | 113 | 122 | 123 | 130 | 131 | 132 | 133 | 134 |
135 |
136 |
137 | ); 138 | } 139 | }); 140 | ``` 141 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/barchart/barchart_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/barchart/barchart_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/baselines/Index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | /* eslint max-len:0 */ 12 | 13 | import React from "react"; 14 | import { TimeSeries } from "pondjs"; 15 | 16 | import ChartContainer from "../../../../../components/ChartContainer"; 17 | import ChartRow from "../../../../../components/ChartRow"; 18 | import Charts from "../../../../../components/Charts"; 19 | import YAxis from "../../../../../components/YAxis"; 20 | import LineChart from "../../../../../components/LineChart"; 21 | import Baseline from "../../../../../components/Baseline"; 22 | import Resizable from "../../../../../components/Resizable"; 23 | 24 | import baselines_docs from "./baselines_docs.md"; 25 | import baselines_thumbnail from "./baselines_thumbnail.png"; 26 | 27 | // Data 28 | const data = require("./usd_vs_euro.json"); 29 | const points = data.widget[0].data.reverse(); 30 | const series = new TimeSeries({ 31 | name: "USD_vs_EURO", 32 | columns: ["time", "value"], 33 | points 34 | }); 35 | 36 | const style = { 37 | value: { 38 | stroke: "#a02c2c", 39 | opacity: 0.2 40 | } 41 | }; 42 | 43 | const baselineStyle = { 44 | line: { 45 | stroke: "steelblue", 46 | strokeWidth: 1, 47 | opacity: 0.4, 48 | strokeDasharray: "none" 49 | }, 50 | label: { 51 | fill: "steelblue" 52 | } 53 | }; 54 | 55 | const baselineStyleLite = { 56 | line: { 57 | stroke: "steelblue", 58 | strokeWidth: 1, 59 | opacity: 0.5 60 | }, 61 | label: { 62 | fill: "steelblue" 63 | } 64 | }; 65 | 66 | const baselineStyleExtraLite = { 67 | line: { 68 | stroke: "steelblue", 69 | strokeWidth: 1, 70 | opacity: 0.2, 71 | strokeDasharray: "1,1" 72 | }, 73 | label: { 74 | fill: "steelblue" 75 | } 76 | }; 77 | 78 | class baselines extends React.Component { 79 | state = { 80 | tracker: null, 81 | timerange: series.range() 82 | }; 83 | 84 | handleTrackerChanged = tracker => { 85 | this.setState({ tracker }); 86 | }; 87 | 88 | handleTimeRangeChange = timerange => { 89 | this.setState({ timerange }); 90 | }; 91 | 92 | render() { 93 | return ( 94 | 95 | 102 | 103 | 111 | 112 | 113 | 120 | 127 | 132 | 137 | 144 | 145 | 146 | 147 | 148 | ); 149 | } 150 | } 151 | 152 | // Export example 153 | export default { baselines, baselines_docs, baselines_thumbnail }; 154 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/baselines/baselines_docs.md: -------------------------------------------------------------------------------- 1 | 2 | In this simple `BaseLine` example we have a `TimeSeries` that we plot with a `LineChart`. Using pond.js we can easily extract statistic for the plot, such as max, min, avg and stdev. This example then uses the `Baseline` to overlay this information on top of the `LineChart`. This example also shows custom TimeAxis formatting, by passing in a d3 time format string to the `ChartContainer`. 3 | 4 | ```js 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ``` 23 | 24 | ## Styling 25 | 26 | The baseline can also be styled 27 | 28 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/baselines/baselines_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/baselines/baselines_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/climate/Index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/climate/Index.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/climate/climate_docs.md: -------------------------------------------------------------------------------- 1 | 2 | [http://climate.nasa.gov/vital-signs/global-temperature/ 3 | ](http://climate.nasa.gov/vital-signs/global-temperature/) 4 | 5 | Data source: NASA's Goddard Institute for Space Studies (GISS). 6 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/climate/climate_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/climate/climate_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/continents/continents_docs.md: -------------------------------------------------------------------------------- 1 | This example shows a stacked area chart. Stacking can be configured both above and below the axis, but in this example we just stack up. 2 | 3 | This example also shows the use of the `Styler` to build the `AreaChart` style given a list of `columnNames` and a `scheme`: 4 | 5 | const styler = Styler(columnNames, scheme); 6 | 7 | The `scheme` is a string corresponding to one of the color brewer sets. In this example, it is selected by the user with the pull down. 8 | 9 | Alternatively, the styler could be set with a custom list of colors like this: 10 | 11 | const customColorsList = [ 12 | "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", 13 | "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", 14 | "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", 15 | "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" 16 | ]; 17 | const styler = Styler(columnNames.map((c, i) => ({ 18 | key: c, 19 | color: customColorsList[i] 20 | }))); 21 | 22 | This example also shows how to set the interpolation to any of D3's interpolate functions, in this case `curveBasis`. 23 | 24 | Here is the chart defined in the component `render()` function: 25 | 26 | 27 | 28 | 34 | 35 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/continents/continents_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/continents/continents_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/currency/currency_docs.md: -------------------------------------------------------------------------------- 1 | This example shows multiple `LineCharts` built from multiple columns in a single `TimeSeries` using the `columns` prop. 2 | 3 | This example also shows the use of the `Styler` to build the `LineChart` and `Legend` style for the two columns ("aud" and "euro"): 4 | 5 | const styler = Styler([ 6 | {key: "aud", color: "steelblue", width: 1, dashed: true}, 7 | {key: "euro", color: "#F68B24", width: 2} 8 | ]); 9 | 10 | The `Legend` is rendered as follows, supporting highlighting and selection. In this way these states are synchronized between the `Legend` and the `LineChart`: 11 | 12 | this.setState({highlight})} 18 | selection={this.state.selection} 19 | onSelectionChange={selection => this.setState({selection})} 20 | categories={[ 21 | {key: "aud", label: "AUD", value: audValue}, 22 | {key: "euro", label: "Euro", value: euroValue} 23 | ]} /> 24 | 25 | The LineChart itself is rendered like this: 26 | 27 | this.setState({ selection: null })} 36 | enablePanZoom={true} 37 | onTimeRangeChanged={this.handleTimeRangeChange} 38 | onMouseMove={(x, y) => this.handleMouseMove(x, y)} 39 | minDuration={1000 * 60 * 60 * 24 * 30} 40 | > 41 | 42 | 51 | 52 | 61 | this.setState({ highlight }) 62 | } 63 | selection={this.state.selection} 64 | onSelectionChange={selection => 65 | this.setState({ selection }) 66 | } 67 | /> 68 | 69 | 75 | 76 | 77 | 78 | 79 | The `CrossHairs` component isn't part of react-timeseries-charts. It is defined like this: 80 | 81 | ``` 82 | class CrossHairs extends React.Component { 83 | render() { 84 | const { x, y } = this.props; 85 | const style = { pointerEvents: "none", stroke: "#ccc" }; 86 | if (!_.isNull(x) && !_.isNull(y)) { 87 | return ( 88 | 89 | 90 | 91 | 92 | ); 93 | } else { 94 | return ; 95 | } 96 | } 97 | } 98 | ``` 99 | 100 | You can create any chart you want like this. The important thing about this is that a set of props will be supplied to the component when it is rendered. Those include the dimensions of the chart with `width` and `height`, and the scales `yScale` and `timeScale`. 101 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/currency/currency_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/currency/currency_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/cycling/cycling.css: -------------------------------------------------------------------------------- 1 | rect.extent { 2 | fill: steelblue; 3 | opacity: 0.25; 4 | } -------------------------------------------------------------------------------- /src/website/packages/charts/examples/cycling/cycling_docs.md: -------------------------------------------------------------------------------- 1 | In this example we display this data in two ways: 2 | 1. as two overlaid line charts using two separate axes, or 3 | 2. as a channel display where the user instead scrubs the data to see the value. 4 | 5 | It demonstrates: 6 | * Broken lines for missing data 7 | * Pan and zoom over the dataset: Drag to pan, scrollwheel to zoom 8 | * Brushing over an elevation chart: drag and resize the blue rectangle to pan and zoom 9 | * Hover info boxes, in the multi-axis mode 10 | * Channel display using LabelAxis and ValueAxis 11 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/cycling/cycling_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/cycling/cycling_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/ddos/ddos_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/ddos/ddos_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/examples.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | // 12 | // Export all of the examples 13 | // 14 | 15 | import baselines from "./baselines/Index"; 16 | import barchart from "./barchart/Index"; 17 | import realtime from "./realtime/Index"; 18 | import continents from "./continents/Index"; 19 | import currency from "./currency/Index"; 20 | import cycling from "./cycling/Index"; 21 | import ddos from "./ddos/Index"; 22 | import outages from "./outages/Index"; 23 | import stockchart from "./stockchart/Index"; 24 | import traffic from "./traffic/Index"; 25 | import weather from "./weather/Index"; 26 | import wind from "./wind/Index"; 27 | import volume from "./volume/Index"; 28 | import nyc from "./nyc/Index"; 29 | import climate from "./climate/Index"; 30 | import trend from "./trend/Index"; 31 | 32 | export default { 33 | ...realtime, 34 | ...baselines, 35 | ...barchart, 36 | ...continents, 37 | ...currency, 38 | ...cycling, 39 | ...ddos, 40 | ...outages, 41 | ...stockchart, 42 | ...traffic, 43 | ...weather, 44 | ...wind, 45 | ...volume, 46 | ...nyc, 47 | ...climate, 48 | ...trend 49 | }; 50 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "realtime": { 3 | "title": "Realtime", 4 | "description": "This example demonstrates using the pond.js library in conjunction with the charts library to do client side time series processing.", 5 | "tags": [ 6 | "Realtime", 7 | "BarChart", 8 | "ScatterChart", 9 | "pondjs" 10 | ] 11 | }, 12 | "barchart": { 13 | "title": "Simple BarChart", 14 | "description": "This example shows a simple BarChart.", 15 | "tags": [ 16 | "BarChart", 17 | "pondjs" 18 | ] 19 | }, 20 | "baselines": { 21 | "title": "Baseline demo", 22 | "description": "This example demonstrates drawing multiple Baselines across a LineChart.", 23 | "tags": [ 24 | "LineChart", 25 | "pondjs", 26 | "Baseline" 27 | ] 28 | }, 29 | "continents": { 30 | "title": "Stacked AreaCharts", 31 | "description": "This example demonstrates stacking of AreaCharts along with use of the Styler.", 32 | "tags": [ 33 | "AreaChart", 34 | "Legend", 35 | "styler" 36 | ] 37 | }, 38 | "currency": { 39 | "title": "Currency example", 40 | "description": "This example demonstrates plotting multiple LineCharts on top of each other. The LineCharts are selectable and the time scale can be panned and zoomed.", 41 | "tags": [ 42 | "LineChart", 43 | "Baseline", 44 | "Legend", 45 | "styler", 46 | "panzoom", 47 | "selectable" 48 | ] 49 | }, 50 | "cycling": { 51 | "title": "Cycling example", 52 | "description": "A multi-channel visualization of a bike ride. Features pan and zoom and brushing of 18,000+ points per channel.", 53 | "tags": [ 54 | "LineChart", 55 | "AreaChart", 56 | "BoxChart", 57 | "Legend", 58 | "styler", 59 | "panzoom", 60 | "Brush", 61 | "channels", 62 | "infobox", 63 | "TimeMarker" 64 | ] 65 | }, 66 | "ddos": { 67 | "title": "DDoS attack", 68 | "description": "A LineChart example featuring scale transitions, an interactive legend, and drag to zoom", 69 | "tags": [ 70 | "LineChart", 71 | "Legend", 72 | "styler", 73 | "dragzoom" 74 | ] 75 | }, 76 | "outages": { 77 | "title": "Outage events", 78 | "description": "Example showing the experimental EventChart.", 79 | "tags": [ 80 | "LabelAxis", 81 | "EventChart", 82 | "panzoom" 83 | ] 84 | }, 85 | "stockchart": { 86 | "title": "Stockchart", 87 | "description": "Example in progress to build a stock chart. Demonstrates log to linear scale transitions.", 88 | "tags": [ 89 | "LineChart", 90 | "BarChart", 91 | "panzoom" 92 | ] 93 | }, 94 | "traffic": { 95 | "title": "Network Traffic example", 96 | "description": "Example of how ESnet uses the charts library to display network traffic.", 97 | "tags": [ 98 | "AreaChart", 99 | "panzoom" 100 | ] 101 | }, 102 | "trend": { 103 | "title": "D3's trend example", 104 | "description": "Example of displaying percentile ranges in different ways.", 105 | "tags": [ 106 | "BoxChart", 107 | "BandChart" 108 | ] 109 | }, 110 | "weather": { 111 | "title": "Weather example", 112 | "description": "Storm visualized as a multi-row chart.", 113 | "tags": [ 114 | "AreaChart", 115 | "LineChart", 116 | "ScatterChart" 117 | ] 118 | }, 119 | "wind": { 120 | "title": "Wind Scatter example", 121 | "description": "Basic scatter chart example.", 122 | "tags": [ 123 | "ScatterChart", 124 | "BandChart" 125 | ] 126 | }, 127 | "volume": { 128 | "title": "BarChart example", 129 | "description": "Bar chart examples using traffic volume data.", 130 | "tags": [ 131 | "BarChart" 132 | ] 133 | }, 134 | "nyc": { 135 | "title": "NYC temperature example", 136 | "description": "Box plot example using NYC temperature data over 1 year. It shows the historical max and min temperature vs actual temperature range.", 137 | "tags": [ 138 | "BoxChart" 139 | ] 140 | }, 141 | "climate": { 142 | "title": "Climate temperature data", 143 | "description": "Change in global surface temperature relative to 1951-1980 average temperatures", 144 | "tags": [ 145 | "Baseline", 146 | "LineChart", 147 | "ScatterChart", 148 | "EventMarker" 149 | ] 150 | } 151 | } -------------------------------------------------------------------------------- /src/website/packages/charts/examples/nyc/nyc_docs.md: -------------------------------------------------------------------------------- 1 | ## Box chart example 2 | 3 | A box chart is capable of displaying two ranges and a center marker. The classic example is to use the inner range to display the interquartile range, the outer range to display the min to max extent of the data (though there's other definitions too), and the center marker to show the median. 4 | 5 | You can map data to these ranges in two ways, either by passing in a continuous series and letting the chart build up the aggregations necessary (percentiles for example) for a given interval (5 min for example), or, predefining them as an array for the data column under consideration. 6 | 7 | In this example we want to do something a little different. We have data that shows the maximum and minimum temperature in New York for each day, along with the historical maximum and minimum temperatures. Our visualization will map the outer range to the historical extremes and the inner range to the actual temperature range for that day. 8 | 9 | First we need to import out data, which is in a CSV file that we read in as `weather`. We use Pond to make an array of `IndexedEvents`, one for each day. For the data of each event, we have a single field `temp` that contains an array of our values. 10 | 11 | ``` 12 | const events = weather.map(item => { 13 | const timestamp = moment(new Date(item.date)); 14 | 15 | const { 16 | date, 17 | actual_min_temp, 18 | actual_max_temp, 19 | record_min_temp, 20 | record_max_temp, 21 | } = item; 22 | 23 | return new IndexedEvent(date, { 24 | temp: [ 25 | +record_min_temp, 26 | +actual_min_temp, 27 | +actual_max_temp, 28 | +record_max_temp, 29 | ] 30 | }, false); 31 | }); 32 | 33 | const series = new TimeSeries({ name, new Collection(events) }); 34 | ``` 35 | 36 | We can then render our `series`. Note that this example also demonstrates the ability to pass a function, rather than a d3 format string, as the `YAxis` format property. 37 | 38 | ``` 39 | render() { 40 | return ( 41 | ... 42 | 46 | 47 | 48 | 53 | 54 | Number(n).toFixed() + "°F" } /> 60 | 61 | 62 | ... 63 | ); 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/nyc/nyc_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/nyc/nyc_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/outages/Index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | /* eslint max-len:0 */ 12 | 13 | import React from "react/"; 14 | import createReactClass from "create-react-class"; 15 | 16 | // Pond 17 | import { TimeSeries, TimeRangeEvent, TimeRange } from "pondjs"; 18 | 19 | // Imports from the charts library 20 | import ChartContainer from "../../../../../components/ChartContainer"; 21 | import ChartRow from "../../../../../components/ChartRow"; 22 | import Charts from "../../../../../components/Charts"; 23 | import EventChart from "../../../../../components/EventChart"; 24 | import Resizable from "../../../../../components/Resizable"; 25 | 26 | import outages_docs from "./outages_docs.md"; 27 | import outages_thumbnail from "./outages_thumbnail.png"; 28 | 29 | // 30 | // Test data 31 | // 32 | 33 | const outageEvents = [ 34 | { 35 | startTime: "2015-03-08T09:00:00Z", 36 | endTime: "2015-03-22T14:00:00Z", 37 | title: "ANL Scheduled Maintenance", 38 | description: "ANL will be switching border routers...", 39 | completed: true, 40 | external_ticket: "", 41 | esnet_ticket: "ESNET-20150302-002", 42 | organization: "ANL", 43 | type: "Planned" 44 | }, 45 | { 46 | startTime: "2015-04-01T03:30:00Z", 47 | endTime: "2015-04-02T16:50:00Z", 48 | title: "STAR-CR5 < 100 ge 06519 > ANL - Outage", 49 | description: "The listed circuit was unavailable due to bent pins.", 50 | completed: true, 51 | external_ticket: "3576:144", 52 | esnet_ticket: "ESNET-20150421-013", 53 | organization: "Internet2 / Level 3", 54 | type: "Unplanned" 55 | }, 56 | { 57 | startTime: "2015-04-22T03:30:00Z", 58 | endTime: "2015-04-22T13:00:00Z", 59 | description: "At 13:33 pacific circuit 06519 went down.", 60 | title: "STAR-CR5 < 100 ge 06519 > ANL - Outage", 61 | completed: true, 62 | external_ticket: "", 63 | esnet_ticket: "ESNET-20150421-013", 64 | organization: "Internet2 / Level 3", 65 | type: "Unplanned" 66 | } 67 | ]; 68 | 69 | // 70 | // Turn data into TimeSeries 71 | // 72 | 73 | const events = outageEvents.map( 74 | ({ startTime, endTime, ...data }) => 75 | new TimeRangeEvent(new TimeRange(new Date(startTime), new Date(endTime)), data) 76 | ); 77 | const series = new TimeSeries({ name: "outages", events }); 78 | 79 | // 80 | // Render event chart 81 | // 82 | 83 | function outageEventStyleFunc(event, state) { 84 | const color = event.get("type") === "Planned" ? "#998ec3" : "#f1a340"; 85 | switch (state) { 86 | case "normal": 87 | return { 88 | fill: color 89 | }; 90 | case "hover": 91 | return { 92 | fill: color, 93 | opacity: 0.4 94 | }; 95 | case "selected": 96 | return { 97 | fill: color 98 | }; 99 | default: 100 | //pass 101 | } 102 | } 103 | 104 | const outages = createReactClass({ 105 | getInitialState() { 106 | return { 107 | tracker: null, 108 | timerange: series.timerange() 109 | }; 110 | }, 111 | handleTrackerChanged(tracker) { 112 | this.setState({ tracker }); 113 | }, 114 | handleTimeRangeChange(timerange) { 115 | this.setState({ timerange }); 116 | }, 117 | render() { 118 | return ( 119 |
120 |
121 |
122 | 123 | 128 | 129 | 130 | e.get("title")} 135 | /> 136 | 137 | 138 | 139 | 140 |
141 |
142 |
143 | ); 144 | } 145 | }); 146 | 147 | // Export example 148 | export default { outages, outages_docs, outages_thumbnail }; 149 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/outages/outages_docs.md: -------------------------------------------------------------------------------- 1 | This example shows a short list of network outages as an `EventChart`. `EventCharts` are currently experimental and don't yet conform to the style guidelines. 2 | 3 | Here we build an `EventChart`. 4 | 5 | 9 | 10 | 11 | e.get("title")} /> 15 | 16 | 17 | 18 | 19 | ### Styling 20 | 21 | Styling is currently performed with a callback function. In the above example `outageEventStyleCB` is a function implemented as follows: 22 | 23 | function outageEventStyleCB(event, state) { 24 | const color = event.get("type") === "Planned" ? "#998ec3" : "#f1a340"; 25 | switch (state) { 26 | case "normal": 27 | return { 28 | fill: color 29 | }; 30 | case "hover": 31 | return { 32 | fill: color, 33 | opacity: 0.4 34 | }; 35 | case "selected": 36 | return { 37 | fill: color 38 | }; 39 | } 40 | } 41 | 42 | The purpose of the function is to set a different color depending on if our event outage was planned or not. 43 | 44 | **Note: This form of style setting is similar, but not the same, as the API style guide, so will likely change in the near future.** 45 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/outages/outages_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/outages/outages_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/realtime/realtime_docs.md: -------------------------------------------------------------------------------- 1 | 2 | In this example we have an simulated incoming stream of measurements, represented by the dots. The visualization you see shows the 5 min aggregations (both 50th and 90th percentile) of the incoming stream as a green bar chart. We calculate this as described below. 3 | 4 | ### Events 5 | 6 | To do this, each event is generated semi-randomly, but they could be coming from a real source. We add a new Event for each minute, but emit 5 per second to speed up the simulation. Essentially we do this: 7 | 8 | ```js 9 | import { Event } from "pondjs"; 10 | 11 | const value = getRandomValue(); 12 | const time = getNextTime(); 13 | const event = new Event(time, value); 14 | ``` 15 | 16 | Now we want to do some things with that Event: 17 | 18 | * Store it, so we can show the scatter plot 19 | * Aggregate it to give us our 5 min average and maximum values 20 | 21 | To store it, we put it into a circle buffer that keeps the last n Events. Otherwise we'll eventually kill the browser. The circle buffer is placed in the React component's state. 22 | 23 | ### Aggregation 24 | 25 | For the more interesting part, the aggregation, we need to setup up a couple of Pond Pipelines to do the work. Here's the 5 min aggregation pipeline that we setup: 26 | 27 | ```js 28 | 29 | import { Stream, Pipeline, EventOut, percentile } from "pondjs"; 30 | 31 | ... 32 | 33 | const stream = new Stream(); 34 | 35 | Pipeline() 36 | .from(stream) 37 | .windowBy("5m") 38 | .emitOn("discard") 39 | .aggregate({ 40 | value: {value: percentile(90)} 41 | }) 42 | .to(EventOut, event => { 43 | // store the output events in our component state 44 | }); 45 | ``` 46 | 47 | The Pipeline now just needs a feed of events added to its stream in order to process them into a new aggregated events. Each time one of these new events is emitted we take that from the callback defined in `to()` and place it into the component's state. 48 | 49 | 50 | ```js 51 | stream.addEvent(event); 52 | ``` 53 | 54 | ### Visualization 55 | 56 | The first thing we need to do is turn our three event lists (the original events along with the two aggregated event streams) into TimeSeries objects which can then be passed to our charting code. Since we can construct a pond.js TimeSeries object from a list of events, this is simply a matter of pulling the list from the circle buffer and giving it to the TimeSeries constructor. 57 | 58 | For example, our 5 min 50th percentiles: 59 | 60 | ```js 61 | const name = "5m-percentile-50"; 62 | const events = this.state.perc50Out.toArray(); // <- from circle buffer 63 | const avgSeries = new TimeSeries({name, events}); 64 | ``` 65 | 66 | Next we figure out the begin and end times for the chart. The chart expands outward until it gets to 3 hours and then pans with the new data. Once we calculate the beginTime and endTime we make a TimeRange to represent this range: 67 | 68 | ```js 69 | const timeRange = new TimeRange(beginTime, endTime); 70 | ``` 71 | 72 | Finally we render() the chart: 73 | 74 | ```js 75 | render() { 76 | return ( 77 | 78 | 79 | 84 | 85 | 89 | 93 | 96 | 97 | 98 | 99 | ); 100 | } 101 | ``` 102 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/realtime/realtime_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/realtime/realtime_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/stockchart/stockchart_docs.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/stockchart/stockchart_docs.md -------------------------------------------------------------------------------- /src/website/packages/charts/examples/stockchart/stockchart_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/stockchart/stockchart_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/traffic/traffic_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/traffic/traffic_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/trend/Index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | /* eslint max-len:0 */ 12 | 13 | import React from "react"; 14 | 15 | // Pond 16 | import { TimeSeries } from "pondjs"; 17 | 18 | // Imports from the charts library 19 | import ChartContainer from "../../../../../components/ChartContainer"; 20 | import ChartRow from "../../../../../components/ChartRow"; 21 | import Charts from "../../../../../components/Charts"; 22 | import YAxis from "../../../../../components/YAxis"; 23 | import BandChart from "../../../../../components/BandChart"; 24 | import LineChart from "../../../../../components/LineChart"; 25 | import Resizable from "../../../../../components/Resizable"; 26 | import styler from "../../../../../js/styler"; 27 | 28 | import data from "./data.json"; 29 | 30 | import trend_docs from "./trend_docs.md"; 31 | import trend_thumbnail from "./trend_thumbnail.png"; 32 | 33 | const series = new TimeSeries({ 34 | name: "series", 35 | columns: ["index", "t", "median"], 36 | points: data.map(({ date, pct05, pct25, pct50, pct75, pct95 }) => [ 37 | date, 38 | [pct05 / 1000, pct25 / 1000, pct75 / 1000, pct95 / 1000], 39 | pct50 / 1000 40 | ]) 41 | }); 42 | 43 | class trend extends React.Component { 44 | render() { 45 | const style = styler([ 46 | { key: "t", color: "steelblue", width: 1, opacity: 1 }, 47 | { key: "median", color: "#333", width: 1 } 48 | ]); 49 | 50 | return ( 51 |
52 |
53 |
54 | BarChart 55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 72 | 73 | 81 | 89 | 90 | 91 | 92 | 93 |
94 |
95 |
96 | ); 97 | } 98 | } 99 | 100 | // Export example 101 | export default { trend, trend_docs, trend_thumbnail }; 102 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/trend/trend_docs.md: -------------------------------------------------------------------------------- 1 | 2 | In this example we have more than a months's worth of data showing loading times across releases of a hypothetical web application: 3 | 4 | ``` 5 | const data = [ 6 | { 7 | "date": "2014-08-01", 8 | "pct05": 5350, 9 | "pct25": 6756, 10 | "pct50": 7819, 11 | "pct75": 9284, 12 | "pct95": 13835 13 | }, 14 | { 15 | "date": "2014-08-02", 16 | "pct05": 4439, 17 | "pct25": 5584, 18 | "pct50": 6554, 19 | "pct75": 8016, 20 | "pct95": 12765 21 | }, 22 | { 23 | "date": "2014-08-03", 24 | "pct05": 4247, 25 | "pct25": 5419, 26 | "pct50": 6332, 27 | "pct75": 7754, 28 | "pct95": 12236 29 | }, 30 | { 31 | "date": "2014-08-04", 32 | "pct05": 3293, 33 | "pct25": 4414, 34 | "pct50": 5191, 35 | "pct75": 6491, 36 | "pct95": 10325 37 | }, 38 | .... 39 | ]; 40 | ``` 41 | 42 | We want to take that data and make a Trend Chart, a mixture of a line chart and area chart from it. 43 | 44 | This isn't the exact format we need for our chart. Firstly, like other charts, it needs to be a [Pond TimeSeries](http://software.es.net/pond/#/timeseries). Secondly, the TimeSeries is constructed from points where the first column refers to the index, the second column is an array of values representing the 5th, 25th, 75th and 95th percentile. Finally, the third column represents the median value. 45 | 46 | Note that often you will either pass the indexed data from the server, or a more dense timeseries will be aggregated with Pond to these indexed events (see the realtime example). 47 | 48 | ``` 49 | const series = new TimeSeries({ 50 | name: "series", 51 | columns: ["index", "t", "median"], 52 | points: data.map(({ date, pct05, pct25, pct50, pct75, pct95 }) => [ 53 | date, 54 | [ 55 | pct05 / 1000, 56 | pct25 / 1000, 57 | pct75 / 1000, 58 | pct95 / 1000 59 | ], 60 | pct50 / 1000 61 | ]) 62 | }); 63 | ``` 64 | 65 | To style the trend chart, we pass in the values to the styler object where the key refers to the column in the series 66 | 67 | ``` 68 | const style = styler([ 69 | { key: "t", color: "steelblue", width: 1, opacity: 1 }, 70 | { key: "median", color: "#333", width: 1 } 71 | ]); 72 | ``` 73 | 74 | Now that we have a series and style object, we can render the chart as follows: 75 | 76 | ``` 77 | class trend extends React.Component { 78 | render() { 79 | return ( 80 |
81 |
82 |
83 | BarChart 84 |
85 |
86 |
87 |
88 |
89 | 90 | 91 | 92 | 101 | 102 | 110 | 118 | 119 | 120 | 121 | 122 |
123 |
124 |
125 | ); 126 | } 127 | }; 128 | ``` 129 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/trend/trend_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/trend/trend_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/volume/volume_docs.md: -------------------------------------------------------------------------------- 1 | This simple example of a bar chart displays a pan and zoom chart that shows traffic levels for each day of October 2014. The original data used here was captured to debug a measurement error (seen clearly in Oct 10th). 2 | 3 | To begin with we converted the original data into Pond's TimeSeries data structure as `octoberTraffic`: 4 | 5 | import { TimeSeries } from "pondjs"; 6 | 7 | const octoberTraffic = new TimeSeries({ 8 | name: "Traffic", 9 | utc: false, 10 | columns: ["time", "in", "out"], 11 | points: trafficPoints 12 | }); 13 | 14 | Points are simply an array of tuples, each of which is `[index, value1, value2, ...]`. In this case this looks like `['2014-10-DD', volIn, volOut]`. An index can be of several forms, but is a string that represents a time range (e.g. 2014-10-08 represents the time range spanning October 8th 2014). 15 | 16 | We also set `utc` to false here so that the index time ranges are defined in local time. Visualizations of time series data default to showing local time (though UTC is also possible), while `IndexedEvents` default to being in UTC. 17 | 18 | Now we can render a the chart. The `` element does the rendering of the chart itself. As with other chart types, the vertical scale is provided by referencing the `` (`axis='traffic'`). 19 | 20 | 28 | 29 | 34 | 35 | this.setState({highlight})} 43 | selection={this.state.selection} 44 | onSelectionChange={selection => this.setState({selection})} /> 45 | 50 | 51 | 56 | 57 | 58 | 59 | The style provides the coloring, relating each channel to styles for "normal", "highlight" (hover), "selected" and "muted". Muted is the style shown on bars which are not selected: 60 | 61 | const style = { 62 | in: { 63 | normal: {fill: "#A5C8E1"}, 64 | highlighted: {fill: "#bfdff6"}, 65 | selected: {fill: "#5aa2d5"}, 66 | muted: {fill: "#A5C8E1", opacity: 0.4} 67 | } 68 | }; 69 | 70 | Side note: this chart can also be zoomed in and then panned with constraints. This is controlled using the `` props. Drag to pan, scroll wheel to zoom. 71 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/volume/volume_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/volume/volume_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/weather/weather_docs.md: -------------------------------------------------------------------------------- 1 | This example uses three rows to create stacked chart: 2 | 3 | this.setState({tracker})} > 11 | 12 | 14 | 15 | 20 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 39 | { return event.get("radius"); }}/> 45 | 46 | 48 | 49 | 50 | 51 | 52 | 59 | 64 | 65 | 67 | 68 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/weather/weather_raw.txt: -------------------------------------------------------------------------------- 1 | TimePST,TemperatureF,Dew PointF,Humidity,Sea Level PressureIn,VisibilityMPH,Wind Direction,Wind SpeedMPH,Gust SpeedMPH,PrecipitationIn,Events,Conditions,WindDirDegrees,DateUTC 2 | 12:53 AM,63.0,53.1,70,29.70,10.0,SE,20.7,31.1,N/A,,Overcast,140,2014-12-11 08:53:00 3 | 1:53 AM,62.1,52.0,70,29.66,10.0,SE,21.9,-,N/A,,Overcast,140,2014-12-11 09:53:00 4 | 2:50 AM,62.6,53.6,72,29.62,10.0,SSE,26.5,34.5,N/A,,Overcast,150,2014-12-11 10:50:00 5 | 2:53 AM,63.0,53.1,70,29.62,10.0,SSE,25.3,34.5,N/A,,Overcast,150,2014-12-11 10:53:00 6 | 3:53 AM,63.0,53.1,70,29.60,10.0,SSE,34.5,41.4,N/A,,Overcast,160,2014-12-11 11:53:00 7 | 4:15 AM,62.6,53.6,72,29.60,10.0,SSE,31.1,39.1,N/A,,Overcast,150,2014-12-11 12:15:00 8 | 4:53 AM,63.0,53.1,70,29.58,10.0,SSE,33.4,41.4,0.00,,Overcast,150,2014-12-11 12:53:00 9 | 5:53 AM,62.1,54.0,75,29.54,10.0,SSE,32.2,42.6,0.00,Rain,Light Rain,150,2014-12-11 13:53:00 10 | 6:53 AM,60.1,55.0,83,29.53,4.0,SSE,29.9,43.7,0.08,Rain,Heavy Rain,150,2014-12-11 14:53:00 11 | 7:53 AM,60.1,55.9,86,29.52,6.0,SSE,28.8,41.4,0.12,Rain,Rain,150,2014-12-11 15:53:00 12 | 8:06 AM,60.8,55.4,82,29.57,2.0,SSE,28.8,35.7,0.12,Rain,Heavy Rain,160,2014-12-11 16:06:00 13 | 8:10 AM,59.0,55.4,88,29.57,1.0,SSE,27.6,35.7,0.19,Rain,Heavy Rain,160,2014-12-11 16:10:00 14 | 8:22 AM,59.0,57.2,94,29.59,1.2,SSW,23.0,36.8,0.37,Rain,Heavy Rain,200,2014-12-11 16:22:00 15 | 8:27 AM,59.0,57.2,94,29.60,2.0,SW,18.4,36.8,0.39,Rain,Heavy Rain,230,2014-12-11 16:27:00 16 | 8:46 AM,59.0,55.4,88,29.62,3.0,South,13.8,-,0.51,Rain,Heavy Rain,180,2014-12-11 16:46:00 17 | 8:53 AM,59.0,55.9,90,29.62,3.0,South,12.7,-,0.55,Rain,Heavy Rain,180,2014-12-11 16:53:00 18 | 9:47 AM,57.2,55.4,94,29.64,2.0,SSW,20.7,24.2,0.21,Rain,Heavy Rain,200,2014-12-11 17:47:00 19 | 9:48 AM,57.9,55.0,90,29.64,2.0,SSW,19.6,24.2,0.22,Rain,Heavy Rain,200,2014-12-11 17:48:00 20 | 10:33 AM,57.2,53.6,88,29.66,2.0,WSW,15.0,-,0.19,Rain,Heavy Rain,250,2014-12-11 18:33:00 21 | 10:45 AM,57.2,53.6,88,29.66,2.0,WSW,11.5,-,0.23,Rain,Heavy Rain,250,2014-12-11 18:45:00 22 | 10:53 AM,57.0,54.0,89,29.66,3.0,SW,9.2,-,0.26,Rain,Heavy Rain,230,2014-12-11 18:53:00 23 | 11:53 AM,57.9,54.0,87,29.65,6.0,South,8.1,-,0.14,Rain,Light Rain,180,2014-12-11 19:53:00 24 | 12:53 PM,57.0,54.0,89,29.65,2.0,South,6.9,-,0.11,Rain,Rain,190,2014-12-11 20:53:00 25 | 1:53 PM,55.0,52.0,89,29.63,2.5,SE,4.6,-,0.15,Rain,Rain,140,2014-12-11 21:53:00 26 | 2:36 PM,55.4,51.8,88,29.64,4.0,South,5.8,-,0.10,Rain,Rain,170,2014-12-11 22:36:00 27 | 2:53 PM,55.0,51.1,86,29.65,3.0,SSE,5.8,-,0.14,Rain,Rain,150,2014-12-11 22:53:00 28 | 3:53 PM,53.1,50.0,89,29.65,3.0,South,8.1,-,0.26,Rain,Heavy Rain,170,2014-12-11 23:53:00 29 | 4:53 PM,52.0,48.9,89,29.63,6.0,East,5.8,-,0.17,Rain,Heavy Rain,100,2014-12-12 00:53:00 30 | 5:53 PM,51.1,48.9,92,29.64,7.0,SE,3.5,-,0.14,Rain,Rain,130,2014-12-12 01:53:00 31 | 6:53 PM,51.1,48.9,92,29.65,7.0,ENE,5.8,-,0.14,Rain,Rain,60,2014-12-12 02:53:00 32 | 7:53 PM,51.1,48.9,92,29.64,7.0,NE,5.8,-,0.12,Rain,Rain,50,2014-12-12 03:53:00 33 | 8:53 PM,51.1,48.9,92,29.67,6.0,ENE,4.6,-,0.15,Rain,Rain,70,2014-12-12 04:53:00 34 | 9:53 PM,51.1,48.9,92,29.68,6.0,Calm,Calm,-,0.20,Rain,Rain,0,2014-12-12 05:53:00 35 | 10:53 PM,51.1,48.9,92,29.67,8.0,Calm,Calm,-,0.11,Rain,Rain,0,2014-12-12 06:53:00 36 | 11:09 PM,51.8,48.2,88,29.68,7.0,Calm,Calm,-,0.02,Rain,Light Rain,0,2014-12-12 07:09:00 37 | 11:53 PM,50.0,48.9,96,29.67,10.0,Calm,Calm,-,0.06,Rain,Light Rain,0,2014-12-12 07:53:00 -------------------------------------------------------------------------------- /src/website/packages/charts/examples/weather/weather_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/weather/weather_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/examples/wind/wind_docs.md: -------------------------------------------------------------------------------- 1 | The ScatterChart takes a TimeSeries as its `series` prop, 2 | along with a list of `columns` to plot. 3 | 4 | Here we style each point with a function passed to the `style` prop, 5 | rather than passing an object, though you can do that too. However, 6 | it is common for a scatter plot to need to style per point, so we 7 | demonstrate that here. 8 | 9 | This style function is passed the `column` and `event` to style and returns 10 | an object with the style for each state the point could be in: 11 | normal, highlighted, selected or muted. Be aware that this is called 12 | for every point on every render, so be gentle. 13 | 14 | ``` 15 | const perEventStyle = (column, event) => { 16 | const color = heat[ 17 | Math.floor((1 - event.get("station1") / 40) * 11) 18 | ]; 19 | return { 20 | normal: { 21 | fill: color, 22 | opacity: 1.0 23 | }, 24 | highlighted: { 25 | fill: color, 26 | stroke: "none", 27 | opacity: 1.0 28 | }, 29 | selected: { 30 | fill: "none", 31 | stroke: "#2CB1CF", 32 | strokeWidth: 3, 33 | opacity: 1.0 34 | }, 35 | muted: { 36 | stroke: "none", 37 | opacity: 0.4, 38 | fill: color 39 | } 40 | }; 41 | }; 42 | ``` 43 | 44 | Similarly we can control the radius of each point with a function 45 | passed to the `radius` prop: 46 | 47 | ``` 48 | radius={(event, column) => 49 | column === "station1" ? 3 : 2} 50 | ``` 51 | 52 | In this case we just say that if the column we're rendering is 53 | "station1" we render a radius of 3, otherwise a radius of 2. But 54 | alternatively it would be easy to use a value in the event to render 55 | a radius based on magnitude, allowing you to create a bubble plot. 56 | 57 | Other parts of this example are similar to other examples, such as the 58 | use of timerange state to control pan and zoom, and handling of selection. 59 | Note the use of `onBackgroundClick` on the ChartContainer to deselect any selection. 60 | 61 | We also render a `BandChart` to show the outer range from the 5th percentile to the 95th, 62 | along with an inner range for the interquantile. 63 | 64 | Here is the render code: 65 | 66 | ``` 67 | 71 | this.setState({ selection: null })} 72 | onTimeRangeChanged={timerange => 73 | this.setState({ timerange })} 74 | > 75 | 76 | 78 | 79 | 92 | 112 | column === "station1" ? 3 : 2} 113 | /> 114 | 115 | 116 | 117 | ``` 118 | -------------------------------------------------------------------------------- /src/website/packages/charts/examples/wind/wind_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/examples/wind/wind_thumbnail.png -------------------------------------------------------------------------------- /src/website/packages/charts/guides/1_introduction.md: -------------------------------------------------------------------------------- 1 | 2 | ## 1. Introduction 3 | 4 | --- 5 | 6 | This library contains a set of modular charting components used for building flexible interactive charts in React. What does it look like? 7 | 8 | ```js 9 | render() { 10 | ... 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | ``` 25 | 26 | ### 1.1 Why another chart library? 27 | 28 | This charts library was built using React from the ground up, specifically to visualize TimeSeries data and network traffic data in particular. We recognized early that we could combine the composability of React with the drawing primitives of d3, to meet our visualization needs. Other libraries have also come to the same conclusion. 29 | 30 | For us, initial key drivers in the build our own equation were: 31 | 32 | * Time series use cases first, not an after thought 33 | * Built on an underlying timeseries abstraction (pond.js) 34 | * Pan and zoom, with enough control to dynamically load in data 35 | * Ability to visualize network traffic data using stacked and up/down area charts 36 | 37 | Since then the library has grown to form the basis of visualization throughout the public facing [ESnet Portal](http://my.es.net). 38 | 39 | ### 1.2 Features 40 | 41 | Current features of the library include: 42 | 43 | * Declarative layout of charts using JSX 44 | * Composition into multiple axis and multiple rows and overlays 45 | * Interactivity, including pan and zoom, selection and highlighting 46 | * Easily add your own chart types or overlays 47 | * Line, area, scatter, bar, boxplot and event charts 48 | * Brushing for interactive chart region selection 49 | * Chart pan and zoom constraints 50 | * Legends 51 | * Baselines 52 | * Markers 53 | 54 | Please continue to read the documentation to see how to get started, or browse the examples for a feel for the library. 55 | 56 | -------------------------------------------------------------------------------- /src/website/packages/charts/guides/2_getting_started.md: -------------------------------------------------------------------------------- 1 | 2 | ## 2. Getting started 3 | 4 | --- 5 | 6 | ### 2.1 How to Install 7 | 8 | This charts library is intended to be installed with [npm](https://www.npmjs.com/) and the built into your project with a tool like [Webpack](https://webpack.github.io/). It expects React to be present, as well as our TimeSeries abstraction library, [pond.js](http://software.es.net/pond). More on this below. To install: 9 | 10 | npm install react-timeseries-charts pondjs --save 11 | 12 | ### 2.2 Imports 13 | 14 | Once installed, you can import the necessary components from the library: 15 | 16 | ```js 17 | import { 18 | Charts, 19 | ChartContainer, 20 | ChartRow, 21 | YAxis, 22 | LineChart 23 | } from "react-timeseries-charts"; 24 | ``` 25 | 26 | ### 2.3 Rendering 27 | 28 | With the charts library, we construct our chart or charts in the `render()` function of our component. For a simple example here we create a visualization two line charts along with two axes, specified in JSX: 29 | 30 | ```jsx 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ``` 42 | 43 | At the outer most layer, we add a `` which contains our time range for the x-axis. All charts within a ChartContainer share the same x-axis. In this case we get the TimeRange from the TimeSeries itself, but you could specify one yourself. You also need to provide a width for the chart, or wrap the chart in a `` component and that will inject a width for you. 44 | 45 | For the next layer of the layout we make a ``. We can have multiple charts stacked on top of each other by using more than one row. In this case we just have one row. Each row has a specific height in the layout, so we specify that as 200px high here. 46 | 47 | Next up we want to put something in our row. Rows contain two parts: 48 | * A central flexible sized area in which charts can be added 49 | * Axes on either the left or right of the central area. 50 | 51 | This central area is surrounded in the JSX by the `` tag. Each chart in this area is composited on top of each other. In this case we are adding two ``s, one for each of our timeseries. As a result they will be drawn on top of each other. (Note that as of v0.9, it is also possible to draw multiple channels of a TimeSeries as multiple line charts using a single ). For scaling each chart will reference an axis that will define the scale as well as display that scale visually as the y-axis. 52 | 53 | Finally, we specify the axes that the charts reference. These go either before or after the `` group, depending on if you want the axis before (to the left) or after the charts (to the right). You can specify any number of axes on either side. For each `` you specify the `id` so that a chart can reference it, the `label` you want displayed alongside the axis and, importantly, the scale using `min` and `max`. You can also specify the `type` of the axis (`linear`, `log`, etc), a non-default `width` and the `format`. Axes are optional, but if you don't link a Chart to and Axis, you should supply the scale yourself (as a d3 scale like `scaleLinear` to the `yScale` prop passed to the specific chart). 54 | -------------------------------------------------------------------------------- /src/website/packages/charts/guides/guides.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2016-present, The Regents of the University of California, 3 | * through Lawrence Berkeley National Laboratory (subject to receipt 4 | * of any required approvals from the U.S. Dept. of Energy). 5 | * All rights reserved. 6 | * 7 | * This source code is licensed under the BSD-style license found in the 8 | * LICENSE file in the root directory of this source tree. 9 | */ 10 | 11 | import intro from "./1_introduction.md"; 12 | import start from "./2_getting_started.md"; 13 | import style from "./3_styling.md"; 14 | import annotations from "./4_annotations.md"; 15 | 16 | export default { 17 | intro, 18 | start, 19 | style, 20 | annotations 21 | }; 22 | -------------------------------------------------------------------------------- /src/website/packages/charts/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/src/website/packages/charts/logo.png -------------------------------------------------------------------------------- /zooming.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esnet/react-timeseries-charts/aa9c9b368100d78337b562d9e2833f2d90d9de3d/zooming.gif --------------------------------------------------------------------------------