From 4ea682406c0ad6bee06d74f7b23eeea9fd482aa7 Mon Sep 17 00:00:00 2001 From: hs <> Date: Fri, 1 Jun 2018 22:13:53 -0700 Subject: [PATCH 01/17] hsdatab doc version --- Gruntfile.js | 6 - LICENSE | 19 - README.md | 25 - docs/data/hsdatab.json | 3395 +++++ docs/data/index.json | 6 + docs/example/defEquityList.json | 10 + docs/example/equityList.json | 10 + docs/example/hsGraph.js | 10647 ++++++++++++++ docs/example/hsLayout.css | 88 + docs/example/hsLayout.css.map | 1 + docs/example/hsLayout.js | 6527 +++++++++ docs/example/hsWidget.js | 6867 +++++++++ docs/example/index.json | 13 + docs/example/layout.html | 11 + docs/example/search.json | 6 + docs/hsDoc.css | 1062 ++ docs/hsDoc.js | 12128 ++++++++++++++++ docs/index.html | 11 + docs/src/hsData/Data.html | 557 + docs/src/hsData/DataFilters.html | 272 + docs/src/hsData/DataTypes.html | 48 + docs/src/hsData/index.html | 32 + docs/src/hsData/overview.html | 40 + docs/src/hsDoc/DocSets.html | 168 + docs/src/hsDoc/Site.html | 78 + docs/src/hsDoc/index.html | 27 + docs/src/hsDoc/markdown.html | 100 + docs/src/hsDoc/overview.html | 161 + docs/src/hsDoc/view/DocsMenu.html | 56 + docs/src/hsDoc/view/LeftNav.html | 171 + docs/src/hsDoc/view/MainComment.html | 171 + docs/src/hsDoc/view/MainDetail.html | 181 + docs/src/hsDoc/view/MainExample.html | 285 + docs/src/hsDoc/view/MainExample.spec.html | 33 + docs/src/hsDoc/view/Parts.html | 218 + docs/src/hsDoc/view/Tooltip.html | 25 + docs/src/hsGraph/Axes.html | 450 + docs/src/hsGraph/AxesCfg.html | 234 + docs/src/hsGraph/AxesDefaultCfg.html | 181 + docs/src/hsGraph/AxesTypes.html | 110 + docs/src/hsGraph/Canvas.html | 89 + docs/src/hsGraph/Chart.html | 148 + docs/src/hsGraph/Config.html | 40 + docs/src/hsGraph/Data.html | 351 + docs/src/hsGraph/Graph.html | 404 + docs/src/hsGraph/Grid.html | 139 + docs/src/hsGraph/Legend.html | 73 + docs/src/hsGraph/Plot.html | 106 + docs/src/hsGraph/PlotArea.html | 105 + docs/src/hsGraph/PlotBar.html | 115 + docs/src/hsGraph/PlotLine.html | 68 + docs/src/hsGraph/PlotMarkers.html | 71 + docs/src/hsGraph/SVGElem.html | 312 + docs/src/hsGraph/Scale.html | 299 + docs/src/hsGraph/Series.html | 380 + docs/src/hsGraph/SeriesLine.html | 18 + docs/src/hsGraph/example/start.html | 19 + docs/src/hsGraph/hsGraph.html | 182 + docs/src/hsGraph/index.html | 26 + docs/src/hsGraph/overview.html | 94 + docs/src/hsLayout/example/columns.x.html | 88 + docs/src/hsLayout/example/config.x.html | 82 + docs/src/hsLayout/example/layout.x.html | 138 + docs/src/hsLayout/example/start.html | 19 + docs/src/hsLayout/hsConfig.html | 274 + docs/src/hsLayout/index.html | 31 + docs/src/hsLayout/mithril.html | 43 + docs/src/hsLayout/overview.html | 95 + docs/src/hsLayout/view/Container.html | 159 + docs/src/hsLayout/view/Layout.html | 153 + docs/src/hsLayout/view/Layouter.html | 148 + docs/src/hsLayout/view/PillaredLayout.html | 359 + .../hsLayout/view/PillaredLayout.spec.html | 101 + docs/src/hsLayout/view/PillaredLayouter.html | 360 + .../hsLayout/view/PillaredLayouter.spec.html | 101 + docs/src/hsLayout/view/TileLayout.html | 156 + docs/src/hsLayout/view/TileLayouter.html | 180 + docs/src/hsLayout/view/Tokens.html | 75 + docs/src/hsNode/cpUtil.html | 59 + docs/src/hsNode/cpUtil.spec.html | 80 + docs/src/hsNode/date.html | 89 + docs/src/hsNode/date.spec.html | 59 + docs/src/hsNode/excel.html | 282 + docs/src/hsNode/excel.spec.html | 152 + docs/src/hsNode/fsUtil.html | 307 + docs/src/hsNode/fsUtil.spec.html | 571 + docs/src/hsNode/httpUtil.html | 75 + docs/src/hsNode/index.html | 30 + docs/src/hsNode/log.html | 308 + docs/src/hsNode/log.spec.html | 149 + docs/src/hsNode/node.html | 72 + docs/src/hsNode/node.spec.html | 75 + docs/src/hsStock/Home.html | 65 + docs/src/hsStock/Router.html | 82 + docs/src/hsStock/Site.html | 70 + docs/src/hsStock/controller/Assets.html | 78 + docs/src/hsStock/controller/Equities.html | 195 + docs/src/hsStock/controller/Equity.html | 493 + docs/src/hsStock/controller/EquityList.html | 120 + docs/src/hsStock/controller/EquityLoader.html | 345 + docs/src/hsStock/controller/Loader.html | 18 + docs/src/hsStock/controller/Trader.html | 325 + docs/src/hsStock/controller/TraderIEX.html | 311 + docs/src/hsStock/controller/Venue.html | 68 + docs/src/hsStock/controller/VenueIEX.html | 416 + docs/src/hsStock/fileIO.html | 49 + docs/src/hsStock/index.html | 25 + docs/src/hsStock/overview.html | 23 + docs/src/hsStock/saveToFile.html | 36 + .../hsStock/server/convertInvestments.html | 20 + docs/src/hsStock/view/Equity.html | 242 + docs/src/hsStock/view/Header.html | 31 + docs/src/hsStock/view/Import.html | 71 + docs/src/hsStock/view/ImportPane.html | 65 + docs/src/hsStock/view/LeftNav.html | 45 + docs/src/hsStock/view/Main.html | 85 + docs/src/hsStock/view/MainDetails.html | 145 + docs/src/hsStock/view/MainGraph.html | 121 + docs/src/hsStock/view/MainMenu.html | 31 + docs/src/hsStock/view/Modal.html | 31 + docs/src/hsStock/view/SiteMenu.html | 31 + docs/src/hsStock/view/StockQuotes.html | 103 + docs/src/hsStock/view/Trade.html | 24 + docs/src/hsStock/view/TradePane.html | 128 + docs/src/hsStock/view/Trader.html | 110 + docs/src/hsStock/view/TraderIEX.html | 281 + docs/src/hsStock/view/View.html | 87 + docs/src/hsStock/view/ViewLeft.html | 149 + docs/src/hsStock/view/ViewPane.html | 45 + docs/src/hsUtil/Checksum.html | 33 + docs/src/hsUtil/Date.html | 95 + docs/src/hsUtil/Number.html | 34 + docs/src/hsUtil/PacingQueue.html | 63 + docs/src/hsUtil/TimedPromise.html | 46 + docs/src/hsUtil/hsChecksum.html | 33 + docs/src/hsUtil/hsTimedPromise.html | 46 + docs/src/hsUtil/hsUtil.html | 52 + docs/src/hsUtil/index.html | 24 + docs/src/hsUtil/overview.html | 30 + docs/src/hsUtil/showdown.html | 24 + docs/src/hsWidget/AddRemove.html | 48 + docs/src/hsWidget/Button.html | 74 + docs/src/hsWidget/Collapsible.html | 93 + docs/src/hsWidget/CornerButton.html | 120 + docs/src/hsWidget/DropOver.html | 87 + docs/src/hsWidget/Menu.html | 83 + docs/src/hsWidget/Menu.spec.html | 66 + docs/src/hsWidget/Modal.html | 68 + docs/src/hsWidget/OneOfButtons.html | 39 + docs/src/hsWidget/RadioButton.html | 89 + docs/src/hsWidget/Selector.html | 177 + docs/src/hsWidget/ToggleButton.html | 99 + docs/src/hsWidget/ToolbarButton.html | 147 + docs/src/hsWidget/TypeAhead.html | 150 + docs/src/hsWidget/example/start.html | 19 + docs/src/hsWidget/index.html | 38 + docs/src/hsWidget/overview.html | 192 + docs/src/hsWidgets/AddRemove.html | 36 + docs/src/hsWidgets/Button.html | 32 + docs/src/hsWidgets/Collapsible.html | 54 + docs/src/hsWidgets/Menu.html | 142 + docs/src/hsWidgets/Menu.spec.html | 66 + docs/src/hsWidgets/Modal.html | 32 + docs/src/hsWidgets/css/Button.html | 32 + docs/src/hsWidgets/example/start.html | 19 + docs/src/hsWidgets/index.html | 27 + docs/src/hsWidgets/overview.html | 28 + package.json | 27 - sharedGruntConfig.js | 290 - src/Data.ts | 540 - src/DataFilters.ts | 254 - src/index.ts | 14 - src/overview.ts | 22 - tsconfigGrunt.json | 16 - tslint.json | 11 - 175 files changed, 59390 insertions(+), 1224 deletions(-) delete mode 100755 Gruntfile.js delete mode 100644 LICENSE delete mode 100644 README.md create mode 100644 docs/data/hsdatab.json create mode 100644 docs/data/index.json create mode 100644 docs/example/defEquityList.json create mode 100644 docs/example/equityList.json create mode 100644 docs/example/hsGraph.js create mode 100644 docs/example/hsLayout.css create mode 100644 docs/example/hsLayout.css.map create mode 100644 docs/example/hsLayout.js create mode 100644 docs/example/hsWidget.js create mode 100644 docs/example/index.json create mode 100644 docs/example/layout.html create mode 100644 docs/example/search.json create mode 100644 docs/hsDoc.css create mode 100644 docs/hsDoc.js create mode 100644 docs/index.html create mode 100644 docs/src/hsData/Data.html create mode 100644 docs/src/hsData/DataFilters.html create mode 100644 docs/src/hsData/DataTypes.html create mode 100644 docs/src/hsData/index.html create mode 100644 docs/src/hsData/overview.html create mode 100644 docs/src/hsDoc/DocSets.html create mode 100644 docs/src/hsDoc/Site.html create mode 100644 docs/src/hsDoc/index.html create mode 100644 docs/src/hsDoc/markdown.html create mode 100644 docs/src/hsDoc/overview.html create mode 100644 docs/src/hsDoc/view/DocsMenu.html create mode 100644 docs/src/hsDoc/view/LeftNav.html create mode 100644 docs/src/hsDoc/view/MainComment.html create mode 100644 docs/src/hsDoc/view/MainDetail.html create mode 100644 docs/src/hsDoc/view/MainExample.html create mode 100644 docs/src/hsDoc/view/MainExample.spec.html create mode 100644 docs/src/hsDoc/view/Parts.html create mode 100644 docs/src/hsDoc/view/Tooltip.html create mode 100644 docs/src/hsGraph/Axes.html create mode 100644 docs/src/hsGraph/AxesCfg.html create mode 100644 docs/src/hsGraph/AxesDefaultCfg.html create mode 100644 docs/src/hsGraph/AxesTypes.html create mode 100644 docs/src/hsGraph/Canvas.html create mode 100644 docs/src/hsGraph/Chart.html create mode 100644 docs/src/hsGraph/Config.html create mode 100644 docs/src/hsGraph/Data.html create mode 100644 docs/src/hsGraph/Graph.html create mode 100644 docs/src/hsGraph/Grid.html create mode 100644 docs/src/hsGraph/Legend.html create mode 100644 docs/src/hsGraph/Plot.html create mode 100644 docs/src/hsGraph/PlotArea.html create mode 100644 docs/src/hsGraph/PlotBar.html create mode 100644 docs/src/hsGraph/PlotLine.html create mode 100644 docs/src/hsGraph/PlotMarkers.html create mode 100644 docs/src/hsGraph/SVGElem.html create mode 100644 docs/src/hsGraph/Scale.html create mode 100644 docs/src/hsGraph/Series.html create mode 100644 docs/src/hsGraph/SeriesLine.html create mode 100644 docs/src/hsGraph/example/start.html create mode 100644 docs/src/hsGraph/hsGraph.html create mode 100644 docs/src/hsGraph/index.html create mode 100644 docs/src/hsGraph/overview.html create mode 100644 docs/src/hsLayout/example/columns.x.html create mode 100644 docs/src/hsLayout/example/config.x.html create mode 100644 docs/src/hsLayout/example/layout.x.html create mode 100644 docs/src/hsLayout/example/start.html create mode 100644 docs/src/hsLayout/hsConfig.html create mode 100644 docs/src/hsLayout/index.html create mode 100644 docs/src/hsLayout/mithril.html create mode 100644 docs/src/hsLayout/overview.html create mode 100644 docs/src/hsLayout/view/Container.html create mode 100644 docs/src/hsLayout/view/Layout.html create mode 100644 docs/src/hsLayout/view/Layouter.html create mode 100644 docs/src/hsLayout/view/PillaredLayout.html create mode 100644 docs/src/hsLayout/view/PillaredLayout.spec.html create mode 100644 docs/src/hsLayout/view/PillaredLayouter.html create mode 100644 docs/src/hsLayout/view/PillaredLayouter.spec.html create mode 100644 docs/src/hsLayout/view/TileLayout.html create mode 100644 docs/src/hsLayout/view/TileLayouter.html create mode 100644 docs/src/hsLayout/view/Tokens.html create mode 100644 docs/src/hsNode/cpUtil.html create mode 100644 docs/src/hsNode/cpUtil.spec.html create mode 100644 docs/src/hsNode/date.html create mode 100644 docs/src/hsNode/date.spec.html create mode 100644 docs/src/hsNode/excel.html create mode 100644 docs/src/hsNode/excel.spec.html create mode 100644 docs/src/hsNode/fsUtil.html create mode 100644 docs/src/hsNode/fsUtil.spec.html create mode 100644 docs/src/hsNode/httpUtil.html create mode 100644 docs/src/hsNode/index.html create mode 100644 docs/src/hsNode/log.html create mode 100644 docs/src/hsNode/log.spec.html create mode 100644 docs/src/hsNode/node.html create mode 100644 docs/src/hsNode/node.spec.html create mode 100644 docs/src/hsStock/Home.html create mode 100644 docs/src/hsStock/Router.html create mode 100644 docs/src/hsStock/Site.html create mode 100644 docs/src/hsStock/controller/Assets.html create mode 100644 docs/src/hsStock/controller/Equities.html create mode 100644 docs/src/hsStock/controller/Equity.html create mode 100644 docs/src/hsStock/controller/EquityList.html create mode 100644 docs/src/hsStock/controller/EquityLoader.html create mode 100644 docs/src/hsStock/controller/Loader.html create mode 100644 docs/src/hsStock/controller/Trader.html create mode 100644 docs/src/hsStock/controller/TraderIEX.html create mode 100644 docs/src/hsStock/controller/Venue.html create mode 100644 docs/src/hsStock/controller/VenueIEX.html create mode 100644 docs/src/hsStock/fileIO.html create mode 100644 docs/src/hsStock/index.html create mode 100644 docs/src/hsStock/overview.html create mode 100644 docs/src/hsStock/saveToFile.html create mode 100644 docs/src/hsStock/server/convertInvestments.html create mode 100644 docs/src/hsStock/view/Equity.html create mode 100644 docs/src/hsStock/view/Header.html create mode 100644 docs/src/hsStock/view/Import.html create mode 100644 docs/src/hsStock/view/ImportPane.html create mode 100644 docs/src/hsStock/view/LeftNav.html create mode 100644 docs/src/hsStock/view/Main.html create mode 100644 docs/src/hsStock/view/MainDetails.html create mode 100644 docs/src/hsStock/view/MainGraph.html create mode 100644 docs/src/hsStock/view/MainMenu.html create mode 100644 docs/src/hsStock/view/Modal.html create mode 100644 docs/src/hsStock/view/SiteMenu.html create mode 100644 docs/src/hsStock/view/StockQuotes.html create mode 100644 docs/src/hsStock/view/Trade.html create mode 100644 docs/src/hsStock/view/TradePane.html create mode 100644 docs/src/hsStock/view/Trader.html create mode 100644 docs/src/hsStock/view/TraderIEX.html create mode 100644 docs/src/hsStock/view/View.html create mode 100644 docs/src/hsStock/view/ViewLeft.html create mode 100644 docs/src/hsStock/view/ViewPane.html create mode 100644 docs/src/hsUtil/Checksum.html create mode 100644 docs/src/hsUtil/Date.html create mode 100644 docs/src/hsUtil/Number.html create mode 100644 docs/src/hsUtil/PacingQueue.html create mode 100644 docs/src/hsUtil/TimedPromise.html create mode 100644 docs/src/hsUtil/hsChecksum.html create mode 100644 docs/src/hsUtil/hsTimedPromise.html create mode 100644 docs/src/hsUtil/hsUtil.html create mode 100644 docs/src/hsUtil/index.html create mode 100644 docs/src/hsUtil/overview.html create mode 100644 docs/src/hsUtil/showdown.html create mode 100644 docs/src/hsWidget/AddRemove.html create mode 100644 docs/src/hsWidget/Button.html create mode 100644 docs/src/hsWidget/Collapsible.html create mode 100644 docs/src/hsWidget/CornerButton.html create mode 100644 docs/src/hsWidget/DropOver.html create mode 100644 docs/src/hsWidget/Menu.html create mode 100644 docs/src/hsWidget/Menu.spec.html create mode 100644 docs/src/hsWidget/Modal.html create mode 100644 docs/src/hsWidget/OneOfButtons.html create mode 100644 docs/src/hsWidget/RadioButton.html create mode 100644 docs/src/hsWidget/Selector.html create mode 100644 docs/src/hsWidget/ToggleButton.html create mode 100644 docs/src/hsWidget/ToolbarButton.html create mode 100644 docs/src/hsWidget/TypeAhead.html create mode 100644 docs/src/hsWidget/example/start.html create mode 100644 docs/src/hsWidget/index.html create mode 100644 docs/src/hsWidget/overview.html create mode 100644 docs/src/hsWidgets/AddRemove.html create mode 100644 docs/src/hsWidgets/Button.html create mode 100644 docs/src/hsWidgets/Collapsible.html create mode 100644 docs/src/hsWidgets/Menu.html create mode 100644 docs/src/hsWidgets/Menu.spec.html create mode 100644 docs/src/hsWidgets/Modal.html create mode 100644 docs/src/hsWidgets/css/Button.html create mode 100644 docs/src/hsWidgets/example/start.html create mode 100644 docs/src/hsWidgets/index.html create mode 100644 docs/src/hsWidgets/overview.html delete mode 100755 package.json delete mode 100644 sharedGruntConfig.js delete mode 100644 src/Data.ts delete mode 100644 src/DataFilters.ts delete mode 100644 src/index.ts delete mode 100644 src/overview.ts delete mode 100644 tsconfigGrunt.json delete mode 100644 tslint.json diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100755 index 183d3fa..0000000 --- a/Gruntfile.js +++ /dev/null @@ -1,6 +0,0 @@ -/*global module:false*/ -module.exports = function(grunt) { - const sgc = require('./sharedGruntConfig')(grunt, __dirname, [], 'util'); - grunt.initConfig(sgc); -}; - diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 28baf98..0000000 --- a/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) HelpfulScripts 2015-2018 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index b507a29..0000000 --- a/README.md +++ /dev/null @@ -1,25 +0,0 @@ -*hsdatab* provides a JavaScript-based data management and query mechanism. - -Data is managed in a simple in-memory database that holds data in rows of columns. It autodetermines the types of data held in each column, along with the domain range for each column of data. A simple query language is -provided to filter matching data rows. - -## Usage -``` - -import { data } from 'hsdata'; - -// creating the data -const colNames = ['Name', 'Value', 'Start', 'End']; -const rows = [ - ['Harry', '100', '3/1/14', '11/20/14'], - ['Mary', '1500', '7/1/14', '9/30/14'], - ['Peter', '400', '5/20/14', '4/30/15'], - ['Jane', '700', '11/13/14', '8/15/15'] -]; -const data = new Data({colNames:colNames, rows:rows}); - -// querying the data -const query = {Name:["Peter", "Jane"]}; // query: Name is Peter or Jane -const result = data.filter(query); // returns new dataset with matching rows -console.log(result.getColumn('Name').join(', ')); // > Peter, Jane -``` diff --git a/docs/data/hsdatab.json b/docs/data/hsdatab.json new file mode 100644 index 0000000..8cc4011 --- /dev/null +++ b/docs/data/hsdatab.json @@ -0,0 +1,3395 @@ +{ + "id": 0, + "name": "hsdatab", + "kind": 0, + "flags": {}, + "children": [ + { + "id": 49, + "name": "\"Data\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.ts", + "comment": {}, + "children": [ + { + "id": 63, + "name": "Data", + "kind": 128, + "kindString": "Class", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "# Data\nA simple in-memory database that holds data in rows of columns." + }, + "children": [ + { + "id": 75, + "name": "constructor", + "kind": 512, + "kindString": "Constructor", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 76, + "name": "new Data", + "kind": 16384, + "kindString": "Constructor signature", + "flags": {}, + "parameters": [ + { + "id": 77, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 50 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 63 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 81, + "character": 5 + } + ] + }, + { + "id": 125, + "name": "data", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 381, + "character": 16 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 160 + } + }, + "defaultValue": " []" + }, + { + "id": 126, + "name": "meta", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 382, + "character": 16 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "MetaStruct", + "id": 57 + } + }, + "defaultValue": " []" + }, + { + "id": 127, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 383, + "character": 16 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 142, + "name": "allRows", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 143, + "name": "allRows", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "A generator that provides the specified column value for each row in `Data` in sequence." + }, + "parameters": [ + { + "id": 144, + "name": "column", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "\n" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ], + "type": { + "type": "reference", + "name": "Iterable", + "typeArguments": [ + { + "type": "reference", + "name": "DataVal", + "id": 159 + } + ] + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 482, + "character": 21 + } + ] + }, + { + "id": 112, + "name": "castData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 113, + "name": "castData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 249, + "character": 19 + } + ] + }, + { + "id": 149, + "name": "castVal", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 150, + "name": "castVal", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "The result of the cast.", + "tags": [ + { + "tag": "description", + "text": "Casts the sample to the specified data type.\n" + } + ] + }, + "parameters": [ + { + "id": 151, + "name": "type", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "The type to cast into. In case of _any_ - i.e. `type`\ndoes not match any of the previous keywords, no casting occurs." + }, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 152, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataVal", + "id": 159 + } + } + ], + "type": { + "type": "reference", + "name": "DataVal", + "id": 159 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 518, + "character": 19 + } + ] + }, + { + "id": 90, + "name": "colAdd", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 91, + "name": "colAdd", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "adds a new column to the data set. if `newCol` already exists,\nthe column index is returned withoput change.", + "returns": "the index for the new column\n" + }, + "parameters": [ + { + "id": 92, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the name of the new column" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 135, + "character": 17 + } + ] + }, + { + "id": 93, + "name": "colInitialize", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 94, + "name": "colInitialize", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "initializes the specifed column with values, adding a new column if needed.\nIf `val`is a function, it is called as ```\nval(colValue:DataVal, rowIndex:number, row:DataRow)\n```" + }, + "parameters": [ + { + "id": 95, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the column to initialize" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + }, + { + "id": 96, + "name": "initializer", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the value to initialize with, or a function whose return\nvalue is used to initialize the column\n" + }, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 157, + "character": 24 + } + ] + }, + { + "id": 100, + "name": "colName", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 101, + "name": "colName", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column name for the specified column.\n`col` can be either an index or a name.", + "returns": "the column name or `undefined`.\n" + }, + "parameters": [ + { + "id": 102, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 189, + "character": 18 + } + ] + }, + { + "id": 103, + "name": "colNames", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 104, + "name": "colNames", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the names for all columns.", + "returns": "an array of strings with the names.\n" + }, + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 200, + "character": 19 + } + ] + }, + { + "id": 97, + "name": "colNumber", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 98, + "name": "colNumber", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column index of the specified column.\n`col` can be either an index or a name.", + "returns": "the column number or `undefined`.\n" + }, + "parameters": [ + { + "id": 99, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 174, + "character": 20 + } + ] + }, + { + "id": 105, + "name": "colType", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 106, + "name": "colType", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column type for the specified column.\n`col` can be either an index or a name.", + "returns": "the column type.\n" + }, + "parameters": [ + { + "id": 107, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 210, + "character": 18 + } + ] + }, + { + "id": 83, + "name": "export", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 84, + "name": "export", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Exports to an object literal" + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 50 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 106, + "character": 17 + } + ] + }, + { + "id": 114, + "name": "filter", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 115, + "name": "filter", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "filters this data set and returns a new data set with a\nshallow copy of rows that pass the `condition`.\nSee {@link DataFilters DataFilters} for rules and examples on how to construct conditions.", + "returns": "a new Data object with rows that pass the filter\n" + }, + "parameters": [ + { + "id": 116, + "name": "condition", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "filters" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 63 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 266, + "character": 17 + } + ] + }, + { + "id": 108, + "name": "findDomain", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 109, + "name": "findDomain", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "modifies `domain` to include all values in column `col`." + }, + "parameters": [ + { + "id": 110, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the column name or index" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + }, + { + "id": 111, + "name": "domain", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the\n" + }, + "type": { + "type": "reference", + "name": "Domain", + "id": 157 + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 220, + "character": 21 + } + ] + }, + { + "id": 139, + "name": "findType", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 140, + "name": "findType", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample\n", + "tags": [ + { + "tag": "description", + "text": "determines the data type. Supported types are\n```\n'date': sample represents a Date, either as a Date object or a String\n'number': sample represents a number\n'percent': sample represents a percentage (special case of a real number)\n'nominal': sample represents a nominal (ordinal or categorical) value\n```" + } + ] + }, + "parameters": [ + { + "id": 141, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the value to bve typed." + }, + "type": { + "type": "reference", + "name": "DataVal", + "id": 159 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 451, + "character": 20 + } + ] + }, + { + "id": 136, + "name": "findTypes", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 137, + "name": "findTypes", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Determines the type of data in `col`. An array of counts is created for all\nencountered types, sorted by descending frequency. THe most likely type in position 0\nof the array is returned.", + "returns": "the most likely type of data in `col`.\n" + }, + "parameters": [ + { + "id": 138, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the index of the column to be typed." + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 419, + "character": 21 + } + ] + }, + { + "id": 87, + "name": "getColumn", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 88, + "name": "getColumn", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Returns the values in the specified column as a new array." + }, + "parameters": [ + { + "id": 89, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the column to return.\n" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 159 + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 124, + "character": 20 + } + ] + }, + { + "id": 85, + "name": "getData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 86, + "name": "getData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the 2D array underlying the data base." + }, + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 160 + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 116, + "character": 18 + } + ] + }, + { + "id": 128, + "name": "getMeta", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 129, + "name": "getMeta", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 130, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ], + "type": { + "type": "reference", + "name": "MetaStruct", + "id": 57 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 385, + "character": 19 + } + ] + }, + { + "id": 78, + "name": "getName", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 79, + "name": "getName", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the `name` field for this data base, if any\n" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 90, + "character": 18 + } + ] + }, + { + "id": 80, + "name": "import", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 81, + "name": "import", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Imports data from an object literal `data`" + }, + "parameters": [ + { + "id": 82, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data set to import\n" + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 50 + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 98, + "character": 17 + } + ] + }, + { + "id": 121, + "name": "map", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 122, + "name": "map", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": " Maps one or more columns in each rows of values based\non the result of the `mapFn`, which behaves similarly to the Array.map() method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the `mapFn` is passed the column arrays per row as parameter.\nThis allows for complex mapping combining conditions across multiple columns.\n```\ndata.map(function(values){\n values[1] = values[3] * values[5];\n return values;\n});\n```\nBe sure to return the `values` array as a result.\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `mapFn`, along with the row index and the entire row array. This allows for simple mapping.\n```\ndata.map('Price', function(value, i, values) {\n return value * 2;\n});\n```", + "returns": "a new Data object containing the mapping.\n" + }, + "parameters": [ + { + "id": 123, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data column, or columns, to apply the mapping to." + }, + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "ColumnReference", + "id": 158 + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ] + } + }, + { + "id": 124, + "name": "mapFn", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "a function to implement the mapping,\ncalled on each row of the data set in turn as `mapFn(val, i, c, rows)`, where\n- `val`: the column value in the current row\n- `c`: the column index in the current row\n- `i`: the row index\n- `rows`: the rows being iterated over\n` *\nfollows the same specifications as the function passed to Array.map().
\nFor column mode, some predefined map functions can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
'noop'replace value with itself, performing no operation.
'cumulate'replace value with the cumulative sum of values up to the current element.
" + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "mapFn", + "id": 124 + } + ] + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 63 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 348, + "character": 14 + } + ] + }, + { + "id": 131, + "name": "setData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 132, + "name": "setData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "sets `data` to the existing data set. If data has previously been set,\n`data` will be added to the end of the list if all `names` match those of the\nexisting set." + }, + "parameters": [ + { + "id": 133, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data to add" + }, + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 160 + } + } + }, + { + "id": 134, + "name": "names", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "an array of names that match the columns" + }, + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 135, + "name": "autoType", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "unless set to false, the method will attempt to determine the\ntype of data and automatically cast data points to their correct value\n" + }, + "type": { + "type": "intrinsic", + "name": "boolean" + }, + "defaultValue": "true" + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 401, + "character": 19 + } + ] + }, + { + "id": 117, + "name": "sort", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 118, + "name": "sort", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the Data object in order to allow for chaining.\n", + "tags": [ + { + "tag": "description", + "text": "Sorts the rows of values based on the result of the `sortFn`,\nwhich behaves similarly to the Array.sort method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the column arrays are passed as samples into the `sortFn`.\nThis allows for complex sorts, combining conditions across multiple columns.\n```\ndata.sort((row1, row2) => row1[5] - row2[5] );\n```\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `sortFn`. This allows filtering for simple conditions.
\n**The specified column will be automatically cast prior to sorting**
\n`data.sort('Date', function(val1, val2) { return val1 - val2; });`" + } + ] + }, + "parameters": [ + { + "id": 119, + "name": "sortFn", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "a function to implement the conditions,\nfollows the same specifications as the function passed to Array.sort().\nSome predefined sort function can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
'`ascending`'sort in ascending order.
'`descending`'sort in decending order.
" + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "sortFn", + "id": 119 + } + ] + } + }, + { + "id": 120, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the data column to use for sorting." + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 158 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 63 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 296, + "character": 15 + } + ] + }, + { + "id": 145, + "name": "toDate", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 146, + "name": "toDate", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "a new Date object parsed from `str`.", + "tags": [ + { + "tag": "description", + "text": "returns a new Date object parsed from `str` and corrects for a difference in\ninterpreting centuries between webkit and mozilla in converting strings to Dates:\nThe string \"15/7/03\" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.\nIf `limitYear` is not specified this method uses 1970 as the decision date:\nyears 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.\n" + } + ] + }, + "parameters": [ + { + "id": 147, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the string to convert to a date" + }, + "type": { + "type": "reference", + "name": "DataVal", + "id": 159 + } + }, + { + "id": 148, + "name": "limitYear", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the year below which the century is corrected. Defaults to 1970." + }, + "type": { + "type": "intrinsic", + "name": "number" + }, + "defaultValue": "1970" + } + ], + "type": { + "type": "reference", + "name": "Date" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 499, + "character": 18 + } + ] + }, + { + "id": 71, + "name": "toDataSet", + "kind": 2048, + "kindString": "Method", + "flags": { + "isStatic": true, + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 72, + "name": "toDataSet", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 73, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataLiteralSet", + "id": 161 + } + }, + { + "id": 74, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "reference", + "name": "DataSet", + "id": 50 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 75, + "character": 27 + } + ] + }, + { + "id": 64, + "name": "type", + "kind": 2097152, + "kindString": "Object literal", + "flags": { + "isStatic": true, + "isExported": true, + "isPublic": true + }, + "children": [ + { + "id": 68, + "name": "currency", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 70, + "character": 16 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"currency data\"" + }, + { + "id": 67, + "name": "date", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 69, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"date data\"" + }, + { + "id": 66, + "name": "name", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 68, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"name data\"" + }, + { + "id": 70, + "name": "nominal", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 72, + "character": 15 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"nominal data\"" + }, + { + "id": 65, + "name": "number", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 67, + "character": 14 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"number data\"" + }, + { + "id": 69, + "name": "percent", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 71, + "character": 15 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"percent data\"" + } + ], + "groups": [ + { + "title": "Variables", + "kind": 32, + "children": [ + 68, + 67, + 66, + 70, + 65, + 69 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 66, + "character": 22 + } + ], + "type": { + "type": "intrinsic", + "name": "object" + } + } + ], + "groups": [ + { + "title": "Constructors", + "kind": 512, + "children": [ + 75 + ] + }, + { + "title": "Properties", + "kind": 1024, + "children": [ + 125, + 126, + 127 + ] + }, + { + "title": "Methods", + "kind": 2048, + "children": [ + 142, + 112, + 149, + 90, + 93, + 100, + 103, + 97, + 105, + 83, + 114, + 108, + 139, + 136, + 87, + 85, + 128, + 78, + 80, + 121, + 131, + 117, + 145, + 71 + ] + }, + { + "title": "Object literals", + "kind": 2097152, + "children": [ + 64 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 62, + "character": 17 + } + ] + }, + { + "id": 50, + "name": "DataSet", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a JSON format data set, using arrays of names and rows" + }, + "children": [ + { + "id": 52, + "name": "colNames", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "an array of column names. Each name matches the column with the same index in DataRow" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 36, + "character": 12 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 51, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "comment": { + "shortText": "an optional name for the data set" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 34, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 53, + "name": "rows", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "rows of data" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 38, + "character": 8 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 160 + } + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 52, + 51, + 53 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 32, + "character": 24 + } + ] + }, + { + "id": 57, + "name": "MetaStruct", + "kind": 256, + "kindString": "Interface", + "flags": {}, + "children": [ + { + "id": 60, + "name": "accessed", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 49, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 61, + "name": "cast", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 50, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 59, + "name": "column", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 48, + "character": 10 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 58, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 47, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 62, + "name": "types", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 51, + "character": 9 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "TypeStruct", + "id": 54 + } + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 60, + 61, + 59, + 58, + 62 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 46, + "character": 20 + } + ] + }, + { + "id": 54, + "name": "TypeStruct", + "kind": 256, + "kindString": "Interface", + "flags": {}, + "children": [ + { + "id": 56, + "name": "count", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 42 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 55, + "name": "type", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 27 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 56, + 55 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 20 + } + ] + }, + { + "id": 158, + "name": "ColumnReference", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 23, + "character": 27 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "string" + } + ] + } + }, + { + "id": 161, + "name": "DataLiteralSet", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a JSON format data set, using an array of {name:value, ...} literals" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 42, + "character": 26 + } + ], + "type": { + "type": "reference", + "name": "Array", + "typeArguments": [ + { + "type": "intrinsic", + "name": "any" + } + ] + } + }, + { + "id": 160, + "name": "DataRow", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a single row of column values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 29, + "character": 19 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 159 + } + } + }, + { + "id": 159, + "name": "DataVal", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a generic data value type, used in the {@link Data.DataRow `DataRow`} array" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 26, + "character": 19 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "Date" + } + ] + } + }, + { + "id": 155, + "name": "DateDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a Date domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 14, + "character": 22 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "reference", + "name": "Date" + }, + { + "type": "reference", + "name": "Date" + } + ] + } + }, + { + "id": 157, + "name": "Domain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a generic domain that can be any of the typed domains." + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 20, + "character": 18 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "NumDomain", + "id": 154 + }, + { + "type": "reference", + "name": "DateDomain", + "id": 155 + }, + { + "type": "reference", + "name": "NameDomain", + "id": 156 + } + ] + } + }, + { + "id": 156, + "name": "NameDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a categorical domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 17, + "character": 22 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 154, + "name": "NumDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a numeric domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 11, + "character": 21 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "number" + } + ] + } + }, + { + "id": 153, + "name": "NumRange", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a [min-max] range" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 8, + "character": 20 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "number" + } + ] + } + }, + { + "id": 167, + "name": "mapFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 55, + "character": 17 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 168, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 169, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 170, + "name": "colVal", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 171, + "name": "colIndex", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 172, + "name": "rowIndex", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 173, + "name": "rows", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "array", + "elementType": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "any" + } + } + } + } + ], + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 55, + "character": 20 + } + ] + } + } + }, + { + "id": 162, + "name": "sortFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 54, + "character": 18 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 163, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 164, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 165, + "name": "x", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 166, + "name": "y", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 54, + "character": 20 + } + ] + } + } + } + ], + "groups": [ + { + "title": "Classes", + "kind": 128, + "children": [ + 63 + ] + }, + { + "title": "Interfaces", + "kind": 256, + "children": [ + 50, + 57, + 54 + ] + }, + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 158, + 161, + 160, + 159, + 155, + 157, + 156, + 154, + 153, + 167, + 162 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 1, + "name": "\"DataFilters\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/DataFilters.ts", + "comment": { + "shortText": "The HsData object will feature its own column meta information, as well as\na copy of the rows array which allows for `filter` and `sort` operations.\nHowever, the column arrays will be shared with the original HsData object in order to be memory efficient.\nThis means that `map` and `newColumn` operations on the new object will affect the original object or any\nobject derived via `query`.", + "tags": [ + { + "tag": "description", + "text": "executes a query on the data. Each row in the data is checked and those for which\n`conditions` is true are returned as a new HsData object.\n\n## General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n## IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n## RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n## Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdata.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" + } + ] + }, + "children": [ + { + "id": 2, + "name": "SetAndCondition", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "children": [ + { + "id": 4, + "name": "and", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 144, + "character": 7 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + }, + { + "id": 5, + "name": "not", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 145, + "character": 7 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + }, + { + "id": 3, + "name": "or", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 143, + "character": 6 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 4, + 5, + 3 + ] + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 142, + "character": 32 + } + ] + }, + { + "id": 6, + "name": "TermAndCondition", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "indexSignature": [ + { + "id": 7, + "name": "__index", + "kind": 8192, + "kindString": "Index signature", + "flags": {}, + "parameters": [ + { + "id": 8, + "name": "colDesc", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "DataVal", + "id": 159 + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 159 + } + }, + { + "type": "reference", + "name": "TermConditionFunction", + "id": 14 + } + ] + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 148, + "character": 33 + } + ] + }, + { + "id": 13, + "name": "AndCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 140, + "character": 24 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "SetAndCondition", + "id": 2 + }, + { + "type": "reference", + "name": "TermAndCondition", + "id": 6 + } + ] + } + }, + { + "id": 9, + "name": "Condition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 133, + "character": 21 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "IndexCondition", + "id": 10 + }, + { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + ] + } + }, + { + "id": 10, + "name": "IndexCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "true if row index matches the number(s)" + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 136, + "character": 26 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 12, + "name": "OrCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 139, + "character": 23 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "array", + "elementType": { + "type": "reference", + "name": "AndCondition", + "id": 13 + } + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "IndexCondition", + "id": 10 + } + } + ] + } + }, + { + "id": 11, + "name": "RecursiveCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 138, + "character": 30 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "AndCondition", + "id": 13 + }, + { + "type": "reference", + "name": "OrCondition", + "id": 12 + } + ] + } + }, + { + "id": 38, + "name": "ReduceFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 231, + "character": 20 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 39, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 40, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 41, + "name": "keep", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 42, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 160 + } + }, + { + "id": 43, + "name": "i", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 231, + "character": 22 + } + ] + } + } + }, + { + "id": 14, + "name": "TermConditionFunction", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 156, + "character": 33 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 15, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 16, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 17, + "name": "value", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataVal", + "id": 159 + } + }, + { + "id": 18, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 160 + } + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 156, + "character": 35 + } + ] + } + } + }, + { + "id": 44, + "name": "filter", + "kind": 64, + "kindString": "Function", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 45, + "name": "filter", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 46, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "Data", + "id": 63 + } + }, + { + "id": 47, + "name": "cond", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + }, + { + "id": 48, + "name": "reduceFn", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "ReduceFn", + "id": 38 + } + ] + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 63 + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 233, + "character": 22 + } + ] + }, + { + "id": 28, + "name": "resolveCondition", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 29, + "name": "resolveCondition", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "applies `condition` to a row of data and returns `true` if the row passes." + }, + "parameters": [ + { + "id": 30, + "name": "condition", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the complex condition to test against" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + }, + { + "id": 31, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the row values" + }, + "type": { + "type": "reference", + "name": "DataRow", + "id": 160 + } + }, + { + "id": 32, + "name": "r", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the row index in the data set" + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 33, + "name": "colNumber", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reflection", + "declaration": { + "id": 34, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 35, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 36, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 185, + "character": 80 + } + ] + } + } + }, + { + "id": 37, + "name": "and", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "\n" + }, + "type": { + "type": "intrinsic", + "name": "boolean" + }, + "defaultValue": "true" + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 185, + "character": 25 + } + ] + }, + { + "id": 19, + "name": "resolveTerminalCondition", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 20, + "name": "resolveTerminalCondition", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 21, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 22, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 23, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 160 + } + }, + { + "id": 24, + "name": "colNumber", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reflection", + "declaration": { + "id": 25, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 26, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 27, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 159, + "character": 79 + } + ] + } + } + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 159, + "character": 33 + } + ] + } + ], + "groups": [ + { + "title": "Interfaces", + "kind": 256, + "children": [ + 2, + 6 + ] + }, + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 13, + 9, + 10, + 12, + 11, + 38, + 14 + ] + }, + { + "title": "Functions", + "kind": 64, + "children": [ + 44, + 28, + 19 + ] + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 174, + "name": "\"index\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/index.ts", + "sources": [ + { + "fileName": "index.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 175, + "name": "\"overview\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", + "comment": { + "shortText": "# hsData", + "text": "Helpful Scripts data management functions that are framework independent.\n\n## Data Types\n-   {@link Data.NumRange NumRange} defines a single [min, max] numeric range.\n-   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column\n-   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column\n-   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column\n-   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains.\n-   {@link Data.ColSpecifier ColSpecifier} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array\n-   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array\n-   {@link Data.DataRow DataRow} a single row of column values\n\n## Data Class\n-   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions\n" + }, + "sources": [ + { + "fileName": "overview.ts", + "line": 1, + "character": 0 + } + ] + } + ], + "groups": [ + { + "title": "External modules", + "kind": 1, + "children": [ + 49, + 1, + 174, + 175 + ] + } + ] +} \ No newline at end of file diff --git a/docs/data/index.json b/docs/data/index.json new file mode 100644 index 0000000..ce75152 --- /dev/null +++ b/docs/data/index.json @@ -0,0 +1,6 @@ +{ + "docs": [ + "hsdatab.json" + ], + "title": "HS Libraries" +} \ No newline at end of file diff --git a/docs/example/defEquityList.json b/docs/example/defEquityList.json new file mode 100644 index 0000000..4e1244a --- /dev/null +++ b/docs/example/defEquityList.json @@ -0,0 +1,10 @@ +{ + "Stocks": { + "GOOG": "Alphabet", + "MSFT": "Microsoft", + "AAPL": "Apple" + }, + "Bonds": {}, + "ETFs": {}, + "Indices":{} +} \ No newline at end of file diff --git a/docs/example/equityList.json b/docs/example/equityList.json new file mode 100644 index 0000000..4e1244a --- /dev/null +++ b/docs/example/equityList.json @@ -0,0 +1,10 @@ +{ + "Stocks": { + "GOOG": "Alphabet", + "MSFT": "Microsoft", + "AAPL": "Apple" + }, + "Bonds": {}, + "ETFs": {}, + "Indices":{} +} \ No newline at end of file diff --git a/docs/example/hsGraph.js b/docs/example/hsGraph.js new file mode 100644 index 0000000..c3e4b83 --- /dev/null +++ b/docs/example/hsGraph.js @@ -0,0 +1,10647 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 18); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__view_PillaredLayouter__ = __webpack_require__(21); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__view_TileLayouter__ = __webpack_require__(22); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__view_Layout__ = __webpack_require__(23); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Layout", function() { return __WEBPACK_IMPORTED_MODULE_2__view_Layout__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__view_Tokens__ = __webpack_require__(4); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "FILL", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["b"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "px", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["g"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "pc", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["f"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "LayoutToken", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["d"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__view_Layouter__ = __webpack_require__(3); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Layouter", function() { return __WEBPACK_IMPORTED_MODULE_4__view_Layouter__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__hsConfig__ = __webpack_require__(36); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "HsConfig", function() { return __WEBPACK_IMPORTED_MODULE_5__hsConfig__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__mithril__ = __webpack_require__(7); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "m", function() { return __WEBPACK_IMPORTED_MODULE_6__mithril__["a"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "o", function() { return __WEBPACK_IMPORTED_MODULE_6__mithril__["b"]; }); + +if (__WEBPACK_IMPORTED_MODULE_0__view_PillaredLayouter__) { } + +if (__WEBPACK_IMPORTED_MODULE_1__view_TileLayouter__) { } + + + + + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxLQUFLLE9BQU8sTUFBVSx5QkFBeUIsQ0FBQztBQUFNLElBQUcsT0FBTyxFQUFFLEdBQUU7QUFDM0UsT0FBTyxLQUFLLEtBQUssTUFBWSxxQkFBcUIsQ0FBQztBQUFVLElBQUcsS0FBSyxFQUFFLEdBQUU7QUFFekUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFTLGVBQWUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQ1osV0FBVyxFQUFFLE1BQU8sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBVSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVUsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxDQUFDLEVBQVMsQ0FBQyxFQUFFLE1BQU8sV0FBVyxDQUFBIn0= + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["d"] = round; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return TextHAlign; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return TextVAlign; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); + +function round(num) { + const result = num.toFixed(1); + if (result === 'Infinity') { + return '1e20'; + } + return result; +} +var TextHAlign; +(function (TextHAlign) { + TextHAlign["start"] = "start"; + TextHAlign["middle"] = "middle"; + TextHAlign["end"] = "end"; +})(TextHAlign || (TextHAlign = {})); +var TextVAlign; +(function (TextVAlign) { + TextVAlign["top"] = "top"; + TextVAlign["center"] = "center"; + TextVAlign["bottom"] = "bottom"; +})(TextVAlign || (TextVAlign = {})); +class SVGElem { + text(cfg, text) { + let yShift = 0; + let hAlign = cfg.xpos; + switch (cfg.xpos) { + case TextHAlign.start: break; + case TextHAlign.end: break; + case TextHAlign.middle: + default: + hAlign = TextHAlign.middle; + break; + } + switch (cfg.ypos) { + case TextVAlign.top: + yShift = 0.7; + break; + case TextVAlign.center: + yShift = 0.35; + break; + case TextVAlign.bottom: + default: + yShift = 0; + break; + } + const param = { + x: cfg.x || '', + y: cfg.y || '', + dx: round(cfg.hOffset || 0) + 'em', + dy: round((cfg.vOffset || 0) + yShift) + 'em', + style: `text-anchor:${hAlign}; ${cfg.style || ''}`, + class: cfg.cssClass, + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('text', param, text); + } + rect(tl, area, style, title) { + if (area.w < 0) { + tl.x += area.w; + area.w = -area.w; + } + if (area.h < 0) { + tl.y += area.h; + area.h = -area.h; + } + const param = { + x: round(tl.x), y: round(tl.y), + width: round(area.w) + (area.wunit || ''), + height: round(area.h) + (area.hunit || ''), + style: style + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('rect', param), Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title); + } + circle(c, r, style, title) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('circle', { cx: round(c.x), cy: round(c.y), r: round(r), style: style }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); + } + clipRect(tl, area, id) { + const param = { + x: round(tl.x), y: round(tl.y), + width: round(area.w) + (area.wunit || ''), + height: round(area.h) + (area.hunit || '') + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('defs', Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('clipPath', { id: id }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('rect', param))); + } + line(x0, x1, y0, y1, cssClass) { + const param = { + x1: round(x0), y1: round(y0), + x2: round(x1), y2: round(y1), + class: cssClass + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); + } + horLine(x0, x1, y, cssClass) { + const param = { + x1: round(x0), y1: round(y), + x2: round(x1), y2: round(y), + class: cssClass + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); + } + verLine(x, y0, y1, cssClass) { + const param = { + x1: round(x), y1: round(y0), + x2: round(x), y2: round(y1), + class: cssClass + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); + } + polyline(data, x, y, scales, id, style, title) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polyline', { + 'clip-path': id ? `url(#${id})` : undefined, + style: style, + points: data.map((row) => `${round(scales.x.convert(row[x]))},${round(scales.y.convert(row[y]))}`).join(' ') + }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); + } + polygon(dataFore, dataBack, x, yFore, yBack, scales, id, style, title) { + const indexed = (x === undefined); + const sx = (_x) => round(scales.x.convert(_x)); + const sy = (_y) => round(scales.y.convert(_y)); + const clip = id ? `url(#${id})` : undefined; + const points = dataFore.map((row, i) => `${sx(indexed ? i : row[x])},${sy(row[yFore])}`) + .concat(dataBack.map((row, i) => `${sx(indexed ? (dataBack.length - i - 1) : row[x])},${sy(yBack ? row[yBack] : 0)}`)).join(' '); + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polygon', { 'clip-path': clip, style: style, points: points }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); + } + shape(points, id, style, title) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polyline', { + 'clip-path': id ? `url(#${id})` : undefined, + style: style, + points: points.map((row) => `${round(row[0])},${round(row[1])}`).join(' ') + }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = SVGElem; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU1ZHRWxlbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9TVkdFbGVtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxDQUFDLEVBQVMsTUFBTSxVQUFVLENBQUM7QUF3RXBDLE1BQU0sZ0JBQWlCLEdBQVU7SUFDN0IsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QixJQUFJLE1BQU0sS0FBSyxVQUFVLEVBQUU7UUFDdkIsT0FBTyxNQUFNLENBQUM7S0FDakI7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNsQixDQUFDO0FBRUQsTUFBTSxDQUFOLElBQVksVUFJWDtBQUpELFdBQVksVUFBVTtJQUNsQiw2QkFBaUIsQ0FBQTtJQUNqQiwrQkFBa0IsQ0FBQTtJQUNsQix5QkFBZSxDQUFBO0FBQ25CLENBQUMsRUFKVyxVQUFVLEtBQVYsVUFBVSxRQUlyQjtBQUVELE1BQU0sQ0FBTixJQUFZLFVBSVg7QUFKRCxXQUFZLFVBQVU7SUFDbEIseUJBQWUsQ0FBQTtJQUNmLCtCQUFrQixDQUFBO0lBQ2xCLCtCQUFrQixDQUFBO0FBQ3RCLENBQUMsRUFKVyxVQUFVLEtBQVYsVUFBVSxRQUlyQjtBQUVELE1BQU07SUFNRixJQUFJLENBQUMsR0FBWSxFQUFFLElBQVc7UUFDMUIsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ2YsSUFBSSxNQUFNLEdBQWMsR0FBRyxDQUFDLElBQUksQ0FBQztRQUNqQyxRQUFPLEdBQUcsQ0FBQyxJQUFJLEVBQUU7WUFDYixLQUFLLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBRSxNQUFNO1lBQzlCLEtBQUssVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFJLE1BQU07WUFDOUIsS0FBSyxVQUFVLENBQUMsTUFBTSxDQUFDO1lBQ3ZCO2dCQUFlLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDO2dCQUFDLE1BQU07U0FDcEQ7UUFDRCxRQUFPLEdBQUcs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 + +/***/ }), +/* 2 */ +/***/ (function(module, exports) { + +var g; + +// This works in non-strict mode +g = (function() { + return this; +})(); + +try { + // This works if eval is allowed (see CSP) + g = g || Function("return this")() || (1,eval)("this"); +} catch(e) { + // This works if the window reference is available + if(typeof window === "object") + g = window; +} + +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} + +module.exports = g; + + +/***/ }), +/* 3 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Tokens__ = __webpack_require__(4); + +class Layouter { + constructor(areaDesc) { + this.areaDesc = areaDesc; + this.spacing = 0; + } + static translate(params) { + if (params.length === 0) { + params.push(''); + } + return params.map((param) => { + if (typeof param === 'string') { + if (param.endsWith('px')) { + return Object(__WEBPACK_IMPORTED_MODULE_0__Tokens__["g" /* px */])(parseInt(param)); + } + if (param.endsWith('%')) { + return Object(__WEBPACK_IMPORTED_MODULE_0__Tokens__["f" /* pc */])(parseInt(param)); + } + if (param.toLowerCase() === 'fill') { + return __WEBPACK_IMPORTED_MODULE_0__Tokens__["b" /* FILL */]; + } + } + else { + return param; + } + }); + } + static register(keyword, style) { + Layouter.layoutStyles[keyword] = style; + } + static createLayout(attrs, components) { + let css = ''; + Object.keys(Layouter.layoutStyles).some(key => { + if (attrs[key]) { + css = new Layouter.layoutStyles[key](Layouter.translate(attrs[key])).getStyles(components); + attrs[key] = undefined; + return true; + } + return false; + }); + return css; + } + ; +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Layouter; + +Layouter.layoutStyles = {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5b3V0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdmlldy9MYXlvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFhQSxPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxVQUFVLENBQUM7QUF5QnhDLE1BQU07SUF5RUYsWUFBbUIsUUFBc0I7UUFBdEIsYUFBUSxHQUFSLFFBQVEsQ0FBYztRQVJ6QyxZQUFPLEdBQUcsQ0FBQyxDQUFDO0lBUWdDLENBQUM7SUF6RHJDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBd0I7UUFDN0MsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7U0FBRTtRQUM3QyxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFnQixFQUFFLEVBQUU7WUFDbkMsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUU7Z0JBQzNCLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRTtvQkFBRSxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFBRTtnQkFDekQsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO29CQUFFLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO2lCQUFFO2dCQUN4RCxJQUFJLEtBQUssQ0FBQyxXQUFXLEVBQUUsS0FBRyxNQUFNLEVBQUU7b0JBQUUsT0FBTyxJQUFJLENBQUM7aUJBQUM7YUFDcEQ7aUJBQU07Z0JBQ0gsT0FBTyxLQUFLLENBQUM7YUFDaEI7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFXTSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQWMsRUFBRSxLQUFxQjtRQUV4RCxRQUFRLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUMzQyxDQUFDO0lBVU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxLQUFTLEVBQUUsVUFBdUI7UUFDekQsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBQ2IsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQzFDLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUNaLEdBQUcsR0FBRyxJQUFJLFFBQVEsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDM0YsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsQ0FBQztnQkFDdkIsT0FBTyxJQUFJLENBQUM7YUFDZjtZQUNELE9BQU8sS0FBSyxDQUFDO1FBQ2pCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0lBVzRDLENBQUM7O0FBcEV2QyxxQkFBWSxHQUF1QixFQUFFLENBQUMifQ== + +/***/ }), +/* 4 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["g"] = px; +/* harmony export (immutable) */ __webpack_exports__["f"] = pc; +class LayoutToken { + constructor(size) { + this.size = size; + } + getSize() { return this.size; } +} +/* harmony export (immutable) */ __webpack_exports__["d"] = LayoutToken; + +class DefinedToken extends LayoutToken { + constructor(size) { super(size); } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = DefinedToken; + +class FillToken extends LayoutToken { + constructor() { super(-1); } +} +/* harmony export (immutable) */ __webpack_exports__["c"] = FillToken; + +class PixelToken extends DefinedToken { + constructor(size) { super(size); } +} +/* harmony export (immutable) */ __webpack_exports__["e"] = PixelToken; + +class PercentToken extends DefinedToken { + constructor(size) { super(size); } +} +/* unused harmony export PercentToken */ + +function px(px) { return new PixelToken(px); } +function pc(pc) { return new PercentToken(pc); } +const FILL = new FillToken(); +/* harmony export (immutable) */ __webpack_exports__["b"] = FILL; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9rZW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvVG9rZW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE1BQU07SUFDRixZQUFvQixJQUFZO1FBQVosU0FBSSxHQUFKLElBQUksQ0FBUTtJQUFHLENBQUM7SUFDN0IsT0FBTyxLQUFLLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Q0FDekM7QUFLRCxNQUFNLG1CQUE2QixTQUFRLFdBQVc7SUFDbEQsWUFBWSxJQUFZLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUM3QztBQUtELE1BQU0sZ0JBQWlCLFNBQVEsV0FBVztJQUN0QyxnQkFBZ0IsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0NBQy9CO0FBS0QsTUFBTSxpQkFBa0IsU0FBUSxZQUFZO0lBQ3hDLFlBQVksSUFBVyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Q0FDNUM7QUFLRCxNQUFNLG1CQUFvQixTQUFRLFlBQVk7SUFDMUMsWUFBWSxJQUFXLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUM1QztBQU1ELE1BQU0sYUFBYSxFQUFTLElBQU0sT0FBTyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFNOUQsTUFBTSxhQUFhLEVBQVMsSUFBTSxPQUFPLElBQUksWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUtoRSxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQyJ9 + +/***/ }), +/* 5 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); + +; + +function getCrossAt(cross, scale) { + let crossesAt; + switch (cross) { + case 'min': + crossesAt = scale.domain()[0]; + break; + case 'max': + crossesAt = scale.domain()[1]; + break; + default: crossesAt = cross || 0; + } + return scale.convert(crossesAt); +} +class Axes extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { + static defaultConfig(cfg) { + function scaleCfg() { + return { + type: Axes.type.linear, + domain: ['auto', 'auto'] + }; + } + function labelCfg(primary, x, major) { + return { + visible: major, text: '', + xpos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].end : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].start), + ypos: x ? (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].bottom) : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].center, + hOffset: x ? 0 : (primary ? -0.7 : 0.7), + vOffset: x ? (primary ? 0.7 : -0.7) : 0 + }; + } + function markCfg(primary, major) { + return { + visible: major, + length: (primary ? 1 : -1) * (major ? 10 : 5) + }; + } + function titleCfg(primary, x) { + return { + visible: true, text: (x ? 'x' : 'y') + (primary ? '' : '2'), + xpos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].end : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].start), + ypos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].bottom : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top), + hOffset: x ? -2 : (primary ? 0 : 0.3), + vOffset: x ? (primary ? 0.4 : -1.2) : (primary ? -0.5 : 0.7) + }; + } + function axisCfg(primary, x) { + return { + visible: primary ? true : false, + crossesAt: primary ? 'min' : 'max', + scale: scaleCfg(), + title: titleCfg(primary, x), + ticks: { + major: { + marks: markCfg(primary, true), + labels: labelCfg(primary, x, true), + labelFmt: undefined + }, + minor: { + marks: markCfg(primary, false), + labels: labelCfg(primary, x, false), + labelFmt: undefined + } + } + }; + } + cfg.axes = { + primary: { + x: axisCfg(true, true), + y: axisCfg(true, false) + }, + secondary: { + x: axisCfg(false, true), + y: axisCfg(false, false) + } + }; + } + static adjustConfig(cfg) { + } + drawAxisLine(x, range, cross) { + return x ? this.horLine(range[0], range[1], cross, 'hs-graph-axis-line') : + this.verLine(cross, range[0], range[1], 'hs-graph-axis-line'); + } + drawTitle(x, ttlCfg, type, range, cross) { + ttlCfg.cssClass = 'hs-graph-axis-title'; + const xy = { transform: `translate(${x ? range[1] : cross}, ${x ? cross : range[1]})` }; + return !ttlCfg.visible ? undefined : + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('g', xy, this.text(ttlCfg, ttlCfg.text)); + } + drawTickMarks(x, type, crossesAt, scale, ticks, cfg) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${type}-tick-marks` }, !cfg.marks.visible ? '' : ticks.marks.map((t) => { + return x ? this.verLine(scale.convert(t), crossesAt, crossesAt + cfg.marks.length) : + this.horLine(crossesAt, crossesAt - cfg.marks.length, scale.convert(t)); + })); + } + drawTickLabels(x, type, crossesAt, scale, ticks, cfg) { + scale.setLabelFormat(cfg.labelFmt); + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${type}-tick-label` }, !cfg.labels.visible ? '' : ticks.labels.map((t) => { + const v = scale.convert(t.pos); + const xy = { transform: `translate(${x ? v : crossesAt}, ${x ? crossesAt : v})` }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('g', xy, this.text(cfg.labels, t.text)); + })); + } + drawAxis(dir, scales, type, axisCfg) { + const x = dir === 'x'; + const range = scales[dir].range(); + const cfg = axisCfg[type][dir]; + scales[dir].scaleType(cfg.scale.type); + const crossesAt = getCrossAt(cfg.crossesAt, scales[x ? 'y' : 'x']); + const ticks = scales[dir].ticks(); + return !cfg.visible ? undefined : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${dir} hs-graph-axis-${type}` }, [ + this.drawAxisLine(x, range, crossesAt), + this.drawTitle(x, cfg.title, type, range, crossesAt), + this.drawTickMarks(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor), + this.drawTickMarks(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major), + this.drawTickLabels(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor), + this.drawTickLabels(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major) + ]); + } + view(node) { + const cfg = node.attrs.cfg; + const scales = node.attrs.scales; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-axis' }, [ + this.drawAxis('x', scales.primary, 'primary', cfg), + this.drawAxis('y', scales.primary, 'primary', cfg), + this.drawAxis('x', scales.secondary, 'secondary', cfg), + this.drawAxis('y', scales.secondary, 'secondary', cfg) + ]); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Axes; + +Axes.type = { + linear: 'linear axis', + log: 'log axis', + date: 'date axis', + index: 'index axis', + percent: 'percent axis', + ordinal: 'ordinal axis', + nominal: 'nominal axis' +}; +class ExampleLinearAxis { +} +class ExampleLogAxis { +} +class ExampleDateAxis { +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXhlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9BeGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZEQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQU8sVUFBVSxDQUFDO0FBVXBDLENBQUM7QUFLRCxPQUFPLEVBQUUsT0FBTyxFQUNQLFVBQVUsRUFDVixVQUFVLEVBQ0osTUFBVSxXQUFXLENBQUM7QUFRckMsb0JBQW9CLEtBQW1CLEVBQUUsS0FBVztJQUNoRCxJQUFJLFNBQWdCLENBQUM7SUFDckIsUUFBUSxLQUFLLEVBQUU7UUFDWCxLQUFLLEtBQUs7WUFBRSxTQUFTLEdBQVcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTTtRQUN6RCxLQUFLLEtBQUs7WUFBRSxTQUFTLEdBQVcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTTtRQUN6RCxPQUFPLENBQUMsQ0FBSSxTQUFTLEdBQVcsS0FBSyxJQUFJLENBQUMsQ0FBQztLQUM5QztJQUNELE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUNwQyxDQUFDO0FBRUQsTUFBTSxXQUFZLFNBQVEsT0FBTztJQWtHN0IsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFVO1FBQzNCO1lBQ0ksT0FBTztnQkFDSCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO2dCQUN0QixNQUFNLEVBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDO2FBQ2xDLENBQUM7UUFDTixDQUFDO1FBQ0Qsa0JBQWtCLE9BQWUsRUFBRSxDQUFTLEVBQUUsS0FBYTtZQUN2RCxPQUFPO2dCQUNILE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7Z0JBQ3hCLElBQUksRUFBRSxDQUFDLENBQUEsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxD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 + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Series__ = __webpack_require__(9); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_hsutil__ = __webpack_require__(8); + + + + +class Plot extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { + drawLine(clipID, data, x, y, scales, sStyle, title) { + const style = `stroke: ${sStyle.line.color}; stroke-width:${sStyle.line.width};`; + return !sStyle.line.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-line', '') : this.polyline(data, x, y, scales, clipID, style, title); + } + drawMarker(clipID, data, x, y, scales, sStyle, title) { + const mrk = __WEBPACK_IMPORTED_MODULE_2__Series__["a" /* Series */].marker; + let style = `fill:${sStyle.marker.color}`; + return !sStyle.marker.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-marker', '') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series-markers' }, data.map((p) => { + const cx = scales.x.convert(p[x]); + const cy = scales.y.convert(p[y]); + const r = sStyle.marker.size; + switch (sStyle.marker.shape) { + case mrk.circle: + return this.circle({ x: cx, y: cy }, r, style, title); + case mrk.square: + return this.rect({ x: cx - r, y: cy - r }, { w: 2 * r, h: 2 * r }, style, title); + case mrk.diamond: + return this.shape([[cx - r, cy], [cx, cy + r], [cx + r, cy], [cx, cy - r]], undefined, style, title); + case mrk.upTriangle: + return this.shape([[cx - r, cy + r], [cx + r, cy + r], [cx, cy - r]], undefined, style, title); + case mrk.downTriangle: + return this.shape([[cx - r, cy - r], [cx + r, cy - r], [cx, cy + r]], undefined, style, title); + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`.unkown-marker-${sStyle.marker.shape}`, ''); + })); + } + drawLabel(clipID, data, x, y, lbl, scales, sDef) { + const sStyle = sDef.style; + const cfg = { + text: '', + cssClass: ``, + style: `fill:${sStyle.label.color}`, + xpos: __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle, + ypos: __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].center, + hOffset: sDef.hOffset, + vOffset: sDef.vOffset + }; + return !sStyle.marker.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-marker', '') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series-labels' }, data.map((p) => { + cfg.x = '' + scales.x.convert(p[x]); + cfg.y = '' + scales.y.convert(p[y]); + return this.text(cfg, Object(__WEBPACK_IMPORTED_MODULE_3_hsutil__["d" /* round */])(p[lbl], 3)); + })); + } + drawArea(clipID, data, x, yFore, yBack, scales, sStyle, title) { + if (sStyle.fill.visible) { + const style = `fill: ${sStyle.fill.color};`; + const drawFore = data; + const drawBack = data.slice().reverse(); + return this.polygon(drawFore, drawBack, x, yFore, yBack, scales, clipID, style, title); + } + else { + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-line', ''); + } + } + setDefaults(data, series, scales) { + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Plot; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxvdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9QbG90LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sRUFBRSxDQUFDLEVBQVEsTUFBVyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLE9BQU8sRUFFUCxVQUFVLEVBQ1YsVUFBVSxFQUFFLE1BQVEsV0FBVyxDQUFDO0FBSXpDLE9BQU8sRUFBRSxNQUFNLEVBRUssTUFBUyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFhLFFBQVEsQ0FBQztBQUV0QyxNQUFNLFdBQXFCLFNBQVEsT0FBTztJQUN0QyxRQUFRLENBQUMsTUFBYSxFQUFFLElBQWMsRUFBRSxDQUFRLEVBQUUsQ0FBUSxFQUFFLE1BQWMsRUFBRSxNQUFrQixFQUFFLEtBQWE7UUFDekcsTUFBTSxLQUFLLEdBQUcsV0FBVyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssa0JBQWtCLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUM7UUFDakYsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDbkgsQ0FBQztJQUVELFVBQVUsQ0FBQyxNQUFhLEVBQUUsSUFBYyxFQUFFLENBQVEsRUFBRSxDQUFRLEVBQUUsTUFBYyxFQUFFLE1BQWtCLEVBQUUsS0FBYTtRQUMzRyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzFCLElBQUksS0FBSyxHQUFHLFFBQVEsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMxQyxPQUFPLENBQUMsTUFBTSxDQUFD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 + +/***/ }), +/* 7 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return o; }); +if (!global['window']) { + console.log('creating non-browser polyfill'); + global['window'] = __webpack_require__(24)(); + global['document'] = window.document; +} +const m = __webpack_require__(30); +/* harmony export (immutable) */ __webpack_exports__["a"] = m; + +const o = __webpack_require__(31); +o.root = window.document.createElement("div"); + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWl0aHJpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taXRocmlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEVBQUU7SUFDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO0lBRTdDLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxPQUFPLENBQUMsbUNBQW1DLENBQUMsRUFBRSxDQUFDO0lBQ2xFLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDO0NBRXhDO0FBS0QsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQU9wQyxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUN6QyxDQUFDLENBQUMsSUFBSSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBRTlDLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyJ9 +/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(2))) + +/***/ }), +/* 8 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__TimedPromise__ = __webpack_require__(39); +/* unused harmony reexport timeout */ +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_0__TimedPromise__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__showdown__ = __webpack_require__(40); +/* unused harmony reexport markDown */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Checksum__ = __webpack_require__(42); +/* unused harmony reexport shortCheckSum */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Date__ = __webpack_require__(43); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_3__Date__["a"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return __WEBPACK_IMPORTED_MODULE_3__Date__["b"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Number__ = __webpack_require__(44); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return __WEBPACK_IMPORTED_MODULE_4__Number__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__PacingQueue__ = __webpack_require__(45); +/* unused harmony reexport PacingQueue */ + + + + + + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVksWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTyxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsTUFBWSxRQUFRLENBQUM7QUFDeEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFlLFVBQVUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQVMsZUFBZSxDQUFDIn0= + +/***/ }), +/* 9 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Axes__ = __webpack_require__(5); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__PlotLine__ = __webpack_require__(47); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__PlotMarkers__ = __webpack_require__(48); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__PlotBar__ = __webpack_require__(49); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__PlotArea__ = __webpack_require__(50); + + + + + + + +function copyDefault(target, source, defaults) { + Object.keys(source).forEach((key) => { + if (typeof source[key] === 'object') { + if (target[key] === undefined) { + target[key] = {}; + } + copyDefault(target[key], source[key], defaults); + } + else { + if (target[key] === undefined) { + target[key] = source[key]; + } + if (target[key] === 'default') { + target[key] = defaults[key]; + } + } + }); +} +class Series extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { + static defaultConfig(cfg) { + cfg.series = new SeriesConfig(); + } + static adjustConfig(cfg) { + cfg.series.series.forEach((s) => { + if (s.x === undefined) { + cfg.axes.primary.x.title.hOffset = 0; + cfg.axes.primary.x.scale.type = __WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */].type.index; + cfg.grid.minor.ver.visible = false; + } + }); + } + drawClipRect(clipID, scales) { + return !clipID ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('') : this.clipRect({ x: scales.x.range()[0], y: scales.y.range()[1] }, { + w: scales.x.range()[1] - scales.x.range()[0], + h: scales.y.range()[0] - scales.y.range()[1] + }, clipID); + } + view(node) { + const cfg = node.attrs.cfg; + const scales = node.attrs.scales.primary; + const data = node.attrs.data; + const clipID = cfg.clip ? 'hs' + Math.floor(Math.random() * 10000) : undefined; + cfg.series.map((s) => { + if (s.map === Series.map.shared) { + s.ySum = '$sum'; + data[s.dataIndex].colAdd(s.ySum); + data[s.dataIndex].colInitialize(s.ySum, 0); + } + }); + cfg.series.map((s) => { + const dt = data[s.dataIndex]; + if (s.map === Series.map.shared) { + const valCol = dt.colNumber(s.y); + dt.colInitialize(s.ySum, (v, i, row) => { return v + row[valCol]; }); + } + if (s.map) { + s.yBase = '$' + s.map; + dt.colAdd(s.yBase); + dt.colInitialize(s.yBase, 0); + } + }); + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series' }, [ + this.drawClipRect(clipID, scales), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', cfg.series.map((s, i) => { + const dt = data[s.dataIndex]; + const type = Series.plot[s.type] || Series.plot.line; + type.setDefaults(dt, s, scales); + const d = s.cond ? dt.filter(s.cond) : dt; + const plot = type.plot(d, s, scales, i, clipID); + if (s.map) { + const valCol = d.colNumber(s.y); + d.colInitialize(s.yBase, (v, i, row) => { return v + row[valCol]; }); + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-series-${i}` }, plot); + })) + ]); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Series; + +Series.marker = { + circle: Symbol('circle marker'), + square: Symbol('square marker'), + diamond: Symbol('diamond marker'), + upTriangle: Symbol('upward triangle marker'), + downTriangle: Symbol('downward triangle marker') +}; +Series.plot = { + line: new __WEBPACK_IMPORTED_MODULE_3__PlotLine__["a" /* PlotLine */](), + marker: new __WEBPACK_IMPORTED_MODULE_4__PlotMarkers__["a" /* PlotMarkers */](), + bar: new __WEBPACK_IMPORTED_MODULE_5__PlotBar__["a" /* PlotBar */](), + area: new __WEBPACK_IMPORTED_MODULE_6__PlotArea__["a" /* PlotArea */]() +}; +Series.map = { + stacked: 'stacked', + shared: 'shared' +}; +class SeriesConfig { + constructor() { + this.seriesDefs = []; + this.clip = true; + this.defaultStyle = { + line: { color: 'default', visible: true, width: 2 }, + marker: { color: 'default', visible: false, size: 10, shape: Series.marker.circle }, + label: { color: 'default', visible: false }, + fill: { color: 'default', visible: false }, + bar: { color: 'default', visible: false, width: 50, offset: 30 } + }; + this.defaultColors = ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f', '#000', '#444', '#888', '#ccc']; + } + set series(cfg) { + const defStyle = this.defaultStyle; + const defColors = this.defaultColors; + cfg.forEach((s) => { + s.type = s.type || 'line'; + s.style = s.style || {}; + s.dataIndex = s.dataIndex || 0; + const defaults = { + color: defColors[this.seriesDefs.length] + }; + copyDefault(s.style, defStyle, defaults); + this.seriesDefs.push(s); + switch (s.type) { + case 'line': + s.style.line.visible = true; + break; + case 'marker': + s.style.marker.visible = true; + break; + case 'area': + s.style.fill.visible = true; + break; + case 'bar': + s.style.fill.visible = true; + break; + } + }); + } + get series() { return this.seriesDefs; } +} +/* unused harmony export SeriesConfig */ + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VyaWVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1Nlcmllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFvQkEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFXLFVBQVUsQ0FBQztBQU14QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQVcsV0FBVyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBYyxRQUFRLENBQUM7QUFFdEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFVLFlBQVksQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU8sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBVyxXQUFXLENBQUM7QUFDekMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFVLFlBQVksQ0FBQztBQUcxQyxxQkFBcUIsTUFBVSxFQUFFLE1BQVUsRUFBRSxRQUFZO0lBQ3JELE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBVSxFQUFFLEVBQUU7UUFDdkMsSUFBSSxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxRQUFRLEVBQUU7WUFDakMsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7YUFBRTtZQUNwRCxXQUFXLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztTQUNuRDthQUFNO1lBQ0gsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7YUFBRTtZQUM3RCxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxTQUFTLEVBQUU7Z0JBQUUsTUFBTSxDQUFD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 + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = function parseURL(url, root) { + var data = {} + var protocolIndex = url.indexOf("://") + var pathnameIndex = protocolIndex > -1 ? url.indexOf("/", protocolIndex + 3) : url.indexOf("/") + var searchIndex = url.indexOf("?") + var hashIndex = url.indexOf("#") + if ((pathnameIndex > searchIndex && searchIndex > -1) || (pathnameIndex > hashIndex && hashIndex > -1)) pathnameIndex = -1 + if (searchIndex > hashIndex && hashIndex > -1) searchIndex = -1 + var pathnameEnd = searchIndex > -1 ? searchIndex : hashIndex > -1 ? hashIndex : url.length + if (protocolIndex > -1) { + //it's a full URL + if (pathnameIndex < 0) pathnameIndex = url.length + var portIndex = url.indexOf(":", protocolIndex + 1) + if (portIndex < 0) portIndex = pathnameIndex + data.protocol = url.slice(0, protocolIndex + 1) + data.hostname = url.slice(protocolIndex + 3, portIndex) + data.port = url.slice(portIndex + 1, pathnameIndex) + data.pathname = url.slice(pathnameIndex, pathnameEnd) || "/" + } + else { + data.protocol = root.protocol + data.hostname = root.hostname + data.port = root.port + if (pathnameIndex === 0) { + //it's an absolute path + data.pathname = url.slice(pathnameIndex, pathnameEnd) || "/" + } + else if (searchIndex !== 0 && hashIndex !== 0) { + //it's a relative path + var slashIndex = root.pathname.lastIndexOf("/") + var path = slashIndex > -1 ? root.pathname.slice(0, slashIndex + 1) : "./" + var normalized = url.slice(0, pathnameEnd).replace(/^\.$/, root.pathname.slice(slashIndex + 1)).replace(/^\.\//, "") + var dotdot = /\/[^\/]+?\/\.{2}/g + var pathname = path + normalized + pathname = path + normalized + while (dotdot.test(pathname)) pathname = pathname.replace(dotdot, "") + pathname = pathname.replace(/\/\.\//g, "/").replace(/^(\/\.{2})+/, "") || "/" + data.pathname = pathname + } + } + var searchEnd = hashIndex > -1 ? hashIndex : url.length + data.search = searchIndex > -1 ? url.slice(searchIndex, searchEnd) : "" + data.hash = hashIndex > -1 ? url.slice(hashIndex) : "" + return data +} + + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(setImmediate) { + +module.exports = typeof setImmediate === "function" ? setImmediate : setTimeout + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12).setImmediate)) + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(global) {var apply = Function.prototype.apply; + +// DOM APIs, for completeness + +exports.setTimeout = function() { + return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); +}; +exports.setInterval = function() { + return new Timeout(apply.call(setInterval, window, arguments), clearInterval); +}; +exports.clearTimeout = +exports.clearInterval = function(timeout) { + if (timeout) { + timeout.close(); + } +}; + +function Timeout(id, clearFn) { + this._id = id; + this._clearFn = clearFn; +} +Timeout.prototype.unref = Timeout.prototype.ref = function() {}; +Timeout.prototype.close = function() { + this._clearFn.call(window, this._id); +}; + +// Does not start the time, just sets up the members needed. +exports.enroll = function(item, msecs) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = msecs; +}; + +exports.unenroll = function(item) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = -1; +}; + +exports._unrefActive = exports.active = function(item) { + clearTimeout(item._idleTimeoutId); + + var msecs = item._idleTimeout; + if (msecs >= 0) { + item._idleTimeoutId = setTimeout(function onTimeout() { + if (item._onTimeout) + item._onTimeout(); + }, msecs); + } +}; + +// setimmediate attaches itself to the global object +__webpack_require__(26); +// On some exotic environments, it's not clear which object `setimmeidate` was +// able to install onto. Search each possibility in the same order as the +// `setimmediate` library. +exports.setImmediate = (typeof self !== "undefined" && self.setImmediate) || + (typeof global !== "undefined" && global.setImmediate) || + (this && this.setImmediate); +exports.clearImmediate = (typeof self !== "undefined" && self.clearImmediate) || + (typeof global !== "undefined" && global.clearImmediate) || + (this && this.clearImmediate); + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) + +/***/ }), +/* 13 */ +/***/ (function(module, exports) { + +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + + +/***/ }), +/* 14 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__DataFilters__ = __webpack_require__(38); + +; +class Data { + constructor(data) { + this.data = []; + this.meta = []; + this.import(data); + } + static toDataSet(data, name) { + data = data || [{}]; + const names = Object.keys(data[0]); + const rows = data.map((r) => names.map((n) => r[n])); + return { rows: rows, colNames: names, name: name || undefined }; + } + getName() { + return this.name; + } + import(data) { + this.name = data.name; + this.setData(data.rows, data.colNames); + } + export() { + return { + rows: this.getData(), + colNames: this.colNames() + }; + } + getData() { + return this.data; + } + getColumn(col) { + const cn = this.colNumber(col); + return this.data.map((row) => row[cn]); + } + colAdd(col) { + let m = this.getMeta(col); + if (m === undefined) { + m = this.meta[col] = {}; + m.name = col; + m.column = this.meta.length; + this.meta.push(m); + m.cast = false; + m.accessed = false; + } + return m.column; + } + colInitialize(col, initializer) { + const cn = this.colNumber(col); + if (!cn && typeof col === 'string') { + this.colAdd(col); + } + const fn = typeof initializer === 'function'; + if (cn !== undefined) { + this.data.map((r, i) => r[cn] = fn ? initializer(r[cn], i, r) : initializer); + } + } + colNumber(col) { + const m = this.getMeta(col); + if (!m) { + return undefined; + } + else { + m.accessed = true; + return m.column; + } + } + colName(col) { + var m = this.getMeta(col); + if (!m) { + return undefined; + } + m.accessed = true; + return m.name; + } + colNames() { + return this.meta.map((m) => m.name); + } + colType(col) { + const meta = this.getMeta(col); + return meta ? meta.types[0].type : Data.type.name; + } + findDomain(col, domain) { + if (col === undefined) { + domain[0] = 0; + domain[1] = this.data.length - 1; + } + else { + const c = this.colNumber(col); + const type = this.colType(col); + if (this.data === undefined) { + console.log('no data'); + } + switch (type) { + case Data.type.nominal: + this.data.forEach((r) => { + const nomDom = domain; + if (nomDom.indexOf('' + r[c]) < 0) { + nomDom.push('' + r[c]); + } + }); + break; + default: + this.data.forEach((r) => { + let v = r[c]; + if (v !== undefined && v !== null) { + domain[0] = (v < domain[0]) ? v : domain[0]; + domain[1] = (v > domain[1]) ? v : domain[1]; + } + }); + } + } + } + castData() { + this.meta.forEach((c) => { + const col = c.column; + if (!c.cast) { + this.data.forEach((row) => row[col] = this.castVal(c.types[0].type, row[col])); + } + c.cast = true; + }); + } + filter(condition) { + return Object(__WEBPACK_IMPORTED_MODULE_0__DataFilters__["a" /* filter */])(this, condition); + } + sort(sortFn, col) { + let fn = sortFn; + if (!col) { + this.data.sort(fn); + } + else { + col = this.colNumber(col); + if (sortFn === 'descending') { + fn = (a, b) => (b > a) ? 1 : ((b < a) ? -1 : 0); + } + if (sortFn === 'ascending') { + fn = (a, b) => (b < a) ? 1 : ((b > a) ? -1 : 0); + } + this.data.sort((r1, r2) => fn(r1[col], r2[col])); + } + return this; + } + map(col, mapFn) { + const noop = (val) => val; + const cumulate = () => { + let sum = 0; + return (val, i) => { sum += +val; return sum; }; + }; + function getFn() { + let fn; + switch (mapFn) { + case 'cumulate': + fn = cumulate(); + break; + case 'noop': + fn = noop; + break; + default: fn = mapFn; + } + return fn; + } + let result = new Data({ colNames: this.colNames(), rows: this.data.slice(), name: this.getName() }); + const names = col['length'] ? col : [col]; + names.map((cn) => { + const c = this.colNumber(cn); + let fn = getFn(); + result.data = result.data.map((row, i, rows) => { + row[c] = fn(row[c], c, i, rows); + return row; + }); + }); + return result; + } + getMeta(col) { + if (!this.meta) { + this.meta = []; + } + if (!this.meta[col]) { + return undefined; + } + this.meta[col].accessed = true; + return this.meta[col]; + } + setData(data, names, autoType = true) { + this.meta = []; + this.data = data; + if (!names) { + console.log(); + } + names.forEach((col) => this.colAdd(col)); + names.forEach((col) => this.findTypes(col)); + this.castData(); + } + findTypes(col) { + const m = this.getMeta(col); + const types = []; + Object.keys(Data.type).forEach((t) => { + const ts = { type: Data.type[t], count: 0 }; + types.push(ts); + types[Data.type[t]] = ts; + }); + for (let v of this.allRows(col)) { + const t = this.findType(v); + if (t !== null) { + types[t].count++; + } + } + types.sort(function (a, b) { + if (a.type === 'currency' && a.count > 0) { + return -1; + } + if (b.type === 'currency' && b.count > 0) { + return 1; + } + return b.count - a.count; + }); + m.types = types; + return types[0].type; + } + findType(val) { + if (val && val !== '') { + if (val instanceof Date) { + return Data.type.date; + } + if (typeof val === 'number') { + return Data.type.number; + } + const strVal = '' + val; + if ('' + parseFloat(strVal) === strVal) { + return Data.type.number; + } + if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { + return Data.type.currency; + } + if (strVal.endsWith('%') && !isNaN(parseFloat(strVal))) { + return Data.type.percent; + } + if (!isNaN(this.toDate(strVal).getTime())) { + return Data.type.date; + } + if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { + if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { + return Data.type.currency; + } + } + switch (strVal.toLowerCase()) { + case "null": break; + case "#ref!": break; + default: if (val.length > 0) { + return Data.type.nominal; + } + } + } + return null; + } + *allRows(column) { + const c = this.colNumber(column); + for (let r = 0; r < this.data.length; r++) { + yield this.data[r][c]; + } + } + toDate(val, limitYear = 1970) { + let d; + if (val instanceof Date) { + d = val; + } + else { + d = new Date(val); + } + let yr = d.getFullYear(); + if (yr < 100) { + yr += 1900; + d.setFullYear((yr < limitYear) ? yr + 100 : yr); + } + return d; + } + castVal(type, val) { + switch (type) { + case Data.type.date: + if (val instanceof Date) { + return val; + } + val = this.toDate(val); + if (isNaN(val.getTime())) { + val = null; + } + break; + case Data.type.percent: + if (typeof val === 'string') { + const num = parseFloat(val); + val = val.endsWith('%') ? num / 100 : num; + } + if (isNaN(val)) { + val = null; + } + break; + case Data.type.currency: + if (typeof val === 'string') { + val = val.replace(/[^eE\+\-\.\d]/g, ''); + } + case Data.type.number: + if (typeof val === 'string') { + val = parseFloat(val); + } + if (isNaN(val)) { + val = null; + } + break; + default: val = '' + val; + } + return val; + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Data; + +Data.type = { + number: 'number data', + name: 'name data', + date: 'date data', + currency: 'currency data', + percent: 'percent data', + nominal: 'nominal data' +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGF0YS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9EYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLE9BQU8sRUFBYSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUF1Q0UsQ0FBQztBQWtCckQsTUFBTTtJQXFCRixZQUFZLElBQWE7UUEwU2pCLFNBQUksR0FBaUIsRUFBRSxDQUFDO1FBQ3hCLFNBQUksR0FBaUIsRUFBRSxDQUFDO1FBMVM1QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3RCLENBQUM7SUFWTSxNQUFNLENBQUMsU0FBUyxDQUFDLElBQW1CLEVBQUUsSUFBWTtRQUNyRCxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDcEIsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBSyxFQUFFLEVBQUUsQ0FDNUIsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQyxPQUFPLEVBQUUsSUFBSSxFQUFDLElBQUksRUFBRSxRQUFRLEVBQUMsS0FBSyxFQUFFLElBQUksRUFBQyxJQUFJLElBQUUsU0FBUyxFQUFFLENBQUM7SUFDL0QsQ0FBQztJQVNNLE9BQU87UUFDVixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDckIsQ0FBQztJQU1NLE1BQU0sQ0FBQyxJQUFZO1FBQ3RCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFLTSxN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 + +/***/ }), +/* 15 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Axes__ = __webpack_require__(5); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_hsutil__ = __webpack_require__(8); + + +function addTickNumber(t, v) { + t.labels.push({ pos: v, text: '' + Math.round(v * 1000000) / 1000000 }); +} +function addTickDate(t, v, fmt) { + t.labels.push({ pos: v.getTime(), text: Object(__WEBPACK_IMPORTED_MODULE_1_hsutil__["a" /* date */])(fmt, v) }); +} +function linScaleTickMarks(dom, ticks, numTicks) { + function addTicks(unit, ticks) { + let exp = Math.pow(10, Math.floor(Math.log10(unit))); + unit = Math.floor(unit / exp) * exp; + const min = Math.floor(dom[0] / unit) * unit; + const max = Math.ceil(dom[1] / unit) * unit; + for (let v = min; v <= max; v += unit) { + addTickNumber(ticks, v); + } + return unit; + } + const majorUnit = addTicks((dom[1] - dom[0]) / numTicks, ticks.major); + addTicks(majorUnit / numTicks, ticks.minor); +} +function percentScaleTickMarks(dom, ticks, numTicks) { + const formatPercent = (m) => m.text = `${Math.round(m.pos) * 100}%`; + linScaleTickMarks(dom, ticks, numTicks); + ticks.major.labels.forEach(formatPercent); + ticks.minor.labels.forEach(formatPercent); +} +function logScaleTickMarks(dom, ticks) { + dom[0] = Math.max(dom[0], 1e-20); + dom[1] = Math.max(dom[1], 1e-20); + let dif = Math.pow(10, Math.floor(Math.log10(dom[1] - dom[0]))); + let min = Math.pow(10, Math.floor(Math.log10(dom[0]))); + let max = Math.pow(10, Math.ceil(Math.log10(dom[1]))); + if (dif > min) { + for (let v = min; v <= max; v *= 10) { + for (let i = 1; i <= 20; i++) { + if (i === 1 && v * i < max) { + addTickNumber(ticks.major, v * i); + } + else if (i % 10 === 0) { } + else if (i < 10) { + addTickNumber(ticks.minor, v * i); + } + else if (i % 2 === 0) { + addTickNumber(ticks.minor, v * i); + } + } + } + } + else { + min = Math.floor(dom[0] / dif) * dif; + max = Math.ceil(dom[1] / dif) * dif; + if ((max - min) / dif < 4) { + dif /= 2; + } + for (let v = min; v <= max; v += dif) { + addTickNumber(ticks.major, v); + } + addTickNumber(ticks.major, min); + addTickNumber(ticks.major, max); + } +} +const tickCategories = [ + [10, 0, 0, 0], [5, 0, 0, 0], [2, 0, 0, 0], [1, 0, 0, 0], [0, 6, 0, 0], [0, 3, 0, 0], [0, 1, 0, 0], [0, 0, 7, 0], [0, 0, 1, 0], [0, 0, 0, 4], [0, 0, 0, 1] +]; +function dateScaleTickMarks(dom, ticks, fmt = '%MM/%DD/%YY') { + function addDates(i, tickDefs) { + const createDate = (idx) => new Date(Math.floor(dateDom[idx].getFullYear() / modYr) * modYr + (idx ? incYr : 0), (incYr > 0) ? 0 : Math.floor(dateDom[idx].getMonth() / modMo) * modMo + (idx ? incMo : 0), (incMo > 0) ? 1 : (dateDom[idx].getDate() - ((incDay === 7) ? dateDom[idx].getDay() : 0)) + (idx ? incDay : 0), (incDay > 0) ? 0 : (dateDom[idx].getHours()) + (idx ? incHour : 0)); + const incYr = tickCategories[i][0]; + const incMo = tickCategories[i][1]; + const incDay = tickCategories[i][2]; + const incHour = tickCategories[i][3]; + const modYr = incYr || 1; + const modMo = incMo || 1; + const date0 = createDate(0); + const date1 = createDate(1); + fmt = incHour ? '%hh:%mm' : '%MM/%DD/%YY'; + for (let d = date0; d <= date1; d = new Date(d.getFullYear() + incYr, d.getMonth() + incMo, d.getDate() + incDay, d.getHours() + incHour)) { + addTickDate(tickDefs, d, fmt); + } + } + const dateDom = [ + (typeof dom[0] === 'number') ? new Date(dom[0]) : dom[0], + (typeof dom[1] === 'number') ? new Date(dom[1]) : dom[1] + ]; + if (isNaN(dateDom[0].getTime())) { + dateDom[0] = new Date('1/1/1980'); + } + if (isNaN(dateDom[1].getTime())) { + dateDom[0] = new Date(); + } + const d = dateDom[1].getTime() - dateDom[0].getTime(); + tickCategories.some((cat, i) => { + const dMin = __WEBPACK_IMPORTED_MODULE_1_hsutil__["c" /* ms */].fromDays((cat[0] * 365 + cat[1] * 30 + cat[2])) + __WEBPACK_IMPORTED_MODULE_1_hsutil__["c" /* ms */].fromHours(cat[3]); + if (d > 3 * dMin) { + addDates(i, ticks.major); + addDates(Math.min(i + 1, tickCategories.length - 1), ticks.minor); + return true; + } + else { + return false; + } + }); +} +function createTickLabels(type, domain, numTicks, fmt) { + const sort = (a, b) => a.pos - b.pos; + function sortTicks() { + ticks.minor.labels.sort(sort); + ticks.major.labels.sort(sort); + } + ; + const dom = [domain[0], domain[1]]; + const ticks = { + major: { marks: [], labels: [] }, + minor: { marks: [], labels: [] } + }; + switch (type) { + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: + logScaleTickMarks(dom, ticks); + sortTicks(); + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: + dateScaleTickMarks(dom, ticks, fmt); + sortTicks(); + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: + percentScaleTickMarks(dom, ticks, numTicks); + sortTicks(); + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: + default: + linScaleTickMarks(dom, ticks, numTicks); + sortTicks(); + } + return ticks; +} +class Scale { + constructor(cfg) { + this.cfg = cfg; + this.typeVal = __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear; + this.rangeVal = [0, 1]; + this.domVal = [0, 1]; + this.domMinAuto = 0; + this.domMaxAuto = 0; + this.scaleType(cfg.type); + this.domain(cfg.domain); + } + setLabelFormat(labelFmt) { + this.labelFmt = labelFmt; + } + range(r) { + if (r) { + this.rangeVal = r; + } + return this.rangeVal; + } + domain(dom) { + if (dom) { + if (this.scaleType() === __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date) { + if (typeof dom[0] === 'string' || typeof dom[1] === 'string') { + this.domVal[0] = (dom[0] === 'auto') ? 0 : Date.parse(dom[0]); + this.domVal[1] = (dom[1] === 'auto') ? 1 : Date.parse(dom[1]); + } + } + else { + this.domVal[0] = (dom[0] === 'auto') ? 0 : dom[0]; + this.domVal[1] = (dom[1] === 'auto') ? 1 : dom[1]; + } + switch (dom[0]) { + case 'tight': + this.domMinAuto = 2; + break; + case 'auto': + this.domMinAuto = 1; + break; + default: this.domMinAuto = 0; + } + switch (dom[1]) { + case 'tight': + this.domMaxAuto = 2; + break; + case 'auto': + this.domMaxAuto = 1; + break; + default: this.domMaxAuto = 0; + } + } + if (this.typeVal === __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log) { + if (this.domVal[1] <= 0) { + this.domVal[1] = 10; + } + if (this.domVal[0] <= 0) { + this.domVal[0] = this.domVal[1] / 10; + } + } + return this.domVal; + } + scaleType(s) { + if (s) { + this.typeVal = s; + } + return this.typeVal; + } + setAutoDomain(dom) { + const ticks = createTickLabels(this.scaleType(), dom, 4, this.labelFmt); + switch (this.domMinAuto) { + case 1: + this.domVal[0] = ticks.major.labels[0] ? ticks.major.labels[0].pos : dom[0]; + break; + case 2: + this.domVal[0] = dom[0]; + break; + } + switch (this.domMaxAuto) { + case 1: + this.domVal[1] = ticks.major.labels[ticks.major.labels.length - 1].pos; + break; + case 2: + this.domVal[1] = dom[1]; + break; + } + } + ticks(numTicks = 4) { + function marksFromLabels(ticks, type) { + switch (type) { + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: + const numLabels = ticks.major.labels.length; + ticks.major.marks = Array(numLabels + 1).fill(1).map((e, i) => i - 0.5); + ticks.minor.marks = ticks.minor.labels ? ticks.minor.labels.map((l) => l.pos) : []; + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: + default: + ticks.major.marks = ticks.major.labels ? ticks.major.labels.map((l) => l.pos) : []; + ticks.minor.marks = ticks.minor.labels ? ticks.minor.labels.map((l) => l.pos) : []; + } + } + const dom = [this.domain()[0], this.domain()[1]]; + const inRange = (t) => t.pos >= dom[0] && t.pos <= dom[1]; + const ticks = createTickLabels(this.scaleType(), this.domain(), numTicks, this.labelFmt); + ticks.minor.labels = ticks.minor.labels.filter(inRange); + ticks.major.labels = ticks.major.labels.filter(inRange); + if (ticks.major.labels.length === 0) { + ticks.major.labels = ticks.minor.labels; + ticks.minor.labels = []; + } + marksFromLabels(ticks, this.scaleType()); + return ticks; + } + convert(domVal) { + const dom = this.domain(); + const range = this.range(); + const domMin = dom[0]; + const domMax = dom[1]; + let result; + switch (this.scaleType()) { + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: + result = Math.log(domVal / domMin) / Math.log(domMax / domMin) * (range[1] - range[0]) + range[0]; + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: + default: + result = (domVal - domMin) / (domMax - domMin) * (range[1] - range[0]) + range[0]; + } + return result; + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Scale; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2NhbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU2NhbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFjLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxNQUFVLFFBQVEsQ0FBQztBQU90Qyx1QkFBdUIsQ0FBVSxFQUFFLENBQVE7SUFDdkMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUMsT0FBTyxDQUFDLEdBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztBQUN0RSxDQUFDO0FBRUQscUJBQXFCLENBQVUsRUFBRSxDQUFNLEVBQUUsR0FBVTtJQUMvQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQzNELENBQUM7QUFJRCwyQkFBMkIsR0FBWSxFQUFFLEtBQVcsRUFBRSxRQUFlO0lBQ2pFLGtCQUFrQixJQUFXLEVBQUUsS0FBYztRQUN6QyxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JELElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxHQUFHLENBQUMsR0FBQyxHQUFHLENBQUM7UUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUMsSUFBSSxDQUFDO1FBQ3pDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQztRQUN4QyxLQUFLLElBQUksQ0FBQyxHQUFDLEdBQUcsRUFBRSxDQUFDLElBQUUsR0FBRyxFQUFFLENBQUMsSUFBRSxJQUFJLEVBQUU7WUFBRSxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQUU7UUFDN0QsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUNELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RFLFFBQVEsQ0FBQyxTQUFTLEdBQUcsUUFBUSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNoRCxDQUFDO0FBRUQsK0JBQStCLEdBQVksRUFBRSxLQUFXLEVBQUUsUUFBZTtJQUNyRSxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFDLEdBQUcsR0FBRyxDQUFDO0lBQzVFLGlCQUFpQixDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDeEMsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQzFDLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUU5QyxDQUFDO0FBRUQsMkJBQTJCLEdBQVksRUFBRSxLQUFXO0lBQ2hELEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNqQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDakMsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEUsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2RCxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RELElBQUksR0FBRyxHQUFHLEdBQUcsRUFBRTtRQUNYLEtBQUssSUFBSSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFFLEVBQUUsRUFBRTtZQUM3QixLQUFLLElBQUksQ0FBQyxHQUFDLENBQUMsRUFBRSxDQUFDLElBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN0QixJQUFJLENBQUMsS0FBRyxDQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsR0FBQyxHQUFHLEVBQUU7b0JBQUUsYUFBYSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUFFO3FCQUNyRCxJQUFJLENBQUMsR0FBQyxFQUFFLEtBQUcsQ0FBQyxFQUFFLEdBQUU7cUJBQ2hCLElBQUksQ0FBQyxHQUFDLEVBQUUs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 + +/***/ }), +/* 16 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); + + +class Grid extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { + static defaultConfig(cfg) { + cfg.grid = { + major: { + hor: { visible: true }, + ver: { visible: true } + }, + minor: { + hor: { visible: false }, + ver: { visible: false } + } + }; + } + static adjustConfig(cfg) { + } + drawHorGrid(cfg, scale, range, ticks) { + return !cfg.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-hor' }, ticks.marks.map((t) => this.horLine(range[0], range[1], scale.convert(t)))); + } + drawVerGrid(cfg, scale, range, ticks) { + return !cfg.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-ver' }, ticks.marks.map((t) => this.verLine(scale.convert(t), range[0], range[1]))); + } + view(node) { + const cfg = node.attrs.cfg; + const scales = node.attrs.scales; + const ps = scales.primary; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid' }, [ + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-minor' }, [ + this.drawHorGrid(cfg.minor.hor, ps.y, ps.x.range(), ps.y.ticks().minor), + this.drawVerGrid(cfg.minor.ver, ps.x, ps.y.range(), ps.x.ticks().minor) + ]), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-major' }, [ + this.drawHorGrid(cfg.major.hor, ps.y, ps.x.range(), ps.y.ticks().major), + this.drawVerGrid(cfg.major.ver, ps.x, ps.y.range(), ps.x.ticks().major) + ]) + ]); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Grid; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR3JpZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9HcmlkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlCQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQVcsVUFBVSxDQUFDO0FBR3hDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBVyxXQUFXLENBQUM7QUF5QnpDLE1BQU0sV0FBWSxTQUFRLE9BQU87SUFxQjdCLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVTtRQUMzQixHQUFHLENBQUMsSUFBSSxHQUFnQjtZQUNwQixLQUFLLEVBQUU7Z0JBQ0gsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFDLElBQUksRUFBRTtnQkFDckIsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFDLElBQUksRUFBRTthQUN4QjtZQUNELEtBQUssRUFBRTtnQkFDSCxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUMsS0FBSyxFQUFFO2dCQUN0QixHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUMsS0FBSyxFQUFFO2FBQ3pCO1NBQ0osQ0FBQztJQUNOLENBQUM7SUFNRCxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQVU7SUFDOUIsQ0FBQztJQUtPLFdBQVcsQ0FBQyxHQUFxQixFQUFFLEtBQVcsRUFBRSxLQUFjLEVBQUUsS0FBYztRQUNsRixPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLG1CQUFtQixFQUFFLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUMxRixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUNyRCxDQUFDLENBQUM7SUFDUCxDQUFDO0lBS08sV0FBVyxDQUFDLEdBQXFCLEVBQUUsS0FBVyxFQUFFLEtBQWMsRUFBRSxLQUFjO1FBQ2xGLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMsbUJBQW1CLEVBQUUsRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQzFGLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQ3JELENBQUMsQ0FBQztJQUNQLENBQUM7SUFHRCxJQUFJLENBQUMsSUFBWTtRQUNiLE1BQU0sR0FBRyxHQUFlLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO1FBQ3ZDLE1BQU0sTUFBTSxHQUFVLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQ3hDLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFDMUIsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLGVBQWUsRUFBQyxFQUFFO1lBQ3RDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMscUJBQXFCLEVBQUUsRUFBRTtnQkFDdEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLENBQUM7Z0JBQ3ZFLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDO2FBQzFFLENBQUM7WUFDRixDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLHFCQUFxQixFQUFFLEVBQUU7Z0JBQ3RDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDO2dCQUN2RSxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLEtBQUssQ0FBQzthQUMxRSxDQUFDO1NBQ0wsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztDQUNKIn0= + +/***/ }), +/* 17 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); + +; +class Legend { + static defaultConfig(cfg) { + cfg.legend = {}; + } + static adjustConfig(cfg) { + } + view(node) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-legend', width: '100%', height: '100%' }); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Legend; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGVnZW5kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL0xlZ2VuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFnQkEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFPLFVBQVUsQ0FBQztBQU9uQyxDQUFDO0FBRUYsTUFBTTtJQWFGLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVTtRQUMzQixHQUFHLENBQUMsTUFBTSxHQUFpQixFQUMxQixDQUFDO0lBQ04sQ0FBQztJQU1ELE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBVTtJQUU5QixDQUFDO0lBRUQsSUFBSSxDQUFDLElBQVk7UUFDYixPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMsaUJBQWlCLEVBQUUsS0FBSyxFQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQztJQUM3RSxDQUFDO0NBQ0oifQ== + +/***/ }), +/* 18 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0____ = __webpack_require__(19); + +if (__WEBPACK_IMPORTED_MODULE_0____["a" /* Graph */]) { } +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXhhbXBsZS9zdGFydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQzVCLElBQUksS0FBSyxFQUFFLEdBQUUifQ== + +/***/ }), +/* 19 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Graph__ = __webpack_require__(20); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_0__Graph__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Series__ = __webpack_require__(9); +/* unused harmony reexport Series */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Axes__ = __webpack_require__(5); +/* unused harmony reexport Axes */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Scale__ = __webpack_require__(15); +/* unused harmony reexport Scale */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Grid__ = __webpack_require__(16); +/* unused harmony reexport Grid */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Legend__ = __webpack_require__(17); +/* unused harmony reexport Legend */ + + + + + + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFTLFNBQVMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsTUFBTSxFQUVMLE1BQWUsVUFBVSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBVSxRQUFRLENBQUM7QUFDbEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFTLFNBQVMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQVUsUUFBUSxDQUFDO0FBQ2xDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBUSxVQUFVLENBQUMifQ== + +/***/ }), +/* 20 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_hsdata__ = __webpack_require__(37); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Axes__ = __webpack_require__(5); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Scale__ = __webpack_require__(15); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Canvas__ = __webpack_require__(46); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Series__ = __webpack_require__(9); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Chart__ = __webpack_require__(51); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Grid__ = __webpack_require__(16); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__Legend__ = __webpack_require__(17); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__SVGElem__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10_hsutil__ = __webpack_require__(8); + + + + + + + + + + + +const viewBoxWidth = 1000; +let viewBoxHeight = 700; +function copy(def) { + let result = {}; + Object.keys(def).map((k) => { + if (typeof def[k] === 'object' && !Array.isArray(def[k]) && def[k] !== null) { + result[k] = copy(def[k]); + } + else { + result[k] = def[k]; + } + }); + return result; +} +class Graph extends __WEBPACK_IMPORTED_MODULE_9__SVGElem__["a" /* SVGElem */] { + constructor() { + super(...arguments); + this.marginOffset = { + left: 0, + right: 0, + top: 0, + bottom: 0 + }; + } + static makeConfig(userCfg) { + const cfg = {}; + Graph.defaultConfig(cfg); + __WEBPACK_IMPORTED_MODULE_4__Canvas__["a" /* Canvas */].defaultConfig(cfg); + __WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */].defaultConfig(cfg); + __WEBPACK_IMPORTED_MODULE_5__Series__["a" /* Series */].defaultConfig(cfg); + __WEBPACK_IMPORTED_MODULE_7__Grid__["a" /* Grid */].defaultConfig(cfg); + __WEBPACK_IMPORTED_MODULE_6__Chart__["a" /* Chart */].defaultConfig(cfg); + __WEBPACK_IMPORTED_MODULE_8__Legend__["a" /* Legend */].defaultConfig(cfg); + if (userCfg) { + try { + userCfg(cfg); + } + catch (e) { + console.log('error in usercfg'); + console.log(e); + console.log(e.stack); + } + } + return cfg; + } + static defaultConfig(cfg) { + cfg.graph = { + margin: { + top: 10, + left: 10, + bottom: 10, + right: 10 + }, + timeCond: {} + }; + } + static adjustConfig(cfg) { + __WEBPACK_IMPORTED_MODULE_4__Canvas__["a" /* Canvas */].adjustConfig(cfg); + __WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */].adjustConfig(cfg); + __WEBPACK_IMPORTED_MODULE_5__Series__["a" /* Series */].adjustConfig(cfg); + __WEBPACK_IMPORTED_MODULE_7__Grid__["a" /* Grid */].adjustConfig(cfg); + __WEBPACK_IMPORTED_MODULE_6__Chart__["a" /* Chart */].adjustConfig(cfg); + __WEBPACK_IMPORTED_MODULE_8__Legend__["a" /* Legend */].adjustConfig(cfg); + } + createPlotArea(cfgm) { + const tl = { + x: cfgm.left + this.marginOffset.left, + y: cfgm.top + this.marginOffset.top + }; + const br = { + x: viewBoxWidth - cfgm.right - this.marginOffset.right, + y: viewBoxHeight - cfgm.bottom - this.marginOffset.bottom + }; + return { tl: tl, br: br }; + } + createData(cfg) { + if (!cfg.series.data) { + console.log('cfg.series.data not set'); + } + if (!(cfg.series.data.length > 0)) { + console.log('cfg.series.data not initialised with array of DataSets'); + } + const timeCond = cfg.graph.timeCond; + return cfg.series.data.map((d) => ((d instanceof __WEBPACK_IMPORTED_MODULE_1_hsdata__["a" /* Data */]) ? d : new __WEBPACK_IMPORTED_MODULE_1_hsdata__["a" /* Data */](d)).filter(timeCond)); + } + createScales(axes) { + if (!this.scales) { + this.scales = { + primary: { x: new __WEBPACK_IMPORTED_MODULE_3__Scale__["a" /* Scale */](axes.primary.x.scale), y: new __WEBPACK_IMPORTED_MODULE_3__Scale__["a" /* Scale */](axes.primary.y.scale) }, + secondary: { x: new __WEBPACK_IMPORTED_MODULE_3__Scale__["a" /* Scale */](axes.secondary.x.scale), y: new __WEBPACK_IMPORTED_MODULE_3__Scale__["a" /* Scale */](axes.secondary.y.scale) } + }; + } + return this.scales; + } + adjustRange(plotArea, scales) { + scales.primary.x.range([plotArea.tl.x, plotArea.br.x]); + scales.primary.y.range([plotArea.br.y, plotArea.tl.y]); + scales.secondary.x.range([plotArea.tl.x, plotArea.br.x]); + scales.secondary.y.range([plotArea.br.y, plotArea.tl.y]); + } + adjustHeight(node) { + if (node.dom && node.dom.parentElement) { + const p = node.dom.parentElement; + const temp = viewBoxWidth * p.clientHeight / p.clientWidth; + if (!isNaN(temp) && temp !== viewBoxHeight) { + viewBoxHeight = temp; + } + } + } + adjustMargins(cfg) { + const cfgm = cfg.graph.margin; + function getBBox(css) { + const elems = document.getElementsByClassName(css); + const box = Array.prototype.map.call(elems, (e) => e.getBBox()); + if (box && box[0]) { + margin.t = Math.max(margin.t, cfgm.top - box[0].y); + margin.l = Math.max(margin.l, cfgm.left - box[0].x); + margin.b = Math.max(margin.b, box[0].y + box[0].height + cfgm.bottom - viewBoxHeight); + margin.r = Math.max(margin.r, box[0].x + box[0].width + cfgm.right - viewBoxWidth); + } + margin.t = Math.min(margin.t, 40); + margin.b = 30; + margin.l = 40; + } + const margin = { t: -1e6, l: -1e6, b: -1e6, r: -1e6 }; + getBBox('hs-graph-axis'); + getBBox('hs-graph-chart'); + this.marginOffset.top += Math.max(margin.t); + this.marginOffset.left += Math.max(margin.l); + this.marginOffset.bottom += Math.max(margin.b); + this.marginOffset.right += Math.max(margin.r); + } + onupdate(node) { + this.adjustHeight(node); + } + oncreate(node) { + window.addEventListener("resize", function () { __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].redraw(); }); + this.adjustHeight(node); + Promise.resolve(node.attrs.cfg) + .then(Object(__WEBPACK_IMPORTED_MODULE_10_hsutil__["b" /* delay */])(10)) + .then(this.adjustMargins.bind(this)) + .then(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].redraw); + } + adjustDomains(cfg, scales, data) { + const domains = [[1e20, -1e20], [1e20, -1e20]]; + cfg.series.map((s) => { + if (s.x) { + data[s.dataIndex].findDomain(s.x, domains[0]); + } + else { + domains[0][0] = 0; + domains[0][1] = data[s.dataIndex].export().rows.length - 1; + } + if (s.y) { + data[s.dataIndex].findDomain(s.y, domains[1]); + } + if (s.yBase) { + data[s.dataIndex].findDomain(s.yBase, domains[1]); + } + }); + scales.primary.x.setAutoDomain(domains[0]); + scales.primary.y.setAutoDomain(domains[1]); + } + view(node) { + const cfgFn = node.attrs.cfgFn; + const cfg = Graph.makeConfig(cfgFn); + const plotArea = this.createPlotArea(cfg.graph.margin); + const scales = this.createScales(cfg.axes); + this.adjustRange(plotArea, scales); + const data = this.createData(cfg); + this.adjustDomains(cfg.series, scales, data); + Graph.adjustConfig(cfg); + node.attrs.cfg = cfg; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph', width: '100%', height: '100%', + viewBox: `0 0 ${Object(__WEBPACK_IMPORTED_MODULE_9__SVGElem__["d" /* round */])(viewBoxWidth)} ${Object(__WEBPACK_IMPORTED_MODULE_9__SVGElem__["d" /* round */])(viewBoxHeight)}` }, [ + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_4__Canvas__["a" /* Canvas */], { cfg: cfg.canvas }), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_6__Chart__["a" /* Chart */], { cfg: cfg.chart, plotArea: plotArea }), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_7__Grid__["a" /* Grid */], { cfg: cfg.grid, scales: scales }), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */], { cfg: cfg.axes, scales: scales }), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_5__Series__["a" /* Series */], { cfg: cfg.series, scales: scales, data: data }), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_8__Legend__["a" /* Legend */], { cfg: cfg.legend }) + ]); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Graph; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR3JhcGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvR3JhcGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBaUVBLE9BQU8sRUFBRSxDQUFDLEVBQVEsTUFBVyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLElBQUksRUFFTyxNQUFTLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQWMsUUFBUSxDQUFDO0FBR3RDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBYSxTQUFTLENBQUM7QUFDdkMsT0FBTyxFQUFFLE1BQU0sRUFDUSxNQUFNLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsTUFBTSxFQUVRLE1BQU0sVUFBVSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxLQUFLLEVBQ1EsTUFBTyxTQUFTLENBQUM7QUFDdkMsT0FBTyxFQUFFLElBQUksRUFDUyxNQUFPLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsTUFBTSxFQUNRLE1BQU0sVUFBVSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxPQUFPLEVBR1AsS0FBSyxFQUFFLE1BQWEsV0FBVyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBYSxRQUFRLENBQUM7QUFFdEMsTUFBTSxZQUFZLEdBQVcsSUFBSSxDQUFDO0FBQ2xDLElBQU0sYUFBYSxHQUFVLEdBQUcsQ0FBQztBQWlEakMsY0FBYyxHQUFPO0lBQ2pCLElBQUksTUFBTSxHQUFPLEVBQUUsQ0FBQztJQUNwQixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFO1FBQzlCLElBQUksT0FBTyxHQUFHLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLEtBQUcsSUFBSSxFQUFFO1lBQ3ZFLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDNUI7YUFBTTtZQUNILE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDdEI7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUNILE9BQU8sTUFBTSxDQUFDO0FBQ2xCLENBQUM7QUFXRCxNQUFNLFlBQWEsU0FBUSxPQUFPO0lBQWxDOztRQWtGWSxpQkFBWSxHQUFHO1lBQ25CLElBQUksRUFBSSxDQUFDO1lBQ1QsS0FBSyxFQUFHLENBQUM7WUFDVCxHQUFHLEVBQUssQ0FBQztZQUNULE1BQU0sRUFBRSxDQUFDO1NBQ1osQ0FBQztJQXlJTixDQUFDO0lBL01XLE1BQU0sQ0FBQyxVQUFVLENBQUMsT0FBYztRQUNwQyxNQUFNLEdBQUcsR0FBVSxFQUFFLENBQUM7UUFDdEIsS0FBSyxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN6QixNQUFNLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDeEIsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hCLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDekIsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMxQixJQUFJLE9BQU8sRUFBRTtZQUNULElBQUk7Z0JBQ0EsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQ2hCO1lBQUMsT0FBTSxDQUFDLEVBQUU7Z0JBQ1AsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO2dCQUNoQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNmLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQ3hCO1NBQ0o7UUFDRCxPQUFPLEdBQUcsQ0FBQztJQUNmLENBQUM7SUFvQlMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFVO1FBQ3JDLEdBQUcsQ0FBQyxLQUFLLEdBQWdCO1lBQ3JCLE1BQU0sRUFBRTtnQkFDSixHQUFHLEVBQUUsRUFBRTtnQkFDUCxJQUFJLEVBQUUsRUFBRTtnQkFDUixNQUFNLEVBQUUsRUFBRTtnQkFDVixLQUFLLEVBQUUsRUFBRTthQUNaO1lBQ0QsUUFBUSxFQUFFLEVBQUU7U0FDZixDQUFDO0lBQ04sQ0FBQztJQU9TLE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBVTtRQUNwQyxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pCLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdkIsTUFBTSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN6QixJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZCLEtBQUssQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDeEIsTUFBTSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBWU8sY0FBYyxDQUFDLElBQTJEO1FBQzlFLE1BQU0sRUFBRSxHQUFHO1lBQ1AsQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJO1lBQ3JDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRztTQUN0QyxDQUFDO1FBQ0YsTUFBTSxFQUFFLEdBQUc7WUFDUCxDQUFDLEVBQUUsWUFBWSxHQUFJLElBQUksQ0FBQyxLQUFLLEdBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLO1lBQ3hELENBQUMsRUFBRSxhQUFhLEdBQUcsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU07U0FDNUQsQ0FBQztRQUNGLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBRU8sVUFBVSxDQUFDLEdBQU87UUFDdEIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFO1lBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMseUJBQXlCLENBQUMsQ0FBQztTQUMxQztRQUNELElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsRUFBRTtZQUMvQixPQUFPLENBQUMsR0FBRyxDQUFDLHdEQUF3RCxDQUFDLENBQUM7U0FDekU7UUFDRCxNQUFNLFFBQVEsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQztRQUNwQyxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQWMsRUFBRSxFQUFFLENBQzFDLENBQUMsQ0FBQyxDQUFDLFlBQVksSUFBSSxDQUFDLENBQUEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBRU8sWUFBWSxDQUFDLElBQVE7UUFDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFBRSxJQUFJLENBQUMsTUFBTSxHQUFHO2dCQUM5QixPQUFPLEVBQUksRUFBRSxDQUFDLEVBQUUsSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUksQ0FBQyxFQUFFLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFFO2dCQUN2RixTQUFTLEVBQUUsRUFBRSxDQUFDLEVBQUUsSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFFO2FBQzVGLENBQUM7U0FBQztRQUNILE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUN2QixDQUFDO0lBRUQsV0FBVyxDQUFDLFFBQWEsRUFBRSxNQUFhO1FBQ3BDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN2RCxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdkQsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3pELE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBT0QsWUFBWSxDQUFDLElBQVk7UUFDckIsSUFBSSxJQUFJLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFO1lBQ3BDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDO1lBQ2pDLE1BQU0sSUFBSSxHQUFHLFlBQVksR0FBRyxDQUFDLENBQUMsWUFBWSxHQUFHLENBQUMsQ0FBQyxXQUFXLENBQUM7WUFDM0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLEtBQUssYUFBYSxFQUFFO2dCQUN4QyxhQUFhLEdBQUcsSUFBSSxDQUFDO2FBQ3hCO1NBQ0o7SUFDTCxDQUFDO0lBS0QsYUFBYSxDQUFDLEdBQVU7UUFDcEIsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7UUFDOUIsaUJBQWlCLEdBQVc7WUFDeEIsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25ELE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFLLEVBQUMsRUFBRSxDQUFBLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ2xFLElBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDZCxNQUFNLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxHQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDakQsTUFBTSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLElBQUksR0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ2xELE1BQU0sQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxJQUFJLENBQUMsTUFBTSxHQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUNqRixNQUFNLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUUsSUFBSSxDQUFDLEtBQUssR0FBRSxZQUFZLENBQUMsQ0FBQzthQUNsRjtZQUNELE1BQU0sQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ2xDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2QsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDbEIsQ0FBQztRQUNELE1BQU0sTUFBTSxHQUFHLEVBQUMsQ0FBQyxFQUFDLENBQUMsR0FBRyxFQUFDLENBQUMsRUFBQyxDQUFDLEdBQUcsRUFBQyxDQUFDLEVBQUMsQ0FBQyxHQUFHLEVBQUMsQ0FBQyxFQUFDLENBQUMsR0FBRyxFQUFDLENBQUM7UUFDN0MsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3pCLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxJQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxJQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRCxRQUFRLENBQUMsSUFBWTtRQUNqQixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzVCLENBQUM7SUFFRCxRQUFRLENBQUMsSUFBWTtRQUNqQixNQUFNLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxFQUFFLGNBQWEsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDOUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN4QixPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO2FBQzFCLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDZixJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDbkMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBS0QsYUFBYSxDQUFDLEdBQWdCLEVBQUUsTUFBYSxFQUFFLElBQVc7UUFDdEQsTUFBTSxPQUFPLEdBQWdCLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFFNUQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFXLEVBQUUsRUFBRTtZQUMzQixJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQU07Z0JBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUFFO2lCQUNsRDtnQkFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDO2FBQUU7WUFDN0YsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFNO2dCQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFBRTtZQUMvRCxJQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUU7Z0JBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUFFO1FBQ3ZFLENBQUMsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvQyxDQUFDO0lBR0QsSUFBSSxDQUFDLElBQVk7UUFDYixNQUFNLEtBQUssR0FBUyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztRQUNyQyxNQUFNLEdBQUcsR0FBVSxLQUFLLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNDLE1BQU0sUUFBUSxHQUFRLElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM1RCxNQUFNLE1BQU0sR0FBVSxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNuQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFN0MsS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN4QixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFDckIsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLFVBQVUsRUFBRSxLQUFLLEVBQUMsTUFBTSxFQUFFLE1BQU0sRUFBQyxNQUFNO1lBQ3ZELE9BQU8sRUFBQyxPQUFPLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxLQUFLLENBQUMsYUFBYSxDQUFDLEVBQUUsRUFBRSxFQUFFO1lBQ3BFLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxHQUFHLEVBQUMsR0FBRyxDQUFDLE1BQU0sRUFBQyxDQUFDO1lBQzVCLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLEVBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUMsUUFBUSxFQUFFLENBQUM7WUFDOUMsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLEdBQUcsRUFBQyxHQUFHLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBQyxNQUFNLEVBQUUsQ0FBQztZQUN4QyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsR0FBRyxFQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3hDLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxHQUFHLEVBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUMsTUFBTSxFQUFFLElBQUksRUFBQyxJQUFJLEVBQUUsQ0FBQztZQUN2RCxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsR0FBRyxFQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQztTQUNoQyxDQUFDLENBQUM7SUFDUCxDQUFDO0NBQ0oifQ== + +/***/ }), +/* 21 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Layouter__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tokens__ = __webpack_require__(4); + + +const PillarLayouts = [ + 'columns', 'rows' +]; +/* harmony export (immutable) */ __webpack_exports__["PillarLayouts"] = PillarLayouts; + +const cParams = { + columns: { + cssClass: '.hs-column-layout', + fields: ['top', 'bottom', 'left', 'right', 'height', 'width'] + }, + rows: { + cssClass: '.hs-row-layout', + fields: ['left', 'right', 'top', 'bottom', 'width', 'height'] + } +}; +class PillarLayouter extends __WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */] { + constructor(params, areaDesc) { + super(areaDesc); + this.areaDesc = areaDesc; + this.fields = params.fields; + this.cssClass = params.cssClass; + let n = areaDesc.length - 1; + let first = 0; + let last = 0; + this.unit = areaDesc.some((area) => (area instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["e" /* PixelToken */])) ? + this.unitPixel : this.unitPercent; + areaDesc.some((area, i) => ((areaDesc[i] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? ++first < 0 : true)); + areaDesc.some((area, i) => ((areaDesc[n - i] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? ++last < 0 : true)); + this.firstFixed = first; + this.lastFixed = Math.min(last, areaDesc.length - first); + } + ; + getSizes(num) { + const first = this.firstFixed; + const last = this.lastFixed; + const desc = this.areaDesc; + const len = desc.length; + return [...Array(num).keys()].map((i) => { + let size = null; + let t = null; + if (i > num - 1 - last) { + size = desc[len - (num - i)].getSize(); + t = 'end'; + } + else if (i < first) { + size = desc[i].getSize(); + t = 'start'; + } + else if (len > 0 && len === first) { + size = desc[len - 1].getSize(); + t = 'start'; + } + return { size: size, code: t, fields: {} }; + }); + } + unitPercent(num) { + let f = this.fields; + let max = 100.0; + let styles = this.getSizes(num); + styles.forEach(style => { if (style.size) { + max = max - style.size; + num--; + } }); + let defDim = max / num; + function pass(styles, ix0, ix1, breakCond) { + let sumDim = 0; + styles.some(style => { + let size = style.size || defDim; + if (breakCond(style.code)) { + return true; + } + style.fields[ix0] = sumDim + '%'; + sumDim += size; + style.fields[ix1] = (100 - sumDim) + '%'; + style.fields[f[5]] = 'auto'; + return false; + }); + } + pass(styles, f[2], f[3], (e) => e === 'end'); + pass(styles.reverse(), f[3], f[2], (e) => e !== 'end'); + return styles.reverse(); + } + ; + unitPixel(num) { + let styles = this.getSizes(num); + let f = this.fields; + let defDim = 100.0 / num; + let sumDim = 0; + styles.some((style, i) => { + if (style.code === 'start') { + style.fields[f[2]] = sumDim + 'px'; + sumDim += style.size + (this.spacing || 0) + (this.spacing || 0); + style.fields[f[3]] = 'auto'; + style.fields[f[5]] = style.size + 'px'; + } + else if (style.code === null) { + style.fields[f[2]] = (sumDim > 0) ? (sumDim + 'px') : (i * defDim + '%'); + sumDim = -1; + style.fields[f[3]] = (100 - (i + 1) * defDim) + '%'; + style.fields[f[5]] = 'auto'; + } + else if (style.code === 'end') { + return true; + } + return false; + }); + sumDim = 0; + styles.slice().reverse().some((style, i) => { + style.fields[f[3]] = sumDim + 'px'; + if (style.code === 'end') { + sumDim += style.size + (this.spacing || 0) + (this.spacing || 0); + style.fields[f[2]] = 'auto'; + style.fields[f[5]] = style.size + 'px'; + } + else { + if (sumDim > 0 && style.code !== 'start') { + style.fields[f[5]] = 'auto'; + } + return true; + } + return false; + }); + return styles; + } + ; + getStyles(components) { + let f = this.fields; + let styles = this.unit(components.length); + components.map((c, i) => { + c.style = `${f[0]}:0%; ${f[1]}:0%; `; + Object.keys(styles[i].fields).forEach((st) => { c.style += `${st}: ${styles[i].fields[st]};`; }); + }); + return this.cssClass; + } + ; +} +; +class Columns extends PillarLayouter { + constructor(areaDesc) { + super(cParams[PillarLayouts[0]], areaDesc); + this.areaDesc = areaDesc; + } + ; +} +; +class Rows extends PillarLayouter { + constructor(areaDesc) { + super(cParams[PillarLayouts[1]], areaDesc); + this.areaDesc = areaDesc; + } + ; +} +; +__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register(PillarLayouts[0], Columns); +__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register(PillarLayouts[1], Rows); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGlsbGFyZWRMYXlvdXRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy92aWV3L1BpbGxhcmVkTGF5b3V0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBMkNBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBWSxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUFlLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBUyxVQUFVLENBQUM7QUFnQnBFLE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRztJQUN6QixTQUFTLEVBQUUsTUFBTTtDQUNwQixDQUFDO0FBS0YsTUFBTSxPQUFPLEdBQUc7SUFDWixPQUFPLEVBQWdCO1FBQ25CLFFBQVEsRUFBRSxtQkFBbUI7UUFDN0IsTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUM7S0FDaEU7SUFDRCxJQUFJLEVBQWdCO1FBQ2hCLFFBQVEsRUFBRSxnQkFBZ0I7UUFDMUIsTUFBTSxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUM7S0FDaEU7Q0FDSixDQUFDO0FBT0Ysb0JBQThCLFNBQVEsUUFBUTtJQWExQyxZQUFZLE1BQW1CLEVBQVMsUUFBc0I7UUFDMUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRG9CLGFBQVEsR0FBUixRQUFRLENBQWM7UUFFMUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzVCLElBQUksQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztRQUVoQyxJQUFJLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQztRQUMxQixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxJQUFJLElBQUksR0FBSSxDQUFDLENBQUM7UUFFZCxJQUFJLENBQUMsSUFB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 + +/***/ }), +/* 22 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Layouter__ = __webpack_require__(3); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tokens__ = __webpack_require__(4); + + +class Tiles extends __WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */] { + constructor(areaDesc) { + super(areaDesc); + this.areaDesc = areaDesc; + this.unit = areaDesc.some((area) => (area instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["e" /* PixelToken */])) ? + this.unitPixel : this.unitPercent; + } + ; + unitPercent(num) { + const desc = this.areaDesc; + const fill = this.areaDesc.some(a => (a instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["c" /* FillToken */])); + const root = Math.sqrt(num); + const rows = Math.round(root); + let cols = Math.floor(root); + if (root > cols) { + cols++; + } + let width = (desc[0] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[0].getSize() : undefined; + let height = (desc[1] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[1].getSize() : width; + width = width || 100 / cols; + height = height || 100 / rows; + let left = 0; + let top = 0; + let styles = [...Array(num).keys()].map(i => { + let r = 'auto'; + let w = width + '%'; + let b = 'auto'; + let h = height + '%'; + if ((left + 2 * width) > 100 && fill) { + r = '0%'; + w = 'auto'; + } + if ((top + 2 * height) > 100 && fill) { + b = '0%'; + h = 'auto'; + } + const style = ` + top: ${Math.floor(top)}%; bottom:${b}; + left: ${left}%; right:${r}; + width: ${w}; height: ${h}; + `; + if (Math.round(left += width) > 100 - Math.floor(width)) { + left = 0; + top += height; + } + return style; + }); + return styles; + } + ; + unitPixel(num) { + const desc = this.areaDesc; + const root = Math.sqrt(num); + const rows = Math.round(root); + let cols = Math.floor(root); + if (root > cols) { + cols++; + } + let width = (desc[0] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[0].getSize() : undefined; + let height = (desc[1] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[1].getSize() : width; + width = width || 100 / cols; + height = height || 100 / rows; + let left = 0; + let top = 0; + let styles = [...Array(num).keys()].map(i => { + let r = 'auto'; + let w = width + 'px'; + let b = 'auto'; + let h = height + 'px'; + const style = ` + top: ${Math.floor(top)}%; bottom:${b}; + left: ${left}%; right:${r}; + width: ${w}; height: ${h}; + `; + if (Math.round(left += width) > 100 - Math.floor(width)) { + left = 0; + top += height; + } + return style; + }); + return styles; + } + ; + getStyles(components) { + let styles = this.unit(components.length); + components.map((c, i) => { + c.style = styles[i]; + }); + return '.hs-tile-layout'; + } + ; +} +; +__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register('tiles', Tiles); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGlsZUxheW91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvVGlsZUxheW91dGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZEQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVksWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBZSxTQUFTLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFTLFVBQVUsQ0FBQztBQU8vRSxXQUFZLFNBQVEsUUFBUTtJQVF4QixZQUFtQixRQUFzQjtRQUNyQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFERCxhQUFRLEdBQVIsUUFBUSxDQUFjO1FBSXJDLElBQUksQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQWdCLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxZQUFZLFVBQVUsQ0FBQyxDQUFDLENBQUEsQ0FBQztZQUMxRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFDLENBQUM7SUFBQSxDQUFDO0lBRU0sV0FBVyxDQUFDLEdBQVU7UUFDMUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUMzQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxZQUFZLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDL0QsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzlCLElBQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDOUIsSUFBSSxJQUFJLEdBQUcsSUFBSSxFQUFFO1lBQUUsSUFBSSxFQUFFLENBQUM7U0FB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 + +/***/ }), +/* 23 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__mithril__ = __webpack_require__(7); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Layouter__ = __webpack_require__(3); + + +class Layout { + getComponents(node) { + return !Array.isArray(node.attrs.content) ? node.attrs.content : + node.attrs.content.map((c) => { + if (c.compClass) { + c.attrs.route = node.attrs.route; + return Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(c.compClass, c.attrs); + } + else { + return c; + } + }); + } + getCSS(node) { + return node.attrs.css || ''; + } + normalizeContent(components) { + if (typeof components === 'string') { + return [Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])('.hs-leaf', __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].trust(components))]; + } + if (components.length > 0) { + return components.map((comp) => (comp instanceof Layout) ? comp : Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(Layout, { content: comp })); + } + return [components]; + } + view(node) { + const content = this.normalizeContent(this.getComponents(node)); + let css = __WEBPACK_IMPORTED_MODULE_1__Layouter__["a" /* Layouter */].createLayout(node.attrs, content); + const attrs = { + style: node.style, + route: node.attrs.route, + onclick: node.attrs.onclick + }; + node.attrs.route = undefined; + if (node.attrs.href) { + attrs.href = node.attrs.href; + attrs.oncreate = __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].route.link; + attrs.onupdate = __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].route.link; + } + return Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(`.hs-layout ${css} ${this.getCSS(node)}`, attrs, content.map((c) => c)); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Layout; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5b3V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvTGF5b3V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlCQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQVcsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBWSxZQUFZLENBQUM7QUF5QjVDLE1BQU07SUFvQlEsYUFBYSxDQUFDLElBQVU7UUFDOUIsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMzRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFLLEVBQUUsRUFBRTtnQkFDN0IsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFO29CQUNiLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO29CQUNqQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztpQkFDbEM7cUJBQU07b0JBQ0gsT0FBTyxDQUFDLENBQUM7aUJBQ1o7WUFDTCxDQUFDLENBQUMsQ0FBQztJQUNYLENBQUM7SUFRUyxNQUFNLENBQUMsSUFBVTtRQUN2QixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQztJQUNoQyxDQUFDO0lBR08sZ0JBQWdCLENBQUMsVUFBNkM7UUFDbEUsSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUU7WUFDaEMsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDL0M7UUFDRCxJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFFO1lBQ3JCLE9BQU8sVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQXlCLEVBQVEsRUFBRSxDQUNsRCxDQUFDLElBQUksWUFBWSxNQUFNLENBQUMsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUMsT0FBTyxFQUFDLElBQUksRUFBQyxDQUFDLENBQ2pFLENBQUM7U0FDTDtRQUVELE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBcUJELElBQUksQ0FBQyxJQUFVO1FBQ1gsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNoRSxJQUFJLEdBQUcsR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDckQsTUFBTSxLQUFLLEdBQU87WUFDZCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSztZQUN2QixPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPO1NBQzlCLENBQUM7UUFDRixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUM7UUFDN0IsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRTtZQUNqQixLQUFLLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO1lBQzdCLEtBQUssQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7WUFDOUIsS0FBSyxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztTQUNqQztRQUNELE9BQU8sQ0FBQyxDQUFDLGNBQWMsR0FBRyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RixDQUFDO0NBQ0oifQ== + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var pushStateMock = __webpack_require__(25) +var domMock = __webpack_require__(27) +var xhrMock = __webpack_require__(28) + +module.exports = function(env) { + env = env || {} + var $window = env.window = {} + + var dom = domMock() + var xhr = xhrMock() + for (var key in dom) if (!$window[key]) $window[key] = dom[key] + for (var key in xhr) if (!$window[key]) $window[key] = xhr[key] + pushStateMock(env) + + return $window +} + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var parseURL = __webpack_require__(10) +var callAsync = __webpack_require__(11) + +function debouncedAsync(f) { + var ref + return function() { + if (ref != null) return + ref = callAsync(function(){ + ref = null + f() + }) + } +} + +module.exports = function(options) { + if (options == null) options = {} + + var $window = options.window || {} + var protocol = options.protocol || "http:" + var hostname = options.hostname || "localhost" + var port = "" + var pathname = "/" + var search = "" + var hash = "" + + var past = [{url: getURL(), isNew: true, state: null, title: null}], future = [] + + function getURL() { + if (protocol === "file:") return protocol + "//" + pathname + search + hash + return protocol + "//" + hostname + prefix(":", port) + pathname + search + hash + } + function setURL(value) { + var data = parseURL(value, {protocol: protocol, hostname: hostname, port: port, pathname: pathname}) + var isNew = false + if (data.protocol != null && data.protocol !== protocol) protocol = data.protocol, isNew = true + if (data.hostname != null && data.hostname !== hostname) hostname = data.hostname, isNew = true + if (data.port != null && data.port !== port) port = data.port, isNew = true + if (data.pathname != null && data.pathname !== pathname) pathname = data.pathname, isNew = true + if (data.search != null && data.search !== search) search = data.search, isNew = true + if (data.hash != null && data.hash !== hash) { + hash = data.hash + if (!isNew) { + hashchange() + } + } + return isNew + } + + function prefix(prefix, value) { + if (value === "") return "" + return (value.charAt(0) !== prefix ? prefix : "") + value + } + function _hashchange() { + if (typeof $window.onhashchange === "function") $window.onhashchange({type: "hashchange"}) + } + var hashchange = debouncedAsync(_hashchange) + function popstate() { + if (typeof $window.onpopstate === "function") $window.onpopstate({type: "popstate", state: $window.history.state}) + } + function unload() { + if (typeof $window.onunload === "function") $window.onunload({type: "unload"}) + } + + $window.location = { + get protocol() { + return protocol + }, + get hostname() { + return hostname + }, + get port() { + return port + }, + get pathname() { + return pathname + }, + get search() { + return search + }, + get hash() { + return hash + }, + get origin() { + if (protocol === "file:") return "null" + return protocol + "//" + hostname + prefix(":", port) + }, + get host() { + if (protocol === "file:") return "" + return hostname + prefix(":", port) + }, + get href() { + return getURL() + }, + + set protocol(value) { + throw new Error("Protocol is read-only") + }, + set hostname(value) { + unload() + past.push({url: getURL(), isNew: true}) + future = [] + hostname = value + }, + set port(value) { + if (protocol === "file:") throw new Error("Port is read-only under `file://` protocol") + unload() + past.push({url: getURL(), isNew: true}) + future = [] + port = value + }, + set pathname(value) { + if (protocol === "file:") throw new Error("Pathname is read-only under `file://` protocol") + unload() + past.push({url: getURL(), isNew: true}) + future = [] + pathname = prefix("/", value) + }, + set search(value) { + unload() + past.push({url: getURL(), isNew: true}) + future = [] + search = prefix("?", value) + }, + set hash(value) { + var oldHash = hash + past.push({url: getURL(), isNew: false}) + future = [] + hash = prefix("#", value) + if (oldHash != hash) hashchange() + }, + + set origin(value) { + //origin is writable but ignored + }, + set host(value) { + //host is writable but ignored in Chrome + }, + set href(value) { + var url = getURL() + var isNew = setURL(value) + if (isNew) { + setURL(url) + unload() + setURL(value) + } + past.push({url: url, isNew: isNew}) + future = [] + }, + } + $window.history = { + pushState: function(state, title, url) { + past.push({url: getURL(), isNew: false, state: state, title: title}) + future = [] + setURL(url) + }, + replaceState: function(state, title, url) { + var entry = past[past.length - 1] + entry.state = state + entry.title = title + setURL(url) + }, + back: function() { + if (past.length > 1) { + var entry = past.pop() + if (entry.isNew) unload() + future.push({url: getURL(), isNew: false, state: entry.state, title: entry.title}) + setURL(entry.url) + if (!entry.isNew) popstate() + } + }, + forward: function() { + var entry = future.pop() + if (entry != null) { + if (entry.isNew) unload() + past.push({url: getURL(), isNew: false, state: entry.state, title: entry.title}) + setURL(entry.url) + if (!entry.isNew) popstate() + } + }, + get state() { + return past.length === 0 ? null : past[past.length - 1].state + }, + } + $window.onpopstate = null, + $window.onhashchange = null, + $window.onunload = null + + return $window +} + + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, undefined) { + "use strict"; + + if (global.setImmediate) { + return; + } + + var nextHandle = 1; // Spec says greater than zero + var tasksByHandle = {}; + var currentlyRunningATask = false; + var doc = global.document; + var registerImmediate; + + function setImmediate(callback) { + // Callback can either be a function or a string + if (typeof callback !== "function") { + callback = new Function("" + callback); + } + // Copy function arguments + var args = new Array(arguments.length - 1); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i + 1]; + } + // Store and register the task + var task = { callback: callback, args: args }; + tasksByHandle[nextHandle] = task; + registerImmediate(nextHandle); + return nextHandle++; + } + + function clearImmediate(handle) { + delete tasksByHandle[handle]; + } + + function run(task) { + var callback = task.callback; + var args = task.args; + switch (args.length) { + case 0: + callback(); + break; + case 1: + callback(args[0]); + break; + case 2: + callback(args[0], args[1]); + break; + case 3: + callback(args[0], args[1], args[2]); + break; + default: + callback.apply(undefined, args); + break; + } + } + + function runIfPresent(handle) { + // From the spec: "Wait until any invocations of this algorithm started before this one have completed." + // So if we're currently running a task, we'll need to delay this invocation. + if (currentlyRunningATask) { + // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a + // "too much recursion" error. + setTimeout(runIfPresent, 0, handle); + } else { + var task = tasksByHandle[handle]; + if (task) { + currentlyRunningATask = true; + try { + run(task); + } finally { + clearImmediate(handle); + currentlyRunningATask = false; + } + } + } + } + + function installNextTickImplementation() { + registerImmediate = function(handle) { + process.nextTick(function () { runIfPresent(handle); }); + }; + } + + function canUsePostMessage() { + // The test against `importScripts` prevents this implementation from being installed inside a web worker, + // where `global.postMessage` means something completely different and can't be used for this purpose. + if (global.postMessage && !global.importScripts) { + var postMessageIsAsynchronous = true; + var oldOnMessage = global.onmessage; + global.onmessage = function() { + postMessageIsAsynchronous = false; + }; + global.postMessage("", "*"); + global.onmessage = oldOnMessage; + return postMessageIsAsynchronous; + } + } + + function installPostMessageImplementation() { + // Installs an event handler on `global` for the `message` event: see + // * https://developer.mozilla.org/en/DOM/window.postMessage + // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages + + var messagePrefix = "setImmediate$" + Math.random() + "$"; + var onGlobalMessage = function(event) { + if (event.source === global && + typeof event.data === "string" && + event.data.indexOf(messagePrefix) === 0) { + runIfPresent(+event.data.slice(messagePrefix.length)); + } + }; + + if (global.addEventListener) { + global.addEventListener("message", onGlobalMessage, false); + } else { + global.attachEvent("onmessage", onGlobalMessage); + } + + registerImmediate = function(handle) { + global.postMessage(messagePrefix + handle, "*"); + }; + } + + function installMessageChannelImplementation() { + var channel = new MessageChannel(); + channel.port1.onmessage = function(event) { + var handle = event.data; + runIfPresent(handle); + }; + + registerImmediate = function(handle) { + channel.port2.postMessage(handle); + }; + } + + function installReadyStateChangeImplementation() { + var html = doc.documentElement; + registerImmediate = function(handle) { + // Create a + + \ No newline at end of file diff --git a/docs/example/search.json b/docs/example/search.json new file mode 100644 index 0000000..56736a6 --- /dev/null +++ b/docs/example/search.json @@ -0,0 +1,6 @@ +[ + "John", + "Jane", + "Peter", + "Mary" +] \ No newline at end of file diff --git a/docs/hsDoc.css b/docs/hsDoc.css new file mode 100644 index 0000000..67c8c2a --- /dev/null +++ b/docs/hsDoc.css @@ -0,0 +1,1062 @@ +.hs-layout { + left: 0%; + top: 0%; + width: 100%; + height: 100%; + position: absolute; + display: block; + overflow: scroll; +} +.hs-row-layout > .hs-layout { + box-sizing: border-box; +} +.hs-column-layout > .hs-layout { + box-sizing: border-box; +} +.hs-tile-layout > .hs-layout { + box-sizing: border-box; +} +.hs-layout-frame { + position: relative; +} +.hs-layout-fill { + position: relative; + padding: 0; + margin: 0; + width: 100%; + height: 100%; +} +.hs-align-left { + text-align: left; +} +.hs-align-right { + text-align: right; +} +.hs-align-center { + text-align: center; +} +/*# sourceMappingURL=hsLayout.css.map */ +.hs-menu { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; + box-sizing: content-box; + height: 30px; + background-color: transparent; +} +.hs-menu .hs-layout { + overflow: hidden; + border-left: 0.5px solid white; + border-right: 0.5px solid white; +} +.hs-menu .hs-layout:first-child { + border-left: none; +} +.hs-menu .hs-layout:last-child { + border-right: none; +} +.hs-menu .hs-selectable { + overflow: hidden; + padding: 5px 0px 5px 10px; + background-color: #eee; +} +.hs-menu .hs-selected { + background-color: #fff; + font-weight: bold; +} +.hs-collapsible-arrow { + width: 0; + height: 0; + display: inline-block; +} +.hs-collapsible-arrow-right { + width: 0; + height: 0; + display: inline-block; + border-left: 7px solid #666; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + padding-right: 3px; +} +.hs-collapsible-arrow-down { + width: 0; + height: 0; + display: inline-block; + border-left: 7px solid #666; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + padding-right: 3px; + transform: rotate(90deg); +} +.hs-collapsible-arrow-up { + width: 0; + height: 0; + display: inline-block; + border-left: 7px solid #666; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + padding-right: 3px; + transform: rotate(-90deg); +} +.hs-collapsible-arrow-left { + width: 0; + height: 0; + display: inline-block; + border-left: 7px solid #666; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + padding-right: 3px; + transform: rotate(180deg); +} +.hs-collapsible { + position: relative; +} +.hs-collapsible-title div { + display: inline-block; +} +.hs-collapsible-title div.hs-collapsible-pre { + position: absolute; + margin-right: auto; + left: 3px; + top: 3.5px; +} +.hs-collapsible-title div.hs-collapsible-pre + div { + margin-left: 13px; +} +.hs-collapsible-title div.hs-collapsible-post { + position: absolute; + margin-left: auto; + right: 3px; + top: 3.5px; +} +.hs-collapsible-content { + left: 5px; + position: relative; + overflow: hidden; + height: 0%; + max-height: 0%; +} +.hs-collapsible-expanded .hs-collapsible-content { + height: auto; + max-height: 100%; + transition: all 0.3s ease-in-out; +} +.hs-dropover { + position: relative; +} +.hs-dropover-content { + left: 5px; + position: relative; + transition: all 0.3s ease-in-out; + overflow: hidden; + max-height: 0%; +} +.hs-dropover-content.hs-dropover-expanded { + max-height: 100%; +} +.hs-abstract-button-group { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; +} +.hs-abstract-button { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; +} +.hs-button { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; + margin-left: 5px; + margin-right: 5px; + height: 30px; + border-radius: 6px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + color: white; + font-weight: bold; + background-color: #48f; +} +.hs-button:hover { + background-color: #2a78ff; +} +.hs-button.hs-button-pressed { + background-color: #aac9ff; +} +.hs-button span { + vertical-align: middle; + line-height: 30px; +} +.hs-button-group { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; + overflow: hidden; + border-radius: 6px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + background-color: transparent; + height: 30px; +} +.hs-button-group .hs-selectable { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; + line-height: 30px; + background: linear-gradient(to bottom, #eee, #dde); +} +.hs-button-group .hs-selectable.hs-selected { + background: initial; + background-color: #48f; + font-weight: bold; + color: white; +} +.hs-button-group > .hs-layout > :first-child > .hs-selectable { + border-left: none; + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} +.hs-button-group > .hs-layout > :last-child > .hs-selectable { + border-right: none; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} +.hs-radio-buttons { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; + overflow: hidden; + border-radius: 6px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + background-color: transparent; + height: 30px; +} +.hs-radio-buttons .hs-selectable { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; + line-height: 30px; + background: linear-gradient(to bottom, #eee, #dde); +} +.hs-radio-buttons .hs-selectable.hs-selected { + background: initial; + background-color: #48f; + font-weight: bold; + color: white; +} +.hs-radio-buttons > .hs-layout > :first-child > .hs-selectable { + border-left: none; + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} +.hs-radio-buttons > .hs-layout > :last-child > .hs-selectable { + border-right: none; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} +.hs-toggle-button { + position: relative; + margin: 0px; + box-sizing: border-box; + text-align: center; + vertical-align: middle; + margin-left: 5px; + margin-right: 5px; + height: 30px; + border-radius: 6px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + color: white; + font-weight: bold; + background-color: #48f; +} +.hs-toggle-button:hover { + background-color: #2a78ff; +} +.hs-toggle-button.hs-button-pressed { + background-color: #aac9ff; +} +.hs-toggle-button span { + vertical-align: middle; + line-height: 30px; +} +.hs-toggle-button span { + vertical-align: middle; + line-height: 30px; +} +.hs-corner-button { + position: absolute; + top: 0; + right: 0; + font-size: 16pt; + line-height: 20px; + width: 20px; + height: 20px; + border-bottom-left-radius: 5px; + border-top-right-radius: 10px; + text-align: center; + vertical-align: middle; +} +.hs-modal-background { + position: fixed; + left: 0%; + right: 0%; + top: 0%; + bottom: 0%; + background-color: rgba(16, 16, 16, 0.6); + z-index: 998; +} +.hs-modal-foreground { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding: 10px; + background-color: white; + border-radius: 10px; + z-index: 999; + width: auto; + height: auto; +} +.hs-add-button { + position: absolute; + top: 0; + right: 0; + width: 1em; +} +.hs-add-button::before { + content: '+'; +} +.hs-add-button:hover { + font-weight: bold; +} +.hs-remove-button { + position: absolute; + top: -0.5em; + right: 0; + width: 1em; +} +.hs-remove-button::before { + content: '_'; +} +.hs-remove-button:hover { + font-weight: bold; +} +.hs-form { + position: relative; +} +.hs-typeahead-input { + position: relative; + left: 5px; + right: 5px; + top: 0; + box-shadow: 0 0 5px 0px #ccc; + border: 1px solid #ccf; + border-radius: 4px; + padding: 4px; + font-size: 16px; +} +.hs-typeahead-input.hs-typeahead-value { + color: #66f; +} +.hs-typeahead-input.hs-typeahead-placeholder { + color: #ccc; +} +.hs-typeahead-list { + position: absolute; + z-index: 9999; + left: 20px; + width: 200px; + border: 1px solid #aaf; + box-shadow: 0 0 5px 0px #ccc inset; + background-color: white; +} +.hs-typeahead-list div { + padding: 5px; +} +.hs-typeahead-list div:hover { + text-shadow: 0 0 3px #88f; +} +/*# sourceMappingURL=hsWidget.css.map */ +.hs-graph { + font-size: 20px; + position: absolute; +} +.hs-graph-canvas { + fill: none; +} +.hs-graph-axis { + stroke: black; +} +.hs-graph-axis text { + fill: black; + stroke: none; +} +.hs-graph-axis-title { + font-size: 120%; +} +.hs-graph-axis-x .hs-graph-axis-title { + text-anchor: end; +} +.hs-graph-axis-y .hs-graph-axis-title { + text-anchor: middle; +} +.hs-graph-axis-tick-label text { + font-size: 80%; +} +.hs-graph-axis-major-tick-label text { + font-size: 80%; +} +.hs-graph-axis-minor-tick-label text { + font-size: 80%; +} +.hs-graph-axis-minor-tick-label text { + font-size: 80%; +} +.hs-graph-grid line { + stroke-width: 1; +} +.hs-graph-grid-major line { + stroke: #ccc; +} +.hs-graph-grid-minor line { + stroke: #eee; +} +.hs-graph-series { + fill: none; +} +.hs-graph-series-labels { + font-size: 70%; +} +.hs-graph-chart { + fill: white; +} +.hs-graph-chart text { + fill: black; + stroke: none; +} +.hs-graph-chart-title { + font-size: 140%; +} +/*# sourceMappingURL=hsGraph.css.map */ +body { + color: black; +} +.hs-layout { + margin: 0; + padding: 0; +} +th { + text-align: left; +} +.hs-tooltip { + position: relative; + display: inline; +} +.hs-tooltip span { + position: absolute; + white-space: nowrap; + padding-left: 5px; + padding-right: 5px; + font-size: 12px; + color: #FFFFFF; + background: #000; + height: 1.6em; + line-height: 1.6em; + text-align: center; + visibility: hidden; + border-radius: 5px; + box-shadow: -1px 4px 6px #888; +} +.hs-tooltip span:after { + content: ''; + position: absolute; + width: 0; + height: 0; +} +.hs-tooltip span.hs-tooltip-left:after { + top: 50%; + left: 100%; + margin-top: -5px; + border-left: 5px solid #000; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; +} +.hs-tooltip span.hs-tooltip-right:after { + top: 50%; + right: 100%; + margin-top: -5px; + border-right: 5px solid #000; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; +} +.hs-tooltip span.hs-tooltip-top:after { + top: 100%; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} +.hs-tooltip span.hs-tooltip-bottom:after { + bottom: 100%; + left: 50%; + margin-left: -5px; + border-bottom: 5px solid #000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} +.hs-tooltip:hover span { + visibility: visible; + opacity: 1; + z-index: 999; +} +.hs-tooltip:hover span.hs-tooltip-left { + right: 100%; + top: 50%; + margin-top: -5px; +} +.hs-tooltip:hover span.hs-tooltip-right { + left: 100%; + top: 50%; + margin-top: -5px; + margin-left: 5px; +} +.hs-tooltip:hover span.hs-tooltip-top { + bottom: 1.6em; + left: 0%; +} +.hs-tooltip:hover span.hs-tooltip-bottom { + top: 1.6em; + left: 0%; + margin-top: 5px; +} +.hs-site-header .hs-site-title { + padding: 5px 10px; + border-bottom: 1px solid #ccc; +} +.hs-site-header .hs-menu .hs-selectable { + border-left: 0.5px solid white; + border-right: rgba(255, 255, 255, 0); + border-bottom: 1px solid #ccc; +} +.hs-site-header .hs-menu .hs-selected { + border-bottom: 1px solid white; +} +.hs-left { + /* + a.hs-left-nav-selected { + background-color: @SelectColor; + &:hover { + background-color: darken(@HoverColor, 10%); + } + } +*/ +} +.hs-left a { + text-decoration: none; + color: black; +} +.hs-left a :link, +.hs-left a :visited { + text-decoration: none; +} +.hs-left .hs-left-nav { + padding: 0px 5px 0 5px; + font-size: 0.8em; + list-style-type: none; +} +.hs-left .hs-library-name { + font-size: 1.6em; + font-weight: bold; + padding: 0.3em 10px; + margin: 2px 0; + height: 0.8em; +} +.hs-left .hs-library-name:hover { + background-color: #eef; +} +.hs-left .hs-left-nav-module { + margin-top: 5px; + margin-bottom: 10px; + border: 1px solid #aaa; + border-radius: 5px; + overflow: hidden; +} +.hs-left .hs-left-nav-module .hs-collapsible-title { + padding-left: 5px; + font-size: 1.2em; + background-color: #eee; +} +.hs-left .hs-left-nav-module .hs-collapsible-title:hover { + background-color: #ccc; +} +.hs-left .hs-left-nav-module.hs-collapsible-expanded .hs-collapsible-title { + background-color: #cfc; +} +.hs-left .hs-left-nav-header { + padding-right: 5px; + text-align: right; + font-style: italic; + background-color: #eef; +} +.hs-left .hs-left-nav-entries { + border-top: 1px solid #ccc; +} +.hs-left .hs-left-nav-entry { + padding-left: 5px; + background-color: transparent; +} +.hs-left .hs-left-nav-entry:hover { + background-color: #fee; +} +.hs-left .hs-left-nav-exported { + color: #44f; + font-weight: bold; +} +.hs-item-padding { + padding: 10px 0.4em 10px 0em; +} +.hs-item-title { + background-color: #eef; + border-top: 1px solid #d5d5ff; + border-bottom: 1px solid #d5d5ff; + margin-top: 5px; + padding: 10px 0.4em 10px 0em; + padding-left: 5px; +} +.hs-item-name { + font-weight: bold; + color: #008; + font-size: 1.1em; +} +.hs-item-unknown-type { + color: #f44; +} +.hs-item-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; +} +.hs-item-export-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; +} +.hs-item-public-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; + color: #484; +} +.hs-item-private-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; + color: #844; +} +.hs-item-protected-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; + color: #884; +} +.hs-item-static-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; + color: #888; +} +.hs-item-constructorProperty-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; + color: #848; +} +.hs-item-optional-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; + color: #aaa; +} +.hs-item-unknown-flag { + color: #44f; + padding: 10px 0.4em 10px 0em; + color: #f44; + font-weight: bold; +} +.hs-item-kind { + font-style: italic; + padding: 10px 0.4em 10px 0em; +} +.hs-item-extends { + padding: 10px 0.4em 10px 0em; + padding-left: 0.3em; +} +.hs-item-extensions { + padding: 10px 0.4em 10px 0em; +} +.hs-item-extension { + padding: 10px 0.4em 10px 0em; +} +.hs-item-unknown-kind { + color: #f44; +} +.hs-item-signature { + font-size: 1em; +} +.hs-item-signature .hs-item-name { + padding: 0; +} +.hs-item-default { + font-size: 90%; + background-color: #fff; + padding: 2px; + border-radius: 4px; + font-weight: bold; +} +.hs-item-sig-type { + border-radius: 4px; + background-color: #ddb; + padding: 2px 4px; + margin-left: 2px; + margin-right: 2px; + font-size: 0.9em; +} +.hs-item-sig-type :link { + text-decoration: none; +} +.hs-item-type-instrinct { + font-style: italic; + color: #800; +} +.hs-item-optional:after { + content: '?'; + font-style: italic; + font-weight: bold; +} +.hs-item-sig-param { + margin: 0 2px; +} +.hs-item-sig-param .hs-item-name { + color: #008; + font-size: 1em; + font-weight: normal; +} +.hs-item-member-source { + float: right; + padding: 10px 0em; + margin-right: 10px; + bottom: 3px; + font-size: 0.7em; +} +.hs-item-comment { + margin-left: 5px; + margin-right: 5px; + font-size: 0.9em; + padding: 5px 0px 10px 0px; +} +.hs-item-comment h1 { + margin-top: 1.3em; + margin-bottom: 1em; + font-size: 2em; + color: #336; +} +.hs-item-comment h2 { + margin-top: 1em; + margin-bottom: 0.6em; + font-size: 1.6em; + color: #336; +} +.hs-item-comment h3 { + margin-top: 1em; + margin-bottom: 0.6em; + font-size: 1.4em; + color: #336; +} +.hs-item-comment h4 { + margin-top: 1em; + margin-bottom: 0.4em; + font-size: 1.1em; + color: #336; +} +.hs-item-comment pre { + margin-top: 5px; +} +.hs-item-comment-special { + margin: 4px 0; + line-height: 1.6em; + font-size: 1em; +} +.hs-item-comment-special .hs-item-comment-tag { + font-size: 0.9em; + background-color: #eee; + border: 1px solid #aae; + border-radius: 2px; + width: 200px; + margin-right: 10px; +} +.hs-item-comment-special .hs-item-comment-tag:after { + content: ':'; +} +.hs-item-comment-desc { + line-height: 1.3em; + margin-top: 5px; + margin-bottom: 10px; +} +.hs-item-comment-desc li, +.hs-item-comment-desc p { + margin: 5px 0 0 0; +} +.hs-item-comment-desc ul { + margin: 0 0 10px 0; +} +.hs-item-comment-params { + display: inline-block; +} +.hs-item-comment-param { + line-height: 1.6em; + margin-top: 5px; + margin-bottom: 5px; + background-color: #eee; + border-radius: 5px; +} +.hs-item-comment-return { + line-height: 1.6em; + margin-top: 5px; + margin-bottom: 5px; + background-color: #eee; + border-radius: 5px; + margin-top: 0px; +} +.hs-item-comment-tag { + padding: 3px 5px; + font-weight: bold; + font-size: 1.1em; + color: #000; +} +.hs-item-comment-return .hs-item-comment-tag { + color: #00A; +} +.hs-item-public .hs-item-comment-return .hs-item-comment-tag { + color: #060; +} +.hs-item-comment-text { + padding: 3px 5px; + color: #000; +} +.hs-item-comment-return .hs-item-comment-text { + color: #00A; +} +.hs-item-public .hs-item-comment-return .hs-item-comment-text { + color: #060; +} +.hs-item-comment-default-value { + font-style: italic; +} +.hs-code-indent { + display: inline-block; + width: 20px; +} +.hs-main-detail { + border-left: 1px solid #ccc; +} +.hs-item-detail { + list-style-type: none; + margin-top: 50px; +} +.hs-item-members { + font-size: 1em; +} +.hs-item-member-title { + background-color: #e0e0ef; + font-size: 1.3em; + font-weight: bold; + padding: 5px 0 5px 0; + margin: 4px 0; +} +.hs-item-member-title span { + margin-left: 5px; + margin-right: 5px; +} +.hs-item-desc { + padding-left: 0.5em; +} +.hs-item-variable { + background: linear-gradient(to bottom, #e0e0ef 30%, rgba(255, 255, 255, 0)); +} +.hs-item-title .hs-item-variable { + background-image: none; +} +.hs-item-member.hs-item-public .hs-item-member-title { + background-color: #e0efe0; + color: #060; +} +.hs-item-member.hs-item-public .hs-item-variable { + background: linear-gradient(to bottom, #e0efe0 30%, rgba(255, 255, 255, 0)); +} +.hs-item-member.hs-item-static .hs-item-member-title { + background-color: #efefe0; + color: #600; +} +.hs-item-member.hs-item-static .hs-item-variable { + background: linear-gradient(to bottom, #efefe0 30%, rgba(255, 255, 255, 0)); +} +.hs-item-child { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-member-type { + display: inline; +} +.hs-item-class { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-interface { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-constructor { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-external-module { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-alias { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-property { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-accessors { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-parameter { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-object-literal { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-variable { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-method { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-function { + padding: 4px 0 10px 0px; + font-size: 1em; +} +.hs-item-inherited { + background-color: #f8f8f8; + font-size: 80%; + color: #444; +} +.hs-item-inherited.hs-item-member-title { + background-color: #eef; + font-size: 100%; +} +.hs-item-inherited .hs-item-inherited-from { + font-style: italic; +} +.hs-item-unknown-member { + padding: 4px 0 10px 0px; + font-size: 1em; + background-color: #f00; + color: #fff; + font-weight: bold; +} +pre { + padding-left: 10px; + margin-right: 10px; + border-radius: 4px; + background-color: #f4f4f4; +} +pre code { + padding: 0; +} +code { + color: #800; + background-color: #f4f4f4; + border-radius: 4px; + padding: 3px; +} +example { + display: block; + height: 300px; + width: 100%; + padding: 5px; + box-sizing: border-box; +} +example .hs-execution { + background-color: #eed; +} +example .hs-execution div { + margin: 0px; +} +example .hs-execution .hs-leaf { + padding: 5px; +} +example .hs-execution .hs-white { + position: absolute; + background-color: white; + padding-left: 5px; + left: 5px; + top: 0; + bottom: 0; + right: 0; +} +example .hs-source .hs-menu .hs-selectable { + background-color: white; +} +example .hs-source .hs-menu .hs-selectable.hs-selected { + background-color: #dde; +} +example .hs-source .hs-source-main { + background-color: #dde; + font-size: 12px; +} +example .hs-source .hs-selected { + background-color: #dde; +} +example pre { + padding-left: 10px; +} +example > .hs-column-layout > .hs-layout:last-child { + border-left: 3px solid white; +} +example code, +example pre { + background-color: transparent; + color: black; + line-height: 18px; +} +.hs-site-footer { + font-size: 50%; + color: #888; +} +body { + font-family: Arial, sans-serif; + font-size: 16px; +} +.hs-indent { + margin-left: 5px; + margin-right: 5px; +} +/*# sourceMappingURL=hsDoc.css.map */ \ No newline at end of file diff --git a/docs/hsDoc.js b/docs/hsDoc.js new file mode 100644 index 0000000..4503fad --- /dev/null +++ b/docs/hsDoc.js @@ -0,0 +1,12128 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 27); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__view_PillaredLayouter__ = __webpack_require__(29); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__view_TileLayouter__ = __webpack_require__(30); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__view_Layout__ = __webpack_require__(31); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Layout", function() { return __WEBPACK_IMPORTED_MODULE_2__view_Layout__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__view_Tokens__ = __webpack_require__(5); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "FILL", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["b"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "px", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["g"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "pc", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["f"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "LayoutToken", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["d"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__view_Layouter__ = __webpack_require__(4); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Layouter", function() { return __WEBPACK_IMPORTED_MODULE_4__view_Layouter__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__hsConfig__ = __webpack_require__(44); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "HsConfig", function() { return __WEBPACK_IMPORTED_MODULE_5__hsConfig__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__mithril__ = __webpack_require__(11); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "m", function() { return __WEBPACK_IMPORTED_MODULE_6__mithril__["a"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "o", function() { return __WEBPACK_IMPORTED_MODULE_6__mithril__["b"]; }); + +if (__WEBPACK_IMPORTED_MODULE_0__view_PillaredLayouter__) { } + +if (__WEBPACK_IMPORTED_MODULE_1__view_TileLayouter__) { } + + + + + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxLQUFLLE9BQU8sTUFBVSx5QkFBeUIsQ0FBQztBQUFNLElBQUcsT0FBTyxFQUFFLEdBQUU7QUFDM0UsT0FBTyxLQUFLLEtBQUssTUFBWSxxQkFBcUIsQ0FBQztBQUFVLElBQUcsS0FBSyxFQUFFLEdBQUU7QUFFekUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFTLGVBQWUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQ1osV0FBVyxFQUFFLE1BQU8sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBVSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVUsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxDQUFDLEVBQVMsQ0FBQyxFQUFFLE1BQU8sV0FBVyxDQUFBIn0= + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["d"] = round; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return TextHAlign; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return TextVAlign; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); + +function round(num) { + const result = num.toFixed(1); + if (result === 'Infinity') { + return '1e20'; + } + return result; +} +var TextHAlign; +(function (TextHAlign) { + TextHAlign["start"] = "start"; + TextHAlign["middle"] = "middle"; + TextHAlign["end"] = "end"; +})(TextHAlign || (TextHAlign = {})); +var TextVAlign; +(function (TextVAlign) { + TextVAlign["top"] = "top"; + TextVAlign["center"] = "center"; + TextVAlign["bottom"] = "bottom"; +})(TextVAlign || (TextVAlign = {})); +class SVGElem { + text(cfg, text) { + let yShift = 0; + let hAlign = cfg.xpos; + switch (cfg.xpos) { + case TextHAlign.start: break; + case TextHAlign.end: break; + case TextHAlign.middle: + default: + hAlign = TextHAlign.middle; + break; + } + switch (cfg.ypos) { + case TextVAlign.top: + yShift = 0.7; + break; + case TextVAlign.center: + yShift = 0.35; + break; + case TextVAlign.bottom: + default: + yShift = 0; + break; + } + const param = { + x: cfg.x || '', + y: cfg.y || '', + dx: round(cfg.hOffset || 0) + 'em', + dy: round((cfg.vOffset || 0) + yShift) + 'em', + style: `text-anchor:${hAlign}; ${cfg.style || ''}`, + class: cfg.cssClass, + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('text', param, text); + } + rect(tl, area, style, title) { + if (area.w < 0) { + tl.x += area.w; + area.w = -area.w; + } + if (area.h < 0) { + tl.y += area.h; + area.h = -area.h; + } + const param = { + x: round(tl.x), y: round(tl.y), + width: round(area.w) + (area.wunit || ''), + height: round(area.h) + (area.hunit || ''), + style: style + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('rect', param), Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title); + } + circle(c, r, style, title) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('circle', { cx: round(c.x), cy: round(c.y), r: round(r), style: style }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); + } + clipRect(tl, area, id) { + const param = { + x: round(tl.x), y: round(tl.y), + width: round(area.w) + (area.wunit || ''), + height: round(area.h) + (area.hunit || '') + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('defs', Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('clipPath', { id: id }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('rect', param))); + } + line(x0, x1, y0, y1, cssClass) { + const param = { + x1: round(x0), y1: round(y0), + x2: round(x1), y2: round(y1), + class: cssClass + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); + } + horLine(x0, x1, y, cssClass) { + const param = { + x1: round(x0), y1: round(y), + x2: round(x1), y2: round(y), + class: cssClass + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); + } + verLine(x, y0, y1, cssClass) { + const param = { + x1: round(x), y1: round(y0), + x2: round(x), y2: round(y1), + class: cssClass + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); + } + polyline(data, x, y, scales, id, style, title) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polyline', { + 'clip-path': id ? `url(#${id})` : undefined, + style: style, + points: data.map((row) => `${round(scales.x.convert(row[x]))},${round(scales.y.convert(row[y]))}`).join(' ') + }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); + } + polygon(dataFore, dataBack, x, yFore, yBack, scales, id, style, title) { + const indexed = (x === undefined); + const sx = (_x) => round(scales.x.convert(_x)); + const sy = (_y) => round(scales.y.convert(_y)); + const clip = id ? `url(#${id})` : undefined; + const points = dataFore.map((row, i) => `${sx(indexed ? i : row[x])},${sy(row[yFore])}`) + .concat(dataBack.map((row, i) => `${sx(indexed ? (dataBack.length - i - 1) : row[x])},${sy(yBack ? row[yBack] : 0)}`)).join(' '); + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polygon', { 'clip-path': clip, style: style, points: points }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); + } + shape(points, id, style, title) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polyline', { + 'clip-path': id ? `url(#${id})` : undefined, + style: style, + points: points.map((row) => `${round(row[0])},${round(row[1])}`).join(' ') + }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = SVGElem; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU1ZHRWxlbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9TVkdFbGVtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxDQUFDLEVBQVMsTUFBTSxVQUFVLENBQUM7QUF3RXBDLE1BQU0sZ0JBQWlCLEdBQVU7SUFDN0IsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QixJQUFJLE1BQU0sS0FBSyxVQUFVLEVBQUU7UUFDdkIsT0FBTyxNQUFNLENBQUM7S0FDakI7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNsQixDQUFDO0FBRUQsTUFBTSxDQUFOLElBQVksVUFJWDtBQUpELFdBQVksVUFBVTtJQUNsQiw2QkFBaUIsQ0FBQTtJQUNqQiwrQkFBa0IsQ0FBQTtJQUNsQix5QkFBZSxDQUFBO0FBQ25CLENBQUMsRUFKVyxVQUFVLEtBQVYsVUFBVSxRQUlyQjtBQUVELE1BQU0sQ0FBTixJQUFZLFVBSVg7QUFKRCxXQUFZLFVBQVU7SUFDbEIseUJBQWUsQ0FBQTtJQUNmLCtCQUFrQixDQUFBO0lBQ2xCLCtCQUFrQixDQUFBO0FBQ3RCLENBQUMsRUFKVyxVQUFVLEtBQVYsVUFBVSxRQUlyQjtBQUVELE1BQU07SUFNRixJQUFJLENBQUMsR0FBWSxFQUFFLElBQVc7UUFDMUIsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ2YsSUFBSSxNQUFNLEdBQWMsR0FBRyxDQUFDLElBQUksQ0FBQztRQUNqQyxRQUFPLEdBQUcsQ0FBQyxJQUFJLEVBQUU7WUFDYixLQUFLLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBRSxNQUFNO1lBQzlCLEtBQUssVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFJLE1BQU07WUFDOUIsS0FBSyxVQUFVLENBQUMsTUFBTSxDQUFDO1lBQ3ZCO2dCQUFlLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDO2dCQUFDLE1BQU07U0FDcEQ7UUFDRCxRQUFPLEdB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 + +/***/ }), +/* 2 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__TimedPromise__ = __webpack_require__(58); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return __WEBPACK_IMPORTED_MODULE_0__TimedPromise__["b"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return __WEBPACK_IMPORTED_MODULE_0__TimedPromise__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__showdown__ = __webpack_require__(59); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "markDown", function() { return __WEBPACK_IMPORTED_MODULE_1__showdown__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Checksum__ = __webpack_require__(60); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "shortCheckSum", function() { return __WEBPACK_IMPORTED_MODULE_2__Checksum__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Date__ = __webpack_require__(61); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "date", function() { return __WEBPACK_IMPORTED_MODULE_3__Date__["a"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ms", function() { return __WEBPACK_IMPORTED_MODULE_3__Date__["b"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Number__ = __webpack_require__(62); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "round", function() { return __WEBPACK_IMPORTED_MODULE_4__Number__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__PacingQueue__ = __webpack_require__(63); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "PacingQueue", function() { return __WEBPACK_IMPORTED_MODULE_5__PacingQueue__["a"]; }); + + + + + + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVksWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTyxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsTUFBWSxRQUFRLENBQUM7QUFDeEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFlLFVBQVUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQVMsZUFBZSxDQUFDIn0= + +/***/ }), +/* 3 */ +/***/ (function(module, exports) { + +var g; + +// This works in non-strict mode +g = (function() { + return this; +})(); + +try { + // This works if eval is allowed (see CSP) + g = g || Function("return this")() || (1,eval)("this"); +} catch(e) { + // This works if the window reference is available + if(typeof window === "object") + g = window; +} + +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} + +module.exports = g; + + +/***/ }), +/* 4 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Tokens__ = __webpack_require__(5); + +class Layouter { + constructor(areaDesc) { + this.areaDesc = areaDesc; + this.spacing = 0; + } + static translate(params) { + if (params.length === 0) { + params.push(''); + } + return params.map((param) => { + if (typeof param === 'string') { + if (param.endsWith('px')) { + return Object(__WEBPACK_IMPORTED_MODULE_0__Tokens__["g" /* px */])(parseInt(param)); + } + if (param.endsWith('%')) { + return Object(__WEBPACK_IMPORTED_MODULE_0__Tokens__["f" /* pc */])(parseInt(param)); + } + if (param.toLowerCase() === 'fill') { + return __WEBPACK_IMPORTED_MODULE_0__Tokens__["b" /* FILL */]; + } + } + else { + return param; + } + }); + } + static register(keyword, style) { + Layouter.layoutStyles[keyword] = style; + } + static createLayout(attrs, components) { + let css = ''; + Object.keys(Layouter.layoutStyles).some(key => { + if (attrs[key]) { + css = new Layouter.layoutStyles[key](Layouter.translate(attrs[key])).getStyles(components); + attrs[key] = undefined; + return true; + } + return false; + }); + return css; + } + ; +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Layouter; + +Layouter.layoutStyles = {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5b3V0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdmlldy9MYXlvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFhQSxPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxVQUFVLENBQUM7QUF5QnhDLE1BQU07SUF5RUYsWUFBbUIsUUFBc0I7UUFBdEIsYUFBUSxHQUFSLFFBQVEsQ0FBYztRQVJ6QyxZQUFPLEdBQUcsQ0FBQyxDQUFDO0lBUWdDLENBQUM7SUF6RHJDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBd0I7UUFDN0MsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7U0FBRTtRQUM3QyxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFnQixFQUFFLEVBQUU7WUFDbkMsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUU7Z0JBQzNCLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRTtvQkFBRSxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFBRTtnQkFDekQsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO29CQUFFLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO2lCQUFFO2dCQUN4RCxJQUFJLEtBQUssQ0FBQyxXQUFXLEVBQUUsS0FBRyxNQUFNLEVBQUU7b0JBQUUsT0FBTyxJQUFJLENBQUM7aUJBQUM7YUFDcEQ7aUJBQU07Z0JBQ0gsT0FBTyxLQUFLLENBQUM7YUFDaEI7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFXTSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQWMsRUFBRSxLQUFxQjtRQUV4RCxRQUFRLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUMzQyxDQUFDO0lBVU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxLQUFTLEVBQUUsVUFBdUI7UUFDekQsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBQ2IsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQzFDLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUNaLEdBQUcsR0FBRyxJQUFJLFFBQVEsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDM0YsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsQ0FBQztnQkFDdkIsT0FBTyxJQUFJLENBQUM7YUFDZjtZQUNELE9BQU8sS0FBSyxDQUFDO1FBQ2pCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0lBVzRDLENBQUM7O0FBcEV2QyxxQkFBWSxHQUF1QixFQUFFLENBQUMifQ== + +/***/ }), +/* 5 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["g"] = px; +/* harmony export (immutable) */ __webpack_exports__["f"] = pc; +class LayoutToken { + constructor(size) { + this.size = size; + } + getSize() { return this.size; } +} +/* harmony export (immutable) */ __webpack_exports__["d"] = LayoutToken; + +class DefinedToken extends LayoutToken { + constructor(size) { super(size); } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = DefinedToken; + +class FillToken extends LayoutToken { + constructor() { super(-1); } +} +/* harmony export (immutable) */ __webpack_exports__["c"] = FillToken; + +class PixelToken extends DefinedToken { + constructor(size) { super(size); } +} +/* harmony export (immutable) */ __webpack_exports__["e"] = PixelToken; + +class PercentToken extends DefinedToken { + constructor(size) { super(size); } +} +/* unused harmony export PercentToken */ + +function px(px) { return new PixelToken(px); } +function pc(pc) { return new PercentToken(pc); } +const FILL = new FillToken(); +/* harmony export (immutable) */ __webpack_exports__["b"] = FILL; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9rZW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvVG9rZW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE1BQU07SUFDRixZQUFvQixJQUFZO1FBQVosU0FBSSxHQUFKLElBQUksQ0FBUTtJQUFHLENBQUM7SUFDN0IsT0FBTyxLQUFLLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Q0FDekM7QUFLRCxNQUFNLG1CQUE2QixTQUFRLFdBQVc7SUFDbEQsWUFBWSxJQUFZLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUM3QztBQUtELE1BQU0sZ0JBQWlCLFNBQVEsV0FBVztJQUN0QyxnQkFBZ0IsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0NBQy9CO0FBS0QsTUFBTSxpQkFBa0IsU0FBUSxZQUFZO0lBQ3hDLFlBQVksSUFBVyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Q0FDNUM7QUFLRCxNQUFNLG1CQUFvQixTQUFRLFlBQVk7SUFDMUMsWUFBWSxJQUFXLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUM1QztBQU1ELE1BQU0sYUFBYSxFQUFTLElBQU0sT0FBTyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFNOUQsTUFBTSxhQUFhLEVBQVMsSUFBTSxPQUFPLElBQUksWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUtoRSxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQyJ9 + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); + +const FILE = './data/index.json'; +class DocSets { + static add(content) { + const lib = content.name; + DocSets.gList.set.push(lib); + DocSets.gList.set.sort(); + DocSets.gList.index[lib] = {}; + recursiveIndex(content, DocSets.gList.index[lib], lib); + } + static loadList(file) { + file = file || FILE; + return DocSets.loadIndexSet(file); + } + static get(lib, id = 0) { + if (lib) { + if (DocSets.gList.index[lib]) { + return DocSets.gList.index[lib][id + '']; + } + else { + return DocSets.gList.set; + } + } + else { + return DocSets.gList.set; + } + } + static loadIndexSet(file) { + return __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].request({ method: "GET", url: file }) + .then((result) => { + DocSets.gTitle = result.title; + let i = file.lastIndexOf('/'); + const dir = file.substring(0, i + 1); + return Promise.all(result.docs.map((f) => loadDocSet(dir, f))); + }) + .catch(console.log); + } + static title() { return DocSets.gTitle; } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = DocSets; + +DocSets.gList = { set: [], index: {} }; +; +function loadDocSet(dir, file) { + return __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].request({ method: "GET", url: dir + file }) + .then((r) => { + DocSets.add(r); + }) + .catch(console.log); +} +function recursiveIndex(content, index, lib, path = '') { + function getNewPath(content) { + content.name = content.name.replace(/["'](.+)["']|(.+)/g, "$1$2"); + const elName = content.name.match(/([^\/]+)$/)[1]; + content.name = elName; + return content.fullPath = (path === '') ? elName : `${path}.${elName}`; + } + function markIfModule(content) { + if (content.comment && content.comment.tags) { + content.comment.tags.forEach((tag) => { + if (tag.tag === 'module') { + content.innerModule = tag.text.trim(); + } + }); + } + } + content.lib = lib; + if (typeof content === 'object' && content.name) { + const newPath = getNewPath(content); + markIfModule(content); + index[content.id + ''] = content; + if (newPath.length > 0) { + index[newPath] = content; + } + if (content.children) { + content.children.map((c) => recursiveIndex(c, index, lib, newPath)); + } + if (content.signatures) { + content.signatures.map((c) => recursiveIndex(c, index, lib, newPath)); + } + if (content.parameters) { + content.parameters.map((c) => recursiveIndex(c, index, lib, newPath)); + } + if (content.type && content.type.declaration && content.type.declaration.children) { + content.type.declaration.children.map((c) => recursiveIndex(c, index, lib, newPath)); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG9jU2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9Eb2NTZXRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVNBLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBUyxVQUFVLENBQUM7QUFNaEMsTUFBTSxJQUFJLEdBQVUsbUJBQW1CLENBQUM7QUFPeEMsTUFBTTtJQU1LLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBVztRQUN6QixNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDO1FBQ3pCLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN6QixPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDOUIsY0FBYyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBT00sTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFZO1FBQy9CLElBQUksR0FBRyxJQUFJLElBQUksSUFBSSxDQUFDO1FBRXBCLE9BQU8sT0FBTyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBU00sTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFXLEVBQUUsS0FBaUIsQ0FBQztRQUM3QyxJQUFJLEdBQUcsRUFBRTtZQUNMLElBQUksT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7Z0JBQzFCLE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFDLEVBQUUsQ0FBQyxDQUFDO2FBQzFDO2lCQUFNO2dCQUNILE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FB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 + +/***/ }), +/* 7 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Menu__ = __webpack_require__(46); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Menu", function() { return __WEBPACK_IMPORTED_MODULE_0__Menu__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Button__ = __webpack_require__(47); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Button", function() { return __WEBPACK_IMPORTED_MODULE_1__Button__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__RadioButton__ = __webpack_require__(17); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return __WEBPACK_IMPORTED_MODULE_2__RadioButton__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__ToggleButton__ = __webpack_require__(18); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ToggleButton", function() { return __WEBPACK_IMPORTED_MODULE_3__ToggleButton__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__CornerButton__ = __webpack_require__(19); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "CornerButton", function() { return __WEBPACK_IMPORTED_MODULE_4__CornerButton__["b"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ButtonSymbols", function() { return __WEBPACK_IMPORTED_MODULE_4__CornerButton__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__AddRemove__ = __webpack_require__(48); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "AddButton", function() { return __WEBPACK_IMPORTED_MODULE_5__AddRemove__["a"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "RemoveButton", function() { return __WEBPACK_IMPORTED_MODULE_5__AddRemove__["b"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Collapsible__ = __webpack_require__(49); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Collapsible", function() { return __WEBPACK_IMPORTED_MODULE_6__Collapsible__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Modal__ = __webpack_require__(50); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Modal", function() { return __WEBPACK_IMPORTED_MODULE_7__Modal__["a"]; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__TypeAhead__ = __webpack_require__(51); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "TypeAhead", function() { return __WEBPACK_IMPORTED_MODULE_8__TypeAhead__["a"]; }); + + + + + + + + + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFjLFFBQVEsQ0FBQztBQUV0QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQVksVUFBVSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTyxlQUFlLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxZQUFZLEVBQ1osYUFBYSxFQUNiLE1BQW9CLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxTQUFTLEVBQ1QsWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTyxlQUFlLENBQUM7QUFDN0MsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFhLFNBQVMsQ0FBQztBQUN2QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQVMsYUFBYSxDQUFDIn0= + +/***/ }), +/* 8 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["b"] = oneOfItems; +/* unused harmony export anyItems */ +/* unused harmony export selectable */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); + +function oneOfItems(items, title) { + Object.keys(this.items).forEach((key) => { + this.items[key].isSelected = (key === title); + }); +} +function anyItems(items, title) { + this.items[title].isSelected = !this.items[title].isSelected; +} +class Selector { + constructor() { + this.updateSelected = [oneOfItems, anyItems][0]; + this.items = {}; + } + init(desc, updateSelected = oneOfItems) { + this.updateSelected = updateSelected.bind(this); + desc.items = desc.items || []; + desc.changed = desc.changed || ((item) => console.log(`missing changed() function for menu item ${item}`)); + this.checkSelectedItem(desc); + return desc; + } + ; + checkSelectedItem(desc) { + if (this.selectedItem === undefined) { + if (typeof desc.defaultItem === 'number') { + this.selectedItem = desc.items[desc.defaultItem % desc.items.length]; + } + else { + this.selectedItem = desc.defaultItem || desc.items[0]; + } + } + } + internalStateUpdate(desc, item) { + this.selectedItem = item; + this.checkSelectedItem(desc); + this.updateSelected(this.items, this.selectedItem); + } + renderItem(desc, i) { + const reactor = (callback) => (item) => { + this.internalStateUpdate(desc, item); + if (typeof callback === 'function') { + callback(item); + } + }; + const l = desc.items[i] || ''; + const itemCss = desc.itemCss || []; + this.checkSelectedItem(desc); + return selectable({ + title: l, + css: itemCss[i], + isSelected: this.selectedItem ? (l.toLowerCase() === this.selectedItem.toLowerCase()) : false, + mouseDown: reactor(desc.mouseDown), + mouseUp: reactor(desc.mouseUp), + clicked: reactor(desc.changed) + }); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Selector; + +; +function selectable(childDesc) { + const css = childDesc.css || ''; + const cssSelected = `${childDesc.isSelected ? 'hs-selected' : ''}`; + const onclick = childDesc.clicked ? () => { childDesc.clicked(childDesc.title); } : undefined; + const onmousedown = childDesc.mouseDown ? () => { childDesc.mouseDown(childDesc.title); } : undefined; + const onmouseup = childDesc.mouseUp ? () => { childDesc.mouseUp(childDesc.title); } : undefined; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`.hs-selectable ${css} ${cssSelected}`, { style: childDesc.style, onclick: onclick, onmousedown: onmousedown, onmouseup: onmouseup }, childDesc.title); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VsZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvU2VsZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBcUJBLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxVQUFVLENBQUM7QUEwQzdCLE1BQU0scUJBQXFCLEtBQTZCLEVBQUUsS0FBWTtJQUNsRSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFVLEVBQUUsRUFBRTtRQUMzQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsR0FBRyxDQUFDLEdBQUcsS0FBRyxLQUFLLENBQUMsQ0FBQztJQUMvQyxDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUFNRCxNQUFNLG1CQUFtQixLQUE2QixFQUFFLEtBQVk7SUFDaEUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxVQUFVLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLFVBQVUsQ0FBQztBQUNqRSxDQUFDO0FBTUQsTUFBTTtJQUFOO1FBT1ksbUJBQWMsR0FBWSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUtwRCxVQUFLLEdBQTRCLEVBQUUsQ0FBQztJQStDaEQsQ0FBQztJQTdDRyxJQUFJLENBQUMsSUFBaUIsRUFBRSxpQkFBMEIsVUFBVTtRQUN4RCxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEQsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLElBQVcsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0Q0FBNEMsSUFB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 + +/***/ }), +/* 9 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); + +; + +function getCrossAt(cross, scale) { + let crossesAt; + switch (cross) { + case 'min': + crossesAt = scale.domain()[0]; + break; + case 'max': + crossesAt = scale.domain()[1]; + break; + default: crossesAt = cross || 0; + } + return scale.convert(crossesAt); +} +class Axes extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { + static defaultConfig(cfg) { + function scaleCfg() { + return { + type: Axes.type.linear, + domain: ['auto', 'auto'] + }; + } + function labelCfg(primary, x, major) { + return { + visible: major, text: '', + xpos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].end : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].start), + ypos: x ? (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].bottom) : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].center, + hOffset: x ? 0 : (primary ? -0.7 : 0.7), + vOffset: x ? (primary ? 0.7 : -0.7) : 0 + }; + } + function markCfg(primary, major) { + return { + visible: major, + length: (primary ? 1 : -1) * (major ? 10 : 5) + }; + } + function titleCfg(primary, x) { + return { + visible: true, text: (x ? 'x' : 'y') + (primary ? '' : '2'), + xpos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].end : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].start), + ypos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].bottom : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top), + hOffset: x ? -2 : (primary ? 0 : 0.3), + vOffset: x ? (primary ? 0.4 : -1.2) : (primary ? -0.5 : 0.7) + }; + } + function axisCfg(primary, x) { + return { + visible: primary ? true : false, + crossesAt: primary ? 'min' : 'max', + scale: scaleCfg(), + title: titleCfg(primary, x), + ticks: { + major: { + marks: markCfg(primary, true), + labels: labelCfg(primary, x, true), + labelFmt: undefined + }, + minor: { + marks: markCfg(primary, false), + labels: labelCfg(primary, x, false), + labelFmt: undefined + } + } + }; + } + cfg.axes = { + primary: { + x: axisCfg(true, true), + y: axisCfg(true, false) + }, + secondary: { + x: axisCfg(false, true), + y: axisCfg(false, false) + } + }; + } + static adjustConfig(cfg) { + } + drawAxisLine(x, range, cross) { + return x ? this.horLine(range[0], range[1], cross, 'hs-graph-axis-line') : + this.verLine(cross, range[0], range[1], 'hs-graph-axis-line'); + } + drawTitle(x, ttlCfg, type, range, cross) { + ttlCfg.cssClass = 'hs-graph-axis-title'; + const xy = { transform: `translate(${x ? range[1] : cross}, ${x ? cross : range[1]})` }; + return !ttlCfg.visible ? undefined : + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('g', xy, this.text(ttlCfg, ttlCfg.text)); + } + drawTickMarks(x, type, crossesAt, scale, ticks, cfg) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${type}-tick-marks` }, !cfg.marks.visible ? '' : ticks.marks.map((t) => { + return x ? this.verLine(scale.convert(t), crossesAt, crossesAt + cfg.marks.length) : + this.horLine(crossesAt, crossesAt - cfg.marks.length, scale.convert(t)); + })); + } + drawTickLabels(x, type, crossesAt, scale, ticks, cfg) { + scale.setLabelFormat(cfg.labelFmt); + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${type}-tick-label` }, !cfg.labels.visible ? '' : ticks.labels.map((t) => { + const v = scale.convert(t.pos); + const xy = { transform: `translate(${x ? v : crossesAt}, ${x ? crossesAt : v})` }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('g', xy, this.text(cfg.labels, t.text)); + })); + } + drawAxis(dir, scales, type, axisCfg) { + const x = dir === 'x'; + const range = scales[dir].range(); + const cfg = axisCfg[type][dir]; + scales[dir].scaleType(cfg.scale.type); + const crossesAt = getCrossAt(cfg.crossesAt, scales[x ? 'y' : 'x']); + const ticks = scales[dir].ticks(); + return !cfg.visible ? undefined : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${dir} hs-graph-axis-${type}` }, [ + this.drawAxisLine(x, range, crossesAt), + this.drawTitle(x, cfg.title, type, range, crossesAt), + this.drawTickMarks(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor), + this.drawTickMarks(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major), + this.drawTickLabels(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor), + this.drawTickLabels(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major) + ]); + } + view(node) { + const cfg = node.attrs.cfg; + const scales = node.attrs.scales; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-axis' }, [ + this.drawAxis('x', scales.primary, 'primary', cfg), + this.drawAxis('y', scales.primary, 'primary', cfg), + this.drawAxis('x', scales.secondary, 'secondary', cfg), + this.drawAxis('y', scales.secondary, 'secondary', cfg) + ]); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Axes; + +Axes.type = { + linear: 'linear axis', + log: 'log axis', + date: 'date axis', + index: 'index axis', + percent: 'percent axis', + ordinal: 'ordinal axis', + nominal: 'nominal axis' +}; +class ExampleLinearAxis { +} +class ExampleLogAxis { +} +class ExampleDateAxis { +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXhlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9BeGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZEQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQU8sVUFBVSxDQUFDO0FBVXBDLENBQUM7QUFLRCxPQUFPLEVBQUUsT0FBTyxFQUNQLFVBQVUsRUFDVixVQUFVLEVBQ0osTUFBVSxXQUFXLENBQUM7QUFRckMsb0JBQW9CLEtBQW1CLEVBQUUsS0FBVztJQUNoRCxJQUFJLFNBQWdCLENBQUM7SUFDckIsUUFBUSxLQUFLLEVBQUU7UUFDWCxLQUFLLEtBQUs7WUFBRSxTQUFTLEdBQVcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTTtRQUN6RCxLQUFLLEtBQUs7WUFBRSxTQUFTLEdBQVcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTTtRQUN6RCxPQUFPLENBQUMsQ0FBSSxTQUFTLEdBQVcsS0FBSyxJQUFJLENBQUMsQ0FBQztLQUM5QztJQUNELE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUNwQyxDQUFDO0FBRUQsTUFBTSxXQUFZLFNBQVEsT0FBTztJQWtHN0IsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFVO1FBQzNCO1lBQ0ksT0FBTztnQkFDSCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO2dCQUN0QixNQUFNLEVBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDO2FBQ2xDLENBQUM7UUFDTixDQUFDO1FBQ0Qsa0JBQWtCLE9BQWUsRUFBRSxDQUFTLEVBQUUsS0FBYTtZQUN2RCxPQUFPO2dCQUNILE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7Z0JBQ3hCLElBQUksRUFBRSxDQUFDLENBQUEsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FB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 + +/***/ }), +/* 10 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Series__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_hsutil__ = __webpack_require__(2); + + + + +class Plot extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { + drawLine(clipID, data, x, y, scales, sStyle, title) { + const style = `stroke: ${sStyle.line.color}; stroke-width:${sStyle.line.width};`; + return !sStyle.line.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-line', '') : this.polyline(data, x, y, scales, clipID, style, title); + } + drawMarker(clipID, data, x, y, scales, sStyle, title) { + const mrk = __WEBPACK_IMPORTED_MODULE_2__Series__["a" /* Series */].marker; + let style = `fill:${sStyle.marker.color}`; + return !sStyle.marker.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-marker', '') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series-markers' }, data.map((p) => { + const cx = scales.x.convert(p[x]); + const cy = scales.y.convert(p[y]); + const r = sStyle.marker.size; + switch (sStyle.marker.shape) { + case mrk.circle: + return this.circle({ x: cx, y: cy }, r, style, title); + case mrk.square: + return this.rect({ x: cx - r, y: cy - r }, { w: 2 * r, h: 2 * r }, style, title); + case mrk.diamond: + return this.shape([[cx - r, cy], [cx, cy + r], [cx + r, cy], [cx, cy - r]], undefined, style, title); + case mrk.upTriangle: + return this.shape([[cx - r, cy + r], [cx + r, cy + r], [cx, cy - r]], undefined, style, title); + case mrk.downTriangle: + return this.shape([[cx - r, cy - r], [cx + r, cy - r], [cx, cy + r]], undefined, style, title); + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`.unkown-marker-${sStyle.marker.shape}`, ''); + })); + } + drawLabel(clipID, data, x, y, lbl, scales, sDef) { + const sStyle = sDef.style; + const cfg = { + text: '', + cssClass: ``, + style: `fill:${sStyle.label.color}`, + xpos: __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle, + ypos: __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].center, + hOffset: sDef.hOffset, + vOffset: sDef.vOffset + }; + return !sStyle.marker.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-marker', '') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series-labels' }, data.map((p) => { + cfg.x = '' + scales.x.convert(p[x]); + cfg.y = '' + scales.y.convert(p[y]); + return this.text(cfg, Object(__WEBPACK_IMPORTED_MODULE_3_hsutil__["round"])(p[lbl], 3)); + })); + } + drawArea(clipID, data, x, yFore, yBack, scales, sStyle, title) { + if (sStyle.fill.visible) { + const style = `fill: ${sStyle.fill.color};`; + const drawFore = data; + const drawBack = data.slice().reverse(); + return this.polygon(drawFore, drawBack, x, yFore, yBack, scales, clipID, style, title); + } + else { + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-line', ''); + } + } + setDefaults(data, series, scales) { + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Plot; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxvdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9QbG90LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sRUFBRSxDQUFDLEVBQVEsTUFBVyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLE9BQU8sRUFFUCxVQUFVLEVBQ1YsVUFBVSxFQUFFLE1BQVEsV0FBVyxDQUFDO0FBSXpDLE9BQU8sRUFBRSxNQUFNLEVBRUssTUFBUyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFhLFFBQVEsQ0FBQztBQUV0QyxNQUFNLFdBQXFCLFNBQVEsT0FBTztJQUN0QyxRQUFRLENBQUMsTUFBYSxFQUFFLElBQWMsRUFBRSxDQUFRLEVBQUUsQ0FBUSxFQUFFLE1BQWMsRUFBRSxNQUFrQixFQUFFLEtBQWE7UUFDekcsTUFBTSxLQUFLLEdBQUcsV0FBVyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssa0JBQWtCLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUM7UUFDakYsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDbkgsQ0FBQztJQUVELFVBQVUsQ0FBQyxNQUFhLEVBQUUsSUFBYyxFQUFFLENBQVEsRUFBRSxDQUFRLEVBQUUsTUFBYyxFQUFFLE1BQWtCLEVBQUUsS0FBYTtRQUMzRyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzFCLElBQUksS0FBSyxHQUFHLFFBQVEsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMxQyxPQUFPLENBQUMsTUFBTSxD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 + +/***/ }), +/* 11 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return o; }); +if (!global['window']) { + console.log('creating non-browser polyfill'); + global['window'] = __webpack_require__(32)(); + global['document'] = window.document; +} +const m = __webpack_require__(38); +/* harmony export (immutable) */ __webpack_exports__["a"] = m; + +const o = __webpack_require__(39); +o.root = window.document.createElement("div"); + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWl0aHJpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taXRocmlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEVBQUU7SUFDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO0lBRTdDLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxPQUFPLENBQUMsbUNBQW1DLENBQUMsRUFBRSxDQUFDO0lBQ2xFLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDO0NBRXhDO0FBS0QsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQU9wQyxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUN6QyxDQUFDLENBQUMsSUFBSSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBRTlDLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyJ9 +/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(3))) + +/***/ }), +/* 12 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Axes__ = __webpack_require__(9); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__PlotLine__ = __webpack_require__(68); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__PlotMarkers__ = __webpack_require__(69); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__PlotBar__ = __webpack_require__(70); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__PlotArea__ = __webpack_require__(71); + + + + + + + +function copyDefault(target, source, defaults) { + Object.keys(source).forEach((key) => { + if (typeof source[key] === 'object') { + if (target[key] === undefined) { + target[key] = {}; + } + copyDefault(target[key], source[key], defaults); + } + else { + if (target[key] === undefined) { + target[key] = source[key]; + } + if (target[key] === 'default') { + target[key] = defaults[key]; + } + } + }); +} +class Series extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { + static defaultConfig(cfg) { + cfg.series = new SeriesConfig(); + } + static adjustConfig(cfg) { + cfg.series.series.forEach((s) => { + if (s.x === undefined) { + cfg.axes.primary.x.title.hOffset = 0; + cfg.axes.primary.x.scale.type = __WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */].type.index; + cfg.grid.minor.ver.visible = false; + } + }); + } + drawClipRect(clipID, scales) { + return !clipID ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('') : this.clipRect({ x: scales.x.range()[0], y: scales.y.range()[1] }, { + w: scales.x.range()[1] - scales.x.range()[0], + h: scales.y.range()[0] - scales.y.range()[1] + }, clipID); + } + view(node) { + const cfg = node.attrs.cfg; + const scales = node.attrs.scales.primary; + const data = node.attrs.data; + const clipID = cfg.clip ? 'hs' + Math.floor(Math.random() * 10000) : undefined; + cfg.series.map((s) => { + if (s.map === Series.map.shared) { + s.ySum = '$sum'; + data[s.dataIndex].colAdd(s.ySum); + data[s.dataIndex].colInitialize(s.ySum, 0); + } + }); + cfg.series.map((s) => { + const dt = data[s.dataIndex]; + if (s.map === Series.map.shared) { + const valCol = dt.colNumber(s.y); + dt.colInitialize(s.ySum, (v, i, row) => { return v + row[valCol]; }); + } + if (s.map) { + s.yBase = '$' + s.map; + dt.colAdd(s.yBase); + dt.colInitialize(s.yBase, 0); + } + }); + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series' }, [ + this.drawClipRect(clipID, scales), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', cfg.series.map((s, i) => { + const dt = data[s.dataIndex]; + const type = Series.plot[s.type] || Series.plot.line; + type.setDefaults(dt, s, scales); + const d = s.cond ? dt.filter(s.cond) : dt; + const plot = type.plot(d, s, scales, i, clipID); + if (s.map) { + const valCol = d.colNumber(s.y); + d.colInitialize(s.yBase, (v, i, row) => { return v + row[valCol]; }); + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-series-${i}` }, plot); + })) + ]); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Series; + +Series.marker = { + circle: Symbol('circle marker'), + square: Symbol('square marker'), + diamond: Symbol('diamond marker'), + upTriangle: Symbol('upward triangle marker'), + downTriangle: Symbol('downward triangle marker') +}; +Series.plot = { + line: new __WEBPACK_IMPORTED_MODULE_3__PlotLine__["a" /* PlotLine */](), + marker: new __WEBPACK_IMPORTED_MODULE_4__PlotMarkers__["a" /* PlotMarkers */](), + bar: new __WEBPACK_IMPORTED_MODULE_5__PlotBar__["a" /* PlotBar */](), + area: new __WEBPACK_IMPORTED_MODULE_6__PlotArea__["a" /* PlotArea */]() +}; +Series.map = { + stacked: 'stacked', + shared: 'shared' +}; +class SeriesConfig { + constructor() { + this.seriesDefs = []; + this.clip = true; + this.defaultStyle = { + line: { color: 'default', visible: true, width: 2 }, + marker: { color: 'default', visible: false, size: 10, shape: Series.marker.circle }, + label: { color: 'default', visible: false }, + fill: { color: 'default', visible: false }, + bar: { color: 'default', visible: false, width: 50, offset: 30 } + }; + this.defaultColors = ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f', '#000', '#444', '#888', '#ccc']; + } + set series(cfg) { + const defStyle = this.defaultStyle; + const defColors = this.defaultColors; + cfg.forEach((s) => { + s.type = s.type || 'line'; + s.style = s.style || {}; + s.dataIndex = s.dataIndex || 0; + const defaults = { + color: defColors[this.seriesDefs.length] + }; + copyDefault(s.style, defStyle, defaults); + this.seriesDefs.push(s); + switch (s.type) { + case 'line': + s.style.line.visible = true; + break; + case 'marker': + s.style.marker.visible = true; + break; + case 'area': + s.style.fill.visible = true; + break; + case 'bar': + s.style.fill.visible = true; + break; + } + }); + } + get series() { return this.seriesDefs; } +} +/* unused harmony export SeriesConfig */ + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VyaWVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL1Nlcmllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFvQkEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFXLFVBQVUsQ0FBQztBQU14QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQVcsV0FBVyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBYyxRQUFRLENBQUM7QUFFdEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFVLFlBQVksQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU8sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBVyxXQUFXLENBQUM7QUFDekMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFVLFlBQVksQ0FBQztBQUcxQyxxQkFBcUIsTUFBVSxFQUFFLE1BQVUsRUFBRSxRQUFZO0lBQ3JELE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBVSxFQUFFLEVBQUU7UUFDdkMsSUFBSSxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxRQUFRLEVBQUU7WUFDakMsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7YUFBRTtZQUNwRCxXQUFXLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztTQUNuRDthQUFNO1lBQ0gsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7YUFBRTtZQUM3RCxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxTQUFTLEVBQUU7Z0JBQUUsTUFBTSxD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 + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = function parseURL(url, root) { + var data = {} + var protocolIndex = url.indexOf("://") + var pathnameIndex = protocolIndex > -1 ? url.indexOf("/", protocolIndex + 3) : url.indexOf("/") + var searchIndex = url.indexOf("?") + var hashIndex = url.indexOf("#") + if ((pathnameIndex > searchIndex && searchIndex > -1) || (pathnameIndex > hashIndex && hashIndex > -1)) pathnameIndex = -1 + if (searchIndex > hashIndex && hashIndex > -1) searchIndex = -1 + var pathnameEnd = searchIndex > -1 ? searchIndex : hashIndex > -1 ? hashIndex : url.length + if (protocolIndex > -1) { + //it's a full URL + if (pathnameIndex < 0) pathnameIndex = url.length + var portIndex = url.indexOf(":", protocolIndex + 1) + if (portIndex < 0) portIndex = pathnameIndex + data.protocol = url.slice(0, protocolIndex + 1) + data.hostname = url.slice(protocolIndex + 3, portIndex) + data.port = url.slice(portIndex + 1, pathnameIndex) + data.pathname = url.slice(pathnameIndex, pathnameEnd) || "/" + } + else { + data.protocol = root.protocol + data.hostname = root.hostname + data.port = root.port + if (pathnameIndex === 0) { + //it's an absolute path + data.pathname = url.slice(pathnameIndex, pathnameEnd) || "/" + } + else if (searchIndex !== 0 && hashIndex !== 0) { + //it's a relative path + var slashIndex = root.pathname.lastIndexOf("/") + var path = slashIndex > -1 ? root.pathname.slice(0, slashIndex + 1) : "./" + var normalized = url.slice(0, pathnameEnd).replace(/^\.$/, root.pathname.slice(slashIndex + 1)).replace(/^\.\//, "") + var dotdot = /\/[^\/]+?\/\.{2}/g + var pathname = path + normalized + pathname = path + normalized + while (dotdot.test(pathname)) pathname = pathname.replace(dotdot, "") + pathname = pathname.replace(/\/\.\//g, "/").replace(/^(\/\.{2})+/, "") || "/" + data.pathname = pathname + } + } + var searchEnd = hashIndex > -1 ? hashIndex : url.length + data.search = searchIndex > -1 ? url.slice(searchIndex, searchEnd) : "" + data.hash = hashIndex > -1 ? url.slice(hashIndex) : "" + return data +} + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(setImmediate) { + +module.exports = typeof setImmediate === "function" ? setImmediate : setTimeout + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(15).setImmediate)) + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(global) {var apply = Function.prototype.apply; + +// DOM APIs, for completeness + +exports.setTimeout = function() { + return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); +}; +exports.setInterval = function() { + return new Timeout(apply.call(setInterval, window, arguments), clearInterval); +}; +exports.clearTimeout = +exports.clearInterval = function(timeout) { + if (timeout) { + timeout.close(); + } +}; + +function Timeout(id, clearFn) { + this._id = id; + this._clearFn = clearFn; +} +Timeout.prototype.unref = Timeout.prototype.ref = function() {}; +Timeout.prototype.close = function() { + this._clearFn.call(window, this._id); +}; + +// Does not start the time, just sets up the members needed. +exports.enroll = function(item, msecs) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = msecs; +}; + +exports.unenroll = function(item) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = -1; +}; + +exports._unrefActive = exports.active = function(item) { + clearTimeout(item._idleTimeoutId); + + var msecs = item._idleTimeout; + if (msecs >= 0) { + item._idleTimeoutId = setTimeout(function onTimeout() { + if (item._onTimeout) + item._onTimeout(); + }, msecs); + } +}; + +// setimmediate attaches itself to the global object +__webpack_require__(34); +// On some exotic environments, it's not clear which object `setimmeidate` was +// able to install onto. Search each possibility in the same order as the +// `setimmediate` library. +exports.setImmediate = (typeof self !== "undefined" && self.setImmediate) || + (typeof global !== "undefined" && global.setImmediate) || + (this && this.setImmediate); +exports.clearImmediate = (typeof self !== "undefined" && self.clearImmediate) || + (typeof global !== "undefined" && global.clearImmediate) || + (this && this.clearImmediate); + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }), +/* 16 */ +/***/ (function(module, exports) { + +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + + +/***/ }), +/* 17 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Selector__ = __webpack_require__(8); + + + + +class RadioButton extends __WEBPACK_IMPORTED_MODULE_1__Selector__["a" /* Selector */] { + viewGroup(css, node) { + const desc = this.init(node.attrs.desc, __WEBPACK_IMPORTED_MODULE_1__Selector__["b" /* oneOfItems */]); + node.attrs.desc = undefined; + css = `${css} ${node.attrs.css || ''}`; + const style = node.attrs.style || ''; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(css, { style: style }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_0_hslayout__["Layout"], { + columns: [], + content: desc.items.map((l, i) => this.renderItem(desc, i)) + })); + } + view(node) { return this.viewGroup('.hs-radio-buttons', node); } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = RadioButton; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmFkaW9CdXR0b24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvUmFkaW9CdXR0b24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBaUNBLE9BQU8sRUFBRSxDQUFDLEVBQVMsTUFBVSxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFZLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVUsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBUSxZQUFZLENBQUM7QUFvQjFDLE1BQU0sa0JBQW1CLFNBQVEsUUFBUTtJQUNyQyxTQUFTLENBQUMsR0FBVSxFQUFFLElBQVc7UUFDN0IsTUFBTSxJQUFJLEdBQWdCLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDakUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEdBQUcsU0FBUyxDQUFDO1FBQzVCLEdBQUcsR0FBRyxHQUFHLEdBQUcsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUN2QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7UUFFckMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUMsS0FBSyxFQUFDLEtBQUssRUFBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7WUFDbkMsT0FBTyxFQUFFLEVBQUU7WUFDWCxPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFRLEVBQUUsQ0FBUSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztTQUM1RSxDQUFDLENBQUMsQ0FBQztJQUNSLENBQUM7SUFDRCxJQUFJLENBQUMsSUFBVyxJQUFXLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Q0FDakYifQ== + +/***/ }), +/* 18 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Selector__ = __webpack_require__(8); + + + +class ToggleButton extends __WEBPACK_IMPORTED_MODULE_1__Selector__["a" /* Selector */] { + constructor() { + super(...arguments); + this.toggleIndex = -1; + this.mouseDown = ''; + } + view(node) { + const desc = this.init(node.attrs.desc, __WEBPACK_IMPORTED_MODULE_1__Selector__["b" /* oneOfItems */]); + node.attrs.desc = undefined; + const css = node.attrs.css || ''; + const style = node.attrs.style || ''; + const parentChanged = desc.changed; + desc.changed = ((item) => { + this.toggleIndex = (this.toggleIndex + 1) % desc.items.length; + item = desc.items[this.toggleIndex]; + this.internalStateUpdate(desc, item); + if (parentChanged) { + parentChanged(item); + } + }); + if (this.toggleIndex < 0) { + this.toggleIndex = 0; + } + desc.mouseDown = () => this.mouseDown = '.hs-button-pressed'; + desc.mouseUp = () => this.mouseDown = ''; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`.hs-toggle-button${css}${this.mouseDown}`, { style: style }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', this.renderItem(desc, this.toggleIndex))); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = ToggleButton; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9nZ2xlQnV0dG9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL1RvZ2dsZUJ1dHRvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFpQ0EsT0FBTyxFQUFFLENBQUMsRUFBUyxNQUFVLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVUsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBUSxZQUFZLENBQUM7QUFtQjFDLE1BQU0sbUJBQW9CLFNBQVEsUUFBUTtJQUExQzs7UUFDWSxnQkFBVyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ2pCLGNBQVMsR0FBRyxFQUFFLENBQUM7SUF5QjNCLENBQUM7SUF4QkcsSUFBSSxDQUFDLElBQVc7UUFDWixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3BELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLFNBQVMsQ0FBQztRQUM1QixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUM7UUFDakMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDO1FBR3JDLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDbkMsSUFBSSxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsSUFBVyxFQUFFLEVBQUU7WUFDNUIsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLEdBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7WUFDNUQsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ3BDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDckMsSUFBSSxhQUFhLEVBQUU7Z0JBQUUsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO2FBQUU7UUFDL0MsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLElBQUksQ0FBQyxXQUFXLEdBQUMsQ0FBQyxFQUFFO1lBQUUsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7U0FBRTtRQUVqRCxJQUFJLENBQUMsU0FBUyxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUcsb0JBQW9CLENBQUM7UUFDN0QsSUFBSSxDQUFDLE9BQU8sR0FBSyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQztRQUUzQyxPQUFPLENBQUMsQ0FBQyxvQkFBb0IsR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBQyxLQUFLLEVBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUN6RSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQzFDLENBQUMsQ0FBQztJQUNQLENBQUM7Q0FDSiJ9 + +/***/ }), +/* 19 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); + +const ButtonSymbols = { + cross: { sym: '×' }, + minus: { sym: '−' }, + plus: { sym: '+' }, + dLeft: { sym: '«' }, + dRight: { sym: '»' }, + left: { sym: '‹' }, + right: { sym: '›' }, + leftTri: { sym: '◂' }, + rightTri: { sym: '▸' }, + upTri: { sym: '▴' }, + downTri: { sym: '▾' }, + up: { sym: '∧' }, + down: { sym: '∨' }, + lArrow: { sym: '←' }, + rArrow: { sym: '→' }, + uArrow: { sym: '↑' }, + dArrow: { sym: '↓' }, + empty: { sym: '○' }, + emptySlash: { sym: '∅' }, + oSlash: { sym: 'ø' }, + o: { sym: 'ο' }, + lines3: { sym: '≡' }, + sum: { sym: 'Σ' }, + ellipsis: { sym: '…' }, + vertEllips: { sym: '⁝' }, + bullet: { sym: '•' }, + enter: { sym: '↵' }, + again: { sym: '↻' }, + start: { sym: '⇱' }, + end: { sym: '⇲' } +}; +/* harmony export (immutable) */ __webpack_exports__["a"] = ButtonSymbols; + +class CornerButton { + constructor(symbol = '-') { + this.symbol = symbol; + } + static getSymbol(name) { + return ButtonSymbols[name] ? ButtonSymbols[name].sym : ''; + } + view(node) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.hs-corner-button', { onclick: node.attrs.onclick }, __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].trust(node.attrs.symbol)); + } +} +/* harmony export (immutable) */ __webpack_exports__["b"] = CornerButton; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29ybmVyQnV0dG9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0Nvcm5lckJ1dHRvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUF1REEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFPLFVBQVUsQ0FBQztBQUVwQyxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUc7SUFDekIsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRTtJQUM5QixLQUFLLEVBQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLElBQUksRUFBUSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUM7SUFDdkIsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLElBQUksRUFBUSxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUM7SUFDOUIsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBQztJQUM5QixPQUFPLEVBQUssRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLFFBQVEsRUFBSSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUM7SUFDN0IsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixPQUFPLEVBQUssRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLEVBQUUsRUFBVSxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUM7SUFDM0IsSUFBSSxFQUFRLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBQztJQUMxQixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFDO0lBQzVCLE1BQU0sRUFBTSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUM7SUFDNUIsTUFBTSxFQUFNLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBQztJQUM1QixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFDO0lBQzVCLEtBQUssRUFBTyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUM7SUFDN0IsVUFBVSxFQUFFLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFDO0lBQzlCLENBQUMsRUFBVyxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUM7SUFDL0IsTUFBTSxFQUFNLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixHQUFHLEVBQVMsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLFFBQVEsRUFBSSxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUM7SUFDOUIsVUFBVSxFQUFFLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFDO0lBQzVCLEtBQUssRUFBTyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUM7SUFDN0IsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixLQUFLLEVBQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLEdBQUcsRUFBUyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUM7Q0FDaEMsQ0FBQztBQUVGLE1BQU07SUFDRixZQUFzQixTQUFPLEdBQUc7UUFBVixXQUFNLEdBQU4sTUFBTSxDQUFJO0lBQUcsQ0FBQztJQUNwQyxNQUFNLENBQUMsU0FBUyxDQUFDLElBQVc7UUFDeEIsT0FBTyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUEsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUM3RCxDQUFDO0lBQ0QsSUFBSSxDQUFDLElBQVU7UUFDWCxPQUFPLENBQUMsQ0FBQyxtQkFBbUIsRUFDeEIsRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFDL0IsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQztDQUNKIn0= + +/***/ }), +/* 20 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["b"] = flags; +/* harmony export (immutable) */ __webpack_exports__["e"] = kindString; +/* harmony export (immutable) */ __webpack_exports__["d"] = itemName; +/* unused harmony export itemTooltip */ +/* harmony export (immutable) */ __webpack_exports__["a"] = extensionOf; +/* harmony export (immutable) */ __webpack_exports__["c"] = inheritedFrom; +/* harmony export (immutable) */ __webpack_exports__["i"] = sourceLink; +/* harmony export (immutable) */ __webpack_exports__["f"] = libLink; +/* harmony export (immutable) */ __webpack_exports__["h"] = signature; +/* unused harmony export defaultVal */ +/* harmony export (immutable) */ __webpack_exports__["j"] = type; +/* harmony export (immutable) */ __webpack_exports__["g"] = makeID; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tooltip__ = __webpack_require__(53); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__DocSets__ = __webpack_require__(6); + + + +const SourceBase = 'src/'; +function flags(mdl, ignore = []) { + const ignoreExportInKind = ['Method', 'Property']; + const knownFlags = { + isExported: 'export', + isExternal: 'external', + isPublic: 'public', + isPrivate: 'private', + isProtected: 'protected', + isConstructorProperty: 'constructorProperty', + isStatic: 'static', + isOptional: 'optional' + }; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-flags', !mdl.flags ? [] : + Object.keys(mdl.flags).map((f) => { + let ign = false; + let flag = knownFlags[f]; + if (flag === undefined) { + flag = f; + } + else { + ign = (ignore.indexOf(flag) >= 0); + } + if (flag === 'export' && ignoreExportInKind.indexOf(mdl.kindString) >= 0) { + ign = true; + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`span.hs-item-${ign ? 'ignore' : (flag === f ? 'unknown' : flag)}-flag`, ign ? undefined : flag); + })); +} +function kindString(mdl) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-kind', mdl.kindString); +} +function itemName(mdl, sub) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', !mdl.fullPath ? sub.name : libLink('a', mdl.lib, mdl.fullPath, sub.name)); +} +function itemTooltip(mdl) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', Object(__WEBPACK_IMPORTED_MODULE_1__Tooltip__["a" /* tooltip */])(mdl.name, 'class name and then some', 'bottom')); +} +function extensionOf(mdl) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-extensions', !mdl.extendedTypes ? undefined : [ + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-extends', 'extends'), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', mdl.extendedTypes.map((t, i) => Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-extension', [ + libLink('a', mdl.lib, __WEBPACK_IMPORTED_MODULE_2__DocSets__["a" /* DocSets */].get(mdl.lib, t.id).fullPath, t.name), + mdl.extendedTypes.map.length > (i + 1) ? ', ' : '' + ]))), + ]); +} +function inheritedFrom(mdl) { + if (mdl.inheritedFrom) { + let parent = __WEBPACK_IMPORTED_MODULE_2__DocSets__["a" /* DocSets */].get(mdl.lib, mdl.inheritedFrom.id); + parent = __WEBPACK_IMPORTED_MODULE_2__DocSets__["a" /* DocSets */].get(mdl.lib, parent.fullPath.substring(0, parent.fullPath.lastIndexOf('.'))); + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-inherited-from', [ + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', 'inherited from '), + libLink('a', parent.lib, parent.fullPath, parent.name) + ]); + } + else { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-inherited-from', undefined); + } +} +function sourceLink(mdl) { + const source = mdl.sources ? mdl.sources[0] : undefined; + if (source) { + let file = (source.fileName || '').replace('.ts', '.html'); + const index = file.indexOf(mdl.lib); + if (index > 0) { + file = file.substr(index); + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-member-source', Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('a', { href: `${SourceBase}${mdl.lib}/${file}#${Math.max(0, source.line - 5)}`, target: "_blank" }, '[source]')); + } + else { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-member-source', ''); + } +} +function libLink(css, lib, id, name) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(css, { href: `/api/${lib}/${id}`, oncreate: __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].route.link, onupdate: __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].route.link }, name); +} +; +function signature(s, mdl) { + const comma = (i) => (i > 0) ? ', ' : ''; + function optional(flags) { + return (flags && flags.isOptional) ? '.hs-item-optional' : ''; + } + let sig = []; + if (s) { + if (s.parameters) { + sig = s.parameters.map((p, i) => Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', [ + comma(i), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-sig-param', [ + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`span.hs-item-name${optional(p.flags)}`, p.name), + type(p, mdl.lib) + ]) + ])); + } + switch (mdl.kindString) { + case 'Method': + case 'Function': + case 'Constructor': + sig.unshift(Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', '(')); + sig.push(Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', ')')); + break; + default: + } + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-signature', sig); +} +function defaultVal(s, lib) { + if (s && s.defaultValue) { + let val = ` = ${s.defaultValue}`.replace(/{/gi, '{ ').replace(/}/gi, ' }'); + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-default', val); + } + else { + return; + } +} +function type(t, lib) { + function _type(tt) { + switch (tt.type) { + case undefined: return ''; + case 'array': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-array', ['Array<', _type(tt.elementType), '>']); + case 'tuple': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-tuple', [ + '[ ', + ...tt.elements.map((e, i) => [i > 0 ? ', ' : undefined, _type(e)]), + ' ]' + ]); + case 'intrinsic': + case 'instrinct': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-instrinct', tt.id ? libLink('span', lib, tt.fullPath, tt.name) : tt.name); + case 'stringLiteral': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-string-literal', tt.type); + case 'union': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-union', [...tt.types.map((e, i) => [i > 0 ? ' | ' : undefined, _type(e)])]); + case 'reference': + let refRes = tt.name; + if (tt.id) { + const typeRef = __WEBPACK_IMPORTED_MODULE_2__DocSets__["a" /* DocSets */].get(lib, tt.id); + if (typeRef.typeArguments) { + refRes = typeRef.name + '<' + typeRef.typeArguments.map(_type).join(', ') + '>'; + } + else if (typeRef.id) { + refRes = libLink('a', lib, typeRef.fullPath, typeRef.name); + } + else { + refRes = typeRef.name; + } + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-reference', refRes); + case 'reflection': + let rflRes; + if (tt.declaration) { + rflRes = !tt.declaration.children ? tt.declaration.kindString : + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-reflection', [ + '{ ', + ...tt.declaration.children.map((c, i) => [i > 0 ? ', ' : undefined, c.name, ': ', _type(c.type)]), + ' }' + ]); + } + else { + rflRes = 'UNKNOWN'; + } + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-reflection', rflRes); + default: + console.log('unknown type ' + tt.type); + console.log(t); + return t.type; + } + } + try { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', !t.type ? '' : [ + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', ':'), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-sig-type', _type(t.type)), + defaultVal(t, lib) + ]); + } + catch (e) { + console.log(e); + console.log(e.trace); + } +} +function makeID(section, mdl) { + let result = section ? section + '_' : ''; + result = (result + (mdl.name || '')).toLowerCase(); + return (result !== '') ? result : undefined; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFydHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdmlldy9QYXJ0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQU0sVUFBVSxDQUFDO0FBQ25DLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDcEMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUVyQyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUM7QUFJMUIsTUFBTSxnQkFBZ0IsR0FBTyxFQUFFLFNBQWdCLEVBQUU7SUFDN0MsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUNsRCxNQUFNLFVBQVUsR0FBRztRQUNmLFVBQVUsRUFBYyxRQUFRO1FBQ2hDLFVBQVUsRUFBYyxVQUFVO1FBQ2xDLFFBQVEsRUFBZ0IsUUFBUTtRQUNoQyxTQUFTLEVBQWUsU0FBUztRQUNqQyxXQUFXLEVBQWEsV0FBVztRQUNuQyxxQkFBcUIsRUFBRyxxQkFBcUI7UUFDN0MsUUFBUSxFQUFnQixRQUFRO1FBQ2hDLFVBQVUsRUFBYyxVQUFVO0tBQ3JDLENBQUM7SUFDRixPQUFPLENBQUMsQ0FBQyxvQkFBb0IsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzNDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFO1lBQ3BDLElBQUksR0FBRyxHQUFHLEtBQUssQ0FBQztZQUNoQixJQUFJLElBQUksR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDekIsSUFBSSxJQUFJLEtBQUssU0FBUyxFQUFFO2dCQUFFLElBQUksR0FBRyxDQUFDLENBQUM7YUFBRTtpQkFDaEM7Z0JBQUUsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFD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 + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +var __WEBPACK_AMD_DEFINE_RESULT__;;/*! showdown 02-06-2017 */ +(function(){ +/** + * Created by Tivie on 13-07-2015. + */ + +function getDefaultOpts (simple) { + 'use strict'; + + var defaultOptions = { + omitExtraWLInCodeBlocks: { + defaultValue: false, + describe: 'Omit the default extra whiteline added to code blocks', + type: 'boolean' + }, + noHeaderId: { + defaultValue: false, + describe: 'Turn on/off generated header id', + type: 'boolean' + }, + prefixHeaderId: { + defaultValue: false, + describe: 'Specify a prefix to generated header ids', + type: 'string' + }, + ghCompatibleHeaderId: { + defaultValue: false, + describe: 'Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)', + type: 'boolean' + }, + headerLevelStart: { + defaultValue: false, + describe: 'The header blocks level start', + type: 'integer' + }, + parseImgDimensions: { + defaultValue: false, + describe: 'Turn on/off image dimension parsing', + type: 'boolean' + }, + simplifiedAutoLink: { + defaultValue: false, + describe: 'Turn on/off GFM autolink style', + type: 'boolean' + }, + excludeTrailingPunctuationFromURLs: { + defaultValue: false, + describe: 'Excludes trailing punctuation from links generated with autoLinking', + type: 'boolean' + }, + literalMidWordUnderscores: { + defaultValue: false, + describe: 'Parse midword underscores as literal underscores', + type: 'boolean' + }, + literalMidWordAsterisks: { + defaultValue: false, + describe: 'Parse midword asterisks as literal asterisks', + type: 'boolean' + }, + strikethrough: { + defaultValue: false, + describe: 'Turn on/off strikethrough support', + type: 'boolean' + }, + tables: { + defaultValue: false, + describe: 'Turn on/off tables support', + type: 'boolean' + }, + tablesHeaderId: { + defaultValue: false, + describe: 'Add an id to table headers', + type: 'boolean' + }, + ghCodeBlocks: { + defaultValue: true, + describe: 'Turn on/off GFM fenced code blocks support', + type: 'boolean' + }, + tasklists: { + defaultValue: false, + describe: 'Turn on/off GFM tasklist support', + type: 'boolean' + }, + smoothLivePreview: { + defaultValue: false, + describe: 'Prevents weird effects in live previews due to incomplete input', + type: 'boolean' + }, + smartIndentationFix: { + defaultValue: false, + description: 'Tries to smartly fix indentation in es6 strings', + type: 'boolean' + }, + disableForced4SpacesIndentedSublists: { + defaultValue: false, + description: 'Disables the requirement of indenting nested sublists by 4 spaces', + type: 'boolean' + }, + simpleLineBreaks: { + defaultValue: false, + description: 'Parses simple line breaks as
(GFM Style)', + type: 'boolean' + }, + requireSpaceBeforeHeadingText: { + defaultValue: false, + description: 'Makes adding a space between `#` and the header text mandatory (GFM Style)', + type: 'boolean' + }, + ghMentions: { + defaultValue: false, + description: 'Enables github @mentions', + type: 'boolean' + }, + ghMentionsLink: { + defaultValue: 'https://github.com/{u}', + description: 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.', + type: 'string' + }, + encodeEmails: { + defaultValue: true, + description: 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities', + type: 'boolean' + }, + openLinksInNewWindow: { + defaultValue: false, + description: 'Open all links in new windows', + type: 'boolean' + } + }; + if (simple === false) { + return JSON.parse(JSON.stringify(defaultOptions)); + } + var ret = {}; + for (var opt in defaultOptions) { + if (defaultOptions.hasOwnProperty(opt)) { + ret[opt] = defaultOptions[opt].defaultValue; + } + } + return ret; +} + +function allOptionsOn () { + 'use strict'; + var options = getDefaultOpts(true), + ret = {}; + for (var opt in options) { + if (options.hasOwnProperty(opt)) { + ret[opt] = true; + } + } + return ret; +} + +/** + * Created by Tivie on 06-01-2015. + */ + +// Private properties +var showdown = {}, + parsers = {}, + extensions = {}, + globalOptions = getDefaultOpts(true), + setFlavor = 'vanilla', + flavor = { + github: { + omitExtraWLInCodeBlocks: true, + simplifiedAutoLink: true, + excludeTrailingPunctuationFromURLs: true, + literalMidWordUnderscores: true, + strikethrough: true, + tables: true, + tablesHeaderId: true, + ghCodeBlocks: true, + tasklists: true, + disableForced4SpacesIndentedSublists: true, + simpleLineBreaks: true, + requireSpaceBeforeHeadingText: true, + ghCompatibleHeaderId: true, + ghMentions: true + }, + original: { + noHeaderId: true, + ghCodeBlocks: false + }, + ghost: { + omitExtraWLInCodeBlocks: true, + parseImgDimensions: true, + simplifiedAutoLink: true, + excludeTrailingPunctuationFromURLs: true, + literalMidWordUnderscores: true, + strikethrough: true, + tables: true, + tablesHeaderId: true, + ghCodeBlocks: true, + tasklists: true, + smoothLivePreview: true, + simpleLineBreaks: true, + requireSpaceBeforeHeadingText: true, + ghMentions: false, + encodeEmails: true + }, + vanilla: getDefaultOpts(true), + allOn: allOptionsOn() + }; + +/** + * helper namespace + * @type {{}} + */ +showdown.helper = {}; + +/** + * TODO LEGACY SUPPORT CODE + * @type {{}} + */ +showdown.extensions = {}; + +/** + * Set a global option + * @static + * @param {string} key + * @param {*} value + * @returns {showdown} + */ +showdown.setOption = function (key, value) { + 'use strict'; + globalOptions[key] = value; + return this; +}; + +/** + * Get a global option + * @static + * @param {string} key + * @returns {*} + */ +showdown.getOption = function (key) { + 'use strict'; + return globalOptions[key]; +}; + +/** + * Get the global options + * @static + * @returns {{}} + */ +showdown.getOptions = function () { + 'use strict'; + return globalOptions; +}; + +/** + * Reset global options to the default values + * @static + */ +showdown.resetOptions = function () { + 'use strict'; + globalOptions = getDefaultOpts(true); +}; + +/** + * Set the flavor showdown should use as default + * @param {string} name + */ +showdown.setFlavor = function (name) { + 'use strict'; + if (!flavor.hasOwnProperty(name)) { + throw Error(name + ' flavor was not found'); + } + showdown.resetOptions(); + var preset = flavor[name]; + setFlavor = name; + for (var option in preset) { + if (preset.hasOwnProperty(option)) { + globalOptions[option] = preset[option]; + } + } +}; + +/** + * Get the currently set flavor + * @returns {string} + */ +showdown.getFlavor = function () { + 'use strict'; + return setFlavor; +}; + +/** + * Get the options of a specified flavor. Returns undefined if the flavor was not found + * @param {string} name Name of the flavor + * @returns {{}|undefined} + */ +showdown.getFlavorOptions = function (name) { + 'use strict'; + if (flavor.hasOwnProperty(name)) { + return flavor[name]; + } +}; + +/** + * Get the default options + * @static + * @param {boolean} [simple=true] + * @returns {{}} + */ +showdown.getDefaultOptions = function (simple) { + 'use strict'; + return getDefaultOpts(simple); +}; + +/** + * Get or set a subParser + * + * subParser(name) - Get a registered subParser + * subParser(name, func) - Register a subParser + * @static + * @param {string} name + * @param {function} [func] + * @returns {*} + */ +showdown.subParser = function (name, func) { + 'use strict'; + if (showdown.helper.isString(name)) { + if (typeof func !== 'undefined') { + parsers[name] = func; + } else { + if (parsers.hasOwnProperty(name)) { + return parsers[name]; + } else { + throw Error('SubParser named ' + name + ' not registered!'); + } + } + } +}; + +/** + * Gets or registers an extension + * @static + * @param {string} name + * @param {object|function=} ext + * @returns {*} + */ +showdown.extension = function (name, ext) { + 'use strict'; + + if (!showdown.helper.isString(name)) { + throw Error('Extension \'name\' must be a string'); + } + + name = showdown.helper.stdExtName(name); + + // Getter + if (showdown.helper.isUndefined(ext)) { + if (!extensions.hasOwnProperty(name)) { + throw Error('Extension named ' + name + ' is not registered!'); + } + return extensions[name]; + + // Setter + } else { + // Expand extension if it's wrapped in a function + if (typeof ext === 'function') { + ext = ext(); + } + + // Ensure extension is an array + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } + + var validExtension = validate(ext, name); + + if (validExtension.valid) { + extensions[name] = ext; + } else { + throw Error(validExtension.error); + } + } +}; + +/** + * Gets all extensions registered + * @returns {{}} + */ +showdown.getAllExtensions = function () { + 'use strict'; + return extensions; +}; + +/** + * Remove an extension + * @param {string} name + */ +showdown.removeExtension = function (name) { + 'use strict'; + delete extensions[name]; +}; + +/** + * Removes all extensions + */ +showdown.resetExtensions = function () { + 'use strict'; + extensions = {}; +}; + +/** + * Validate extension + * @param {array} extension + * @param {string} name + * @returns {{valid: boolean, error: string}} + */ +function validate (extension, name) { + 'use strict'; + + var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension', + ret = { + valid: true, + error: '' + }; + + if (!showdown.helper.isArray(extension)) { + extension = [extension]; + } + + for (var i = 0; i < extension.length; ++i) { + var baseMsg = errMsg + ' sub-extension ' + i + ': ', + ext = extension[i]; + if (typeof ext !== 'object') { + ret.valid = false; + ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given'; + return ret; + } + + if (!showdown.helper.isString(ext.type)) { + ret.valid = false; + ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given'; + return ret; + } + + var type = ext.type = ext.type.toLowerCase(); + + // normalize extension type + if (type === 'language') { + type = ext.type = 'lang'; + } + + if (type === 'html') { + type = ext.type = 'output'; + } + + if (type !== 'lang' && type !== 'output' && type !== 'listener') { + ret.valid = false; + ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"'; + return ret; + } + + if (type === 'listener') { + if (showdown.helper.isUndefined(ext.listeners)) { + ret.valid = false; + ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"'; + return ret; + } + } else { + if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) { + ret.valid = false; + ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method'; + return ret; + } + } + + if (ext.listeners) { + if (typeof ext.listeners !== 'object') { + ret.valid = false; + ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given'; + return ret; + } + for (var ln in ext.listeners) { + if (ext.listeners.hasOwnProperty(ln)) { + if (typeof ext.listeners[ln] !== 'function') { + ret.valid = false; + ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln + + ' must be a function but ' + typeof ext.listeners[ln] + ' given'; + return ret; + } + } + } + } + + if (ext.filter) { + if (typeof ext.filter !== 'function') { + ret.valid = false; + ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given'; + return ret; + } + } else if (ext.regex) { + if (showdown.helper.isString(ext.regex)) { + ext.regex = new RegExp(ext.regex, 'g'); + } + if (!(ext.regex instanceof RegExp)) { + ret.valid = false; + ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given'; + return ret; + } + if (showdown.helper.isUndefined(ext.replace)) { + ret.valid = false; + ret.error = baseMsg + '"regex" extensions must implement a replace string or function'; + return ret; + } + } + } + return ret; +} + +/** + * Validate extension + * @param {object} ext + * @returns {boolean} + */ +showdown.validateExtension = function (ext) { + 'use strict'; + + var validateExtension = validate(ext, null); + if (!validateExtension.valid) { + console.warn(validateExtension.error); + return false; + } + return true; +}; + +/** + * showdownjs helper functions + */ + +if (!showdown.hasOwnProperty('helper')) { + showdown.helper = {}; +} + +/** + * Check if var is string + * @static + * @param {string} a + * @returns {boolean} + */ +showdown.helper.isString = function (a) { + 'use strict'; + return (typeof a === 'string' || a instanceof String); +}; + +/** + * Check if var is a function + * @static + * @param {*} a + * @returns {boolean} + */ +showdown.helper.isFunction = function (a) { + 'use strict'; + var getType = {}; + return a && getType.toString.call(a) === '[object Function]'; +}; + +/** + * isArray helper function + * @static + * @param {*} a + * @returns {boolean} + */ +showdown.helper.isArray = function (a) { + 'use strict'; + return a.constructor === Array; +}; + +/** + * Check if value is undefined + * @static + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + */ +showdown.helper.isUndefined = function (value) { + 'use strict'; + return typeof value === 'undefined'; +}; + +/** + * ForEach helper function + * Iterates over Arrays and Objects (own properties only) + * @static + * @param {*} obj + * @param {function} callback Accepts 3 params: 1. value, 2. key, 3. the original array/object + */ +showdown.helper.forEach = function (obj, callback) { + 'use strict'; + // check if obj is defined + if (showdown.helper.isUndefined(obj)) { + throw new Error('obj param is required'); + } + + if (showdown.helper.isUndefined(callback)) { + throw new Error('callback param is required'); + } + + if (!showdown.helper.isFunction(callback)) { + throw new Error('callback param must be a function/closure'); + } + + if (typeof obj.forEach === 'function') { + obj.forEach(callback); + } else if (showdown.helper.isArray(obj)) { + for (var i = 0; i < obj.length; i++) { + callback(obj[i], i, obj); + } + } else if (typeof (obj) === 'object') { + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + callback(obj[prop], prop, obj); + } + } + } else { + throw new Error('obj does not seem to be an array or an iterable object'); + } +}; + +/** + * Standardidize extension name + * @static + * @param {string} s extension name + * @returns {string} + */ +showdown.helper.stdExtName = function (s) { + 'use strict'; + return s.replace(/[_?*+\/\\.^-]/g, '').replace(/\s/g, '').toLowerCase(); +}; + +function escapeCharactersCallback (wholeMatch, m1) { + 'use strict'; + var charCodeToEscape = m1.charCodeAt(0); + return '¨E' + charCodeToEscape + 'E'; +} + +/** + * Callback used to escape characters when passing through String.replace + * @static + * @param {string} wholeMatch + * @param {string} m1 + * @returns {string} + */ +showdown.helper.escapeCharactersCallback = escapeCharactersCallback; + +/** + * Escape characters in a string + * @static + * @param {string} text + * @param {string} charsToEscape + * @param {boolean} afterBackslash + * @returns {XML|string|void|*} + */ +showdown.helper.escapeCharacters = function (text, charsToEscape, afterBackslash) { + 'use strict'; + // First we have to escape the escape characters so that + // we can build a character class out of them + var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])'; + + if (afterBackslash) { + regexString = '\\\\' + regexString; + } + + var regex = new RegExp(regexString, 'g'); + text = text.replace(regex, escapeCharactersCallback); + + return text; +}; + +var rgxFindMatchPos = function (str, left, right, flags) { + 'use strict'; + var f = flags || '', + g = f.indexOf('g') > -1, + x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')), + l = new RegExp(left, f.replace(/g/g, '')), + pos = [], + t, s, m, start, end; + + do { + t = 0; + while ((m = x.exec(str))) { + if (l.test(m[0])) { + if (!(t++)) { + s = x.lastIndex; + start = s - m[0].length; + } + } else if (t) { + if (!--t) { + end = m.index + m[0].length; + var obj = { + left: {start: start, end: s}, + match: {start: s, end: m.index}, + right: {start: m.index, end: end}, + wholeMatch: {start: start, end: end} + }; + pos.push(obj); + if (!g) { + return pos; + } + } + } + } + } while (t && (x.lastIndex = s)); + + return pos; +}; + +/** + * matchRecursiveRegExp + * + * (c) 2007 Steven Levithan + * MIT License + * + * Accepts a string to search, a left and right format delimiter + * as regex patterns, and optional regex flags. Returns an array + * of matches, allowing nested instances of left/right delimiters. + * Use the "g" flag to return all matches, otherwise only the + * first is returned. Be careful to ensure that the left and + * right format delimiters produce mutually exclusive matches. + * Backreferences are not supported within the right delimiter + * due to how it is internally combined with the left delimiter. + * When matching strings whose format delimiters are unbalanced + * to the left or right, the output is intentionally as a + * conventional regex library with recursion support would + * produce, e.g. "<" and ">" both produce ["x"] when using + * "<" and ">" as the delimiters (both strings contain a single, + * balanced instance of ""). + * + * examples: + * matchRecursiveRegExp("test", "\\(", "\\)") + * returns: [] + * matchRecursiveRegExp(">>t<>", "<", ">", "g") + * returns: ["t<>", ""] + * matchRecursiveRegExp("
test
", "]*>", "", "gi") + * returns: ["test"] + */ +showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) { + 'use strict'; + + var matchPos = rgxFindMatchPos (str, left, right, flags), + results = []; + + for (var i = 0; i < matchPos.length; ++i) { + results.push([ + str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end), + str.slice(matchPos[i].match.start, matchPos[i].match.end), + str.slice(matchPos[i].left.start, matchPos[i].left.end), + str.slice(matchPos[i].right.start, matchPos[i].right.end) + ]); + } + return results; +}; + +/** + * + * @param {string} str + * @param {string|function} replacement + * @param {string} left + * @param {string} right + * @param {string} flags + * @returns {string} + */ +showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) { + 'use strict'; + + if (!showdown.helper.isFunction(replacement)) { + var repStr = replacement; + replacement = function () { + return repStr; + }; + } + + var matchPos = rgxFindMatchPos(str, left, right, flags), + finalStr = str, + lng = matchPos.length; + + if (lng > 0) { + var bits = []; + if (matchPos[0].wholeMatch.start !== 0) { + bits.push(str.slice(0, matchPos[0].wholeMatch.start)); + } + for (var i = 0; i < lng; ++i) { + bits.push( + replacement( + str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end), + str.slice(matchPos[i].match.start, matchPos[i].match.end), + str.slice(matchPos[i].left.start, matchPos[i].left.end), + str.slice(matchPos[i].right.start, matchPos[i].right.end) + ) + ); + if (i < lng - 1) { + bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start)); + } + } + if (matchPos[lng - 1].wholeMatch.end < str.length) { + bits.push(str.slice(matchPos[lng - 1].wholeMatch.end)); + } + finalStr = bits.join(''); + } + return finalStr; +}; + +/** + * Returns the index within the passed String object of the first occurrence of the specified regex, + * starting the search at fromIndex. Returns -1 if the value is not found. + * + * @param {string} str string to search + * @param {RegExp} regex Regular expression to search + * @param {int} [fromIndex = 0] Index to start the search + * @returns {Number} + * @throws InvalidArgumentError + */ +showdown.helper.regexIndexOf = function (str, regex, fromIndex) { + 'use strict'; + if (!showdown.helper.isString(str)) { + throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string'; + } + if (regex instanceof RegExp === false) { + throw 'InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp'; + } + var indexOf = str.substring(fromIndex || 0).search(regex); + return (indexOf >= 0) ? (indexOf + (fromIndex || 0)) : indexOf; +}; + +/** + * Splits the passed string object at the defined index, and returns an array composed of the two substrings + * @param {string} str string to split + * @param {int} index index to split string at + * @returns {[string,string]} + * @throws InvalidArgumentError + */ +showdown.helper.splitAtIndex = function (str, index) { + 'use strict'; + if (!showdown.helper.isString(str)) { + throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string'; + } + return [str.substring(0, index), str.substring(index)]; +}; + +/** + * Obfuscate an e-mail address through the use of Character Entities, + * transforming ASCII characters into their equivalent decimal or hex entities. + * + * Since it has a random component, subsequent calls to this function produce different results + * + * @param {string} mail + * @returns {string} + */ +showdown.helper.encodeEmailAddress = function (mail) { + 'use strict'; + var encode = [ + function (ch) { + return '&#' + ch.charCodeAt(0) + ';'; + }, + function (ch) { + return '&#x' + ch.charCodeAt(0).toString(16) + ';'; + }, + function (ch) { + return ch; + } + ]; + + mail = mail.replace(/./g, function (ch) { + if (ch === '@') { + // this *must* be encoded. I insist. + ch = encode[Math.floor(Math.random() * 2)](ch); + } else { + var r = Math.random(); + // roughly 10% raw, 45% hex, 45% dec + ch = ( + r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch) + ); + } + return ch; + }); + + return mail; +}; + +/** + * POLYFILLS + */ +// use this instead of builtin is undefined for IE8 compatibility +if (typeof(console) === 'undefined') { + console = { + warn: function (msg) { + 'use strict'; + alert(msg); + }, + log: function (msg) { + 'use strict'; + alert(msg); + }, + error: function (msg) { + 'use strict'; + throw msg; + } + }; +} + +/** + * Common regexes. + * We declare some common regexes to improve performance + */ +showdown.helper.regexes = { + asteriskAndDash: /([*_])/g +}; + +/** + * Created by Estevao on 31-05-2015. + */ + +/** + * Showdown Converter class + * @class + * @param {object} [converterOptions] + * @returns {Converter} + */ +showdown.Converter = function (converterOptions) { + 'use strict'; + + var + /** + * Options used by this converter + * @private + * @type {{}} + */ + options = {}, + + /** + * Language extensions used by this converter + * @private + * @type {Array} + */ + langExtensions = [], + + /** + * Output modifiers extensions used by this converter + * @private + * @type {Array} + */ + outputModifiers = [], + + /** + * Event listeners + * @private + * @type {{}} + */ + listeners = {}, + + /** + * The flavor set in this converter + */ + setConvFlavor = setFlavor; + + _constructor(); + + /** + * Converter constructor + * @private + */ + function _constructor () { + converterOptions = converterOptions || {}; + + for (var gOpt in globalOptions) { + if (globalOptions.hasOwnProperty(gOpt)) { + options[gOpt] = globalOptions[gOpt]; + } + } + + // Merge options + if (typeof converterOptions === 'object') { + for (var opt in converterOptions) { + if (converterOptions.hasOwnProperty(opt)) { + options[opt] = converterOptions[opt]; + } + } + } else { + throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions + + ' was passed instead.'); + } + + if (options.extensions) { + showdown.helper.forEach(options.extensions, _parseExtension); + } + } + + /** + * Parse extension + * @param {*} ext + * @param {string} [name=''] + * @private + */ + function _parseExtension (ext, name) { + + name = name || null; + // If it's a string, the extension was previously loaded + if (showdown.helper.isString(ext)) { + ext = showdown.helper.stdExtName(ext); + name = ext; + + // LEGACY_SUPPORT CODE + if (showdown.extensions[ext]) { + console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' + + 'Please inform the developer that the extension should be updated!'); + legacyExtensionLoading(showdown.extensions[ext], ext); + return; + // END LEGACY SUPPORT CODE + + } else if (!showdown.helper.isUndefined(extensions[ext])) { + ext = extensions[ext]; + + } else { + throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.'); + } + } + + if (typeof ext === 'function') { + ext = ext(); + } + + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } + + var validExt = validate(ext, name); + if (!validExt.valid) { + throw Error(validExt.error); + } + + for (var i = 0; i < ext.length; ++i) { + switch (ext[i].type) { + + case 'lang': + langExtensions.push(ext[i]); + break; + + case 'output': + outputModifiers.push(ext[i]); + break; + } + if (ext[i].hasOwnProperty('listeners')) { + for (var ln in ext[i].listeners) { + if (ext[i].listeners.hasOwnProperty(ln)) { + listen(ln, ext[i].listeners[ln]); + } + } + } + } + + } + + /** + * LEGACY_SUPPORT + * @param {*} ext + * @param {string} name + */ + function legacyExtensionLoading (ext, name) { + if (typeof ext === 'function') { + ext = ext(new showdown.Converter()); + } + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } + var valid = validate(ext, name); + + if (!valid.valid) { + throw Error(valid.error); + } + + for (var i = 0; i < ext.length; ++i) { + switch (ext[i].type) { + case 'lang': + langExtensions.push(ext[i]); + break; + case 'output': + outputModifiers.push(ext[i]); + break; + default:// should never reach here + throw Error('Extension loader error: Type unrecognized!!!'); + } + } + } + + /** + * Listen to an event + * @param {string} name + * @param {function} callback + */ + function listen (name, callback) { + if (!showdown.helper.isString(name)) { + throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given'); + } + + if (typeof callback !== 'function') { + throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given'); + } + + if (!listeners.hasOwnProperty(name)) { + listeners[name] = []; + } + listeners[name].push(callback); + } + + function rTrimInputText (text) { + var rsp = text.match(/^\s*/)[0].length, + rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm'); + return text.replace(rgx, ''); + } + + /** + * Dispatch an event + * @private + * @param {string} evtName Event name + * @param {string} text Text + * @param {{}} options Converter Options + * @param {{}} globals + * @returns {string} + */ + this._dispatch = function dispatch (evtName, text, options, globals) { + if (listeners.hasOwnProperty(evtName)) { + for (var ei = 0; ei < listeners[evtName].length; ++ei) { + var nText = listeners[evtName][ei](evtName, text, this, options, globals); + if (nText && typeof nText !== 'undefined') { + text = nText; + } + } + } + return text; + }; + + /** + * Listen to an event + * @param {string} name + * @param {function} callback + * @returns {showdown.Converter} + */ + this.listen = function (name, callback) { + listen(name, callback); + return this; + }; + + /** + * Converts a markdown string into HTML + * @param {string} text + * @returns {*} + */ + this.makeHtml = function (text) { + //check if text is not falsy + if (!text) { + return text; + } + + var globals = { + gHtmlBlocks: [], + gHtmlMdBlocks: [], + gHtmlSpans: [], + gUrls: {}, + gTitles: {}, + gDimensions: {}, + gListLevel: 0, + hashLinkCounts: {}, + langExtensions: langExtensions, + outputModifiers: outputModifiers, + converter: this, + ghCodeBlocks: [] + }; + + // This lets us use ¨ trema as an escape char to avoid md5 hashes + // The choice of character is arbitrary; anything that isn't + // magic in Markdown will work. + text = text.replace(/¨/g, '¨T'); + + // Replace $ with ¨D + // RegExp interprets $ as a special character + // when it's in a replacement string + text = text.replace(/\$/g, '¨D'); + + // Standardize line endings + text = text.replace(/\r\n/g, '\n'); // DOS to Unix + text = text.replace(/\r/g, '\n'); // Mac to Unix + + // Stardardize line spaces (nbsp causes trouble in older browsers and some regex flavors) + text = text.replace(/\u00A0/g, ' '); + + if (options.smartIndentationFix) { + text = rTrimInputText(text); + } + + // Make sure text begins and ends with a couple of newlines: + text = '\n\n' + text + '\n\n'; + + // detab + text = showdown.subParser('detab')(text, options, globals); + + /** + * Strip any lines consisting only of spaces and tabs. + * This makes subsequent regexs easier to write, because we can + * match consecutive blank lines with /\n+/ instead of something + * contorted like /[ \t]*\n+/ + */ + text = text.replace(/^[ \t]+$/mg, ''); + + //run languageExtensions + showdown.helper.forEach(langExtensions, function (ext) { + text = showdown.subParser('runExtension')(ext, text, options, globals); + }); + + // run the sub parsers + text = showdown.subParser('hashPreCodeTags')(text, options, globals); + text = showdown.subParser('githubCodeBlocks')(text, options, globals); + text = showdown.subParser('hashHTMLBlocks')(text, options, globals); + text = showdown.subParser('hashCodeTags')(text, options, globals); + text = showdown.subParser('stripLinkDefinitions')(text, options, globals); + text = showdown.subParser('blockGamut')(text, options, globals); + text = showdown.subParser('unhashHTMLSpans')(text, options, globals); + text = showdown.subParser('unescapeSpecialChars')(text, options, globals); + + // attacklab: Restore dollar signs + text = text.replace(/¨D/g, '$$'); + + // attacklab: Restore tremas + text = text.replace(/¨T/g, '¨'); + + // Run output modifiers + showdown.helper.forEach(outputModifiers, function (ext) { + text = showdown.subParser('runExtension')(ext, text, options, globals); + }); + + return text; + }; + + /** + * Set an option of this Converter instance + * @param {string} key + * @param {*} value + */ + this.setOption = function (key, value) { + options[key] = value; + }; + + /** + * Get the option of this Converter instance + * @param {string} key + * @returns {*} + */ + this.getOption = function (key) { + return options[key]; + }; + + /** + * Get the options of this Converter instance + * @returns {{}} + */ + this.getOptions = function () { + return options; + }; + + /** + * Add extension to THIS converter + * @param {{}} extension + * @param {string} [name=null] + */ + this.addExtension = function (extension, name) { + name = name || null; + _parseExtension(extension, name); + }; + + /** + * Use a global registered extension with THIS converter + * @param {string} extensionName Name of the previously registered extension + */ + this.useExtension = function (extensionName) { + _parseExtension(extensionName); + }; + + /** + * Set the flavor THIS converter should use + * @param {string} name + */ + this.setFlavor = function (name) { + if (!flavor.hasOwnProperty(name)) { + throw Error(name + ' flavor was not found'); + } + var preset = flavor[name]; + setConvFlavor = name; + for (var option in preset) { + if (preset.hasOwnProperty(option)) { + options[option] = preset[option]; + } + } + }; + + /** + * Get the currently set flavor of this converter + * @returns {string} + */ + this.getFlavor = function () { + return setConvFlavor; + }; + + /** + * Remove an extension from THIS converter. + * Note: This is a costly operation. It's better to initialize a new converter + * and specify the extensions you wish to use + * @param {Array} extension + */ + this.removeExtension = function (extension) { + if (!showdown.helper.isArray(extension)) { + extension = [extension]; + } + for (var a = 0; a < extension.length; ++a) { + var ext = extension[a]; + for (var i = 0; i < langExtensions.length; ++i) { + if (langExtensions[i] === ext) { + langExtensions[i].splice(i, 1); + } + } + for (var ii = 0; ii < outputModifiers.length; ++i) { + if (outputModifiers[ii] === ext) { + outputModifiers[ii].splice(i, 1); + } + } + } + }; + + /** + * Get all extension of THIS converter + * @returns {{language: Array, output: Array}} + */ + this.getAllExtensions = function () { + return { + language: langExtensions, + output: outputModifiers + }; + }; +}; + +/** + * Turn Markdown link shortcuts into XHTML tags. + */ +showdown.subParser('anchors', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('anchors.before', text, options, globals); + + var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) { + if (showdown.helper.isUndefined(title)) { + title = ''; + } + linkId = linkId.toLowerCase(); + + // Special case for explicit empty url + if (wholeMatch.search(/\(? ?(['"].*['"])?\)$/m) > -1) { + url = ''; + } else if (!url) { + if (!linkId) { + // lower-case and turn embedded newlines into spaces + linkId = linkText.toLowerCase().replace(/ ?\n/g, ' '); + } + url = '#' + linkId; + + if (!showdown.helper.isUndefined(globals.gUrls[linkId])) { + url = globals.gUrls[linkId]; + if (!showdown.helper.isUndefined(globals.gTitles[linkId])) { + title = globals.gTitles[linkId]; + } + } else { + return wholeMatch; + } + } + + //url = showdown.helper.escapeCharacters(url, '*_', false); // replaced line to improve performance + url = url.replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback); + + var result = ''; + + return result; + }; + + // First, handle reference-style links: [link text] [id] + text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag); + + // Next, inline-style links: [link text](url "optional title") + // cases with crazy urls like ./image/cat1).png + text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g, + writeAnchorTag); + + // normal cases + text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]??(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g, + writeAnchorTag); + + // handle reference-style shortcuts: [link text] + // These must come last in case you've also got [link test][1] + // or [link test](/foo) + text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag); + + // Lastly handle GithubMentions if option is enabled + if (options.ghMentions) { + text = text.replace(/(^|\s)(\\)?(@([a-z\d\-]+))(?=[.!?;,[\]()]|\s|$)/gmi, function (wm, st, escape, mentions, username) { + if (escape === '\\') { + return st + mentions; + } + + //check if options.ghMentionsLink is a string + if (!showdown.helper.isString(options.ghMentionsLink)) { + throw new Error('ghMentionsLink option must be a string'); + } + var lnk = options.ghMentionsLink.replace(/\{u}/g, username); + return st + '' + mentions + ''; + }); + } + + text = globals.converter._dispatch('anchors.after', text, options, globals); + return text; +}); + +// url allowed chars [a-z\d_.~:/?#[]@!$&'()*+,;=-] + +var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)()(?=\s|$)(?!["<>])/gi, + simpleURLRegex2 = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]]?)(?=\s|$)(?!["<>])/gi, + //simpleURLRegex3 = /\b(((https?|ftp):\/\/|www\.)[a-z\d.-]+\.[a-z\d_.~:/?#\[\]@!$&'()*+,;=-]+?)([.!?()]?)(?=\s|$)(?!["<>])/gi, + delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>/gi, + simpleMailRegex = /(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gmi, + delimMailRegex = /<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi, + + replaceLink = function (options) { + 'use strict'; + + return function (wm, link, m2, m3, trailingPunctuation) { + var lnkTxt = link, + append = '', + target = ''; + if (/^www\./i.test(link)) { + link = link.replace(/^www\./i, 'http://www.'); + } + if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) { + append = trailingPunctuation; + } + if (options.openLinksInNewWindow) { + target = ' target="¨E95Eblank"'; + } + return '' + lnkTxt + '' + append; + }; + }, + + replaceMail = function (options, globals) { + 'use strict'; + return function (wholeMatch, b, mail) { + var href = 'mailto:'; + b = b || ''; + mail = showdown.subParser('unescapeSpecialChars')(mail, options, globals); + if (options.encodeEmails) { + href = showdown.helper.encodeEmailAddress(href + mail); + mail = showdown.helper.encodeEmailAddress(mail); + } else { + href = href + mail; + } + return b + '' + mail + ''; + }; + }; + +showdown.subParser('autoLinks', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('autoLinks.before', text, options, globals); + + text = text.replace(delimUrlRegex, replaceLink(options)); + text = text.replace(delimMailRegex, replaceMail(options, globals)); + + text = globals.converter._dispatch('autoLinks.after', text, options, globals); + + return text; +}); + +showdown.subParser('simplifiedAutoLinks', function (text, options, globals) { + 'use strict'; + + if (!options.simplifiedAutoLink) { + return text; + } + + text = globals.converter._dispatch('simplifiedAutoLinks.before', text, options, globals); + + if (options.excludeTrailingPunctuationFromURLs) { + text = text.replace(simpleURLRegex2, replaceLink(options)); + } else { + text = text.replace(simpleURLRegex, replaceLink(options)); + } + text = text.replace(simpleMailRegex, replaceMail(options, globals)); + + text = globals.converter._dispatch('simplifiedAutoLinks.after', text, options, globals); + + return text; +}); + +/** + * These are all the transformations that form block-level + * tags like paragraphs, headers, and list items. + */ +showdown.subParser('blockGamut', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('blockGamut.before', text, options, globals); + + // we parse blockquotes first so that we can have headings and hrs + // inside blockquotes + text = showdown.subParser('blockQuotes')(text, options, globals); + text = showdown.subParser('headers')(text, options, globals); + + // Do Horizontal Rules: + text = showdown.subParser('horizontalRule')(text, options, globals); + + text = showdown.subParser('lists')(text, options, globals); + text = showdown.subParser('codeBlocks')(text, options, globals); + text = showdown.subParser('tables')(text, options, globals); + + // We already ran _HashHTMLBlocks() before, in Markdown(), but that + // was to escape raw HTML in the original Markdown source. This time, + // we're escaping the markup we've just created, so that we don't wrap + //

tags around block-level tags. + text = showdown.subParser('hashHTMLBlocks')(text, options, globals); + text = showdown.subParser('paragraphs')(text, options, globals); + + text = globals.converter._dispatch('blockGamut.after', text, options, globals); + + return text; +}); + +showdown.subParser('blockQuotes', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('blockQuotes.before', text, options, globals); + + text = text.replace(/((^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) { + var bq = m1; + + // attacklab: hack around Konqueror 3.5.4 bug: + // "----------bug".replace(/^-/g,"") == "bug" + bq = bq.replace(/^[ \t]*>[ \t]?/gm, '¨0'); // trim one level of quoting + + // attacklab: clean up hack + bq = bq.replace(/¨0/g, ''); + + bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines + bq = showdown.subParser('githubCodeBlocks')(bq, options, globals); + bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse + + bq = bq.replace(/(^|\n)/g, '$1 '); + // These leading spaces screw with

 content, so we need to fix that:
+    bq = bq.replace(/(\s*
[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
+      var pre = m1;
+      // attacklab: hack around Konqueror 3.5.4 bug:
+      pre = pre.replace(/^  /mg, '¨0');
+      pre = pre.replace(/¨0/g, '');
+      return pre;
+    });
+
+    return showdown.subParser('hashBlock')('
\n' + bq + '\n
', options, globals); + }); + + text = globals.converter._dispatch('blockQuotes.after', text, options, globals); + return text; +}); + +/** + * Process Markdown `
` blocks.
+ */
+showdown.subParser('codeBlocks', function (text, options, globals) {
+  'use strict';
+
+  text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
+
+  // sentinel workarounds for lack of \A and \Z, safari\khtml bug
+  text += '¨0';
+
+  var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g;
+  text = text.replace(pattern, function (wholeMatch, m1, m2) {
+    var codeblock = m1,
+        nextChar = m2,
+        end = '\n';
+
+    codeblock = showdown.subParser('outdent')(codeblock, options, globals);
+    codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);
+    codeblock = showdown.subParser('detab')(codeblock, options, globals);
+    codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
+    codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
+
+    if (options.omitExtraWLInCodeBlocks) {
+      end = '';
+    }
+
+    codeblock = '
' + codeblock + end + '
'; + + return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar; + }); + + // strip sentinel + text = text.replace(/¨0/, ''); + + text = globals.converter._dispatch('codeBlocks.after', text, options, globals); + return text; +}); + +/** + * + * * Backtick quotes are used for spans. + * + * * You can use multiple backticks as the delimiters if you want to + * include literal backticks in the code span. So, this input: + * + * Just type ``foo `bar` baz`` at the prompt. + * + * Will translate to: + * + *

Just type foo `bar` baz at the prompt.

+ * + * There's no arbitrary limit to the number of backticks you + * can use as delimters. If you need three consecutive backticks + * in your code, use four for delimiters, etc. + * + * * You can use spaces to get literal backticks at the edges: + * + * ... type `` `bar` `` ... + * + * Turns to: + * + * ... type `bar` ... + */ +showdown.subParser('codeSpans', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('codeSpans.before', text, options, globals); + + if (typeof(text) === 'undefined') { + text = ''; + } + text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, + function (wholeMatch, m1, m2, m3) { + var c = m3; + c = c.replace(/^([ \t]*)/g, ''); // leading whitespace + c = c.replace(/[ \t]*$/g, ''); // trailing whitespace + c = showdown.subParser('encodeCode')(c, options, globals); + return m1 + '' + c + ''; + } + ); + + text = globals.converter._dispatch('codeSpans.after', text, options, globals); + return text; +}); + +/** + * Convert all tabs to spaces + */ +showdown.subParser('detab', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('detab.before', text, options, globals); + + // expand first n-1 tabs + text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width + + // replace the nth with two sentinels + text = text.replace(/\t/g, '¨A¨B'); + + // use the sentinel to anchor our regex so it doesn't explode + text = text.replace(/¨B(.+?)¨A/g, function (wholeMatch, m1) { + var leadingText = m1, + numSpaces = 4 - leadingText.length % 4; // g_tab_width + + // there *must* be a better way to do this: + for (var i = 0; i < numSpaces; i++) { + leadingText += ' '; + } + + return leadingText; + }); + + // clean up sentinels + text = text.replace(/¨A/g, ' '); // g_tab_width + text = text.replace(/¨B/g, ''); + + text = globals.converter._dispatch('detab.after', text, options, globals); + return text; +}); + +/** + * Smart processing for ampersands and angle brackets that need to be encoded. + */ +showdown.subParser('encodeAmpsAndAngles', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('encodeAmpsAndAngles.before', text, options, globals); + + // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: + // http://bumppo.net/projects/amputator/ + text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&'); + + // Encode naked <'s + text = text.replace(/<(?![a-z\/?$!])/gi, '<'); + + // Encode < + text = text.replace(/ + text = text.replace(/>/g, '>'); + + text = globals.converter._dispatch('encodeAmpsAndAngles.after', text, options, globals); + return text; +}); + +/** + * Returns the string, with after processing the following backslash escape sequences. + * + * attacklab: The polite way to do this is with the new escapeCharacters() function: + * + * text = escapeCharacters(text,"\\",true); + * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); + * + * ...but we're sidestepping its use of the (slow) RegExp constructor + * as an optimization for Firefox. This function gets called a LOT. + */ +showdown.subParser('encodeBackslashEscapes', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('encodeBackslashEscapes.before', text, options, globals); + + text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback); + text = text.replace(/\\([`*_{}\[\]()>#+.!~=|-])/g, showdown.helper.escapeCharactersCallback); + + text = globals.converter._dispatch('encodeBackslashEscapes.after', text, options, globals); + return text; +}); + +/** + * Encode/escape certain characters inside Markdown code runs. + * The point is that in code, these characters are literals, + * and lose their special Markdown meanings. + */ +showdown.subParser('encodeCode', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('encodeCode.before', text, options, globals); + + // Encode all ampersands; HTML entities are not + // entities within a Markdown code span. + text = text + .replace(/&/g, '&') + // Do the angle bracket song and dance: + .replace(//g, '>') + // Now, escape characters that are magic in Markdown: + .replace(/([*_{}\[\]\\=~-])/g, showdown.helper.escapeCharactersCallback); + + text = globals.converter._dispatch('encodeCode.after', text, options, globals); + return text; +}); + +/** + * Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they + * don't conflict with their use in Markdown for code, italics and strong. + */ +showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.before', text, options, globals); + + // Build a regex to find HTML tags and comments. See Friedl's + // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. + var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi; + + text = text.replace(regex, function (wholeMatch) { + return wholeMatch + .replace(/(.)<\/?code>(?=.)/g, '$1`') + .replace(/([\\`*_~=|])/g, showdown.helper.escapeCharactersCallback); + }); + + text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.after', text, options, globals); + return text; +}); + +/** + * Handle github codeblocks prior to running HashHTML so that + * HTML contained within the codeblock gets escaped properly + * Example: + * ```ruby + * def hello_world(x) + * puts "Hello, #{x}" + * end + * ``` + */ +showdown.subParser('githubCodeBlocks', function (text, options, globals) { + 'use strict'; + + // early exit if option is not enabled + if (!options.ghCodeBlocks) { + return text; + } + + text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals); + + text += '¨0'; + + text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) { + var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n'; + + // First parse the github code block + codeblock = showdown.subParser('encodeCode')(codeblock, options, globals); + codeblock = showdown.subParser('detab')(codeblock, options, globals); + codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines + codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace + + codeblock = '
' + codeblock + end + '
'; + + codeblock = showdown.subParser('hashBlock')(codeblock, options, globals); + + // Since GHCodeblocks can be false positives, we need to + // store the primitive text and the parsed text in a global var, + // and then return a token + return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n'; + }); + + // attacklab: strip sentinel + text = text.replace(/¨0/, ''); + + return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals); +}); + +showdown.subParser('hashBlock', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('hashBlock.before', text, options, globals); + text = text.replace(/(^\n+|\n+$)/g, ''); + text = '\n\n¨K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n'; + text = globals.converter._dispatch('hashBlock.after', text, options, globals); + return text; +}); + +/** + * Hash and escape elements that should not be parsed as markdown + */ +showdown.subParser('hashCodeTags', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('hashCodeTags.before', text, options, globals); + + var repFunc = function (wholeMatch, match, left, right) { + var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right; + return '¨C' + (globals.gHtmlSpans.push(codeblock) - 1) + 'C'; + }; + + // Hash naked + text = showdown.helper.replaceRecursiveRegExp(text, repFunc, ']*>', '', 'gim'); + + text = globals.converter._dispatch('hashCodeTags.after', text, options, globals); + return text; +}); + +showdown.subParser('hashElement', function (text, options, globals) { + 'use strict'; + + return function (wholeMatch, m1) { + var blockText = m1; + + // Undo double lines + blockText = blockText.replace(/\n\n/g, '\n'); + blockText = blockText.replace(/^\n/, ''); + + // strip trailing blank lines + blockText = blockText.replace(/\n+$/g, ''); + + // Replace the element text with a marker ("¨KxK" where x is its key) + blockText = '\n\n¨K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n'; + + return blockText; + }; +}); + +showdown.subParser('hashHTMLBlocks', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('hashHTMLBlocks.before', text, options, globals); + + var blockTags = [ + 'pre', + 'div', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'blockquote', + 'table', + 'dl', + 'ol', + 'ul', + 'script', + 'noscript', + 'form', + 'fieldset', + 'iframe', + 'math', + 'style', + 'section', + 'header', + 'footer', + 'nav', + 'article', + 'aside', + 'address', + 'audio', + 'canvas', + 'figure', + 'hgroup', + 'output', + 'video', + 'p' + ], + repFunc = function (wholeMatch, match, left, right) { + var txt = wholeMatch; + // check if this html element is marked as markdown + // if so, it's contents should be parsed as markdown + if (left.search(/\bmarkdown\b/) !== -1) { + txt = left + globals.converter.makeHtml(match) + right; + } + return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n'; + }; + + for (var i = 0; i < blockTags.length; ++i) { + + var opTagPos, + rgx1 = new RegExp('^ {0,3}<' + blockTags[i] + '\\b[^>]*>', 'im'), + patLeft = '<' + blockTags[i] + '\\b[^>]*>', + patRight = ''; + // 1. Look for the first position of the first opening HTML tag in the text + while ((opTagPos = showdown.helper.regexIndexOf(text, rgx1)) !== -1) { + //2. Split the text in that position + var subTexts = showdown.helper.splitAtIndex(text, opTagPos), + //3. Match recursively + newSubText1 = showdown.helper.replaceRecursiveRegExp(subTexts[1], repFunc, patLeft, patRight, 'im'); + + // prevent an infinite loop + if (newSubText1 === subTexts[1]) { + break; + } + text = subTexts[0].concat(newSubText1); + } + } + // HR SPECIAL CASE + text = text.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, + showdown.subParser('hashElement')(text, options, globals)); + + // Special case for standalone HTML comments + text = showdown.helper.replaceRecursiveRegExp(text, function (txt) { + return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n'; + }, '^ {0,3}', 'gm'); + + // PHP and ASP-style processor instructions ( and <%...%>) + text = text.replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, + showdown.subParser('hashElement')(text, options, globals)); + + text = globals.converter._dispatch('hashHTMLBlocks.after', text, options, globals); + return text; +}); + +/** + * Hash span elements that should not be parsed as markdown + */ +showdown.subParser('hashHTMLSpans', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('hashHTMLSpans.before', text, options, globals); + + function hashHTMLSpan (html) { + return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C'; + } + + // Hash Self Closing tags + text = text.replace(/<[^>]+?\/>/gi, function (wm) { + return hashHTMLSpan(wm); + }); + + // Hash tags without properties + text = text.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g, function (wm) { + return hashHTMLSpan(wm); + }); + + // Hash tags with properties + text = text.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g, function (wm) { + return hashHTMLSpan(wm); + }); + + // Hash self closing tags without /> + text = text.replace(/<[^>]+?>/gi, function (wm) { + return hashHTMLSpan(wm); + }); + + /*showdown.helper.matchRecursiveRegExp(text, ']*>', '', 'gi');*/ + + text = globals.converter._dispatch('hashHTMLSpans.after', text, options, globals); + return text; +}); + +/** + * Unhash HTML spans + */ +showdown.subParser('unhashHTMLSpans', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('unhashHTMLSpans.before', text, options, globals); + + for (var i = 0; i < globals.gHtmlSpans.length; ++i) { + var repText = globals.gHtmlSpans[i], + // limiter to prevent infinite loop (assume 10 as limit for recurse) + limit = 0; + + while (/¨C(\d+)C/.test(repText)) { + var num = RegExp.$1; + repText = repText.replace('¨C' + num + 'C', globals.gHtmlSpans[num]); + if (limit === 10) { + break; + } + ++limit; + } + text = text.replace('¨C' + i + 'C', repText); + } + + text = globals.converter._dispatch('unhashHTMLSpans.after', text, options, globals); + return text; +}); + +/** + * Hash and escape
 elements that should not be parsed as markdown
+ */
+showdown.subParser('hashPreCodeTags', function (text, options, globals) {
+  'use strict';
+  text = globals.converter._dispatch('hashPreCodeTags.before', text, options, globals);
+
+  var repFunc = function (wholeMatch, match, left, right) {
+    // encode html entities
+    var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;
+    return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
+  };
+
+  // Hash 

+  text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^ {0,3}]*>\\s*]*>', '^ {0,3}\\s*
', 'gim'); + + text = globals.converter._dispatch('hashPreCodeTags.after', text, options, globals); + return text; +}); + +showdown.subParser('headers', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('headers.before', text, options, globals); + + var headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart), + ghHeaderId = options.ghCompatibleHeaderId, + + // Set text-style headers: + // Header 1 + // ======== + // + // Header 2 + // -------- + // + setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm, + setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm; + + text = text.replace(setextRegexH1, function (wholeMatch, m1) { + + var spanGamut = showdown.subParser('spanGamut')(m1, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"', + hLevel = headerLevelStart, + hashBlock = '' + spanGamut + ''; + return showdown.subParser('hashBlock')(hashBlock, options, globals); + }); + + text = text.replace(setextRegexH2, function (matchFound, m1) { + var spanGamut = showdown.subParser('spanGamut')(m1, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"', + hLevel = headerLevelStart + 1, + hashBlock = '' + spanGamut + ''; + return showdown.subParser('hashBlock')(hashBlock, options, globals); + }); + + // atx-style headers: + // # Header 1 + // ## Header 2 + // ## Header 2 with closing hashes ## + // ... + // ###### Header 6 + // + var atxStyle = (options.requireSpaceBeforeHeadingText) ? /^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm : /^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm; + + text = text.replace(atxStyle, function (wholeMatch, m1, m2) { + var hText = m2; + if (options.customizedHeaderId) { + hText = m2.replace(/\s?\{([^{]+?)}\s*$/, ''); + } + + var span = showdown.subParser('spanGamut')(hText, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"', + hLevel = headerLevelStart - 1 + m1.length, + header = '' + span + ''; + + return showdown.subParser('hashBlock')(header, options, globals); + }); + + function headerId (m) { + var title; + + // It is separate from other options to allow combining prefix and customized + if (options.customizedHeaderId) { + var match = m.match(/\{([^{]+?)}\s*$/); + if (match && match[1]) { + m = match[1]; + } + } + + // Prefix id to prevent causing inadvertent pre-existing style matches. + if (showdown.helper.isString(options.prefixHeaderId)) { + title = options.prefixHeaderId + m; + } else if (options.prefixHeaderId === true) { + title = 'section ' + m; + } else { + title = m; + } + + if (ghHeaderId) { + title = title + .replace(/ /g, '-') + // replace previously escaped chars (&, ¨ and $) + .replace(/&/g, '') + .replace(/¨T/g, '') + .replace(/¨D/g, '') + // replace rest of the chars (&~$ are repeated as they might have been escaped) + // borrowed from github's redcarpet (some they should produce similar results) + .replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g, '') + .toLowerCase(); + } else { + title = title + .replace(/[^\w]/g, '') + .toLowerCase(); + } + + if (globals.hashLinkCounts[title]) { + title = title + '-' + (globals.hashLinkCounts[title]++); + } else { + globals.hashLinkCounts[title] = 1; + } + return title; + } + + text = globals.converter._dispatch('headers.after', text, options, globals); + return text; +}); + +/** + * Turn Markdown link shortcuts into XHTML tags. + */ +showdown.subParser('horizontalRule', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('horizontalRule.before', text, options, globals); + + var key = showdown.subParser('hashBlock')('
', options, globals); + text = text.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm, key); + text = text.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm, key); + text = text.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm, key); + + text = globals.converter._dispatch('horizontalRule.after', text, options, globals); + return text; +}); + +/** + * Turn Markdown image shortcuts into tags. + */ +showdown.subParser('images', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('images.before', text, options, globals); + + var inlineRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g, + crazyRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g, + referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g, + refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g; + + function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) { + + var gUrls = globals.gUrls, + gTitles = globals.gTitles, + gDims = globals.gDimensions; + + linkId = linkId.toLowerCase(); + + if (!title) { + title = ''; + } + // Special case for explicit empty url + if (wholeMatch.search(/\(? ?(['"].*['"])?\)$/m) > -1) { + url = ''; + + } else if (url === '' || url === null) { + if (linkId === '' || linkId === null) { + // lower-case and turn embedded newlines into spaces + linkId = altText.toLowerCase().replace(/ ?\n/g, ' '); + } + url = '#' + linkId; + + if (!showdown.helper.isUndefined(gUrls[linkId])) { + url = gUrls[linkId]; + if (!showdown.helper.isUndefined(gTitles[linkId])) { + title = gTitles[linkId]; + } + if (!showdown.helper.isUndefined(gDims[linkId])) { + width = gDims[linkId].width; + height = gDims[linkId].height; + } + } else { + return wholeMatch; + } + } + + altText = altText + .replace(/"/g, '"') + //altText = showdown.helper.escapeCharacters(altText, '*_', false); + .replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback); + //url = showdown.helper.escapeCharacters(url, '*_', false); + url = url.replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback); + var result = '' + altText + 'x "optional title") + // cases with crazy urls like ./image/cat1).png + text = text.replace(crazyRegExp, writeImageTag); + + // normal cases + text = text.replace(inlineRegExp, writeImageTag); + + // handle reference-style shortcuts: |[img text] + text = text.replace(refShortcutRegExp, writeImageTag); + + text = globals.converter._dispatch('images.after', text, options, globals); + return text; +}); + +showdown.subParser('italicsAndBold', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('italicsAndBold.before', text, options, globals); + + // it's faster to have 3 separate regexes for each case than have just one + // because of backtracing, in some cases, it could lead to an exponential effect + // called "catastrophic backtrace". Ominous! + + function parseInside (txt, left, right) { + if (options.simplifiedAutoLink) { + txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals); + } + return left + txt + right; + } + + // Parse underscores + if (options.literalMidWordUnderscores) { + text = text.replace(/\b___(\S[\s\S]*)___\b/g, function (wm, txt) { + return parseInside (txt, '', ''); + }); + text = text.replace(/\b__(\S[\s\S]*)__\b/g, function (wm, txt) { + return parseInside (txt, '', ''); + }); + text = text.replace(/\b_(\S[\s\S]*?)_\b/g, function (wm, txt) { + return parseInside (txt, '', ''); + }); + } else { + text = text.replace(/___(\S[\s\S]*?)___/g, function (wm, m) { + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + text = text.replace(/__(\S[\s\S]*?)__/g, function (wm, m) { + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + text = text.replace(/_([^\s_][\s\S]*?)_/g, function (wm, m) { + // !/^_[^_]/.test(m) - test if it doesn't start with __ (since it seems redundant, we removed it) + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + } + + // Now parse asterisks + if (options.literalMidWordAsterisks) { + text = text.trim().replace(/(?:^| +)\*{3}(\S[\s\S]*?)\*{3}(?: +|$)/g, function (wm, txt) { + return parseInside (txt, ' ', ' '); + }); + text = text.trim().replace(/(?:^| +)\*{2}(\S[\s\S]*?)\*{2}(?: +|$)/g, function (wm, txt) { + return parseInside (txt, ' ', ' '); + }); + text = text.trim().replace(/(?:^| +)\*{1}(\S[\s\S]*?)\*{1}(?: +|$)/g, function (wm, txt) { + return parseInside (txt, ' ', '' + (wm.slice(-1) === ' ' ? ' ' : '')); + }); + } else { + text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) { + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + text = text.replace(/\*\*(\S[\s\S]*?)\*\*/g, function (wm, m) { + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + text = text.replace(/\*([^\s*][\s\S]*?)\*/g, function (wm, m) { + // !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it) + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + } + + + text = globals.converter._dispatch('italicsAndBold.after', text, options, globals); + return text; +}); + +/** + * Form HTML ordered (numbered) and unordered (bulleted) lists. + */ +showdown.subParser('lists', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('lists.before', text, options, globals); + + /** + * Process the contents of a single ordered or unordered list, splitting it + * into individual list items. + * @param {string} listStr + * @param {boolean} trimTrailing + * @returns {string} + */ + function processListItems (listStr, trimTrailing) { + // The $g_list_level global keeps track of when we're inside a list. + // Each time we enter a list, we increment it; when we leave a list, + // we decrement. If it's zero, we're not in a list anymore. + // + // We do this because when we're not inside a list, we want to treat + // something like this: + // + // I recommend upgrading to version + // 8. Oops, now this line is treated + // as a sub-list. + // + // As a single paragraph, despite the fact that the second line starts + // with a digit-period-space sequence. + // + // Whereas when we're inside a list (or sub-list), that line will be + // treated as the start of a sub-list. What a kludge, huh? This is + // an aspect of Markdown's syntax that's hard to parse perfectly + // without resorting to mind-reading. Perhaps the solution is to + // change the syntax rules such that sub-lists must start with a + // starting cardinal number; e.g. "1." or "a.". + globals.gListLevel++; + + // trim trailing blank lines: + listStr = listStr.replace(/\n{2,}$/, '\n'); + + // attacklab: add sentinel to emulate \z + listStr += '¨0'; + + var rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm, + isParagraphed = (/\n[ \t]*\n(?!¨0)/.test(listStr)); + + // Since version 1.5, nesting sublists requires 4 spaces (or 1 tab) indentation, + // which is a syntax breaking change + // activating this option reverts to old behavior + if (options.disableForced4SpacesIndentedSublists) { + rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm; + } + + listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) { + checked = (checked && checked.trim() !== ''); + + var item = showdown.subParser('outdent')(m4, options, globals), + bulletStyle = ''; + + // Support for github tasklists + if (taskbtn && options.tasklists) { + bulletStyle = ' class="task-list-item" style="list-style-type: none;"'; + item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () { + var otp = '
  • a
  • + // instead of: + //
    • - - a
    + // So, to prevent it, we will put a marker (¨A)in the beginning of the line + // Kind of hackish/monkey patching, but seems more effective than overcomplicating the list parser + item = item.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g, function (wm2) { + return '¨A' + wm2; + }); + + // m1 - Leading line or + // Has a double return (multi paragraph) or + // Has sublist + if (m1 || (item.search(/\n{2,}/) > -1)) { + item = showdown.subParser('githubCodeBlocks')(item, options, globals); + item = showdown.subParser('blockGamut')(item, options, globals); + } else { + // Recursion for sub-lists: + item = showdown.subParser('lists')(item, options, globals); + item = item.replace(/\n$/, ''); // chomp(item) + item = showdown.subParser('hashHTMLBlocks')(item, options, globals); + // Colapse double linebreaks + item = item.replace(/\n\n+/g, '\n\n'); + // replace double linebreaks with a placeholder + item = item.replace(/\n\n/g, '¨B'); + if (isParagraphed) { + item = showdown.subParser('paragraphs')(item, options, globals); + } else { + item = showdown.subParser('spanGamut')(item, options, globals); + } + item = item.replace(/¨B/g, '\n\n'); + } + + // now we need to remove the marker (¨A) + item = item.replace('¨A', ''); + // we can finally wrap the line in list item tags + item = '' + item + '\n'; + + return item; + }); + + // attacklab: strip sentinel + listStr = listStr.replace(/¨0/g, ''); + + globals.gListLevel--; + + if (trimTrailing) { + listStr = listStr.replace(/\s+$/, ''); + } + + return listStr; + } + + /** + * Check and parse consecutive lists (better fix for issue #142) + * @param {string} list + * @param {string} listType + * @param {boolean} trimTrailing + * @returns {string} + */ + function parseConsecutiveLists (list, listType, trimTrailing) { + // check if we caught 2 or more consecutive lists by mistake + // we use the counterRgx, meaning if listType is UL we look for OL and vice versa + var olRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?\d+\.[ \t]/gm : /^ {0,3}\d+\.[ \t]/gm, + ulRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?[*+-][ \t]/gm : /^ {0,3}[*+-][ \t]/gm, + counterRxg = (listType === 'ul') ? olRgx : ulRgx, + result = ''; + + if (list.search(counterRxg) !== -1) { + (function parseCL (txt) { + var pos = txt.search(counterRxg); + if (pos !== -1) { + // slice + result += '\n<' + listType + '>\n' + processListItems(txt.slice(0, pos), !!trimTrailing) + '\n'; + + // invert counterType and listType + listType = (listType === 'ul') ? 'ol' : 'ul'; + counterRxg = (listType === 'ul') ? olRgx : ulRgx; + + //recurse + parseCL(txt.slice(pos)); + } else { + result += '\n<' + listType + '>\n' + processListItems(txt, !!trimTrailing) + '\n'; + } + })(list); + } else { + result = '\n<' + listType + '>\n' + processListItems(list, !!trimTrailing) + '\n'; + } + + return result; + } + + // add sentinel to hack around khtml/safari bug: + // http://bugs.webkit.org/show_bug.cgi?id=11231 + text += '¨0'; + + if (globals.gListLevel) { + text = text.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm, + function (wholeMatch, list, m2) { + var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; + return parseConsecutiveLists(list, listType, true); + } + ); + } else { + text = text.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm, + function (wholeMatch, m1, list, m3) { + var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; + return parseConsecutiveLists(list, listType, false); + } + ); + } + + // strip sentinel + text = text.replace(/¨0/, ''); + text = globals.converter._dispatch('lists.after', text, options, globals); + return text; +}); + +/** + * Remove one level of line-leading tabs or spaces + */ +showdown.subParser('outdent', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('outdent.before', text, options, globals); + + // attacklab: hack around Konqueror 3.5.4 bug: + // "----------bug".replace(/^-/g,"") == "bug" + text = text.replace(/^(\t|[ ]{1,4})/gm, '¨0'); // attacklab: g_tab_width + + // attacklab: clean up hack + text = text.replace(/¨0/g, ''); + + text = globals.converter._dispatch('outdent.after', text, options, globals); + return text; +}); + +/** + * + */ +showdown.subParser('paragraphs', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('paragraphs.before', text, options, globals); + // Strip leading and trailing lines: + text = text.replace(/^\n+/g, ''); + text = text.replace(/\n+$/g, ''); + + var grafs = text.split(/\n{2,}/g), + grafsOut = [], + end = grafs.length; // Wrap

    tags + + for (var i = 0; i < end; i++) { + var str = grafs[i]; + // if this is an HTML marker, copy it + if (str.search(/¨(K|G)(\d+)\1/g) >= 0) { + grafsOut.push(str); + + // test for presence of characters to prevent empty lines being parsed + // as paragraphs (resulting in undesired extra empty paragraphs) + } else if (str.search(/\S/) >= 0) { + str = showdown.subParser('spanGamut')(str, options, globals); + str = str.replace(/^([ \t]*)/g, '

    '); + str += '

    '; + grafsOut.push(str); + } + } + + /** Unhashify HTML blocks */ + end = grafsOut.length; + for (i = 0; i < end; i++) { + var blockText = '', + grafsOutIt = grafsOut[i], + codeFlag = false; + // if this is a marker for an html block... + // use RegExp.test instead of string.search because of QML bug + while (/¨(K|G)(\d+)\1/.test(grafsOutIt)) { + var delim = RegExp.$1, + num = RegExp.$2; + + if (delim === 'K') { + blockText = globals.gHtmlBlocks[num]; + } else { + // we need to check if ghBlock is a false positive + if (codeFlag) { + // use encoded version of all text + blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text, options, globals); + } else { + blockText = globals.ghCodeBlocks[num].codeblock; + } + } + blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs + + grafsOutIt = grafsOutIt.replace(/(\n\n)?¨(K|G)\d+\2(\n\n)?/, blockText); + // Check if grafsOutIt is a pre->code + if (/^]*>\s*]*>/.test(grafsOutIt)) { + codeFlag = true; + } + } + grafsOut[i] = grafsOutIt; + } + text = grafsOut.join('\n'); + // Strip leading and trailing lines: + text = text.replace(/^\n+/g, ''); + text = text.replace(/\n+$/g, ''); + return globals.converter._dispatch('paragraphs.after', text, options, globals); +}); + +/** + * Run extension + */ +showdown.subParser('runExtension', function (ext, text, options, globals) { + 'use strict'; + + if (ext.filter) { + text = ext.filter(text, globals.converter, options); + + } else if (ext.regex) { + // TODO remove this when old extension loading mechanism is deprecated + var re = ext.regex; + if (!(re instanceof RegExp)) { + re = new RegExp(re, 'g'); + } + text = text.replace(re, ext.replace); + } + + return text; +}); + +/** + * These are all the transformations that occur *within* block-level + * tags like paragraphs, headers, and list items. + */ +showdown.subParser('spanGamut', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('spanGamut.before', text, options, globals); + text = showdown.subParser('codeSpans')(text, options, globals); + text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals); + text = showdown.subParser('encodeBackslashEscapes')(text, options, globals); + + // Process anchor and image tags. Images must come first, + // because ![foo][f] looks like an anchor. + text = showdown.subParser('images')(text, options, globals); + text = showdown.subParser('anchors')(text, options, globals); + + // Make links out of things like `` + // Must come after anchors, because you can use < and > + // delimiters in inline links like [this](). + text = showdown.subParser('autoLinks')(text, options, globals); + text = showdown.subParser('italicsAndBold')(text, options, globals); + text = showdown.subParser('strikethrough')(text, options, globals); + text = showdown.subParser('simplifiedAutoLinks')(text, options, globals); + + // we need to hash HTML tags inside spans + text = showdown.subParser('hashHTMLSpans')(text, options, globals); + + // now we encode amps and angles + text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals); + + // Do hard breaks + if (options.simpleLineBreaks) { + // GFM style hard breaks + text = text.replace(/\n/g, '
    \n'); + } else { + // Vanilla hard breaks + text = text.replace(/ +\n/g, '
    \n'); + } + + text = globals.converter._dispatch('spanGamut.after', text, options, globals); + return text; +}); + +showdown.subParser('strikethrough', function (text, options, globals) { + 'use strict'; + + function parseInside (txt) { + if (options.simplifiedAutoLink) { + txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals); + } + return '' + txt + ''; + } + + if (options.strikethrough) { + text = globals.converter._dispatch('strikethrough.before', text, options, globals); + text = text.replace(/(?:~){2}([\s\S]+?)(?:~){2}/g, function (wm, txt) { return parseInside(txt); }); + text = globals.converter._dispatch('strikethrough.after', text, options, globals); + } + + return text; +}); + +/** + * Strips link definitions from text, stores the URLs and titles in + * hash references. + * Link defs are in the form: ^[id]: url "optional title" + */ +showdown.subParser('stripLinkDefinitions', function (text, options, globals) { + 'use strict'; + + var regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm; + + // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug + text += '¨0'; + + text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) { + linkId = linkId.toLowerCase(); + globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url, options, globals); // Link IDs are case-insensitive + + if (blankLines) { + // Oops, found blank lines, so it's not a title. + // Put back the parenthetical statement we stole. + return blankLines + title; + + } else { + if (title) { + globals.gTitles[linkId] = title.replace(/"|'/g, '"'); + } + if (options.parseImgDimensions && width && height) { + globals.gDimensions[linkId] = { + width: width, + height: height + }; + } + } + // Completely remove the definition from the text + return ''; + }); + + // attacklab: strip sentinel + text = text.replace(/¨0/, ''); + + return text; +}); + +showdown.subParser('tables', function (text, options, globals) { + 'use strict'; + + if (!options.tables) { + return text; + } + + var tableRgx = /^ {0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|¨0)/gm; + + function parseStyles (sLine) { + if (/^:[ \t]*--*$/.test(sLine)) { + return ' style="text-align:left;"'; + } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) { + return ' style="text-align:right;"'; + } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) { + return ' style="text-align:center;"'; + } else { + return ''; + } + } + + function parseHeaders (header, style) { + var id = ''; + header = header.trim(); + if (options.tableHeaderId) { + id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"'; + } + header = showdown.subParser('spanGamut')(header, options, globals); + + return '' + header + '\n'; + } + + function parseCells (cell, style) { + var subText = showdown.subParser('spanGamut')(cell, options, globals); + return '' + subText + '\n'; + } + + function buildTable (headers, cells) { + var tb = '\n\n\n', + tblLgn = headers.length; + + for (var i = 0; i < tblLgn; ++i) { + tb += headers[i]; + } + tb += '\n\n\n'; + + for (i = 0; i < cells.length; ++i) { + tb += '\n'; + for (var ii = 0; ii < tblLgn; ++ii) { + tb += cells[i][ii]; + } + tb += '\n'; + } + tb += '\n
    \n'; + return tb; + } + + text = globals.converter._dispatch('tables.before', text, options, globals); + + // find escaped pipe characters + text = text.replace(/\\(\|)/g, showdown.helper.escapeCharactersCallback); + + // parse tables + text = text.replace(tableRgx, function (rawTable) { + + var i, tableLines = rawTable.split('\n'); + + // strip wrong first and last column if wrapped tables are used + for (i = 0; i < tableLines.length; ++i) { + if (/^ {0,3}\|/.test(tableLines[i])) { + tableLines[i] = tableLines[i].replace(/^ {0,3}\|/, ''); + } + if (/\|[ \t]*$/.test(tableLines[i])) { + tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, ''); + } + } + + var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}), + rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}), + rawCells = [], + headers = [], + styles = [], + cells = []; + + tableLines.shift(); + tableLines.shift(); + + for (i = 0; i < tableLines.length; ++i) { + if (tableLines[i].trim() === '') { + continue; + } + rawCells.push( + tableLines[i] + .split('|') + .map(function (s) { + return s.trim(); + }) + ); + } + + if (rawHeaders.length < rawStyles.length) { + return rawTable; + } + + for (i = 0; i < rawStyles.length; ++i) { + styles.push(parseStyles(rawStyles[i])); + } + + for (i = 0; i < rawHeaders.length; ++i) { + if (showdown.helper.isUndefined(styles[i])) { + styles[i] = ''; + } + headers.push(parseHeaders(rawHeaders[i], styles[i])); + } + + for (i = 0; i < rawCells.length; ++i) { + var row = []; + for (var ii = 0; ii < headers.length; ++ii) { + if (showdown.helper.isUndefined(rawCells[i][ii])) { + + } + row.push(parseCells(rawCells[i][ii], styles[ii])); + } + cells.push(row); + } + + return buildTable(headers, cells); + }); + + text = globals.converter._dispatch('tables.after', text, options, globals); + + return text; +}); + +/** + * Swap back in all the special characters we've hidden. + */ +showdown.subParser('unescapeSpecialChars', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('unescapeSpecialChars.before', text, options, globals); + + text = text.replace(/¨E(\d+)E/g, function (wholeMatch, m1) { + var charCodeToReplace = parseInt(m1); + return String.fromCharCode(charCodeToReplace); + }); + + text = globals.converter._dispatch('unescapeSpecialChars.after', text, options, globals); + return text; +}); + +var root = this; + +// CommonJS/nodeJS Loader +if (typeof module !== 'undefined' && module.exports) { + module.exports = showdown; + +// AMD Loader +} else if (true) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { + 'use strict'; + return showdown; + }).call(exports, __webpack_require__, exports, module), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + +// Regular Browser loader +} else { + root.showdown = showdown; +} +}).call(this); + +//# sourceMappingURL=showdown.js.map + + +/***/ }), +/* 22 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Data__ = __webpack_require__(23); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Data", function() { return __WEBPACK_IMPORTED_MODULE_0__Data__["a"]; }); + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBV0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFFBQVEsQ0FBQyJ9 + +/***/ }), +/* 23 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__DataFilters__ = __webpack_require__(66); + +; +class Data { + constructor(data) { + this.data = []; + this.meta = []; + this.import(data); + } + static toDataSet(data, name) { + data = data || [{}]; + const names = Object.keys(data[0]); + const rows = data.map((r) => names.map((n) => r[n])); + return { rows: rows, colNames: names, name: name || undefined }; + } + getName() { + return this.name; + } + import(data) { + this.name = data.name; + this.setData(data.rows, data.colNames); + } + export() { + return { + rows: this.getData(), + colNames: this.colNames() + }; + } + getData() { + return this.data; + } + getColumn(col) { + const cn = this.colNumber(col); + return this.data.map((row) => row[cn]); + } + colAdd(col) { + let m = this.getMeta(col); + if (m === undefined) { + m = this.meta[col] = {}; + m.name = col; + m.column = this.meta.length; + this.meta.push(m); + m.cast = false; + m.accessed = false; + } + return m.column; + } + colInitialize(col, initializer) { + const cn = this.colNumber(col); + if (!cn && typeof col === 'string') { + this.colAdd(col); + } + const fn = typeof initializer === 'function'; + if (cn !== undefined) { + this.data.map((r, i) => r[cn] = fn ? initializer(r[cn], i, r) : initializer); + } + } + colNumber(col) { + const m = this.getMeta(col); + if (!m) { + return undefined; + } + else { + m.accessed = true; + return m.column; + } + } + colName(col) { + var m = this.getMeta(col); + if (!m) { + return undefined; + } + m.accessed = true; + return m.name; + } + colNames() { + return this.meta.map((m) => m.name); + } + colType(col) { + const meta = this.getMeta(col); + return meta ? meta.types[0].type : Data.type.name; + } + findDomain(col, domain) { + if (col === undefined) { + domain[0] = 0; + domain[1] = this.data.length - 1; + } + else { + const c = this.colNumber(col); + const type = this.colType(col); + if (this.data === undefined) { + console.log('no data'); + } + switch (type) { + case Data.type.nominal: + this.data.forEach((r) => { + const nomDom = domain; + if (nomDom.indexOf('' + r[c]) < 0) { + nomDom.push('' + r[c]); + } + }); + break; + default: + this.data.forEach((r) => { + let v = r[c]; + if (v !== undefined && v !== null) { + domain[0] = (v < domain[0]) ? v : domain[0]; + domain[1] = (v > domain[1]) ? v : domain[1]; + } + }); + } + } + } + castData() { + this.meta.forEach((c) => { + const col = c.column; + if (!c.cast) { + this.data.forEach((row) => row[col] = this.castVal(c.types[0].type, row[col])); + } + c.cast = true; + }); + } + filter(condition) { + return Object(__WEBPACK_IMPORTED_MODULE_0__DataFilters__["a" /* filter */])(this, condition); + } + sort(sortFn, col) { + let fn = sortFn; + if (!col) { + this.data.sort(fn); + } + else { + col = this.colNumber(col); + if (sortFn === 'descending') { + fn = (a, b) => (b > a) ? 1 : ((b < a) ? -1 : 0); + } + if (sortFn === 'ascending') { + fn = (a, b) => (b < a) ? 1 : ((b > a) ? -1 : 0); + } + this.data.sort((r1, r2) => fn(r1[col], r2[col])); + } + return this; + } + map(col, mapFn) { + const noop = (val) => val; + const cumulate = () => { + let sum = 0; + return (val, i) => { sum += +val; return sum; }; + }; + function getFn() { + let fn; + switch (mapFn) { + case 'cumulate': + fn = cumulate(); + break; + case 'noop': + fn = noop; + break; + default: fn = mapFn; + } + return fn; + } + let result = new Data({ colNames: this.colNames(), rows: this.data.slice(), name: this.getName() }); + const names = col['length'] ? col : [col]; + names.map((cn) => { + const c = this.colNumber(cn); + let fn = getFn(); + result.data = result.data.map((row, i, rows) => { + row[c] = fn(row[c], c, i, rows); + return row; + }); + }); + return result; + } + getMeta(col) { + if (!this.meta) { + this.meta = []; + } + if (!this.meta[col]) { + return undefined; + } + this.meta[col].accessed = true; + return this.meta[col]; + } + setData(data, names, autoType = true) { + this.meta = []; + this.data = data; + if (!names) { + console.log(); + } + names.forEach((col) => this.colAdd(col)); + names.forEach((col) => this.findTypes(col)); + this.castData(); + } + findTypes(col) { + const m = this.getMeta(col); + const types = []; + Object.keys(Data.type).forEach((t) => { + const ts = { type: Data.type[t], count: 0 }; + types.push(ts); + types[Data.type[t]] = ts; + }); + for (let v of this.allRows(col)) { + const t = this.findType(v); + if (t !== null) { + types[t].count++; + } + } + types.sort(function (a, b) { + if (a.type === 'currency' && a.count > 0) { + return -1; + } + if (b.type === 'currency' && b.count > 0) { + return 1; + } + return b.count - a.count; + }); + m.types = types; + return types[0].type; + } + findType(val) { + if (val && val !== '') { + if (val instanceof Date) { + return Data.type.date; + } + if (typeof val === 'number') { + return Data.type.number; + } + const strVal = '' + val; + if ('' + parseFloat(strVal) === strVal) { + return Data.type.number; + } + if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { + return Data.type.currency; + } + if (strVal.endsWith('%') && !isNaN(parseFloat(strVal))) { + return Data.type.percent; + } + if (!isNaN(this.toDate(strVal).getTime())) { + return Data.type.date; + } + if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { + if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { + return Data.type.currency; + } + } + switch (strVal.toLowerCase()) { + case "null": break; + case "#ref!": break; + default: if (val.length > 0) { + return Data.type.nominal; + } + } + } + return null; + } + *allRows(column) { + const c = this.colNumber(column); + for (let r = 0; r < this.data.length; r++) { + yield this.data[r][c]; + } + } + toDate(val, limitYear = 1970) { + let d; + if (val instanceof Date) { + d = val; + } + else { + d = new Date(val); + } + let yr = d.getFullYear(); + if (yr < 100) { + yr += 1900; + d.setFullYear((yr < limitYear) ? yr + 100 : yr); + } + return d; + } + castVal(type, val) { + switch (type) { + case Data.type.date: + if (val instanceof Date) { + return val; + } + val = this.toDate(val); + if (isNaN(val.getTime())) { + val = null; + } + break; + case Data.type.percent: + if (typeof val === 'string') { + const num = parseFloat(val); + val = val.endsWith('%') ? num / 100 : num; + } + if (isNaN(val)) { + val = null; + } + break; + case Data.type.currency: + if (typeof val === 'string') { + val = val.replace(/[^eE\+\-\.\d]/g, ''); + } + case Data.type.number: + if (typeof val === 'string') { + val = parseFloat(val); + } + if (isNaN(val)) { + val = null; + } + break; + default: val = '' + val; + } + return val; + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Data; + +Data.type = { + number: 'number data', + name: 'name data', + date: 'date data', + currency: 'currency data', + percent: 'percent data', + nominal: 'nominal data' +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGF0YS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9EYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLE9BQU8sRUFBYSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUF1Q0UsQ0FBQztBQWtCckQsTUFBTTtJQXFCRixZQUFZLElBQWE7UUEwU2pCLFNBQUksR0FBaUIsRUFBRSxDQUFDO1FBQ3hCLFNBQUksR0FBaUIsRUFBRSxDQUFDO1FBMVM1QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3RCLENBQUM7SUFWTSxNQUFNLENBQUMsU0FBUyxDQUFDLElBQW1CLEVBQUUsSUFBWTtRQUNyRCxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDcEIsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBSyxFQUFFLEVBQUUsQ0FDNUIsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQyxPQUFPLEVBQUUsSUFBSSxFQUFDLElBQUksRUFBRSxRQUFRLEVBQUMsS0FBSyxFQUFFLElBQUksRUFBQyxJQUFJLElBQUUsU0FBUyxFQUFFLENBQUM7SUFDL0QsQ0FBQztJQVNNLE9BQU87UUFDVixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDckIsQ0FBQztJQU1NLE1BQU0sQ0FBQyxJQUFZO1FBQ3RCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFLTSxN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 + +/***/ }), +/* 24 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Axes__ = __webpack_require__(9); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_hsutil__ = __webpack_require__(2); + + +function addTickNumber(t, v) { + t.labels.push({ pos: v, text: '' + Math.round(v * 1000000) / 1000000 }); +} +function addTickDate(t, v, fmt) { + t.labels.push({ pos: v.getTime(), text: Object(__WEBPACK_IMPORTED_MODULE_1_hsutil__["date"])(fmt, v) }); +} +function linScaleTickMarks(dom, ticks, numTicks) { + function addTicks(unit, ticks) { + let exp = Math.pow(10, Math.floor(Math.log10(unit))); + unit = Math.floor(unit / exp) * exp; + const min = Math.floor(dom[0] / unit) * unit; + const max = Math.ceil(dom[1] / unit) * unit; + for (let v = min; v <= max; v += unit) { + addTickNumber(ticks, v); + } + return unit; + } + const majorUnit = addTicks((dom[1] - dom[0]) / numTicks, ticks.major); + addTicks(majorUnit / numTicks, ticks.minor); +} +function percentScaleTickMarks(dom, ticks, numTicks) { + const formatPercent = (m) => m.text = `${Math.round(m.pos) * 100}%`; + linScaleTickMarks(dom, ticks, numTicks); + ticks.major.labels.forEach(formatPercent); + ticks.minor.labels.forEach(formatPercent); +} +function logScaleTickMarks(dom, ticks) { + dom[0] = Math.max(dom[0], 1e-20); + dom[1] = Math.max(dom[1], 1e-20); + let dif = Math.pow(10, Math.floor(Math.log10(dom[1] - dom[0]))); + let min = Math.pow(10, Math.floor(Math.log10(dom[0]))); + let max = Math.pow(10, Math.ceil(Math.log10(dom[1]))); + if (dif > min) { + for (let v = min; v <= max; v *= 10) { + for (let i = 1; i <= 20; i++) { + if (i === 1 && v * i < max) { + addTickNumber(ticks.major, v * i); + } + else if (i % 10 === 0) { } + else if (i < 10) { + addTickNumber(ticks.minor, v * i); + } + else if (i % 2 === 0) { + addTickNumber(ticks.minor, v * i); + } + } + } + } + else { + min = Math.floor(dom[0] / dif) * dif; + max = Math.ceil(dom[1] / dif) * dif; + if ((max - min) / dif < 4) { + dif /= 2; + } + for (let v = min; v <= max; v += dif) { + addTickNumber(ticks.major, v); + } + addTickNumber(ticks.major, min); + addTickNumber(ticks.major, max); + } +} +const tickCategories = [ + [10, 0, 0, 0], [5, 0, 0, 0], [2, 0, 0, 0], [1, 0, 0, 0], [0, 6, 0, 0], [0, 3, 0, 0], [0, 1, 0, 0], [0, 0, 7, 0], [0, 0, 1, 0], [0, 0, 0, 4], [0, 0, 0, 1] +]; +function dateScaleTickMarks(dom, ticks, fmt = '%MM/%DD/%YY') { + function addDates(i, tickDefs) { + const createDate = (idx) => new Date(Math.floor(dateDom[idx].getFullYear() / modYr) * modYr + (idx ? incYr : 0), (incYr > 0) ? 0 : Math.floor(dateDom[idx].getMonth() / modMo) * modMo + (idx ? incMo : 0), (incMo > 0) ? 1 : (dateDom[idx].getDate() - ((incDay === 7) ? dateDom[idx].getDay() : 0)) + (idx ? incDay : 0), (incDay > 0) ? 0 : (dateDom[idx].getHours()) + (idx ? incHour : 0)); + const incYr = tickCategories[i][0]; + const incMo = tickCategories[i][1]; + const incDay = tickCategories[i][2]; + const incHour = tickCategories[i][3]; + const modYr = incYr || 1; + const modMo = incMo || 1; + const date0 = createDate(0); + const date1 = createDate(1); + fmt = incHour ? '%hh:%mm' : '%MM/%DD/%YY'; + for (let d = date0; d <= date1; d = new Date(d.getFullYear() + incYr, d.getMonth() + incMo, d.getDate() + incDay, d.getHours() + incHour)) { + addTickDate(tickDefs, d, fmt); + } + } + const dateDom = [ + (typeof dom[0] === 'number') ? new Date(dom[0]) : dom[0], + (typeof dom[1] === 'number') ? new Date(dom[1]) : dom[1] + ]; + if (isNaN(dateDom[0].getTime())) { + dateDom[0] = new Date('1/1/1980'); + } + if (isNaN(dateDom[1].getTime())) { + dateDom[0] = new Date(); + } + const d = dateDom[1].getTime() - dateDom[0].getTime(); + tickCategories.some((cat, i) => { + const dMin = __WEBPACK_IMPORTED_MODULE_1_hsutil__["ms"].fromDays((cat[0] * 365 + cat[1] * 30 + cat[2])) + __WEBPACK_IMPORTED_MODULE_1_hsutil__["ms"].fromHours(cat[3]); + if (d > 3 * dMin) { + addDates(i, ticks.major); + addDates(Math.min(i + 1, tickCategories.length - 1), ticks.minor); + return true; + } + else { + return false; + } + }); +} +function createTickLabels(type, domain, numTicks, fmt) { + const sort = (a, b) => a.pos - b.pos; + function sortTicks() { + ticks.minor.labels.sort(sort); + ticks.major.labels.sort(sort); + } + ; + const dom = [domain[0], domain[1]]; + const ticks = { + major: { marks: [], labels: [] }, + minor: { marks: [], labels: [] } + }; + switch (type) { + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: + logScaleTickMarks(dom, ticks); + sortTicks(); + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: + dateScaleTickMarks(dom, ticks, fmt); + sortTicks(); + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: + percentScaleTickMarks(dom, ticks, numTicks); + sortTicks(); + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: + default: + linScaleTickMarks(dom, ticks, numTicks); + sortTicks(); + } + return ticks; +} +class Scale { + constructor(cfg) { + this.cfg = cfg; + this.typeVal = __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear; + this.rangeVal = [0, 1]; + this.domVal = [0, 1]; + this.domMinAuto = 0; + this.domMaxAuto = 0; + this.scaleType(cfg.type); + this.domain(cfg.domain); + } + setLabelFormat(labelFmt) { + this.labelFmt = labelFmt; + } + range(r) { + if (r) { + this.rangeVal = r; + } + return this.rangeVal; + } + domain(dom) { + if (dom) { + if (this.scaleType() === __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date) { + if (typeof dom[0] === 'string' || typeof dom[1] === 'string') { + this.domVal[0] = (dom[0] === 'auto') ? 0 : Date.parse(dom[0]); + this.domVal[1] = (dom[1] === 'auto') ? 1 : Date.parse(dom[1]); + } + } + else { + this.domVal[0] = (dom[0] === 'auto') ? 0 : dom[0]; + this.domVal[1] = (dom[1] === 'auto') ? 1 : dom[1]; + } + switch (dom[0]) { + case 'tight': + this.domMinAuto = 2; + break; + case 'auto': + this.domMinAuto = 1; + break; + default: this.domMinAuto = 0; + } + switch (dom[1]) { + case 'tight': + this.domMaxAuto = 2; + break; + case 'auto': + this.domMaxAuto = 1; + break; + default: this.domMaxAuto = 0; + } + } + if (this.typeVal === __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log) { + if (this.domVal[1] <= 0) { + this.domVal[1] = 10; + } + if (this.domVal[0] <= 0) { + this.domVal[0] = this.domVal[1] / 10; + } + } + return this.domVal; + } + scaleType(s) { + if (s) { + this.typeVal = s; + } + return this.typeVal; + } + setAutoDomain(dom) { + const ticks = createTickLabels(this.scaleType(), dom, 4, this.labelFmt); + switch (this.domMinAuto) { + case 1: + this.domVal[0] = ticks.major.labels[0] ? ticks.major.labels[0].pos : dom[0]; + break; + case 2: + this.domVal[0] = dom[0]; + break; + } + switch (this.domMaxAuto) { + case 1: + this.domVal[1] = ticks.major.labels[ticks.major.labels.length - 1].pos; + break; + case 2: + this.domVal[1] = dom[1]; + break; + } + } + ticks(numTicks = 4) { + function marksFromLabels(ticks, type) { + switch (type) { + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: + const numLabels = ticks.major.labels.length; + ticks.major.marks = Array(numLabels + 1).fill(1).map((e, i) => i - 0.5); + ticks.minor.marks = ticks.minor.labels ? ticks.minor.labels.map((l) => l.pos) : []; + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: + default: + ticks.major.marks = ticks.major.labels ? ticks.major.labels.map((l) => l.pos) : []; + ticks.minor.marks = ticks.minor.labels ? ticks.minor.labels.map((l) => l.pos) : []; + } + } + const dom = [this.domain()[0], this.domain()[1]]; + const inRange = (t) => t.pos >= dom[0] && t.pos <= dom[1]; + const ticks = createTickLabels(this.scaleType(), this.domain(), numTicks, this.labelFmt); + ticks.minor.labels = ticks.minor.labels.filter(inRange); + ticks.major.labels = ticks.major.labels.filter(inRange); + if (ticks.major.labels.length === 0) { + ticks.major.labels = ticks.minor.labels; + ticks.minor.labels = []; + } + marksFromLabels(ticks, this.scaleType()); + return ticks; + } + convert(domVal) { + const dom = this.domain(); + const range = this.range(); + const domMin = dom[0]; + const domMax = dom[1]; + let result; + switch (this.scaleType()) { + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: + result = Math.log(domVal / domMin) / Math.log(domMax / domMin) * (range[1] - range[0]) + range[0]; + break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: break; + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: + case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: + default: + result = (domVal - domMin) / (domMax - domMin) * (range[1] - range[0]) + range[0]; + } + return result; + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Scale; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2NhbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvU2NhbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFjLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxNQUFVLFFBQVEsQ0FBQztBQU90Qyx1QkFBdUIsQ0FBVSxFQUFFLENBQVE7SUFDdkMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUMsT0FBTyxDQUFDLEdBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztBQUN0RSxDQUFDO0FBRUQscUJBQXFCLENBQVUsRUFBRSxDQUFNLEVBQUUsR0FBVTtJQUMvQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQzNELENBQUM7QUFJRCwyQkFBMkIsR0FBWSxFQUFFLEtBQVcsRUFBRSxRQUFlO0lBQ2pFLGtCQUFrQixJQUFXLEVBQUUsS0FBYztRQUN6QyxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JELElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxHQUFHLENBQUMsR0FBQyxHQUFHLENBQUM7UUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUMsSUFBSSxDQUFDO1FBQ3pDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQztRQUN4QyxLQUFLLElBQUksQ0FBQyxHQUFDLEdBQUcsRUFBRSxDQUFDLElBQUUsR0FBRyxFQUFFLENBQUMsSUFBRSxJQUFJLEVBQUU7WUFBRSxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQUU7UUFDN0QsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUNELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RFLFFBQVEsQ0FBQyxTQUFTLEdBQUcsUUFBUSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNoRCxDQUFDO0FBRUQsK0JBQStCLEdBQVksRUFBRSxLQUFXLEVBQUUsUUFBZTtJQUNyRSxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFDLEdBQUcsR0FBRyxDQUFDO0lBQzVFLGlCQUFpQixDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDeEMsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQzFDLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUU5QyxDQUFDO0FBRUQsMkJBQTJCLEdBQVksRUFBRSxLQUFXO0lBQ2hELEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNqQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDakMsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEUsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2RCxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RELElBQUksR0FBRyxHQUFHLEdBQUcsRUFBRTtRQUNYLEtBQUssSUFBSSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFFLEVBQUUsRUFBRTtZQUM3QixLQUFLLElBQUksQ0FBQyxHQUFDLENBQUMsRUFBRSxDQUFDLElBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN0QixJQUFJLENBQUMsS0FBRyxDQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsR0FBQyxHQUFHLEVBQUU7b0JBQUUsYUFBYSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUFFO3FCQUNyRCxJQUFJLENBQUMsR0FBQyxFQUFFLEtBQUcsQ0FBQyxFQUFFLEdBQUU7cUJBQ2hCLElBQUksQ0FBQyxHQUFDLEVB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 + +/***/ }), +/* 25 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); + + +class Grid extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { + static defaultConfig(cfg) { + cfg.grid = { + major: { + hor: { visible: true }, + ver: { visible: true } + }, + minor: { + hor: { visible: false }, + ver: { visible: false } + } + }; + } + static adjustConfig(cfg) { + } + drawHorGrid(cfg, scale, range, ticks) { + return !cfg.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-hor' }, ticks.marks.map((t) => this.horLine(range[0], range[1], scale.convert(t)))); + } + drawVerGrid(cfg, scale, range, ticks) { + return !cfg.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-ver' }, ticks.marks.map((t) => this.verLine(scale.convert(t), range[0], range[1]))); + } + view(node) { + const cfg = node.attrs.cfg; + const scales = node.attrs.scales; + const ps = scales.primary; + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid' }, [ + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-minor' }, [ + this.drawHorGrid(cfg.minor.hor, ps.y, ps.x.range(), ps.y.ticks().minor), + this.drawVerGrid(cfg.minor.ver, ps.x, ps.y.range(), ps.x.ticks().minor) + ]), + Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-major' }, [ + this.drawHorGrid(cfg.major.hor, ps.y, ps.x.range(), ps.y.ticks().major), + this.drawVerGrid(cfg.major.ver, ps.x, ps.y.range(), ps.x.ticks().major) + ]) + ]); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Grid; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR3JpZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9HcmlkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlCQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQVcsVUFBVSxDQUFDO0FBR3hDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBVyxXQUFXLENBQUM7QUF5QnpDLE1BQU0sV0FBWSxTQUFRLE9BQU87SUFxQjdCLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVTtRQUMzQixHQUFHLENBQUMsSUFBSSxHQUFnQjtZQUNwQixLQUFLLEVBQUU7Z0JBQ0gsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFDLElBQUksRUFBRTtnQkFDckIsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFDLElBQUksRUFBRTthQUN4QjtZQUNELEtBQUssRUFBRTtnQkFDSCxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUMsS0FBSyxFQUFFO2dCQUN0QixHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUMsS0FBSyxFQUFFO2FBQ3pCO1NBQ0osQ0FBQztJQUNOLENBQUM7SUFNRCxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQVU7SUFDOUIsQ0FBQztJQUtPLFdBQVcsQ0FBQyxHQUFxQixFQUFFLEtBQVcsRUFBRSxLQUFjLEVBQUUsS0FBYztRQUNsRixPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLG1CQUFtQixFQUFFLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUMxRixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUNyRCxDQUFDLENBQUM7SUFDUCxDQUFDO0lBS08sV0FBVyxDQUFDLEdBQXFCLEVBQUUsS0FBVyxFQUFFLEtBQWMsRUFBRSxLQUFjO1FBQ2xGLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMsbUJBQW1CLEVBQUUsRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQzFGLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQ3JELENBQUMsQ0FBQztJQUNQLENBQUM7SUFHRCxJQUFJLENBQUMsSUFBWTtRQUNiLE1BQU0sR0FBRyxHQUFlLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO1FBQ3ZDLE1BQU0sTUFBTSxHQUFVLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQ3hDLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFDMUIsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLGVBQWUsRUFBQyxFQUFFO1lBQ3RDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMscUJBQXFCLEVBQUUsRUFBRTtnQkFDdEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLENBQUM7Z0JBQ3ZFLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDO2FBQzFFLENBQUM7WUFDRixDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLHFCQUFxQixFQUFFLEVBQUU7Z0JBQ3RDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDO2dCQUN2RSxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLEtBQUssQ0FBQzthQUMxRSxDQUFDO1NBQ0wsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztDQUNKIn0= + +/***/ }), +/* 26 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); + +; +class Legend { + static defaultConfig(cfg) { + cfg.legend = {}; + } + static adjustConfig(cfg) { + } + view(node) { + return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-legend', width: '100%', height: '100%' }); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Legend; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGVnZW5kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0xlZ2VuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFnQkEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFPLFVBQVUsQ0FBQztBQU9uQyxDQUFDO0FBRUYsTUFBTTtJQWFGLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVTtRQUMzQixHQUFHLENBQUMsTUFBTSxHQUFpQixFQUMxQixDQUFDO0lBQ04sQ0FBQztJQU1ELE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBVTtJQUU5QixDQUFDO0lBRUQsSUFBSSxDQUFDLElBQVk7UUFDYixPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMsaUJBQWlCLEVBQUUsS0FBSyxFQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQztJQUM3RSxDQUFDO0NBQ0oifQ== + +/***/ }), +/* 27 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Site__ = __webpack_require__(28); + +Object(__WEBPACK_IMPORTED_MODULE_0__Site__["a" /* init */])(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBS0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUU5QixJQUFJLEVBQUUsQ0FBQyJ9 + +/***/ }), +/* 28 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = init; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__view_DocsMenu__ = __webpack_require__(45); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__view_LeftNav__ = __webpack_require__(52); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__view_MainDetail__ = __webpack_require__(54); + + + + +const TitleHeight = '30px'; +const FooterHeight = '10px'; +const LeftNavWidth = '200px'; +const SiteName = 'HSDocs'; +const myConfig = { + Layout: { + rows: [TitleHeight, "fill", FooterHeight], + css: '.hs-site', + content: [{ + Layout: { + columns: [LeftNavWidth, "fill"], + css: '.hs-site-header', + content: [ + { Layout: { + css: '.hs-site-title', + content: SiteName, + href: '/api/' + } }, + { DocsMenu: { docSet: "./data/index.json" } } + ] + } + }, { + Layout: { + columns: [LeftNavWidth, "fill"], + content: [ + { LeftNav: {} }, + { MainDetail: {} } + ] + } + }, + { Layout: { + css: '.hs-site-footer', + content: '(c) Helpful Scripts' + } } + ] + }, + route: { + default: '/api', + paths: [ + '/api', + '/api/:lib', + '/api/:lib/:field' + ] + } +}; +function init() { + new __WEBPACK_IMPORTED_MODULE_0_hslayout__["HsConfig"]([__WEBPACK_IMPORTED_MODULE_0_hslayout__, __WEBPACK_IMPORTED_MODULE_1__view_DocsMenu__, __WEBPACK_IMPORTED_MODULE_2__view_LeftNav__, __WEBPACK_IMPORTED_MODULE_3__view_MainDetail__]).attachNodeTree(myConfig, document.body); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2l0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9TaXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sS0FBSyxRQUFRLE1BQU8sVUFBVSxDQUFDO0FBQ3RDLE9BQU8sS0FBSyxNQUFNLE1BQU8saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxLQUFLLElBQUksTUFBUyxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEtBQUssSUFBSSxNQUFTLG1CQUFtQixDQUFDO0FBRzdDLE1BQU0sV0FBVyxHQUFLLE1BQU0sQ0FBQztBQUM3QixNQUFNLFlBQVksR0FBSSxNQUFNLENBQUM7QUFDN0IsTUFBTSxZQUFZLEdBQUksT0FBTyxDQUFDO0FBQzlCLE1BQU0sUUFBUSxHQUFRLFFBQVEsQ0FBQztBQUUvQixNQUFNLFFBQVEsR0FBRztJQUNiLE1BQU0sRUFBRTtRQUNKLElBQUksRUFBRyxDQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsWUFBWSxDQUFDO1FBQzFDLEdBQUcsRUFBRSxVQUFVO1FBQ2YsT0FBTyxFQUFFLENBQUM7Z0JBQ04sTUFBTSxFQUFDO29CQUNILE9BQU8sRUFBRSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUM7b0JBQy9CLEdBQUcsRUFBRSxpQkFBaUI7b0JBQ3RCLE9BQU8sRUFBRTt3QkFDTCxFQUFFLE1BQU0sRUFBSztnQ0FDVCxHQUFHLEVBQUUsZ0JBQWdCO2dDQUNyQixPQUFPLEVBQUUsUUFBUTtnQ0FDakIsSUFBSSxFQUFDLE9BQU87NkJBQ2YsRUFBQzt3QkFDRixFQUFFLFFBQVEsRUFBSyxFQUFFLE1BQU0sRUFBQyxtQkFBbUIsRUFBQyxFQUFDO3FCQUNoRDtpQkFDSjthQUFDLEVBQUM7Z0JBQ0gsTUFBTSxFQUFDO29CQUNILE9BQU8sRUFBRSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUM7b0JBQy9CLE9BQU8sRUFBRTt3QkFDTCxFQUFFLE9BQU8sRUFBSyxFQUFFLEVBQUM7d0JBQ2pCLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBQztxQkFDcEI7aUJBQ0o7YUFBQztZQUNGLEVBQUUsTUFBTSxFQUFFO29CQUNOLEdBQUcsRUFBRSxpQkFBaUI7b0JBQ3RCLE9BQU8sRUFBRSxxQkFBcUI7aUJBQ2pDLEVBQUM7U0FDTDtLQUNKO0lBQ0QsS0FBSyxFQUFFO1FBQ0gsT0FBTyxFQUFFLE1BQU07UUFDZixLQUFLLEVBQUU7WUFDSCxNQUFNO1lBQ04sV0FBVztZQUNYLGtCQUFrQjtTQUNyQjtLQUNKO0NBQ0osQ0FBQztBQUdGLE1BQU07SUFDRixJQUFJLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2xHLENBQUMifQ== + +/***/ }), +/* 29 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Layouter__ = __webpack_require__(4); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tokens__ = __webpack_require__(5); + + +const PillarLayouts = [ + 'columns', 'rows' +]; +/* harmony export (immutable) */ __webpack_exports__["PillarLayouts"] = PillarLayouts; + +const cParams = { + columns: { + cssClass: '.hs-column-layout', + fields: ['top', 'bottom', 'left', 'right', 'height', 'width'] + }, + rows: { + cssClass: '.hs-row-layout', + fields: ['left', 'right', 'top', 'bottom', 'width', 'height'] + } +}; +class PillarLayouter extends __WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */] { + constructor(params, areaDesc) { + super(areaDesc); + this.areaDesc = areaDesc; + this.fields = params.fields; + this.cssClass = params.cssClass; + let n = areaDesc.length - 1; + let first = 0; + let last = 0; + this.unit = areaDesc.some((area) => (area instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["e" /* PixelToken */])) ? + this.unitPixel : this.unitPercent; + areaDesc.some((area, i) => ((areaDesc[i] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? ++first < 0 : true)); + areaDesc.some((area, i) => ((areaDesc[n - i] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? ++last < 0 : true)); + this.firstFixed = first; + this.lastFixed = Math.min(last, areaDesc.length - first); + } + ; + getSizes(num) { + const first = this.firstFixed; + const last = this.lastFixed; + const desc = this.areaDesc; + const len = desc.length; + return [...Array(num).keys()].map((i) => { + let size = null; + let t = null; + if (i > num - 1 - last) { + size = desc[len - (num - i)].getSize(); + t = 'end'; + } + else if (i < first) { + size = desc[i].getSize(); + t = 'start'; + } + else if (len > 0 && len === first) { + size = desc[len - 1].getSize(); + t = 'start'; + } + return { size: size, code: t, fields: {} }; + }); + } + unitPercent(num) { + let f = this.fields; + let max = 100.0; + let styles = this.getSizes(num); + styles.forEach(style => { if (style.size) { + max = max - style.size; + num--; + } }); + let defDim = max / num; + function pass(styles, ix0, ix1, breakCond) { + let sumDim = 0; + styles.some(style => { + let size = style.size || defDim; + if (breakCond(style.code)) { + return true; + } + style.fields[ix0] = sumDim + '%'; + sumDim += size; + style.fields[ix1] = (100 - sumDim) + '%'; + style.fields[f[5]] = 'auto'; + return false; + }); + } + pass(styles, f[2], f[3], (e) => e === 'end'); + pass(styles.reverse(), f[3], f[2], (e) => e !== 'end'); + return styles.reverse(); + } + ; + unitPixel(num) { + let styles = this.getSizes(num); + let f = this.fields; + let defDim = 100.0 / num; + let sumDim = 0; + styles.some((style, i) => { + if (style.code === 'start') { + style.fields[f[2]] = sumDim + 'px'; + sumDim += style.size + (this.spacing || 0) + (this.spacing || 0); + style.fields[f[3]] = 'auto'; + style.fields[f[5]] = style.size + 'px'; + } + else if (style.code === null) { + style.fields[f[2]] = (sumDim > 0) ? (sumDim + 'px') : (i * defDim + '%'); + sumDim = -1; + style.fields[f[3]] = (100 - (i + 1) * defDim) + '%'; + style.fields[f[5]] = 'auto'; + } + else if (style.code === 'end') { + return true; + } + return false; + }); + sumDim = 0; + styles.slice().reverse().some((style, i) => { + style.fields[f[3]] = sumDim + 'px'; + if (style.code === 'end') { + sumDim += style.size + (this.spacing || 0) + (this.spacing || 0); + style.fields[f[2]] = 'auto'; + style.fields[f[5]] = style.size + 'px'; + } + else { + if (sumDim > 0 && style.code !== 'start') { + style.fields[f[5]] = 'auto'; + } + return true; + } + return false; + }); + return styles; + } + ; + getStyles(components) { + let f = this.fields; + let styles = this.unit(components.length); + components.map((c, i) => { + c.style = `${f[0]}:0%; ${f[1]}:0%; `; + Object.keys(styles[i].fields).forEach((st) => { c.style += `${st}: ${styles[i].fields[st]};`; }); + }); + return this.cssClass; + } + ; +} +; +class Columns extends PillarLayouter { + constructor(areaDesc) { + super(cParams[PillarLayouts[0]], areaDesc); + this.areaDesc = areaDesc; + } + ; +} +; +class Rows extends PillarLayouter { + constructor(areaDesc) { + super(cParams[PillarLayouts[1]], areaDesc); + this.areaDesc = areaDesc; + } + ; +} +; +__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register(PillarLayouts[0], Columns); +__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register(PillarLayouts[1], Rows); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGlsbGFyZWRMYXlvdXRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy92aWV3L1BpbGxhcmVkTGF5b3V0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBMkNBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBWSxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUFlLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBUyxVQUFVLENBQUM7QUFnQnBFLE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRztJQUN6QixTQUFTLEVBQUUsTUFBTTtDQUNwQixDQUFDO0FBS0YsTUFBTSxPQUFPLEdBQUc7SUFDWixPQUFPLEVBQWdCO1FBQ25CLFFBQVEsRUFBRSxtQkFBbUI7UUFDN0IsTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUM7S0FDaEU7SUFDRCxJQUFJLEVBQWdCO1FBQ2hCLFFBQVEsRUFBRSxnQkFBZ0I7UUFDMUIsTUFBTSxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUM7S0FDaEU7Q0FDSixDQUFDO0FBT0Ysb0JBQThCLFNBQVEsUUFBUTtJQWExQyxZQUFZLE1BQW1CLEVBQVMsUUFBc0I7UUFDMUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRG9CLGFBQVEsR0FBUixRQUFRLENBQWM7UUFFMUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzVCLElBQUksQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztRQUVoQyxJQUFJLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQztRQUMxQixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxJQUFJLElBQUksR0FBSSxDQUFDLENBQUM7UUFFZCxJQUFJLENBQUMsSUFB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 + +/***/ }), +/* 30 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Layouter__ = __webpack_require__(4); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tokens__ = __webpack_require__(5); + + +class Tiles extends __WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */] { + constructor(areaDesc) { + super(areaDesc); + this.areaDesc = areaDesc; + this.unit = areaDesc.some((area) => (area instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["e" /* PixelToken */])) ? + this.unitPixel : this.unitPercent; + } + ; + unitPercent(num) { + const desc = this.areaDesc; + const fill = this.areaDesc.some(a => (a instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["c" /* FillToken */])); + const root = Math.sqrt(num); + const rows = Math.round(root); + let cols = Math.floor(root); + if (root > cols) { + cols++; + } + let width = (desc[0] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[0].getSize() : undefined; + let height = (desc[1] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[1].getSize() : width; + width = width || 100 / cols; + height = height || 100 / rows; + let left = 0; + let top = 0; + let styles = [...Array(num).keys()].map(i => { + let r = 'auto'; + let w = width + '%'; + let b = 'auto'; + let h = height + '%'; + if ((left + 2 * width) > 100 && fill) { + r = '0%'; + w = 'auto'; + } + if ((top + 2 * height) > 100 && fill) { + b = '0%'; + h = 'auto'; + } + const style = ` + top: ${Math.floor(top)}%; bottom:${b}; + left: ${left}%; right:${r}; + width: ${w}; height: ${h}; + `; + if (Math.round(left += width) > 100 - Math.floor(width)) { + left = 0; + top += height; + } + return style; + }); + return styles; + } + ; + unitPixel(num) { + const desc = this.areaDesc; + const root = Math.sqrt(num); + const rows = Math.round(root); + let cols = Math.floor(root); + if (root > cols) { + cols++; + } + let width = (desc[0] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[0].getSize() : undefined; + let height = (desc[1] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[1].getSize() : width; + width = width || 100 / cols; + height = height || 100 / rows; + let left = 0; + let top = 0; + let styles = [...Array(num).keys()].map(i => { + let r = 'auto'; + let w = width + 'px'; + let b = 'auto'; + let h = height + 'px'; + const style = ` + top: ${Math.floor(top)}%; bottom:${b}; + left: ${left}%; right:${r}; + width: ${w}; height: ${h}; + `; + if (Math.round(left += width) > 100 - Math.floor(width)) { + left = 0; + top += height; + } + return style; + }); + return styles; + } + ; + getStyles(components) { + let styles = this.unit(components.length); + components.map((c, i) => { + c.style = styles[i]; + }); + return '.hs-tile-layout'; + } + ; +} +; +__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register('tiles', Tiles); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGlsZUxheW91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvVGlsZUxheW91dGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZEQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVksWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBZSxTQUFTLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFTLFVBQVUsQ0FBQztBQU8vRSxXQUFZLFNBQVEsUUFBUTtJQVF4QixZQUFtQixRQUFzQjtRQUNyQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFERCxhQUFRLEdBQVIsUUFBUSxDQUFjO1FBSXJDLElBQUksQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQWdCLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxZQUFZLFVBQVUsQ0FBQyxDQUFDLENBQUEsQ0FBQztZQUMxRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFDLENBQUM7SUFBQSxDQUFDO0lBRU0sV0FBVyxDQUFDLEdBQVU7UUFDMUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUMzQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxZQUFZLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDL0QsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzlCLElBQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDOUIsSUFBSSxJQUFJLEdBQUcsSUFBSSxFQUFFO1lBQUUsSUFBSSxFQUFFLENBQUM7U0FB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 + +/***/ }), +/* 31 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__mithril__ = __webpack_require__(11); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Layouter__ = __webpack_require__(4); + + +class Layout { + getComponents(node) { + return !Array.isArray(node.attrs.content) ? node.attrs.content : + node.attrs.content.map((c) => { + if (c.compClass) { + c.attrs.route = node.attrs.route; + return Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(c.compClass, c.attrs); + } + else { + return c; + } + }); + } + getCSS(node) { + return node.attrs.css || ''; + } + normalizeContent(components) { + if (typeof components === 'string') { + return [Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])('.hs-leaf', __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].trust(components))]; + } + if (components.length > 0) { + return components.map((comp) => (comp instanceof Layout) ? comp : Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(Layout, { content: comp })); + } + return [components]; + } + view(node) { + const content = this.normalizeContent(this.getComponents(node)); + let css = __WEBPACK_IMPORTED_MODULE_1__Layouter__["a" /* Layouter */].createLayout(node.attrs, content); + const attrs = { + style: node.style, + route: node.attrs.route, + onclick: node.attrs.onclick + }; + node.attrs.route = undefined; + if (node.attrs.href) { + attrs.href = node.attrs.href; + attrs.oncreate = __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].route.link; + attrs.onupdate = __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].route.link; + } + return Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(`.hs-layout ${css} ${this.getCSS(node)}`, attrs, content.map((c) => c)); + } +} +/* harmony export (immutable) */ __webpack_exports__["a"] = Layout; + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5b3V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvTGF5b3V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlCQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQVcsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBWSxZQUFZLENBQUM7QUF5QjVDLE1BQU07SUFvQlEsYUFBYSxDQUFDLElBQVU7UUFDOUIsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMzRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFLLEVBQUUsRUFBRTtnQkFDN0IsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFO29CQUNiLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO29CQUNqQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztpQkFDbEM7cUJBQU07b0JBQ0gsT0FBTyxDQUFDLENBQUM7aUJBQ1o7WUFDTCxDQUFDLENBQUMsQ0FBQztJQUNYLENBQUM7SUFRUyxNQUFNLENBQUMsSUFBVTtRQUN2QixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQztJQUNoQyxDQUFDO0lBR08sZ0JBQWdCLENBQUMsVUFBNkM7UUFDbEUsSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUU7WUFDaEMsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDL0M7UUFDRCxJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFFO1lBQ3JCLE9BQU8sVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQXlCLEVBQVEsRUFBRSxDQUNsRCxDQUFDLElBQUksWUFBWSxNQUFNLENBQUMsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUMsT0FBTyxFQUFDLElBQUksRUFBQyxDQUFDLENBQ2pFLENBQUM7U0FDTDtRQUVELE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBcUJELElBQUksQ0FBQyxJQUFVO1FBQ1gsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNoRSxJQUFJLEdBQUcsR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDckQsTUFBTSxLQUFLLEdBQU87WUFDZCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSztZQUN2QixPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPO1NBQzlCLENBQUM7UUFDRixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUM7UUFDN0IsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRTtZQUNqQixLQUFLLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO1lBQzdCLEtBQUssQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7WUFDOUIsS0FBSyxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztTQUNqQztRQUNELE9BQU8sQ0FBQyxDQUFDLGNBQWMsR0FBRyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RixDQUFDO0NBQ0oifQ== + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var pushStateMock = __webpack_require__(33) +var domMock = __webpack_require__(35) +var xhrMock = __webpack_require__(36) + +module.exports = function(env) { + env = env || {} + var $window = env.window = {} + + var dom = domMock() + var xhr = xhrMock() + for (var key in dom) if (!$window[key]) $window[key] = dom[key] + for (var key in xhr) if (!$window[key]) $window[key] = xhr[key] + pushStateMock(env) + + return $window +} + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var parseURL = __webpack_require__(13) +var callAsync = __webpack_require__(14) + +function debouncedAsync(f) { + var ref + return function() { + if (ref != null) return + ref = callAsync(function(){ + ref = null + f() + }) + } +} + +module.exports = function(options) { + if (options == null) options = {} + + var $window = options.window || {} + var protocol = options.protocol || "http:" + var hostname = options.hostname || "localhost" + var port = "" + var pathname = "/" + var search = "" + var hash = "" + + var past = [{url: getURL(), isNew: true, state: null, title: null}], future = [] + + function getURL() { + if (protocol === "file:") return protocol + "//" + pathname + search + hash + return protocol + "//" + hostname + prefix(":", port) + pathname + search + hash + } + function setURL(value) { + var data = parseURL(value, {protocol: protocol, hostname: hostname, port: port, pathname: pathname}) + var isNew = false + if (data.protocol != null && data.protocol !== protocol) protocol = data.protocol, isNew = true + if (data.hostname != null && data.hostname !== hostname) hostname = data.hostname, isNew = true + if (data.port != null && data.port !== port) port = data.port, isNew = true + if (data.pathname != null && data.pathname !== pathname) pathname = data.pathname, isNew = true + if (data.search != null && data.search !== search) search = data.search, isNew = true + if (data.hash != null && data.hash !== hash) { + hash = data.hash + if (!isNew) { + hashchange() + } + } + return isNew + } + + function prefix(prefix, value) { + if (value === "") return "" + return (value.charAt(0) !== prefix ? prefix : "") + value + } + function _hashchange() { + if (typeof $window.onhashchange === "function") $window.onhashchange({type: "hashchange"}) + } + var hashchange = debouncedAsync(_hashchange) + function popstate() { + if (typeof $window.onpopstate === "function") $window.onpopstate({type: "popstate", state: $window.history.state}) + } + function unload() { + if (typeof $window.onunload === "function") $window.onunload({type: "unload"}) + } + + $window.location = { + get protocol() { + return protocol + }, + get hostname() { + return hostname + }, + get port() { + return port + }, + get pathname() { + return pathname + }, + get search() { + return search + }, + get hash() { + return hash + }, + get origin() { + if (protocol === "file:") return "null" + return protocol + "//" + hostname + prefix(":", port) + }, + get host() { + if (protocol === "file:") return "" + return hostname + prefix(":", port) + }, + get href() { + return getURL() + }, + + set protocol(value) { + throw new Error("Protocol is read-only") + }, + set hostname(value) { + unload() + past.push({url: getURL(), isNew: true}) + future = [] + hostname = value + }, + set port(value) { + if (protocol === "file:") throw new Error("Port is read-only under `file://` protocol") + unload() + past.push({url: getURL(), isNew: true}) + future = [] + port = value + }, + set pathname(value) { + if (protocol === "file:") throw new Error("Pathname is read-only under `file://` protocol") + unload() + past.push({url: getURL(), isNew: true}) + future = [] + pathname = prefix("/", value) + }, + set search(value) { + unload() + past.push({url: getURL(), isNew: true}) + future = [] + search = prefix("?", value) + }, + set hash(value) { + var oldHash = hash + past.push({url: getURL(), isNew: false}) + future = [] + hash = prefix("#", value) + if (oldHash != hash) hashchange() + }, + + set origin(value) { + //origin is writable but ignored + }, + set host(value) { + //host is writable but ignored in Chrome + }, + set href(value) { + var url = getURL() + var isNew = setURL(value) + if (isNew) { + setURL(url) + unload() + setURL(value) + } + past.push({url: url, isNew: isNew}) + future = [] + }, + } + $window.history = { + pushState: function(state, title, url) { + past.push({url: getURL(), isNew: false, state: state, title: title}) + future = [] + setURL(url) + }, + replaceState: function(state, title, url) { + var entry = past[past.length - 1] + entry.state = state + entry.title = title + setURL(url) + }, + back: function() { + if (past.length > 1) { + var entry = past.pop() + if (entry.isNew) unload() + future.push({url: getURL(), isNew: false, state: entry.state, title: entry.title}) + setURL(entry.url) + if (!entry.isNew) popstate() + } + }, + forward: function() { + var entry = future.pop() + if (entry != null) { + if (entry.isNew) unload() + past.push({url: getURL(), isNew: false, state: entry.state, title: entry.title}) + setURL(entry.url) + if (!entry.isNew) popstate() + } + }, + get state() { + return past.length === 0 ? null : past[past.length - 1].state + }, + } + $window.onpopstate = null, + $window.onhashchange = null, + $window.onunload = null + + return $window +} + + +/***/ }), +/* 34 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, undefined) { + "use strict"; + + if (global.setImmediate) { + return; + } + + var nextHandle = 1; // Spec says greater than zero + var tasksByHandle = {}; + var currentlyRunningATask = false; + var doc = global.document; + var registerImmediate; + + function setImmediate(callback) { + // Callback can either be a function or a string + if (typeof callback !== "function") { + callback = new Function("" + callback); + } + // Copy function arguments + var args = new Array(arguments.length - 1); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i + 1]; + } + // Store and register the task + var task = { callback: callback, args: args }; + tasksByHandle[nextHandle] = task; + registerImmediate(nextHandle); + return nextHandle++; + } + + function clearImmediate(handle) { + delete tasksByHandle[handle]; + } + + function run(task) { + var callback = task.callback; + var args = task.args; + switch (args.length) { + case 0: + callback(); + break; + case 1: + callback(args[0]); + break; + case 2: + callback(args[0], args[1]); + break; + case 3: + callback(args[0], args[1], args[2]); + break; + default: + callback.apply(undefined, args); + break; + } + } + + function runIfPresent(handle) { + // From the spec: "Wait until any invocations of this algorithm started before this one have completed." + // So if we're currently running a task, we'll need to delay this invocation. + if (currentlyRunningATask) { + // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a + // "too much recursion" error. + setTimeout(runIfPresent, 0, handle); + } else { + var task = tasksByHandle[handle]; + if (task) { + currentlyRunningATask = true; + try { + run(task); + } finally { + clearImmediate(handle); + currentlyRunningATask = false; + } + } + } + } + + function installNextTickImplementation() { + registerImmediate = function(handle) { + process.nextTick(function () { runIfPresent(handle); }); + }; + } + + function canUsePostMessage() { + // The test against `importScripts` prevents this implementation from being installed inside a web worker, + // where `global.postMessage` means something completely different and can't be used for this purpose. + if (global.postMessage && !global.importScripts) { + var postMessageIsAsynchronous = true; + var oldOnMessage = global.onmessage; + global.onmessage = function() { + postMessageIsAsynchronous = false; + }; + global.postMessage("", "*"); + global.onmessage = oldOnMessage; + return postMessageIsAsynchronous; + } + } + + function installPostMessageImplementation() { + // Installs an event handler on `global` for the `message` event: see + // * https://developer.mozilla.org/en/DOM/window.postMessage + // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages + + var messagePrefix = "setImmediate$" + Math.random() + "$"; + var onGlobalMessage = function(event) { + if (event.source === global && + typeof event.data === "string" && + event.data.indexOf(messagePrefix) === 0) { + runIfPresent(+event.data.slice(messagePrefix.length)); + } + }; + + if (global.addEventListener) { + global.addEventListener("message", onGlobalMessage, false); + } else { + global.attachEvent("onmessage", onGlobalMessage); + } + + registerImmediate = function(handle) { + global.postMessage(messagePrefix + handle, "*"); + }; + } + + function installMessageChannelImplementation() { + var channel = new MessageChannel(); + channel.port1.onmessage = function(event) { + var handle = event.data; + runIfPresent(handle); + }; + + registerImmediate = function(handle) { + channel.port2.postMessage(handle); + }; + } + + function installReadyStateChangeImplementation() { + var html = doc.documentElement; + registerImmediate = function(handle) { + // Create a + + \ No newline at end of file diff --git a/docs/src/hsData/Data.html b/docs/src/hsData/Data.html new file mode 100644 index 0000000..490c8c7 --- /dev/null +++ b/docs/src/hsData/Data.html @@ -0,0 +1,557 @@ + + +

    Data.ts

    +
       1/**
    +   2 */

    +   3
    +   4 /** */
    +   5import { Condition, filter } from './DataFilters';
    +   6
    +   7/** defines a [min-max] range */
    +   8export type NumRange = [number, number];
    +   9
    +  10/** defines a numeric domain that includes all values of a column */
    +  11export type NumDomain = [number, number];
    +  12
    +  13/** defines a Date domain that includes all values of a column */
    +  14export type DateDomain = [Date, Date];
    +  15
    +  16/** defines a categorical domain that includes all values of a column */
    +  17export type NameDomain = string[];
    +  18
    +  19/** defines a generic domain that can be any of the typed domains. */
    +  20export type Domain = NumDomain | DateDomain | NameDomain;
    +  21
    +  22/** defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    +  23export type ColumnReference = number|string;
    +  24
    +  25/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    +  26export type DataVal = number|string|Date;
    +  27
    +  28/** a single row of column values */
    +  29export type DataRow = DataVal[];
    +  30
    +  31/** a JSON format data set, using arrays of names and rows */
    +  32export interface DataSet {
    +  33    /** an optional name for the data set */
    +  34    name?:  string;
    +  35    /** an array of column names. Each name matches the column with the same index in DataRow */
    +  36    colNames:  string[];   
    +  37    /** rows of data */
    +  38    rows:   DataRow[];
    +  39}
    +  40
    +  41/** a JSON format data set, using an array of {name:value, ...} literals*/
    +  42export type DataLiteralSet = Array;
    +  43
    +  44interface TypeStruct { type: string; count: number;};
    +  45
    +  46interface MetaStruct {
    +  47    name:       string;         // column name
    +  48    column:     number;         // column index
    +  49    accessed:   boolean;        // has column data been accessed?
    +  50    cast:       boolean;        // has column data been cast 
    +  51    types:      TypeStruct[];   // data types, sorted by likelihood
    +  52}
    +  53
    +  54export type sortFn = (x:any, y:any) => number;
    +  55export type mapFn  = (colVal:any, colIndex?:number, rowIndex?:number, rows?:any[][]) => any;
    +  56
    +  57/**
    +  58 * # Data
    +  59 * A simple in-memory database that holds data in rows of columns.
    +  60 * 
    +  61 */

    +  62export class Data {
    +  63    //----------------------------
    +  64    // public part
    +  65    //----------------------------
    +  66    public static type = {
    +  67        number:     'number data',
    +  68        name:       'name data',
    +  69        date:       'date data',
    +  70        currency:   'currency data',
    +  71        percent:    'percent data',
    +  72        nominal:    'nominal data'
    +  73    };
    +  74
    +  75    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    +  76        data = data || [{}];
    +  77        const names = Object.keys(data[0]);
    +  78        const rows = data.map((r:any) => 
    +  79            names.map((n:string) => r[n]));
    +  80        return { rows:rows, colNames:names, name:name||undefined };
    +  81    }
    +  82
    +  83    constructor(data?:DataSet) {
    +  84        this.import(data);
    +  85    }
    +  86
    +  87    /**
    +  88     * @return the `name` field for this data base, if any
    +  89     */

    +  90    public getName():string {
    +  91        return this.name;
    +  92    }
    +  93
    +  94    /**
    +  95     * Imports data from an object literal `data`
    +  96     * @param data the data set to import
    +  97     */

    +  98    public import(data:DataSet) {
    +  99        this.name = data.name;
    + 100        this.setData(data.rows, data.colNames);
    + 101    }
    + 102
    + 103    /**
    + 104     * Exports to an object literal
    + 105     */

    + 106    public export():DataSet {
    + 107        return {
    + 108            rows: this.getData(),
    + 109            colNames:this.colNames()
    + 110        };
    + 111    }
    + 112
    + 113    /**
    + 114     * returns the 2D array underlying the data base.
    + 115     */

    + 116    public getData():DataRow[] {
    + 117        return this.data;
    + 118    }
    + 119
    + 120    /**
    + 121     * Returns the values in the specified column as a new array.
    + 122     * @param col the column to return.
    + 123     */

    + 124    public getColumn(col:ColumnReference): DataVal[] {
    + 125        const cn = this.colNumber(col);
    + 126        return this.data.map((row:DataRow) => row[cn]);
    + 127    }
    + 128
    + 129    /**
    + 130     * adds a new column to the data set. if `newCol` already exists, 
    + 131     * the column index is returned withoput change.
    + 132     * @param col the name of the new column
    + 133     * @return the index for the new column
    + 134     */

    + 135    public colAdd(col:string):number {
    + 136        let m = this.getMeta(col);
    + 137        if (m === undefined) { 
    + 138            m = this.meta[col] = {};
    + 139            m.name   = col; 
    + 140            m.column = this.meta.length;
    + 141            this.meta.push(m);      // access name by both column name and index
    + 142            m.cast     = false;         // has not been cast yet
    + 143            m.accessed = false;         // has not been accessed yet
    + 144        }
    + 145        return m.column;
    + 146    }
    + 147
    + 148    /**
    + 149     * initializes the specifed column with values, adding a new column if needed. 
    + 150     * If `val`is a function, it is called as ```
    + 151     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    + 152     * ```
    + 153     * @param col the column to initialize
    + 154     * @param initializer the value to initialize with, or a function whose return
    + 155     * value is used to initialize the column
    + 156     */

    + 157    public colInitialize(col:ColumnReference, initializer:any) {
    + 158        const cn = this.colNumber(col);
    + 159        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    + 160        const fn = typeof initializer === 'function';
    + 161        if (cn!==undefined) {
    + 162            this.data.map((r:DataRow, i:number) =>
    + 163                r[cn] = fn? initializer(r[cn], i, r) : initializer
    + 164            );
    + 165        }
    + 166    }
    + 167
    + 168    /**
    + 169     * returns the column index of the specified column. 
    + 170     * `col` can be either an index or a name.
    + 171     * @param column the data column, name or index, for which to return the index. 
    + 172     * @return the column number or `undefined`.
    + 173     */

    + 174    public colNumber(col:ColumnReference) {
    + 175        const m = this.getMeta(col);
    + 176        if (!m) { return undefined; }
    + 177        else {
    + 178            m.accessed = true; 
    + 179            return m.column; 
    + 180        }
    + 181    }
    + 182    
    + 183    /**
    + 184     * returns the column name for the specified column. 
    + 185     * `col` can be either an index or a name.
    + 186     * @param column the data column, name or index. 
    + 187     * @return the column name or `undefined`.
    + 188     */

    + 189    public colName(col:ColumnReference) {
    + 190        var m = this.getMeta(col);
    + 191        if (!m) { return undefined; }
    + 192        m.accessed = true; 
    + 193        return m.name; 
    + 194    }
    + 195
    + 196    /**
    + 197     * returns the names for all columns. 
    + 198     * @return an array of strings with the names.
    + 199     */

    + 200    public colNames():string[] {
    + 201        return this.meta.map((m:MetaStruct) => m.name); 
    + 202    }
    + 203
    + 204    /**
    + 205     * returns the column type for the specified column. 
    + 206     * `col` can be either an index or a name.
    + 207     * @param column the data column, name or index. 
    + 208     * @return the column type.
    + 209     */

    + 210    public colType(col:ColumnReference) { 
    + 211        const meta = this.getMeta(col);
    + 212        return meta? meta.types[0].type : Data.type.name;
    + 213    }
    + 214
    + 215    /**
    + 216     * modifies `domain` to include all values in column `col`.
    + 217     * @param col the column name or index 
    + 218     * @param domain the 
    + 219     */

    + 220    public findDomain(col:ColumnReference, domain:Domain) {
    + 221        if (col === undefined) { // use array index as domain
    + 222            domain[0] = 0;
    + 223            domain[1] = this.data.length-1;
    + 224        } else {
    + 225            const c = this.colNumber(col);
    + 226            const type = this.colType(col);
    + 227            if (this.data === undefined) {
    + 228                console.log('no data'); 
    + 229            }
    + 230            switch(type) {
    + 231                case Data.type.nominal: 
    + 232                    this.data.forEach((r:DataRow) => {
    + 233                        const nomDom = domain;
    + 234                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    + 235                    });
    + 236                    break;
    + 237                default: 
    + 238                    this.data.forEach((r:DataRow) => {
    + 239                        let v:number = r[c];
    + 240                        if (v!==undefined && v!==null) {
    + 241                            domain[0] = (v + 242                            domain[1] = (v>domain[1])? v : domain[1];
    + 243                        }
    + 244                    });
    + 245            }
    + 246        }
    + 247    }
    + 248
    + 249    public castData() {
    + 250        this.meta.forEach((c:MetaStruct) => {
    + 251            const col = c.column;
    + 252            if (!c.cast) {
    + 253                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    + 254            }
    + 255            c.cast = true;
    + 256        });
    + 257    }
    + 258
    + 259    /**
    + 260     * filters this data set and returns a new data set with a 
    + 261     * shallow copy of rows that pass the `condition`.
    + 262     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    + 263     * @param condition filters 
    + 264     * @return a new Data object with rows that pass the filter
    + 265     */

    + 266    public filter(condition:Condition):Data {
    + 267        return filter(this, condition);
    + 268    }
    + 269
    + 270    /**
    + 271     * @description Sorts the rows of values based on the result of the `sortFn`, 
    + 272     * which behaves similarly to the Array.sort method.  
    + 273     * Two modes are supported:
    + 274     * # Array Mode
    + 275     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    + 276     * This allows for complex sorts, combining conditions across multiple columns.
    + 277     * ```
    + 278     * data.sort((row1, row2) => row1[5] - row2[5] );
    + 279     * ```
    + 280     * # Column mode
    + 281     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 282     * into `sortFn`. This allows filtering for simple conditions.

    + 283     * **The specified column will be automatically cast prior to sorting**

    + 284     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    + 285     * @param col optional; the data column to use for sorting. 
    + 286     * @param sortFn a function to implement the conditions, 
    + 287     * follows the same specifications as the function passed to Array.sort(). 
    + 288     * Some predefined sort function can be invoked by providing a 
    + 289     * respective string instead of a function. The following functions are defined:
    + 290        
    + 291        
    + 292        
    + 293        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    + 294     * @return the Data object in order to allow for chaining.
    + 295     */

    + 296    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    + 297        let fn = sortFn;
    + 298        if (!col) {
    + 299            this.data.sort(fn);
    + 300        } else {
    + 301            col = this.colNumber(col);
    + 302            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b + 303            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    + 304            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    + 305        }
    + 306        return this;
    + 307    }
    + 308
    + 309    /** 
    + 310    *  Maps one or more columns in each rows of values based 
    + 311     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    + 312     * Two modes are supported:
    + 313     * # Array Mode
    + 314     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    + 315     * This allows for complex mapping combining conditions across multiple columns.
    + 316     * ```
    + 317     * data.map(function(values){ 
    + 318     *    values[1] = values[3] * values[5]; 
    + 319     *    return values; 
    + 320     * });
    + 321     * ```
    + 322     * Be sure to return the `values` array as a result.
    + 323     * # Column mode
    + 324     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 325     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    + 326     * ```
    + 327     * data.map('Price', function(value, i, values) { 
    + 328     *    return value * 2; 
    + 329     * });
    + 330     * ```
    + 331     * @param col the data column, or columns, to apply the mapping to. 
    + 332     * @param mapFn a function to implement the mapping,
    + 333     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    + 334     * - `val`: the column value in the current row
    + 335     * - `c`: the column index in the current row
    + 336     * - `i`: the row index 
    + 337     * - `rows`: the rows being iterated over
    + 338`    * 
    + 339     * follows the same specifications as the function passed to Array.map().

    + 340     * For column mode, some predefined map functions can be invoked by providing a 
    + 341     * respective string instead of a function. The following functions are defined:
    + 342        
    + 343        
    + 344        
    + 345        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    + 346     * @return a new Data object containing the mapping.
    + 347     */

    + 348    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    + 349        const noop = (val:any) => val;
    + 350        const cumulate = () => { 
    + 351            let sum=0; 
    + 352            return (val:number, i:number) => { sum += +val; return sum; };
    + 353        };
    + 354        function getFn() {
    + 355            let fn; // define fn inside each col loop to ensure initialization
    + 356            switch (mapFn) {
    + 357                case 'cumulate': fn = cumulate(); break;
    + 358                case 'noop':     fn = noop; break;
    + 359                default:         fn = mapFn;
    + 360            }
    + 361            return fn;
    + 362        }
    + 363
    + 364        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    + 365
    + 366        const names = col['length']? col : [col];            
    + 367        names.map((cn:ColumnReference) => {
    + 368            const c = this.colNumber(cn);
    + 369            let fn = getFn(); // define fn inside each col loop to ensure initialization
    + 370            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    + 371                row[c] = fn(row[c], c, i, rows); 
    + 372                return row;
    + 373            });
    + 374        });
    + 375        return result;
    + 376    }
    + 377
    + 378    //----------------------------
    + 379    // private part
    + 380    //----------------------------
    + 381    private data: DataRow[]    = [];
    + 382    private meta: MetaStruct[] = [];
    + 383    private name: string;
    + 384
    + 385    private getMeta(col:ColumnReference):MetaStruct { 
    + 386        if (!this.meta) { this.meta = []; }
    + 387        if (!this.meta[col]) { return undefined; }
    + 388        this.meta[col].accessed = true;
    + 389        return this.meta[col]; 
    + 390    }
    + 391
    + 392    /**
    + 393     * sets `data` to the existing data set. If data has previously been set, 
    + 394     * `data` will be added to the end of the list if all `names`  match those of the 
    + 395     * existing set. 
    + 396     * @param data the data to add
    + 397     * @param names an array of names that match the columns
    + 398     * @param autoType unless set to false, the method will attempt to determine the 
    + 399     * type of data and automatically cast data points to their correct value
    + 400     */

    + 401    private setData(data:DataRow[], names:string[], autoType=true):void {
    + 402        this.meta = [];
    + 403        this.data = data;
    + 404        if (!names) {
    + 405            console.log();
    + 406        }
    + 407        names.forEach((col:string) => this.colAdd(col));
    + 408        names.forEach((col:string) => this.findTypes(col));
    + 409        this.castData();
    + 410    }
    + 411
    + 412    /**
    + 413     * Determines the type of data in `col`. An array of counts is created for all
    + 414     * encountered types, sorted by descending frequency. THe most likely type in position 0
    + 415     * of the array is returned.
    + 416     * @param col the index of the column to be typed. 
    + 417     * @return the most likely type of data in `col`.
    + 418     */

    + 419    private findTypes(col:ColumnReference):string {
    + 420        const m = this.getMeta(col);
    + 421        const types:TypeStruct[] = [];
    + 422        Object.keys(Data.type).forEach((t:string) => {
    + 423            const ts = { type: Data.type[t], count: 0 }; 
    + 424            types.push(ts);
    + 425            types[Data.type[t]] = ts;
    + 426        });
    + 427        for (let v of this.allRows(col)) {
    + 428            const t = this.findType(v);
    + 429            if (t !== null) { types[t].count++; }
    + 430        }
    + 431        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    + 432            if (a.type==='currency'&&a.count>0) { return -1; }
    + 433            if (b.type==='currency'&&b.count>0) { return 1; }
    + 434            return b.count - a.count;
    + 435        });
    + 436        m.types = types;
    + 437        return types[0].type;
    + 438    }
    + 439
    + 440    /**
    + 441     * @description determines the data type. Supported types are 
    + 442     * ```
    + 443     * 'date':    sample represents a Date, either as a Date object or a String 
    + 444     * 'number':  sample represents a number
    + 445     * 'percent': sample represents a percentage (special case of a real number)
    + 446     * 'nominal': sample represents a nominal (ordinal or categorical) value
    + 447     * ```
    + 448     * @param val the value to bve typed.
    + 449     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    + 450     */

    + 451    private findType(val:DataVal) {
    + 452        if (val && val!=='') {
    + 453            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    + 454            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    + 455
    + 456            // else: val is a string:
    + 457            const strVal = ''+val;
    + 458            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    + 459            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    + 460            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    + 461            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    + 462
    + 463            // european large number currency representation: '$dd,ddd[,ddd]'
    + 464            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    + 465                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    + 466                    return Data.type.currency; 
    + 467                }
    + 468            }
    + 469            switch (strVal.toLowerCase()) {
    + 470                case "null": break;
    + 471                case "#ref!": break;
    + 472                default: if (val.length>0) { return Data.type.nominal; }
    + 473            }
    + 474        }
    + 475        return null;
    + 476    }    
    + 477
    + 478    /**
    + 479     * A generator that provides the specified column value for each row in `Data` in sequence. 
    + 480     * @param column 
    + 481     */

    + 482    private * allRows(column:ColumnReference):Iterable {
    + 483        const c = this.colNumber(column);
    + 484        for (let r=0; r + 485            yield this.data[r][c];
    + 486        }
    + 487    }
    + 488
    + 489    /**
    + 490     * @param val the string to convert to a date
    + 491     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    + 492     * @returns a new Date object parsed from `str`.
    + 493     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    + 494     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    + 495     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    + 496     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    + 497     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    + 498     */

    + 499    private toDate(val:DataVal, limitYear=1970):Date {
    + 500        let d:Date;
    + 501        if (val instanceof Date) { d = val; }
    + 502                            else { d = new Date(val); }   
    + 503        let yr=d.getFullYear();
    + 504        if (yr < 100) { 
    + 505            yr += 1900; 
    + 506            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    + 507        }
    + 508        return d;
    + 509    }
    + 510
    + 511    /**
    + 512     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    + 513     * does not match any of the previous keywords, no casting occurs.
    + 514     * @param sample The value to cast.
    + 515     * @returns The result of the cast. 
    + 516     * @description Casts the sample to the specified data type.
    + 517     */

    + 518    private castVal(type:string, val:DataVal):DataVal {
    + 519        switch (type) {
    + 520            case Data.type.date:    if (val instanceof Date) { return val; }
    + 521                            val = this.toDate(val);
    + 522                            if (isNaN(val.getTime())) { val = null; }
    + 523                            break;
    + 524            case Data.type.percent: if (typeof val === 'string') {
    + 525                                const num = parseFloat(val);
    + 526                                val = (val).endsWith('%')? num/100 : num;
    + 527                            } 
    + 528                            if (isNaN(val)) { val = null; }
    + 529                            break;
    + 530            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    + 531             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    + 532             /* falls through */
    + 533            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    + 534                            if (isNaN(val)) { val = null; }
    + 535                            break;
    + 536            default:        val = ''+val;
    + 537        }
    + 538        return val;
    + 539     }     
    + 540}
    + + \ No newline at end of file diff --git a/docs/src/hsData/DataFilters.html b/docs/src/hsData/DataFilters.html new file mode 100644 index 0000000..d4c08f7 --- /dev/null +++ b/docs/src/hsData/DataFilters.html @@ -0,0 +1,272 @@ + + +

    DataFilters.ts

    +
       1
    +   2/**
    +   3
    +   4* The HsData object will feature its own column meta information, as well as 
    +   5* a copy of the rows array which allows for `filter` and `sort` operations. 
    +   6* However, the column arrays will be shared with the original HsData object in order to be memory efficient.
    +   7* This means that `map` and `newColumn` operations on the new object will affect the original object or any 
    +   8* object derived via `query`.  
    +   9* @description executes a query on the data. Each row in the data is checked and those for which
    +  10* `conditions` is true are returned as a new HsData object. 
    +  11*  
    +  12* ## General Condition
    +  13* ```
    +  14* Condition = 
    +  15*    IndexCondition            -> conditions on the row index
    +  16* || RecursiveCondition        -> (set of) conditions on column values
    +  17* ```
    +  18
    +  19* ## IndexCondition
    +  20* ```
    +  21* IndexCondition =
    +  22*    rowIndex:number           -> true if row index matches
    +  23* ```
    +  24
    +  25* ## RecursiveCondition
    +  26* ```
    +  27* RecursiveCondition =
    +  28*    OrCondition               -> OR: true if any compound condition is true
    +  29* || AndCondition              -> AND: true if all compound conditions are true
    +  30
    +  31* OrCondition =                -> OR: true if
    +  32*    AndCondition[]               -> any of the AndConditions are true
    +  33* || IndexCondition[]             -> any of thr IndexConditions are true
    +  34
    +  35* AndCondition =               -> AND: true if
    +  36*    SetAndCondition              -> all SetAndConditions are true
    +  37* || TermAndCondition             -> or if all TermAndConditions are true
    +  38*
    +  39* SetAndCondition = {          -> AND: true if all sub-conditions are true
    +  40*    'or':  RecursiveCondition    -> true if any RecursiveCondition is true
    +  41* || 'and': RecursiveCondition    -> true if all RecursiveCondition are true
    +  42* || 'not': RecursiveCondition    -> true if the condition is false
    +  43*
    +  44* TermAndCondition = {         -> Terminal AND: true if all terminal sub-conditions are true
    +  45*    colDesc:colValue             -> true if colValue matches 
    +  46* || colDesc:[colValue, ...]      -> true if any of the colValues match
    +  47* || colDesc:function(value,row)  -> true if function returns true 
    +  48* }
    +  49
    +  50* colDesc = either column name or index
    +  51* ```
    +  52
    +  53* ## Practical Tips
    +  54* ```
    +  55*    {'or': [recurCond, ...]}    -> OR, same as [recurCond, ...]
    +  56* || {'or': {SetCond, ...}}      -> OR, same as [SetCond, ...]
    +  57* || {'and': [recurCond, ...]}   -> AND, true if all recurCond are true
    +  58* || {'and': {SetCond, ...}}     -> AND, same as {SetCond, ...}
    +  59* || {'not': {SetCond, ...}}     -> NAND: true if the SetCond are true
    +  60* || {'not': [recurCond, ...]}   -> NOR: true if any of the recurCond are true
    +  61* ```
    +  62*      
    +  63* # Example
    +  64
    +  65
    +  66* const colNames = ['Name', 'Value', 'Start', 'End'];
    +  67* const rows = [
    +  68*   ['Harry', '100', '3/1/14', '11/20/14'], 
    +  69*   ['Mary', '1500', '7/1/14',  '9/30/14'],
    +  70*   ['Peter', '400', '5/20/14', '4/30/15'],  
    +  71*   ['Jane', '700', '11/13/14', '8/15/15']
    +  72* ]
    +  73* const data = new hsdata.Data({colNames:colNames, rows:rows});
    +  74
    +  75* queries = [
    +  76*   ['0', undefined,                           'undefined query => pass all'],
    +  77*   ['1', [],                                  'empty OR:  []   => fail all'],
    +  78*   ['2', {},                                  'empty AND: {}   => pass all'],
    +  79*   ['3', 1,                                   '2nd row: pass row 1'],
    +  80*   ['4', [1,3],                               '2nd+4th: pass rows: 1 and 3'],
    +  81*   ['5', {Name:"Jane"},                       'Name is Jane'],
    +  82*   ['6', {1:1500},                            'Column 2 is 1500'],
    +  83*   ['7', {Name:["Peter", "Jane"]},            'Name is Peter or Jane'],
    +  84*   ['8', [{Name:"Peter"}, {Value:1500}],      'Name is Peter or Value is 1500'],
    +  85*   ['9', {or:{Name:"Peter", Value:1500}},     'OR:  same as 8:'],
    +  86*   ['A', {or:[{Name:"Peter"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],
    +  87*   ['B', {Name:"Peter", Value:400},           'Name is Peter and Value is 400'],
    +  88*   ['C', {and:{Name:"Peter", Value:400}},     'AND: {Name is Peter, Value is 400}'],
    +  89*   ['D', {and:{Name:"Peter", Value:1500}},    'AND: {Name is Peter, Value is 1500}'],
    +  90*   ['E', {and:[{Name:"Peter"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],
    +  91*   ['F', {and:[{Name:"Peter"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],
    +  92*   ['G', {not:{Name:"Peter", Value:400}},     'NAND: not {Name is Peter and Value is 400}'],
    +  93*   ['H', {not:{Name:"Peter", Value:1500}},    'NAND: not {Name is Peter and Value is 1500}'],
    +  94*   ['I', {not:[{Name:"Peter"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],
    +  95*   ['J', {Name:(v) => v.length===4},          'Name has 4 letters']
    +  96* ];
    +  97*
    +  98* m.mount(root, { 
    +  99*   view:() => m('', [
    + 100*       m('h3', 'Given the data set:'),
    + 101*       m('table#data', [
    + 102*           m('tr', colNames.map(n => m('th', n))),
    + 103*           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    + 104*       ]),
    + 105*       m('h3', 'The following queries yield:'),
    + 106*       m('table', [
    + 107*           m('tr', [m('th','#'), m('th','Query'), m('th',"Live Result, by 'Name' field")]),
    + 108*           ...queries.map(q => {
    + 109*               const result = data.filter(q[1]).getColumn('Name').join(', ');
    + 110*               return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);
    + 111*           })
    + 112*       ])
    + 113*   ])
    + 114* });
    + 115
    + 116
    + 117*   $exampleID { height: 600px; }
    + 118*   #data th { width:15%; }
    + 119*   table { 
    + 120*       font-size: 10pt;
    + 121*       margin-left: 10px;
    + 122*   }
    + 123
    + 124*      
    + 125*/

    + 126
    + 127/** */
    + 128import { Data,
    + 129         DataVal,
    + 130         DataRow
    + 131} from './Data'; 
    + 132
    + 133export type Condition = IndexCondition | RecursiveCondition;
    + 134
    + 135/** true if row index matches the number(s) */
    + 136export type IndexCondition = number;
    + 137
    + 138export type RecursiveCondition = AndCondition | OrCondition;
    + 139export type OrCondition = AndCondition[] | IndexCondition[];
    + 140export type AndCondition = SetAndCondition | TermAndCondition;
    + 141
    + 142export interface SetAndCondition {
    + 143    or?: RecursiveCondition;
    + 144    and?:RecursiveCondition;
    + 145    not?:RecursiveCondition;
    + 146};
    + 147
    + 148export interface TermAndCondition { 
    + 149    [colDesc:string]: 
    + 150        DataVal 
    + 151      | DataVal[]
    + 152      | TermConditionFunction
    + 153    ;
    + 154};
    + 155
    + 156export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean;
    + 157
    + 158
    + 159function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { 
    + 160    const col = colNumber(name);
    + 161    const valIsFunction = (typeof val === 'function');
    + 162    const valIsArray = ((typeof val === 'object') && (val.length!==undefined));
    + 163    if (isNaN(col)) { 
    + 164        console.log(`column name '${name}' cannot be resolved in terminal condition ${name}=${val}`);
    + 165        console.log(row);
    + 166        return false; // -> this condition is not met;
    + 167    } else if (valIsFunction) { 
    + 168        // query true if function evaluates to true
    + 169        return val(row[col], row);
    + 170    } else if (valIsArray) {
    + 171        // query true if empty array, or at least one c true
    + 172        return (val.length === 0) || val.some((v:any) => row[col] === v); 
    + 173    } else { // object: all conditions have to be met, unless specified as or
    + 174        return (row[col] === val); 
    + 175    }
    + 176}
    + 177
    + 178/**
    + 179 * applies `condition` to a row of data and returns `true` if the row passes.
    + 180 * @param condition the complex condition to test against
    + 181 * @param r the row index in the data set
    + 182 * @param row the row values 
    + 183 * @param and 
    + 184 */

    + 185function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and=true):boolean { 
    + 186    let orResult = false;
    + 187    let andResult= true;          
    + 188    // undefined condition is TRUE
    + 189    if (condition===undefined) { return true; }
    + 190    
    + 191    // Simple Index Condition on row index:
    + 192    else if (typeof condition === 'number') { return (condition === r); }
    + 193
    + 194    // Recursive Condition - OR: [...], AND {...}: 
    + 195    else if (typeof condition === 'object') {
    + 196        // array -> or condition on a list of row indices or compound conditions
    + 197        const mc = condition;
    + 198
    + 199        // OR condition: [...] 
    + 200        if (mc.length !== undefined) {            
    + 201            return (mc.length === 0)? 
    + 202                // empty OR is false:
    + 203                false : 
    + 204                // else: OR is true if any sub-condition is met
    + 205                mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, false));
    + 206        } 
    + 207        // AND condition: {...}
    + 208        else { 
    + 209            for (const name in condition) {
    + 210                let conditionMet = and; // initialize with false for OR, and true for AND conjunction
    + 211                const setCond = condition;
    + 212                
    + 213                // resolve SetConditions:
    + 214                switch (name) {
    + 215                    case 'or':  conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break;
    + 216                    case 'and': conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break;
    + 217                    case 'not': conditionMet = !resolveCondition(setCond.not, row, r, colNumber, true); break;
    + 218                    default:    conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); 
    + 219                }
    + 220                if (conditionMet) { orResult  = true;  if(!and) { break; }} // OR conjunction: exit for name loop if condition met
    + 221                             else { andResult = false; if(and)  { break; }} // AND conjunction: exit for name loop if condition not met
    + 222            }
    + 223        }    
    + 224    } else {
    + 225        console.error(`unrecognized condition: ${JSON.stringify(condition)}`);
    + 226        return false;
    + 227    }
    + 228    return and? andResult : orResult;
    + 229}
    + 230
    + 231export type ReduceFn = (keep:boolean, row:DataRow, i:number) => void;
    + 232
    + 233export function filter(data:Data, cond:Condition, reduceFn?:string|ReduceFn):Data {
    + 234    const noop = () => 0;
    + 235    const colNumber = (name:string):number => data.colNumber(name);
    + 236    let fn:ReduceFn;
    + 237    switch (reduceFn) {
    + 238        default: fn = (typeof reduceFn === 'function')? reduceFn : noop;
    + 239    } 
    + 240    try {
    + 241        return new Data({
    + 242            name:     data.getName(),
    + 243            colNames: data.colNames(), 
    + 244            rows:data.getData().filter((row:DataRow, i:number) => {
    + 245                const keep = resolveCondition(cond, row, i, colNumber);
    + 246                if (fn) { fn(keep, row, i); }
    + 247                return keep;
    + 248            })
    + 249        });
    + 250    } catch(err) {
    + 251        console.log(err);
    + 252        console.log(err.stack);
    + 253    }
    + 254}
    + 255
    + + \ No newline at end of file diff --git a/docs/src/hsData/DataTypes.html b/docs/src/hsData/DataTypes.html new file mode 100644 index 0000000..9e2f184 --- /dev/null +++ b/docs/src/hsData/DataTypes.html @@ -0,0 +1,48 @@ + + +

    DataTypes.ts

    +
       1/** defines a [min-max] range */
    +   2export type NumRange = [number, number];
    +   3
    +   4/** defines a numeric domain that includes all values of a column */
    +   5export type NumDomain = [number, number];
    +   6
    +   7/** defines a Date domain that includes all values of a column */
    +   8export type DateDomain = [Date, Date];
    +   9
    +  10/** defines a categorical domain that includes all values of a column */
    +  11export type NameDomain = string[];
    +  12
    +  13/** defines a generic domain that can be any of the typed domains. */
    +  14export type Domain = NumDomain | DateDomain | NameDomain;
    +  15
    +  16/** defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    +  17export type ColSpecifier = number|string;
    +  18
    +  19/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    +  20export type DataVal = number|string|Date;
    +  21
    +  22/** a single row of column values */
    +  23export type DataRow = DataVal[];
    +  24
    +  25/** a JSON format data set */
    +  26export interface DataSet {
    +  27    rows:DataRow[];
    +  28    names:ColSpecifier[];   
    +  29}
    +  30
    +  31
    + + \ No newline at end of file diff --git a/docs/src/hsData/index.html b/docs/src/hsData/index.html new file mode 100644 index 0000000..f59d1fa --- /dev/null +++ b/docs/src/hsData/index.html @@ -0,0 +1,32 @@ + + +

    index.ts

    +
       1export { NumRange,
    +   2         NumDomain,
    +   3         DateDomain,
    +   4         NameDomain,
    +   5         Domain,
    +   6         ColumnReference,
    +   7         DataVal,
    +   8         DataRow,
    +   9         DataSet
    +  10        }       from './Data';
    +  11
    +  12export { Data } from './Data';
    +  13export { Condition} from './DataFilters';
    +  14
    +  15
    + + \ No newline at end of file diff --git a/docs/src/hsData/overview.html b/docs/src/hsData/overview.html new file mode 100644 index 0000000..25c079d --- /dev/null +++ b/docs/src/hsData/overview.html @@ -0,0 +1,40 @@ + + +

    overview.ts

    +
       1/**
    +   2 * # hsData
    +   3 * 
    +   4 * Helpful Scripts data management functions that are framework independent. 
    +   5 * 
    +   6 * ## Data Types
    +   7 * -   {@link Data.NumRange NumRange} defines a single [min, max] numeric range.
    +   8 * -   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column
    +   9 * -   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column
    +  10 * -   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column
    +  11 * -   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains.
    +  12 * -   {@link Data.ColSpecifier ColSpecifier} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array 
    +  13 * -   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array
    +  14 * -   {@link Data.DataRow DataRow} a single row of column values
    +  15 * 
    +  16 * ## Data Class
    +  17 * -   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions
    +  18 */

    +  19
    +  20 /** */
    +  21
    +  22 
    +  23
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/DocSets.html b/docs/src/hsDoc/DocSets.html new file mode 100644 index 0000000..413b078 --- /dev/null +++ b/docs/src/hsDoc/DocSets.html @@ -0,0 +1,168 @@ + + +

    DocSets.ts

    +
       1/**
    +   2 * DocSets.ts. Loads the doc.json files to process and display as documentation.
    +   3 * Processing occurs in these steps:
    +   4 * 1. Load the index.json file that contains a list of doc.json files to load, one for each library to show
    +   5 * 2. Load each doc.json file, which describes a library
    +   6 * 3. Call DocSets.add to add the library name to the registry and create an index of entries for the library
    +   7 */

    +   8
    +   9/** */
    +  10import { m }    from 'hslayout';
    +  11
    +  12/**
    +  13 * the default location for the index .json files, relative to the web page:
    +  14 * `'./data/index.json'`
    +  15 */

    +  16const FILE:string = './data/index.json';
    +  17
    +  18
    +  19/**
    +  20 * DocSets object. Keeps a list of registered docsets and 
    +  21 * provides access to elements of each docset.
    +  22 */

    +  23export class DocSets { 
    +  24    /** Contains references to the docsets and all elements per docset, accessible per ID. */
    +  25    private static gList = <{set:string[], index:{}}>{set:[], index:{}};
    +  26    private static gTitle: string;
    +  27
    +  28    /** Adds the docset in `content` to the `gList` */
    +  29    public static add(content:any) {
    +  30        const lib = content.name;
    +  31        DocSets.gList.set.push(lib);
    +  32        DocSets.gList.set.sort();
    +  33        DocSets.gList.index[lib] = {};
    +  34        recursiveIndex(content, DocSets.gList.index[lib], lib);
    +  35    }
    +  36
    +  37    /**
    +  38     * loads an index set and the docsets it contains from driectory `dir`.
    +  39     * @param file the optional directory to read from. If unspecified, 
    +  40     * read from the index file specified by {@link DocSets.FILE `FILE`}.
    +  41     */

    +  42    public static loadList(file?:string):Promise {
    +  43        file = file || FILE;   
    +  44//console.log('requesting docSet ' + file);
    +  45        return DocSets.loadIndexSet(file); 
    +  46    }
    +  47
    +  48    /**
    +  49     * returns the specified documentation element.
    +  50     * When called without parameters, a string[] of available docSets is returned.
    +  51     * When called with only `lib` specified, the corresponding docSet overview is returned.
    +  52     * @param lib specifies the docset to scan. 
    +  53     * @param id specifies the element within the docSet, either by its id number, or by its path
    +  54     */

    +  55    public static get(lib?:string, id:number|string=0) { 
    +  56        if (lib) {
    +  57            if (DocSets.gList.index[lib]) { 
    +  58                return DocSets.gList.index[lib][id+'']; 
    +  59            } else {
    +  60                return DocSets.gList.set; 
    +  61            }
    +  62        } else {
    +  63            return DocSets.gList.set; 
    +  64        }
    +  65    }
    +  66
    +  67    /**
    +  68     * Loads `index.json` from the directory specified in `dir`.
    +  69     * Each entry in the index is interpreted as a docset and loaded.
    +  70     * @param dir the directory to read from
    +  71     * @param file the index file to read
    +  72     */

    +  73    private static loadIndexSet(file:string):Promise { 
    +  74        return m.request({ method: "GET", url: file })
    +  75            .then((result:any) =>  {
    +  76//console.log('received index');
    +  77                DocSets.gTitle = result.title;
    +  78                let i = file.lastIndexOf('/');
    +  79                const dir = file.substring(0,i+1);
    +  80                return Promise.all(result.docs.map((f:string) => loadDocSet(dir, f)));            
    +  81            })
    +  82            .catch(console.log);
    +  83    }
    +  84
    +  85
    +  86    public static title() { return DocSets.gTitle; }
    +  87};
    +  88
    +  89/**
    +  90 * Loads a docset specified by file from the directory `dir`. 
    +  91 * Once received, the docset is registered in `modules` via the `add` method.
    +  92 * @param dir the directory to read from
    +  93 * @param file the `json` file to load as docset
    +  94 */

    +  95function loadDocSet(dir:string, file:string):Promise {
    +  96    return m.request({ method: "GET", url: dir+file })
    +  97        .then((r:any) => {
    +  98// console.log('received ' + dir+file);
    +  99            DocSets.add(r);
    + 100        })
    + 101        .catch(console.log);
    + 102}
    + 103
    + 104/**
    + 105 * recurses through the docset and registers all `children` entries of an entry by id,
    + 106 * starting with the root entry.
    + 107 * @param content the docset object literal to traverse
    + 108 * @param index the index in which to register the entries
    + 109 * @param lib the docset name, used for name validation
    + 110 */

    + 111function recursiveIndex(content:any, index:any, lib:string, path='') {
    + 112    function getNewPath(content:any) {
    + 113        content.name = content.name.replace(/["'](.+)["']|(.+)/g, "$1$2");  // remove quotes 
    + 114        const elName  = content.name.match(/([^\/]+)$/)[1];         // name = part after last /
    + 115        content.name = elName;
    + 116        return content.fullPath = (path==='')? elName : `${path}.${elName}`;
    + 117    }
    + 118
    + 119    function markIfModule(content:any) {
    + 120        if (content.comment && content.comment.tags) {
    + 121            content.comment.tags.forEach((tag:any) => {
    + 122                if (tag.tag === 'module') {
    + 123                    content.innerModule = tag.text.trim();
    + 124                }
    + 125            });
    + 126        }
    + 127    }
    + 128    content.lib = lib;
    + 129    if (typeof content === 'object' && content.name) {
    + 130        const newPath = getNewPath(content);
    + 131
    + 132        markIfModule(content);
    + 133
    + 134        index[content.id+''] = content;
    + 135        if (newPath.length>0) { index[newPath] = content; }
    + 136
    + 137        if (content.children) {
    + 138            content.children.map((c:any) => recursiveIndex(c, index, lib, newPath));
    + 139        }
    + 140        if (content.signatures) {
    + 141            content.signatures.map((c:any) => recursiveIndex(c, index, lib, newPath));
    + 142        }
    + 143        if (content.parameters) {
    + 144            content.parameters.map((c:any) => recursiveIndex(c, index, lib, newPath));
    + 145        }
    + 146        if (content.type && content.type.declaration && content.type.declaration.children) {
    + 147            content.type.declaration.children.map((c:any) => recursiveIndex(c, index, lib, newPath));
    + 148        }
    + 149    }
    + 150}
    + 151
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/Site.html b/docs/src/hsDoc/Site.html new file mode 100644 index 0000000..1a6fd6f --- /dev/null +++ b/docs/src/hsDoc/Site.html @@ -0,0 +1,78 @@ + + +

    Site.ts

    +
       1/**
    +   2 * Site documentation
    +   3 */

    +   4
    +   5/** */
    +   6import * as hslayout  from 'hslayout';
    +   7import * as header  from './view/DocsMenu';
    +   8import * as left    from './view/LeftNav';
    +   9import * as main    from './view/MainDetail';
    +  10
    +  11
    +  12const TitleHeight   = '30px'; 
    +  13const FooterHeight  = '10px';  
    +  14const LeftNavWidth  = '200px';
    +  15const SiteName      = 'HSDocs'; 
    +  16 
    +  17const myConfig = {
    +  18    Layout: { // whole page
    +  19        rows:  [TitleHeight, "fill", FooterHeight],
    +  20        css: '.hs-site',
    +  21        content: [{
    +  22            Layout:{ // top row
    +  23                columns: [LeftNavWidth, "fill"],
    +  24                css: '.hs-site-header',
    +  25                content: [
    +  26                    { Layout:    { 
    +  27                        css: '.hs-site-title',
    +  28                        content: SiteName, 
    +  29                        href:'/api/' 
    +  30                    }},
    +  31                    { DocsMenu:    { docSet:"./data/index.json"}}
    +  32                ]                
    +  33            }},{
    +  34            Layout:{ // main part
    +  35                columns: [LeftNavWidth, "fill"], 
    +  36                content: [
    +  37                    { LeftNav:    {}},
    +  38                    { MainDetail: {}}
    +  39                ]                
    +  40            }},
    +  41            { Layout: { // footer
    +  42                css: '.hs-site-footer',
    +  43                content: '(c) Helpful Scripts'
    +  44            }}
    +  45        ] 
    +  46    },
    +  47    route: {
    +  48        default: '/api',
    +  49        paths: [
    +  50            '/api',             // defines `http://localhost/#!/api/
    +  51            '/api/:lib',        // defines `http://localhost/#!/api/:hsLib
    +  52            '/api/:lib/:field'  // defines `http://localhost/#!/api/:hsLib/:id        
    +  53        ]
    +  54    }
    +  55}; 
    +  56
    +  57
    +  58export function init() {
    +  59    new hslayout.HsConfig([hslayout, header, left, main]).attachNodeTree(myConfig, document.body);
    +  60}
    +  61
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/index.html b/docs/src/hsDoc/index.html new file mode 100644 index 0000000..0b2e58d --- /dev/null +++ b/docs/src/hsDoc/index.html @@ -0,0 +1,27 @@ + + +

    index.ts

    +
       1/**
    +   2 * Progam entry point. Initiates loading the docsets and setting up a router structure
    +   3 */

    +   4
    +   5/** */
    +   6import { init } from './Site';
    +   7
    +   8init();
    +   9
    +  10
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/markdown.html b/docs/src/hsDoc/markdown.html new file mode 100644 index 0000000..0de823c --- /dev/null +++ b/docs/src/hsDoc/markdown.html @@ -0,0 +1,100 @@ + + +

    markdown.ts

    +
       1const showdown  = require('showdown');
    +   2
    +   3/**
    +   4 * process a markdown comment string and returns the equivalent html syntax. 
    +   5 * @param text the comment to markdown
    +   6 * @param short if true, only the first paragraph is returned
    +   7 * @return the marked down comment
    +   8 */

    +   9export function markDown(text:string, short:boolean=false, currentRoute:string):string {
    +  10    const converter = new showdown.Converter({
    +  11        tables:                 true,   // enables |...| style tables; requires 2nd |---| line
    +  12        ghCompatibleHeaderId:   true,   // github-style dash-separated header IDs
    +  13        smartIndentationFix:    true,   // fixes ES6 template indentations
    +  14        takslists:              true,   // enable - [ ] task; doesn't seem to work.
    +  15        strikethrough:          true    // enables ~~text~~
    +  16    });
    +  17    let result = (!text)? '' : converter.makeHtml(text);
    +  18    if (short) {
    +  19        const i = result.indexOf('

    ');
    +  20        if (i>0) { result = result.substring(0, i); }
    +  21    }
    +  22    result = substituteLinks(result, currentRoute);
    +  23    return result;
    +  24}
    +  25
    +  26/**
    +  27 * replaces link statements in the comment with hyperlink references.
    +  28 * The format of a link statement is "{@link *docset*:*path* linked text}", where
    +  29 * - *docset* is the name of the docset
    +  30 * - *path* is the structural path of a component with steps on the path separated by a period,
    +  31 *    following the pattern *module*.*entity*.*member* with
    +  32 *     - *module* = the name of the module file
    +  33 *     - *entity* = [*class* | *function* | *variable*]
    +  34 *     - *member* = [*method* | *variable*]
    +  35 * - if *path* is omittied, or is `overview`, the library overview will be shown.
    +  36 *   
    +  37 * Examples: 
    +  38 * - '{@link hsDoc: Doc Overview}' -> {@link hsDoc: Doc Overview}
    +  39 * - '{@link hsDoc:DocSets.DocSets.add the `adds` function}' --> {@link hsDoc:DocSets.DocSets.add the `adds` function}
    +  40 * 
    +  41 * @param comment the comment in which to replace the links
    +  42 * @return the comment with substituted links 
    +  43 */

    +  44function substituteLinks(comment:string, currentRoute:string):string {
    +  45    function deconstructRoute(route:string) {
    +  46        let lib, mod;
    +  47        route.replace(/\/([^\/.]*)\/([^\/\s]*$)/gi, (match, ...args) => {
    +  48            lib = args[0];
    +  49            mod = args[1];
    +  50            return '';
    +  51        }); 
    +  52        return [lib, mod];
    +  53    }
    +  54
    +  55    function getLibMod(path:string) {
    +  56        let lib, mod, frag; 
    +  57        if (path.indexOf(':')>0) {
    +  58            [lib, mod] = path.split(':');
    +  59        } else  {
    +  60            lib = defLib;
    +  61            mod = path;
    +  62        }
    +  63        if (mod.indexOf('#')>0) {
    +  64            [mod, frag] = mod.split('#');
    +  65        }
    +  66        return [lib, mod, frag];       
    +  67    }
    +  68
    +  69    let [defLib] = deconstructRoute(currentRoute);
    +  70
    +  71    // regex: requires whitespace before {@link; otherwise treated as quoted '{@link...}'
    +  72    comment = comment.replace(/\s{@link ([\S]*)\s*(.+)}/gi, (match, ...args) => {
    +  73        const path = args[0];
    +  74        const text = args[1];
    +  75        let [lib, module] = getLibMod(path);        
    +  76        return (module === '' || module === '0' || module === 'overview')?
    +  77                ` ${text}
    ` :
    +  78                ` ${text}`;
    +  79    });
    +  80    return comment;
    +  81
    +  82}
    +  83
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/overview.html b/docs/src/hsDoc/overview.html new file mode 100644 index 0000000..3a7a95f --- /dev/null +++ b/docs/src/hsDoc/overview.html @@ -0,0 +1,161 @@ + + +

    overview.ts

    +
       1/**
    +   2# hsDoc
    +   3___
    +   4hsDoc.js is a code documentation viewer for [Typescript](https://www.typescriptlang.org) projects.
    +   5It renders JSON documentation files as created by [typedoc](http://typedoc.org).
    +   6
    +   7## Creating the Documentation DocSet
    +   8Follow the instruction for `typedoc` in commenting the code and set the `json` option to create a 
    +   9json file containing the documentation. See the Configuration section below for details.
    +  10
    +  11In addition to the documented source files, `hsDoc` recognizes a special **`overview.ts`** file 
    +  12that will be displayed as a project overview. 
    +  13For this to work, `typedoc` requires the file to have two separate comment entries.
    +  14If the second comment is missing, `typedoc` will not generate a comment in the DocSet.
    +  15
    +  16DocSets are shown as menu tabs across the top of the window. To include a DocSet in the menu, ensure that the 
    +  17corresponding documentation `.json` file is copied into the `data` folder inside the `hsDoc` staging location 
    +  18for the http server. Then edit the `index.json` file to include the documentation file name in the "docs" section. 
    +  19
    +  20### Modules
    +  21Each source file is considered to be a `module`. Modules are shown in the left-hand overview panel of the main `hsDoc` window.
    +  22Alternatively, a `@module` statement in the summary comment at the top of a file will create, or add to, a module of the specified name.
    +  23This encourages to separate code into files without cluttering the overview.
    +  24
    +  25### Linking across the docsets
    +  26Links to items across the docsets can be placed via a link directive: 
    +  27- "{@link [*docset*:]*module*.*item* linked text}", 
    +  28where
    +  29 - *docset* optional; the name of the docset. If omitted, a link within the current docSet will be created
    +  30 - *module* is name of the module to link to; 
    +  31   if *module* is `overview`, or unspecified, the link will point to the docset overview page.
    +  32 - *item* is the name, or period-separated path, of the item within the module. 
    +  33 - *linked text* is displayed with a link to path within module
    +  34
    +  35Examples:
    +  36- '{@link overview Overview of hsDoc docSet}' -> {@link overview Overview of hsDoc docSet}
    +  37- '{@link hsDoc: Overview of hsDoc docSet}' -> {@link hsDoc: Overview of hsDoc docSet}
    +  38- '{@link hsDoc:DocSets.DocSets.add the `adds` function}' --> {@link hsDoc:DocSets.DocSets.add the `adds` function}
    +  39- '{@link DocSets.DocSets.add the `adds` function}' --> {@link DocSets.DocSets.add the `adds` function}
    +  40
    +  41
    +  42### Mithril Code Examples
    +  43 * `hsDoc` supports creating inline code examples in comment sections as explained 
    +  44 * in the {@link hsDoc:MainExample MainExample overview}.
    +  45 * 
    +  46 * 
    +  47 * let tl = [10, 10];
    +  48 * 
    +  49 * const rnd = () => Math.floor(80*Math.random());
    +  50 * 
    +  51 * function click() { tl = tl.map(i => rnd()); }
    +  52 * 
    +  53 * m.mount(root, {
    +  54 *     view: () => m('.myBlock', {
    +  55 *         onclick:click, 
    +  56 *         style:`top:${tl[0]}%; left:${tl[1]}%;`
    +  57 *     }, m('', 'click me'))})
    +  58 * 
    +  59 * 
    +  60 * .myBlock {
    +  61 *     text-align:center;
    +  62 *     color: white;
    +  63 *     background-color: red;
    +  64 *     position:relative;
    +  65 *     width:  20%;
    +  66 *     height: 30%;
    +  67 * }
    +  68 * .myBlock div {
    +  69 *     padding-top: 40%;
    +  70 * }
    +  71 * 
    +  72 * 

    +  73
    +  74## Configuring typedoc
    +  75As an example, we use grunt-typedoc with the following configuration:
    +  76
    +  77### tsconfig.json:
    +  78A `tsconfig.json` file seems to be required by typedoc. The file can be empty
    +  79
    +  80### Gruntfile:
    +  81module.exports = function(grunt) {
    +  82    ...
    +  83    typedoc: {
    +  84        code: {
    +  85            options: {
    +  86                tsconfig: 'typedoc.json',
    +  87                json:   './docs/hsDocs.json',
    +  88                out:    './docs',
    +  89                mode:   'modules',
    +  90                name:   'hsDoc'
    +  91            }
    +  92            src: ['src/*.ts', '!src/*.spec.ts']
    +  93        }
    +  94    },
    +  95
    +  96   ...
    +  97   grunt.loadNpmTasks('grunt-typedoc');
    +  98   ...
    +  99   grunt.registerTask('doc', ['typedoc']);
    + 100}
    + 101

    + 102
    + 103## Setting up the web app
    + 1041. Create an **`index.html`** in the directory to serve from (web-app directory): 
    + 105
    + 106
    + 107
    + 108
    + 109
    + 110

    + 111
    + 1122. Copy **`hsDocs.js`** and **`styles.css`** into the same directory
    + 113
    + 1143. Create a subdirectory **`data`** and copy the docsets into it, including **`hsDocs.json`**
    + 115
    + 1164. Create a list of docsets to render in a new file **`index.json`** inside **`data`**:
    + 117
    + 118{
    + 119    "docs": [
    + 120        "hsDocs.json",
    + 121        ...
    + 122    ],
    + 123    "title": "HS Libraries"   // will be displayed at the top left corner
    + 124}

    + 125
    + 1265. Point a browser to the web-app directory
    + 127
    + 128## Dependencies
    + 129### For creating the docsets:
    + 130- [typedoc](http://typedoc.org)
    + 131
    + 132### For rendering the docsets:
    + 133- [Mithril](https://mithril.js.org)
    + 134- [showdown](https://github.com/showdownjs/showdown)
    + 135- [hsLayout]
    + 136- [webpack]
    + 137
    + 138## Structural Code Overview
    + 139The main entry point for the web-app is index.ts, which initiates loading the docsets 
    + 140and sets up a mithril {@link hsDoc:Router router} 
    + 141
    + 142*/

    + 143
    + 144/** */
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/view/DocsMenu.html b/docs/src/hsDoc/view/DocsMenu.html new file mode 100644 index 0000000..cdd20ab --- /dev/null +++ b/docs/src/hsDoc/view/DocsMenu.html @@ -0,0 +1,56 @@ + + +

    view/DocsMenu.ts

    +
       1import { m, Vnode, Layout }  from 'hslayout';
    +   2import { DocSets }              from '../DocSets'; 
    +   3import { Menu, SelectorDesc }       from 'hswidget';
    +   4
    +   5/**
    +   6 * Creates the title menu for selecting between the different docsets.
    +   7 * Instantiate the DocsMenu via a standard `mithril` call:```
    +   8 *    m(DocsMenu, { docSet:})
    +   9 * ```
    +  10 * DocsMenu performs the following actions:
    +  11 * - for the first call of the view lifecycle hook, the available docSets are loaded.
    +  12 *   DocsMenu searches for an index `json` file at the location specified in the 
    +  13 *   `docSet` field of the `node.attrs` parameter. If none is specified, the 
    +  14 *   default is used as specified in the {@link hsDoc:DocSets.FILE DocSets FILE} setting.
    +  15 * - DocsMenu retrieves all available docSets via {@link hsDoc:DocSets.DocSets.get DocSets.get}.
    +  16 * - DocsMenu creates a `SelectorDesc` structure with a {@link hsWidget:hsSelector.SelectorDesc.changed `changed`} callback that initiates a route change 
    +  17 *   to the selected docSet
    +  18 */

    +  19export class DocsMenu extends Layout {
    +  20    docSet = '';
    +  21
    +  22    private getDesc(attrs:any):SelectorDesc { 
    +  23        if (this.docSet !== attrs.docSet) {
    +  24            this.docSet = attrs.docSet;
    +  25            DocSets.loadList(attrs.docSet);
    +  26        }
    +  27        const items = DocSets.get(); 
    +  28        return {
    +  29            items: items.map((c:string) => c),
    +  30            defaultItem: (attrs.route && attrs.route.lib)? attrs.route.lib : items[0],
    +  31            changed: (item:string) => m.route.set('/api/:lib/0', {lib:item})
    +  32        };
    +  33    }
    +  34
    +  35    getComponents(node:Vnode):Vnode {
    +  36        const desc:SelectorDesc = this.getDesc(node.attrs);
    +  37        return m(Menu, {desc: desc});
    +  38    }
    +  39}
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/view/LeftNav.html b/docs/src/hsDoc/view/LeftNav.html new file mode 100644 index 0000000..ed4f037 --- /dev/null +++ b/docs/src/hsDoc/view/LeftNav.html @@ -0,0 +1,171 @@ + + +

    view/LeftNav.ts

    +
       1/**
    +   2 * LeftNav: Responsible for constructing the left-hand navigation pane. 
    +   3 */

    +   4
    +   5/** */
    +   6import { m, Vnode}  from 'hslayout';
    +   7import { Layout }from 'hslayout';
    +   8import { Collapsible }from 'hswidget';
    +   9import { DocSets } from '../DocSets'; 
    +  10import { libLink } from './Parts'; 
    +  11
    +  12
    +  13/**
    +  14 * Constructs the left-hand navigation pane
    +  15 */

    +  16export class LeftNav extends Layout {
    +  17    getComponents(node: Vnode): Vnode {
    +  18        let lib:string;
    +  19        let field:string;
    +  20        if (node.attrs && node.attrs.route) {
    +  21            lib = node.attrs.route.lib;
    +  22            field = node.attrs.route.field;
    +  23        }
    +  24        const docSet = DocSets.get(lib, 0) || {name:'unknown', id:0};
    +  25        return m('.hs-left', [m('.hs-left-nav', navList(docSet, field))]);
    +  26    } 
    +  27}
    +  28
    +  29/** creates the list if modules (`*.ts` files) */
    +  30function navList(docSet:any, field:string):Vnode[] {
    +  31    /** */
    +  32    function collectModules(docSet:any) {
    +  33        const modulesByName = {};
    +  34        docSet.modules = [];
    +  35        if (docSet.children) {
    +  36            docSet.children.forEach((c:any) => {
    +  37                // don't show modules from other projects (isExternal flag) or modules on the ignore list
    +  38                if (!(c.flags && c.flags.isExternal) && !ignoreModules[c.name]) {
    +  39                    const name = c.innerModule? c.innerModule : c.name;
    +  40                    let module = modulesByName[name];
    +  41                    if (!module) {  // new module
    +  42                        docSet.modules.push(module = modulesByName[name] = { 
    +  43                            name: name,
    +  44                            lib: docSet.lib,
    +  45                            fullPath: docSet.fullPath + '.'+ name,
    +  46                            groups:[]
    +  47                        });
    +  48                    }
    +  49                    // get existing module groups
    +  50                    const groups = {};
    +  51                    module.groups.forEach((g:any) => groups[g.title] = g); 
    +  52                    // for each group in child:
    +  53                    if (c.groups) { c.groups.forEach((g:any) => {
    +  54                        let group = groups[g.title]; // get existing 
    +  55                        if (!group) {                 //  else create new
    +  56                            group = groups[g.title] = {
    +  57                                children:[],
    +  58                                kind: g.kind,
    +  59                                title: g.title
    +  60                            };
    +  61                        module.groups.push(group);
    +  62                        }
    +  63                        group.children = group.children.concat(g.children);
    +  64                    });}
    +  65                }
    +  66            });
    +  67        }
    +  68    }
    +  69    /** 
    +  70     * processes a module, i.e. a `.ts` file.
    +  71     */

    +  72    function externalModule(mdl:any) {
    +  73        let selected = false;
    +  74        if (field===''+mdl.id || field.indexOf(mdl.fullPath) === 0) { selected=true; }
    +  75
    +  76        return m(Collapsible, {css:`.hs-left-nav-module`, preArrow: true, isExpanded:selected, components:[
    +  77            m(`${selected?'.hs-left-nav-selected':''}`, libLink(`a.hs-left-nav-module-name `, mdl.lib, mdl.fullPath, mdl.name)),
    +  78            !mdl.groups? undefined : mdl.groups.map((g:any) => entries(g, mdl, field))
    +  79        ]});
    +  80    }
    +  81
    +  82    if (docSet.kind === 0) { // External DocSets
    +  83        collectModules(docSet);
    +  84//        const modules = docSet.children? docSet.children.map(externalModule) : ['no children'];
    +  85        const modules = docSet.modules.map(externalModule);
    +  86        modules.unshift(m('.hs-left-nav-header', 'Modules'));
    +  87        return [m('.hs-left-nav-content', modules)];
    +  88    }
    +  89}
    +  90
    +  91/**
    +  92 * modules to ignore in the list
    +  93 */

    +  94const ignoreModules = {
    +  95    overview:   true,   // the project overview.ts file
    +  96    index:      true    // the index.ts file
    +  97};
    +  98
    +  99//const expanded: {string?:boolean} = {};
    + 100
    + 101/**
    + 102 * processes a group of entries, e.g. Variables, Functions, or Classes.
    + 103 * @param group the group structure within the docset
    + 104 * @param mdl the entire module docset
    + 105 * @param field the field ID to be displayed on the main panel
    + 106 */

    + 107function entries(group:any, mdl:any, field:string) {
    + 108    function moduleGet(c:any) {
    + 109        return DocSets.get(mdl.lib, c);
    + 110    }
    + 111    /**
    + 112     * processes one entry within a group, e.g. one variable, function, or class.
    + 113     */

    + 114    function entry(mod:any) { 
    + 115        const selected = (field===''+mod.id || field===mod.fullPath)? '.hs-left-nav-selected' : '';
    + 116        const exported = (mod.flags && mod.flags.isExported);
    + 117        const statik   = (mod.flags && mod.flags.isStatic);
    + 118        const css = `a.hs-left-nav-entry ${selected} ${exported?'.hs-left-nav-exported' : ''}`;
    + 119        return (!exported && group.title==='Variables')? '' :   // ignore local module variables
    + 120            m('', [
    + 121                statik? 'static': '',
    + 122                libLink(css, mod.lib, mod.fullPath, mod.name)
    + 123            ]);
    + 124    }
    + 125
    + 126    function empty(mod:any) { return mod !== ''; }
    + 127
    + 128    let grp = [];
    + 129    if (group && group.children) {
    + 130        grp = group.children
    + 131            .map(moduleGet)         // replace id reference by module
    + 132            .sort(exportAscending)  // sort: exported first, then alphabetically
    + 133            .map(entry)             // replace module by vnode structure
    + 134            .filter(empty);         // filter empty elements
    + 135        if (grp.length > 0) { // add an entries header if there are elements
    + 136            grp.unshift(m('.hs-left-nav-header', group.title));
    + 137        }
    + 138    }
    + 139    return (grp.length > 1)? m(`.hs-left-nav-entries`, grp) : '';
    + 140}
    + 141
    + 142/**
    + 143 * sorting function: sort first by exported status, then alphabetically.
    + 144 */

    + 145function exportAscending(a:any, b:any):boolean|number {
    + 146    if (a.flags && b.flags) {
    + 147        if (a.flags.isExported && b.flags.isExported) { return a.name > b.name; }
    + 148        else if (a.flags.isExported) { return -1; }
    + 149        else if (b.flags.isExported) { return 1; }
    + 150        else { return a.name > b.name; }
    + 151    } else { return a.name > b.name; }
    + 152}
    + 153
    + 154
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/view/MainComment.html b/docs/src/hsDoc/view/MainComment.html new file mode 100644 index 0000000..8aaf21b --- /dev/null +++ b/docs/src/hsDoc/view/MainComment.html @@ -0,0 +1,171 @@ + + +

    view/MainComment.ts

    +
       1/**
    +   2 * Processing of comments.
    +   3 */

    +   4
    +   5/** */
    +   6import { m, Vnode } from 'hslayout';
    +   7import { markDown } from '../markdown';
    +   8import { example }  from './MainExample';
    +   9
    +  10/**
    +  11 * Main comment processing. The result appears directly below the title in the main panel.
    +  12 * Function parameters are not reported in short form here since it is assumed they will be listed 
    +  13 * individually below the main comment
    +  14 * @param mdl the module to scan for comments
    +  15 * @return a vnode representing the comment entries
    +  16 */

    +  17export function commentLong(mdl:any):Vnode { 
    +  18    let content:any[] = [];
    +  19    if (mdl.comment) {
    +  20        content.push(textOrShortTextOrDescription(mdl.comment, false));
    +  21        content.push(returns(mdl.comment, false));
    +  22        content.push(commentRemainder(mdl.comment));
    +  23    }
    +  24    return m('.hs-item-comment', content);
    +  25}
    +  26
    +  27/**
    +  28 * Shortended comment processing. This form is used to report on subitems below the main panel item.
    +  29 * If `short` is true, only the first paragraph of the main comment will be returned. Otherwise, 
    +  30 * this function creates a full comment including an inline list of parameters and the return value
    +  31 * @param mdl the module to scan for comments
    +  32 * @param short if true, only the first paragraph of the main comment is processed.
    +  33 * @return a vnode representing the comment entries
    +  34 */

    +  35export function comment(mdl:any, short=false):Vnode {
    +  36    let content:any[] = [];
    +  37    if (mdl.comment) {
    +  38        content.push(textOrShortTextOrDescription(mdl.comment, short));
    +  39        if (!short) {
    +  40            content.push(otherCommentTags(mdl.comment));
    +  41            if (mdl.parameters) {
    +  42                content = content.concat(mainCommentParams(mdl.parameters));
    +  43            }
    +  44        }
    +  45        content.push(returns(mdl.comment, false));
    +  46        content.push(commentRemainder(mdl.comment));
    +  47    }
    +  48    return m('.hs-item-comment', content);
    +  49
    +  50
    +  51/**
    +  52 * Report the item's description. This can come in different forms that are all handled here:
    +  53 * - comment.shortText: 
    +  54 * - comment.text: 
    +  55 * - comment.tags[{tag:'description}, text:]
    +  56 * Any resulting comment will be translated from markdown to html and returned as a `Vnode`.
    +  57 * @param comment the comment object to parse
    +  58 * @param short boolean; if true, only the first paragraph of the description will be returned
    +  59 */

    +  60function textOrShortTextOrDescription(comment:any, short:boolean):Vnode {
    +  61    let text = (comment.shortText || '');
    +  62    if (comment.text) { text += '\n'+ (comment.text || ''); }
    +  63    if (comment.tags) {
    +  64        comment.tags.map((tag:any) => {if (tag.tag==='description') { text = tag.text;}} );
    +  65    }
    +  66    text = text.replace(//gi, short? '' : example({}));
    +  67    return m('.hs-item-comment-desc', prettifyCode(text, short));
    +  68}
    +  69
    +  70/**
    +  71 * creates the `returns` message for a function or method.
    +  72 */

    +  73function returns(comment:any, short:boolean):Vnode {
    +  74    let text = comment.returns;
    +  75    return m('.hs-item-comment-return', !text? '': [            
    +  76        m('span.hs-item-comment-tag', 'returns:'), 
    +  77        m('span.hs-item-comment-text', text)
    +  78    ]);
    +  79}
    +  80
    +  81function commentRemainder(comment:any):string|Vnode {
    +  82    return m('', Object.keys(comment).map((tag:any) => {
    +  83            switch(tag) {
    +  84                case 'tags':        // already handled
    +  85                case 'shortText':   // already handled
    +  86                case 'text':        // already handled
    +  87                case 'description': // already handled
    +  88                case 'returns':     // already handled
    +  89                        return '';
    +  90                default: return m('.hs-item-comment-special', [
    +  91                    m('span.hs-item-comment-tag', tag), 
    +  92                    m('span.hs-item-comment-text', comment[tag])
    +  93                ]);;
    +  94            }
    +  95    }));
    +  96}
    +  97
    +  98function otherCommentTags(comment:any):string|Vnode {
    +  99    return m('', !comment.tags? [] : comment.tags.map((tag:any) => {
    + 100        switch(tag.tag) {
    + 101            case 'description': return ''; // skip since already handled
    + 102            default: return m('.hs-item-comment-special', [
    + 103                m('span.hs-item-comment-tag', tag.tag), 
    + 104                m('span.hs-item-comment-text', tag.text)
    + 105            ]);
    + 106        }
    + 107    }));
    + 108}
    + 109
    + 110function mainCommentParams(params:any):Vnode {
    + 111    return m('.hs-item-comment-params',  params.map((par:any) =>
    + 112        m('.hs-item-comment-param', [
    + 113            m('span.hs-item-comment-tag', par.name+':'), 
    + 114            m('span.hs-item-comment-text', !par.comment? '' :
    + 115                ((par.defaultValue!==undefined)? `[default: ${par.defaultValue}] ` : '') + par.comment.text
    + 116            )
    + 117        ])
    + 118    ));
    + 119}
    + 120
    + 121/**
    + 122 * finds segments of `...` in `comment` and replaces them with a prettified version.
    + 123 * Currently the function performs two operations:
    + 124 * - add indentation for brackets {...}
    + 125 * - wrap the <code>...</code> part within <pre>...</pre> brackets
    + 126 * @param comment the comment comment 
    + 127 */

    + 128function prettifyCode(comment:string, short:boolean):Vnode { 
    + 129//    const indentSpaces = 2;
    + 130    let result = comment;
    + 131
    + 132    function braceIndenting(text:string): string {
    + 133        let indent = 0;
    + 134        const result = text
    + 135            .substring(6, text.length-7)    // remove  and 
    + 136            .trim()
    + 137            .replace(/(<)/g, '<').replace(/(>)/g, '>')
    + 138            .split('\n')
    + 139            .map((l:string) => {
    + 140                let oldIndent = indent;
    + 141                let k = l.trim();
    + 142                indent += Math.max(-1, Math.min(1, k.split('{').length - k.split('}').length)); 
    + 143                indent += Math.max(-1, Math.min(1, k.split('[').length - k.split(']').length)); 
    + 144                return ''.repeat(((indent < oldIndent)?indent:oldIndent)) + k;
    + 145            })
    + 146            .join('\n')
    + 147            .trim();
    + 148        return '
    ' + result + '
    ';
    + 149    }
    + 150
    + 151    result = result.replace(/([\S\s]*?)<\/code>/gi, braceIndenting);
    + 152    return m.trust(markDown(result, short, m.route.get()));
    + 153}
    + 154
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/view/MainDetail.html b/docs/src/hsDoc/view/MainDetail.html new file mode 100644 index 0000000..fe2f999 --- /dev/null +++ b/docs/src/hsDoc/view/MainDetail.html @@ -0,0 +1,181 @@ + + +

    view/MainDetail.ts

    +
       1import { m, Vnode}      from 'hslayout';
    +   2import { Layout }    from 'hslayout';
    +   3import { DocSets }      from '../DocSets'; 
    +   4import { comment, commentLong }  from './MainComment';
    +   5import { flags, sourceLink, signature, type, 
    +   6         extensionOf, inheritedFrom,
    +   7         kindString, itemName, makeID } 
    +   8                        from './Parts'; 
    +   9
    +  10
    +  11/**
    +  12 * Creates Documentation on the main panel 
    +  13 */

    +  14export class MainDetail extends Layout { 
    +  15    getComponents(node:Vnode): Vnode {
    +  16        let lib, field;
    +  17        if (node.attrs.route) {
    +  18            lib = node.attrs.route.lib;
    +  19            field = node.attrs.route.field;
    +  20        }
    +  21        node.attrs.route = undefined;
    +  22
    +  23        let result = getOverview(lib, field) || itemDoc(DocSets.get(lib, field) || ''); 
    +  24        return m('.hs-main-detail', [result]); 
    +  25    }
    +  26}
    +  27
    +  28/**
    +  29 * Checks if the project overview is being requested and returns the overview, 
    +  30 * or `undefined` if not available
    +  31 * @param mdl the module name to check
    +  32 * @return Vnode containing the overview file, or `undefined`
    +  33 */

    +  34function getOverview(lib:string, mdl:string):Vnode {
    +  35    if (mdl === '0' || mdl === '') {  //show module overview
    +  36        mdl = DocSets.get(lib, `${lib}.overview`);
    +  37        if (mdl) { // if project has an overview:
    +  38            return overviewDoc(mdl); 
    +  39        }
    +  40    }
    +  41    return undefined;
    +  42}
    +  43
    +  44/**
    +  45 * Creates documentation for standard items in the main panel
    +  46 * @param mdl the module to document on the main panel
    +  47 */

    +  48function itemDoc(mdl:any) {
    +  49    const sig = mdl.signatures? mdl.signatures[0] : mdl;
    +  50    return m('.hs-item-doc', [
    +  51        title(mdl, sig),
    +  52        commentLong(sig),
    +  53        members(sig, sig)
    +  54    ]);
    +  55}
    +  56
    +  57/**
    +  58 * Creates documentation for the project overview in the main panel
    +  59 * @param mdl the module to document on the main panel
    +  60 */

    +  61function overviewDoc(mdl:any) {
    +  62    const sig = mdl.signatures? mdl.signatures[0] : mdl;
    +  63    return m('.hs-item-doc', [
    +  64        commentLong(sig),
    +  65    ]);
    +  66}
    +  67
    +  68/**
    +  69 * renders the title of the main panel
    +  70 * @param mdl the module to document 
    +  71 * @param sig a signature of the module, or the the module itself
    +  72 */

    +  73function title(mdl:any, sig:any): Vnode { 
    +  74    return m('.hs-item-title', {id: makeID('title', mdl)}, itemDescriptor(mdl, sig)); 
    +  75}
    +  76
    +  77function members(mdl:any, sig:any): Vnode {
    +  78    if (mdl.groups) {
    +  79        return m('.hs-item-members', [
    +  80            ...mdl.groups.map((g:any) => member(g, mdl.lib, true, true)),
    +  81            ...mdl.groups.map((g:any) => member(g, mdl.lib, true, false)),
    +  82            ...mdl.groups.map((g:any) => member(g, mdl.lib, false, true)),
    +  83            ...mdl.groups.map((g:any) => member(g, mdl.lib, false, false))
    +  84        ]);
    +  85    } else if (mdl.parameters) {
    +  86        return m('.hs-item-members', parameter(mdl.parameters, mdl.lib));
    +  87    } else {
    +  88        return m('.hs-item-members');
    +  89    }
    +  90}
    +  91
    +  92function parameter(g:any[], lib:string): Vnode {
    +  93    let content = g.map((c:any) => m('.hs-item-parameter', {id:makeID('parameter', c)}, itemChild(c)));
    +  94    content.unshift(m('.hs-item-member-title', {id:'parameters'}, m('span', 'Parameters')));
    +  95    return m('.hs-item-member', content);
    +  96}
    +  97
    +  98function member(group:any, lib:string, statc:boolean, publc: boolean): Vnode {
    +  99    const resolve           = ((c:number) => DocSets.get(lib, c));
    + 100    const directChildren    = ((mdl:any) => !mdl['inheritedFrom']);
    + 101    const inheritedChildren = ((mdl:any) =>  mdl['inheritedFrom']);
    + 102    const groupMap = {
    + 103        'External modules': '.hs-item-external-module',
    + 104        'Constructors':     '.hs-item-constructor',
    + 105        'Classes':          '.hs-item-class',          
    + 106        'Interfaces':       '.hs-item-interface',          
    + 107        'Functions':        '.hs-item-function',          
    + 108        'Methods':          '.hs-item-method',          
    + 109        'Variables':        '.hs-item-variable',
    + 110        'Object literals':  '.hs-item-object-literal',
    + 111        'Properties':       '.hs-item-property',
    + 112        'Type aliases':     '.hs-item-alias',          
    + 113        'Accessors':        '.hs-item-accessors'        
    + 114    };
    + 115    const fn = groupMap[group.title] || '.hs-item-unknown-member';
    + 116    const isPublic = (flags:any) => flags.isPublic || (flags.isExported && !flags.isPrivate);
    + 117
    + 118    const content = group.children
    + 119        .map(resolve)
    + 120        .filter(directChildren)
    + 121        .filter((mdl:any) => statc? mdl.flags.isStatic : !mdl.flags.isStatic)
    + 122        .filter((mdl:any) => publc? isPublic(mdl.flags) : !isPublic(mdl.flags))
    + 123        .map((mdl:any) => m(fn, {id:makeID(group.title, mdl)}, itemChild(mdl)));
    + 124    const inherited = group.children
    + 125        .map(resolve)
    + 126        .filter(inheritedChildren)
    + 127        .filter((mdl:any) => statc? mdl.flags.isStatic : !mdl.flags.isStatic)
    + 128        .filter((mdl:any) => publc? mdl.flags.isPublic : !mdl.flags.isPublic)
    + 129        .map((mdl:any) => m(`.hs-item-inherited ${fn}`, {id:makeID(group.title, mdl)}, itemChild(mdl)));
    + 130
    + 131    const publStr = publc?'Public':'Protected or Private';
    + 132    const statStr = statc?'Static':''; 
    + 133    if (inherited.length>0) {
    + 134        inherited.unshift(m('.hs-item-inherited .hs-item-member-title', m('span', `${publStr} ${statStr} Inherited ${group.title}`)));
    + 135    }
    + 136    if (content.length>0) {
    + 137        content.unshift(m('.hs-item-member-title', {id:group.title.toLowerCase()}, m('span', `${publStr} ${statStr} ${group.title}`)));
    + 138    }
    + 139    return m(`.hs-item-member ${statc?'.hs-item-static':''} ${publc?'.hs-item-public':''}`, content.concat(inherited));
    + 140}
    + 141
    + 142function itemDescriptor(mdl:any, sig:any):Vnode {
    + 143    try { return m('.hs-item-desc', [ 
    + 144            flags(mdl),
    + 145            kindString(mdl),
    + 146            itemName(mdl, mdl),
    + 147            signature(sig, mdl),
    + 148            type(sig,  mdl.lib),
    + 149            extensionOf(mdl),
    + 150            inheritedFrom(mdl),
    + 151            sourceLink(mdl)
    + 152        ]);
    + 153    }
    + 154    catch(e) { console.log(e); console.log(mdl); }
    + 155}
    + 156
    + 157function itemChild(mdl:any, sig=mdl): Vnode[] {
    + 158    return mdl.signatures? 
    + 159        mdl.signatures.map((s:any) => m('.hs-item-child-signature',[itemDescriptor(mdl, s), comment(s, true)])) : 
    + 160        [itemDescriptor(mdl, sig), comment(sig,true)];
    + 161}
    + 162
    + 163
    + 164
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/view/MainExample.html b/docs/src/hsDoc/view/MainExample.html new file mode 100644 index 0000000..7c29c09 --- /dev/null +++ b/docs/src/hsDoc/view/MainExample.html @@ -0,0 +1,285 @@ + + +

    view/MainExample.ts

    +
       1/**
    +   2 * Comment sections may contain code examples that are placed within <example> tags.
    +   3 * 
    +   4 * `hsDoc` will interpret and execute Javascript instructions within a <`file name='script.js'`> tag.
    +   5 * and stylesheet instructions with a <`file name='style.css'`> tag, as in following example:
    +   6 * 
    +   7 *     <example> 
    +   8 *     
    +   9 *     m.mount(root, { 
    +  10 *         view:() => m(hslayout.Layout, { columns:[], 
    +  11 *             content:['first line','second line')]
    +  12 *         })
    +  13 *     });
    +  14 *     
    +  15 * 
    +  16 *     
    +  17 *     .hsLeaf { 
    +  18 *         color: blue; 
    +  19 *     }
    +  20 *     
    +  21 *     </example>
    +  22 * 
     
    +  23 * 
    +  24 * ### Scripts 
    +  25 * Scripts are expected to mount a `mithril Vnode` on a root DOM element using `m.mount` or `m.render`. 
    +  26 * Do not use `m.route` as only a single call is allowed per web app and that is used to manage the 
    +  27 * main hsDoc site menu and navigation.
    +  28 * 
    +  29 * hsDoc internally uses the [global `Function` object][Function] to parse and execute the script. 
    +  30 * Thus the script has access only to global objects and to objects provided
    +  31 * as parameters in the `Function` constructor. hsDoc currently provides the following namespaces as parameters
    +  32 * for use in the scripts:
    +  33 * - **m**: the `Mithril` m function    
    +  34 * - **layout**: the {@link hsLayout: `hsLayout`} namespace, providing functions to layout the browser window.
    +  35 * - **widget**: the {@link hsGraph: `hsGraph`} namespace, providing various UI widget functions.
    +  36 * - additionally, the parameter **root** is provided as the DOM element to mount to.
    +  37 * 
    +  38 * [Function]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
    +  39 * 
    +  40 * ### Styles
    +  41 * Styles will be automatically sandboxed so they are valid only within the enclosing example tags. 
    +  42 * This is achieved by prefixing css tags with a unique exmple ID and allows multiple examples to co-exist on the same page.
    +  43 * In the DOM, the example ID is assgned top the <example> tag.
    +  44 * Use `$exampleID` as css tag in the `css` section of the example to refer to the <example> element, 
    +  45 * as shown below.
    +  46 * 
    +  47 * ### Example
    +  48 * 
    +  49 * 
    +  50 * m.mount(root, { 
    +  51 *     view:() => m(hslayout.Layout, {
    +  52 *         css:'.myExample', 
    +  53 *         columns:[], 
    +  54 *         content:[
    +  55 *             'third line',
    +  56 *             'fourth line'
    +  57 *         ]
    +  58 *     })
    +  59 * });
    +  60 * 
    +  61 * 
    +  62 * $exampleID { height: 200px;}
    +  63 * .hs-layout { 
    +  64 *     margin:0; 
    +  65 * }
    +  66 * .myExample { 
    +  67 *     color: red; 
    +  68 *     font-weight:bold; 
    +  69 * }
    +  70 * 
    +  71 * 

    +  72 */

    +  73
    +  74/** */
    +  75import { m }                from 'hslayout';
    +  76import { Menu, SelectorDesc }   from 'hswidget';
    +  77import { Layout }        from 'hslayout';
    +  78import { shortCheckSum }    from 'hsutil'; 
    +  79import { delay }            from 'hsutil'; 
    +  80import * as hslayout        from 'hslayout';
    +  81import * as hswidget        from 'hswidget';
    +  82import * as hsgraph         from 'hsgraph';
    +  83import * as hsdata          from 'hsdata';
    +  84import * as hsutil          from 'hsutil';
    +  85
    +  86
    +  87/**
    +  88 * describes an executable comment example
    +  89 */

    +  90interface CommentDescriptor { 
    +  91    exampleID: string;                  // example tag ID
    +  92    menuID:    string;                  // menu tag ID
    +  93    desc:   SelectorDesc;               // menu items
    +  94    attrs?: {string?:string};           // 
    +  95    pages:  {string?:string};           // page content for each menu item
    +  96    executeScript?: (root:any) => void; // the example code to execute
    +  97    executeSource?: '';                 // the source code to execute
    +  98    activeSrcPage:string;               // the active page for the source display
    +  99}
    + 100
    + 101/**
    + 102 * Map containing various exampkle configurations 
    + 103 */

    + 104const gInitialized:{string?:CommentDescriptor} = {};
    + 105
    + 106/**
    + 107 * creates the example configuration, generates the DOM hook, and sets up the example execution.
    + 108 * `example` takes a context map of the form `{ name:module, ...}` and return a function 
    + 109 * that can be used in calls to `string.replace`as in the following example:
    + 110 * 

    + 111 * import * as layout from "layout";
    + 112 * text = text.replace(/([\S\s]*?)<\/example>/gi, example({layout:layout}));
    + 113 * 

    + 114 * The modules `m`, `hsLayout`, and `hsGraph` will be added by default as 
    + 115 * ` { m: m, layout: layout, widget: widget } `
    + 116 * @param example the example string extracted from the comment, including the `` tags.
    + 117 * @param context the context in which the example script should be run, expressed as `name`:`namespace` pairs.
    + 118 */

    + 119export function example(context:any) { 
    + 120    context.m        = m;
    + 121    context.hslayout = hslayout;
    + 122    context.hswidget = hswidget;
    + 123    context.hsgraph  = hsgraph;
    + 124    context.hsdata   = hsdata;
    + 125    context.hsutil   = hsutil;
    + 126    const libNames = Object.keys(context);
    + 127    const modules = libNames.map(n => context[n]);
    + 128    return (exmpl:string) => { 
    + 129        const instance = shortCheckSum(exmpl);
    + 130        let IDs = gInitialized[instance]; 
    + 131        if (!IDs) {
    + 132            IDs = gInitialized[instance] = initDesc(() => addExample(IDs)   // called when source menu changes
    + 133                .then(executeScript) 
    + 134                .catch(executeError)
    + 135            );
    + 136            IDs.executeSource = exmpl;
    + 137            try {
    + 138                const scriptFn = new Function('root', ...libNames, getCommentDescriptor(IDs, exmpl));    
    + 139                IDs.executeScript = (root:any) => scriptFn(root, ...modules);
    + 140            }
    + 141            catch(e) { console.log('creating script:' + e); }
    + 142        }
    + 143        if (document.getElementById(IDs.menuID)) { 
    + 144        } else {
    + 145            addExample(IDs).then(executeScript).catch(executeError);
    + 146        }
    + 147
    + 148        const frameHeight = (IDs.attrs? IDs.attrs.height : undefined) || '300px';
    + 149        const wrapWithID = (css:string) => css==='$exampleID'? `#${IDs.exampleID}`: `#${IDs.menuID} ${css}`;
    + 150
    + 151        // prefix css selectors with ID of main execution area to sandbox the scope
    + 152        // (^|}): start of string or end of previous style def
    + 153        // \s*?: any white spaces
    + 154        // (\S*?): capturing group: css name
    + 155        // \s*?{: whitespaces, followed by start of style def
    + 156        const style = (!IDs.pages['css'])? '':                              // empty if no css defined
    + 157                      IDs.pages['css'].replace(/(^|})\s*?(\S*?)\s*?{/gi,    // otherwise wrap each css statement
    + 158                         (x:string, ...args:any[]) => x.replace(args[1], wrapWithID(args[1]))
    + 159        );
    + 160        return ``;
    + 161    };
    + 162}
    + 163
    + 164/**
    + 165 * creates the example configuration 
    + 166 */

    + 167function initDesc(fn:any):CommentDescriptor {
    + 168    return {
    + 169        exampleID:  getNewID(),    // example tag ID
    + 170        menuID:     getNewID(),    // main execution area tag ID
    + 171        desc:
    + 172            items:[],
    + 173            selectedItem: 'js',
    + 174            changed: fn,
    + 175            size: ["50px"]
    + 176        },
    + 177        pages:{},
    + 178        activeSrcPage: undefined
    + 179    };
    + 180}
    + 181
    + 182/** creates a new random example ID for each call. */
    + 183function getNewID():string { 
    + 184    return 'hs'+Math.floor(1000000*Math.random());
    + 185}
    + 186
    + 187/** asynchronously adds the example structure on the page and then executed the script. */
    + 188function addExample(IDs:CommentDescriptor):Promise {
    + 189    return Promise.resolve(IDs).then(addExampleStructure).then(delay(1)); 
    + 190}
    + 191
    + 192/**
    + 193 * returns a parameterless function that can be called via setTimeout to 
    + 194 * mount the menu and execute the script function provided in `IDs`. 
    + 195 * @param IDs the `CommentDescriptor` to execute on. 
    + 196 */

    + 197function addExampleStructure(IDs:CommentDescriptor):CommentDescriptor { 
    + 198    let item = IDs.activeSrcPage || 'js';
    + 199    const root = document.getElementById(IDs.exampleID);
    + 200
    + 201    IDs.desc.changed = (newItem:string) => {
    + 202        item = IDs.activeSrcPage = newItem;
    + 203    };
    + 204
    + 205    m.mount(root, {view: () => m(Layout, { 
    + 206        columns: ["50%"],
    + 207        content: [
    + 208            m(Layout, {
    + 209                content: m('.hs-layout .hs-execution', {id:IDs.menuID}, 'placeholder')
    + 210            }),
    + 211            m(Layout, {
    + 212                rows:["30px", "fill"],
    + 213                css: '.hs-source',
    + 214                content:[
    + 215                    m(Menu, {desc: IDs.desc, size:['50px'] }),
    + 216                    m(Layout, { content: m('.hs-layout .hs-source-main', m.trust(`
    ${IDs.pages[item]}
    `))})
    + 217                ]
    + 218            })
    + 219        ]})
    + 220    });
    + 221    return IDs;
    + 222}
    + 223
    + 224/**
    + 225 * execute the provided script 
    + 226 * @param IDs provides the context in which the script is exceuted/
    + 227 */

    + 228function executeScript(IDs:CommentDescriptor) {
    + 229    const root = document.getElementById(IDs.menuID);
    + 230    try { IDs.executeScript(root); }
    + 231    catch(e) { 
    + 232        console.log("error executing script: " + e); 
    + 233        console.log(IDs.executeSource);
    + 234        console.log(e.stack);
    + 235    }
    + 236    m.redraw();
    + 237    return IDs;
    + 238}
    + 239
    + 240function executeError(e:any) {
    + 241    console.log('rejection executing script:');
    + 242    console.log(e);
    + 243}
    + 244 
    + 245/**
    + 246 * Fills in all fields of the CommentDescriptor provided as `IDs`.
    + 247 * @param IDs the CommentDescriptor to complete
    + 248 * @param example the example string, including  tag
    + 249 * @return the script to execute, as a string
    + 250 */

    + 251function getCommentDescriptor(IDs:CommentDescriptor, example:string):string {
    + 252    let result = '';
    + 253    let attrs = example.match(/)/i);
    + 254    if (attrs && attrs[1]) { 
    + 255        const at = attrs[1].split('=');
    + 256        IDs.attrs =  {[at[0]]: at[1]};
    + 257    }
    + 258    example.replace(/([\S\s]*?)<\/file>/gi, function(text:string) {
    + 259        const args = [...arguments];
    + 260        const content = args[2].trim(); // the part between  and 
    + 261        IDs.desc.items.push(args[1]);   // record available extensions, i.e. 'js', 'html', etc 
    + 262        IDs.pages[args[1]] = content;   // associate the content with the extension
    + 263        return result;
    + 264    });
    + 265    return IDs.pages['js'];
    + 266}
    + 267
    + 268
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/view/MainExample.spec.html b/docs/src/hsDoc/view/MainExample.spec.html new file mode 100644 index 0000000..1d3378b --- /dev/null +++ b/docs/src/hsDoc/view/MainExample.spec.html @@ -0,0 +1,33 @@ + + +

    view/MainExample.spec.ts

    +
       1const hslayout = require('hslayout');
    +   2const m = hslayout.m;
    +   3const o = hslayout.o;
    +   4
    +   5
    +   6o.spec('example', () => {
    +   7    let docsMenu:any;
    +   8    o.before(() => {
    +   9        m.mount(o.root, {view: () => m('', '')});
    +  10        docsMenu = o.root.childNodes[0];
    +  11    }); 
    +  12    o('DocsMenu exists', () => {
    +  13        o(docsMenu===undefined).equals(false)('should be defined');
    +  14    });
    +  15});
    +  16
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/view/Parts.html b/docs/src/hsDoc/view/Parts.html new file mode 100644 index 0000000..fff6508 --- /dev/null +++ b/docs/src/hsDoc/view/Parts.html @@ -0,0 +1,218 @@ + + +

    view/Parts.ts

    +
       1import { m, Vnode} from 'hslayout';
    +   2import { tooltip } from './Tooltip';
    +   3import { DocSets } from '../DocSets'; 
    +   4
    +   5const SourceBase = 'src/'; 
    +   6
    +   7
    +   8// TODO: sort flags in array to garantee sequence of printing
    +   9export function flags(mdl:any, ignore:string[]=[]) {
    +  10    const ignoreExportInKind = ['Method', 'Property'];
    +  11    const knownFlags = {
    +  12        isExported:             'export',
    +  13        isExternal:             'external', // 
    +  14        isPublic:               'public',
    +  15        isPrivate:              'private',
    +  16        isProtected:            'protected',
    +  17        isConstructorProperty:  'constructorProperty',
    +  18        isStatic:               'static',
    +  19        isOptional:             'optional'
    +  20    };
    +  21    return m('span.hs-item-flags', !mdl.flags? [] : 
    +  22        Object.keys(mdl.flags).map((f:string) => {
    +  23            let ign = false;
    +  24            let flag = knownFlags[f];
    +  25            if (flag === undefined) { flag = f; }
    +  26            else { ign = (ignore.indexOf(flag) >= 0); }
    +  27            if (flag === 'export' && ignoreExportInKind.indexOf(mdl.kindString)>=0) { ign = true; }
    +  28            return m(`span.hs-item-${ign?'ignore':(flag===f?'unknown':flag)}-flag`, ign? undefined : flag);
    +  29        })
    +  30    );
    +  31}
    +  32
    +  33export function kindString(mdl:any) {
    +  34    return m('span.hs-item-kind', mdl.kindString);
    +  35}
    +  36
    +  37export function itemName(mdl:any, sub:any) {
    +  38    return m('span.hs-item-name', !mdl.fullPath? sub.name : libLink('a', mdl.lib, mdl.fullPath, sub.name));
    +  39}
    +  40
    +  41
    +  42export function itemTooltip(mdl:any) {
    +  43    return m('span.hs-item-name', tooltip(mdl.name, 'class name and then some', 'bottom'));
    +  44}
    +  45
    +  46export function extensionOf(mdl:any) {
    +  47    return m('span.hs-item-extensions', !mdl.extendedTypes? undefined : [
    +  48        m('span.hs-item-extends', 'extends'),
    +  49        m('span', mdl.extendedTypes.map((t:any, i:number) =>
    +  50            m('span.hs-item-extension', [
    +  51                libLink('a', mdl.lib, DocSets.get(mdl.lib, t.id).fullPath, t.name),
    +  52                mdl.extendedTypes.map.length>(i+1)? ', ': ''
    +  53            ])
    +  54        )),
    +  55    ]);
    +  56}
    +  57
    +  58export function inheritedFrom(mdl:any) {
    +  59    if (mdl.inheritedFrom) {
    +  60        let parent = DocSets.get(mdl.lib, mdl.inheritedFrom.id);
    +  61        parent = DocSets.get(mdl.lib, parent.fullPath.substring(0, parent.fullPath.lastIndexOf('.')));
    +  62        return m('span.hs-item-inherited-from', [
    +  63            m('span', 'inherited from '),
    +  64            libLink('a', parent.lib, parent.fullPath, parent.name)
    +  65        ]);
    +  66    } else {
    +  67        return m('span.hs-item-inherited-from', undefined);
    +  68    }
    +  69}
    +  70
    +  71export function sourceLink(mdl:any) {
    +  72    const source = mdl.sources? mdl.sources[0] : undefined;
    +  73    if (source) {
    +  74        let file = (source.fileName || '').replace('.ts', '.html');
    +  75        const index = file.indexOf(mdl.lib);
    +  76        if (index>0) {
    +  77            file = file.substr(index); // only consider links within the docSet (everything after the lib name)
    +  78        }
    +  79        return m('span.hs-item-member-source',  
    +  80            m('a', { href:`${SourceBase}${mdl.lib}/${file}#${Math.max(0,source.line-5)}`, target:"_blank"}, '[source]')
    +  81        );
    +  82    } else {
    +  83        return m('span.hs-item-member-source', '');
    +  84    }
    +  85}
    +  86
    +  87/**
    +  88 * creates a library link on the specified `name`. 
    +  89 * The link points to `/api//`
    +  90 * @param css the css tag selector to use
    +  91 * @param cls the css class selector to use
    +  92 * @param lib the lib string to point to
    +  93 * @param id the id number to point to
    +  94 * @param name the name on which to formt he link
    +  95 */

    +  96export function libLink(css:string, lib:string, id:string, name:string) {
    +  97    return m(css, { href:`/api/${lib}/${id}`, oncreate: m.route.link, onupdate: m.route.link }, name);
    +  98};
    +  99
    + 100/**
    + 101 * creates a function or method signature
    + 102 */

    + 103export function signature(s:any, mdl:any): Vnode {
    + 104    const comma = (i:number) => (i>0)? ', ': '';
    + 105    function optional(flags: any) {
    + 106        return (flags && flags.isOptional)? '.hs-item-optional' : '';
    + 107    }
    + 108
    + 109    let sig = [];
    + 110    if (s) {
    + 111        if (s.parameters) {
    + 112            sig = s.parameters.map((p:any, i:number) => m('span', [
    + 113                comma(i),
    + 114                m('span.hs-item-sig-param', [
    + 115                    m(`span.hs-item-name${optional(p.flags)}`, p.name),
    + 116                    type(p, mdl.lib)
    + 117                ])
    + 118            ]));
    + 119        }
    + 120        switch (mdl.kindString) {
    + 121            case 'Method':
    + 122            case 'Function': 
    + 123            case 'Constructor': 
    + 124                sig.unshift(m('span.hs-item-name', '('));
    + 125                sig.push(m('span.hs-item-name', ')'));
    + 126                break;
    + 127            default:
    + 128        }
    + 129    }
    + 130    return m('span.hs-item-signature', sig);
    + 131}
    + 132
    + 133/**
    + 134 * adds a default value, if defined
    + 135 */

    + 136export function defaultVal(s:any, lib:string): Vnode {
    + 137    if (s && s.defaultValue) {
    + 138        let val = ` = ${s.defaultValue}`.replace(/{/gi, '{ ').replace(/}/gi, ' }');
    + 139        return m('span.hs-item-default', val);
    + 140    } else {
    + 141        return;
    + 142    }        
    + 143}
    + 144
    + 145export function type(t:any, lib:string) {
    + 146    function _type(tt:any):any {
    + 147        switch (tt.type) {
    + 148            case undefined:         return '';
    + 149            case 'array':           return m('span.hs-item-type-array', ['Array<', _type(tt.elementType), '>']);
    + 150                                    
    + 151            case 'tuple':           return m('span.hs-item-type-tuple', [
    + 152                                        '[ ',
    + 153                                        ...tt.elements.map((e:any, i:number) => [i>0?', ':undefined, _type(e)]),
    + 154                                        ' ]'
    + 155                                    ]);
    + 156            case 'intrinsic':
    + 157            case 'instrinct':       return m('span.hs-item-type-instrinct', tt.id? libLink('span', lib, tt.fullPath, tt.name) : tt.name); 
    + 158            case 'stringLiteral':   return m('span.hs-item-type-string-literal', tt.type); 
    + 159            case 'union':           return m('span.hs-item-type-union', [...tt.types.map((e:any, i:number) => [i>0?' | ':undefined, _type(e)])]);
    + 160            case 'reference':       let refRes = tt.name;
    + 161                                    if (tt.id) {
    + 162                                        const typeRef = DocSets.get(lib, tt.id);
    + 163                                        if (typeRef.typeArguments) { refRes = typeRef.name+'<'+ typeRef.typeArguments.map(_type).join(', ') + '>'; }
    + 164                                        else if (typeRef.id)       { refRes = libLink('a', lib, typeRef.fullPath, typeRef.name); }
    + 165                                        else                       { refRes = typeRef.name; }
    + 166                                    }
    + 167                                    return m('span.hs-item-type-reference', refRes);
    + 168            case 'reflection':      let rflRes;
    + 169                                    if (tt.declaration) {
    + 170                                        rflRes = !tt.declaration.children? tt.declaration.kindString :
    + 171                                            m('span.hs-item-reflection', [
    + 172                                                '{ ',
    + 173                                                ...tt.declaration.children.map((c:any, i:number) => 
    + 174                                                    [i>0?', ':undefined, c.name, ': ', _type(c.type)]
    + 175                                                ),
    + 176                                                ' }'
    + 177                                            ]);
    + 178                                    } else {
    + 179                                        rflRes = 'UNKNOWN';
    + 180                                    }
    + 181                                    return m('span.hs-item-type-reflection', rflRes);
    + 182            default: console.log('unknown type '+ tt.type);
    + 183                     console.log(t);
    + 184                     return t.type;
    + 185        }
    + 186    }
    + 187
    + 188    try {
    + 189       return m('span', !t.type? '': [
    + 190           m('span.hs-item-name',':'), 
    + 191           m('span.hs-item-sig-type', _type(t.type)),
    + 192           defaultVal(t, lib)
    + 193        ]);
    + 194    } catch(e) { console.log(e); console.log(e.trace); }
    + 195}
    + 196
    + 197export function makeID(section:string, mdl:any) {
    + 198    let result = section? section+'_' : '';
    + 199    result = (result + (mdl.name || '')).toLowerCase();
    + 200    return (result!=='')? result : undefined;
    + 201}
    + + \ No newline at end of file diff --git a/docs/src/hsDoc/view/Tooltip.html b/docs/src/hsDoc/view/Tooltip.html new file mode 100644 index 0000000..8617ad4 --- /dev/null +++ b/docs/src/hsDoc/view/Tooltip.html @@ -0,0 +1,25 @@ + + +

    view/Tooltip.ts

    +
       1import { m, Vnode} from 'hslayout';
    +   2
    +   3export function tooltip(text:string, tip:string, position:string):Vnode { 
    +   4    // position: top, left, botton, right
    +   5    return m('.hs-tooltip[href=#]', [text, m(`span.hs-tooltip-${position}`, tip)]);
    +   6}
    +   7
    +   8
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Axes.html b/docs/src/hsGraph/Axes.html new file mode 100644 index 0000000..e1dc329 --- /dev/null +++ b/docs/src/hsGraph/Axes.html @@ -0,0 +1,450 @@ + + +

    Axes.ts

    +
       1/**
    +   2 * # Axes
    +   3 * renders the x- and y-axis with title, tick marks and labels.
    +   4 * 
    +   5 * ### Attributes
    +   6 * The `Axes` class is called by {@link Graph.Graph `Graph`} as 
    +   7 * `m(Axes, { cfg:cfg.axes, scales:scales })`
    +   8 * with the following attributes:
    +   9 * - cfg: a {@link Axes.AxesConfig AxesConfig} object
    +  10 * - scales: a {@link Axes.Scales Scales } object
    +  11 *
    +  12 * ### Configurations and Defaults
    +  13 * See {@link Axes.Axes.defaultConfig Axes.defaultConfig}
    +  14 * 
    +  15 * ### Example
    +  16 * 
    +  17 * 
    +  18 * let series = {
    +  19 *    colNames:['time', 'volume', 'price'],
    +  20 *    rows:[
    +  21 *      [0.2, 0.7, 0.87],
    +  22 *      [0.4, 0.015, 0.7],
    +  23 *      [0.6, 0.01, 0.7],
    +  24 *      [0.7, 5, 0.6],
    +  25 *      [0.8, 10, 0.75]
    +  26 * ]};
    +  27 * 
    +  28 * function myConfig(cfg) {
    +  29 *      cfg.series.data   = [series];
    +  30 *      cfg.series.series = [
    +  31 *          { x:'time', y:'volume'},
    +  32 *          { x:'time', y:'price'}
    +  33 *      ];
    +  34 *      cfg.series.series[0].style.marker.visible = true;
    +  35 *      cfg.series.series[1].style.marker.visible = true;
    +  36 *      cfg.series.series[1].style.marker.shape = hsgraph.Series.marker.square;
    +  37 *      cfg.chart.title.text          = 'Volume over Time';
    +  38 *      cfg.chart.title.xpos          = 'end';
    +  39 *      cfg.chart.title.ypos          = 'top';
    +  40 *      cfg.chart.title.vOffset       = -1.5;
    +  41 *      cfg.grid.minor.hor.visible    = true;
    +  42 * 
    +  43 *      const axes = cfg.axes.primary;
    +  44 *      axes.x.title.text = 'time';
    +  45 *      axes.y.title.text = 'volume';
    +  46 *      axes.y.scale.type = hsgraph.Axes.type.log;
    +  47 * }
    +  48 * 
    +  49 * m.mount(root, { 
    +  50 *      view:() => m(hsgraph.Graph, {cfgFn: myConfig })
    +  51 * });
    +  52 *
    +  53 * 
    +  54 * 
    +  55 * .hs-graph-chart { fill: #fff; }
    +  56 * .hs-graph-series { stroke-width: 5; }
    +  57 * 
    +  58 * 

    +  59 */

    +  60
    +  61 /** */
    +  62import { m, Vnode}  from 'hslayout';
    +  63import { XYScale,
    +  64         ScaleCfg, 
    +  65         Scales,
    +  66         MarkCfg,
    +  67         AxisCfg,
    +  68         AxesConfig,
    +  69         TickStruct,
    +  70         TickLabel,
    +  71         TickDefs } from './AxesTypes';
    +  72;
    +  73import { Config, 
    +  74         LabelCfg } from './Graph';
    +  75import { Scale }    from './Scale';
    +  76import { Domain }   from 'hsdata';
    +  77import { SVGElem, 
    +  78         TextHAlign,
    +  79         TextVAlign,
    +  80         Area }     from './SVGElem';
    +  81
    +  82
    +  83/** 
    +  84 * calculates the range value of axis crossing from a domain value.
    +  85 * @param cross the domain value where the axis crosses. Either 'min', 'max', or a numeric domain value
    +  86 * @param scale the Scale object for the perpendicular axis.
    +  87 */

    +  88function getCrossAt(cross:string|number, scale:Scale):number {
    +  89    let crossesAt:number;
    +  90    switch (cross) {
    +  91        case 'min': crossesAt = scale.domain()[0]; break;
    +  92        case 'max': crossesAt = scale.domain()[1]; break;
    +  93        default:    crossesAt = cross || 0;
    +  94    }
    +  95    return scale.convert(crossesAt);
    +  96}
    +  97
    +  98export class Axes extends SVGElem {
    +  99    /**
    + 100     * Defines available axis types:
    + 101     * - linear
    + 102     * - log
    + 103     * - date
    + 104     * - index
    + 105     * - percent
    + 106     * - ordinal
    + 107     * - nominal
    + 108     */

    + 109    static type = {
    + 110        linear:     'linear axis',
    + 111        log:        'log axis',
    + 112        date:       'date axis',
    + 113        index:      'index axis',
    + 114        percent:    'percent axis',
    + 115        ordinal:    'ordinal axis',
    + 116        nominal:    'nominal axis'
    + 117    };
    + 118
    + 119    /** 
    + 120    * Defines default values for display elements in `Axes`
    + 121    * sets the default configuration for the primary and secondary axes.
    + 122    * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations. 
    + 123    * 
    + 124    * ### Configurations and Defaults
    + 125    * ```
    + 126    * cfg.axes = {@link AxesTypes.AxesConfig } {
    + 127    *    primary: {                // Primary axis:
    + 128    *       x: axisCfg(true, true),
    + 129    *       y: axisCfg(true, false)
    + 130    *    },
    + 131    *    secondary: {               // Secondary axis:
    + 132    *       x: axisCfg(false, true),
    + 133    *       y: axisCfg(false, false)
    + 134    *    }
    + 135    *  }
    + 136    * ```
    + 137    * #### axisCfg(primary:boolean, x:boolean):
    + 138    * ```
    + 139    *  cfg.axes.[primary|secondary].[x|y] = {@link AxesTypes.AxisCfg }{
    + 140    *     visible:    primary? true : false,   // hide secondary axes
    + 141    *     crossesAt:  primary? 'min':'max',    // default axis crossing
    + 142    *     scale:     {@link AxesTypes.ScaleCfg }scaleCfg(),     // scale type and domain
    + 143    *     title:     {@link Graph.LabelCfg }titleCfg(primary, x),
    + 144    *     ticks:     {@link AxesTypes.TicksCfg }{                    
    + 145    *         major: {@link AxesTypes.TickStruct }{                
    + 146    *             marks:  {@link AxesTypes.MarkCfg }markCfg(primary, true),  
    + 147    *             labels: {@link Graph.LabelCfg }labelCfg(primary, x, true),     
    + 148    *             labelFmt: undefined 
    + 149    *         },
    + 150    *         minor: {@link AxesTypes.TickStruct }{ 
    + 151    *             marks:  markCfg(primary, false),
    + 152    *             labels: labelCfg(primary, x, false),     
    + 153    *             labelFmt: undefined 
    + 154    *         }
    + 155    *     } 
    + 156    *  }
    + 157    * ```
    + 158    * #### scaleCfg():
    + 159    * ```
    + 160    *  cfg.axes.[primary|secondary].[x|y].scale = {@link AxesTypes.ScaleCfg }{
    + 161    *      type:   {@link Axes.Axes.type } Axes.type.linear,  
    + 162    *      domain: {@link Data.Domain }['auto', 'auto']    // : min/max of domain; 'auto', 'tight', or a domain value
    + 163    *  }
    + 164    * ```
    + 165    * #### titleCfg(primary:boolean, x:boolean):
    + 166    * ```
    + 167    *  cfg.axes.[primary|secondary].[x|y].title = {@link SVGElem.TextElem }{
    + 168    *     visible: true,  
    + 169    *     text:    (x? 'x' : 'y') + (primary? '' : '2'),    // 'x' / 'y' or 'x2' / 'y2'
    + 170    *     xpos:    x? 'end' : (primary? 'middle' : 'start'),          
    + 171    *     ypos:    x? 'top' : (primary? 'bottom' : 'top'),           
    + 172    *     hOffset: x? -2 : (primary? 0 : 0.3),            
    + 173    *     vOffset: x? (primary? 0.4 : -1.2) : (primary? -0.5 : 0.7) 
    + 174    *  }      
    + 175    * ```
    + 176    * #### markCfg(primary:boolean, major:boolean):
    + 177    * ```
    + 178    *  cfg.axes.[primary|secondary].[x|y].ticks.[major|minor].marks = {@link AxesTypes.MarkCfg }{
    + 179    *     visible: major, 
    + 180    *     length: (primary? 1 : -1) * (major? 10 : 5) 
    + 181    *  }      
    + 182    * ```
    + 183    * #### labelCfg(primary:boolean, x:boolean, major:boolean):
    + 184    * ```
    + 185    *  cfg.axes.[primary|secondary].[x|y].ticks.[major|minor].labels = {@link SVGElem.TextElem }{
    + 186    *     visible: major, 
    + 187    *     xpos: x? 'middle' : (primary? 'end' : 'start')
    + 188    *     ypos: x? (primary? 'top' : 'bottom') : 'center', 
    + 189    *     hOffset: x? 0 (primary? -0.7 : 0.7), 
    + 190    *     vOffset: x? (primary? 0.7 : -0.7) : 0
    + 191    *  }      
    + 192    * ```
    + 193    * @param cfg the configuration object, containing default settings for all 
    + 194    * previously configured components.
    + 195    */

    + 196    static defaultConfig(cfg:Config) {
    + 197        function scaleCfg():ScaleCfg {
    + 198            return {                             // axis scaling information
    + 199                type: Axes.type.linear,         //    scale type
    + 200                domain:['auto', 'auto']  //    min/max of domain; 'auto', or a domain value
    + 201            };
    + 202        }
    + 203        function labelCfg(primary:boolean, x:boolean, major:boolean):LabelCfg {
    + 204            return { 
    + 205                visible: major, text: '',
    + 206                xpos: x? TextHAlign.middle : (primary? TextHAlign.end : TextHAlign.start),
    + 207                ypos: x? (primary? TextVAlign.top : TextVAlign.bottom) : TextVAlign.center, 
    + 208                hOffset: x? 0 : (primary? -0.7 : 0.7), 
    + 209                vOffset: x? (primary? 0.7 : -0.7) : 0
    + 210            }; 
    + 211        }
    + 212        function markCfg(primary: boolean, major:boolean):MarkCfg {
    + 213            return { 
    + 214                visible: major, 
    + 215                length: (primary? 1 : -1) * (major? 10 : 5) 
    + 216            };
    + 217        }
    + 218        function titleCfg(primary:boolean, x:boolean):LabelCfg {
    + 219            return {
    + 220                visible: true,  text: (x? 'x' : 'y') + (primary? '' : '2'),    
    + 221                xpos:  x? TextHAlign.end : (primary? TextHAlign.middle : TextHAlign.start),          
    + 222                ypos:  x? TextVAlign.top : (primary? TextVAlign.bottom : TextVAlign.top),           
    + 223                hOffset: x? -2 : (primary? 0 : 0.3),            
    + 224                vOffset: x? (primary? 0.4 : -1.2) : (primary? -0.5 : 0.7)       
    + 225            };
    + 226        }
    + 227        function axisCfg(primary:boolean, x:boolean):AxisCfg {
    + 228            return {
    + 229                visible:    primary? true : false, 
    + 230                crossesAt:  primary?'min':'max', 
    + 231                scale:      scaleCfg(),
    + 232                title: titleCfg(primary, x),
    + 233                ticks: {                    
    + 234                    major: {                
    + 235                        marks:  markCfg(primary, true),  
    + 236                        labels: labelCfg(primary, x, true),
    + 237                        labelFmt: undefined    
    + 238                    },
    + 239                    minor: { 
    + 240                        marks:  markCfg(primary, false),
    + 241                        labels: labelCfg(primary, x, false),    
    + 242                        labelFmt: undefined    
    + 243                    }
    + 244                } 
    + 245            };
    + 246        }
    + 247        cfg.axes = {
    + 248            primary: {
    + 249                x: axisCfg(true, true),
    + 250                y: axisCfg(true, false)
    + 251            },
    + 252            secondary: {
    + 253                x: axisCfg(false, true),
    + 254                y: axisCfg(false, false)
    + 255            }
    + 256        };
    + 257    }
    + 258
    + 259    /**
    + 260     * Makes adjustments to cfg based on current settings
    + 261     * @param cfg the configuration object, containing default settings for all components
    + 262     */

    + 263    static adjustConfig(cfg:Config) { 
    + 264    }
    + 265    
    + 266    /**
    + 267     * draws the axis line
    + 268     */

    + 269    drawAxisLine(x:boolean, range:Area, cross:number) {
    + 270        return x? this.horLine(range[0], range[1], cross, 'hs-graph-axis-line') :
    + 271                  this.verLine(cross, range[0], range[1], 'hs-graph-axis-line');
    + 272    }
    + 273
    + 274    /**
    + 275     * draws the axis title
    + 276     */

    + 277    drawTitle(x:boolean, ttlCfg:LabelCfg, type: string, range:Area, cross:number):Vnode {
    + 278        ttlCfg.cssClass = 'hs-graph-axis-title';
    + 279        const xy = { transform:`translate(${x?range[1]:cross}, ${x?cross:range[1]})` };
    + 280        return !ttlCfg.visible? undefined : 
    + 281            m('g', xy, this.text(ttlCfg, ttlCfg.text));
    + 282    }
    + 283
    + 284    /**
    + 285     * draws the tick marks. Labels are plotted for major tick marks only.
    + 286     */

    + 287    drawTickMarks(x:boolean, type:string, crossesAt:number, scale:Scale, ticks:TickDefs, cfg:TickStruct):Vnode {
    + 288        return m('svg', { class:`hs-graph-axis-${type}-tick-marks`}, 
    + 289            !cfg.marks.visible? '' : ticks.marks.map((t:number) => { 
    + 290                return x? this.verLine(scale.convert(t), crossesAt, crossesAt+cfg.marks.length) :
    + 291                          this.horLine(crossesAt, crossesAt-cfg.marks.length, scale.convert(t));
    + 292            })
    + 293        );
    + 294    }
    + 295
    + 296    /**
    + 297     * draws the tick labels. Labels are plotted for major tick marks only.
    + 298     */

    + 299    drawTickLabels(x:boolean, type:string, crossesAt:number, scale:Scale, ticks:TickDefs, cfg:TickStruct):Vnode {
    + 300        scale.setLabelFormat(cfg.labelFmt);
    + 301        return m('svg', {class:`hs-graph-axis-${type}-tick-label`}, 
    + 302            !cfg.labels.visible? '' : ticks.labels.map((t:TickLabel) => { 
    + 303                const v = scale.convert(t.pos);
    + 304                const xy = { transform:`translate(${x?v:crossesAt}, ${x?crossesAt:v})` };
    + 305                return m('g', xy, this.text(cfg.labels, t.text));
    + 306            })
    + 307        );
    + 308    }
    + 309
    + 310    /**
    + 311     * draws a single axis
    + 312     * @param dir axis to draw: 'x' or 'y'
    + 313     * @param attrs attributes required for rendering:
    + 314     * - type: 'primary' or 'secondary'
    + 315     * - scales:
    + 316     * - cfg: 
    + 317     */

    + 318    drawAxis(dir:string, scales: XYScale, type:string, axisCfg:AxesConfig):Vnode {
    + 319        const x = dir==='x';
    + 320        const range = scales[dir].range();
    + 321        const cfg   = axisCfg[type][dir];
    + 322        scales[dir].scaleType(cfg.scale.type);
    + 323        const crossesAt:number = getCrossAt(cfg.crossesAt, scales[x?'y':'x']);
    + 324        const ticks = scales[dir].ticks();
    + 325        return !cfg.visible? undefined : m('svg', { class:`hs-graph-axis-${dir} hs-graph-axis-${type}`}, [
    + 326            this.drawAxisLine(x, range, crossesAt),
    + 327            this.drawTitle(x, cfg.title, type, range, crossesAt),
    + 328            this.drawTickMarks(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor),
    + 329            this.drawTickMarks(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major),
    + 330            this.drawTickLabels(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor),
    + 331            this.drawTickLabels(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major)
    + 332        ]);
    + 333    }
    + 334
    + 335    view(node?: Vnode): Vnode {
    + 336        const cfg:AxesConfig = node.attrs.cfg;
    + 337        const scales:Scales  = node.attrs.scales;
    + 338        return m('svg', {class:'hs-graph-axis'}, [
    + 339            this.drawAxis('x', scales.primary, 'primary', cfg),
    + 340            this.drawAxis('y', scales.primary, 'primary', cfg),
    + 341            this.drawAxis('x', scales.secondary, 'secondary', cfg),
    + 342            this.drawAxis('y', scales.secondary, 'secondary', cfg)
    + 343        ]);
    + 344    }
    + 345}
    + 346
    + 347/**
    + 348 * ### Simple Example
    + 349 * 
    + 350 * 
    + 351 * let series = {
    + 352 *    colNames:['time', 'volume'],
    + 353 *    rows:[
    + 354 *      [-1, 0.2],
    + 355 *      [0.2, 0.7],
    + 356 *      [0.4, -0.2],
    + 357 *      [0.6, 0],
    + 358 *      [0.8, 0.5],
    + 359 *      [1, 0.7]
    + 360 * ]};
    + 361 * 
    + 362 * m.mount(root, { 
    + 363 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    + 364 *          cfg.chart.title.text          = 'Simple Example';
    + 365 *          cfg.series.data   = [series];
    + 366 *          cfg.series.series = [{ x:'time', y:'volume' }];
    + 367 *      }})
    + 368 * });
    + 369 *
    + 370 * 
    + 371 * 
    + 372 * .hs-graph-chart { fill: #fff; }
    + 373 * .hs-graph-series { stroke-width: 5; }
    + 374 * 
    + 375 * 

    + 376 */

    + 377class ExampleLinearAxis {}
    + 378
    + 379/**
    + 380* ### Logarithmic Axis
    + 381
    + 382
    + 383* let series = {
    + 384*    colNames:['time', 'volume'],
    + 385*    rows:[[0.3, 0.2], [0.32, 0.7], [0.4, 8], [0.56, 10], [0.7, 0.5], [0.8, 15]]
    + 386* };
    + 387
    + 388* m.mount(root, { 
    + 389*      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    + 390*          cfg.chart.title.text = 'Log Y Axis';
    + 391*          cfg.series.data   = [series];
    + 392*          cfg.series.series = [{ x'time', y:'volume' }];
    + 393*          cfg.axes.primary.x.scale.type = hsgraph.Axes.type.log;
    + 394*          cfg.axes.primary.x.scale.domain = ['tight', 'tight'];
    + 395*          cfg.axes.primary.y.scale.type = hsgraph.Axes.type.log;
    + 396*          cfg.axes.primary.y.scale.domain = ['auto', 'auto'];
    + 397*          cfg.grid.minor.hor.visible = true;
    + 398*          cfg.grid.minor.ver.visible = true;
    + 399*      }})
    + 400* });
    + 401*
    + 402
    + 403

    + 404*/

    + 405class ExampleLogAxis {}
    + 406
    + 407/**
    + 408* ### Date Axis
    + 409
    + 410
    + 411* let series = {
    + 412*    colNames:['time', 'volume'],
    + 413*    rows:[['2/6/17', 0.2], ['3/18/17', 0.7], ['5/1/17', 8], ['11/20/17', 10], ['1/15/18', 0.5]]
    + 414* };
    + 415
    + 416* m.mount(root, { 
    + 417*      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    + 418*          cfg.chart.title.text = 'Date X Axis';
    + 419*          cfg.series.data   = [series];
    + 420*          cfg.series.series = [{ x:'time', y:'volume' }];
    + 421*          cfg.axes.primary.x.scale.type = hsgraph.Axes.type.date;
    + 422*          cfg.axes.primary.x.ticks.major.labelFmt = '%MMM %YY';
    + 423*      }})
    + 424* });
    + 425*
    + 426
    + 427
    + 428* .hs-graph-series { stroke-width: 5; }
    + 429
    + 430

    + 431*/

    + 432class ExampleDateAxis {}
    + 433
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/AxesCfg.html b/docs/src/hsGraph/AxesCfg.html new file mode 100644 index 0000000..10a4bac --- /dev/null +++ b/docs/src/hsGraph/AxesCfg.html @@ -0,0 +1,234 @@ + + +

    AxesCfg.ts

    +
       1/**
    +   2 * # AxesCfg
    +   3 * sets the default configuration for the primary and secondary axes
    +   4 * 
    +   5 * ### Configurations and Defaults
    +   6 * ```
    +   7 *  {@link Axes.AxesSet AxesSet}:
    +   8 *  primary: {                          // Primary axis:
    +   9 *      x: {                            // {@link Axes.AxisCfg AxisCfg}
    +  10 *          visible: true,              // axis visibility
    +  11 *          crossesAt:'min',            // axis crossing in domain: 'min', 'max', or domain value
    +  12 *          scale: {                    // {@link Axes.ScaleCfg ScaleCfg}; axis scaling information
    +  13 *              type: 'linear',             
    +  14 *              domain:['auto', 'auto'] // min/max of domain; set to autodetect
    +  15 *          },
    +  16 *          title: {                    // {@link Axes.AxisTitleCfg AxisTitleCfg}; axis title configuration
    +  17 *              visible: true,  text: 'x'                   
    +  18 *              hAlign:  'end', vAlign:  'top',             
    +  19 *              hOffset: -2,    vOffset: 0.4                
    +  20 *          },
    +  21 *          ticks: {                    // tick mark configuration
    +  22 *              major: {                // {@link Axes.TickStruct TickStruct}; major ticks
    +  23 *                  marks: { visible: true, length: 10 },  
    +  24 *                  labels: { hAlign: 'middle', vAlign: 'top', hOffset: 0, vOffset: 0.7 }      
    +  25 *              },
    +  26 *              minor: {                // {@link Axes.TickStruct TickStruct}; minor ticks
    +  27 *                  marks: { visible: true,  length: 5 },
    +  28 *                  labels: { hAlign: 'middle', vAlign: 'top', hOffset: 0, vOffset: 0.7 }
    +  29 *              }   
    +  30 *          } 
    +  31 *      },
    +  32 *      y: {visible: true, 
    +  33 *          crossesAt:'min',
    +  34 *          scale: {       
    +  35 *              type: 'linear', 
    +  36 *              domain:['auto', 'auto']  
    +  37 *          },
    +  38 *          title: {text:'y', visible:true,
    +  39 *              hAlign:  'middle', hOffset: 0,
    +  40 *              vAlign:  'bottom', vOffset: -0.5
    +  41 *          },
    +  42 *          ticks: { 
    +  43 *              major: { marks: { visible:true, length:10 },
    +  44 *                      labels:{ hAlign: 'end', vAlign: 'center', hOffset: -0.7, vOffset: 0 }
    +  45 *              }, 
    +  46 *              minor: { marks: { visible:true, length:5 },
    +  47 *                       labels:{ hAlign: 'end', vAlign: 'center', hOffset: -0.7, vOffset: 0 }
    +  48 *              } 
    +  49 *          }
    +  50 *      }
    +  51 *  },
    +  52 *  secondary: {                        // Secondary axis:
    +  53 *      x: {visible: true, 
    +  54 *          crossesAt:'max',
    +  55 *          scale: {       
    +  56 *              type: 'linear', 
    +  57 *              domain:['auto', 'auto']  
    +  58 *          },
    +  59 *          title: {text:'x2', visible:true, 
    +  60 *                  hAlign:  'end', hOffset: -2,
    +  61 *                  vAlign:  'top', vOffset: -1.2
    +  62 *          },
    +  63 *          ticks: { 
    +  64 *              major: { marks: { visible:true, length:-10 },
    +  65 *                          labels:{ hAlign: 'middle', vAlign: 'bottom', hOffset: 0, vOffset: -0.7 }
    +  66 *              }, 
    +  67 *              minor: { marks: { visible:true, length:-5 },
    +  68 *                          labels:{ hAlign: 'middle', vAlign: 'bottom', hOffset: 0, vOffset: -0.7 }
    +  69 *              } 
    +  70 *          }
    +  71 *      },
    +  72 *      y: {visible: true, 
    +  73 *          crossesAt:'max',
    +  74 *          scale: {       
    +  75 *              type: 'linear', 
    +  76 *              domain:['auto', 'auto']  
    +  77 *          },
    +  78 *          title: {text:'y2', visible:true, 
    +  79 *                  hAlign:  'start', hOffset: 0.3,
    +  80 *                  vAlign:  'top', vOffset: 0.7
    +  81 *          },
    +  82 *          ticks: { 
    +  83 *              major: { marks: { visible:true, length:-10 },
    +  84 *                          labels:{ hAlign: 'start', vAlign: 'center', hOffset: 0.7, vOffset: 0 }
    +  85 *              }, 
    +  86 *              minor: { marks: { visible:true, length:-5 },
    +  87 *                          labels:{ hAlign: 'start', vAlign: 'center', hOffset: 0.7, vOffset: 0 }
    +  88 *              } 
    +  89 *          }
    +  90 *      }
    +  91 *  }
    +  92 * ```
    +  93 */

    +  94
    +  95/** */
    +  96import { Config }   from './Graph';
    +  97import { TitleCfg } from './SVGElem';
    +  98import { AxesSet, ScaleCfg, TickStruct }    
    +  99                    from './Axes';
    + 100
    + 101/** Defines coinfigurable settings per axis */
    + 102export interface AxisCfg {
    + 103    /** determines if the axis will be rendered */
    + 104    visible:    boolean;     
    + 105     
    + 106    /** configures the axis title; see {@link SVGElem.TitleCfg TitleCfg} */  
    + 107    title:      TitleCfg;
    + 108
    + 109    /** axis crossing in domain: 'min', 'max', or domain value */
    + 110    crossesAt:  number|string; 
    + 111
    + 112    /** scale type and domain; see {@link Axes.ScaleCfg ScaleCfg} */
    + 113    scale: ScaleCfg;
    + 114
    + 115    /** configures the major and minor ticks; see {@link Axes.TickStruct TickStruct} */
    + 116    ticks: {
    + 117        major:  TickStruct;
    + 118        minor:  TickStruct;
    + 119    };
    + 120}
    + 121
    + 122export function configAxes(config:Config):AxesSet { return {
    + 123    primary: {
    + 124        x: {visible: true,              // axis visibility
    + 125            crossesAt:'min',            // axis crossing in domain: 'min', 'max', or domain value
    + 126            scale: {                    // axis scaling information
    + 127                type: 'linear',         //    scale type: 'linear'|'log'|'date'|'index'|'percent'|'ordinal'|'nominal'
    + 128                domain:['auto', 'auto'] //    min/max of domain; set to autodetect
    + 129            },
    + 130            title: {          // axis title configuration
    + 131                visible: true,          //    title visibility
    + 132                text:    'x',           //    title text
    + 133                xpos:  'end',           // label text-align: 'start' | 'middle' | 'end'
    + 134                ypos:  'top',           // label  vertical align: 'top' | 'center' | 'bottom'
    + 135                hOffset: -2,            // horizontal label offset in 'em'
    + 136                vOffset: 0.4            // vertical label offset in 'em'
    + 137            },
    + 138            ticks: {                    // tick mark configuration
    + 139                major: {                // major ticks:
    + 140                    marks: {            // tick marks:
    + 141                        visible: true,  //    tick visibility
    + 142                        length: 10      //    tick length in viewBox coordinates
    + 143                    },  
    + 144                    labels: {           // tick labels:
    + 145                        xpos: 'middle', //    label text-align: 'start' | 'middle' | 'end'
    + 146                        ypos: 'top',    //    label vertical align: 'top' | 'center' | 'bottom'
    + 147                        hOffset: 0,     //    horizontal label offset in 'em'
    + 148                        vOffset: 0.7    //    vertical label offset in 'em'
    + 149                    }      
    + 150                },
    + 151                minor: { marks: { visible: true,  length: 5, },
    + 152                            labels:{ xpos: 'middle', ypos: 'top', hOffset: 0, vOffset: 0.7 }      
    + 153                }
    + 154            } // length of tick marks
    + 155        },
    + 156        y: {visible: true, 
    + 157            crossesAt:'min',
    + 158            scale: {       
    + 159                type: 'linear', 
    + 160                domain:['auto', 'auto']  
    + 161            },
    + 162            title: {text:'y', visible:true,
    + 163                    xpos:  'middle', hOffset: 0,
    + 164                    ypos:  'bottom', vOffset: -0.5
    + 165            },
    + 166            ticks: { 
    + 167                major: { marks: { visible:true, length:10 },
    + 168                            labels:{ xpos: 'end', ypos: 'center', hOffset: -0.7, vOffset: 0 }
    + 169                }, 
    + 170                minor: { marks: { visible:true, length:5 },
    + 171                            labels:{ xpos: 'end', ypos: 'center', hOffset: -0.7, vOffset: 0 }
    + 172                } 
    + 173            }
    + 174        }
    + 175    },
    + 176    secondary: {
    + 177        x: {visible: false, 
    + 178            crossesAt:'max',
    + 179            scale: {       
    + 180                type: 'linear', 
    + 181                domain:['auto', 'auto']  
    + 182            },
    + 183            title: {text:'x2', visible:true, 
    + 184                    xpos:  'end', hOffset: -2,
    + 185                    ypos:  'top', vOffset: -1.2
    + 186            },
    + 187            ticks: { 
    + 188                major: { marks: { visible:true, length:-10 },
    + 189                            labels:{ xpos: 'middle', ypos: 'bottom', hOffset: 0, vOffset: -0.7 }
    + 190                }, 
    + 191                minor: { marks: { visible:true, length:-5 },
    + 192                            labels:{ xpos: 'middle', ypos: 'bottom', hOffset: 0, vOffset: -0.7 }
    + 193                } 
    + 194            }
    + 195        },
    + 196        y: {visible: false, 
    + 197            crossesAt:'max',
    + 198            scale: {       
    + 199                type: 'linear', 
    + 200                domain:['auto', 'auto']  
    + 201            },
    + 202            title: {text:'y2', visible:true, 
    + 203                    xpos:  'start', hOffset: 0.3,
    + 204                    ypos:  'top', vOffset: 0.7
    + 205            },
    + 206            ticks: { 
    + 207                major: { marks: { visible:true, length:-10 },
    + 208                            labels:{ xpos: 'start', ypos: 'center', hOffset: 0.7, vOffset: 0 }
    + 209                }, 
    + 210                minor: { marks: { visible:true, length:-5 },
    + 211                            labels:{ xpos: 'start', ypos: 'center', hOffset: 0.7, vOffset: 0 }
    + 212                } 
    + 213            }
    + 214        }
    + 215    }
    + 216};}
    + 217
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/AxesDefaultCfg.html b/docs/src/hsGraph/AxesDefaultCfg.html new file mode 100644 index 0000000..96a1a1d --- /dev/null +++ b/docs/src/hsGraph/AxesDefaultCfg.html @@ -0,0 +1,181 @@ + + +

    AxesDefaultCfg.ts

    +
       1/**
    +   2 * # AxesCfg
    +   3 * sets the default configuration for the primary and secondary axes
    +   4 * 
    +   5 * ### Configurations and Defaults
    +   6 * See {@link AxesDefaultCfg.configAxes configAxes}
    +   7 */

    +   8
    +   9/** */
    +  10import { Config }               from './Graph';
    +  11import { TitleCfg }             from './SVGElem';
    +  12import { Scale, ScaleCfg, DomainCfg }  from './Scale';
    +  13import { AxesSet, MarkCfg, TicksCfg }    from './Axes';
    +  14
    +  15/** Defines configurable settings per axis */
    +  16export interface AxisCfg {
    +  17    /** determines if the axis will be rendered */
    +  18    visible:    boolean;     
    +  19     
    +  20    /** configures the axis title */  
    +  21    title:      TitleCfg;
    +  22
    +  23    /** axis crossing in domain: 'min', 'max', or domain value */
    +  24    crossesAt:  number|string; 
    +  25
    +  26    /** scale type and domain */
    +  27    scale: ScaleCfg;
    +  28
    +  29    /** configures the major and minor ticks */
    +  30    ticks: TicksCfg;
    +  31}
    +  32
    +  33/**
    +  34 * # configAxes
    +  35 * sets the default configuration for the primary and secondary axes
    +  36 * 
    +  37 * ### Configurations and Defaults
    +  38 * #### defaultScale: {@link Scale.ScaleCfg Scale.ScaleCfg} =
    +  39 * ```
    +  40 *  {
    +  41 *      type: Scale.type.linear,   // {@link Scale.Scale.type Scale.type} 
    +  42 *      domain:['auto', 'auto']    // {@link Scale.DomainCfg Scale.DomainCfg}: min/max of domain; 'auto', or a domain value
    +  43 *  }
    +  44 * ```
    +  45 * #### cfg...title: {@link SVGElem.TitleCfg titleCfg} =
    +  46 * ```
    +  47 *  {
    +  48 *     visible: true,  
    +  49 *     text:    (x? 'x' : 'y') + (primary? '' : '2'),    // 'x'/'y' or 'x2'/'y2'
    +  50 *     xpos:    x? 'end' : (primary? 'middle' : 'start'),          
    +  51 *     ypos:    x? 'top' : (primary? 'bottom' : 'top'),           
    +  52 *     hOffset: x? -2 : (primary? 0 : 0.3),            
    +  53 *     vOffset: x? (primary? 0.4 : -1.2) : (primary? -0.5 : 0.7) 
    +  54 *  }      
    +  55 * ```
    +  56 * #### cfg..ticks..marks: {@link AxisDefaultCfg.MarkCfg markCfg} =
    +  57 * ```
    +  58 *  {
    +  59 *     visible: true, 
    +  60 *     length: (primary? 1 : -1) * (major? 10 : 5) 
    +  61 *  }      
    +  62 * ```
    +  63 * #### cfg..ticks..labels: {@link SVGElem.TitleCfg labelCfg} =
    +  64 * ```
    +  65 *  {
    +  66 *     visible: true, 
    +  67 *     xpos: x? 'middle' : (primary? 'end' : 'start')
    +  68 *     ypos: x? (primary? 'top' : 'bottom') : 'center', 
    +  69 *     hOffset: x? 0 (primary? -0.7 : 0.7), 
    +  70 *     vOffset: x? (primary? 0.7 : -0.7) : 0
    +  71 *  }      
    +  72 * ```
    +  73 * #### cfg..: {@link Axis.AxisCfg axisCfg} =
    +  74 * ```
    +  75 *  {
    +  76 *     visible:    primary? true : false,   // hide secondary axes
    +  77 *     crossesAt:  primary?'min':'max',     // default axis crossing
    +  78 *     scale:      defaultScale,            // see above
    +  79 *     title:      titleCfg(primary, x),
    +  80 *     ticks: {                    
    +  81 *         major: {                
    +  82 *             marks: markCfg(primary, true),  
    +  83 *             labels: tickLabelCfg(primary, x)      
    +  84 *         },
    +  85 *         minor: { 
    +  86 *             marks: markCfg(primary, false),
    +  87 *             labels: tickLabelCfg(primary, x)     
    +  88 *         }
    +  89 *     } 
    +  90 *  }
    +  91 * ```
    +  92 * #### cfg.axes: {@link Axes.AxesSet AxesSet} =
    +  93 * ```
    +  94 * {
    +  95 *    primary: {                // Primary axis:
    +  96 *       x: axisCfg(true, true),
    +  97 *       y: axisCfg(true, false)
    +  98 *    },
    +  99 *    secondary: {               // Secondary axis:
    + 100 *       x: axisCfg(false, true),
    + 101 *       y: axisCfg(false, false)
    + 102 *    }
    + 103 *  }
    + 104 * ```
    + 105 */

    + 106export function configAxes(cfg:Config):AxesSet { 
    + 107    const defaultScale:ScaleCfg = {                  // axis scaling information
    + 108        type: Scale.type.linear,            //    scale type
    + 109        domain:['auto', 'auto']  //    min/max of domain; 'auto', or a domain value
    + 110    };
    + 111    function labelCfg(primary:boolean, x:boolean):TitleCfg {
    + 112        return { 
    + 113            visible: true, text: '', 
    + 114            xpos: x? 'middle' : (primary? 'end' : 'start'),
    + 115            ypos: x? (primary? 'top' : 'bottom') : 'center', 
    + 116            hOffset: x? 0 : (primary? -0.7 : 0.7), 
    + 117            vOffset: x? (primary? 0.7 : -0.7) : 0
    + 118        }; 
    + 119    }
    + 120    function markCfg(primary: boolean, major:boolean):MarkCfg {
    + 121        return { 
    + 122            visible: true, 
    + 123            length: (primary? 1 : -1) * (major? 10 : 5) 
    + 124        };
    + 125    }
    + 126    function titleCfg(primary:boolean, x:boolean):TitleCfg {
    + 127        return {
    + 128            visible: true,  text: (x? 'x' : 'y') + (primary? '' : '2'),    
    + 129            xpos:  x? 'end' : (primary? 'middle' : 'start'),          
    + 130            ypos:  x? 'top' : (primary? 'bottom' : 'top'),           
    + 131            hOffset: x? -2 : (primary? 0 : 0.3),            
    + 132            vOffset: x? (primary? 0.4 : -1.2) : (primary? -0.5 : 0.7)       
    + 133        };
    + 134    }
    + 135    function axisCfg(primary:boolean, x:boolean):AxisCfg {
    + 136        return {
    + 137            visible:    primary? true : false, 
    + 138            crossesAt:  primary?'min':'max', 
    + 139            scale:      defaultScale,
    + 140            title: titleCfg(primary, x),
    + 141            ticks: {                    
    + 142                major: {                
    + 143                    marks:  markCfg(primary, true),  
    + 144                    labels: labelCfg(primary, x)      
    + 145                },
    + 146                minor: { 
    + 147                    marks:  markCfg(primary, false),
    + 148                    labels: labelCfg(primary, x)     
    + 149                }
    + 150            } 
    + 151        };
    + 152    }
    + 153    return {
    + 154        primary: {
    + 155            x: axisCfg(true, true),
    + 156            y: axisCfg(true, false)
    + 157        },
    + 158        secondary: {
    + 159            x: axisCfg(false, true),
    + 160            y: axisCfg(false, false)
    + 161        }
    + 162    };
    + 163}
    + 164
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/AxesTypes.html b/docs/src/hsGraph/AxesTypes.html new file mode 100644 index 0000000..5182d2b --- /dev/null +++ b/docs/src/hsGraph/AxesTypes.html @@ -0,0 +1,110 @@ + + +

    AxesTypes.ts

    +
       1/**
    +   2 * @module Axes
    +   3 */

    +   4
    +   5 /** */
    +   6import { VisibleCfg, 
    +   7         LabelCfg } from './Graph';
    +   8import { Scale }    from './Scale';
    +   9import { Domain }   from 'hsdata';
    +  10
    +  11/** Set of `Scales` for x- and y-axis*/
    +  12export interface XYScale { x: Scale; y:Scale; }
    +  13
    +  14/** Set of `Scales` for primary and secondary x- and y-axes. */
    +  15export interface Scales {
    +  16    primary:   XYScale;
    +  17    secondary: XYScale;
    +  18}
    +  19
    +  20/**
    +  21 * Configures the scale type and domain boundaries `[min, max]` to be displayed.
    +  22 */

    +  23export interface ScaleCfg {
    +  24    /** scale type: {@link Axes.Axes.type Axes.type}.`linear` | `log` | `date` | `index` | `percent` | `ordinal` | `nominal` */
    +  25    type: string;
    +  26
    +  27    /**
    +  28     * Configures the domain boundaries `[min, max]` to be displayed.
    +  29     * For ordinal values these are the numeric min and max values of the domain,
    +  30     * or the special values 
    +  31     * - `auto`: determines the domain automatically from the data. Boundaries are set 'loosely' 
    +  32     *   so that the major tick mark below and above the data range are displayed as well.
    +  33     * - `tight`: same as `auto`, except the domain covers exactly the values contained in data. 
    +  34     * Both values can be set indepoendently for `min` and `max`
    +  35     */

    +  36    domain: Domain;
    +  37}
    +  38
    +  39export interface Ticks {
    +  40    major: TickDefs;
    +  41    minor: TickDefs;
    +  42}
    +  43
    +  44export interface TickLabel {
    +  45    pos:number;     // domain value, at which to print tick label
    +  46    text:string;    // string to print at labelPos
    +  47}
    +  48
    +  49export interface TickDefs {
    +  50    marks:  number[];   // domain values where to draw a mark
    +  51    labels: TickLabel[];// 
    +  52};
    +  53
    +  54/** Defines configurable settings for tick marks */
    +  55export interface MarkCfg extends VisibleCfg {
    +  56    /** length in viewBox coordinates */
    +  57    length:  number; 
    +  58}
    +  59
    +  60/** Defines configurable settings for tick marks and labels per axis */
    +  61export interface TickStruct {
    +  62    marks:  MarkCfg;
    +  63    labels: LabelCfg;
    +  64    labelFmt: string;
    +  65}
    +  66
    +  67/** Defines configurable settings for major and minor ticks (marks and labels) */
    +  68export interface TicksCfg {
    +  69    major:  TickStruct;
    +  70    minor:  TickStruct;
    +  71}
    +  72
    +  73/** Defines configurable settings. */
    +  74export interface AxesConfig  {
    +  75    primary:   { x: AxisCfg; y: AxisCfg; };
    +  76    secondary: { x: AxisCfg; y: AxisCfg; };
    +  77}
    +  78
    +  79/** Defines configurable settings per axis */
    +  80export interface AxisCfg extends VisibleCfg{
    +  81    /** configures the axis title */  
    +  82    title:      LabelCfg;
    +  83
    +  84    /** axis crossing in domain: 'min', 'max', or domain value */
    +  85    crossesAt:  number|string; 
    +  86
    +  87    /** axis type  */
    +  88    scale: ScaleCfg;
    +  89
    +  90    /** configures the major and minor ticks */
    +  91    ticks: TicksCfg;
    +  92}
    +  93
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Canvas.html b/docs/src/hsGraph/Canvas.html new file mode 100644 index 0000000..99c42d8 --- /dev/null +++ b/docs/src/hsGraph/Canvas.html @@ -0,0 +1,89 @@ + + +

    Canvas.ts

    +
       1/**
    +   2 * # Canvas
    +   3 * renders the graph's background.
    +   4 * 
    +   5 * ### Attributes
    +   6 * The `Canvas` class is called by {@link Graph.Graph `Graph`} as 
    +   7 * `m(Canvas, { cfg:cfg.canvas}))`
    +   8 * with the following attributes:
    +   9 * - cfg: a {@link Canvas.CanvasConfig `CanvasConfig`} configuration object
    +  10 * 
    +  11 * ### Configurations and Defaults
    +  12 * See {@link Canvas.Canvas.defaultConfig Canvas.defaultConfig}
    +  13 */

    +  14
    +  15/** */
    +  16import { m, Vnode}              from 'hslayout';
    +  17import { SVGElem, Area }        from './SVGElem';
    +  18import { Config, VisibleCfg }   from './Graph';
    +  19
    +  20
    +  21/** Defines configurable settings. */
    +  22export interface CanvasConfig extends VisibleCfg{
    +  23    range?:  Area;              // graph width and height
    +  24}
    +  25
    +  26export class Canvas extends SVGElem {
    +  27    /** 
    +  28     * Defines default values for all configurable parameters in `Graph`.
    +  29     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    +  30     * 
    +  31     * ### Configurations and Defaults
    +  32     * ```
    +  33     *  cfg.canvas = {@link Canvas.CanvasConfig }{
    +  34     *     range: {         // the graphs background rect:
    +  35     *        w: 100,       //    width
    +  36     *        h: 100,       //    height
    +  37     *        wunit:'%',    //    unit for width
    +  38     *        hunit:'%'     //    unit for height
    +  39     *     }   
    +  40     *  } 
    +  41     * ``` 
    +  42     * @param cfg the configuration object, containing default settings for all 
    +  43     * previously configured components. 
    +  44     */

    +  45    static defaultConfig(cfg:Config) {
    +  46        cfg.canvas = {
    +  47            range:  { // graph width and height
    +  48                w: 100, wunit:'%',
    +  49                h: 100, hunit:'%'
    +  50            }  
    +  51        };
    +  52    }
    +  53
    +  54    /**
    +  55     * Makes adjustments to cfg based on current settings
    +  56     * @param cfg the configuration object, containing default settings for all components
    +  57     */

    +  58    static adjustConfig(cfg:Config) {
    +  59    }
    +  60    
    +  61    view(node?: Vnode): Vnode {
    +  62        const cg = node.attrs.cfg;
    +  63        return m('svg', {class: 'hs-graph-canvas'}, [
    +  64            this.rect({x:0, y:0},
    +  65                { w:cg.range.w, h:cg.range.h, wunit:cg.range.wunit, hunit:cg.range.hunit},
    +  66                '' // style string
    +  67            )
    +  68        ]);
    +  69    }
    +  70}
    +  71
    +  72
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Chart.html b/docs/src/hsGraph/Chart.html new file mode 100644 index 0000000..969ee24 --- /dev/null +++ b/docs/src/hsGraph/Chart.html @@ -0,0 +1,148 @@ + + +

    Chart.ts

    +
       1/**
    +   2 * # Chart
    +   3 * renders the chart background and title.
    +   4 * 
    +   5 * ### Attributes
    +   6 * The `Chart` class is called by {@link Graph.Graph `Graph`} as 
    +   7 * `m(Chart, { cfg:cfg.chart, plotArea:plotArea })`
    +   8 * with the following attributes:
    +   9 * - cfg: a {@link Chart.ChartConfig ChartConfig} object
    +  10 * - plotArea: a {@link SVGElem.Rect Rect } object for plotting the chart background
    +  11 * 
    +  12 * ### Configurations and Defaults
    +  13 * See {@link Chart.Chart.defaultConfig Chart.defaultConfig}
    +  14 */

    +  15
    +  16 /** */
    +  17import { m, Vnode}          from 'hslayout';
    +  18import { Config, 
    +  19         LabelCfg,
    +  20         VisibleCfg }       from './Graph';
    +  21import { SVGElem,  Rect }   from './SVGElem';
    +  22
    +  23
    +  24/** Defines configurable settings. */
    +  25export interface ChartConfig extends VisibleCfg {
    +  26    /** the title text and positioning  */
    +  27    title:  LabelCfg;
    +  28};
    +  29
    +  30/**
    +  31 * Renders the chart background and title.
    +  32 */

    +  33export class Chart extends SVGElem { 
    +  34    /** 
    +  35     * Defines default values for display elements in `Chart`
    +  36     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    +  37     * 
    +  38     * ### Configurations and Defaults
    +  39     * ```
    +  40     *  cfg.chart = {@link Chart.ChartConfig }{
    +  41     *     visible: true,          // Chart area is visible
    +  42     *     title:  {               // the chart title
    +  43     *        visible: true,      // Chart title is visible
    +  44     *        text:'',            // the sting to display
    +  45     *        hOffset: 0,         // horizontal label offset in 'em'
    +  46     *        vOffset: -1.5,      // vertical label offset in 'em'
    +  47     *        xpos:'middle',      // hor. title position: 0-100%, rel. to Chart
    +  48     *        ypos:'top'          // ver. title position: 0-100%, rel. to Chart
    +  49     *     }   
    +  50     *  } 
    +  51     * ``` 
    +  52     * @param cfg the configuration object, containing default settings for all 
    +  53     * previously configured components.
    +  54     */

    +  55    static defaultConfig(cfg:Config) {
    +  56        cfg.chart = {
    +  57            visible: true,          // Chart area is visible
    +  58            title:  {     // the chart title
    +  59                visible: true,      // Chart title is visible
    +  60                text:'',            // the sting to display
    +  61                hOffset: 0,         // horizontal label offset in 'em'
    +  62                vOffset: -1.5,      // vertical label offset in 'em'
    +  63                xpos:'middle',      // hor. title position: 0-100%, rel. to Chart
    +  64                ypos:'top'          // ver. title position: 0-100%, rel. to Chart
    +  65            }
    +  66        };
    +  67    return cfg;
    +  68    }
    +  69
    +  70    /**
    +  71     * Makes adjustments to cfg based on current settings
    +  72     * @param cfg the configuration object, containing default settings for all components
    +  73     */

    +  74    static adjustConfig(cfg:Config) {        
    +  75    }
    +  76    
    +  77    static clientWidth:number;
    +  78    static clientHeight:number;
    +  79
    +  80    onupdate(node?: Vnode) { 
    +  81        this.updateTitleSize(node);
    +  82//                m.redraw();
    +  83    }
    +  84
    +  85    updateTitleSize(node: Vnode) {
    +  86        // get clientWidth /Height of title
    +  87        if (node.dom) {
    +  88            const c = node.dom.lastChild;
    +  89            if (c && c.clientWidth>0) {
    +  90                if (Chart.clientWidth !== c.clientWidth) {
    +  91                    Chart.clientWidth = c.clientWidth;
    +  92                    Chart.clientHeight = c.clientHeight;
    +  93                }
    +  94            }
    +  95        }
    +  96    }
    +  97
    +  98    drawBackground(plotArea:Rect) {
    +  99        const tl = plotArea.tl;
    + 100        const br = plotArea.br;
    + 101        return this.rect({x:tl.x, y:tl.y}, {w: br.x-tl.x, h: br.y-tl.y},'');
    + 102    }
    + 103
    + 104    drawTitle(plotArea:Rect, cfg:ChartConfig) {
    + 105        const tl = plotArea.tl;
    + 106        const br = plotArea.br;
    + 107        cfg.title.cssClass = 'hs-graph-chart-title';
    + 108        switch(cfg.title.xpos) {
    + 109            case 'start':   cfg.title.x = tl.x+'';   break;
    + 110            case 'middle':  cfg.title.x = (tl.x+br.x)/2+'';  break;
    + 111            case 'end':     cfg.title.x = br.x+''; break;
    + 112        }
    + 113        switch(cfg.title.ypos) {
    + 114            case 'top':     cfg.title.y = tl.y+'';   break;
    + 115            case 'center':  cfg.title.y = (tl.y+br.y)/2+'';  break;
    + 116            case 'bottom':  cfg.title.y = br.y+''; break;
    + 117        }
    + 118        return !cfg.title.visible? undefined : this.text(cfg.title, cfg.title.text);
    + 119    }
    + 120
    + 121    view(node?: Vnode): Vnode {
    + 122        const cfg:ChartConfig = node.attrs.cfg;
    + 123        const plotArea:Rect = node.attrs.plotArea;
    + 124        return m('svg', { class:'hs-graph-chart'}, [
    + 125            this.drawBackground(plotArea),
    + 126            this.drawTitle(plotArea, cfg)
    + 127        ]);
    + 128    }
    + 129}
    + 130
    + 131
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Config.html b/docs/src/hsGraph/Config.html new file mode 100644 index 0000000..d8671e1 --- /dev/null +++ b/docs/src/hsGraph/Config.html @@ -0,0 +1,40 @@ + + +

    Config.ts

    +
       1import { ScaleSet }     from './Scale';
    +   2import { GraphSet }     from './Graph';
    +   3import { AxisSet }      from './Axes';
    +   4import { SeriesSet }    from './Series';
    +   5import { ChartSet }     from './Chart';
    +   6import { GridSet }      from './Grid';
    +   7
    +   8export interface Config {
    +   9    scale?:  ScaleSet;
    +  10    graph?:  GraphSet;
    +  11    axes?:   AxisSet;
    +  12    chart?:  ChartSet;
    +  13    grid?:   GridSet;
    +  14    series?: SeriesSet;
    +  15    title?:{
    +  16        text?: string;
    +  17        align?: {h:string; v:string}   // h: center | left | right; v: center | top  | bottom
    +  18    };
    +  19    legend?:{
    +  20
    +  21    };
    +  22}
    +  23
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Data.html b/docs/src/hsGraph/Data.html new file mode 100644 index 0000000..78f43d1 --- /dev/null +++ b/docs/src/hsGraph/Data.html @@ -0,0 +1,351 @@ + + +

    Data.ts

    +
       1/**
    +   2 * 
    +   3 */

    +   4
    +   5
    +   6import { Scales }       from './AxesTypes';
    +   7import { SeriesDef, 
    +   8         SeriesConfig } from './Series';
    +   9
    +  10/** defines a [min-max] range */
    +  11export type NumRange = [number, number];
    +  12
    +  13/** defines a numeric domain that includes all values of a column */
    +  14export type NumDomain = [number, number];
    +  15
    +  16/** defines a Date domain that includes all values of a column */
    +  17export type DateDomain = [Date, Date];
    +  18
    +  19/** defines a categorical domain that includes all values of a column */
    +  20export type NameDomain = string[];
    +  21
    +  22/** defines a generic domain that can be any of the typed domains. */
    +  23export type Domain = NumDomain | DateDomain | NameDomain;
    +  24
    +  25/** defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    +  26export type ColSpecifier = number|string;
    +  27
    +  28/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    +  29export type DataVal = number|string|Date;
    +  30
    +  31/** a single row of column values */
    +  32export type DataRow = DataVal[];
    +  33
    +  34/** a row-of-column array of data. Values are accessed as `data[row][column]` */
    +  35export type DataRows = DataRow[];
    +  36
    +  37/** 
    +  38 * Description of a data set:
    +  39 * ```
    +  40 * {
    +  41 *    names: string[],  // array of names for columns in `rows` 
    +  42 *    rows:  DataRows   // row array of columns, accessed as `` 
    +  43 * }
    +  44 * ```
    +  45 */

    +  46export type DataSet = {
    +  47    names: string[];
    +  48    rows:  DataRows;
    +  49};
    +  50
    +  51interface TypeStruct { type: string; count: number;};
    +  52
    +  53interface MetaStruct {
    +  54    name:       string;         // column name
    +  55    column:     number;         // column index
    +  56    accessed:   boolean;        // has column data been accessed?
    +  57    cast:       boolean;        // has column data been cast 
    +  58    types:      TypeStruct[];   // data types, sorted by likelihood
    +  59}
    +  60
    +  61export class Data {
    +  62    public static type = {
    +  63        number:     'number data',
    +  64        name:       'name data',
    +  65        date:       'date data',
    +  66        currency:   'currency data',
    +  67        percent:    'percent data',
    +  68        nominal:    'nominal data'
    +  69    };
    +  70    private data: DataRows;
    +  71    private meta: MetaStruct[] = [];
    +  72
    +  73    private getMeta(col:ColSpecifier):MetaStruct { 
    +  74        if (!this.meta) { this.meta = []; }
    +  75        if (!this.meta[col]) { return undefined; }
    +  76        this.meta[col].accessed = true;
    +  77        return this.meta[col]; 
    +  78    }
    +  79
    +  80    private addColumn(newCol:string):number {
    +  81        var m = this.getMeta(newCol);
    +  82        if (m === undefined) { 
    +  83            m = this.meta[newCol] = {};
    +  84            m.name   = newCol; 
    +  85            m.column = this.meta.length;
    +  86            this.meta.push(m);      // access name by both column name and index
    +  87        }
    +  88        m.cast     = false;         // has not been cast yet
    +  89        m.accessed = false;         // has not been accessed yet
    +  90        return this.meta.length-1;
    +  91    }
    +  92
    +  93     
    +  94    /**
    +  95     * returns the column index of the specified column. 
    +  96     * `col` can be either an index or a name.
    +  97     * @param column the data column, name or index, for which to return the index. 
    +  98     * @return the column number or `undefined`.
    +  99     */

    + 100    public colNumber(col:ColSpecifier) {
    + 101        var m = this.getMeta(col);
    + 102        if (!m) { return undefined; }
    + 103        else {
    + 104            m.accessed = true; 
    + 105            return m.column; 
    + 106        }
    + 107    }
    + 108    
    + 109    /**
    + 110     * returns the column name for the specified column. 
    + 111     * `col` can be either an index or a name.
    + 112     * @param column the data column, name or index. 
    + 113     * @return the column name or `undefined`.
    + 114     */

    + 115    public colName(col:ColSpecifier) {
    + 116        var m = this.getMeta(col);
    + 117        if (!m) { return undefined; }
    + 118        m.accessed = true; 
    + 119        return m.name; 
    + 120    }
    + 121
    + 122    /**
    + 123     * returns the column type for the specified column. 
    + 124     * `col` can be either an index or a name.
    + 125     * @param column the data column, name or index. 
    + 126     * @return the column type.
    + 127     */

    + 128    public colType(col:ColSpecifier) { 
    + 129        return this.getMeta(col).types[0].type;
    + 130    }
    + 131
    + 132
    + 133    /**
    + 134     * Determines the type of data in `col`. An array of counts is created for all
    + 135     * encountered types, sorted by descending frequency. THe most likely type in position 0
    + 136     * of the array is returned.
    + 137     * @param col the index of the column to be typed. 
    + 138     * @return the most likely type of data in `col`.
    + 139     */

    + 140    private findTypes(col:ColSpecifier):string {
    + 141        const m = this.getMeta(col);
    + 142        const types:TypeStruct[] = [];
    + 143        Object.keys(Data.type).forEach((t:string) => {
    + 144            const ts = { type: Data.type[t], count: 0 }; 
    + 145            types.push(ts);
    + 146            types[Data.type[t]] = ts;
    + 147        });
    + 148        for (let v of this.allRows(col)) {
    + 149            const t = this.findType(v);
    + 150            if (t !== null) { types[t].count++; }
    + 151        }
    + 152        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    + 153            if (a.type==='currency'&&a.count>0) { return -1; }
    + 154            if (b.type==='currency'&&b.count>0) { return 1; }
    + 155            return b.count - a.count;
    + 156        });
    + 157        m.types = types;
    + 158        return types[0].type;
    + 159    }
    + 160
    + 161    /**
    + 162     * @description determines the data type. Supported types are 
    + 163     * ```
    + 164     * 'date':    sample represents a Date, either as a Date object or a String 
    + 165     * 'number':  sample represents a number
    + 166     * 'percent': sample represents a percentage (special case of a real number)
    + 167     * 'nominal': sample represents a nominal (ordinal or categorical) value
    + 168     * ```
    + 169     * @param val the value to bve typed.
    + 170     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    + 171     */

    + 172    private findType(val:DataVal) {
    + 173        if (val && val!=='') {
    + 174            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    + 175            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    + 176
    + 177            // else: val is a string:
    + 178            const strVal = ''+val;
    + 179            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    + 180            if (!isNaN(this.toDate(val).getTime()))                            { return Data.type.date; }
    + 181            if (val.endsWith('%') && !isNaN(parseFloat(val)))                  { return Data.type.percent; }
    + 182
    + 183            // european large number currency representation: '$dd,ddd[,ddd]'
    + 184            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    + 185                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    + 186                    return Data.type.currency; 
    + 187                }
    + 188            }
    + 189            switch (strVal.toLowerCase()) {
    + 190                case "null": break;
    + 191                case "#ref!": break;
    + 192                default: if (val.length>0) { return Data.type.nominal; }
    + 193            }
    + 194        }
    + 195        return null;
    + 196    }    
    + 197
    + 198    /**
    + 199     * modifies `domain` to include all values in column `col`.
    + 200     * @param col the column name or index 
    + 201     * @param domain the 
    + 202     */

    + 203    private findDomain(col:ColSpecifier, domain:Domain) {
    + 204        if (col === undefined) { // use array index as domain
    + 205            domain[0] = 0;
    + 206            domain[1] = this.data.length-1;
    + 207        } else {
    + 208            const c = this.colNumber(col);
    + 209            const type = this.colType(col);
    + 210            this.data.forEach((r:DataRow) => {
    + 211                switch(type) {
    + 212                    case Data.type.nominal: 
    + 213                        const nomDom = domain;
    + 214                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    + 215                        break;
    + 216                    default: 
    + 217                        let v:number = r[c];
    + 218                        domain[0] = (v + 219                        domain[1] = (v>domain[1])? v : domain[1];
    + 220                }
    + 221            });
    + 222        }
    + 223    }
    + 224
    + 225    /** 
    + 226     * determines the max ranges each coordinate of each series and auto-sets the domains on the respective scales. 
    + 227     */

    + 228    public adjustDomains(cfg:SeriesConfig, scales:Scales) {
    + 229        let domainDims = 0;
    + 230        cfg.series.forEach((s:SeriesDef) => 
    + 231            domainDims = Math.max(domainDims,s.cols.length)
    + 232        );
    + 233
    + 234        const domains:Domain[] = Array(domainDims).fill(1).map(() => [1e20, -1e20]);
    + 235    
    + 236        cfg.series.map((s:SeriesDef) => { // for each series:
    + 237            s.cols.forEach((colIdx:ColSpecifier, i:number) => {
    + 238                this.findDomain(colIdx, domains[i]);
    + 239            });
    + 240        });
    + 241        scales.primary.x.setAutoDomain(domains[0]);
    + 242        scales.primary.y.setAutoDomain(domains[1]);
    + 243    }
    + 244
    + 245    /**
    + 246     * sets `data` to the existing data set. If data has previously been set, 
    + 247     * `data` will be added to the end of the list if all `names`  match those of the 
    + 248     * existing set. 
    + 249     * @param data the data to add
    + 250     * @param names an array of names that match the columns
    + 251     * @param autoType unless set to false, the method will attempt to determine the 
    + 252     * type of data and automatically cast data points to their correct value
    + 253     */

    + 254    public setData(data:DataRows, names:ColSpecifier[], autoType=true):void {
    + 255        this.meta = undefined;
    + 256        this.data = data;
    + 257        names.forEach((col:string) => this.addColumn(col));
    + 258        names.forEach((col:string) => this.findTypes(col));
    + 259        this.castData();
    + 260    }
    + 261
    + 262    public * allRows(column:ColSpecifier):Iterable {
    + 263        const c = this.colNumber(column);
    + 264        for (let r=0; r + 265            yield this.data[r][c];
    + 266        }
    + 267    }
    + 268
    + 269    public getData():DataRows {
    + 270        return this.data;
    + 271    }
    + 272
    + 273    public castData() {
    + 274        this.meta.forEach((c:MetaStruct) => {
    + 275            const col = c.column;
    + 276            if (!c.cast) {
    + 277                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    + 278            }
    + 279            c.cast = true;
    + 280        });
    + 281    }
    + 282
    + 283    /**
    + 284     * @param str the string to convert to a data
    + 285     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    + 286     * @returns a new Date object parsed from `str`.
    + 287     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    + 288     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    + 289     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    + 290     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    + 291     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    + 292     */

    + 293    private toDate(val:DataVal, limitYear=1970):Date {
    + 294        let d:Date;
    + 295        if (val instanceof Date) { d = val; }
    + 296                            else { d = new Date(val); }   
    + 297        let yr=d.getFullYear();
    + 298        if (yr < 100) { 
    + 299            yr += 1900; 
    + 300            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    + 301        }
    + 302        return d;
    + 303    }
    + 304
    + 305    /**
    + 306     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    + 307     * does not match any of the previous keywords, no casting occurs.
    + 308     * @param sample The value to cast.
    + 309     * @returns The result of the cast. 
    + 310     * @description Casts the sample to the specified data type.
    + 311     */

    + 312    private castVal(type:string, val:DataVal):DataVal {
    + 313        switch (type) {
    + 314            case Data.type.date:    if (val instanceof Date) { return val; }
    + 315                            val = this.toDate(val);
    + 316                            if (isNaN(val.getTime())) { val = null; }
    + 317                            break;
    + 318            case Data.type.percent: if (typeof val === 'string') {
    + 319                                const num = parseFloat(val);
    + 320                                val = (val).endsWith('%')? num/100 : num;
    + 321                            } 
    + 322                            if (isNaN(val)) { val = null; }
    + 323                            break;
    + 324            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    + 325             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    + 326             /* falls through */
    + 327            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    + 328                            if (isNaN(val)) { val = null; }
    + 329                            break;
    + 330            default:        val = ''+val;
    + 331        }
    + 332        return val;
    + 333     }     
    + 334}
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Graph.html b/docs/src/hsGraph/Graph.html new file mode 100644 index 0000000..23a76d2 --- /dev/null +++ b/docs/src/hsGraph/Graph.html @@ -0,0 +1,404 @@ + + +

    Graph.ts

    +
       1/**
    +   2 * # Graph
    +   3 * The main `Graph` object that contains all graph components and sets up the controlling logic.
    +   4 * `Graph` sets up a viewBox that is always 1000 units wide. the height automatically adjusts to fill available space while 
    +   5 * preserving a uniform scaling (i.e. preserveAspectRatio = default (xMidYMid)).
    +   6 * 
    +   7 * ### Attributes
    +   8 * The main entry point for applications using this library is the `Graph` class,
    +   9 * typically called as `m(Graph, {cfgFn: (cfg:any) => {...});` 
    +  10 * Accepted attributes are:
    +  11 * - cfgFn: a {@link Graph.CfgFn CfgFn} function that allows setting graph parameters.
    +  12 *
    +  13 * ### Example
    +  14 * 
    +  15 * 
    +  16 * let series = {
    +  17 *    names:['time', 'volume', 'price'],
    +  18 *    rows:[
    +  19 *          [-1,   0.2, 0.8],
    +  20 *          [0.2,  0.7, 0.87],
    +  21 *          [0.4, -0.2, 0.7],
    +  22 *          [0.6,    0, 0.7],
    +  23 *          [0.8,  0.5, 0.6],
    +  24 *          [1,    0.7, 0.75]
    +  25 *    ]
    +  26 * };
    +  27 * 
    +  28 * function myConfig(cfg) {
    +  29 *      cfg.series.data   = [series];
    +  30 *      cfg.series.series = [
    +  31 *          { x:'time', y:'volume']},
    +  32 *          { x:'time', y:'price']}
    +  33 *      ];
    +  34 *      cfg.series.series[0].style.marker.visible = true;
    +  35 *      cfg.series.series[1].style.marker.visible = true;
    +  36 *      cfg.series.series[1].style.marker.shape = hsgraph.Series.marker.diamond;
    +  37 *      const axes = cfg.axes.primary;
    +  38 *      cfg.chart.title.text          = 'Volume over Time';
    +  39 *      cfg.chart.title.xpos          = 'end';
    +  40 *      cfg.chart.title.ypos          = 'top';
    +  41 *      cfg.chart.title.vOffset       = -1.5;
    +  42 *      axes.x.title.text = 'time';
    +  43 *      axes.y.title.text = 'volume';
    +  44 *      axes.x.crossesAt = 0;
    +  45 *      axes.y.crossesAt = 0;
    +  46 *      cfg.axes.secondary.x.visible = false;
    +  47 *      cfg.axes.secondary.y.visible = false;
    +  48 * }
    +  49 * 
    +  50 * m.mount(root, { 
    +  51 *      view:() => m(hsgraph.Graph, {cfgFn: myConfig })
    +  52 * });
    +  53 *
    +  54 * 
    +  55 * 
    +  56 * .hs-graph-chart { fill: #fff; }
    +  57 * .hs-graph-series { stroke-width: 5; }
    +  58 * 
    +  59 * 

    +  60 * 
    +  61 * ### Configurations and Defaults
    +  62 * See {@link Graph.Graph.defaultConfig Graph.defaultConfig}
    +  63 */

    +  64
    +  65/** */
    +  66import { m, Vnode}      from 'hslayout';
    +  67import { Data, 
    +  68         DataSet,
    +  69         NumDomain }    from 'hsdata';
    +  70import { Axes }         from './Axes';
    +  71import { AxesConfig,
    +  72         Scales }       from './AxesTypes';
    +  73import { Scale }        from './Scale';
    +  74import { Canvas, 
    +  75         CanvasConfig } from './Canvas';
    +  76import { Series, 
    +  77         SeriesDef,
    +  78         SeriesConfig } from './Series';
    +  79import { Chart, 
    +  80         ChartConfig }  from './Chart';
    +  81import { Grid, 
    +  82         GridsConfig }  from './Grid';
    +  83import { Legend, 
    +  84         LegendConfig } from './Legend';
    +  85import { SVGElem, 
    +  86         TextElem,
    +  87         Rect, 
    +  88         round }        from './SVGElem';
    +  89import { delay }        from 'hsutil';
    +  90
    +  91const viewBoxWidth:number  = 1000;  // the viewBox size in px
    +  92let   viewBoxHeight:number = 700;   // the viewBox size in px
    +  93
    +  94
    +  95export interface VisibleCfg extends GraphBaseCfg{
    +  96    visible: boolean;
    +  97}
    +  98
    +  99/** 
    + 100 * Configurator for a title, such as Chart title, or Axis title. 
    + 101 * Titles have their own visible switch.
    + 102 */

    + 103export interface LabelCfg extends TextElem, VisibleCfg {
    + 104}
    + 105
    + 106export interface GraphBaseCfg {
    + 107}
    + 108
    + 109/**
    + 110 */

    + 111export interface Config {
    + 112    viewBox?: { w: number; h: number; };
    + 113    graph?:  GraphConfig;
    + 114    canvas?: CanvasConfig;
    + 115    axes?:   AxesConfig;
    + 116    chart?:  ChartConfig;
    + 117    grid?:   GridsConfig;
    + 118    series?: SeriesConfig;
    + 119    legend?: LegendConfig;
    + 120}
    + 121
    + 122/**
    + 123 * `Graph` related configuration options.
    + 124 * See {@link Graph.Graph.makeConfig Graph.makeConfig} for all configurations and
    + 125 * {@link Graph.Graph.config Graph.config} for default `Graph` configuration.
    + 126 */

    + 127export interface GraphConfig extends GraphBaseCfg {
    + 128    margin :{           // in viewBox units 
    + 129        top:    number;          
    + 130        left:   number;   
    + 131        bottom: number;   
    + 132        right:  number;   
    + 133    };
    + 134    timeCond: any;
    + 135}
    + 136
    + 137/**
    + 138 * Creates a deep copy of `def`, taking fields present in `update` to supercede the default value.
    + 139 * @param def contains the default setting for each parameter
    + 140 */

    + 141function copy(def:any):any {
    + 142    let result:any = {};
    + 143    Object.keys(def).map((k:string) => {
    + 144        if (typeof def[k] === 'object' && !Array.isArray(def[k]) && def[k]!==null) {
    + 145            result[k] = copy(def[k]);
    + 146        } else {
    + 147            result[k] = def[k];
    + 148        }
    + 149    });
    + 150    return result;
    + 151}
    + 152
    + 153/** 
    + 154 * signature of a user configuration function, used in {@link Graph.Graph.makeConfig `Graph.makeConfig`} 
    + 155 * @param cfg the fully initialized configuration object. `CfgFn` should overwrite selected values as needed.
    + 156 */

    + 157export interface CfgFn { (cfg:Config):void; }
    + 158
    + 159
    + 160
    + 161/** The main `Graph` object, responsible for setting up the grpahing components and logic. */
    + 162export class Graph extends SVGElem {
    + 163    /**
    + 164     * Creates and returns a `cfg` configuration object containing configuration entries
    + 165     * for  `Graph` and all of its subcomponents:
    + 166     * -   {@link Graph.Graph.config `cfg.graph`}: some general Graph setting, such as margins
    + 167     * -   {@link Canvas.Canvas.config `cfg.canvas`}:  the background canvas on which all components are rendered
    + 168     * -   {@link Chart.Chart.config `cfg.chart`}: the chart area and title
    + 169     * -   {@link Axes.Axes.config `cfg.axes`}: the x- and y-axes, tick marks and labels, and axis title
    + 170     * -   {@link Grid.Grid.config `cfg.grid`}: the major and minor gridlines
    + 171     * -   {@link Series.Series.config `cfg.series`}: the one or more data series to render
    + 172     * -   {@link Legend.Legend.config `cfg.legend`}: the legend for the shown series
    + 173     * if a `userCfg` function is provided, it gets called after all configurations are
    + 174     * initialized with default values. The `cfg` object is passed as parameter into the 
    + 175     * function, which then can selectively overwrite certain settings as needed.
    + 176     * @param userCfg a user defined configuration function with the signature 
    + 177     * `(cfg:{@link Config Config}):void.`
    + 178     */

    + 179    private static makeConfig(userCfg?:CfgFn):Config { 
    + 180        const cfg:Config = {};
    + 181        Graph.defaultConfig(cfg);
    + 182        Canvas.defaultConfig(cfg);
    + 183        Axes.defaultConfig(cfg);
    + 184        Series.defaultConfig(cfg);
    + 185        Grid.defaultConfig(cfg);
    + 186        Chart.defaultConfig(cfg);
    + 187        Legend.defaultConfig(cfg);
    + 188        if (userCfg) { 
    + 189            try { 
    + 190                userCfg(cfg); 
    + 191            } catch(e) {
    + 192                console.log('error in usercfg');
    + 193                console.log(e);
    + 194                console.log(e.stack);
    + 195            }
    + 196        }
    + 197        return cfg;
    + 198    }
    + 199
    + 200    /** 
    + 201     * Defines default values for all configurable parameters in `Graph`
    + 202     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    + 203     * 
    + 204     * #### Configurations and Defaults
    + 205     * ```
    + 206     *  cfg.graph = {@link Graph.GraphConfig } {
    + 207     *     margin: {      // the margin between viewBox edges and nearest plot component
    + 208     *        top: 10,    // viewBox units      
    + 209     *        left: 10,   // viewBox units    
    + 210     *        bottom: 10, // viewBox units    
    + 211     *        right: 10   // viewBox units 
    + 212     *     }   
    + 213     *  } 
    + 214     * ``` 
    + 215     * @param cfg the configuration object, containing default settings for all 
    + 216     * previously configured components.
    + 217     */

    + 218    protected static defaultConfig(cfg:Config) {      
    + 219        cfg.graph = {
    + 220            margin :{
    + 221                top: 10,    // viewBox units      
    + 222                left: 10,   // viewBox units    
    + 223                bottom: 10, // viewBox units    
    + 224                right: 10   // viewBox units    
    + 225            },
    + 226            timeCond: {}
    + 227        };
    + 228    }
    + 229
    + 230    /**
    + 231     * Makes adjustments to cfg based on current settings.
    + 232     * Called just prior to drawing.
    + 233     * @param cfg the configuration object, containing default settings for all components
    + 234     */

    + 235    protected static adjustConfig(cfg:Config) {
    + 236        Canvas.adjustConfig(cfg);
    + 237        Axes.adjustConfig(cfg);
    + 238        Series.adjustConfig(cfg);
    + 239        Grid.adjustConfig(cfg);
    + 240        Chart.adjustConfig(cfg);
    + 241        Legend.adjustConfig(cfg);
    + 242    }
    + 243
    + 244    private marginOffset = {
    + 245        left:   0,     // in px
    + 246        right:  0,     // in px
    + 247        top:    0,     // in px
    + 248        bottom: 0      // in px
    + 249    };
    + 250
    + 251
    + 252    private scales: Scales;
    + 253
    + 254    private createPlotArea(cfgm:{top:number, left:number, bottom:number, right:number}):Rect {
    + 255        const tl = {
    + 256            x: cfgm.left + this.marginOffset.left,
    + 257            y: cfgm.top + this.marginOffset.top
    + 258        };
    + 259        const br = {
    + 260            x: viewBoxWidth  - cfgm.right  - this.marginOffset.right,
    + 261            y: viewBoxHeight - cfgm.bottom - this.marginOffset.bottom
    + 262        };
    + 263        return { tl: tl, br: br };
    + 264    }
    + 265
    + 266    private createData(cfg:any):Data[] {
    + 267        if (!cfg.series.data) {
    + 268            console.log('cfg.series.data not set');
    + 269        }
    + 270        if (!(cfg.series.data.length > 0)) {
    + 271            console.log('cfg.series.data not initialised with array of DataSets');
    + 272        }
    + 273        const timeCond = cfg.graph.timeCond;
    + 274        return cfg.series.data.map((d:DataSet|Data) => 
    + 275            ((d instanceof Data)? d : new Data(d)).filter(timeCond));
    + 276    }
    + 277
    + 278    private createScales(axes:any):Scales {
    + 279        if (!this.scales) { this.scales = {
    + 280            primary:   { x: new Scale(axes.primary.x.scale),   y: new Scale(axes.primary.y.scale) },
    + 281            secondary: { x: new Scale(axes.secondary.x.scale), y: new Scale(axes.secondary.y.scale) }
    + 282        };}
    + 283        return this.scales;
    + 284    }
    + 285
    + 286    adjustRange(plotArea:Rect, scales:Scales) { 
    + 287        scales.primary.x.range([plotArea.tl.x, plotArea.br.x]);
    + 288        scales.primary.y.range([plotArea.br.y, plotArea.tl.y]);
    + 289        scales.secondary.x.range([plotArea.tl.x, plotArea.br.x]);
    + 290        scales.secondary.y.range([plotArea.br.y, plotArea.tl.y]);
    + 291    }
    + 292
    + 293    /**
    + 294     * adjust the height of the viewBox to match available height in containing window,
    + 295     * e.g. after a resize
    + 296     * @param node the Graph node
    + 297     */

    + 298    adjustHeight(node?: Vnode) {
    + 299        if (node.dom && node.dom.parentElement) {
    + 300            const p = node.dom.parentElement;
    + 301            const temp = viewBoxWidth * p.clientHeight / p.clientWidth;
    + 302            if (!isNaN(temp) && temp !== viewBoxHeight) {
    + 303                viewBoxHeight = temp; 
    + 304            }
    + 305        }
    + 306    }
    + 307
    + 308    /**
    + 309     * check on update of axes bounding box and notify Graph.boxNotify
    + 310     */

    + 311    adjustMargins(cfg:Config) {
    + 312        const cfgm = cfg.graph.margin;
    + 313        function getBBox(css: string) {
    + 314            const elems = document.getElementsByClassName(css);
    + 315            const box = Array.prototype.map.call(elems, (e:any)=>e.getBBox());
    + 316            if(box && box[0]) { 
    + 317                margin.t = Math.max(margin.t, cfgm.top-box[0].y);               
    + 318                margin.l = Math.max(margin.l, cfgm.left-box[0].x);               
    + 319                margin.b = Math.max(margin.b,  box[0].y+box[0].height+cfgm.bottom-viewBoxHeight);               
    + 320                margin.r = Math.max(margin.r, box[0].x+box[0].width +cfgm.right -viewBoxWidth);               
    + 321            }
    + 322            margin.t = Math.min(margin.t, 40);  // limit to max 20px
    + 323            margin.b = 30; //Math.min(margin.b, 40);  // limit to max 20px
    + 324            margin.l = 40;
    + 325        }
    + 326        const margin = {t:-1e6,l:-1e6,b:-1e6,r:-1e6};
    + 327        getBBox('hs-graph-axis');
    + 328        getBBox('hs-graph-chart');
    + 329        this.marginOffset.top    += Math.max(margin.t);
    + 330        this.marginOffset.left   += Math.max(margin.l);
    + 331        this.marginOffset.bottom += Math.max(margin.b);
    + 332        this.marginOffset.right  += Math.max(margin.r);
    + 333    }
    + 334
    + 335    onupdate(node?: Vnode) { 
    + 336        this.adjustHeight(node); 
    + 337    }
    + 338
    + 339    oncreate(node?: Vnode) {
    + 340        window.addEventListener("resize", function() { m.redraw(); });
    + 341        this.adjustHeight(node); 
    + 342        Promise.resolve(node.attrs.cfg)
    + 343            .then(delay(10))
    + 344            .then(this.adjustMargins.bind(this))
    + 345            .then(m.redraw);
    + 346    }
    + 347
    + 348    /** 
    + 349     * determines the max ranges each coordinate of each series and auto-sets the domains on the respective scales. 
    + 350     */

    + 351    adjustDomains(cfg:SeriesConfig, scales:Scales, data:Data[]) {
    + 352        const domains = [[1e20, -1e20], [1e20, -1e20]];
    + 353    
    + 354        cfg.series.map((s:SeriesDef) => { // for each series:
    + 355            if (s.x)     { data[s.dataIndex].findDomain(s.x, domains[0]); }
    + 356            else         { domains[0][0] = 0; domains[0][1] = data[s.dataIndex].export().rows.length-1; }
    + 357            if (s.y)     { data[s.dataIndex].findDomain(s.y, domains[1]); }
    + 358            if (s.yBase) { data[s.dataIndex].findDomain(s.yBase, domains[1]); }
    + 359        });
    + 360        scales.primary.x.setAutoDomain(domains[0]);
    + 361        scales.primary.y.setAutoDomain(domains[1]);
    + 362    }
    + 363
    + 364
    + 365    view(node?: Vnode): Vnode {
    + 366        const cfgFn:CfgFn = node.attrs.cfgFn;
    + 367        const cfg:Config = Graph.makeConfig(cfgFn);
    + 368        const plotArea:Rect = this.createPlotArea(cfg.graph.margin);
    + 369        const scales:Scales = this.createScales(cfg.axes);
    + 370        this.adjustRange(plotArea, scales);
    + 371        const data = this.createData(cfg);
    + 372        this.adjustDomains(cfg.series, scales, data);
    + 373
    + 374        Graph.adjustConfig(cfg);
    + 375        node.attrs.cfg = cfg;
    + 376        return m('svg', { class:'hs-graph', width:'100%', height:'100%', 
    + 377                viewBox:`0 0 ${round(viewBoxWidth)} ${round(viewBoxHeight)}` }, [
    + 378            m(Canvas, { cfg:cfg.canvas}),
    + 379            m(Chart, { cfg:cfg.chart, plotArea:plotArea }),
    + 380            m(Grid, { cfg:cfg.grid, scales:scales }),
    + 381            m(Axes, { cfg:cfg.axes, scales:scales }),
    + 382            m(Series, { cfg:cfg.series, scales:scales, data:data }),
    + 383            m(Legend, { cfg:cfg.legend })
    + 384        ]);
    + 385    }
    + 386}
    + 387
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Grid.html b/docs/src/hsGraph/Grid.html new file mode 100644 index 0000000..3052b0e --- /dev/null +++ b/docs/src/hsGraph/Grid.html @@ -0,0 +1,139 @@ + + +

    Grid.ts

    +
       1/**
    +   2 * # Grid
    +   3 * renders the major and minor gridlines in each direction.
    +   4 * 
    +   5 * ### Attributes
    +   6 * The `Chart` class is called by {@link Graph.Graph `Graph`} as 
    +   7 * `m(Grid, { cfg:cfg.grid, scales:scales })`
    +   8 * with the following attributes:
    +   9 * - cfg: a {@link Grid.GridsConfig GridsConfig} object
    +  10 * - scales: a {@link Axes.Scales Scales } object
    +  11 * 
    +  12 * ### Configurations and Defaults
    +  13 * See {@link Grid.Grid.defaultConfig Grid.defaultConfig}
    +  14 * 
    +  15 */

    +  16
    +  17/** */
    +  18import { m, Vnode}      from 'hslayout';
    +  19import { Config, 
    +  20         VisibleCfg }   from './Graph';
    +  21import { SVGElem }      from './SVGElem';
    +  22import { NumRange }     from 'hsdata';
    +  23import { Scale }        from './Scale';
    +  24import { TickDefs,
    +  25         Scales }       from './AxesTypes';
    +  26
    +  27/** defines configurable parameters for a grid */
    +  28export interface GridCfg extends VisibleCfg{
    +  29}
    +  30
    +  31/** defines configurable parameters for horizontal and vertical grids */
    +  32export interface  GridsCfg {
    +  33    hor: GridCfg;
    +  34    ver: GridCfg;
    +  35}
    +  36
    +  37/** Defines configurable settings. */
    +  38export interface GridsConfig {
    +  39    /** major grid lines */
    +  40    major: GridsCfg;
    +  41
    +  42    /** minor grid lines */
    +  43    minor: GridsCfg;
    +  44}
    +  45
    +  46export class Grid extends SVGElem{ 
    +  47    /** 
    +  48     * Defines default values for all configurable parameters in `Graph`
    +  49     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    +  50     * 
    +  51     * ### Configurations and Defaults
    +  52     * ```
    +  53     *  cfg.grid = {@link Grid.GridsConfig }{
    +  54     *      major: {
    +  55     *          hor: { visible:true },
    +  56     *          ver: { visible:true }
    +  57     *      },
    +  58     *      minor: {
    +  59     *          hor: { visible:false },
    +  60     *          ver: { visible:false }
    +  61     *      }
    +  62     *  } 
    +  63     * ``` 
    +  64     * @param cfg the configuration object, containing default settings for all 
    +  65     * previously configured components.
    +  66     */

    +  67    static defaultConfig(cfg:Config) {
    +  68        cfg.grid = {
    +  69            major: {
    +  70                hor: { visible:true },
    +  71                ver: { visible:true }
    +  72            },
    +  73            minor: {
    +  74                hor: { visible:false },
    +  75                ver: { visible:false }
    +  76            }
    +  77        };
    +  78    }
    +  79
    +  80    /**
    +  81     * Makes adjustments to cfg based on current settings
    +  82     * @param cfg the configuration object, containing default settings for all components
    +  83     */

    +  84    static adjustConfig(cfg:Config) {     
    +  85    }
    +  86    
    +  87    /** 
    +  88     * Draws horizontal gridlines parallel to the x-axis
    +  89     */

    +  90    private drawHorGrid(cfg:{visible:boolean}, scale:Scale, range:NumRange, ticks:TickDefs) {
    +  91        return !cfg.visible? m('svg') : m('svg', { class:'hs-graph-grid-hor' }, ticks.marks.map((t) =>
    +  92            this.horLine(range[0], range[1], scale.convert(t))
    +  93        ));
    +  94    }
    +  95
    +  96    /** 
    +  97     * Draws vertical gridlines parallel to the y-axis
    +  98     */

    +  99    private drawVerGrid(cfg:{visible:boolean}, scale:Scale, range:NumRange, ticks:TickDefs) {
    + 100        return !cfg.visible? m('svg') : m('svg', { class:'hs-graph-grid-ver' }, ticks.marks.map((t) =>
    + 101            this.verLine(scale.convert(t), range[0], range[1])
    + 102        ));
    + 103    }
    + 104
    + 105
    + 106    view(node?: Vnode): Vnode {
    + 107        const cfg:GridsConfig = node.attrs.cfg;
    + 108        const scales:Scales = node.attrs.scales;
    + 109        const ps = scales.primary;
    + 110        return m('svg', { class:'hs-graph-grid'}, [
    + 111            m('svg', { class:'hs-graph-grid-minor' }, [
    + 112                this.drawHorGrid(cfg.minor.hor, ps.y, ps.x.range(), ps.y.ticks().minor),
    + 113                this.drawVerGrid(cfg.minor.ver, ps.x, ps.y.range(), ps.x.ticks().minor)
    + 114            ]),
    + 115            m('svg', { class:'hs-graph-grid-major' }, [
    + 116                this.drawHorGrid(cfg.major.hor, ps.y, ps.x.range(), ps.y.ticks().major),
    + 117                this.drawVerGrid(cfg.major.ver, ps.x, ps.y.range(), ps.x.ticks().major)
    + 118            ])
    + 119        ]);
    + 120    }
    + 121}
    + 122
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Legend.html b/docs/src/hsGraph/Legend.html new file mode 100644 index 0000000..5959d4f --- /dev/null +++ b/docs/src/hsGraph/Legend.html @@ -0,0 +1,73 @@ + + +

    Legend.ts

    +
       1/**
    +   2 * # Legend
    +   3 * renders the series' legend .
    +   4 * 
    +   5 * ### Attributes
    +   6 * The `Legend` class is called by {@link Graph.Graph `Graph`} as 
    +   7 * `m(Legend, { cfg:cfg.legend })`
    +   8 * with the following attributes:
    +   9 * - cfg: a {@link Legend.LegendConfig LegendConfig} object
    +  10 * 
    +  11 * ### Configurations and Defaults
    +  12 * See {@link Legend.Legend.defaultConfig Legend.defaultConfig}
    +  13 * 
    +  14 */

    +  15
    +  16/** */
    +  17import { m, Vnode}  from 'hslayout';
    +  18import { Config }   from './Graph';
    +  19//import { SVGElem }  from './SVGElem';
    +  20
    +  21
    +  22/** Defines configurable settings. */ 
    +  23export interface LegendConfig {
    +  24};
    +  25
    +  26export class Legend {
    +  27    /** 
    +  28     * Defines default values for all configurable parameters in `Legend`
    +  29     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    +  30     * 
    +  31     * ### Configurations and Defaults
    +  32     * ```
    +  33     *  cfg.legend = {@link Legend.LegendConfig }{
    +  34     *  } 
    +  35     * ``` 
    +  36     * @param cfg the configuration object, containing default settings for all 
    +  37     * previously configured components.
    +  38     */

    +  39    static defaultConfig(cfg:Config) {
    +  40        cfg.legend = {
    +  41        };
    +  42    }
    +  43
    +  44    /**
    +  45     * Makes adjustments to cfg based on current settings
    +  46     * @param cfg the configuration object, containing default settings for all components
    +  47     */

    +  48    static adjustConfig(cfg:Config) {
    +  49        
    +  50    }
    +  51    
    +  52    view(node?: Vnode): Vnode {
    +  53        return m('svg', { class:'hs-graph-legend', width:'100%', height:'100%'});
    +  54    }
    +  55}
    +  56
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Plot.html b/docs/src/hsGraph/Plot.html new file mode 100644 index 0000000..5889426 --- /dev/null +++ b/docs/src/hsGraph/Plot.html @@ -0,0 +1,106 @@ + + +

    Plot.ts

    +
       1/**
    +   2 * Abstract base class for plots.
    +   3 */

    +   4
    +   5/** */
    +   6import { m, Vnode}      from 'hslayout';
    +   7import { SVGElem,
    +   8         TextElem,
    +   9         TextHAlign,
    +  10         TextVAlign }   from './SVGElem';
    +  11import { Data, 
    +  12         DataRow }      from 'hsdata';
    +  13import { XYScale }      from './AxesTypes';
    +  14import { Series, 
    +  15         SeriesStyle,
    +  16         SeriesDef }    from './Series';
    +  17import { round }        from 'hsutil';
    +  18
    +  19export abstract class Plot extends SVGElem {
    +  20    drawLine(clipID:string, data:DataRow[], x:number, y:number, scales:XYScale, sStyle:SeriesStyle, title?:string) {
    +  21        const style = `stroke: ${sStyle.line.color}; stroke-width:${sStyle.line.width};`;
    +  22        return !sStyle.line.visible? m('.invisible-line','') : this.polyline(data, x, y, scales, clipID, style, title);
    +  23    }
    +  24
    +  25    drawMarker(clipID:string, data:DataRow[], x:number, y:number, scales:XYScale, sStyle:SeriesStyle, title?:string) {
    +  26        const mrk = Series.marker;
    +  27        let style = `fill:${sStyle.marker.color}`;
    +  28        return !sStyle.marker.visible? m('.invisible-marker','') : m('svg', {class:'hs-graph-series-markers'},
    +  29            data.map((p:number[]) => {
    +  30                const cx = scales.x.convert(p[x]);
    +  31                const cy = scales.y.convert(p[y]);
    +  32                const r  = sStyle.marker.size;
    +  33                switch (sStyle.marker.shape) {
    +  34                    case mrk.circle: 
    +  35                        return this.circle({x:cx, y:cy}, r, style, title);
    +  36                    case mrk.square: 
    +  37                        return this.rect({x:cx-r, y:cy-r}, {w:2*r, h:2*r}, style, title);
    +  38                    case mrk.diamond: 
    +  39                        return this.shape([[cx-r, cy], [cx, cy+r], [cx+r, cy], [cx, cy-r]], undefined, style, title);
    +  40                    case mrk.upTriangle: 
    +  41                        return this.shape([[cx-r, cy+r], [cx+r, cy+r], [cx, cy-r]], undefined, style, title);
    +  42                    case mrk.downTriangle: 
    +  43                        return this.shape([[cx-r, cy-r], [cx+r, cy-r], [cx, cy+r]], undefined, style, title);
    +  44                }
    +  45                return m(`.unkown-marker-${sStyle.marker.shape}`,'');
    +  46            })
    +  47        );
    +  48    }
    +  49
    +  50    drawLabel(clipID:string, data:DataRow[], x:number, y:number, lbl:number, scales:XYScale, sDef:SeriesDef) {
    +  51        const sStyle = sDef.style;
    +  52        const cfg:TextElem = {
    +  53            text:       '', 
    +  54            cssClass:   ``,
    +  55            style:      `fill:${sStyle.label.color}`,
    +  56            xpos:       TextHAlign.middle,
    +  57            ypos:       TextVAlign.center,
    +  58            hOffset:    sDef.hOffset,
    +  59            vOffset:    sDef.vOffset
    +  60        };
    +  61        return !sStyle.marker.visible? m('.invisible-marker','') : m('svg', {class:'hs-graph-series-labels'},
    +  62            data.map((p:DataRow) => {
    +  63                cfg.x = ''+scales.x.convert(p[x]);
    +  64                cfg.y = ''+scales.y.convert(p[y]);
    +  65                return this.text(cfg, round(p[lbl], 3));
    +  66            })
    +  67        );
    +  68    }
    +  69
    +  70    drawArea(clipID:string, data:DataRow[], x:number, yFore:number, yBack:number, scales:XYScale, sStyle:SeriesStyle, title:string) {
    +  71        if (sStyle.fill.visible) {
    +  72            const style = `fill: ${sStyle.fill.color};`;
    +  73            const drawFore = data;
    +  74            const drawBack = data.slice().reverse();
    +  75            return this.polygon(drawFore, drawBack, x, yFore, yBack, scales, clipID, style, title);
    +  76        } else {
    +  77            m('.invisible-line','');
    +  78        }
    +  79    }
    +  80
    +  81    abstract plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[];
    +  82
    +  83    setDefaults(data:Data, series:SeriesDef, scales:XYScale) {
    +  84    }
    +  85
    +  86
    +  87
    +  88
    +  89
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/PlotArea.html b/docs/src/hsGraph/PlotArea.html new file mode 100644 index 0000000..854c832 --- /dev/null +++ b/docs/src/hsGraph/PlotArea.html @@ -0,0 +1,105 @@ + + +

    PlotArea.ts

    +
       1/**
    +   2 * ## PlotArea
    +   3 * Plots data as an area. `PlotArea` is called if the series' `type` is 'area'.
    +   4 * The area will be filled between a series as indexed by `y` and the x-axis, 
    +   5 * or a second series indexed by `yBase`.
    +   6 * If `yBase` equals `$stacked`, subsequent series will be stacked upon each other.
    +   7 * `PlotArea` recognizes the following attributes:
    +   8 * - `x`: name of the x series
    +   9 * - `y`: name of the y series, also used as higher series when filling against `yBase`
    +  10 * - `yBase`: optional lower series to fill against instead of the x-axis. 
    +  11 * - `map`: Use 'stacked' to stack series upon each other. Use 'shared' to show the share of
    +  12 *    each series, normalized to 1.
    +  13 * 
    +  14 * 
    +  15 * 
    +  16 * let series = {
    +  17 *    colNames:['time', 'volume', 'costs'],
    +  18 *    rows:[
    +  19 *      [-1,  0.2, 0.3],
    +  20 *      [0.2, 0.7, 0.2],
    +  21 *      [0.4, 0.1, 0.3],
    +  22 *      [0.6, 0,   0.1],
    +  23 *      [0.8, 0.3, 0.5],
    +  24 *      [1,   0.2, 0.4]
    +  25 * ]};
    +  26 * 
    +  27 * m.mount(root, { 
    +  28 *    view:() => m(hslayout.Layout, {
    +  29 *       rows: [],
    +  30 *       content: [
    +  31 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg)}),
    +  32 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg, 'stacked')}),
    +  33 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg, 'shared')})
    +  34 *       ]
    +  35 *    })
    +  36 * });
    +  37 * function defCfg(cfg, map) {
    +  38 *     cfg.series.series = [
    +  39 *        { x:'time', y:'volume', map:map, type: 'area' },
    +  40 *        { x:'time', y:'costs',  map:map, type: 'area' }
    +  41 *     ];
    +  42 *     cfg.series.data      = [series];
    +  43 *     cfg.series.series[0].style.fill.color = 'rgba(128, 128, 255, 0.5)';
    +  44 *     cfg.series.series[1].style.fill.color = 'rgba(0, 128, 0, 0.5)';
    +  45 *     cfg.axes.primary.y.scale.domain = [0, 1];
    +  46 *     cfg.axes.primary.y.title.visible = false;
    +  47 *     cfg.chart.title.visible = false;
    +  48 * }
    +  49 * 
    +  50 * 
    +  51 * 

    +  52 */

    +  53
    +  54
    +  55/** */
    +  56import { m, Vnode}      from 'hslayout';
    +  57import { Data }         from 'hsdata';
    +  58import { XYScale }      from './AxesTypes';
    +  59import { Plot }         from './Plot';
    +  60import { SeriesDef }    from './Series';
    +  61
    +  62export class PlotArea extends Plot { 
    +  63    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {
    +  64        const x     = data.colNumber(series.x);
    +  65        const y     = data.colNumber(series.y);
    +  66        const yBase = data.colNumber(series.yBase);  // or undefined
    +  67        const yMax  = data.colNumber('$sum');
    +  68        const mapRow = (row:any[]) =>
    +  69            (yMax===undefined)? [
    +  70                row[x],
    +  71                row[y]+row[yBase],
    +  72                row[yBase]
    +  73            ] : [
    +  74                row[x],
    +  75                (row[y]+row[yBase]) / row[yMax],
    +  76                row[yBase] / row[yMax]
    +  77            ]; 
    +  78        if (y===undefined) { return m('.error',''); }
    +  79        if (series.map) {
    +  80            const d = data.getData().map(mapRow);
    +  81            return [this.drawArea(clipID, d, 0, 1, 2, scales, series.style, series.y)];
    +  82        } else {
    +  83            const d = data.getData();
    +  84            return [this.drawArea(clipID, d, x, y, yBase, scales, series.style, series.y)];
    +  85        }
    +  86    }
    +  87}
    +  88
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/PlotBar.html b/docs/src/hsGraph/PlotBar.html new file mode 100644 index 0000000..64061f6 --- /dev/null +++ b/docs/src/hsGraph/PlotBar.html @@ -0,0 +1,115 @@ + + +

    PlotBar.ts

    +
       1/**
    +   2 * ## PlotBar 
    +   3 * Plots data as vertical bars by configuring the series' `type` 
    +   4 * as {@link Series.Series.plot 'bar'}. The `cols` name array starts with 
    +   5 * the x-value column, or `undefined` to use the row index as x-values.
    +   6 * 
    +   7 * #### Mode 1 - Classic Bars
    +   8 * Specify a single name for y-values to generate bars that reach up from the
    +   9 * x-axis to the value in each data row. Negative heights are allowed.
    +  10 * Example: `y:'volume'`
    +  11 * 
    +  12 * #### Mode 2 - High-Low Bars
    +  13 * Specify names for y and yBase values to create high-low bars that reach from the 
    +  14 * y-value to the yBase-value for each data row. Negative heights are allowed.
    +  15 * Example: `y:'open', yBase:'close'`
    +  16 * 
    +  17 * #### Example
    +  18 * 
    +  19 * 
    +  20 * let series = {
    +  21 *    colNames:['time', 'volume', 'open', 'close'],
    +  22 *    rows:[
    +  23 *      [5, 0.2, 0.3, 0.5],
    +  24 *      [10, 0.7, 0.1, 0.2],
    +  25 *      [15, 0.4, 0.5, 0.6],
    +  26 *      [20, 0.1, 0.4, 0.6],
    +  27 *      [25,0.5, 0.3, 0.55],
    +  28 *      [30, 0.3, 0.4, 0.5]
    +  29 * ]};
    +  30 * 
    +  31 * m.mount(root, { 
    +  32 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    +  33 *          cfg.chart.title.text = 'Bar Chart';
    +  34 *          cfg.series.data   = [series];
    +  35 *          cfg.series.series = [
    +  36 *              { y:'volume', type: 'bar'},
    +  37 *              { y:'open', yBase:'close', type: 'bar'}
    +  38 *          ];
    +  39 *          cfg.series.series[0].style.bar.width = 80;
    +  40 *          cfg.series.series[1].style.bar.offset = 0;
    +  41 *          cfg.series.series[1].style.bar.width = 10;
    +  42 *      }})
    +  43 * });
    +  44 *
    +  45 * 
    +  46 * 

    +  47 */

    +  48
    +  49/** */
    +  50import { m, Vnode}      from 'hslayout';
    +  51import { Data }         from 'hsdata';
    +  52import { NumDomain }    from 'hsdata';
    +  53import { XYScale }      from './AxesTypes';
    +  54import { Plot }         from './Plot';
    +  55import { SeriesDef,
    +  56         SeriesStyle }  from './Series';
    +  57
    +  58export class PlotBar extends Plot {
    +  59    drawBar(clipID:string, data:Data, x:number, y:number, y0:number, scales:XYScale, sStyle:SeriesStyle, s:number) {
    +  60        const style = `fill: ${sStyle.bar.color};`;
    +  61        const index = (x === undefined);
    +  62        const domain = scales.x.domain();
    +  63        const offset = s*sStyle.bar.offset * (domain[1] - domain[0])/ (100 * data.getData().length);
    +  64        const width  = sStyle.bar.width    * (domain[1] - domain[0])/ (100 * data.getData().length);
    +  65        return m('svg', {class:'hs-graph-series-bars'}, data.getData().map(
    +  66            (p:number[], i:number) => {
    +  67                const rx0 = scales.x.convert((index? i : p[x]) + offset - width/2);
    +  68                const rx1 = scales.x.convert((index? i : p[x]) + offset + width/2);
    +  69                const ry0 = scales.y.convert(y0===undefined? 0 : p[y0]);
    +  70                const ry = scales.y.convert(p[y]);
    +  71                return this.rect({x:rx0, y:ry0}, {h:ry-ry0, w:rx1-rx0}, style);
    +  72            })
    +  73        );
    +  74    }
    +  75
    +  76    setDefaults(data:Data, series:SeriesDef, scales:XYScale) {
    +  77        super.setDefaults(data, series, scales);
    +  78        let  dom = scales.y.domain();
    +  79        if (dom[0] > 0) { 
    +  80            dom[0] = 0; 
    +  81            scales.y.domain(dom);
    +  82        }
    +  83        if (series.x === undefined) {
    +  84            scales.x.domain([-0.5, data.getData().length-0.5]);
    +  85        }
    +  86    }
    +  87
    +  88    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {
    +  89        const x = data.colNumber(series.x);
    +  90        const y = data.colNumber(series.y);
    +  91        const yBase = series.yBase? data.colNumber(series.yBase) : undefined;
    +  92        if (y===undefined) { return m('.error',''); }
    +  93        return [
    +  94            this.drawBar(clipID, data, x, y, yBase, scales, series.style, i),
    +  95        ];
    +  96    }
    +  97}
    +  98
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/PlotLine.html b/docs/src/hsGraph/PlotLine.html new file mode 100644 index 0000000..db943ab --- /dev/null +++ b/docs/src/hsGraph/PlotLine.html @@ -0,0 +1,68 @@ + + +

    PlotLine.ts

    +
       1/**
    +   2 * ## PlotLine
    +   3 * Plots data as a line by configuring the series' `type` 
    +   4 * as {@link Series.Series.plot 'line'}. The `cols` name array starts with 
    +   5 * the x-value column, followed by the y-column.
    +   6 * 
    +   7 * 
    +   8 * 
    +   9 * let series = {
    +  10 *    colNames:['time', 'volume'],
    +  11 *    rows:[
    +  12 *      [-1, 0.2],
    +  13 *      [0.2, 0.7],
    +  14 *      [0.4, -0.2],
    +  15 *      [0.6, 0],
    +  16 *      [0.8, 0.5],
    +  17 *      [1, 0.7]
    +  18 * ]};
    +  19 * 
    +  20 * m.mount(root, { 
    +  21 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    +  22 *          cfg.chart.title.text          = 'Simple Example';
    +  23 *          cfg.series.data   = [series];
    +  24 *          cfg.series.series = [{ x:'time', y:'volume' }];
    +  25 *      }})
    +  26 * });
    +  27 *
    +  28 * 
    +  29 * 

    +  30 */

    +  31
    +  32/** */
    +  33import { m, Vnode}  from 'hslayout';
    +  34import { Data }     from 'hsdata';
    +  35import { XYScale }  from './AxesTypes';
    +  36import { Plot }     from './Plot';
    +  37import { SeriesDef }from './Series';
    +  38
    +  39export class PlotLine extends Plot { 
    +  40    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {
    +  41        const x = data.colNumber(series.x);
    +  42        const y = data.colNumber(series.y);
    +  43        if (x===undefined) { return m('.error',''); }
    +  44        if (y===undefined) { return m('.error',''); }
    +  45        return [
    +  46            this.drawLine(clipID, data.getData(), x, y, scales, series.style, series.y),
    +  47            this.drawMarker(clipID, data.getData(), x, y, scales, series.style, series.y)
    +  48        ];
    +  49    }
    +  50}
    +  51
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/PlotMarkers.html b/docs/src/hsGraph/PlotMarkers.html new file mode 100644 index 0000000..1b23a9f --- /dev/null +++ b/docs/src/hsGraph/PlotMarkers.html @@ -0,0 +1,71 @@ + + +

    PlotMarkers.ts

    +
       1/**
    +   2 * ## PlotMarkers
    +   3 * Plots data as markers by configuring the series' `type` 
    +   4 * as {@link Series.Series.plot 'markers'}. 
    +   5 * The `cols` name array starts with 
    +   6 * the x-value column, followed by the y-column.
    +   7 * 
    +   8 * 
    +   9 * 
    +  10 * let series = {
    +  11 *    colNames:['time', 'volume'],
    +  12 *    rows:[
    +  13 *      [-1, 0.2],
    +  14 *      [0.2, 0.7],
    +  15 *      [0.4, -0.2],
    +  16 *      [0.6, 0],
    +  17 *      [0.8, 0.5],
    +  18 *      [1, 0.7]
    +  19 * ]};
    +  20 * 
    +  21 * m.mount(root, { 
    +  22 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    +  23 *          cfg.chart.title.text = 'Simple Example';
    +  24 *          cfg.series.data      = [series];
    +  25 *          cfg.series.series    = [{ x:'time', y:'volume', type: 'marker' }];
    +  26 *      }})
    +  27 * });
    +  28 *
    +  29 * 
    +  30 * 

    +  31 */

    +  32
    +  33/** */
    +  34import { m, Vnode}  from 'hslayout';
    +  35import { Data }     from 'hsdata';
    +  36import { XYScale }  from './AxesTypes';
    +  37import { Plot }     from './Plot';
    +  38import { SeriesDef }from './Series';
    +  39
    +  40export class PlotMarkers extends Plot { 
    +  41    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {
    +  42        const x = data.colNumber(series.x);
    +  43        const y = data.colNumber(series.y);
    +  44        const l = series.l? data.colNumber(series.l) : undefined;
    +  45        if (x===undefined) { return m('.error',''); }
    +  46        if (y===undefined) { return m('.error',''); }
    +  47        return [
    +  48            this.drawMarker(clipID, data.getData(), x, y, scales, series.style, series.y),
    +  49            (l===undefined)? undefined :
    +  50                this.drawLabel(clipID, data.getData(), x, y, l, scales, series)
    +  51        ];
    +  52    }
    +  53}
    +  54
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/SVGElem.html b/docs/src/hsGraph/SVGElem.html new file mode 100644 index 0000000..8fc9302 --- /dev/null +++ b/docs/src/hsGraph/SVGElem.html @@ -0,0 +1,312 @@ + + +

    SVGElem.ts

    +
       1import { m, Vnode } from 'hslayout';
    +   2import { XYScale }  from './AxesTypes';
    +   3import { DataRow }  from 'hsdata';
    +   4
    +   5/** svg primitive Point, measured in viewbox coordinates.  */
    +   6export interface Point {
    +   7    /** x-viewbox value of the point */
    +   8    x:   number;
    +   9    /** y-viewbox value of the point */
    +  10    y:   number;
    +  11    /** viewbox unit to use for x coordinate. Allowed values are 'px' or '%'; defaults to 'px' */
    +  12    xunit?: string;
    +  13    /** viewbox unit to use for y coordinate. Allowed values are 'px' or '%'; defaults to 'px' */
    +  14    yunit?: string;
    +  15}
    +  16
    +  17/** svg primitive Rect, measured in viewbox coordinates.  */
    +  18export interface Rect {
    +  19    /** top left point */
    +  20    tl: Point;
    +  21    /** bottom right point */
    +  22    br: Point;
    +  23}
    +  24
    +  25/** 
    +  26 * svg extended Point, measured in viewbox coordinates. 
    +  27 * Extends `Point` with optional `dx` and 'dy' offsets and optional units.
    +  28 */

    +  29export interface ExtendedPoint extends Point{
    +  30    dx?: number;
    +  31    dy?: number;
    +  32    dxunit?: string;
    +  33    dyunit?: string;
    +  34}
    +  35
    +  36
    +  37export interface Area {
    +  38    w: number;
    +  39    h: number;
    +  40    wunit?: string;
    +  41    hunit?: string;
    +  42}
    +  43
    +  44export interface TextElem {
    +  45    /** the text to show */
    +  46    text: string; 
    +  47
    +  48    /** a css class to set */
    +  49    cssClass?:  string;   
    +  50
    +  51    /** a style to set */
    +  52    style?:  string;   
    +  53
    +  54    /** optional absolute x positioning on the canvas, e.g. '50%' */
    +  55    x?:         string;
    +  56
    +  57    /** optional absolute y positioning on the canvas, e.g. '50%' */
    +  58    y?:         string;
    +  59    
    +  60    /** horizontal align: 'start' | 'middle' | 'end'; uses `text-align` attribute */
    +  61    xpos:       TextHAlign;
    +  62
    +  63    /** vertical align: 'top' | 'center' | 'bottom'; uses `dy` attribute */
    +  64    ypos:       TextVAlign;
    +  65
    +  66    /** horizontal label offset in 'em'; uses `dx` attribute */
    +  67    hOffset:    number;
    +  68
    +  69    /** vertical label offset in 'em'; uses `dy` attribute */
    +  70    vOffset:    number;
    +  71}
    +  72
    +  73export function round (num:number):string { 
    +  74    const result = num.toFixed(1);
    +  75    if (result === 'Infinity') {
    +  76        return '1e20';
    +  77    } 
    +  78    return result;
    +  79}
    +  80
    +  81export enum TextHAlign {
    +  82    start   = 'start',
    +  83    middle  = 'middle',
    +  84    end     = 'end'
    +  85}
    +  86
    +  87export enum TextVAlign {
    +  88    top     = 'top',
    +  89    center  = 'center',
    +  90    bottom  = 'bottom'
    +  91}
    +  92
    +  93export abstract class SVGElem {
    +  94    /**
    +  95     * plot some text 
    +  96     * @param cfg configures the text alignment and positioning
    +  97     * @param text the text to plot
    +  98     */

    +  99    text(cfg:TextElem, text:string):Vnode {
    + 100        let yShift = 0;
    + 101        let hAlign:TextHAlign = cfg.xpos;
    + 102        switch(cfg.xpos) {
    + 103            case TextHAlign.start:  break;
    + 104            case TextHAlign.end:    break;
    + 105            case TextHAlign.middle: 
    + 106            default:       hAlign = TextHAlign.middle; break;
    + 107        }
    + 108        switch(cfg.ypos) { // additional y 'em' shift
    + 109            case TextVAlign.top:    yShift = 0.7; break;
    + 110            case TextVAlign.center: yShift = 0.35; break;
    + 111            case TextVAlign.bottom: 
    + 112            default:                yShift =  0; break;
    + 113        }
    + 114        const param = { 
    + 115            x: cfg.x || '', 
    + 116            y: cfg.y || '',
    + 117            dx:round(cfg.hOffset||0) + 'em',    
    + 118            dy:round((cfg.vOffset||0)+yShift) + 'em',
    + 119            style: `text-anchor:${hAlign}; ${cfg.style||''}`,
    + 120            class: cfg.cssClass,
    + 121        };
    + 122        return m('text', param, text);
    + 123    }
    + 124
    + 125    /**
    + 126     * plot a rectangle in domain coordinates
    + 127     * @param tl the top-left corner of the rect
    + 128     * @param area the width and height of the rect
    + 129     * @param style optional css style setting, such as stroke or stroke-width
    + 130     */

    + 131    rect(tl:Point, area:Area, style:string, title?:string):Vnode {
    + 132        if (area.w < 0) {
    + 133            tl.x += area.w;
    + 134            area.w = -area.w;
    + 135        }
    + 136        if (area.h < 0) {
    + 137            tl.y += area.h;
    + 138            area.h = -area.h;
    + 139        }
    + 140        const param = {
    + 141            x: round(tl.x),       y: round(tl.y),
    + 142            width: round(area.w)  + (area.wunit||''), 
    + 143            height: round(area.h) + (area.hunit||''),
    + 144            style: style
    + 145        };
    + 146        return m('rect', param), m('title', title);
    + 147    }
    + 148
    + 149    /**
    + 150     * plot a circle around the center domain point `c`, with radius `r`
    + 151     * @param c the circle's center point in domain coordinates
    + 152     * @param r the circle's radius, in domain coordinates
    + 153     * @param style optional css style setting, such as stroke or stroke-width
    + 154     */

    + 155    circle(c:Point, r:number, style:string, title?:string):Vnode {
    + 156        return m('circle', 
    + 157            { cx: round(c.x), cy: round(c.y), r: round(r), style: style },
    + 158            m('title', title)
    + 159        );
    + 160    }
    + 161
    + 162    /**
    + 163     * defines a clip rect to apply to other elelements via the `id`
    + 164     * @param tl top-left corner of the `clipRect` in domain coordinates
    + 165     * @param area width and height of the `clipRect` in domain coordinates
    + 166     * @param id a unique clip id to reference the `clipRect` by
    + 167     */

    + 168    clipRect(tl:Point, area:Area, id:string):Vnode {
    + 169        const param = {
    + 170            x: round(tl.x),       y: round(tl.y),
    + 171            width: round(area.w)  + (area.wunit||''), 
    + 172            height: round(area.h) + (area.hunit||'')
    + 173        };
    + 174        return m('defs', m('clipPath', {id: id}, m('rect', param)));
    + 175    }
    + 176
    + 177    /**
    + 178     * plots a straight line from `x0/y0` to `x1/y1`.
    + 179     * @param x0 starting point x domain coordinate 
    + 180     * @param x1 ending point x domain coordinate 
    + 181     * @param y0 starting point y domain coordinate 
    + 182     * @param y1 ending point y domain coordinate 
    + 183     * @param cssClass optional css class attribute
    + 184     */

    + 185    line(x0:number, x1:number, y0:number, y1:number, cssClass?:string):Vnode {
    + 186        const param = {
    + 187            x1: round(x0), y1: round(y0), 
    + 188            x2: round(x1),   y2: round(y1), 
    + 189            class: cssClass
    + 190        };
    + 191        return m('line', param);
    + 192    }
    + 193
    + 194    /**
    + 195     * plots a horizontal line from `x0/y` to `x1/y`.
    + 196     * @param x0 starting point x domain coordinate 
    + 197     * @param x1 ending point x domain coordinate 
    + 198     * @param y  starting and ending point y domain coordinate 
    + 199     * @param cssClass optional css class attribute
    + 200     */

    + 201    horLine(x0:number, x1:number, y:number, cssClass?:string):Vnode {
    + 202        const param = {
    + 203            x1: round(x0), y1: round(y), 
    + 204            x2: round(x1), y2: round(y), 
    + 205            class: cssClass
    + 206        };
    + 207        return m('line', param);
    + 208    }
    + 209
    + 210    /**
    + 211     * plots a vertical line from `x/y0` to `x/y1`.
    + 212     * @param x  starting and ending point x domain coordinate 
    + 213     * @param y0 starting point y domain coordinate 
    + 214     * @param y1 ending point y domain coordinate 
    + 215     * @param cssClass optional css class attribute
    + 216     */

    + 217    verLine(x:number, y0:number, y1:number, cssClass?:string):Vnode {
    + 218        const param = {
    + 219            x1: round(x), y1: round(y0), 
    + 220            x2: round(x), y2: round(y1), 
    + 221            class: cssClass
    + 222        };
    + 223        return m('line', param);
    + 224    }
    + 225
    + 226    /**
    + 227     * plots a polyline from points in `data`. `x` and `y` are the indices to reference 
    + 228     * the data for the x-axis, respectively the y-axis in each row in `data`. That is,
    + 229     * plot `data[row][x] / data[row][y]` for all rows. 
    + 230     * @param data an array of rows; each row is an array of data. The first row contains the 
    + 231     * series names and will be skipped.
    + 232     * @param x the index in each row to use as x coordinate
    + 233     * @param y the index in each row to use as y coordinate
    + 234     * @param scales the scales to use to convert coordinates into range values
    + 235     * @param id the unique clip-path id to use, or undefined
    + 236     * @param style an optional `style` attribute, e.g. to set the stroke and stroke-width.
    + 237     */

    + 238    polyline(data:DataRow[], x:number, y:number, scales:XYScale, id:string, style?:string, title?:string):Vnode {
    + 239        return m('polyline', { 
    + 240            'clip-path': id? `url(#${id})` : undefined,
    + 241            style: style,
    + 242            points: data.map((row:number[]) => 
    + 243                `${round(scales.x.convert(row[x]))},${round(scales.y.convert(row[y]))}`).join(' ')
    + 244        }, m('title', title)); 
    + 245    }
    + 246
    + 247    /**
    + 248     * plots a polygon from points in `data`. `x` and `y` are the indices to reference 
    + 249     * the data for the x-axis, respectively the y-axis in each row in `data`. That is,
    + 250     * plot `data[row][x] / data[row][y]` for all rows. 
    + 251     * @param data an array of rows; each row is an array of data. The first row contains the 
    + 252     * series names and will be skipped.
    + 253     * @param x the index in each row to use as x coordinate
    + 254     * @param y the index in each row to use as y coordinate
    + 255     * @param scales the scales to use to convert coordinates into range values
    + 256     * @param id the unique clip-path id to use, or undefined
    + 257     * @param style an optional `style` attribute, e.g. to set the stroke and stroke-width.
    + 258     */

    + 259    polygon(dataFore:DataRow[], dataBack:DataRow[], x:number, yFore:number, yBack:number, scales:XYScale, id:string, style?:string, title?:string):Vnode {
    + 260        const indexed = (x===undefined);
    + 261        const sx = (_x:number) => round(scales.x.convert(_x));
    + 262        const sy = (_y:number) => round(scales.y.convert(_y));
    + 263        const clip = id? `url(#${id})` : undefined;
    + 264        const points:string = 
    + 265                dataFore.map((row:number[], i:number) => 
    + 266                    `${sx(indexed?i:row[x])},${sy(row[yFore])}`)
    + 267        .concat(dataBack.map((row:number[], i:number) => 
    + 268                    `${sx(indexed?(dataBack.length-i-1):row[x])},${sy(yBack?row[yBack]:0)}`
    + 269        )).join(' ');
    + 270        return m('polygon', { 'clip-path': clip, style: style, points: points }, m('title', title));
    + 271    }
    + 272
    + 273    /**
    + 274     * plots a shape from points in `data`. `x` and `y` are the indices to reference 
    + 275     * the data for the x-axis, respectively the y-axis in each row in `data`. That is,
    + 276     * plot `data[row][x] / data[row][y]` for all rows. 
    + 277     * @param data an array of rows; each row is an array of data. The first row contains the 
    + 278     * series names and will be skipped.
    + 279     * @param x the index in each row to use as x coordinate
    + 280     * @param y the index in each row to use as y coordinate
    + 281     * @param scales the scales to use to convert coordinates into range values
    + 282     * @param id the unique clip-path id to use, or undefined
    + 283     * @param style an optional `style` attribute, e.g. to set the stroke and stroke-width.
    + 284     */

    + 285    shape(points:DataRow[], id:string, style:string, title?:string):Vnode {
    + 286        return m('polyline', { 
    + 287            'clip-path': id? `url(#${id})` : undefined,
    + 288            style: style,
    + 289            points: points.map((row:number[]) => 
    + 290                `${round(row[0])},${round(row[1])}`).join(' ')
    + 291            }, m('title', title)); 
    + 292    }
    + 293}
    + 294
    + 295
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Scale.html b/docs/src/hsGraph/Scale.html new file mode 100644 index 0000000..8822b66 --- /dev/null +++ b/docs/src/hsGraph/Scale.html @@ -0,0 +1,299 @@ + + +

    Scale.ts

    +
       1/**
    +   2 * @module Axes
    +   3 */

    +   4
    +   5/** */ 
    +   6import { Domain, 
    +   7         NumRange }     from 'hsdata';
    +   8import { Axes }         from './Axes';
    +   9import { date, ms }     from 'hsutil';
    +  10import { Ticks,
    +  11         TickDefs,
    +  12         TickLabel,
    +  13         ScaleCfg }     from './AxesTypes';
    +  14
    +  15
    +  16function addTickNumber(t:TickDefs, v:number) { 
    +  17    t.labels.push({ pos: v, text: ''+Math.round(v*1000000)/1000000 }); 
    +  18}
    +  19
    +  20function addTickDate(t:TickDefs, v:Date, fmt:string) { 
    +  21    t.labels.push({ pos: v.getTime(), text:date(fmt, v) }); 
    +  22}
    +  23
    +  24
    +  25/** calculate major and minor ticks on a lionear scale. The first and last tick will be smaller and larger than the provided domain. */
    +  26function linScaleTickMarks(dom:NumRange, ticks:Ticks, numTicks:number) {
    +  27    function addTicks(unit:number, ticks:TickDefs):number {
    +  28        let exp = Math.pow(10, Math.floor(Math.log10(unit)));
    +  29        unit = Math.floor(unit / exp)*exp;
    +  30        const min = Math.floor(dom[0]/unit)*unit;
    +  31        const max = Math.ceil(dom[1]/unit)*unit;
    +  32        for (let v=min; v<=max; v+=unit) { addTickNumber(ticks, v); }
    +  33        return unit;
    +  34    }
    +  35    const majorUnit = addTicks((dom[1] - dom[0]) / numTicks, ticks.major);
    +  36    addTicks(majorUnit / numTicks, ticks.minor);
    +  37}
    +  38
    +  39function percentScaleTickMarks(dom:NumRange, ticks:Ticks, numTicks:number) {
    +  40    const formatPercent = (m:TickLabel) => m.text = `${Math.round(m.pos)*100}%`;
    +  41    linScaleTickMarks(dom, ticks, numTicks);
    +  42    ticks.major.labels.forEach(formatPercent);
    +  43    ticks.minor.labels.forEach(formatPercent);
    +  44//    addMinMaxTicks(dom, ticks);
    +  45}
    +  46
    +  47function logScaleTickMarks(dom:NumRange, ticks:Ticks) {
    +  48    dom[0] = Math.max(dom[0], 1e-20);
    +  49    dom[1] = Math.max(dom[1], 1e-20);
    +  50    let dif = Math.pow(10, Math.floor(Math.log10(dom[1] - dom[0])));
    +  51    let min = Math.pow(10, Math.floor(Math.log10(dom[0])));
    +  52    let max = Math.pow(10, Math.ceil(Math.log10(dom[1])));
    +  53    if (dif > min) {
    +  54        for (let v = min; v<=max; v*=10) {
    +  55            for (let i=1; i<=20; i++) {
    +  56                if (i===1 && v*i +  57                else if (i%10===0) {}
    +  58                else if (i<10) {        addTickNumber(ticks.minor, v*i); }
    +  59                else if (i%2===0) {     addTickNumber(ticks.minor, v*i); }
    +  60            }
    +  61        }
    +  62    } else {
    +  63        min = Math.floor(dom[0]/dif)*dif;
    +  64        max = Math.ceil(dom[1]/dif)*dif;
    +  65        if ((max-min)/dif < 4) { 
    +  66            dif /= 2; 
    +  67        }
    +  68        for (let v = min; v<=max; v+=dif) {
    +  69            addTickNumber(ticks.major, v);
    +  70        }
    +  71        addTickNumber(ticks.major, min);
    +  72        addTickNumber(ticks.major, max);
    +  73    }
    +  74}
    +  75
    +  76const tickCategories = [
    +  77    [10,0,0,0], [5,0,0,0], [2,0,0,0], [1,0,0,0], [0,6,0,0], [0,3,0,0], [0,1,0,0], [0,0,7,0], [0,0,1,0], [0,0,0,4], [0,0,0,1]
    +  78];
    +  79
    +  80function dateScaleTickMarks(dom:Domain, ticks:Ticks, fmt='%MM/%DD/%YY') {
    +  81    function addDates(i:number, tickDefs:TickDefs) {
    +  82        const createDate = (idx:number) => new Date(
    +  83            Math.floor(
    +  84   /* yr*/  dateDom[idx].getFullYear()/modYr)*modYr + (idx?incYr:0),
    +  85   /* mo*/  (incYr > 0)? 0 : Math.floor(dateDom[idx].getMonth()/modMo)*modMo + (idx?incMo:0),
    +  86   /* d */  (incMo > 0)? 1 : (dateDom[idx].getDate()- ((incDay === 7)? dateDom[idx].getDay() : 0)) + (idx?incDay:0),
    +  87   /* h */  (incDay> 0)? 0 : (dateDom[idx].getHours()) + (idx?incHour:0)
    +  88        );
    +  89        const incYr   = tickCategories[i][0]; 
    +  90        const incMo   = tickCategories[i][1]; 
    +  91        const incDay  = tickCategories[i][2];
    +  92        const incHour = tickCategories[i][3];
    +  93        const modYr   = incYr || 1;
    +  94        const modMo   = incMo || 1;
    +  95        const date0   = createDate(0);
    +  96        const date1   = createDate(1);
    +  97        fmt = incHour? '%hh:%mm' : '%MM/%DD/%YY';
    +  98        for (let d = date0; d<=date1; d = new Date(d.getFullYear()+incYr, d.getMonth()+incMo, d.getDate()+incDay, d.getHours()+incHour)) { 
    +  99            addTickDate(tickDefs, d, fmt); 
    + 100        } 
    + 101
    + 102    }
    + 103    const dateDom:Date[] = [
    + 104        (typeof dom[0] === 'number')? new Date(dom[0]) : dom[0], 
    + 105        (typeof dom[1] === 'number')? new Date(dom[1]) : dom[1]
    + 106    ];
    + 107    if (isNaN(dateDom[0].getTime())) { dateDom[0] = new Date('1/1/1980'); } 
    + 108    if (isNaN(dateDom[1].getTime())) { dateDom[0] = new Date(); } 
    + 109    const d = dateDom[1].getTime() - dateDom[0].getTime();
    + 110    tickCategories.some((cat:number[], i:number) => {
    + 111        const dMin = ms.fromDays((cat[0]*365 + cat[1]*30 + cat[2])) + ms.fromHours(cat[3]);
    + 112        if (d>3*dMin) {
    + 113            addDates(i, ticks.major);
    + 114            addDates(Math.min(i+1, tickCategories.length-1), ticks.minor);
    + 115            return true;
    + 116        } else {
    + 117            return false;
    + 118        }
    + 119    });
    + 120}
    + 121
    + 122/** calculates major tick label domain values */
    + 123function createTickLabels(type:string, domain:Domain, numTicks:number, fmt:string):Ticks {
    + 124    const sort = (a:TickLabel,b:TickLabel) => a.pos-b.pos;
    + 125    function sortTicks() { 
    + 126        ticks.minor.labels.sort(sort); ticks.major.labels.sort(sort); 
    + 127    };
    + 128    const dom:NumRange = [domain[0], domain[1]];
    + 129    const ticks:Ticks = {
    + 130        major: {marks:[], labels: []},
    + 131        minor: {marks:[], labels: []}
    + 132    };
    + 133    switch(type) {
    + 134        case Axes.type.log:     logScaleTickMarks(dom, ticks); sortTicks(); break;
    + 135        case Axes.type.date:    dateScaleTickMarks(dom, ticks, fmt); sortTicks(); break;
    + 136        case Axes.type.percent: percentScaleTickMarks(dom, ticks, numTicks); sortTicks(); break;
    + 137        case Axes.type.ordinal: break; 
    + 138        case Axes.type.nominal: break;
    + 139        case Axes.type.index:   
    + 140        case Axes.type.linear:
    + 141        default:                linScaleTickMarks(dom, ticks, numTicks); sortTicks(); 
    + 142    }  
    + 143    return ticks;
    + 144}
    + 145
    + 146
    + 147/**
    + 148 * translates a domain into a range
    + 149 */

    + 150export class Scale {    
    + 151    /** Defines default values for all configurable parameters */
    + 152    private typeVal:string      = Axes.type.linear;
    + 153    private rangeVal:NumRange   = [0,1];
    + 154    private domVal:Domain       = [0,1];
    + 155    private domMinAuto          = 0; // 0: explicit domain; 1: auto domain loose, 2: auto tight
    + 156    private domMaxAuto          = 0; // 0: explicit domain; 1: auto domain loose, 2: auto tight
    + 157    private labelFmt:string;
    + 158
    + 159    constructor(private cfg:ScaleCfg) { 
    + 160        this.scaleType(cfg.type);
    + 161        this.domain(cfg.domain);
    + 162    }
    + 163
    + 164    public setLabelFormat(labelFmt:string) {
    + 165        this.labelFmt = labelFmt;
    + 166    }
    + 167
    + 168    public range(r?:NumRange):NumRange   { 
    + 169        if (r) { 
    + 170            this.rangeVal = r; 
    + 171        }
    + 172        return this.rangeVal;
    + 173    }
    + 174    public domain(dom?:Domain):Domain { 
    + 175        if (dom) {
    + 176            if (this.scaleType() === Axes.type.date) {
    + 177                if (typeof dom[0] === 'string'|| typeof dom[1] === 'string') {
    + 178                    this.domVal[0] = (dom[0] === 'auto')? 0 : Date.parse(dom[0]); 
    + 179                    this.domVal[1] = (dom[1] === 'auto')? 1 : Date.parse(dom[1]); 
    + 180                }
    + 181            } else {
    + 182                    this.domVal[0] = (dom[0] === 'auto')? 0 : dom[0]; 
    + 183                    this.domVal[1] = (dom[1] === 'auto')? 1 : dom[1]; 
    + 184            }
    + 185            switch(dom[0]) {
    + 186                case 'tight' : this.domMinAuto = 2; break;
    + 187                case 'auto' :  this.domMinAuto = 1; break;
    + 188                default:       this.domMinAuto = 0;
    + 189            }
    + 190            switch(dom[1]) {
    + 191                case 'tight' : this.domMaxAuto = 2; break;
    + 192                case 'auto' :  this.domMaxAuto = 1; break;
    + 193                default:       this.domMaxAuto = 0;
    + 194            }
    + 195        }
    + 196        if (this.typeVal === Axes.type.log) {
    + 197            if (this.domVal[1] <= 0) { this.domVal[1] = 10; }
    + 198            if (this.domVal[0] <= 0) { this.domVal[0] = (this.domVal[1])/10; }
    + 199        }
    + 200        return this.domVal;
    + 201    }
    + 202    public scaleType(s?:string):string {
    + 203        if (s) { 
    + 204            this.typeVal = s; 
    + 205        }
    + 206        return this.typeVal;
    + 207    }
    + 208
    + 209    /**
    + 210     * If a `domain` limit is set to `auto`, calling this function tells the `Scale`
    + 211     * what the values of the min or max of the data set in the `domain` range are. 
    + 212     * These will be rounded down (for min) and up (for max) to determine the auto-range.
    + 213     * @param dom the `[min,max]` range of the data
    + 214     */

    + 215    public setAutoDomain(dom:NumRange) {
    + 216        const ticks:Ticks = createTickLabels(this.scaleType(), dom, 4, this.labelFmt);
    + 217        switch (this.domMinAuto) {
    + 218            case 1: this.domVal[0] = ticks.major.labels[0]? ticks.major.labels[0].pos : dom[0]; break; // loose
    + 219            case 2: this.domVal[0] = dom[0]; break;             // tight
    + 220        }
    + 221        switch (this.domMaxAuto) {
    + 222            case 1: this.domVal[1] = ticks.major.labels[ticks.major.labels.length-1].pos; break;
    + 223            case 2: this.domVal[1] = dom[1]; break;
    + 224        }
    + 225    }
    + 226
    + 227    /**
    + 228     * Calculates major and minor tick marks in domain coordinates
    + 229     */

    + 230    public ticks(numTicks:number=4):Ticks   { 
    + 231        function marksFromLabels(ticks:Ticks, type:string) {
    + 232            switch(type) {
    + 233                case Axes.type.nominal: 
    + 234                case Axes.type.index:   
    + 235                    const numLabels = ticks.major.labels.length;
    + 236                    ticks.major.marks = Array(numLabels+1).fill(1).map((e:any, i:number) => i-0.5);
    + 237                    ticks.minor.marks = ticks.minor.labels? ticks.minor.labels.map((l:TickLabel) => l.pos) : [];
    + 238                    break;
    + 239                case Axes.type.log: 
    + 240                case Axes.type.date:    
    + 241                case Axes.type.percent: 
    + 242                case Axes.type.ordinal:  
    + 243                case Axes.type.linear:
    + 244                default:
    + 245                    ticks.major.marks = ticks.major.labels? ticks.major.labels.map((l:TickLabel) => l.pos) : [];
    + 246                    ticks.minor.marks = ticks.minor.labels? ticks.minor.labels.map((l:TickLabel) => l.pos) : [];
    + 247            }
    + 248        }
    + 249        const dom:NumRange = [this.domain()[0], this.domain()[1]];
    + 250        const inRange = (t:TickLabel) => t.pos>=dom[0] && t.pos<=dom[1];
    + 251        const ticks:Ticks =  createTickLabels(this.scaleType(), this.domain(), numTicks, this.labelFmt);
    + 252        ticks.minor.labels = ticks.minor.labels.filter(inRange);
    + 253        ticks.major.labels = ticks.major.labels.filter(inRange);
    + 254        if (ticks.major.labels.length === 0) { ticks.major.labels = ticks.minor.labels; ticks.minor.labels = []; }
    + 255        marksFromLabels(ticks, this.scaleType());
    + 256        return ticks;
    + 257    }
    + 258    
    + 259    /** converts a domain value to a range value */
    + 260    convert(domVal:number):number { 
    + 261        const dom = this.domain();
    + 262        const range = this.range();
    + 263        const domMin = dom[0];
    + 264        const domMax = dom[1];
    + 265        let result;
    + 266        switch(this.scaleType()) {
    + 267            case Axes.type.log: 
    + 268                result = Math.log(domVal/domMin) / Math.log(domMax/domMin) * (range[1] - range[0]) + range[0];
    + 269                break;
    + 270            case Axes.type.nominal: break;
    + 271            case Axes.type.date:    
    + 272            case Axes.type.percent: 
    + 273            case Axes.type.index:   
    + 274            case Axes.type.ordinal:  
    + 275            case Axes.type.linear:
    + 276            default:
    + 277                result = (domVal- domMin) / (domMax - domMin) * (range[1] - range[0]) + range[0];
    + 278        }
    + 279        return result;
    + 280    }
    + 281}
    + 282
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/Series.html b/docs/src/hsGraph/Series.html new file mode 100644 index 0000000..79e9e2e --- /dev/null +++ b/docs/src/hsGraph/Series.html @@ -0,0 +1,380 @@ + + +

    Series.ts

    +
       1/**
    +   2 * # Series
    +   3 * renders the one or more series in a variety of styles.
    +   4 * 
    +   5 * ### Configurations and Defaults
    +   6 * See {@link Series.Series.defaultConfig Series.defaultConfig} for defaults
    +   7 * and {@link Series.SeriesDef SeriesDef} for defining configuration details.
    +   8 * 
    +   9 * ### Attributes
    +  10 * The `Series` class is called by {@link Graph.Graph `Graph`} as 
    +  11 * `m(Series, { cfg:cfg.series, scales:scales, data:this.data })`
    +  12 * with the following attributes:
    +  13 * - cfg: {@link Series.SeriesConfig `SeriesConfig`} configuration parameters for series
    +  14 * - scales: {@link Axes.XYScale `XYScale`} the scales to use
    +  15 * - data: {@link hsData:Data.Data `Data`} array of `Data` sets to use, indexed by cfg[].dataIndex
    +  16 * 
    +  17 * @module Series
    +  18 */

    +  19
    +  20/** */
    +  21import { m, Vnode}      from 'hslayout';
    +  22import { Config,
    +  23         VisibleCfg }   from './Graph';
    +  24import { Data, 
    +  25         DataSet }      from 'hsdata';
    +  26import { Condition }    from 'hsdata';
    +  27import { SVGElem }      from './SVGElem';
    +  28import { Axes }         from './Axes';
    +  29import { XYScale }      from './AxesTypes';
    +  30import { PlotLine }     from './PlotLine';
    +  31import { PlotMarkers }  from './PlotMarkers';
    +  32import { PlotBar }      from './PlotBar';
    +  33import { PlotArea }     from './PlotArea';
    +  34
    +  35
    +  36function copyDefault(target:any, source:any, defaults:any) {
    +  37    Object.keys(source).forEach((key:string) => {
    +  38        if (typeof source[key] === 'object') { 
    +  39            if (target[key] === undefined) { target[key] = {}; }
    +  40            copyDefault(target[key], source[key], defaults); 
    +  41        } else {
    +  42            if (target[key] === undefined) { target[key] = source[key]; }
    +  43            if (target[key] === 'default') { target[key] = defaults[key]; }
    +  44        }
    +  45    });
    +  46}
    +  47
    +  48/**
    +  49 * 
    +  50 */

    +  51export class Series extends SVGElem { 
    +  52    /**
    +  53     * Defines available styles for series marker:
    +  54     * - circle
    +  55     * - square
    +  56     * - diamond
    +  57     * - upTriangle
    +  58     * - downTriangle
    +  59     */

    +  60    static marker = {
    +  61        circle:         Symbol('circle marker'),
    +  62        square:         Symbol('square marker'),
    +  63        diamond:        Symbol('diamond marker'),
    +  64        upTriangle:     Symbol('upward triangle marker'),
    +  65        downTriangle:   Symbol('downward triangle marker')
    +  66    };
    +  67
    +  68    /**
    +  69     * Defines available plot types:
    +  70     * - line
    +  71     * - bar
    +  72     */

    +  73    static plot = {
    +  74        line:    new PlotLine(),
    +  75        marker:  new PlotMarkers(),
    +  76        bar:     new PlotBar(),
    +  77        area:    new PlotArea()
    +  78    };
    +  79
    +  80    static map = {
    +  81        stacked: 'stacked',
    +  82        shared:  'shared'
    +  83    };
    +  84
    +  85    /** 
    +  86     * Defines default values for all configurable parameters in `Series`
    +  87     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    +  88     * 
    +  89     * ### Configurations and Defaults
    +  90     * ```
    +  91     *  cfg.series = {@link Series.SeriesConfig }{
    +  92     *          // pool of `Data` sets to be plotted, initialized as `[]`
    +  93     *      data: {@link hsData:Data.DataSet },     
    +  94     *          // series an markers are clipped to the plot area
    +  95     *      clip: true,       
    +  96     *          // array of series descriptors, initialized to empty array (no series)
    +  97     *      series: {@link Series.SeriesDef }[],
    +  98     *          // sets the default colors that will be assigend to series by index
    +  99     *      defaultColors:
    + 100     *          ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f', '#000', '#444', '#888', '#ccc'],
    + 101     *          // sets the default style to be applied to series
    + 102     *      defaultStyle: {@link Series.SeriesStyle } {
    + 103     *          line:   { 
    + 104     *              color: , // the line color to use, preset from defaultColors
    + 105     *              width: 5,       // the line width in viewbox units
    + 106     *              visible: true   // whether line is draw or not
    + 107     *          },
    + 108     *          marker: { 
    + 109     *              color: , // the marker color to use, preset from defaultColors
    + 110     *              size: 10,       // the marker size in viewbox coordinates
    + 111     *              shape: Series.marker.circle, // the marker shaper, See {@link Series.Series.marker Series.marker}
    + 112     *              visible: true 
    + 113     *          },
    + 114     *          fill: { 
    + 115     *              color: , // the fill color to use, preset from defaultColors
    + 116     *              visible: true 
    + 117     *          },
    + 118     *          bar: { 
    + 119     *              color: , // the bar color to use, preset from defaultColors
    + 120     *              width: 10,
    + 121     *              visible: true 
    + 122     *          }
    + 123     *      }
    + 124     *  } 
    + 125     * ``` 
    + 126     * @param cfg the configuration object, containing default settings for all 
    + 127     * previously configured components.
    + 128     */

    + 129    static defaultConfig(cfg:Config) {
    + 130        cfg.series = new SeriesConfig();
    + 131    }
    + 132
    + 133    /**
    + 134     * Makes adjustments to cfg based on current settings
    + 135     * @param cfg the configuration object, containing default settings for all components
    + 136     */

    + 137    static adjustConfig(cfg:Config) { 
    + 138        cfg.series.series.forEach((s:SeriesDef) => {
    + 139            if (s.x === undefined) { // undefined x-value -> use index as x-value
    + 140                cfg.axes.primary.x.title.hOffset = 0;
    + 141                cfg.axes.primary.x.scale.type = Axes.type.index;
    + 142                cfg.grid.minor.ver.visible = false;
    + 143            }
    + 144        });
    + 145    }
    + 146    
    + 147    drawClipRect(clipID:string, scales:XYScale) {
    + 148        return !clipID? m('') : this.clipRect(
    + 149            {   x:scales.x.range()[0], y:scales.y.range()[1]}, 
    + 150            {
    + 151                w:scales.x.range()[1] - scales.x.range()[0], 
    + 152                h:scales.y.range()[0] - scales.y.range()[1]
    + 153            }, 
    + 154            clipID);
    + 155    }
    + 156
    + 157    view(node?: Vnode): Vnode {
    + 158        const cfg:SeriesConfig  = node.attrs.cfg;
    + 159        const scales:XYScale = node.attrs.scales.primary;
    + 160        const data:Data[]    = node.attrs.data;
    + 161        const clipID = cfg.clip? 'hs'+Math.floor(Math.random()*10000) : undefined;
    + 162        cfg.series.map((s:SeriesDef) => {
    + 163            if (s.map === Series.map.shared) {  // reset ySum if needed
    + 164                s.ySum = '$sum';
    + 165                data[s.dataIndex].colAdd(s.ySum);            // add $max if not present
    + 166                data[s.dataIndex].colInitialize(s.ySum, 0);  // and initialize to 0
    + 167            }
    + 168        });
    + 169        cfg.series.map((s:SeriesDef) => {
    + 170            const dt = data[s.dataIndex];
    + 171            if (s.map===Series.map.shared) {    // aggregate ySum over series
    + 172                const valCol = dt.colNumber(s.y);                       
    + 173                dt.colInitialize(s.ySum, (v:number, i:number, row:number[])=>{ return v+row[valCol]; });
    + 174            }
    + 175            if (s.map) {
    + 176                s.yBase = '$'+ s.map;
    + 177                dt.colAdd(s.yBase);             // add $stacked or $shared if not present
    + 178                dt.colInitialize(s.yBase, 0);   // and initialize to 0
    + 179            }
    + 180        });
    + 181        return m('svg', { class:'hs-graph-series'}, [
    + 182            this.drawClipRect(clipID, scales),
    + 183            m('svg', cfg.series.map((s:SeriesDef, i:number) => { 
    + 184                const dt = data[s.dataIndex];
    + 185                const type = Series.plot[s.type] || Series.plot.line;
    + 186                type.setDefaults(dt, s, scales);
    + 187                const d = s.cond? dt.filter(s.cond) : dt;
    + 188                const plot = type.plot(d, s, scales, i, clipID);  // plot y above yBase; 
    + 189                if (s.map) {                                      // if 'stacked' or 'shared' -> accumulate y
    + 190                    const valCol = d.colNumber(s.y);                       
    + 191                    d.colInitialize(s.yBase, (v:number, i:number, row:number[])=>{ return v+row[valCol]; });
    + 192                }
    + 193                return m('svg', {class:`hs-graph-series-${i}`}, plot);
    + 194            }))
    + 195        ]);
    + 196    }
    + 197}
    + 198
    + 199export interface ColoredCfg extends VisibleCfg {
    + 200    /** the color in hex */
    + 201    color: string;
    + 202}
    + 203export interface LineStyle extends ColoredCfg {
    + 204    /** the stroke width in px */
    + 205    width: number; 
    + 206}
    + 207
    + 208export interface MarkerStyle extends ColoredCfg {
    + 209    /** the stroke width in px */
    + 210    size:  number;      
    + 211
    + 212    /** the marker shape, selected from {@link Series.Series.marker Series.marker} */
    + 213    shape: Symbol;              
    + 214}
    + 215
    + 216export interface FillStyle extends ColoredCfg {
    + 217}
    + 218
    + 219export interface TextStyle extends ColoredCfg {
    + 220}
    + 221
    + 222export interface BarStyle extends ColoredCfg {
    + 223    /** width of bars in % of space between bars */
    + 224    width: number;  
    + 225    
    + 226    /** offset between column series in % between bars */
    + 227    offset:number; 
    + 228}
    + 229
    + 230export interface SeriesStyle {
    + 231    line:   LineStyle;
    + 232    marker: MarkerStyle;
    + 233    fill:   FillStyle;
    + 234    bar:    BarStyle;
    + 235    label:  TextStyle;
    + 236}
    + 237
    + 238/** 
    + 239 * Defines Series columns and values to use, as well as the plot type to apply.
    + 240 * The following settings are available for configuration:
    + 241 * ```
    + 242 * cfg.series.series = [{
    + 243 *    type: TYPE,        // the series type, e.g. 'line', etc. See below.
    + 244 *    dataIndex: number, // the `Data` set to use. The index refers to the position in `series.data`
    + 245 *    x: string,         // the column name or index of the x-coordinate to use for drawing
    + 246 *    y: string,         // the column name or index of the y-coordinate to use for drawing
    + 247 *    yBase: string,     // if specified, used as lower series for filling the area
    + 248 *    l: string,         // the column name or index to use for series labels
    + 249 *    hOffset: number;   // horizontal label offset in em o
    + 250 *    vOffset?: number;  // vertical label offset in em
    + 251 *    map?: 'stacked' | 'shared'; // stack series, or show the share (normalize to 100%)
    + 252 *    style: {@link SeriesStyle SeriesStyle},  // allows overriding a default style setting
    + 253 *    cond: {@link hsData:DataFilters.Condition Condition} // allows specifying a filter applied to data before rendering.
    + 254 * }]
    + 255 * ```
    + 256 * The following series s are available. For configuration details, see:
    + 257 * - 'line':  (or omitted): {@link PlotLine PlotLine}
    + 258 * - 'markers': {@link PlotMarkers PlotMarkers}
    + 259 * - 'area':    {@link PlotArea PlotArea}
    + 260 * - 'bar':     {@link PlotBar PlotBar}
    + 261 */

    + 262export interface SeriesDef {
    + 263    /** 
    + 264     * required column names or indices. 
    + 265     * [0] is reserved for the x direction. 
    + 266     * Further elements are dependent on the {@link Series.type plot} type. 
    + 267     */

    + 268    x:string;               // x values
    + 269    y?:string;              // y values
    + 270    yBase?:string;          // if specified, treats (y/yBase) as (high/low) series
    + 271    ySum?:string;           // internal support column for 'shared' mode;
    + 272    l?:string;              // labels
    + 273    hOffset?: number;       // offset in em
    + 274    vOffset?: number;       // offset in em
    + 275    map?: string;           // accepts 'stacked'and 'shared'
    + 276    /** An index into the `Data[]` pool, identifying the `Data` set to use. defaults to `0` */
    + 277    dataIndex?: number;
    + 278    /** optional plot type, selected from {@link Series.Series.plot Series.plot} as string; defaults to  'line' */
    + 279    type?:string;   
    + 280    /** style information to use for plotting; if ommitted, a `type`-dependent default is used */
    + 281    style?:SeriesStyle;
    + 282    /** optinal filter condition on the data prior to drawing */
    + 283    cond?: Condition;
    + 284}
    + 285
    + 286
    + 287/** 
    + 288 * Defines the default settings. 
    + 289 * Implemented as a class rather than interface to allow for a getter/setter implementation
    + 290 * of `series`. This allows for postprocessing user configurations while maintaining 
    + 291 * convenient notation, e.g.
    + 292 * ```
    + 293 *  cfg.series.series = [           // invoke the setter
    + 294 *      { x:'time', y:'volume'},    // behind the scenes, adds 
    + 295 *      { x:'time', y:'price']}     // missing fields such as .style
    + 296 *  ];
    + 297 *  fg.series.series[0].style.marker.visible = true;    // invoke the getter
    + 298 * ```
    + 299 */

    + 300export class SeriesConfig {
    + 301    private seriesDefs:SeriesDef[] = [];
    + 302
    + 303    /** 
    + 304     * the `DataSet`s to be used for plots.
    + 305     * Each set describes the column names and the rows-of-columns data.
    + 306     * The `SeriesDef.dataIndex` determines which set to use.
    + 307     */

    + 308    public data: DataSet[]; 
    + 309
    + 310    /** determines if seires plot will be clipped to the chart area */
    + 311    public clip = true;   
    + 312
    + 313    /** 
    + 314     * determines the default style applied to each series.
    + 315     * Colors will be chosen by series index from `defaultColors`.
    + 316     */

    + 317    public defaultStyle:SeriesStyle = {
    + 318        line:   { color:'default', visible: true, width: 2},
    + 319        marker: { color:'default', visible: false, size: 10, shape: Series.marker.circle},
    + 320        label:  { color:'default', visible: false },
    + 321        fill:   { color:'default', visible: false },
    + 322        bar:    { color:'default', visible: false, width: 50, offset: 30 }
    + 323    };       
    + 324           
    + 325    /** determines the default color for the first couple of series */
    + 326    public defaultColors = ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f', '#000', '#444', '#888', '#ccc'];
    + 327
    + 328    /** 
    + 329     * `series` accessor method: array of series definitions to define plots. 
    + 330     * 
    + 331     */

    + 332    public set series(cfg: SeriesDef[]) {    // array of series descriptions
    + 333        const defStyle = this.defaultStyle;
    + 334        const defColors = this.defaultColors;
    + 335        cfg.forEach((s:SeriesDef) => {
    + 336            s.type = s.type || 'line';
    + 337            s.style = s.style || {};
    + 338            s.dataIndex = s.dataIndex || 0;
    + 339            const defaults = {
    + 340                color:defColors[this.seriesDefs.length]
    + 341            };
    + 342            copyDefault(s.style, defStyle, defaults);
    + 343            this.seriesDefs.push(s);
    + 344            switch (s.type) {
    + 345                case 'line': 
    + 346                    s.style.line.visible = true; 
    + 347                    break;
    + 348                case 'marker': 
    + 349                    s.style.marker.visible = true; 
    + 350                    break;
    + 351                case 'area': 
    + 352                    s.style.fill.visible = true; 
    + 353                    break;
    + 354                case 'bar': 
    + 355                    s.style.fill.visible = true; 
    + 356                    break;
    + 357            }
    + 358        });
    + 359    }
    + 360    public get series():SeriesDef[] { return this.seriesDefs; }
    + 361}
    + 362
    + 363
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/SeriesLine.html b/docs/src/hsGraph/SeriesLine.html new file mode 100644 index 0000000..418536e --- /dev/null +++ b/docs/src/hsGraph/SeriesLine.html @@ -0,0 +1,18 @@ + + +

    SeriesLine.ts

    +
       1
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/example/start.html b/docs/src/hsGraph/example/start.html new file mode 100644 index 0000000..b2bc19b --- /dev/null +++ b/docs/src/hsGraph/example/start.html @@ -0,0 +1,19 @@ + + +

    example/start.ts

    +
       1import { Graph } from '../';
    +   2if (Graph) {}
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/hsGraph.html b/docs/src/hsGraph/hsGraph.html new file mode 100644 index 0000000..68354ae --- /dev/null +++ b/docs/src/hsGraph/hsGraph.html @@ -0,0 +1,182 @@ + + +

    HsGraph.ts

    +
       1/**
    +   2 * # HsGraph
    +   3 * 
    +   4 * 
    +   5 * let series = [
    +   6 *      ['time', 'volume'],
    +   7 *      [-1, 0.2],
    +   8 *      [0.2, 0.7],
    +   9 *      [0.4, -0.2],
    +  10 *      [0.6, 0],
    +  11 *      [0.8, 0.5],
    +  12 *      [1, 0.7]
    +  13 * ];
    +  14 * 
    +  15 * const cfg = {
    +  16 *      series: { 
    +  17 *          data: series, 
    +  18 *          series: [{ xHeader: 'time', yHeader:'volume'}],
    +  19 *          chart: { title: { text: 'Volume over Time' }}
    +  20 *      },
    +  21 *      axes: { primary: { x: { title:'time' }, y: { title:'volume' }}}
    +  22 * }
    +  23 * m.mount(root, { 
    +  24 *      view:() => m(hsgraph.Graph, {cfg: cfg})
    +  25 * });
    +  26 *
    +  27 * 
    +  28 * 
    +  29 * .hs-graph-chart { fill: #fff; }
    +  30 * .hs-graph-series { stroke-width: 5;
    +  31 * 
    +  32 * 

    +  33
    +  34 */

    +  35
    +  36/** */
    +  37import { m, Vnode}           from 'hslayout';
    +  38import { Axes, AxisSet }     from './Axes';
    +  39import { Scale, ScaleSet }   from './Scale';
    +  40import { Canvas, CanvasSet } from './Canvas';
    +  41import { Series, SeriesSet } from './Series';
    +  42import { Chart, ChartSet }   from './Chart';
    +  43import { Grid, GridSet }     from './Grid';
    +  44import { Legend }            from './Legend';
    +  45import { SVGElem }           from './SVGElem';
    +  46
    +  47const viewBoxWidth:number  = 1000;  // the viewBox size
    +  48let   viewBoxHeight:number = 700;   // the viewBox size
    +  49const marginLeft:number    = 50;
    +  50const marginRight:number   = 10;
    +  51const marginTop:number     = 60;
    +  52const marginBottom:number  = 80;
    +  53
    +  54export interface Point {
    +  55    x: number|string;
    +  56    y: number|string;
    +  57}
    +  58export interface Area {
    +  59    w: number|string;
    +  60    h: number|string;
    +  61}
    +  62export interface Config {
    +  63    viewBox:  { w: number; h: number; };
    +  64    plotArea: { t: number; l: number; w: number; h: number; };
    +  65    scale?:  ScaleSet;
    +  66    canvas?: CanvasSet;
    +  67    axes?:   AxisSet;
    +  68    chart?:  ChartSet;
    +  69    grid?:   GridSet;
    +  70    series?: SeriesSet;
    +  71    legend?:{
    +  72
    +  73    };
    +  74}
    +  75/**
    +  76 * Creates a deep copy of `def`, taking fields present in `update` to supercede the default value.
    +  77 * @param def contains the default setting for each parameter
    +  78 * @param update contains updates to some or all of the settings
    +  79 */

    +  80function copy(def:any, update:any):any {
    +  81    let result:any = {};
    +  82    Object.keys(def).map((k:string) => {
    +  83        if (typeof def[k] === 'object' && !Array.isArray(def[k]) && def[k]!==null) {
    +  84            result[k] = copy(def[k], update[k] || {});
    +  85        } else {
    +  86            result[k] = update[k] || def[k];
    +  87        }
    +  88    });
    +  89    return result;
    +  90}
    +  91
    +  92export class HsGraph extends SVGElem {
    +  93    static defConfig:Config = {
    +  94        viewBox:  { w: viewBoxWidth, h: viewBoxHeight },
    +  95        plotArea: { t: marginTop, l: marginLeft, 
    +  96                    w: viewBoxWidth - marginRight - marginLeft,
    +  97                    h: viewBoxHeight - marginTop - marginBottom
    +  98                  }
    +  99    };
    + 100
    + 101    static config(config=HsGraph.defConfig) {
    + 102        Canvas.config(config);
    + 103        Scale.config(config);
    + 104        Axes.config(config);
    + 105        Series.config(config);
    + 106        Grid.config(config);
    + 107        Chart.config(config);
    + 108        Legend.config(config);
    + 109        return config;
    + 110    }
    + 111    
    + 112    private scales = { 
    + 113        primary:  <{x:Scale, y:Scale}> { },
    + 114        secondary:<{x:Scale, y:Scale}> { }
    + 115    };
    + 116
    + 117    private createScales(cfg:any) {
    + 118        const cg = cfg.graph;
    + 119        const cs = cfg.scale;
    + 120        if (!this.scales.primary.x) { 
    + 121            this.scales.primary.x   = new Scale(cs.primary.x);
    + 122            this.scales.primary.y   = new Scale(cs.primary.y);
    + 123            this.scales.secondary.x = new Scale(cs.secondary.x);
    + 124            this.scales.secondary.y = new Scale(cs.secondary.y);
    + 125        }
    + 126        this.scales.primary.x.range   = [cg.left, cg.right];
    + 127        this.scales.primary.y.range   = [cg.bottom, cg.top];
    + 128        this.scales.secondary.x.range = [cg.left, cg.right];
    + 129        this.scales.secondary.y.range = [cg.bottom, cg.top];
    + 130    }
    + 131
    + 132    adjustHeight(node?: Vnode) {
    + 133        if (node.dom && node.dom.parentElement) {
    + 134            const p = node.dom.parentElement;
    + 135            const temp = viewBoxWidth * p.clientHeight / p.clientWidth;
    + 136            if (!isNaN(temp) && temp !== viewBoxHeight) {
    + 137                viewBoxHeight = temp; 
    + 138                console.log('new height = ' + temp);
    + 139            }
    + 140        }
    + 141    }
    + 142
    + 143    onupdate(node?: Vnode) { this.adjustHeight(node); }
    + 144    oncreate(node?: Vnode) {
    + 145        this.adjustHeight(node);
    + 146        window.addEventListener("resize", function() { m.redraw(); });
    + 147    }
    + 148
    + 149    view(node?: Vnode): Vnode {
    + 150        const cp = copy(HsGraph.config(), node.attrs.cfg || {});
    + 151        const cg = cp.graph;
    + 152        this.createScales(cp);
    + 153        return m('svg', { class:'hs-graph', width:'100%', height:'100%', viewBox:`0 0 ${cg.range.w} ${cg.range.h}`, preserveAspectRatio:'xMaxYMin'}, [
    + 154            m(Canvas, { cfg:cp.canvas}),
    + 155            m(Chart, { cfg:cp.chart, x:cg.left, y:cg.top, 
    + 156                       width: cg.right-cg.left, height:cg.bottom-cg.top }),
    + 157            m(Axes, { cfg:cp.axes, scales:this.scales }),
    + 158            m(Grid, { cfg:cp.grid, scales:this.scales }),
    + 159            m(Series, { cfg:cp.series, scales:this.scales }),
    + 160            m(Legend, { cfg:cp.legend })
    + 161        ]);
    + 162    }
    + 163}
    + 164
    + 165
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/index.html b/docs/src/hsGraph/index.html new file mode 100644 index 0000000..b05fa4f --- /dev/null +++ b/docs/src/hsGraph/index.html @@ -0,0 +1,26 @@ + + +

    index.ts

    +
       1export { Graph }    from './Graph';
    +   2export { Series,
    +   3         SeriesDef
    +   4         }          from './Series';
    +   5export { Axes }     from './Axes';
    +   6export { Scale }    from './Scale';
    +   7export { Grid }     from './Grid';
    +   8export { Legend }   from './Legend';
    +   9
    + + \ No newline at end of file diff --git a/docs/src/hsGraph/overview.html b/docs/src/hsGraph/overview.html new file mode 100644 index 0000000..d399b4d --- /dev/null +++ b/docs/src/hsGraph/overview.html @@ -0,0 +1,94 @@ + + +

    overview.ts

    +
       1/**
    +   2# hsGraph
    +   3hsGraph is a simnple graphing utility written in JavaScript and based on the [Mithril](https://mithril.js.org) framework.
    +   4It supports various chart types and scales and provides a convenient programmatic configuration mechanism. 
    +   5
    +   6## Usage
    +   7In mithril, simply render or mount a {@link Graph Graph} Component object and provide a `cfg`
    +   8attribute with the graph's configuration.
    +   9
    +  10### Simple Example
    +  11 * 
    +  12 * 
    +  13 * let data = {
    +  14 *    colNames:['time', 'volume'],
    +  15 *    rows:[
    +  16 *      [-1, 0.2],
    +  17 *      [0.2, 0.7],
    +  18 *      [0.4, -0.2],
    +  19 *      [0.6, 0],
    +  20 *      [0.8, 0.5],
    +  21 *      [1, 0.7]
    +  22 * ]};
    +  23 * 
    +  24 * m.mount(root, { 
    +  25 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    +  26 *          cfg.chart.title.text          = 'Simple Example';
    +  27 *          cfg.series.data   = [data];
    +  28 *          cfg.series.series = [{ x:'time', y:'volume' }];
    +  29 *      }})
    +  30 * });
    +  31 *
    +  32 * 
    +  33 * 
    +  34 * .hs-graph-chart { fill: #fff; }
    +  35 * .hs-graph-series { stroke-width: 5; }
    +  36 * 
    +  37 * 

    +  38
    +  39 ## Setting the data to render
    +  40 Data is provided in a rows-of-columns style array: `data[row][column]`.
    +  41 The first row in the data array contains column names by which the series can be identified.
    +  42 There is no conceptual limit to the number of rows or columns provided to `hsGraph`.
    +  43 In the configuration, 
    +  44 - set the array containing the data: `series.data = data;`  
    +  45 - and specify the x- and y-columns to render, by name: `series.series = [{xHeader:, yHeader:}]`
    +  46
    +  47## Configuration
    +  48All graph components are highly configurable. `hsGraph` uses default values for all configurable fields 
    +  49that can easily be changed, either programmatically or via a custom stylesheet.
    +  50
    +  51To programmatically set rendering parameters, simply provide a configuration function `cfg => {}` 
    +  52to the `cfgFn` attribute when setting up the mithril mount call - see example above. 
    +  53The `cfgFn` receives a configuration object that is fully initialized with default values, 
    +  54and should overwrite parameters as needed. See the overview for each component for configurable 
    +  55parameters.
    +  56
    +  57Available configurations include:
    +  58-   {@link Graph.Graph.defaultConfig Graph.defaultConfig }
    +  59-   {@link Canvas.Canvas.defaultConfig Canvas.defaultConfig}
    +  60-   {@link Chart.Chart.defaultConfig Chart.defaultConfig}
    +  61-   {@link Axes.Axes.defaultConfig Axes.defaultConfig}
    +  62-   {@link Grid.Grid.defaultConfig Grid.defaultConfig}
    +  63-   {@link Series.Series.defaultConfig Series.defaultConfig}
    +  64-   {@link Legend.Legend.defaultConfig Legend.defaultConfig}
    +  65
    +  66## Graph Components
    +  67The rendered graph is organized in a layered structure of components:
    +  68-   {@link Canvas Canvas}:  the background canvas on which all components are rendered
    +  69-   {@link Chart Chart}: the chart area and title
    +  70-   {@link Axes Axes}: the x- and y-axes, tick marks and labels, and axis title
    +  71-   {@link Grid Grid}: the major and minor gridlines
    +  72-   {@link Series Series}: the one or more data series to render
    +  73-   {@link Legend Legend}: the legend for the shown series
    +  74
    +  75*/

    +  76
    +  77/** */
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/example/columns.x.html b/docs/src/hsLayout/example/columns.x.html new file mode 100644 index 0000000..d99ca2e --- /dev/null +++ b/docs/src/hsLayout/example/columns.x.html @@ -0,0 +1,88 @@ + + +

    example/columns.x.ts

    +
       1import { m, Vnode }             from '../mithril';
    +   2import { Container, HsConfig }  from '../';
    +   3
    +   4
    +   5const myConfig = {
    +   6    Rows: {
    +   7        columns:  [''],
    +   8        maxCount: 5,
    +   9        leafCSS: 'leaf',
    +  10        content: [
    +  11            { Rows: {
    +  12                rows: [''],
    +  13                content: [
    +  14                    { aLeaf: { css:'leaf', columns: ['']}},
    +  15                    { aLeaf: { css:'leaf', columns: ['100px'] }},
    +  16                    { aLeaf: { css:'leaf', columns: ['100px', '200px'] }},
    +  17                    { aLeaf: { css:'leaf', columns: ['20%'] }},
    +  18                    { aLeaf: { css:'leaf', columns: ['20%', 'fill'] }}
    +  19                ]
    +  20            }},
    +  21            { Rows: {
    +  22                columns: [''],
    +  23                content: [
    +  24                    { aLeaf: { css:'leaf', rows: ['']}},
    +  25                    { aLeaf: { css:'leaf', rows: ['100px'] }},
    +  26                    { aLeaf: { css:'leaf', rows: ['100px', '200px'] }},
    +  27                    { aLeaf: { css:'leaf', rows: ['20%'] }},
    +  28                    { aLeaf: { css:'leaf', rows: ['20%', 'fill'] }}
    +  29                ]
    +  30            }}
    +  31        ]
    +  32    }
    +  33};
    +  34
    +  35function next(fn:any) {
    +  36    return setTimeout(() => {
    +  37        fn();
    +  38        next(fn);
    +  39    }, 2000);
    +  40}
    +  41
    +  42const example = { 
    +  43    Rows: class extends Container {
    +  44        getComponents(node: Vnode): Vnode {
    +  45            node.attrs.content.forEach((c:any) => c.attrs.maxCount = node.attrs.maxCount);
    +  46            return super.getComponents(node);
    +  47        }
    +  48    },
    +  49    aLeaf: class extends Container {
    +  50        count = 1;
    +  51        maxCount = 0;
    +  52
    +  53        constructor() {
    +  54            super();
    +  55            next(() => {
    +  56                this.count = (this.count >= this.maxCount)? 0 : this.count+1;
    +  57                m.redraw();
    +  58            });
    +  59        }
    +  60
    +  61        getComponents(node: Vnode): Vnode {
    +  62            this.maxCount = this.maxCount = node.attrs.maxCount || 3;
    +  63            const dims = node.attrs.columns || node.attrs.rows;
    +  64            const content = [...Array(this.count).keys()].map((c:number) => `${node.attrs.columns?'Columns':'Rows'}
    ${c+1}
    [${dims.join()}]`);
    +  65            return content;
    +  66        }
    +  67    }
    +  68};
    +  69
    +  70export const cfg = new HsConfig([example]).attachNodeTree(myConfig, document.body);
    +  71
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/example/config.x.html b/docs/src/hsLayout/example/config.x.html new file mode 100644 index 0000000..f1430de --- /dev/null +++ b/docs/src/hsLayout/example/config.x.html @@ -0,0 +1,82 @@ + + +

    example/config.x.ts

    +
       1import { m, Vnode}  from '../mithril';
    +   2import * as hslayout from '../';
    +   3//import * as widgets from '../../hsWidgets/src/';
    +   4
    +   5const myConfig = {
    +   6    Layout: {
    +   7        rows:  ["30px", "fill", "10px"],
    +   8        css: '.my-example',
    +   9        content: [{
    +  10            Layout:{
    +  11                columns: ["200px", "fill"],
    +  12                content: [
    +  13                    { LeftHead:    { lib:"route.lib", field:"route.field"}},
    +  14                    { MainHead:    { lib:"route.lib", field:"route.field"}}
    +  15                ]
    +  16            }},{
    +  17            Layout:{
    +  18                columns: ["200px", "fill"], 
    +  19                content: [
    +  20                    { LeftNav:    { lib:"route.lib", field:"route.field"}},
    +  21                    { MainNav:    { lib:"route.lib", field:"route.field"}}
    +  22                ]
    +  23            }},
    +  24            { Layout: {
    +  25                css: '.hs-site-footer',
    +  26                content: ['(c) Helpful ; Scripts']
    +  27            }}
    +  28        ] 
    +  29    },
    +  30    route: {
    +  31        default: '/api',
    +  32        paths: [
    +  33            '/api',             // defines `http://localhost/#!/api/
    +  34            '/api/:lib',        // defines `http://localhost/#!/api/:hsLib
    +  35            '/api/:lib/:field'  // defines `http://localhost/#!/api/:hsLib/:id        
    +  36        ]
    +  37    }
    +  38}; 
    +  39
    +  40const example = {
    +  41    LeftHead: class extends hslayout.Layout{ 
    +  42        getComponents(node:Vnode) { 
    +  43            return 'The Left Head'; 
    +  44        } 
    +  45    },
    +  46    MainHead: class extends hslayout.Layout{ 
    +  47        getComponents(node:Vnode) { return m('', 'The Main Head'); } 
    +  48    },
    +  49    LeftNav: class extends hslayout.Layout{ 
    +  50        getComponents(node:Vnode) { return m('', 'The Left Nav'); } 
    +  51    },
    +  52    MainNav: class extends hslayout.Layout{ 
    +  53        getComponents(node:Vnode) { return m('', 'The Main Nav'); } 
    +  54    },
    +  55    Footer: class extends hslayout.Layout{ 
    +  56        getComponents(node:Vnode) { return m('.hs-site-footer', '(c) Helpful ; Scripts'); } 
    +  57    }
    +  58};
    +  59
    +  60
    +  61
    +  62new hslayout.HsConfig([hslayout, example])
    +  63    .attachNodeTree(myConfig, document.getElementById('exampleBase'));
    +  64
    +  65
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/example/layout.x.html b/docs/src/hsLayout/example/layout.x.html new file mode 100644 index 0000000..17c2ee0 --- /dev/null +++ b/docs/src/hsLayout/example/layout.x.html @@ -0,0 +1,138 @@ + + +

    example/layout.x.ts

    +
       1/**
    +   2 * # Layout Examples
    +   3 * See example page
    +   4 * 
    +   5 */

    +   6
    +   7 /** */
    +   8import { m, Vnode }             from '../mithril';
    +   9import { Layout, HsConfig }  from '../';
    +  10
    +  11
    +  12const myConfig = {
    +  13    Layout: {
    +  14        rows: ['40px', 'fill'],         // header and main body
    +  15        content: [
    +  16            { Header: { css:'.header', title: 'Layout Example'}},
    +  17            { Main: {
    +  18                tiles:  [''],           // main body wiull arrange in tiles
    +  19                maxCount: 6,
    +  20                leafCSS: 'leaf',
    +  21                content: [
    +  22                    { Layout: {
    +  23                        rows: [''],     // 1st tile: rows of varying columns
    +  24                        content: [
    +  25                            { aLeaf: { css:'leaf', columns: [' ']}},
    +  26                            { aLeaf: { css:'leaf', columns: ['100px'] }},
    +  27                            { aLeaf: { css:'leaf', columns: ['100px', '200px'] }},
    +  28                            { aLeaf: { css:'leaf', columns: ['100px', 'fill'] }},
    +  29                            { aLeaf: { css:'leaf', columns: ['100px', 'fill', '100px'] }},
    +  30                            { aLeaf: { css:'leaf', columns: ['20%'] }},
    +  31                            { aLeaf: { css:'leaf', columns: ['20%', 'fill'] }},
    +  32                            { aLeaf: { css:'leaf', columns: ['20%', 'fill', '20%'] }}
    +  33                        ]
    +  34                    }},
    +  35                    { Layout: {
    +  36                        columns: [''],  // 2nd tile: columns of varying rows
    +  37                        content: [
    +  38                            { aLeaf: { css:'leaf', rows: [' ']}},
    +  39                            { aLeaf: { css:'leaf', rows: ['100px'] }},
    +  40                            { aLeaf: { css:'leaf', rows: ['100px', '200px'] }},
    +  41                            { aLeaf: { css:'leaf', rows: ['100px', 'fill'] }},
    +  42                            { aLeaf: { css:'leaf', rows: ['100px', 'fill', '100px'] }},
    +  43                            { aLeaf: { css:'leaf', rows: ['20%'] }},
    +  44                            { aLeaf: { css:'leaf', rows: ['20%', 'fill'] }},
    +  45                            { aLeaf: { css:'leaf', rows: ['20%', 'fill', '20%'] }}
    +  46                        ]
    +  47                    }},
    +  48                    { Layout: {
    +  49                        tiles: [''],    // 3rd tile: varying tiles
    +  50                        css: 'tile_pct',
    +  51                        content: [
    +  52                            { aLeaf: { css:'leaf', tiles: [' ']}},
    +  53                            { aLeaf: { css:'leaf', tiles: ['40%', 'fill']}},
    +  54                            { aLeaf: { css:'leaf', tiles: ['40%']}},
    +  55                            { aLeaf: { css:'leaf', tiles: ['40%', '30%', 'fill']}},
    +  56                        ]
    +  57                    }},
    +  58                    { Layout: {
    +  59                        tiles: [''],    // 3rd tile: varying tiles
    +  60                        css: 'tile_px',
    +  61                        content: [
    +  62                            { aLeaf: { css:'leaf', tiles: [' ']}},
    +  63                            { aLeaf: { css:'leaf', tiles: [' ', 'fill']}},
    +  64                            { aLeaf: { css:'leaf', tiles: [' ']}},
    +  65                            { aLeaf: { css:'leaf', tiles: [' ']}},
    +  66                        ]
    +  67                    }}
    +  68                ]
    +  69            }}
    +  70        ]
    +  71    }
    +  72};
    +  73
    +  74function next(fn:any) {
    +  75    return setTimeout(() => {
    +  76        fn();
    +  77        next(fn);
    +  78    }, 2000);
    +  79}
    +  80
    +  81const example = { 
    +  82    maxCount: 0,
    +  83    Header: class extends Layout {
    +  84        getComponents(node: Vnode): Vnode {
    +  85            return m(node.attrs.css, node.attrs.title);
    +  86        }
    +  87    },
    +  88    Main: class extends Layout {
    +  89        getComponents(node: Vnode): Vnode {
    +  90            example.maxCount = node.attrs.maxCount || 3;
    +  91            return super.getComponents(node);
    +  92        }
    +  93    },
    +  94    aLeaf: class extends Layout {
    +  95        count = 1;
    +  96        inc = 1;
    +  97
    +  98        constructor() {
    +  99            super();
    + 100            next(() => {
    + 101                this.count += this.inc;
    + 102                if (this.count >= example.maxCount) { this.inc = -1; }
    + 103                if (this.count <= 1)             { this.inc = +1; }
    + 104                m.redraw();
    + 105            });
    + 106        }
    + 107
    + 108        getComponents(node: Vnode): Vnode {
    + 109            const dims = node.attrs.columns || node.attrs.rows || node.attrs.tiles;
    + 110            let text = '';
    + 111            if (node.attrs.columns) { text = 'Columns'; }
    + 112            if (node.attrs.rows) { text = 'Rows'; }
    + 113            if (node.attrs.tiles) { text = 'Tiles'; }
    + 114            const content = [...Array(this.count).keys()].map((c:number) => `${text}
    ${c+1}
    [${dims.join()}]`);
    + 115            return content;
    + 116        }
    + 117    }
    + 118};
    + 119
    + 120export const cfg = new HsConfig([example]).attachNodeTree(myConfig, document.body);
    + 121
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/example/start.html b/docs/src/hsLayout/example/start.html new file mode 100644 index 0000000..a3c2d14 --- /dev/null +++ b/docs/src/hsLayout/example/start.html @@ -0,0 +1,19 @@ + + +

    example/start.ts

    +
       1import { cfg } from './layout.x';
    +   2if (cfg) {}
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/hsConfig.html b/docs/src/hsLayout/hsConfig.html new file mode 100644 index 0000000..0f81528 --- /dev/null +++ b/docs/src/hsLayout/hsConfig.html @@ -0,0 +1,274 @@ + + +

    hsConfig.ts

    +
       1/**
    +   2 * ##HsConfig 
    +   3 * Tool to configure a layout via a configuration object that is either defined
    +   4 * as an object literal or as a JSON file.
    +   5 * 
    +   6 * The structure of the configuration object follows the convention
    +   7 
    +   8 {
    +   9     
    +  10     [,route: {
    +  11        default: '/api',
    +  12        paths: [
    +  13            '/api',             
    +  14            '/api/:lib',       
    +  15            '/api/:lib/:field' 
    +  16        ]
    +  17    }]
    +  18 }
    +  19 

    +  20`` is either {@link hsLayout:Layout.Layout Layout} or a subclass thereof.
    +  21`` is an object literal `{ :[, ...] }`
    +  22
    +  23Arrays and Object Literals in `` define a layout tree that will be traversed,
    +  24After which the tree will be instantiated by calling `m()`.
    +  25Mithril will then recursively create the Classes in the tree and call their `view` methods,
    +  26where `Configuration`settings will be available via the `node.attrs` parameter.
    +  27
    +  28The default `Layout` implementation recognizes the following special `` keys:
    +  29
    +  30* - `content`: the subcomponents to render in `Layout`, allowing for following `` types:
    +  31*     - `[{}, ...]`
    +  32*     - `['string literal', ...]`
    +  33*     - `'string literal'`
    +  34* - `css`: the CSS class to set on `Layout`
    +  35* - `href`: a href attribute to set on `Layout`. This makes `Layout` clickable and sends the 
    +  36     respective attribute value to the Mithril router.
    +  37* - `onclick`: a function to call when `Layout` is clicked.
    +  38*/

    +  39
    +  40/** */
    +  41import { m, Vnode } from './mithril'; 
    +  42import * as layout from './';
    +  43
    +  44/**
    +  45 * creates a deep copy of the struct passed in.
    +  46 * @param struct the object to copy
    +  47 */

    +  48function copy(struct:any): any {
    +  49    let result:any;
    +  50    if (Array.isArray(struct)) { result = []; }
    +  51    else if (typeof struct === 'object') { result = {}; }
    +  52    else { return struct; }
    +  53    Object.keys(struct).map((k:string) => result[k] = copy(struct[k]));
    +  54    return result;
    +  55}
    +  56
    +  57
    +  58/**
    +  59 * resolves the symbol `sym` against the provided `context`.
    +  60 * If successful, returns the class definition for `sym`. 
    +  61 * @param sym the symbol to resolve
    +  62 * @param context the context to resolve against; `mithril` and `hsLayout` 
    +  63 * are implicitely part of the context and need not be specified.
    +  64 * @return the resolved Class, or `undefined`.
    +  65 */

    +  66function resolve(sym:string, context:any[]) {
    +  67    let cl:any;
    +  68    context.concat(layout).some((c:any) =>  cl = c[sym]);
    +  69    return cl;
    +  70}
    +  71
    +  72/**
    +  73 * recurses a configuration, trying to fetch the class definition for each element (key) in `config`. 
    +  74 * If successful, it creates an object literal containing the component class and its attributes.
    +  75 * If unsuccessful, the element's value is returned unaltered so that it can be consumed 
    +  76 * by an instance further up in the recursion tree.
    +  77 * @param config an object literal containing a configuration subtree
    +  78 * @param context an array of objects against which to instantiate elements of `config`.
    +  79 * @return an object literal representing the configuration, with Class names resolved 
    +  80 * against the provided `context`.
    +  81 */

    +  82function recurse(config:any, context:any[]) {
    +  83    if (['string', 'number', 'boolean', 'function'].indexOf(typeof config)>=0) { return config; }
    +  84    const keys = Object.keys(config);
    +  85    let result = config.length? [] : {};
    +  86    keys.map((k:string):Vnode => {
    +  87        const content = recurse(config[k], context); 
    +  88        const cl:any = resolve(k, context);
    +  89        if (cl) { 
    +  90            const r = {
    +  91                compClass:cl,   // Component class
    +  92                attrs:content   // attributes passed to the Component class
    +  93            };
    +  94            (!Array.isArray(config) && keys.length === 1)? 
    +  95                result = r : 
    +  96                result[k] = r;   
    +  97        }
    +  98        else { result[k] = content; }
    +  99    }); 
    + 100    return result; 
    + 101}
    + 102
    + 103
    + 104/**
    + 105 * Interprets a configuration and either mounts it or routs it in `mithril`. 
    + 106 * Example: 
    + 107
    + 108import * as mylib from './mylib';
    + 109
    + 110const myConfig = { 
    + 111    Layout: {
    + 112        rows:  ['50px', 'fill'],
    + 113        css: '.hs-site',
    + 114        content: [{MyClass: {}}, 'bottom row']
    + 115    },
    + 116    route: {
    + 117        default: '/api',
    + 118        paths: [
    + 119            '/api',             // defines `http://localhost/#!/api/
    + 120            '/api/:lib',        // defines `http://localhost/#!/api/foo
    + 121            '/api/:lib/:field'  // defines `http://localhost/#!/api/foo/bar        
    + 122        ]
    + 123    }
    + 124}
    + 125
    + 126const myExample = {
    + 127    MyClass: class extends Layout {
    + 128        view(node:Vnode) { return m('', 'myExample'); }
    + 129    }
    + 130}
    + 131
    + 132new HsConfig([mylib, myExample]).attachNodeTree(myConfig, document.body)
    + 133

    + 134 */

    + 135export class HsConfig {
    + 136    /**
    + 137     * Constructs an HsConfig object on a `context`. Any class names encountered
    + 138     * in the configuration tree when calling `attachNodeTree` will be resolved
    + 139     * against this context. The `mithril`and `hsLayout` namespaces are automatically 
    + 140     * added to the context.
    + 141     * @param context Array of namespaces againt which classes will be resolved.  
    + 142     */

    + 143    constructor(protected context:any[]) {}
    + 144
    + 145    /**
    + 146     * Interprets a configuration object and attaches it to a DOM element
    + 147     * @param config an object literal, or name of a JSON file, containing a configration tree
    + 148     * @param root a DOM element to which to attach the tree
    + 149     */

    + 150    attachNodeTree(config:any, root:any) {
    + 151        /**
    + 152         * decodes the parts of a `route` declaration in the `config` tree
    + 153         * that will be passed to the `mithril` `m.route()` command.
    + 154         * 
    + 155         * `route` defines a `default` path, as well as an array `paths` of 
    + 156         * path templates containing variables of the form `:varName`.
    + 157         * 
    + 158         * All `paths`resolve to the same root element defined in the config tree.
    + 159         * @param route an object literal structured as 
    + 160         * 

    + 161         * {
    + 162         *     default: '...'   // the default path
    + 163         *     paths: [
    + 164         *         '/:var1[/:var2...]'  // path template, 
    + 165         *         ...
    + 166         *     ]
    + 167         * }
    + 168         * 

    + 169         */

    + 170        function decodeRoute(route:any) {
    + 171            const rp:string[] = route.params = [];
    + 172            route.paths.map((p0:string) => {
    + 173                const params = p0.match(/:(.+?)\b/g);
    + 174                if (params) { 
    + 175                    params.map((p1:string) => p1.substr(1))
    + 176                            .map((p2:any) => rp.indexOf(p2)<0? rp.push(p2):''); 
    + 177                }
    + 178            });
    + 179            return route;
    + 180        }
    + 181        /**
    + 182         * Handles top-level interpretations of a config tree and returns 
    + 183         * a normalized object with the following rules:
    + 184         * - a `route` entry, if present, will have a resolved class constructors for each string class designator
    + 185         * - a `root` entry is the first encountered top-level Vnode in `config`
    + 186         * - all other top-level entries in `config` wikll be copied to returned object
    + 187         */

    + 188        function decode(config:any) {
    + 189            let result:any = { };
    + 190            if (config.compClass && !result.root) {   // only capture the first one
    + 191                result.root = config; 
    + 192            } else {
    + 193                Object.keys(config).map((k:any) => {
    + 194                    if (config[k].compClass && !result.root) {   // only capture the first one
    + 195                        result.root = config[k]; 
    + 196                    } else if (k==='route') { 
    + 197                        result.route = decodeRoute(config.route);
    + 198                    } else {
    + 199                        result[k] = config[k];
    + 200                    }
    + 201                });
    + 202            }
    + 203            return result;
    + 204        }
    + 205
    + 206        function prepareRoutes(content:any) {
    + 207            const cr = content.root;
    + 208            class Router {
    + 209                view(node:Vnode) { 
    + 210                    cr.attrs.route = {};
    + 211                    content.route.params.map((k:any) =>
    + 212                        cr.attrs.route[k] = node.attrs[k]
    + 213                    );
    + 214                    return m(cr.compClass, copy(cr.attrs));  
    + 215                }
    + 216            }
    + 217            content.route.routes = {};
    + 218            content.route.paths.map((path:string) => content.route.routes[path] = Router);
    + 219        }
    + 220
    + 221        function mountOrRoute(c:any) {
    + 222            const content = decode(c);
    + 223            const cr = content.root;
    + 224            if (!cr) { 
    + 225                console.log('*** no top level component defined in config:'); 
    + 226                console.log(config); 
    + 227            }
    + 228            if (content.route) {
    + 229                prepareRoutes(content);
    + 230                m.route(root, content.route.default, content.route.routes);
    + 231                console.log('starting router');
    + 232            } else {
    + 233                m.mount(root, {view: (node:Vnode)=> m(cr.compClass, copy(cr.attrs))});
    + 234                console.log('mounting component');
    + 235            }
    + 236        }
    + 237
    + 238        const context = this.context;
    + 239        this.getContent(config)           
    + 240            .then((r:any) => recurse(r, context))
    + 241            .then(mountOrRoute);
    + 242    }
    + 243
    + 244    private getContent(config:any) {
    + 245        return (typeof config === 'string')? this.load(config) : Promise.resolve(config);
    + 246    }
    + 247
    + 248    private load(file:string) {
    + 249        console.log('requesting ' + file);
    + 250        return m.request({ method: "GET", url: file })
    + 251            .catch((e:any) => {
    + 252                console.log('error:');
    + 253                console.log(e);
    + 254            });
    + 255    }
    + 256}
    + 257
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/index.html b/docs/src/hsLayout/index.html new file mode 100644 index 0000000..679f717 --- /dev/null +++ b/docs/src/hsLayout/index.html @@ -0,0 +1,31 @@ + + +

    index.ts

    +
       1/**
    +   2 * @description hsLayout: Library for generating formatted screen layouts.
    +   3 */

    +   4
    +   5import * as pillars     from './view/PillaredLayouter';      if(pillars) {}
    +   6import * as tiles       from './view/TileLayouter';          if(tiles) {}
    +   7/** */
    +   8export { Layout }    from './view/Layout'; 
    +   9export { FILL, px, pc, 
    +  10         LayoutToken }  from './view/Tokens'; 
    +  11export { Layouter }     from './view/Layouter';
    +  12export { HsConfig }     from './hsConfig';
    +  13export { m, Vnode, o }  from './mithril'
    +  14
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/mithril.html b/docs/src/hsLayout/mithril.html new file mode 100644 index 0000000..7d1568a --- /dev/null +++ b/docs/src/hsLayout/mithril.html @@ -0,0 +1,43 @@ + + +

    mithril.ts

    +
       1/**
    +   2 * translates mithril libraries to an ES6 module and provides some Typescript type shortcuts.
    +   3 */

    +   4
    +   5if (!global['window']) {
    +   6    console.log('creating non-browser polyfill');
    +   7    // Polyfill DOM env for mithril
    +   8    global['window'] = require("mithril/test-utils/browserMock.js")();
    +   9    global['document'] = window.document;
    +  10
    +  11}
    +  12
    +  13/**
    +  14 * import and re-export the mithril m objkect
    +  15 */

    +  16export const m = require("mithril");
    +  17
    +  18/**
    +  19 * provide and export a Typescript Vnode type
    +  20 */

    +  21export type Vnode = typeof m.Vnode;
    +  22
    +  23const o = require("mithril/ospec/ospec");
    +  24o.root = window.document.createElement("div");
    +  25
    +  26export { o };
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/overview.html b/docs/src/hsLayout/overview.html new file mode 100644 index 0000000..c47a762 --- /dev/null +++ b/docs/src/hsLayout/overview.html @@ -0,0 +1,95 @@ + + +

    overview.ts

    +
       1/**
    +   2 * # hsLayout 
    +   3 * hsLayout provides means to layout the browser window in various ways.
    +   4 * See [Layout Examples](example/layout.html)
    +   5 * 
    +   6 * ## Concepts
    +   7 * 
    +   8 * ### Layouts
    +   9 * Layouts can be either defined generically:
    +  10 * ```
    +  11 * m(Layout, {
    +  12 *     css: '.myLayoutClass',  // optional
    +  13 *     columns: []
    +  14 *     content: ['left', 'right']
    +  15 * })
    +  16 * ```
    +  17 * Or, for more complex cases, by defining a class that extends {@link Layout.Layout `Layout`}:
    +  18 * ```
    +  19 * class Columns extends Layout {
    +  20 *     getComponents(node:Vnode) {
    +  21 *         return [m(LeftColumn), m(CenterColumn), m(RightColumn)]
    +  22 *     }
    +  23 * }
    +  24 * m(Columns);
    +  25 * ```
    +  26 * 
    +  27 * ### Layouters
    +  28 * To create new layout styles, define a class that extends the abstract {@link Layouter.Layouter `Layouter`} class.
    +  29 * This class should implement the `getStyles` method which calculates the styles attributes required for each `Component`
    +  30 * to be layed out in a `Layout`.
    +  31 * 
    +  32 * Currently defined Layouters:
    +  33 * -   {@link PillaredLayouter.Columns `Columns`}
    +  34 * -   {@link PillaredLayouter.Rows    `Rows`}
    +  35 * -   {@link TileLayouter.Tiles       `Tiles`}
    +  36 * 
    +  37 * ### Example
    +  38 * 
    +  39 * 
    +  40 * const theContent = ['Top row: 50px', 'Bottom row: remainder']
    +  41 * m.mount(root, {view: () => m(hslayout.Layout, {
    +  42 *     css: 'myColumn',
    +  43 *     rows: ["50px", "fill"], 
    +  44 *     content:theContent
    +  45 *     })
    +  46 * });
    +  47 * 
    +  48 * 
    +  49 * .myColumn .hs-layout {
    +  50 *     border: 1px solid white;
    +  51 * }
    +  52 * 
    +  53 * 

    +  54 * 
    +  55 * ### Nested Example
    +  56 * 
    +  57 * 
    +  58 * m.mount(root, {view: () => 
    +  59 *     m(hslayout.Layout, {
    +  60 *         css: 'myColumn',
    +  61 *         rows: ["150px", "fill"], 
    +  62 *         content:[
    +  63 *             m(hslayout.Layout, {columns:['20%'], content:['top left', 'top 2nd']}), 
    +  64 *             m(hslayout.Layout, {columns:['20%'], content:['bottom left', 'bottom 2nd']})
    +  65 *         ]
    +  66 *     })
    +  67 * });
    +  68 * 
    +  69 * 
    +  70 * .myColumn .hs-layout {
    +  71 *     border: 1px solid white;
    +  72 * }
    +  73 * 
    +  74 * 

    +  75 */

    +  76
    +  77/** */
    +  78
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/Container.html b/docs/src/hsLayout/view/Container.html new file mode 100644 index 0000000..8135269 --- /dev/null +++ b/docs/src/hsLayout/view/Container.html @@ -0,0 +1,159 @@ + + +

    view/Container.ts

    +
       1/**
    +   2 Definitions of the abstract base classes `Component` and `Container`.
    +   3 */

    +   4
    +   5/** */
    +   6import { m, Vnode}      from '../mithril';
    +   7
    +   8import { Layout }       from './Layout'; 
    +   9
    +  10/**
    +  11 * abstract base class of a viewable component. Subclasses can be passed into `mithril` 
    +  12 * to create render trees.
    +  13 * ### Example
    +  14 * `m('', [m(Component, {parameters})])`
    +  15 */

    +  16export abstract class Component {
    +  17    /** 
    +  18     * the standard `Mithril` component view function 
    +  19     * @param vnode the vnode passed by `Mithril`
    +  20     * @return A vnode that represents the view of this `Component` 
    +  21     */

    +  22    public abstract view(vnode?: Vnode): Vnode;
    +  23}
    +  24
    +  25/**
    +  26Abstract base class for applying layouts. Subclasses should implement a {@link Container.Container.getComponents `getComponents`} method that returns
    +  27the components to render. The default implementation returns the conponents passed in `node.attrs.content`.
    +  28Optionally, the subclass can also implement {@link Container.Container.getCSS `getCSS`} to provide the CSS class to 
    +  29assign to the component, and override the default implementation, which returns `node.attrs.css`. 
    +  30### Example:
    +  31
    +  32import { Container, px, FILL }  from 'hslayout';
    +  33const TitleHeight   = px(30); 
    +  34const FooterHeight  = px(10); 
    +  35class MyLayout extends Container {
    +  36    getComponents(node:Vnode):Vnode {
    +  37        return this.layout('.my-layout', { rows:[TitleHeight, FILL, FooterHeight] }, [
    +  38            m(), 
    +  39            m(),
    +  40            m()
    +  41        ]);
    +  42    }
    +  43    getCSS(node:Vnode):string {
    +  44    }
    +  45
    +  46

    +  47 */

    +  48export abstract class Container extends Component {
    +  49    /**
    +  50     * holds structural elements in style form: left, right, top, bottom, width, height
    +  51     */

    +  52    public style:string;
    +  53
    +  54//    oninit(node:Vnode)   { this.report('Container:init', node); }
    +  55//    oncreate(node:Vnode) { this.report('Container:create', node); } 
    +  56//    onupdate(node:Vnode) { this.report('Container:update', node); }
    +  57
    +  58    /**
    +  59     * Called during the lifecycle `view` call to retrieve the subcomponents to render in this container.
    +  60     * The default implementation returns components stored in `node.attrs.content`. This allows for 
    +  61     * creating containers directly via mithril: `m(Container, {content:[...]})`. 
    +  62     * In case `node.attrs.content` is an array of literals with a `compClass` field describing a Component class, 
    +  63     * the method will create a Mithril node on that class and pass the `node.attrs.route` argument down to it.
    +  64     * Override this method to create containers that return more sophisticated content.
    +  65     * @return a Vnode or an array or Vnodes
    +  66     */

    +  67    protected getComponents(node:Vnode):Vnode {
    +  68        return !Array.isArray(node.attrs.content)? node.attrs.content :
    +  69            node.attrs.content.map((c:any) => {
    +  70                if (c.compClass) { 
    +  71                    c.attrs.route = node.attrs.route;
    +  72                    return m(c.compClass, c.attrs);
    +  73                } else {
    +  74                    return c;
    +  75                }
    +  76            });
    +  77    }
    +  78
    +  79    /**
    +  80     * Called during the lifecycle `view` call to retrieve the css style class to apply to this container.
    +  81     * The default implementation returns components stored in `node.attrs.css`. This allows for 
    +  82     * creating containers directly via mithril: `m(Container, {content:[...], css:'.my-class'})`.
    +  83     * Override this method to create containers that return more sophisticated content.
    +  84     */

    +  85    protected getCSS(node:Vnode):string {
    +  86        return node.attrs.css || '';
    +  87    }
    +  88
    +  89
    +  90    private normalizeContent(components:Array|string): Vnode {
    +  91        if (typeof components === 'string') { 
    +  92            return [m('.hs-leaf', m.trust(components))]; 
    +  93        }
    +  94        if (components.length>0) { // an array:
    +  95            if (components.some((c:any) => (typeof c !== 'object'))) {
    +  96                return components.map((comp:string|typeof Container):Vnode => 
    +  97                    (comp instanceof Container)? comp : m(Container, {content:comp})
    +  98                );
    +  99            } else {
    + 100                return components;
    + 101            }
    + 102        }
    + 103        return [components];
    + 104    }
    + 105
    + 106    /**
    + 107    lays out the component in `components` according to the configuration in `attrs`.
    + 108    The method returns a vnode container that has an associated `cssClass` style.
    + 109    `layout` is called during the `render` phase of the `mithril` lifecycle, 
    + 110    which ensures an outside-in calling sequence on containers; 
    + 111    i.e. the outermost containers are called first, and `node` will already have the 
    + 112    `style` field set with required style attributes. 
    + 113    These are added to any `attrs` parameter provided.
    + 114
    + 115    The format for the layout configuration in `attrs` is 
    + 116    {}
    + 117    

    + 118     where `keyword` is the keyword with which the `Layout` was registered.
    + 119     * @param cssClass a css style designator; same as used in m(cssClass, ...) 
    + 120     * @param layout the attribute object literal that configures the layout
    + 121     * @param components the components to layout within the container. 
    + 122     * This is either a primitive `string`, or an array of `Container`s or `string`s.
    + 123     * @return a vnode that has an associated `cssClass` style.
    + 124     */

    + 125    view(node:Vnode): Vnode {
    + 126        const content = this.normalizeContent(this.getComponents(node)); // --> Vnode[]
    + 127        let css = Layout.createLayout(node.attrs, content);
    + 128        const attrs:any = {
    + 129            style: node.style,
    + 130            route: node.attrs.route,     
    + 131            onclick: node.attrs.onclick
    + 132        };
    + 133        node.attrs.route = undefined;
    + 134        if (node.attrs.href) { 
    + 135            attrs.href = node.attrs.href;
    + 136            attrs.oncreate = m.route.link;
    + 137            attrs.onupdate = m.route.link;
    + 138        }
    + 139        return m(`.hs-layout ${css} ${this.getCSS(node)}`, attrs, content.map((c:any) => c));
    + 140    }
    + 141}
    + 142
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/Layout.html b/docs/src/hsLayout/view/Layout.html new file mode 100644 index 0000000..9aede41 --- /dev/null +++ b/docs/src/hsLayout/view/Layout.html @@ -0,0 +1,153 @@ + + +

    view/Layout.ts

    +
       1/**
    +   2 * # Layout
    +   3 * A `mithril` component class that layouts available space in the window.
    +   4 * 
    +   5 * ### Invocation
    +   6 * invoked as `m(Layout, {name:, content:Array})`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - :Array, required.  matches a registered {@link Layouter Layouter}
    +  10 * - content: Array, required. The Vnode children to lay out. 
    +  11 * - css:String, optional. The css specifier to use for this `Layout` component.
    +  12 * - route: object literal holding parameters passed from `m.route`
    +  13 * - href: String, optional. If present, makes the component clickable
    +  14 * - onclick:(), optional. The function to call when clicked
    +  15 */

    +  16
    +  17/** */
    +  18import { m, Vnode}      from '../mithril';
    +  19import { Layouter }       from './Layouter'; 
    +  20
    +  21/**
    +  22Base class for applying layouts. Subclasses should implement a {@link Layout.Layout.getComponents `getComponents`} method that returns
    +  23the components to render. The default implementation returns the conponents passed in `node.attrs.content`.
    +  24Optionally, the subclass can also implement {@link Layout.Layout.getCSS `getCSS`} to provide the CSS class to 
    +  25assign to the component, and override the default implementation, which returns `node.attrs.css`. 
    +  26### Example:
    +  27
    +  28import { Layout, px, FILL }  from 'hslayout';
    +  29const TitleHeight   = px(30); 
    +  30const FooterHeight  = px(10); 
    +  31class MyLayout extends Layout {
    +  32    getComponents(node:Vnode):Vnode {
    +  33        return this.layout('.my-layout', { rows:[TitleHeight, FILL, FooterHeight] }, [
    +  34            m(), 
    +  35            m(),
    +  36            m()
    +  37        ]);
    +  38    }
    +  39    getCSS(node:Vnode):string {
    +  40    }
    +  41
    +  42

    +  43 */

    +  44export class Layout {
    +  45    /**
    +  46     * holds structural elements in style form: left, right, top, bottom, width, height
    +  47     */

    +  48    public style:string;
    +  49
    +  50//    oninit(node:Vnode)   { this.report('Layout:init', node); }
    +  51//    oncreate(node:Vnode) { this.report('Layout:create', node); } 
    +  52//    onupdate(node:Vnode) { this.report('Layout:update', node); }
    +  53
    +  54    /**
    +  55     * Called during the lifecycle `view` call to retrieve the subcomponents to render in this container.
    +  56     * The default implementation returns components stored in `node.attrs.content`. This allows for 
    +  57     * creating containers directly via mithril: `m(Layout, {content:[...]})`. 
    +  58     * In case `node.attrs.content` is an array of literals with a `compClass` field describing a Component class, 
    +  59     * the method will create a Mithril node on that class and pass the `node.attrs.route` argument down to it.
    +  60     * 
    +  61     * Override this method to create containers that return more sophisticated content.
    +  62     * @return a String, a Vnode, or an array of Strings or Vnodes
    +  63     */

    +  64    protected getComponents(node:Vnode):Vnode {
    +  65        return !Array.isArray(node.attrs.content)? node.attrs.content :
    +  66            node.attrs.content.map((c:any) => {
    +  67                if (c.compClass) { 
    +  68                    c.attrs.route = node.attrs.route;
    +  69                    return m(c.compClass, c.attrs);
    +  70                } else {
    +  71                    return c;
    +  72                }
    +  73            });
    +  74    }
    +  75
    +  76    /**
    +  77     * Called during the lifecycle `view` call to retrieve the css style class to apply to this container.
    +  78     * The default implementation returns components stored in `node.attrs.css`. This allows for 
    +  79     * creating containers directly via mithril: `m(Layout, {content:[...], css:'.my-class'})`.
    +  80     * Override this method to create containers that return more sophisticated content.
    +  81     */

    +  82    protected getCSS(node:Vnode):string {
    +  83        return node.attrs.css || '';
    +  84    }
    +  85
    +  86
    +  87    private normalizeContent(components:Array|string): Vnode {
    +  88        if (typeof components === 'string') { 
    +  89            return [m('.hs-leaf', m.trust(components))]; 
    +  90        }
    +  91        if (components.length>0) { // an array: ensure elements are Layout components
    +  92            return components.map((comp:string|typeof Layout):Vnode => 
    +  93                    (comp instanceof Layout)? comp : m(Layout, {content:comp})
    +  94            );
    +  95        }
    +  96        // else: assume components is a mithril node: return node as an array
    +  97        return [components];
    +  98    }
    +  99
    + 100    /**
    + 101    lays out the component in `components` according to the configuration in `attrs`.
    + 102    The method returns a vnode container that has an associated `cssClass` style.
    + 103    `layout` is called during the `render` phase of the `mithril` lifecycle, 
    + 104    which ensures an outside-in calling sequence on containers; 
    + 105    i.e. the outermost containers are called first, and `node` will already have the 
    + 106    `style` field set with required style attributes. 
    + 107    These are added to any `attrs` parameter provided.
    + 108
    + 109    The format for the layout configuration in `attrs` is 
    + 110    {}
    + 111    

    + 112     where `keyword` is the keyword with which the `Layouter` was registered.
    + 113     * @param cssClass a css style designator; same as used in m(cssClass, ...) 
    + 114     * @param layout the attribute object literal that configures the layout
    + 115     * @param components the components to layout within the container. 
    + 116     * This is either a primitive `string`, or an array of `Layout`s or `string`s.
    + 117     * @return a vnode that has an associated `cssClass` style.
    + 118     */

    + 119    view(node:Vnode): Vnode {
    + 120        const content = this.normalizeContent(this.getComponents(node)); // --> Vnode[]
    + 121        let css = Layouter.createLayout(node.attrs, content);
    + 122        const attrs:any = {
    + 123            style: node.style,
    + 124            route: node.attrs.route,     
    + 125            onclick: node.attrs.onclick
    + 126        };
    + 127        node.attrs.route = undefined;
    + 128        if (node.attrs.href) { 
    + 129            attrs.href = node.attrs.href;
    + 130            attrs.oncreate = m.route.link;
    + 131            attrs.onupdate = m.route.link;
    + 132        }
    + 133        return m(`.hs-layout ${css} ${this.getCSS(node)}`, attrs, content.map((c:any) => c));
    + 134    }
    + 135}
    + 136
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/Layouter.html b/docs/src/hsLayout/view/Layouter.html new file mode 100644 index 0000000..e95a05b --- /dev/null +++ b/docs/src/hsLayout/view/Layouter.html @@ -0,0 +1,148 @@ + + +

    view/Layouter.ts

    +
       1/**
    +   2Layouter.ts provides basic mechanisms for laying out a view container. 
    +   3Subclasses of `Layouter` should
    +   4- implement the {@link Layouter.Layouter.getStyles getStyles} method.
    +   5- register the subclass and configuration keyword with the static 
    +   6   {@link Layouter.Layouter.register register} method.
    +   7*/

    +   8
    +   9/** */
    +  10import { Vnode} from '../mithril';
    +  11
    +  12import { LayoutToken }  from './Tokens';
    +  13import { Layout }    from './Layout';
    +  14import { px, pc, FILL } from './Tokens';
    +  15
    +  16/**
    +  17Abstract base class for creating layout style implementations.
    +  18Subclasses should implement `getStyles`. In addition, subclasses need to be registered with the 
    +  19static `Layouter.register` method.
    +  20### Example
    +  21
    +  22class MyLayouter extends Layouter {
    +  23    cssClass = '.my-css-class';
    +  24    constructor(public areaDesc:LayoutToken[]) { 
    +  25        super(areaDesc); 
    +  26    }
    +  27    
    +  28    protected getStyles(components:Array):string {
    +  29        components.map((c:Layout|Vnode, i:number) => {
    +  30            c.style = `width:auto; height:auto;
    +  31        });   
    +  32        return this.cssClass;
    +  33   }
    +  34}
    +  35
    +  36Layouter.register('MyLayouter', MyLayouter);
    +  37

    +  38 */

    +  39export abstract class Layouter {
    +  40    /**
    +  41     * statis list of available styles. The key for each entry is the keyword that triggers the style,
    +  42     * and the value is a constructor for that style
    +  43     */

    +  44    static layoutStyles:{string?: Layouter} = {};
    +  45
    +  46        /**
    +  47     * Translates `string` params to {@link hsLayout:Tokens.LayoutToken LayoutTokens}.
    +  48     * The `params` are expected to either
    +  49     * - end in 'px'
    +  50     * - end in '%'
    +  51     * - be equal to 'fill' (case insensitive)
    +  52     * @param params an Array of strings that will be converted to an array of LayourTokens.
    +  53     * 
    +  54     */

    +  55    private static translate(params:Array):Array {
    +  56        if (params.length === 0) { params.push(''); }   //  [] --> ['']
    +  57        return params.map((param:string|any) => {
    +  58            if (typeof param === 'string') {
    +  59                if (param.endsWith('px')) { return px(parseInt(param)); }
    +  60                if (param.endsWith('%')) { return pc(parseInt(param)); }
    +  61                if (param.toLowerCase()==='fill') { return FILL;}
    +  62            } else {
    +  63                return param;
    +  64            }
    +  65        });
    +  66    }
    +  67
    +  68    /**
    +  69     * Register a new Layouter style with corresponding configuration keyword.
    +  70     * Example:```
    +  71     * class ColumnsLayout extends Layouter {...}
    +  72     * Layouter.register('Column', Columns);
    +  73     * ```
    +  74     * @param keyword the keyword used in the attributes to `this.layout`
    +  75     * @param style the `Layouter` implementation to instantiate when encountering `keyword` 
    +  76     */

    +  77    public static register(keyword:string, style:typeof Layouter) {
    +  78//        console.log(`registering ${keyword} layout`);
    +  79        Layouter.layoutStyles[keyword] = style;
    +  80    }
    +  81
    +  82    /**
    +  83     * Lays out the `components` according to the configuration in `attrs`.
    +  84     * The method will search for a registered layout key in `attrs`, then construct the `Layouter` associated with the key
    +  85     * with the parameters for the key, and call the `getStyles` method on the style with the provided `components`.
    +  86     * @param attrs an object literal, typically provided as middle attributes object in the m(css, {}, '') call.
    +  87     * @param components 
    +  88     * @return returns the css class that the `getStyles` function returns.
    +  89     */

    +  90    public static createLayout(attrs:any, components:Array):string {
    +  91        let css = '';
    +  92        Object.keys(Layouter.layoutStyles).some(key => { // executes the first match key in attrs.
    +  93            if (attrs[key]) { 
    +  94                css = new Layouter.layoutStyles[key](Layouter.translate(attrs[key])).getStyles(components); 
    +  95                attrs[key] = undefined;
    +  96                return true;
    +  97            }
    +  98            return false;
    +  99        });
    + 100        return css;
    + 101    }
    + 102
    + 103
    + 104    spacing = 0;   
    + 105    
    + 106    /**
    + 107     * Layouter Constructor, will be called by the static `createLayout` method when creating the layout on a {@link hsLayout:Layout.Layout `Layout`}.
    + 108     * The `areaDesc` parameter is expected to be of the form {: {@link hsLayout:Tokens.LayoutToken `LayoutToken`}[]}} 
    + 109     * and will be passed through form the `Layout` requesting the layout.
    + 110     * @param areaDesc 
    + 111     */

    + 112    constructor(public areaDesc:LayoutToken[]) {};
    + 113
    + 114    /**
    + 115     * Calculates the style attributes required for each component in `Components`.
    + 116     * These attributes are saved in a `style` field on the component itself. 
    + 117     * During rendering these `style` attributes are copied to the `node.attrs.styles` field.
    + 118     * ### Example
    + 119    protected getStyles(components:Array):string {
    + 120        components.map((c:Layout|Vnode, i:number) => {
    + 121            c.style = `width:auto; height:auto;
    + 122        });   
    + 123        return this.cssClass;
    + 124    }
    + 125    

    + 126     * @param components 
    + 127     */

    + 128    protected abstract getStyles(components:Array):string;
    + 129}
    + 130
    + 131
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/PillaredLayout.html b/docs/src/hsLayout/view/PillaredLayout.html new file mode 100644 index 0000000..a328a4f --- /dev/null +++ b/docs/src/hsLayout/view/PillaredLayout.html @@ -0,0 +1,359 @@ + + +

    view/PillaredLayout.ts

    +
       1/**
    +   2Lays out components in pillars, i.e. either {@link hsLayout:PillaredLayout.Columns columns}
    +   3or {@link hsLayout:PillaredLayout.Rows rows}
    +   4Use either of
    +   5- `{rows: [attributes]}`
    +   6- `{columns: [attributes]}` 
    +   7
    +   8to invoke this layout.
    +   9
    +  10### Example
    +  11
    +  12    {rows: [px(200), FILL]}   // --> top row has height 200px, all other rows evenly share remaining space 
    +  13    {rows: ["200px", "fill"]} // --> equivalent description
    +  14

    +  15
    +  16## Attributes
    +  17The following values **v** are valid entries in The Attributes array:
    +  18- **px(n)** or **"px"** -- a fixed number of pixels 
    +  19- **pc(n)** or **"%"**  -- a fixed percentage of available space
    +  20- **FILL** or **"fill"**   -- a special constant to indicate - may appear only once per array.
    +  21
    +  22The following options are supported for the Attributes array:
    +  23- **[ ]**: An empty array; all components will be evenly spaced across the available width. 
    +  24- **[v]**: All components have the specified width (in px or %) and will fill the available space from the left,
    +  25    leaving any remaining unused space on the right. 
    +  26- **[v1, v2]**: All components have the specified widths (in px or %) and will fill the available space from the left,
    +  27    leaving any remaining unused space on the right. If there are more components than widths, the right-most width
    +  28    will be used for the reminaing widgets.
    +  29- **[v, FILL]**: Sets the first (left) widget to a width of `v`.

    +  30    if `v` is specified in %, the remaining n-1 components will have equal relative widths of `(100-v)/(n-1)%`

    +  31    if `v` is specified in px, the remaining n-1 components will have their right borders at location `i*100/n%`, with i=1...n.
    +  32- **[FILL, v]**: Sets the last (right) widget to a width of `v`.

    +  33    if `v` is specified in %, the remaining n-1 components will have equal relative widths of `(100-v)/(n-1)%`

    +  34    if `v` is specified in px, the remaining n-1 components will have their left borders at location `i*100/n%`, with i=0...n-1.
    +  35- **[va, FILL, vb]**: Sets the first and last widget to a width of `va`/`vb`.

    +  36    Both have to be specified either in px or in %.

    +  37    if the unit is %, the remaining n-2 components will have equal relative widths of `(100-vb-va)/(n-2)%`

    +  38    if the unit is px, the remaining n-2 components will have their left/right borders at location `i*100/n%`.
    +  39- **[v1, v2, FILL, v3, v4]**: multiple widths can be specified in uninterrupted sequence both from the left and the right. 
    +  40 */

    +  41
    +  42/** */
    +  43import { Container }    from './Container';
    +  44import { Layout }       from './Layout';
    +  45import { LayoutToken, DefinedToken, PixelToken }    from './Tokens';
    +  46import { Vnode}         from '../mithril';
    +  47
    +  48
    +  49
    +  50/**
    +  51 * interface definition for entries in `cParams`
    +  52 */

    +  53interface PillarParams {
    +  54    cssClass: string;
    +  55    fields: string[];
    +  56}
    +  57
    +  58/**
    +  59 * array of trigger keywords for column and row layout styles
    +  60 */

    +  61export const PillarLayouts = [
    +  62    'columns', 'rows'
    +  63];
    +  64
    +  65/**
    +  66 * contains style settings for the row and column layout
    +  67 */

    +  68const cParams = {
    +  69    columns: {
    +  70        cssClass: '.hs-column-layout',
    +  71        fields: ['top', 'bottom', 'left', 'right', 'height', 'width']
    +  72    },
    +  73    rows: {
    +  74        cssClass: '.hs-row-layout',
    +  75        fields: ['left', 'right', 'top', 'bottom', 'width', 'height']
    +  76    }
    +  77};
    +  78
    +  79type descriptor = {size:number, code:string, fields:{}};
    +  80
    +  81/**
    +  82 * Abstract base Layout for creating Pillars (rows, colums)
    +  83 */

    +  84abstract class Pillars extends Layout{
    +  85    firstFixed: number; // number of DefinedToken entries at the beginning
    +  86    lastFixed:  number; // number of DefinedToken entries at the end
    +  87    unit:(num:number)=>descriptor[];
    +  88    fields: string[];
    +  89    cssClass:string;
    +  90
    +  91    /**
    +  92     * Constructs a Pillared layout (rows or columns).
    +  93     * Determines the `unit` (% or px) from the passed area descriptors
    +  94     * @param params Style params for either rows or columns layout
    +  95     * @param areaDesc Description of the requested layout 
    +  96     */

    +  97    constructor(params:PillarParams, public areaDesc:LayoutToken[]) { 
    +  98        super(areaDesc); 
    +  99        this.fields = params.fields;
    + 100        this.cssClass = params.cssClass;
    + 101
    + 102        let n = areaDesc.length-1;
    + 103        let first = 0;
    + 104        let last  = 0;        
    + 105        // if any of the dimensions are in px, use the pixel method; else use the percent method
    + 106        this.unit = areaDesc.some((area:LayoutToken) => (area instanceof PixelToken))? this.unitPixel : this.unitPercent;   
    + 107        
    + 108        // determine first = number of consecutive fixed fields at start
    + 109        areaDesc.some((area:LayoutToken, i:number) => ((areaDesc[i]   instanceof DefinedToken)? ++first<0 : true));         
    + 110
    + 111        // determine last  = number of consecutive fixed fields at end
    + 112        areaDesc.some((area:LayoutToken, i:number) => ((areaDesc[n-i] instanceof DefinedToken)? ++last<0  : true));         
    + 113
    + 114        this.firstFixed = first;
    + 115        this.lastFixed  = Math.min(last, areaDesc.length-first);
    + 116    };
    + 117
    + 118    // num: number of areas to layout
    + 119    /**
    + 120     * Creates an iterable list of size descriptors, one for each area to be layed out.
    + 121     * Each descriptor 
    + 122     * @param num the number of areas to be layed out
    + 123     * @return Iterable list of `num` size descriptors, one for each area to be layed out
    + 124     */

    + 125    private getSizes(num:number):descriptor[] {
    + 126        const first = this.firstFixed;
    + 127        const last  = this.lastFixed;
    + 128        const desc  = this.areaDesc;
    + 129        const len = desc.length;
    + 130
    + 131        return [...Array(num).keys()].map((i:number) => {
    + 132            let size:number = null;
    + 133            let t = null;
    + 134            if (i > num-1-last)  { size = desc[len - (num-i)].getSize(); t = 'end'; }       // end sequence
    + 135            else if (i < first)  { size = desc[i].getSize(); t = 'start'; }                 // start sequence
    + 136            else if (len>0 && len===first){ size = desc[len-1].getSize(); t = 'start'; }    // all items 
    + 137            return {size:size, code:t, fields:{}};
    + 138        });
    + 139    }
    + 140
    + 141    private unitPercent(num:number):descriptor[] {
    + 142        let f = this.fields;
    + 143        let max = 100.0;
    + 144        let styles:descriptor[] = this.getSizes(num);
    + 145
    + 146        styles.forEach(style => { if (style.size) { max = max - style.size; num--; } });
    + 147        let defDim = max / num;      // divvy up remaining space
    + 148
    + 149        function pass(styles:descriptor[], ix0:string, ix1:string, breakCond:(cond:string)=>boolean) {
    + 150            let sumDim = 0;
    + 151            styles.some(style => { // stop when breakCond is met
    + 152                let size = style.size || defDim;
    + 153                if (breakCond(style.code)) { return true; }
    + 154                style.fields[ix0] = sumDim+'%';
    + 155                sumDim += size;
    + 156                style.fields[ix1] = (100-sumDim)+'%'; 
    + 157                style.fields[f[5]] = 'auto';
    + 158                return false;
    + 159            });
    + 160        }
    + 161
    + 162        pass(styles, f[2], f[3], (e:string) => e==='end');              // forward pass
    + 163        pass(styles.reverse(), f[3], f[2], (e:string) => e!=='end');    // backward pass
    + 164        return styles.reverse();    // reverse a second time for original sequence.
    + 165    };
    + 166
    + 167    private unitPixel(num:number):descriptor[] { // pattern: [px, px, FILL , px, px]
    + 168        let styles:descriptor[] = this.getSizes(num);
    + 169        let f = this.fields;
    + 170       
    + 171        let defDim = 100.0/num;          // used for unspecified widths
    + 172
    + 173        // work forwards through the heights
    + 174        let sumDim = 0;
    + 175        styles.some((style, i) => {
    + 176            if (style.code==='start') {   // so far, all heights explicitly set as px
    + 177                style.fields[f[2]] = sumDim +'px';
    + 178                sumDim += style.size + (this.spacing || 0) + (this.spacing || 0);
    + 179                style.fields[f[3]] = 'auto';
    + 180                style.fields[f[5]] = style.size +'px';
    + 181            } else if (style.code === null) {
    + 182                style.fields[f[2]] = (sumDim>0)? (sumDim +'px') : (i*defDim + '%');
    + 183                sumDim = -1;
    + 184                style.fields[f[3]] = (100-(i+1)*defDim) + '%';
    + 185                style.fields[f[5]] = 'auto';
    + 186            } else if (style.code==='end') { return true; }
    + 187            return false;
    + 188        });
    + 189        
    + 190        // work backwards through the heights
    + 191        sumDim = 0;
    + 192        styles.slice().reverse().some((style, i) => {
    + 193            style.fields[f[3]] = sumDim + 'px';
    + 194            if (style.code === 'end') { 
    + 195                sumDim += style.size + (this.spacing || 0) + (this.spacing || 0);
    + 196                style.fields[f[2]] = 'auto';
    + 197                style.fields[f[5]] = style.size+'px';
    + 198            } else {
    + 199                if (sumDim>0 && style.code !== 'start') {
    + 200                    style.fields[f[5]] = 'auto';
    + 201                }
    + 202                return true; 
    + 203            } 
    + 204            return false;
    + 205        });  
    + 206        return styles;
    + 207    };
    + 208    
    + 209    /**
    + 210     * Calculates the style attributes required for each component in `Components`.
    + 211     * These attributes are saved in a `styles` field on the component itself. 
    + 212     * During rendering these `styles` attributes are copied to the `node.attrs.styles` field.
    + 213     * @param components 
    + 214     */

    + 215    protected getStyles(components:Array):string  { 
    + 216        let f = this.fields;
    + 217        let styles:descriptor[] = this.unit(components.length);
    + 218        components.map((c:Container|Vnode, i:number) => {
    + 219            c.style = `${f[0]}:0%; ${f[1]}:0%; `;
    + 220            Object.keys(styles[i].fields).forEach((st:string) => { c.style += `${st}: ${styles[i].fields[st]};`; });
    + 221        });   
    + 222        return this.cssClass;
    + 223    };
    + 224};
    + 225
    + 226/**
    + 227 * Constructs a columns pillar layout style.

    + 228 * Use `{columns: [attributes]}` to invoke this layout. See top of page for a description.
    + 229 * 
    + 230 * 
    + 231 * const styles = [ 
    + 232 *     [],                // equal spacing
    + 233 *     ["100px"],         // fixed spacing
    + 234 *     ["60px", "100px"], // fixed spacing, first one smaller
    + 235 *     ["100px", "fill"], // first one fixed, rest equal
    + 236 *     ["fill", "100px"], // last one fixed, rest equal
    + 237 *     ["20%"],           // relative spacing, all equal
    + 238 *     ["20%", "fill"],   // first relative, rest equal
    + 239 *     ["fill", "20%"]    // last relative, rest equal
    + 240 * ];
    + 241 * let c = [];
    + 242 * function next() {
    + 243 *     if (c.length >= 5) { c = []; }
    + 244 *     else { c.push(''); }
    + 245 *     setTimeout(next, 2000);
    + 246 *     m.redraw();
    + 247 * }
    + 248 * 
    + 249 * m.mount(root, { 
    + 250 *     view:() => m(hslayout.Container, {
    + 251 *         rows:[],  // each row a style
    + 252 *         content: styles.map(i => m(hslayout.Container, {
    + 253 *             css: '.myExample', 
    + 254 *             content: c.map(c=>(''+i)),
    + 255 *             columns: i    // a style from styles
    + 256 *         }))
    + 257 *     })
    + 258 * });
    + 259 * next();
    + 260 * 
    + 261 * 
    + 262 * .hs-row-layout>.myExample { 
    + 263 *     border-top:    1px solid white;
    + 264 *     border-bottom: 1px solid white;
    + 265 * }
    + 266 * .myExample>.hs-layout {
    + 267 *     border-left:  1px solid white;
    + 268 *     border-right: 1px solid white;
    + 269 *     background-color: #ccc;
    + 270 * }
    + 271 * .myExample { 
    + 272 *     color:       #a44; 
    + 273 *     font-weight: bold; 
    + 274 *     text-align:  center;
    + 275 * }
    + 276 * 
    + 277 * 

    + 278 */

    + 279class Columns extends Pillars {
    + 280    constructor(public areaDesc:LayoutToken[]) { super(cParams[PillarLayouts[0]], areaDesc);  };
    + 281};
    + 282
    + 283/**
    + 284 * Constructs a row pillar layout style.

    + 285 * Use `{row: [attributes]}` to invoke this layout. See top of page for a description.
    + 286 * 
    + 287 * 
    + 288 * const styles = [ 
    + 289 *     [],                // equal spacing
    + 290 *     ["100px"],         // fixed spacing
    + 291 *     ["60px", "100px"], // fixed spacing, first one smaller
    + 292 *     ["100px", "fill"], // first one fixed, rest equal
    + 293 *     ["fill", "100px"], // last one fixed, rest equal
    + 294 *     ["20%"],           // relative spacing, all equal
    + 295 *     ["20%", "fill"],   // first relative, rest equal
    + 296 *     ["fill", "20%"]    // last relative, rest equal
    + 297 * ];
    + 298 * let c = [];
    + 299 * function next() {
    + 300 *     if (c.length >= 5) { c = []; }
    + 301 *     else { c.push(''); }
    + 302 *     setTimeout(next, 2000);
    + 303 *     m.redraw();
    + 304 * }
    + 305 * 
    + 306 * m.mount(root, { 
    + 307 *     view:() => m(hslayout.Container, {
    + 308 *         columns:[],  // each column a style
    + 309 *         content: styles.map(i => m(hslayout.Container, {
    + 310 *             css: '.myExample', 
    + 311 *             content: c.map(c=>(''+i)),
    + 312 *             rows: i   // a style from styles
    + 313 *         }))
    + 314 *     })
    + 315 * });
    + 316 * next();
    + 317 * 
    + 318 * 
    + 319 * .hs-column-layout>.myExample {
    + 320 *     border-left:    1px solid white;
    + 321 *     border-right: 1px solid white;
    + 322 * }
    + 323 * .myExample>.hs-layout {
    + 324 *     border-top:  1px solid white;
    + 325 *     border-bottom: 1px solid white;
    + 326 *     background-color: #ccc;
    + 327 * }
    + 328 * .myExample { 
    + 329 *     color:       #a44; 
    + 330 *     font-weight: bold; 
    + 331 *     text-align:  center;
    + 332 * }
    + 333 * 
    + 334 * 

    + 335 */

    + 336class Rows extends Pillars {
    + 337    constructor(public areaDesc:LayoutToken[]) { super(cParams[PillarLayouts[1]], areaDesc);  };
    + 338};
    + 339
    + 340Layout.register(PillarLayouts[0], Columns);
    + 341Layout.register(PillarLayouts[1],    Rows);
    + 342
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/PillaredLayout.spec.html b/docs/src/hsLayout/view/PillaredLayout.spec.html new file mode 100644 index 0000000..99ab705 --- /dev/null +++ b/docs/src/hsLayout/view/PillaredLayout.spec.html @@ -0,0 +1,101 @@ + + +

    view/PillaredLayout.spec.ts

    +
       1
    +   2const hslayout = require('../src/');
    +   3const m = hslayout.m;
    +   4const o = hslayout.o;
    +   5
    +   6
    +   7const columns = ["150px", "fill"];
    +   8const titles  = ['Left Column: 150px', 'Right Column: remainder'];
    +   9
    +  10
    +  11o.spec('rows', () => {
    +  12    let rows:any;
    +  13    o.before(() => {
    +  14        m.mount(o.root, {view: () => m(hslayout.Container, {
    +  15            css: 'myRow',
    +  16            rows: columns,
    +  17            content: titles
    +  18            })
    +  19        }); 
    +  20        rows = o.root.childNodes[0];
    +  21    }); 
    +  22    o('first level', () => {
    +  23        o(rows===undefined).equals(false)('should be defined');
    +  24        o(rows.className.includes('myRow')).equals(true)(`class myRow in '${rows.className}'`);
    +  25        o(rows.className.includes('hs-row-layout')).equals(true)(`class hs-row-layout in '${rows.className}'`);
    +  26        o(rows.childNodes.length).equals(2)(`has ${rows.childNodes.length} children`);
    +  27    });
    +  28
    +  29    o('second level', () => {
    +  30        rows.childNodes.forEach((c:any, i:number) => {
    +  31            o(c.className.includes('hs-layout')).equals(true)(`class hs-layout in '${c.className}'`);
    +  32            o(c.style.left).equals('0%')(`style left`);
    +  33            o(c.style.right).equals('0%')(`style right`);
    +  34            o(c.style.top).equals((i===0)?'0px':columns[0])(`style top`);
    +  35            o(c.style.bottom).equals((i===0)?'auto':'0px')(`style bottom`);
    +  36            o(c.style.height).equals((i===0)?columns[0]:'auto')(`style height`);
    +  37            o(c.childNodes.length).equals(1)(`has ${c.childNodes.length} children`);
    +  38        });
    +  39    });
    +  40    o('third level', () => {
    +  41        rows.childNodes.forEach((c:any, i:number) => {
    +  42            o(c.childNodes[0].className.includes('hs-leaf')).equals(true)(`class hs-leaf in '${c.childNodes[0].className}'`);
    +  43            o(c.childNodes[0].childNodes[0].nodeValue).equals(titles[i])(`item ${i+1} child leaf text`);
    +  44        });
    +  45    });
    +  46});
    +  47
    +  48o.spec('columns', () => {
    +  49    let rows:any;
    +  50    o.before(() => {
    +  51        m.mount(o.root, {view: () => m(hslayout.Container, {
    +  52            css: 'myColumn',
    +  53            columns: columns,
    +  54            content: titles
    +  55            })
    +  56        }); 
    +  57        rows = o.root.childNodes[0];
    +  58    }); 
    +  59    o('first level', () => {
    +  60        o(rows===undefined).equals(false)('should be defined');
    +  61        o(rows.className.includes('myColumn')).equals(true)(`class myColumn in '${rows.className}'`);
    +  62        o(rows.className.includes('hs-column-layout')).equals(true)(`class hs-column-layout in '${rows.className}'`);
    +  63        o(rows.childNodes.length).equals(2)(`has ${rows.childNodes.length} children`);
    +  64    });
    +  65
    +  66    o('second level', () => {
    +  67        rows.childNodes.forEach((c:any, i:number) => {
    +  68            o(c.className.includes('hs-layout')).equals(true)(`class hs-layout in '${c.className}'`);
    +  69            o(c.style.top).equals('0%')(`style top`);
    +  70            o(c.style.bottom).equals('0%')(`style bottom`);
    +  71            o(c.style.left).equals((i===0)?'0px':columns[0])(`style left`);
    +  72            o(c.style.right).equals((i===0)?'auto':'0px')(`style right`);
    +  73            o(c.style.width).equals((i===0)?columns[0]:'auto')(`style width`);
    +  74            o(c.childNodes.length).equals(1)(`has ${c.childNodes.length} children`);
    +  75        });
    +  76    });
    +  77    o('third level', () => {
    +  78        rows.childNodes.forEach((c:any, i:number) => {
    +  79            o(c.childNodes[0].className.includes('hs-leaf')).equals(true)(`class hs-leaf in '${c.childNodes[0].className}'`);
    +  80            o(c.childNodes[0].childNodes[0].nodeValue).equals(titles[i])(`item ${i+1} child leaf text`);
    +  81        });
    +  82    });
    +  83});
    +  84
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/PillaredLayouter.html b/docs/src/hsLayout/view/PillaredLayouter.html new file mode 100644 index 0000000..23ca97a --- /dev/null +++ b/docs/src/hsLayout/view/PillaredLayouter.html @@ -0,0 +1,360 @@ + + +

    view/PillaredLayouter.ts

    +
       1/**
    +   2Lays out components in pillars, i.e. either {@link hsLayout:PillaredLayout.Columns columns}
    +   3or {@link hsLayout:PillaredLayout.Rows rows}
    +   4Use either of
    +   5- `{rows: [attributes]}`
    +   6- `{columns: [attributes]}` 
    +   7
    +   8to invoke this layout.
    +   9
    +  10### Example
    +  11
    +  12    {rows: [px(200), FILL]}   // --> top row has height 200px, all other rows evenly share remaining space 
    +  13    {rows: ["200px", "fill"]} // --> equivalent description
    +  14

    +  15
    +  16## Attributes
    +  17The following values **v** are valid entries in The Attributes array:
    +  18- **px(n)** or **"px"** -- a fixed number of pixels 
    +  19- **pc(n)** or **"%"**  -- a fixed percentage of available space
    +  20- **FILL** or **"fill"**   -- a special constant to indicate - may appear only once per array.
    +  21
    +  22The following options are supported for the Attributes array:
    +  23- **[ ]**: An empty array; all components will be evenly spaced across the available width. 
    +  24- **[v]**: All components have the specified width (in px or %) and will fill the available space from the left,
    +  25    leaving any remaining unused space on the right. 
    +  26- **[v1, v2]**: All components have the specified widths (in px or %) and will fill the available space from the left,
    +  27    leaving any remaining unused space on the right. If there are more components than widths, the right-most width
    +  28    will be used for the reminaing widgets.
    +  29- **[v, FILL]**: Sets the first (left) widget to a width of `v`.

    +  30    if `v` is specified in %, the remaining n-1 components will have equal relative widths of `(100-v)/(n-1)%`

    +  31    if `v` is specified in px, the remaining n-1 components will have their right borders at location `i*100/n%`, with i=1...n.
    +  32- **[FILL, v]**: Sets the last (right) widget to a width of `v`.

    +  33    if `v` is specified in %, the remaining n-1 components will have equal relative widths of `(100-v)/(n-1)%`

    +  34    if `v` is specified in px, the remaining n-1 components will have their left borders at location `i*100/n%`, with i=0...n-1.
    +  35- **[va, FILL, vb]**: Sets the first and last widget to a width of `va`/`vb`.

    +  36    Both have to be specified either in px or in %.

    +  37    if the unit is %, the remaining n-2 components will have equal relative widths of `(100-vb-va)/(n-2)%`

    +  38    if the unit is px, the remaining n-2 components will have their left/right borders at location `i*100/n%`.
    +  39- **[v1, v2, FILL, v3, v4]**: multiple widths can be specified in uninterrupted sequence both from the left and the right. 
    +  40 */

    +  41
    +  42/** */
    +  43import { Layout }    from './Layout';
    +  44import { Layouter }       from './Layouter';
    +  45import { LayoutToken, DefinedToken, PixelToken }    from './Tokens';
    +  46import { Vnode}         from '../mithril';
    +  47
    +  48
    +  49
    +  50/**
    +  51 * interface definition for entries in `cParams`
    +  52 */

    +  53interface PillarParams {
    +  54    cssClass: string;
    +  55    fields: string[];
    +  56}
    +  57
    +  58/**
    +  59 * array of trigger keywords for column and row layout styles
    +  60 */

    +  61export const PillarLayouts = [
    +  62    'columns', 'rows'
    +  63];
    +  64
    +  65/**
    +  66 * contains style settings for the row and column layout
    +  67 */

    +  68const cParams = {
    +  69    columns: {
    +  70        cssClass: '.hs-column-layout',
    +  71        fields: ['top', 'bottom', 'left', 'right', 'height', 'width']
    +  72    },
    +  73    rows: {
    +  74        cssClass: '.hs-row-layout',
    +  75        fields: ['left', 'right', 'top', 'bottom', 'width', 'height']
    +  76    }
    +  77};
    +  78
    +  79type descriptor = {size:number, code:string, fields:{}};
    +  80
    +  81/**
    +  82 * Abstract base Layouter for creating PillarLayouter (rows, colums)
    +  83 */

    +  84abstract class PillarLayouter extends Layouter{
    +  85    firstFixed: number; // number of DefinedToken entries at the beginning
    +  86    lastFixed:  number; // number of DefinedToken entries at the end
    +  87    unit:(num:number)=>descriptor[];
    +  88    fields: string[];
    +  89    cssClass:string;
    +  90
    +  91    /**
    +  92     * Constructs a Pillared layout (rows or columns).
    +  93     * Determines the `unit` (% or px) from the passed area descriptors
    +  94     * @param params Style params for either rows or columns layout
    +  95     * @param areaDesc Description of the requested layout 
    +  96     */

    +  97    constructor(params:PillarParams, public areaDesc:LayoutToken[]) { 
    +  98        super(areaDesc); 
    +  99        this.fields = params.fields;
    + 100        this.cssClass = params.cssClass;
    + 101
    + 102        let n = areaDesc.length-1;
    + 103        let first = 0;
    + 104        let last  = 0;        
    + 105        // if any of the dimensions are in px, use the pixel method; else use the percent method
    + 106        this.unit = areaDesc.some((area:LayoutToken) => (area instanceof PixelToken))? 
    + 107            this.unitPixel : this.unitPercent;   
    + 108        
    + 109        // determine first = number of consecutive fixed fields at start
    + 110        areaDesc.some((area:LayoutToken, i:number) => 
    + 111            ((areaDesc[i]   instanceof DefinedToken)? ++first<0 : true));         
    + 112
    + 113        // determine last  = number of consecutive fixed fields at end
    + 114        areaDesc.some((area:LayoutToken, i:number) => 
    + 115            ((areaDesc[n-i] instanceof DefinedToken)? ++last<0  : true));         
    + 116
    + 117        this.firstFixed = first;
    + 118        this.lastFixed  = Math.min(last, areaDesc.length-first);
    + 119    };
    + 120
    + 121    // num: number of areas to layout
    + 122    /**
    + 123     * Creates an iterable list of size descriptors, one for each area to be layed out.
    + 124     * Each descriptor 
    + 125     * @param num the number of areas to be layed out
    + 126     * @return Iterable list of `num` size descriptors, one for each area to be layed out
    + 127     */

    + 128    private getSizes(num:number):descriptor[] {
    + 129        const first = this.firstFixed;
    + 130        const last  = this.lastFixed;
    + 131        const desc  = this.areaDesc;
    + 132        const len = desc.length;
    + 133
    + 134        return [...Array(num).keys()].map((i:number) => {
    + 135            let size:number = null;
    + 136            let t = null;
    + 137            if (i > num-1-last)  { size = desc[len - (num-i)].getSize(); t = 'end'; }       // end sequence
    + 138            else if (i < first)  { size = desc[i].getSize(); t = 'start'; }                 // start sequence
    + 139            else if (len>0 && len===first){ size = desc[len-1].getSize(); t = 'start'; }    // all items 
    + 140            return {size:size, code:t, fields:{}};
    + 141        });
    + 142    }
    + 143
    + 144    private unitPercent(num:number):descriptor[] {
    + 145        let f = this.fields;
    + 146        let max = 100.0;
    + 147        let styles:descriptor[] = this.getSizes(num);
    + 148
    + 149        styles.forEach(style => { if (style.size) { max = max - style.size; num--; } });
    + 150        let defDim = max / num;      // divvy up remaining space
    + 151
    + 152        function pass(styles:descriptor[], ix0:string, ix1:string, breakCond:(cond:string)=>boolean) {
    + 153            let sumDim = 0;
    + 154            styles.some(style => { // stop when breakCond is met
    + 155                let size = style.size || defDim;
    + 156                if (breakCond(style.code)) { return true; }
    + 157                style.fields[ix0] = sumDim+'%';
    + 158                sumDim += size;
    + 159                style.fields[ix1] = (100-sumDim)+'%'; 
    + 160                style.fields[f[5]] = 'auto';
    + 161                return false;
    + 162            });
    + 163        }
    + 164
    + 165        pass(styles, f[2], f[3], (e:string) => e==='end');              // forward pass
    + 166        pass(styles.reverse(), f[3], f[2], (e:string) => e!=='end');    // backward pass
    + 167        return styles.reverse();    // reverse a second time for original sequence.
    + 168    };
    + 169
    + 170    private unitPixel(num:number):descriptor[] { // pattern: [px, px, FILL , px, px]
    + 171        let styles:descriptor[] = this.getSizes(num);
    + 172        let f = this.fields;
    + 173       
    + 174        let defDim = 100.0/num;          // used for unspecified widths
    + 175
    + 176        // work forwards through the heights
    + 177        let sumDim = 0;
    + 178        styles.some((style, i) => {
    + 179            if (style.code==='start') {   // so far, all heights explicitly set as px
    + 180                style.fields[f[2]] = sumDim +'px';
    + 181                sumDim += style.size + (this.spacing || 0) + (this.spacing || 0);
    + 182                style.fields[f[3]] = 'auto';
    + 183                style.fields[f[5]] = style.size +'px';
    + 184            } else if (style.code === null) {
    + 185                style.fields[f[2]] = (sumDim>0)? (sumDim +'px') : (i*defDim + '%');
    + 186                sumDim = -1;
    + 187                style.fields[f[3]] = (100-(i+1)*defDim) + '%';
    + 188                style.fields[f[5]] = 'auto';
    + 189            } else if (style.code==='end') { return true; }
    + 190            return false;
    + 191        });
    + 192        
    + 193        // work backwards through the heights
    + 194        sumDim = 0;
    + 195        styles.slice().reverse().some((style, i) => {
    + 196            style.fields[f[3]] = sumDim + 'px';
    + 197            if (style.code === 'end') { 
    + 198                sumDim += style.size + (this.spacing || 0) + (this.spacing || 0);
    + 199                style.fields[f[2]] = 'auto';
    + 200                style.fields[f[5]] = style.size+'px';
    + 201            } else {
    + 202                if (sumDim>0 && style.code !== 'start') {
    + 203                    style.fields[f[5]] = 'auto';
    + 204                }
    + 205                return true; 
    + 206            } 
    + 207            return false;
    + 208        });  
    + 209        return styles;
    + 210    };
    + 211    
    + 212    /**
    + 213     * Calculates the style attributes required for each component in `Components`.
    + 214     * These attributes are saved in a `styles` field on the component itself. 
    + 215     * During rendering these `styles` attributes are copied to the `node.attrs.styles` field.
    + 216     * @param components 
    + 217     */

    + 218    protected getStyles(components:Array):string  { 
    + 219        let f = this.fields;
    + 220        let styles:descriptor[] = this.unit(components.length);
    + 221        components.map((c:Layout|Vnode, i:number) => {
    + 222            c.style = `${f[0]}:0%; ${f[1]}:0%; `;
    + 223            Object.keys(styles[i].fields).forEach((st:string) => { c.style += `${st}: ${styles[i].fields[st]};`; });
    + 224        });   
    + 225        return this.cssClass;
    + 226    };
    + 227};
    + 228
    + 229/**
    + 230 * Constructs a columns pillar layout style.

    + 231 * Use `{columns: [attributes]}` to invoke this layout. See top of page for a description.
    + 232 * 
    + 233 * 
    + 234 * const styles = [ 
    + 235 *     [],                // equal spacing
    + 236 *     ["100px"],         // fixed spacing
    + 237 *     ["60px", "100px"], // fixed spacing, first one smaller
    + 238 *     ["100px", "fill"], // first one fixed, rest equal
    + 239 *     ["fill", "100px"], // last one fixed, rest equal
    + 240 *     ["20%"],           // relative spacing, all equal
    + 241 *     ["20%", "fill"],   // first relative, rest equal
    + 242 *     ["fill", "20%"]    // last relative, rest equal
    + 243 * ];
    + 244 * let c = [];
    + 245 * m.mount(root, { 
    + 246 *     view:() => m(hslayout.Layout, {
    + 247 *         rows:[],  // each row a style
    + 248 *         content: styles.map(i => m(hslayout.Layout, {
    + 249 *             css: '.myExample', 
    + 250 *             content: c.map(c=>(''+i)), // the style descriptor
    + 251 *             columns: i                 // a style from styles
    + 252 *         }))
    + 253 *     })
    + 254 * });
    + 255 * function next() {
    + 256 *     if (c.length >= 5) { c = []; }
    + 257 *     else { c.push(''); }
    + 258 *     setTimeout(next, 2000);
    + 259 *     m.redraw();
    + 260 * }
    + 261 * 
    + 262 * next();
    + 263 * 
    + 264 * 
    + 265 * .hs-row-layout>.myExample { 
    + 266 *     border-top:    1px solid white;
    + 267 *     border-bottom: 1px solid white;
    + 268 * }
    + 269 * .myExample>.hs-layout {
    + 270 *     border:    1px solid white;
    + 271 *     background-color: #ccc;
    + 272 * }
    + 273 * .myExample { 
    + 274 *     color:       #a44; 
    + 275 *     font-weight: bold; 
    + 276 *     text-align:  center;
    + 277 * }
    + 278 * 
    + 279 * 

    + 280 */

    + 281class Columns extends PillarLayouter {
    + 282    constructor(public areaDesc:LayoutToken[]) { super(cParams[PillarLayouts[0]], areaDesc);  };
    + 283};
    + 284
    + 285/**
    + 286 * Constructs a row pillar layout style.

    + 287 * Use `{row: [attributes]}` to invoke this layout. See top of page for a description.
    + 288 * 
    + 289 * 
    + 290 * const styles = [ 
    + 291 *     [],                // equal spacing
    + 292 *     ["100px"],         // fixed spacing
    + 293 *     ["60px", "100px"], // fixed spacing, first one smaller
    + 294 *     ["100px", "fill"], // first one fixed, rest equal
    + 295 *     ["fill", "100px"], // last one fixed, rest equal
    + 296 *     ["20%"],           // relative spacing, all equal
    + 297 *     ["20%", "fill"],   // first relative, rest equal
    + 298 *     ["fill", "20%"]    // last relative, rest equal
    + 299 * ];
    + 300 * let c = [];
    + 301 * function next() {
    + 302 *     if (c.length >= 5) { c = []; }
    + 303 *     else { c.push(''); }
    + 304 *     setTimeout(next, 2000);
    + 305 *     m.redraw();
    + 306 * }
    + 307 * 
    + 308 * m.mount(root, { 
    + 309 *     view:() => m(hslayout.Layout, {
    + 310 *         columns:[],  // each column a style
    + 311 *         content: styles.map(i => m(hslayout.Layout, {
    + 312 *             css: '.myExample', 
    + 313 *             content: c.map(c=>(''+i)),
    + 314 *             rows: i   // a style from styles
    + 315 *         }))
    + 316 *     })
    + 317 * });
    + 318 * next();
    + 319 * 
    + 320 * 
    + 321 * .hs-column-layout>.myExample {
    + 322 *     border-left:  1px solid white;
    + 323 *     border-right: 1px solid white;
    + 324 * }
    + 325 * .myExample>.hs-layout {
    + 326 *     border:    1px solid white;
    + 327 *     background-color: #ccc;
    + 328 * }
    + 329 * .myExample { 
    + 330 *     color:       #a44; 
    + 331 *     font-weight: bold; 
    + 332 *     text-align:  center;
    + 333 * }
    + 334 * 
    + 335 * 

    + 336 */

    + 337class Rows extends PillarLayouter {
    + 338    constructor(public areaDesc:LayoutToken[]) { super(cParams[PillarLayouts[1]], areaDesc);  };
    + 339};
    + 340
    + 341Layouter.register(PillarLayouts[0], Columns);
    + 342Layouter.register(PillarLayouts[1],    Rows);
    + 343
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/PillaredLayouter.spec.html b/docs/src/hsLayout/view/PillaredLayouter.spec.html new file mode 100644 index 0000000..740ecf9 --- /dev/null +++ b/docs/src/hsLayout/view/PillaredLayouter.spec.html @@ -0,0 +1,101 @@ + + +

    view/PillaredLayouter.spec.ts

    +
       1
    +   2const hslayout = require('../src/');
    +   3const m = hslayout.m;
    +   4const o = hslayout.o;
    +   5
    +   6
    +   7const columns = ["150px", "fill"];
    +   8const titles  = ['Left Column: 150px', 'Right Column: remainder'];
    +   9
    +  10
    +  11o.spec('rows', () => {
    +  12    let rows:any;
    +  13    o.before(() => {
    +  14        m.mount(o.root, {view: () => m(hslayout.Layout, {
    +  15            css: 'myRow',
    +  16            rows: columns,
    +  17            content: titles
    +  18            })
    +  19        }); 
    +  20        rows = o.root.childNodes[0];
    +  21    }); 
    +  22    o('first level', () => {
    +  23        o(rows===undefined).equals(false)('should be defined');
    +  24        o(rows.className.includes('myRow')).equals(true)(`class myRow in '${rows.className}'`);
    +  25        o(rows.className.includes('hs-row-layout')).equals(true)(`class hs-row-layout in '${rows.className}'`);
    +  26        o(rows.childNodes.length).equals(2)(`has ${rows.childNodes.length} children`);
    +  27    });
    +  28
    +  29    o('second level', () => {
    +  30        rows.childNodes.forEach((c:any, i:number) => {
    +  31            o(c.className.includes('hs-layout')).equals(true)(`class hs-layout in '${c.className}'`);
    +  32            o(c.style.left).equals('0%')(`style left`);
    +  33            o(c.style.right).equals('0%')(`style right`);
    +  34            o(c.style.top).equals((i===0)?'0px':columns[0])(`style top`);
    +  35            o(c.style.bottom).equals((i===0)?'auto':'0px')(`style bottom`);
    +  36            o(c.style.height).equals((i===0)?columns[0]:'auto')(`style height`);
    +  37            o(c.childNodes.length).equals(1)(`has ${c.childNodes.length} children`);
    +  38        });
    +  39    });
    +  40    o('third level', () => {
    +  41        rows.childNodes.forEach((c:any, i:number) => {
    +  42            o(c.childNodes[0].className.includes('hs-leaf')).equals(true)(`class hs-leaf in '${c.childNodes[0].className}'`);
    +  43            o(c.childNodes[0].childNodes[0].nodeValue).equals(titles[i])(`item ${i+1} child leaf text`);
    +  44        });
    +  45    });
    +  46});
    +  47
    +  48o.spec('columns', () => {
    +  49    let rows:any;
    +  50    o.before(() => {
    +  51        m.mount(o.root, {view: () => m(hslayout.Layout, {
    +  52            css: 'myColumn',
    +  53            columns: columns,
    +  54            content: titles
    +  55            })
    +  56        }); 
    +  57        rows = o.root.childNodes[0];
    +  58    }); 
    +  59    o('first level', () => {
    +  60        o(rows===undefined).equals(false)('should be defined');
    +  61        o(rows.className.includes('myColumn')).equals(true)(`class myColumn in '${rows.className}'`);
    +  62        o(rows.className.includes('hs-column-layout')).equals(true)(`class hs-column-layout in '${rows.className}'`);
    +  63        o(rows.childNodes.length).equals(2)(`has ${rows.childNodes.length} children`);
    +  64    });
    +  65
    +  66    o('second level', () => {
    +  67        rows.childNodes.forEach((c:any, i:number) => {
    +  68            o(c.className.includes('hs-layout')).equals(true)(`class hs-layout in '${c.className}'`);
    +  69            o(c.style.top).equals('0%')(`style top`);
    +  70            o(c.style.bottom).equals('0%')(`style bottom`);
    +  71            o(c.style.left).equals((i===0)?'0px':columns[0])(`style left`);
    +  72            o(c.style.right).equals((i===0)?'auto':'0px')(`style right`);
    +  73            o(c.style.width).equals((i===0)?columns[0]:'auto')(`style width`);
    +  74            o(c.childNodes.length).equals(1)(`has ${c.childNodes.length} children`);
    +  75        });
    +  76    });
    +  77    o('third level', () => {
    +  78        rows.childNodes.forEach((c:any, i:number) => {
    +  79            o(c.childNodes[0].className.includes('hs-leaf')).equals(true)(`class hs-leaf in '${c.childNodes[0].className}'`);
    +  80            o(c.childNodes[0].childNodes[0].nodeValue).equals(titles[i])(`item ${i+1} child leaf text`);
    +  81        });
    +  82    });
    +  83});
    +  84
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/TileLayout.html b/docs/src/hsLayout/view/TileLayout.html new file mode 100644 index 0000000..ae1a08d --- /dev/null +++ b/docs/src/hsLayout/view/TileLayout.html @@ -0,0 +1,156 @@ + + +

    view/TileLayout.ts

    +
       1/**
    +   2Lays out components in tiles
    +   3Use 
    +   4- `{tiles: [attributes]}`
    +   5
    +   6to invoke this layout.
    +   7
    +   8### Example
    +   9
    +  10    {tiles: ["20%]}   // --> tiles will all have 20% of available height and width 
    +  11

    +  12 * 
    +  13 * 
    +  14 * let c = [1,2,3,4,5];
    +  15 * 
    +  16 * m.mount(root, { 
    +  17 *     view:() => m(hslayout.Container, {
    +  18 *         tiles:[], 
    +  19 *         content: c.map((c,i)=>(''+i)),
    +  20 *         css: '.myExample'
    +  21 *     })
    +  22 * });
    +  23 *
    +  24 * function next() {
    +  25 *     if (c.length >= 9) { c = []; }
    +  26 *     else { c.push(''); }
    +  27 *     setTimeout(next, 2000);
    +  28 *     m.redraw();
    +  29 * }
    +  30 * next();
    +  31 * 
    +  32 * 
    +  33 * .myExample .hs-layout { 
    +  34 *     border: 1px solid white;
    +  35 *     background-color: #ccc;
    +  36 *     color:       #a44; 
    +  37 *     text-align:  center;
    +  38 * }
    +  39 * 
    +  40 * 

    +  41
    +  42## Attributes
    +  43The following values **v** are valid entries in The Attributes array:
    +  44- **px(n)** or **"_n_ px"** -- a fixed number of pixels 
    +  45- **pc(n)** or **"_n_ %"**  -- a fixed percentage of available space
    +  46- **FILL** or **"fill"**   -- a special constant to indicate - may appear only once per array.
    +  47
    +  48The following options are supported for the Attributes array:
    +  49- **[ ]**: An empty array; The available tiles will cover the entire width and height. 
    +  50    Their size will adapt as tiles are added.
    +  51- **[FILL]**: like [ ], except the last tile fills the available space. 
    +  52- **[v]**: All components have the specified width and height (in px or %) and will fill the available space from the left,
    +  53    leaving any remaining unused space on the right. 
    +  54- **[w, h]**: All components have the specified width w and height h (in px or %) and will fill the available space from the left,
    +  55    leaving any remaining unused space on the right. 
    +  56- **[v, FILL]**: like [v], except that the last tile in each row will fill the remaining available width 
    +  57    and the tiles in the bottom row will fill the remaining height
    +  58- **[w, h, FILL]**: like [w, h], except that the last tile will fill the remaining available width. 
    +  59 */

    +  60/** */
    +  61import { Container }    from './Container';
    +  62import { Layout }       from './Layout';
    +  63import { LayoutToken, FillToken, DefinedToken, PixelToken }    from './Tokens';
    +  64import { Vnode}         from '../mithril';
    +  65
    +  66type descriptor = {top:string, left:string, right:string, bottom:string, width:string, height:string};
    +  67
    +  68/**
    +  69 */

    +  70class Tiles extends Layout {
    +  71    cssClass:string;
    +  72    unit: any;
    +  73
    +  74    /**
    +  75     * Constructs a Pillared layout (rows or columns)
    +  76     * @param params Style params for either rows or columns layout
    +  77     * @param areaDesc Description of the requested layout 
    +  78     */

    +  79    constructor(public areaDesc:LayoutToken[]) { 
    +  80        super(areaDesc); 
    +  81        // if any of the dimensions are in px, use the pixel method; else use the percent method
    +  82        // get unitPixel if any area is PixelToken           
    +  83        this.unit = areaDesc.some((area:LayoutToken) => (area instanceof PixelToken))? 
    +  84            this.unitPixel : this.unitPercent;           
    +  85    };
    +  86
    +  87    private unitPercent(num:number) {
    +  88        const desc = this.areaDesc;
    +  89        const fill = this.areaDesc.some(a => (a instanceof FillToken));
    +  90        const root = Math.sqrt(num);
    +  91        const rows = Math.round(root);
    +  92        let   cols = Math.floor(root);
    +  93        if (root > cols) { cols++; }
    +  94        let width  = (desc[0] instanceof DefinedToken)? desc[0].getSize() : undefined;
    +  95        let height = (desc[1] instanceof DefinedToken)? desc[1].getSize() : width;
    +  96
    +  97        width  = width  || 100/cols;
    +  98        height = height || 100/rows;
    +  99        let left = 0;
    + 100        let top  = 0;
    + 101
    + 102
    + 103        let styles = [...Array(num).keys()].map(i => { 
    + 104            let r = 'auto';    let w = width+'%'; 
    + 105            let b = 'auot';    let h = height+'%';
    + 106            if ((left + 2*width) > 100 && fill) { r = '0%'; w = 'auto'; }
    + 107            if ((top + 2*height) > 100 && fill) { b = '0%'; h = 'auto'; }
    + 108            const style = `
    + 109                top: ${Math.floor(top)}%; bottom:${b};
    + 110                left: ${left}%;           right:${r};
    + 111                width: ${w};              height: ${h};
    + 112            `;
    + 113            if (Math.round(left += width) > 100-Math.floor(width)) { left = 0; top += height; }
    + 114            return style;
    + 115         });
    + 116        return styles;    // reverse a second time for original sequence.
    + 117    };
    + 118
    + 119    private unitPixel(num:number) { // pattern: [px, px, FILL]
    + 120    };
    + 121    
    + 122    /**
    + 123     * Calculates the style attributes required for each component in `Components`.
    + 124     * These attributes are saved in a `styles` field on the component itself. 
    + 125     * During rendering these `styles` attributes are copied to the `node.attrs.styles` field.
    + 126     * @param components 
    + 127     */

    + 128    protected getStyles(components:Array):string  { 
    + 129        let styles = this.unit(components.length);
    + 130        components.map((c:Container|Vnode, i:number) => {
    + 131            c.style = styles[i];
    + 132        });   
    + 133        return '.hs-tile-layout';
    + 134    };
    + 135};
    + 136
    + 137
    + 138Layout.register('tiles', Tiles);
    + 139
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/TileLayouter.html b/docs/src/hsLayout/view/TileLayouter.html new file mode 100644 index 0000000..e63e4bb --- /dev/null +++ b/docs/src/hsLayout/view/TileLayouter.html @@ -0,0 +1,180 @@ + + +

    view/TileLayouter.ts

    +
       1/**
    +   2Lays out components in tiles
    +   3Use 
    +   4- `{tiles: [attributes]}`
    +   5
    +   6to invoke this layout.
    +   7
    +   8### Example
    +   9
    +  10    {tiles: ["20%"]}   // --> tiles will all have 20% of available height and width 
    +  11

    +  12 * 
    +  13 * 
    +  14 * let c = [1,2,3,4,5];
    +  15 * 
    +  16 * m.mount(root, { 
    +  17 *     view:() => m(hslayout.Layout, {
    +  18 *         tiles:[], 
    +  19 *         content: c.map((c,i)=>(''+i)),
    +  20 *         css: '.myExample'
    +  21 *     })
    +  22 * });
    +  23 *
    +  24 * function next() {
    +  25 *     if (c.length >= 9) { c = []; }
    +  26 *     else { c.push(''); }
    +  27 *     setTimeout(next, 2000);
    +  28 *     m.redraw();
    +  29 * }
    +  30 * next();
    +  31 * 
    +  32 * 
    +  33 * .myExample .hs-layout { 
    +  34 *     border: 1px solid white;
    +  35 *     background-color: #ccc;
    +  36 *     color:       #a44; 
    +  37 *     text-align:  center;
    +  38 * }
    +  39 * 
    +  40 * 

    +  41
    +  42## Attributes
    +  43The following values **v** are valid entries in The Attributes array:
    +  44- **px(n)** or **"_n_ px"** -- a fixed number of pixels 
    +  45- **pc(n)** or **"_n_ %"**  -- a fixed percentage of available space
    +  46- **FILL** or **"fill"**   -- a special constant indicate to fill remaining space - may appear only once per array.
    +  47
    +  48The following options are supported for the Attributes array:
    +  49- **[ ]**: An empty array; The available tiles will cover the entire width and height. 
    +  50    Their size will adapt as tiles are added.
    +  51- **[FILL]**: like [ ], except the last tile fills the available space. 
    +  52- **[v]**: All components have the specified width and height (in px or %) and will fill the available space from the left,
    +  53    leaving any remaining unused space on the right. 
    +  54- **[w, h]**: All components have the specified width w and height h (in px or %) and will fill the available space from the left,
    +  55    leaving any remaining unused space on the right. 
    +  56- **[v, FILL]**: like [v], except that the last tile in each row will fill the remaining available width 
    +  57    and the tiles in the bottom row will fill the remaining height
    +  58- **[w, h, FILL]**: like [w, h], except that the last tile will fill the remaining available width. 
    +  59 */

    +  60/** */
    +  61import { Layout }    from './Layout';
    +  62import { Layouter }       from './Layouter';
    +  63import { LayoutToken, FillToken, DefinedToken, PixelToken }    from './Tokens';
    +  64import { Vnode}         from '../mithril';
    +  65
    +  66type descriptor = {top:string, left:string, right:string, bottom:string, width:string, height:string};
    +  67
    +  68/**
    +  69 */

    +  70class Tiles extends Layouter {
    +  71    cssClass:string;
    +  72    unit: any;
    +  73
    +  74    /**
    +  75     * Constructs a Tileds layout
    +  76     * @param areaDesc Description of the requested layout 
    +  77     */

    +  78    constructor(public areaDesc:LayoutToken[]) { 
    +  79        super(areaDesc); 
    +  80        // if any of the dimensions are in px, use the pixel method; else use the percent method
    +  81        // get unitPixel if any area is PixelToken           
    +  82        this.unit = areaDesc.some((area:LayoutToken) => (area instanceof PixelToken))? 
    +  83            this.unitPixel : this.unitPercent;           
    +  84    };
    +  85
    +  86    private unitPercent(num:number) {
    +  87        const desc = this.areaDesc;
    +  88        const fill = this.areaDesc.some(a => (a instanceof FillToken));
    +  89        const root = Math.sqrt(num);
    +  90        const rows = Math.round(root);
    +  91        let   cols = Math.floor(root);
    +  92        if (root > cols) { cols++; }
    +  93        let width  = (desc[0] instanceof DefinedToken)? desc[0].getSize() : undefined;
    +  94        let height = (desc[1] instanceof DefinedToken)? desc[1].getSize() : width;
    +  95
    +  96        width  = width  || 100/cols;
    +  97        height = height || 100/rows;
    +  98        let left = 0;
    +  99        let top  = 0;
    + 100
    + 101        let styles = [...Array(num).keys()].map(i => { 
    + 102            let r = 'auto';    let w = width+'%'; 
    + 103            let b = 'auto';    let h = height+'%';
    + 104            if ((left + 2*width) > 100 && fill) { r = '0%'; w = 'auto'; }
    + 105            if ((top + 2*height) > 100 && fill) { b = '0%'; h = 'auto'; }
    + 106            const style = `
    + 107                top: ${Math.floor(top)}%; bottom:${b};
    + 108                left: ${left}%;           right:${r};
    + 109                width: ${w};              height: ${h};
    + 110            `;
    + 111            if (Math.round(left += width) > 100-Math.floor(width)) { left = 0; top += height; }
    + 112            return style;
    + 113         });
    + 114        return styles;    
    + 115    };
    + 116
    + 117    private unitPixel(num:number) { // pattern: [px, px, FILL]
    + 118        const desc = this.areaDesc;
    + 119//        const fill = this.areaDesc.some(a => (a instanceof FillToken));
    + 120        const root = Math.sqrt(num);
    + 121        const rows = Math.round(root);
    + 122        let   cols = Math.floor(root);
    + 123        if (root > cols) { cols++; }
    + 124        let width  = (desc[0] instanceof DefinedToken)? desc[0].getSize() : undefined;
    + 125        let height = (desc[1] instanceof DefinedToken)? desc[1].getSize() : width;
    + 126
    + 127        width  = width  || 100/cols;
    + 128        height = height || 100/rows;
    + 129        let left = 0;
    + 130        let top  = 0;
    + 131
    + 132        let styles = [...Array(num).keys()].map(i => { 
    + 133            let r = 'auto';    let w = width+'px'; 
    + 134            let b = 'auto';    let h = height+'px';
    + 135            const style = `
    + 136                top: ${Math.floor(top)}%; bottom:${b};
    + 137                left: ${left}%;           right:${r};
    + 138                width: ${w};              height: ${h};
    + 139            `;
    + 140            if (Math.round(left += width) > 100-Math.floor(width)) { left = 0; top += height; }
    + 141            return style;
    + 142         });
    + 143        return styles;    
    + 144    };
    + 145    
    + 146    /**
    + 147     * Calculates the style attributes required for each component in `Components`.
    + 148     * These attributes are saved in a `styles` field on the component itself. 
    + 149     * During rendering these `styles` attributes are copied to the `node.attrs.styles` field.
    + 150     * @param components 
    + 151     */

    + 152    protected getStyles(components:Array):string  { 
    + 153        let styles = this.unit(components.length);
    + 154        components.map((c:Layout|Vnode, i:number) => {
    + 155            c.style = styles[i];
    + 156        });   
    + 157        return '.hs-tile-layout';
    + 158    };
    + 159};
    + 160
    + 161
    + 162Layouter.register('tiles', Tiles);
    + 163
    + + \ No newline at end of file diff --git a/docs/src/hsLayout/view/Tokens.html b/docs/src/hsLayout/view/Tokens.html new file mode 100644 index 0000000..3fdda1d --- /dev/null +++ b/docs/src/hsLayout/view/Tokens.html @@ -0,0 +1,75 @@ + + +

    view/Tokens.ts

    +
       1/**
    +   2 * ## Layout Tokens
    +   3 * Used to specify layout sizes
    +   4 */

    +   5
    +   6/**
    +   7 * Abstract token for a layout area. It is defined by a single number available via the constructor. 
    +   8 */

    +   9export abstract class LayoutToken {
    +  10    constructor(private size: number) {}
    +  11    public getSize() { return this.size; }
    +  12}
    +  13
    +  14/**
    +  15 * A layout token that is defined in size.
    +  16 */

    +  17export abstract class DefinedToken extends LayoutToken{
    +  18    constructor(size: number) { super(size); } 
    +  19}
    +  20
    +  21/**
    +  22 * A layout token that is undefined in size, and that fill will     the available space.
    +  23 */

    +  24export class FillToken extends LayoutToken {
    +  25    constructor() { super(-1); }
    +  26}
    +  27
    +  28/**
    +  29 * A defined token that sets a size in pixel.
    +  30 */

    +  31export class PixelToken extends DefinedToken {
    +  32    constructor(size:number) { super(size); }
    +  33}
    +  34
    +  35/**
    +  36 * A defined token that sets a size in percent of available space.
    +  37 */

    +  38export class PercentToken extends DefinedToken {
    +  39    constructor(size:number) { super(size); }
    +  40}
    +  41
    +  42/**
    +  43 * A convenience function that returns a defined pixel-sized token
    +  44 * @param px the number of pixels in the token
    +  45 */

    +  46export function px(px:number)   { return new PixelToken(px); }
    +  47
    +  48/**
    +  49 * A convenience function that returns a defined percent-sized token
    +  50 * @param pc the percentage in the token
    +  51 */

    +  52export function pc(pc:number)   { return new PercentToken(pc); }
    +  53
    +  54/**
    +  55 * Convenience constant, standing for an undefined fill token.
    +  56 */

    +  57export const FILL = new FillToken();
    +  58
    + + \ No newline at end of file diff --git a/docs/src/hsNode/cpUtil.html b/docs/src/hsNode/cpUtil.html new file mode 100644 index 0000000..de4df02 --- /dev/null +++ b/docs/src/hsNode/cpUtil.html @@ -0,0 +1,59 @@ + + +

    cpUtil.ts

    +
       1const cp    = require('child_process');
    +   2import { log } from './';
    +   3
    +   4/**
    +   5 * @ngdoc object
    +   6 * @name hsNode.cpUtil
    +   7 * @description Convenience functions for child process access, wrapped in Promises.
    +   8 * - {@link hsNode.cpUtil#methods_exec exec}
    +   9 */

    +  10
    +  11//===============================================================================
    +  12//  Low level Promise wrappers
    +  13 
    +  14/**
    +  15 * @ngdoc object
    +  16 * @name exec
    +  17 * @methodOf hsNode.cpUtil
    +  18 * @description executes `command` in a child process and promises to return the stdout and stderr streams.
    +  19 

    +  20        let utils = require('./cpUtils');
    +  21        utils.exec(cmd)
    +  22            .then((stdout, stderr) => {...})
    +  23            .catch(err => {...});
    +  24

    +  25 * @param {string} command the shell command to execute
    +  26 * @param {object} options the options to pass along to the shell
    +  27 * @return {Promise} promise to provide the stdout and stderr streams form the child process.
    +  28 */

    +  29function exec(command:string, options?:any) {
    +  30    return new Promise((resolve:(result:{out:string, err:string})=>void, reject:(e:string)=>void) => {
    +  31        cp.exec(command, options, (error:string, stdout:string, stderr:string) => {
    +  32            if (error) {
    +  33     log.error('exec for ' + command + ': ' + error);
    +  34                reject(error);
    +  35            } else {
    +  36                resolve({out:stdout, err:stderr});
    +  37            }
    +  38        });
    +  39    });
    +  40}
    +  41
    +  42export { exec };
    + + \ No newline at end of file diff --git a/docs/src/hsNode/cpUtil.spec.html b/docs/src/hsNode/cpUtil.spec.html new file mode 100644 index 0000000..634870f --- /dev/null +++ b/docs/src/hsNode/cpUtil.spec.html @@ -0,0 +1,80 @@ + + +

    cpUtil.spec.ts

    +
       1import { exec } from './';
    +   2
    +   3
    +   4describe("cpUtil", () => {
    +   5    let cpOut:string, cpErr:string, cpE:string;
    +   6    const helper = {
    +   7        out: (out:string, err:string) => { cpOut = out; cpErr = err; },
    +   8        err: (e:string) => { cpE = e; }
    +   9    };
    +  10
    +  11    function call(cmd:string, done:any) {
    +  12        exec(cmd)
    +  13            .then((result:{out:string, err:string}) => { helper.out(result.out, result.err); done(); })
    +  14            .catch((e:string) => { helper.err(e); done(); });
    +  15    }
    +  16
    +  17    beforeEach(() => {
    +  18        cpE = cpErr = cpOut = undefined;
    +  19        spyOn(helper, 'out').and.callThrough();
    +  20        spyOn(helper, 'err').and.callThrough();
    +  21    });
    +  22
    +  23    describe('valid command', () => {
    +  24        beforeEach(done => { call("pwd", done);
    +  25//            cp.exec("pwd")
    +  26//                .then((result:{out:string, err:string}) => { helper.out(result.out, result.err); done(); })
    +  27//                .catch((e:string) => { helper.err(e); done(); });
    +  28        });
    +  29
    +  30        it('should execute "pwd" in a shell without error', done => {
    +  31            expect(helper.out).toHaveBeenCalled();
    +  32            expect(helper.err).not.toHaveBeenCalled();
    +  33            done();
    +  34        });
    +  35
    +  36        it('should result in path', () => {
    +  37            expect(cpOut.trim().endsWith('/hsNode')).toEqual(true);
    +  38            expect(cpE).not.toBeDefined();
    +  39            expect(cpErr).toBe('');
    +  40        });  
    +  41    });
    +  42
    +  43    describe('invalid command', () => {
    +  44        beforeEach(done => { call("abcd", done);
    +  45//            cp.exec("abcd")
    +  46//                .then((result:{out:string, err:string}) => { helper.out(result.out, result.err); done(); })
    +  47//                .catch((e:string) => { helper.err(e); done(); });
    +  48        });
    +  49
    +  50        it('should fail executing "abcd" in a shell', done => {
    +  51            expect(helper.out).not.toHaveBeenCalled();
    +  52            expect(helper.err).toHaveBeenCalled();
    +  53            done();
    +  54        });
    +  55
    +  56        it('should result in error', () => {
    +  57            expect(cpOut).not.toBeDefined();
    +  58            expect(cpErr).not.toBeDefined();
    +  59            expect(cpE).toMatch('abcd: command not found');
    +  60        });  
    +  61    });
    +  62});
    +  63
    + + \ No newline at end of file diff --git a/docs/src/hsNode/date.html b/docs/src/hsNode/date.html new file mode 100644 index 0000000..0e147bc --- /dev/null +++ b/docs/src/hsNode/date.html @@ -0,0 +1,89 @@ + + +

    date.ts

    +
       1/**
    +   2 * @ngdoc object
    +   3 * @name hsNode.date
    +   4 * @description .
    +   5 * ### Date formatting support. 
    +   6 * Formats are specified in a printf-style format string. 
    +   7 * ### Example:
    +   8 * 

    +   9 * import date  from './date';
    +  10 * date('%MM/%DD/%YY');           // -> 08/17/16 (using current date)
    +  11 * let d = new Date('7/4/2010');
    +  12 * date('%DDDD, %MM/%DD/%YY', d); // -> Sunday, 07/04/10
    +  13 * 

    +  14 * ### Supported Formats
    +  15- `%YY, %YYYY`           : two- or four-digit year, as '73', '1973'
    +  16- `%M, %MM, %MMM, %MMMM` : month of year as '2', '02', 'Feb', 'February'
    +  17- `%D, %DD`              : day of month as '5', '05' (1...31)
    +  18- `%DDD, %DDDD`          : day of week as 'Tue', 'Tuesday'
    +  19- `%h, %hh`              : hour of day as '7', '07 (0...23)
    +  20- `%m, %mm`              : minutes as '6', '06' (0..59)
    +  21- `%ss`                  : seconds as '09' (0...59)
    +  22- `%j, %jj, %jjj`        : milliseconds as '1', '15', '159'
    +  23 */

    +  24
    +  25/** translates short month names to full month names */
    +  26const monthStr = [
    +  27    ['Jan', 'January'], ['Feb', 'February'], ['Mar', 'March'], ['Apr', 'April'], ['May', 'May'], ['Jun', 'June'],
    +  28    ['Jul', 'July'], ['Aug', 'August'], ['Sep', 'September'], ['Oct', 'October'], ['Nov', 'November'], ['Dec', 'December']];
    +  29
    +  30/** translates short day names to full day names */
    +  31const dayStr = [
    +  32    ['Sun', 'Sunday'],['Mon', 'Monday'],['Tue', 'Tuesday'],['Wed', 'Wednesday'],['Thu', 'Thursday'],['Fri', 'Friday'],['Sat', 'Saturday']];
    +  33
    +  34/**
    +  35 * left-pads a `number` with zeros to match `minDigits` minimum digits
    +  36 */

    +  37function formatNumber(number:number, minDigits:number):string {
    +  38    let r = ""+number;
    +  39    while (r.length < minDigits) { r = "0" + r; }
    +  40    return r;
    +  41}
    +  42
    +  43
    +  44/**
    +  45 * @ngdoc method 
    +  46 * @name ()
    +  47 * @methodOf hsNode.date
    +  48 * @param {String} formatString the format string to use.
    +  49 * @param {Date=} [date=new Date()] the date to format.
    +  50 * @returns {String} a copy of `formatString` where all supported patterns are replaced by the respective values from `date`.
    +  51 */

    +  52export default (formatString:string, date=new Date()) => formatString
    +  53 .replace(/%YYYY/g, ''+date.getFullYear())
    +  54 .replace(/%YY/g,   ''+(date.getFullYear()%100))
    +  55 .replace(/%MMMM/g,  monthStr[date.getMonth()][1])
    +  56 .replace(/%MMM/g,   monthStr[date.getMonth()][0])
    +  57 .replace(/%MM/g,   formatNumber(date.getMonth()+1,2))
    +  58 .replace(/%M/g,   ''+(date.getMonth()+1))
    +  59 .replace(/%DDDD/g,  dayStr[date.getDay()][1])
    +  60 .replace(/%DDD/g,   dayStr[date.getDay()][0])
    +  61 .replace(/%DD/g,   formatNumber(date.getDate(),2))
    +  62 .replace(/%D/g,   ''+date.getDate())
    +  63 .replace(/%hh/g,   formatNumber(date.getHours(),2))
    +  64 .replace(/%h/g,  ''+date.getHours())
    +  65 .replace(/%mm/g,   formatNumber(date.getMinutes(),2))
    +  66 .replace(/%m/g,   ''+date.getMinutes())
    +  67 .replace(/%ss/g,   formatNumber(date.getSeconds(),2))
    +  68 .replace(/%jjj/g,   formatNumber(date.getMilliseconds(),3))
    +  69 .replace(/%jj/g,   formatNumber(date.getMilliseconds()/10,2))
    +  70 .replace(/%j/g, formatNumber(date.getMilliseconds()/100,1))
    +  71;
    +  72
    + + \ No newline at end of file diff --git a/docs/src/hsNode/date.spec.html b/docs/src/hsNode/date.spec.html new file mode 100644 index 0000000..0423a8f --- /dev/null +++ b/docs/src/hsNode/date.spec.html @@ -0,0 +1,59 @@ + + +

    date.spec.ts

    +
       1import { date } from './';
    +   2
    +   3
    +   4describe("date", function() {
    +   5 it('should have date defined as a function', function() {
    +   6 expect(date).toBeDefined();
    +   7 expect(typeof date).toBe('function');
    +   8 });
    +   9  
    +  10 describe('formatting of date 7/4/2010', function() {
    +  11 let d = new Date('7/4/2010');
    +  12
    +  13 it('should convert "%YYYY-%MMMM-%DD"', function() {
    +  14 expect(date("%YYYY-%MMMM-%DD", d)).toBe("2010-July-04");
    +  15 });
    +  16
    +  17 it('should convert "%YY%MMM%D %YY"', function() {
    +  18 expect(date("%YY%MMM%D %YY", d)).toBe("10Jul4 10");
    +  19 });
    +  20
    +  21 it('should convert "%YY%MM%D %h:%m:%ss.%j"', function() {
    +  22 expect(date("%YY%MM%D %h:%m:%ss.%j", d)).toBe("10074 0:0:00.0");
    +  23 });
    +  24
    +  25 it('should convert "%DDD, %YY%MM%DD %hh:%mm:%ss.%jj"', function() {
    +  26 expect(date("%DDD, %YY%MM%DD %hh:%mm:%ss.%jj", d)).toBe("Sun, 100704 00:00:00.00");
    +  27 });
    +  28
    +  29 it('should convert "%DDDD, %YY%MM%DD %hh:%mm:%ss.%jjj"', function() {
    +  30 expect(date("%DDDD, %YY%MM%DD %hh:%mm:%ss.%jjj", d)).toBe("Sunday, 100704 00:00:00.000");
    +  31 });
    +  32 });
    +  33
    +  34 describe('formatting of current date', function() {
    +  35 let now = new Date();
    +  36
    +  37 it('should format ' + now.toDateString(), function() {
    +  38 expect(date("%YYYY-%MM-%DD")).toBe(date("%YYYY-%MM-%DD", now));
    +  39 });
    +  40 });
    +  41});
    +  42
    + + \ No newline at end of file diff --git a/docs/src/hsNode/excel.html b/docs/src/hsNode/excel.html new file mode 100644 index 0000000..957578f --- /dev/null +++ b/docs/src/hsNode/excel.html @@ -0,0 +1,282 @@ + + +

    excel.ts

    +
       1/**
    +   2 * # Excel 
    +   3 * Convenience functions to access tables in Excel files.
    +   4 * Uses the {@link https://github.com/SheetJS/js-xlsx Sheet JS xlsx parser and writer}.
    +   5 * 
    +   6 * # Excel related functions
    +   7 * - {@link excel.readFile readFile} 
    +   8 *
    +   9 */

    +  10
    +  11 /** */
    +  12const XLSX = require('xlsx');
    +  13
    +  14import { log }      from './';
    +  15import { DataRow}   from 'hsdata';
    +  16import { WorkBook,
    +  17         WorkSheet,
    +  18         CellObject
    +  19       }            from 'xlsx/types';
    +  20
    +  21log.prefix('XL');
    +  22
    +  23
    +  24/**
    +  25 * reads and returns a promise for an {@link #/hsLog/hsNode.excelFile excel file}.
    +  26 * ```
    +  27 * {
    +  28 *     {@link excel.readFile.getSheetNames getSheetNames},
    +  29 *  {@link excel.readFile.getTableColumns getTableColumns},
    +  30 *  {@link excel.readFile.getRowsForTable getRowsForTable},
    +  31 *  {@link excel.readFile.getTable getTable},
    +  32 *  {@link excel.readFile.nextExcelColIndex nextExcelColIndex},
    +  33 *  {@link excel.readFile.getCellValue getCellValue}
    +  34 * }
    +  35 * ```
    +  36 * # Usage
    +  37 * ```
    +  38 * const excel = require('./hsNode.excel');
    +  39 * const excelFile = excel.excelFile('./aFile.xlsx');
    +  40 * ``` 
    +  41 * @param name the name of the Excel file to read
    +  42 * @returns an object of functions providing access to the contents of the excel file.
    +  43 */

    +  44export function readFile(name:string, options?:any):ExcelFile { 
    +  45    //----------- private methods ------------------
    +  46 let workbook:WorkBook;
    +  47
    +  48 /**
    +  49  * returns the value of a cell, or undefined
    +  50  * @param sheet the sheet object or sheet name to retrieve cells from;
    +  51  * @param col the column index ('A',...)
    +  52  * @param row index (1,...)
    +  53  * @returns the value of a cell, or undefined
    +  54  */

    +  55 function getCellValue(sheet:string|WorkSheet, col:string, row:number):string {
    +  56 if (typeof sheet === 'string') { sheet = workbook.Sheets[sheet]; } 
    +  57        let c:CellObject;
    +  58 if (sheet[col+row] && sheet[col+row].v!=='') { 
    +  59            c = sheet[col+row];
    +  60            let val = c.w!==undefined? c.w : c.v;
    +  61 if (c) { switch(c.t) {
    +  62 case 's': return (val).replace(/,/g,';').replace(/[\n\r]+/g,' ').trim();
    +  63 case 'n': /* falls through */ 
    +  64 default: return c.w.replace(/,/g,'');
    +  65 }}
    +  66 }
    +  67 return ''; 
    +  68 }
    +  69
    +  70 /**
    +  71  * **Generator**, yields consecutive cell values over a row
    +  72  * @param sheet the sheet object or sheet name to retrieve cells from;
    +  73  * @param row the row to iterate over
    +  74  * @param colIterator iterable over columns;
    +  75  * or an iterable that generates column indices.
    +  76  */

    +  77 function* getCellValues(sheet:WorkSheet, row:number, colIterator:string[]) {
    +  78 for (let col of colIterator) {
    +  79 yield getCellValue(sheet, col, row); 
    +  80 }
    +  81 }
    +  82
    +  83 /**
    +  84  * **Generator**, yields consecutive column names as an 
    +  85  * {col, name} object. 
    +  86  * The generator exits when the first empty column name is encountered.
    +  87  * @param sheet the sheet to scan
    +  88  * @param row the row to scan
    +  89  * @param startCol defaults to 'A'
    +  90  */

    +  91 function* getConsecutiveColumnNames(sheet:WorkSheet, row:number, startCol='A') {
    +  92 for (let col of nextExcelColIndex(startCol)) {
    +  93 if (!getCellValue(sheet, col, row)) { break; }
    +  94 yield {col:col, name:getCellValue(sheet, col, row)}; 
    +  95 }
    +  96 }
    +  97
    +  98 /**
    +  99  * returns an array[c] of values from columns that match indices provided `columns`.
    + 100  * @param sheet the sheet object or sheet name to retrieve cells from;
    + 101  * @param row the row to iterate over
    + 102  * @param columns a) an array of column names. b) an {from:'A', to:'Z'} object 
    + 103  * @return array of column values in the row
    + 104  */

    + 105 function getRow(sheet:WorkSheet, row:number, columns:string[]) {
    + 106 let result = [...getCellValues(sheet, row, columns)];
    + 107 return result;
    + 108 }
    + 109
    + 110 /**
    + 111  * returns the value of a cell, or undefined
    + 112  * @param sheetName the sheet object or sheet name to retrieve cells from;
    + 113  * @param row index (1,...)
    + 114     * @param it an iterator over columns
    + 115  * @returns the value of a cell, or undefined
    + 116  */

    + 117 function constructCol(sheetName:string, row:number, it:any):TableStruct {
    + 118 let result:TableStruct = {
    + 119 names:[],
    + 120 sheetName: sheetName,
    + 121 headerRow: row,
    + 122 colIndex:  []
    + 123 };
    + 124 for (let col of it) {
    + 125 result.names.push(col.name);
    + 126 result.colIndex.push(col.col);
    + 127 }
    + 128 return result;
    + 129 }
    + 130
    + 131 /**
    + 132  * gets a table of values, starting at the startCol and startRow.
    + 133  * The table includes all consecutive columns with valid names, and all consecutive
    + 134  * rows with at least one valid cell value.
    + 135  * @param sheetID the sheet name or index from which to get the table
    + 136  * @param startCol determines the left edge of the table; defaults to 'A'
    + 137  * @param startRow determines the top edge of the table; defaults to 1
    + 138  * @returns a tuple of {columns, table} 
    + 139  */

    + 140 function getTable(sheetID:string|number, startCol='A', startRow=1) {
    + 141        const sheetName = (typeof sheetID === 'string')? sheetID : getSheetNames()[sheetID];
    + 142 const columns:TableStruct = getTableColumns(sheetName, startCol, startRow);
    + 143 const table:DataRow[]     = getRowsForTable(columns);
    + 144 return {columns, table};
    + 145    }
    + 146    
    + 147
    + 148    //----------- public methods ------------------
    + 149 /**
    + 150  * retrieves sheet names from a file
    + 151  * @returns {[string]} an array of sheet names
    + 152  */

    + 153 function getSheetNames():string[] {
    + 154 let names:string[] = [];
    + 155 for (let s in workbook.Sheets) { 
    + 156 names.push(s);
    + 157 }
    + 158 return names;
    + 159 }
    + 160
    + 161 /**
    + 162  * getTableColumns retrieves an array of consecutive valid column names.
    + 163  * @param sheetName the sheet object to retrieve cells from
    + 164  * @param startCol the first column of the table; defaults to 'A'.
    + 165  * @param row the row to iterate over; defaults to 1.
    + 166  * @returns an excel tabkle description
    + 167  */

    + 168 function getTableColumns(sheetName:string, startCol='A', row=1):TableStruct {
    + 169        let sheet:WorkSheet = workbook.Sheets[sheetName];
    + 170 return constructCol(sheetName, row, getConsecutiveColumnNames(sheet, row, startCol));
    + 171 }
    + 172
    + 173 /**
    + 174  * getRowsForTable returns a 2D array[r][c] of row values, where the columns match the provided 
    + 175  * columns names. 
    + 176  * @param table an array of column descriptors. 
    + 177  * @param maxRows if specified, determines the maximum number of rows to scan for. 
    + 178  * If omitted, iteration stops when the first row of empty values is encountered.
    + 179  */

    + 180 function getRowsForTable(table:TableStruct, maxRows=0):DataRow[] {
    + 181 if (!table.sheetName) { throw new Error('illegal table parameter in getRowsForTable'); }
    + 182 let sheet:WorkSheet = workbook.Sheets[table.sheetName];
    + 183 let result:DataRow[] = [];
    + 184 let row=0; 
    + 185 while (true) {
    + 186 let newRow = getRow(sheet, row+table.headerRow+1, table.colIndex);
    + 187 let filledCells = 0;
    + 188 for (let c in newRow) { if (newRow[c]) { filledCells++; }}
    + 189            row++;
    + 190            // only return non-empty rows
    + 191            if (filledCells > 0) { result.push(newRow); }
    + 192            // if no maxRows specified: break upon first empty row
    + 193            else if (maxRows<=0) {  break; }
    + 194            // if rows exceed maxRows: break;
    + 195 if (maxRows>0 && row>=maxRows) { break; }
    + 196 }
    + 197 return result;
    + 198 }
    + 199
    + 200    /**
    + 201     * **generator** for Excel column indices starting at startCol. 
    + 202     * Following 'Z' the next column generated is 'AA' and so on. The generator 
    + 203     * starts with producing startCol as first index.
    + 204     * # Usage
    + 205     * ```
    + 206     * for (col of file.nextExcelColIndex(startCol='Y') { 
    + 207     *    printf("%s, ", col);      // -> Y, Z, AA, AB
    + 208     *    if (col === 'AB')  { break; }
    + 209     * }
    + 210     * ```
    + 211     * @param startCol the first column index ('A', ....) to yield; defaults to 'A'
    + 212     */

    + 213    function* nextExcelColIndex(startCol='A'):IterableIterator {
    + 214        function nextChar(c:string):string { return String.fromCharCode(c.charCodeAt(0) + 1); }
    + 215        
    + 216        let c = startCol;
    + 217        while (true) {
    + 218            yield c;
    + 219            if (c.length === 1) {
    + 220                c = (c < 'Z')? nextChar(c[0]) : 'AA';
    + 221            } else {
    + 222                var ch = nextChar(c[1]);
    + 223                c = (ch > 'Z')? nextChar(c[0])+'A' : c[0] + ch;
    + 224            }
    + 225        }
    + 226    }
    + 227 log.debug('reading file ' + name);
    + 228 workbook = XLSX.readFile(name, options);
    + 229 return {
    + 230 getSheetNames: getSheetNames,
    + 231 getTableColumns: getTableColumns,
    + 232 getRowsForTable: getRowsForTable,
    + 233 getTable: getTable,
    + 234 nextExcelColIndex: nextExcelColIndex,
    + 235 getCellValue: getCellValue
    + 236 };
    + 237}
    + 238
    + 239
    + 240/**
    + 241 * A structure describing an Excel table
    + 242 */

    + 243export interface TableStruct {
    + 244    names:string[];
    + 245    sheetName:string;
    + 246    headerRow:number;
    + 247    colIndex:string[]; 
    + 248}
    + 249
    + 250/**
    + 251 * 
    + 252 */

    + 253export interface Table {
    + 254    columns:TableStruct;
    + 255    table:DataRow[];
    + 256}
    + 257
    + 258export interface ExcelFile {
    + 259    getSheetNames: () =>string[];
    + 260    getTableColumns: (sheetName:string, startCol?:string, row?:number) => TableStruct;
    + 261    getRowsForTable: (table:TableStruct, maxRows?:number) => DataRow[];
    + 262    getTable: (sheetID:string|number, startCol?:string, startRow?:number) => Table;
    + 263    nextExcelColIndex: (startCol?:string) => IterableIterator;
    + 264    getCellValue: (sheet:string|WorkSheet, col:string, row:number) => string;
    + 265}
    + + \ No newline at end of file diff --git a/docs/src/hsNode/excel.spec.html b/docs/src/hsNode/excel.spec.html new file mode 100644 index 0000000..b5f90fb --- /dev/null +++ b/docs/src/hsNode/excel.spec.html @@ -0,0 +1,152 @@ + + +

    excel.spec.ts

    +
       1import { hsExcel } from './';
    +   2
    +   3const TEST_FILE = '../example/test.xlsx';
    +   4
    +   5describe("hsExcel", function() {
    +   6 it('should have hsExcel defined', function() {
    +   7 expect(hsExcel).toBeDefined();
    +   8 });
    +   9  
    +  10 describe("test file", function() {
    +  11 const NAME  = TEST_FILE;
    +  12 const SHEET = 'Closed';
    +  13 let file:any;
    +  14
    +  15 beforeEach(function() {
    +  16 file = hsExcel.readFile(__dirname+'/'+NAME);
    +  17 });
    +  18
    +  19 it('should have read '+NAME, function() {
    +  20 expect(file).toBeDefined();
    +  21 });
    +  22
    +  23 describe('sheets', function() {
    +  24 let sheets:any;
    +  25
    +  26 beforeEach(function() { 
    +  27 sheets = file.getSheetNames(); 
    +  28 });
    +  29
    +  30 it('should have 2 sheets', function() {
    +  31 expect(sheets.length).toBe(2);
    +  32 });
    +  33
    +  34 it(`should have sheet "${SHEET}"`, function() {
    +  35 expect(sheets.indexOf(SHEET)).toBe(1);
    +  36 });
    +  37 });
    +  38
    +  39 describe('getCellValue', function() {
    +  40 it(`should have cell value`, function() {
    +  41 expect(file.getCellValue(SHEET, 'B', 5)).toBe('Ringo');
    +  42 });
    +  43 });
    +  44
    +  45 describe('header row', function() {
    +  46 it('should have a column name "Topic" on 4th position', function() {
    +  47 let columns = file.getTableColumns(SHEET, 'A', 1);
    +  48 expect(columns.names[2]).toBe('Topic');
    +  49 });
    +  50
    +  51 it('should accept string as row number', function() {
    +  52 let columns = file.getTableColumns(SHEET, 'A', "1");
    +  53 expect(columns.names[2]).toBe('Topic'); 
    +  54 });
    +  55 }); 
    +  56
    +  57 describe('getRowsForTable', function() {
    +  58 it('should fail for illegal collumns', function() {
    +  59 function noSheet() {
    +  60 file.getRowsForTable({});
    +  61 }
    +  62 expect(noSheet).toThrowError('illegal table parameter in getRowsForTable');
    +  63 });
    +  64
    +  65 it('should return maxRows', function() {
    +  66 let columns = file.getTableColumns(SHEET, 'A', 1);
    +  67 let rows = file.getRowsForTable(columns, 1);
    +  68 expect(rows.length).toBe(1);
    +  69 });
    +  70
    +  71 it('should return less than maxRows=10', function() {
    +  72 let columns = file.getTableColumns(SHEET, 'A', 1);
    +  73 let rows = file.getRowsForTable(columns, 10);
    +  74 expect(rows.length).toBe(4);
    +  75 });
    +  76 });
    +  77
    +  78 describe('table rows', function() {
    +  79 let columns:any;
    +  80 let rows:any;
    +  81
    +  82 beforeEach(function() { 
    +  83 columns = file.getTableColumns(SHEET, 'A', 1);
    +  84 rows = file.getRowsForTable(columns);
    +  85 });
    +  86
    +  87 it('should have 4 rows', function() {
    +  88 expect(rows.length).toBe(4);
    +  89 });
    +  90
    +  91 it('should have "Start" value in 4th row', function() {
    +  92 let col = columns.names.indexOf('Start');
    +  93 expect(col).toBe(3);
    +  94 expect(rows[3][col]).toBe('03/01/14');
    +  95 });
    +  96 });
    +  97
    +  98 describe('entire table', function() {
    +  99 it('should have 5 columns', function() {
    + 100 let {columns} = file.getTable(SHEET, 'A', 1);
    + 101 expect(columns.names.length).toBe(5);
    + 102 });
    + 103
    + 104 it('should have 4 rows', function() {
    + 105 let {table} = file.getTable(SHEET, 'A', 1);
    + 106 expect(table.length).toBe(4);
    + 107 });
    + 108 });
    + 109
    + 110 describe('nextExcelColIndex', function() {
    + 111 function nextIndex(startCol:string) { 
    + 112 const gen = file.nextExcelColIndex(startCol);
    + 113 gen.next(); // reproduces startCol;
    + 114 return gen.next().value;
    + 115 }
    + 116
    + 117 it("should produce column 'N' after column 'M'", function() {
    + 118 expect(nextIndex('M')).toBe('N');
    + 119 });
    + 120
    + 121 it("should produce column 'AA' after column 'Z'", function() {
    + 122 expect(nextIndex('Z')).toBe('AA');
    + 123 });
    + 124
    + 125 it("should produce column 'BA' after column 'AZ'", function() {
    + 126 expect(nextIndex('AZ')).toBe('BA');
    + 127 });
    + 128
    + 129 it("should produce column 'BN' after column 'BM'", function() {
    + 130 expect(nextIndex('BM')).toBe('BN');
    + 131 });
    + 132 });
    + 133 });
    + 134});
    + 135
    + + \ No newline at end of file diff --git a/docs/src/hsNode/fsUtil.html b/docs/src/hsNode/fsUtil.html new file mode 100644 index 0000000..5baf573 --- /dev/null +++ b/docs/src/hsNode/fsUtil.html @@ -0,0 +1,307 @@ + + +

    fsUtil.ts

    +
       1const fs  = require('fs');
    +   2const path = require('path');
    +   3
    +   4import { log } from './';
    +   5
    +   6/**
    +   7 * Convenience functions for file system access, wrapped in Promises.
    +   8 * - {@link hsNode.fsUtil#methods_realPath realPath}
    +   9 * - {@link hsNode.fsUtil#methods_pathExists pathExists}
    +  10 * - {@link hsNode.fsUtil#methods_isfile isFile}
    +  11 * - {@link hsNode.fsUtil#methods_isdirectory isDirectory}
    +  12 * - {@link hsNode.fsUtil#methods_readDir readDir}
    +  13 * - {@link hsNode.fsUtil#methods_readFile readFile}
    +  14 * - {@link hsNode.fsUtil#methods_readTextFile readTextFile}
    +  15 * - {@link hsNode.fsUtil#methods_readJsonFile readJsonFile}
    +  16 * - {@link hsNode.fsUtil#methods_writeFile writeFile}
    +  17 * - {@link hsNode.fsUtil#methods_writeTextFile writeTextFile}
    +  18 * - {@link hsNode.fsUtil#methods_writeJsonFile writeJsonFile}
    +  19 * - {@link hsNode.fsUtil#methods_appendFile appendFile}
    +  20 * - {@link hsNode.fsUtil#methods_remove remove}
    +  21 */

    +  22
    +  23 export interface Stats {
    +  24    path:       string;     // path to the file
    +  25    device:     any;        // ID of device containing file
    +  26    iNode:      number;     // Inode number 
    +  27    type:       number;     // File type and mode 
    +  28    numLinks:   number;     // Number of hard links 
    +  29    userID:     string;     // User ID of owner 
    +  30    groupID:    string;     // Group ID of owner 
    +  31    deviceID:   string;     // Device ID (if special file) 
    +  32    totalSize:  number;     // Total size, in bytes 
    +  33    blockSize:  number;     // Block size for filesystem I/O 
    +  34    numBlocks:  number;     // Number of 512B blocks allocated 
    +  35    accessTime:       any;  // Time of last access
    +  36    modifyTime:       any;  // Time of last modification
    +  37    statusChangeTime: any;  // Time of last status change     
    +  38 }
    +  39
    +  40//===============================================================================
    +  41//  Low level Promise wrappers
    +  42
    +  43function stat(thePath:string):Promise {
    +  44 return Promise.resolve(thePath)
    +  45 .then(realPath)
    +  46 .then(thePath => new Promise((resolve:(value:Stats)=>void, reject) => {
    +  47 fs.stat(thePath, (err:any, stats:Stats) => {
    +  48 if(err) { reject(err); } // reject is hard to test: realpath throws an error before stat can.
    +  49 else    { 
    +  50 stats.path = thePath;
    +  51 resolve(stats); 
    +  52 }
    +  53 });
    +  54 }));
    +  55}
    +  56
    +  57function lstat(thePath:string) {
    +  58 return Promise.resolve(thePath)
    +  59 .then(path.normalize)
    +  60 .then(thePath => new Promise((resolve, reject) => {
    +  61 log.debug('lstat for ' + thePath);
    +  62 fs.lstat(thePath, (err:any, stats:any) => {
    +  63 if(err) { reject(err); }
    +  64 else    { 
    +  65 stats.path = thePath;
    +  66 resolve(stats); 
    +  67 }
    +  68 });
    +  69 }));
    +  70}
    +  71
    +  72function error(err:any):any {
    +  73    const msg = `*** error in fsUtil: ${err}`;
    +  74    console.log(msg);
    +  75    console.log(err.trace);
    +  76    throw new Error(msg);
    +  77}
    +  78
    +  79//===============================================================================
    +  80//   Exported functions
    +  81
    +  82/**
    +  83 * determines the canonical path for `thePath`, resolving all symbolic links and '../'in the path.
    +  84 * @param thePath the path to check
    +  85 * @return promise to provide the real canonical system path.
    +  86 */

    +  87function realPath(thePath:string):Promise {
    +  88 return new Promise((resolve:(path:string)=>void, reject:(err:any)=>void) => {
    +  89 fs.realpath(thePath, (err:any, resolvedPath:string) => err? reject(err) : resolve(resolvedPath) );
    +  90    })
    +  91    .catch(error);
    +  92}
    +  93
    +  94/**
    +  95 * determines if `thePath` exists and promises to provide `true` or `false`.
    +  96 * @param {string} thePath the path to check
    +  97 * @return {Promise} promise to provide `true` or `false`
    +  98 */

    +  99function pathExists(thePath:string):Promise {
    + 100 return stat(thePath).then((stats:any) => stats.path).catch(() => false)
    + 101    .catch(error);
    + 102};
    + 103
    + 104/**
    + 105 * determines if `thePath` is a file and promises to provide `true` or `false`.
    + 106 * @param {string} thePath the path to check
    + 107 * @return {Promise} promise to provide `true` or `false`
    + 108 */

    + 109function isFile(thePath:string):Promise {
    + 110 return stat(thePath).then((stats:any) => stats.isFile()? stats.path : false).catch(() => false)
    + 111    .catch(error);
    + 112};
    + 113
    + 114/**
    + 115 * determines if `thePath` is a directory and promises to provide `true` or `false`.
    + 116 * @param {string} thePath the path to check
    + 117 * @return {Promise} promise to provide `true` or `false`
    + 118 */

    + 119function isDirectory(thePath:string):Promise {
    + 120 return stat(thePath).then((stats:any) => stats.isDirectory()? stats.path : false).catch(() => false)
    + 121    .catch(error);
    + 122};
    + 123
    + 124/**
    + 125 * determines if `thePath` is a directory and promises to provide `true` or `false`.
    + 126 * @param {string} thePath the path to check
    + 127 * @return {Promise} promise to provide `true` or `false`
    + 128 */

    + 129function isLink(thePath:string):Promise {
    + 130 return lstat(thePath).then((stats:any) => stats.isSymbolicLink()? stats.path : false).catch(() => false)
    + 131    .catch(error);
    + 132};
    + 133
    + 134/**
    + 135 * lists all files in a directory and promises to provide the list.
    + 136 * @param {string} thePath the path to check
    + 137 * @return {Promise} promise to provide a list of directory entries.
    + 138 */

    + 139function readDir(thePath:string):Promise {
    + 140 return Promise.resolve(thePath)
    + 141 .then(realPath)
    + 142 .then(thePath => new Promise((resolve:(files:any)=>void, reject:(err:any)=>void) => {
    + 143 fs.readdir(thePath, (err:any, files:any) =>  {
    + 144 if(err) { reject(err); }
    + 145 else { 
    + 146 files.path = thePath;
    + 147 resolve(files); 
    + 148 }
    + 149 });
    + 150 }))
    + 151    .catch(error);
    + 152}
    + 153
    + 154
    + 155/**
    + 156 * reads a file either as binary or text and promises to provide the content.
    + 157 * @param {string} thePath the path to read
    + 158 * @param {boolean=} [isText=true] `true`|`false` if file should be read as `utf8`|binary 
    + 159 * @return {Promise} promise to provide file content.
    + 160 */

    + 161function readFile(thePath:string, isText=true):Promise {
    + 162 return new Promise((resolve:(data:any)=>void, reject:(err:any)=>void) => {
    + 163 let encoding = isText? 'utf8' : undefined;
    + 164 fs.readFile(thePath, encoding, (err:any, data:any) => {
    + 165 if (err) { reject(err); }
    + 166 resolve(data);
    + 167 });
    + 168 })
    + 169    .catch(error);
    + 170};
    + 171
    + 172/**
    + 173 * reads a text file and promises to provide the content.
    + 174 * @param {string} thePath the path to read
    + 175 * @return {Promise} promise to provide file content.
    + 176 */

    + 177function readTextFile(thePath:string):Promise { 
    + 178 return readFile(thePath, true)
    + 179    .catch(error);
    + 180};
    + 181
    + 182/**
    + 183 * reads a text file and promises to provide the content.
    + 184 * @param {string} thePath the path to read
    + 185 * @return {Promise} promise to provide file content.
    + 186 */

    + 187function readJsonFile(thePath:string):Promise {
    + 188    return readFile(thePath, true)
    + 189 .then((data:any) => (typeof data === 'string')? JSON.parse(data) : data)
    + 190    .catch(error);
    + 191}
    + 192
    + 193/**
    + 194 * writes a file either as binary or text and promises no return.
    + 195 * @param {string} thePath the path to write to
    + 196 * @param {object} content the content to write
    + 197 * @param {boolean} isText `true`|`false` if file should be read as `utf8`|binary 
    + 198 * @return {Promise} promise to provide nothing.
    + 199 */

    + 200function writeFile(thePath:string, content:string, isText:boolean=true):Promise {
    + 201 return new Promise((resolve, reject) => {
    + 202 var encoding = isText? 'utf8' : undefined;
    + 203     fs.writeFile(thePath, content, encoding, (err:any) => err? reject(err) : resolve());
    + 204 })
    + 205    .catch(error);
    + 206};
    + 207
    + 208/**
    + 209 * writes content to a file either as a stream and promises no return.
    + 210 * @param {string} thePath the path to write to
    + 211 * @param {object} content the content to write
    + 212 * @return {Promise} promise to provide nothing.
    + 213 */

    + 214function writeStream(thePath:string, content:string):Promise {
    + 215 return new Promise((resolve, reject) => {
    + 216        let s = fs.createWriteStream(thePath, {flags:'w', mode:0o666});
    + 217        s.on('error', (src:any) => reject(src));
    + 218        s.write(content, 'binary', () => resolve());
    + 219        s.end();
    + 220 })
    + 221    .catch(error);
    + 222}
    + 223
    + 224/**
    + 225 * writes a text file and promises no return.
    + 226 * @param {string} thePath the path to write
    + 227 * @return {Promise} promise to provide nothing.
    + 228 */

    + 229function writeTextFile(thePath:string, content:string):Promise { 
    + 230 return writeFile(thePath, content, true)
    + 231    .catch(error);
    + 232};
    + 233
    + 234/**
    + 235 * writes a text file and promises no return.
    + 236 * @param {string} thePath the path to write
    + 237 * @param {object} obj the object to write
    + 238 * @return {Promise} promise to provide nothing.
    + 239 */

    + 240function writeJsonFile(thePath:string, obj:any):Promise {
    + 241    return Promise.resolve(obj)
    + 242 .then(JSON.stringify)
    + 243 .then(data => writeTextFile(thePath, data))
    + 244    .catch(error);
    + 245}
    + 246
    + 247/**
    + 248 * appends to a file either as binary or text and promises no return.
    + 249 * @param {string} thePath the path to write to
    + 250 * @param {object} content the content to write
    + 251 * @param {boolean} isText `true`|`false` if file should be read as `utf8`|binary 
    + 252 * @return {Promise} promise to provide nothing.
    + 253 */

    + 254function appendFile(thePath:string, content:string, isText:boolean=true):Promise {
    + 255 return new Promise((resolve, reject) => {
    + 256 var encoding = isText? 'utf8' : undefined;
    + 257     fs.appendFile(thePath, content, encoding, (err:any) => err? reject(err) : resolve());
    + 258 })
    + 259    .catch(error);
    + 260};
    + 261
    + 262/**
    + 263 * promises to delete a file or folder.
    + 264 * @param {string} thePath the path to write
    + 265 * @return {Promise} promise to provide nothing.
    + 266 */

    + 267function remove(thePath:string):Promise {
    + 268 return new Promise((resolve:()=>void, reject:(err:any)=>void) => {
    + 269        fs.unlink(thePath, (e:any) => (e? reject(e) : resolve()));
    + 270 })
    + 271    .catch(error);
    + 272}
    + 273
    + 274export const fsUtil = { 
    + 275    realPath:       realPath, 
    + 276    pathExists:     pathExists, 
    + 277    isFile:         isFile, 
    + 278    isDirectory:    isDirectory, 
    + 279    isLink:         isLink, 
    + 280    readDir:        readDir, 
    + 281    readFile:       readFile, 
    + 282    readTextFile:   readTextFile, 
    + 283    readJsonFile:   readJsonFile, 
    + 284    writeFile:      writeFile, 
    + 285    writeStream:    writeStream, 
    + 286    writeTextFile:  writeTextFile, 
    + 287    writeJsonFile:  writeJsonFile,
    + 288    appendFile:     appendFile, 
    + 289    remove:         remove 
    + 290};
    + + \ No newline at end of file diff --git a/docs/src/hsNode/fsUtil.spec.html b/docs/src/hsNode/fsUtil.spec.html new file mode 100644 index 0000000..cab0147 --- /dev/null +++ b/docs/src/hsNode/fsUtil.spec.html @@ -0,0 +1,571 @@ + + +

    fsUtil.spec.ts

    +
       1import { fsUtil } from './';
    +   2
    +   3
    +   4
    +   5describe("hsFSutil", function() {
    +   6 let called:any;
    +   7    const dir = __dirname; // + '/testTmp/';
    +   8    const TEST_DIR = dir+'/../example/';
    +   9
    +  10    function getCalled(done:()=>void) {
    +  11        let result:string, error:string;
    +  12        let called = { 
    +  13            resolved: (v:string) => { result=v; done(); },
    +  14            rejected: (v:string) => { error =v; done(); },
    +  15            getResult: () => result,
    +  16            getError:  () => error
    +  17        };
    +  18        spyOn(called, 'resolved').and.callThrough(); 
    +  19        spyOn(called, 'rejected').and.callThrough(); 
    +  20        return called;
    +  21    }
    +  22
    +  23 describe('pathExists' , () => {
    +  24 describe(process.cwd() , () => {
    +  25 beforeEach(done => {
    +  26 called = getCalled(done);
    +  27 fsUtil.pathExists(process.cwd()).then(called.resolved).catch(called.rejected);
    +  28 });
    +  29
    +  30 it('should exist', function(done) {
    +  31 expect(called.resolved).toHaveBeenCalledWith(process.cwd());
    +  32 expect(called.rejected).not.toHaveBeenCalled();
    +  33 done();
    +  34 });
    +  35 });
    +  36
    +  37 describe('./' , () => { 
    +  38 beforeEach(done => {
    +  39 called = getCalled(done);
    +  40 fsUtil.pathExists('./').then(called.resolved).catch(called.rejected);
    +  41 });
    +  42
    +  43 it('should exist', function(done) {
    +  44 expect(called.resolved).toHaveBeenCalledWith(process.cwd());
    +  45 expect(called.rejected).not.toHaveBeenCalled();
    +  46 done();
    +  47 });
    +  48 });
    +  49
    +  50 describe('/does-not-exists/', () => {
    +  51 beforeEach(done => {
    +  52 called = getCalled(done);
    +  53 fsUtil.pathExists('/does-not-exists/').then(called.resolved).catch(called.rejected);
    +  54 });
    +  55
    +  56 it('should not exist', function(done) {
    +  57 expect(called.resolved).toHaveBeenCalledWith(false);
    +  58 expect(called.rejected).not.toHaveBeenCalled();
    +  59 done();
    +  60 });
    +  61 });
    +  62 });
    +  63
    +  64 describe('isFile' , () => {
    +  65 describe(dir, () => {
    +  66 beforeEach(done => {
    +  67 called = getCalled(done);
    +  68 fsUtil.isFile(dir).then(called.resolved).catch(called.rejected);
    +  69 });
    +  70
    +  71 it('should not be a file', function(done) {
    +  72 expect(called.resolved).toHaveBeenCalledWith(false);
    +  73 expect(called.rejected).not.toHaveBeenCalled();
    +  74 done();
    +  75 });
    +  76 });
    +  77
    +  78 describe('Gruntfile.js' , () => {
    +  79            let rp:string;
    +  80 beforeEach(done => {
    +  81                fsUtil.realPath(dir+'/../../Gruntfile.js')
    +  82                .then((path:string) => {
    +  83     called = getCalled(done);
    +  84                    rp = path;
    +  85     fsUtil.isFile(rp).then(called.resolved).catch(called.rejected);
    +  86                });
    +  87 });
    +  88
    +  89 it('should be a file', function(done) {
    +  90 expect(called.resolved).toHaveBeenCalledWith(rp);
    +  91 expect(called.rejected).not.toHaveBeenCalled();
    +  92 done();
    +  93 });
    +  94 });
    +  95
    +  96 describe('./Gruntfile.js' , () => { 
    +  97 beforeEach(done => {
    +  98 called = getCalled(done);
    +  99 fsUtil.isFile('./Gruntfile.js').then(called.resolved).catch(called.rejected);
    + 100 });
    + 101
    + 102 it('should be a file', function(done) {
    + 103 expect(called.resolved).toHaveBeenCalledWith(process.cwd()+'/Gruntfile.js');
    + 104 expect(called.rejected).not.toHaveBeenCalled();
    + 105 done();
    + 106 });
    + 107 });
    + 108
    + 109 describe('./Gruntfile.js2', () => {
    + 110 beforeEach(done => {
    + 111 called = getCalled(done);
    + 112 fsUtil.isFile('./Gruntfile.js2').then(called.resolved).catch(called.rejected);
    + 113 });
    + 114  
    + 115 it('should not be a file an not be rejected', function(done) {
    + 116 expect(called.resolved).toHaveBeenCalledWith(false);
    + 117 expect(called.rejected).not.toHaveBeenCalled();
    + 118 done();
    + 119 });
    + 120 });
    + 121 });
    + 122
    + 123 describe('isDirectory' , () => {
    + 124 describe(process.cwd(), () => {
    + 125 beforeEach(done => {
    + 126 called = getCalled(done);
    + 127 fsUtil.isDirectory(process.cwd()).then(called.resolved).catch(called.rejected);
    + 128 });
    + 129
    + 130 it('should be a directory', function(done) {
    + 131 expect(called.resolved).toHaveBeenCalledWith(process.cwd());
    + 132 expect(called.rejected).not.toHaveBeenCalled();
    + 133 done();
    + 134 });
    + 135 });
    + 136
    + 137 describe('./' , () => { 
    + 138 beforeEach(done => {
    + 139 called = getCalled(done);
    + 140 fsUtil.isDirectory('./').then(called.resolved).catch(called.rejected);
    + 141 });
    + 142
    + 143 it('should be a directory', function(done) {
    + 144 expect(called.resolved).toHaveBeenCalledWith(process.cwd());
    + 145 expect(called.rejected).not.toHaveBeenCalled();
    + 146 done();
    + 147 });
    + 148 });
    + 149
    + 150 describe('./Gruntfile.js', () => {
    + 151 beforeEach(done => {
    + 152 called = getCalled(done);
    + 153 fsUtil.isDirectory('./Gruntfile.js').then(called.resolved).catch(called.rejected);
    + 154 });
    + 155  
    + 156 it('valid file should not be a directory an not be rejected', function(done) {
    + 157 expect(called.resolved).toHaveBeenCalledWith(false);
    + 158 expect(called.rejected).not.toHaveBeenCalled();
    + 159 done();
    + 160 });
    + 161 });
    + 162
    + 163 describe('./Gruntfile.js2', () => {
    + 164 beforeEach(done => {
    + 165 called = getCalled(done);
    + 166 fsUtil.isDirectory('./Gruntfile.js2').then(called.resolved).catch(called.rejected);
    + 167 });
    + 168  
    + 169 it('invalid file should not be a directory an not be rejected', function(done) {
    + 170 expect(called.resolved).toHaveBeenCalledWith(false);
    + 171 expect(called.rejected).not.toHaveBeenCalled();
    + 172 done();
    + 173 });
    + 174 });
    + 175 });
    + 176
    + 177 describe('isLink' , () => {
    + 178 describe(__dirname , () => {
    + 179 beforeEach(done => {
    + 180 called = getCalled(done);
    + 181 fsUtil.isLink(__dirname).then(called.resolved).catch(called.rejected);
    + 182 });
    + 183
    + 184 it('should not be a link', function(done) {
    + 185 expect(called.resolved).toHaveBeenCalledWith(false);
    + 186 expect(called.rejected).not.toHaveBeenCalled(); 
    + 187 done();
    + 188 });
    + 189 });
    + 190
    + 191 describe(dir+'/../../node_Modules' , () => {
    + 192 beforeEach(done => {
    + 193 called = getCalled(done);
    + 194 fsUtil.isLink(dir+'/../../node_Modules').then(called.resolved).catch(called.rejected);
    + 195 });
    + 196
    + 197 it('should be a link', function(done) {
    + 198 expect(called.resolved).toHaveBeenCalled();
    + 199 expect(called.resolved).not.toHaveBeenCalledWith(false); // instead: real path
    + 200 expect(called.rejected).not.toHaveBeenCalled();
    + 201 done();
    + 202 });
    + 203 });
    + 204
    + 205 describe(__dirname+'/abc' , () => {
    + 206 beforeEach(done => {
    + 207 called = getCalled(done);
    + 208 fsUtil.isLink(__dirname+'/abc').then(called.resolved).catch(called.rejected);
    + 209 });
    + 210
    + 211 it('should reject for invalid names', function(done) {
    + 212 expect(called.resolved).toHaveBeenCalledWith(false);
    + 213 expect(called.rejected).not.toHaveBeenCalled();
    + 214 done();
    + 215 });
    + 216 });
    + 217
    + 218 });
    + 219
    + 220 describe('readDir' , () => {
    + 221 describe(__dirname , () => {
    + 222 beforeEach(done => {
    + 223 called = getCalled(done);
    + 224 fsUtil.readDir(__dirname).then(called.resolved).catch(called.rejected);
    + 225 });
    + 226
    + 227 it('should return list of spec files', function(done) {
    + 228 expect(called.resolved).toHaveBeenCalled();
    + 229 expect(called.rejected).not.toHaveBeenCalled();
    + 230 expect(called.getResult()).toBeDefined();
    + 231 expect(called.getResult().length).toBeGreaterThan(6);
    + 232 done();
    + 233 });
    + 234 });
    + 235
    + 236 describe(__dirname+'/abcde' , () => {
    + 237 beforeEach(done => {
    + 238 called = getCalled(done);
    + 239 fsUtil.readDir(__dirname+'/abcde').then(called.resolved).catch(called.rejected);
    + 240 });
    + 241
    + 242 it('should reject', function(done) {
    + 243 expect(called.resolved).not.toHaveBeenCalled();
    + 244 expect(called.rejected).toHaveBeenCalled();
    + 245 done();
    + 246 });
    + 247 });
    + 248 });
    + 249
    + 250 describe('readFile' , () => {
    + 251        const file1 = TEST_DIR+'test.xlsx';
    + 252        const file2 = TEST_DIR+'test.xlsx2';
    + 253 describe(file1 , () => {
    + 254 beforeEach(done => {
    + 255 called = getCalled(done);
    + 256 fsUtil.readFile(file1, false).then(called.resolved).catch(called.rejected);
    + 257 });
    + 258
    + 259 it('should read binary file', function(done) {
    + 260 expect(called.resolved).toHaveBeenCalled();
    + 261 expect(typeof called.getResult()).toBe('object');
    + 262 expect(called.rejected).not.toHaveBeenCalled();
    + 263 done();
    + 264 });
    + 265 });
    + 266
    + 267 describe(file2 , () => {
    + 268 beforeEach(done => {
    + 269 called = getCalled(done);
    + 270 fsUtil.readFile(file2, false).then(called.resolved).catch(called.rejected);
    + 271 });
    + 272
    + 273 it('should reject', function(done) {
    + 274 expect(called.resolved).not.toHaveBeenCalled();
    + 275 expect(called.rejected).toHaveBeenCalled();
    + 276 expect(called.getError()+'').toMatch(/Error: ENOENT: no such file or directory/);
    + 277 done();
    + 278 });
    + 279 });
    + 280
    + 281 });
    + 282
    + 283 describe('readTextFile' , () => {
    + 284 describe(__dirname+'/fsUtil.spec.js' , () => {
    + 285 beforeEach(done => {
    + 286 called = getCalled(done);
    + 287 fsUtil.readTextFile(__dirname+'/fsUtil.spec.js').then(called.resolved).catch(called.rejected);
    + 288 });
    + 289
    + 290 it('should read text file', function(done) {
    + 291 expect(called.resolved).toHaveBeenCalled();
    + 292 expect(typeof called.getResult()).toBe('string');
    + 293 expect(called.rejected).not.toHaveBeenCalled();
    + 294 done();
    + 295 });
    + 296 });
    + 297 });
    + 298
    + 299 describe('readJsonFile' , () => {
    + 300        const file = __dirname+'/../../package.json';
    + 301 describe(file , () => {
    + 302 beforeEach(done => {
    + 303 called = getCalled(done);
    + 304 fsUtil.readJsonFile(file).then(called.resolved).catch(called.rejected);
    + 305 });
    + 306
    + 307 it('should read text file', function(done) {
    + 308 expect(called.resolved).toHaveBeenCalled();
    + 309 expect(called.rejected).not.toHaveBeenCalled();
    + 310 expect(typeof called.getResult()).toBe('object');
    + 311 expect(called.getResult().name).toBe('hsNode');
    + 312 done();
    + 313 });
    + 314 });
    + 315 });
    + 316
    + 317 describe('writeFile' , () => {
    + 318 describe(dir+'binFile' , () => {
    + 319 beforeEach(done => {
    + 320 called = getCalled(done);
    + 321 fsUtil.writeFile(dir+'binFile', 'test2', false).then(called.resolved).catch(called.rejected);
    + 322 });
    + 323
    + 324 it('should resolve', function(done) {
    + 325 expect(called.resolved).toHaveBeenCalled();
    + 326 expect(called.rejected).not.toHaveBeenCalled();
    + 327 done();
    + 328 });
    + 329
    + 330 describe('check for bin file', function() {
    + 331 beforeEach(done => {
    + 332 called = getCalled(done);
    + 333 fsUtil.readFile(dir+'binFile', false).then(called.resolved).catch(called.rejected);
    + 334 });
    + 335
    + 336 it('should exist', function(done) {
    + 337 expect(called.resolved).toHaveBeenCalled();
    + 338 expect(called.rejected).not.toHaveBeenCalled();
    + 339 done();
    + 340 });
    + 341
    + 342 it('should contain payload', function(done) {
    + 343 expect(typeof called.getResult()).toBe('object');
    + 344 expect(Buffer.from('test2').equals(called.getResult())).toBe(true);
    + 345 done();
    + 346 });
    + 347 });
    + 348 });
    + 349
    + 350 describe(dir+'binFile2' , () => {
    + 351 beforeEach(done => {
    + 352 called = getCalled(done);
    + 353 fsUtil.readFile(dir+'binFile2', false).then(called.resolved).catch(called.rejected);
    + 354 });
    + 355
    + 356 it('should reject', function(done) {
    + 357 expect(called.resolved).not.toHaveBeenCalled();
    + 358 expect(called.rejected).toHaveBeenCalled();
    + 359 done();
    + 360 });
    + 361 });
    + 362 });
    + 363
    + 364
    + 365 describe('appendFile' , () => {
    + 366 describe(dir+'binFile' , () => {
    + 367 beforeEach(done => {
    + 368 called = getCalled(done);
    + 369 fsUtil.appendFile(dir+'binFile', 'test2', false).then(called.resolved).catch(called.rejected);
    + 370 });
    + 371
    + 372            afterAll(done => {
    + 373                fsUtil.remove(dir+'binFile');
    + 374                done();
    + 375            });
    + 376
    + 377 it('should resolve', function(done) {
    + 378 expect(called.resolved).toHaveBeenCalled();
    + 379 expect(called.rejected).not.toHaveBeenCalled();
    + 380 done();
    + 381 });
    + 382
    + 383 describe('check for bin file', function() {
    + 384 beforeEach(done => {
    + 385 called = getCalled(done);
    + 386 fsUtil.readFile(dir+'binFile', false).then(called.resolved).catch(called.rejected);
    + 387 });
    + 388
    + 389 it('should exist', function(done) {
    + 390 expect(called.resolved).toHaveBeenCalled();
    + 391 expect(called.rejected).not.toHaveBeenCalled();
    + 392 done();
    + 393 });
    + 394
    + 395 it('should contain payload', function(done) {
    + 396 expect(typeof called.getResult()).toBe('object');
    + 397 expect(called.getResult().toString()).toMatch('test2test2test2test2');
    + 398 done();
    + 399 });
    + 400 });
    + 401 });
    + 402
    + 403 describe(dir+'binFile2' , () => {
    + 404 beforeEach(done => {
    + 405 called = getCalled(done);
    + 406 fsUtil.readFile(dir+'binFile2', false).then(called.resolved).catch(called.rejected);
    + 407 });
    + 408
    + 409 it('should reject', function(done) {
    + 410 expect(called.resolved).not.toHaveBeenCalled();
    + 411 expect(called.rejected).toHaveBeenCalled();
    + 412 done();
    + 413 });
    + 414 });
    + 415 });
    + 416
    + 417 describe('writeTextFile' , () => {
    + 418 describe(dir+'txtFile' , () => {
    + 419 beforeEach(done => {
    + 420 called = getCalled(done);
    + 421 fsUtil.writeTextFile(dir+'txtFile', 'test2').then(called.resolved).catch(called.rejected);
    + 422 });
    + 423
    + 424 it('should resolve', function(done) {
    + 425 expect(called.resolved).toHaveBeenCalled();
    + 426 expect(called.rejected).not.toHaveBeenCalled();
    + 427 done();
    + 428 });
    + 429
    + 430 describe('check for text file', function() {
    + 431 beforeEach(done => {
    + 432 called = getCalled(done);
    + 433 fsUtil.readTextFile(dir+'txtFile').then(called.resolved).catch(called.rejected);
    + 434 });
    + 435
    + 436 it('should exist', function(done) {
    + 437 expect(called.resolved).toHaveBeenCalled();
    + 438 expect(called.rejected).not.toHaveBeenCalled();
    + 439 done();
    + 440 });
    + 441
    + 442 it('should contain payload', function(done) {
    + 443 expect(typeof called.getResult()).toBe('string');
    + 444 expect(called.getResult()).toBe('test2');
    + 445 done();
    + 446 });
    + 447 });
    + 448 });
    + 449 });
    + 450
    + 451 describe('writeJsonFile' , () => {
    + 452 describe(dir+'jsnFile' , () => {
    + 453 beforeEach(done => {
    + 454 called = getCalled(done);
    + 455 fsUtil.writeJsonFile(dir+'jsnFile', {"name":"test2"}).then(called.resolved).catch(called.rejected);
    + 456 });
    + 457
    + 458 it('should resolve', function(done) {
    + 459 expect(called.resolved).toHaveBeenCalled();
    + 460 expect(called.rejected).not.toHaveBeenCalled();
    + 461 done();
    + 462 });
    + 463
    + 464 describe('check for json file', function() {
    + 465 beforeEach(done => {
    + 466 called = getCalled(done);
    + 467 fsUtil.readJsonFile(dir+'jsnFile').then(called.resolved).catch(called.rejected);
    + 468 });
    + 469
    + 470 it('should exist', function(done) {
    + 471 expect(called.resolved).toHaveBeenCalled();
    + 472 expect(called.rejected).not.toHaveBeenCalled();
    + 473 done();
    + 474 });
    + 475
    + 476 it('should contain payload', function(done) {
    + 477 expect(typeof called.getResult()).toBe('object');
    + 478 expect(called.getResult().name).toBe('test2');
    + 479 done();
    + 480 });
    + 481 });
    + 482 });
    + 483
    + 484 describe(dir+'jsn2File' , () => {
    + 485 beforeEach(done => {
    + 486 called = getCalled(done);
    + 487 fsUtil.writeJsonFile(dir+'jsn2File', 'test2').then(called.resolved).catch(called.rejected);
    + 488 });
    + 489
    + 490 it('should resolve', function(done) {
    + 491 expect(called.resolved).toHaveBeenCalled();
    + 492 expect(called.rejected).not.toHaveBeenCalled();
    + 493 done();
    + 494 });
    + 495
    + 496 describe('check for json file', function() {
    + 497 beforeEach(done => {
    + 498 called = getCalled(done);
    + 499 fsUtil.readJsonFile(dir+'jsn2File').then(called.resolved).catch(called.rejected);
    + 500 });
    + 501
    + 502 it('should exist', function(done) {
    + 503 expect(called.resolved).toHaveBeenCalled();
    + 504 expect(called.rejected).not.toHaveBeenCalled();
    + 505 done();
    + 506 });
    + 507
    + 508 it('should contain payload', function(done) {
    + 509 expect(typeof called.getResult()).toBe('string');
    + 510 expect(called.getResult()).toBe('test2');
    + 511 done();
    + 512 });
    + 513 });
    + 514 });
    + 515 });
    + 516
    + 517    describe('delete' , () => {
    + 518 describe(dir+'jsnFile' , () => {
    + 519 beforeEach(done => {
    + 520 called = getCalled(done);
    + 521 fsUtil.writeJsonFile(dir+'jsnFile', {"name":"test2"}).then(called.resolved).catch(called.rejected);
    + 522 });
    + 523
    + 524 it('should have created jsnFile', function(done) {
    + 525 expect(called.resolved).toHaveBeenCalled();
    + 526 expect(called.rejected).not.toHaveBeenCalled();
    + 527 done();
    + 528 });
    + 529
    + 530            describe('check for deletion', function() {
    + 531                beforeEach(done => {
    + 532                    called = getCalled(done);
    + 533                    fsUtil.remove(dir+'jsnFile')
    + 534                        .then(called.resolved)
    + 535                        .catch(called.rejected);
    + 536                });
    + 537                
    + 538                it('should have deleted file', function(done) {
    + 539                    expect(called.resolved).toHaveBeenCalled();
    + 540                    expect(called.rejected).not.toHaveBeenCalled();
    + 541                    fsUtil.isFile(dir+'jsnFile')
    + 542                    .then(exists => {
    + 543                        expect(exists).toBe(false);
    + 544                        done();
    + 545                    }).catch(() => {
    + 546                        fail('error deleting file');
    + 547                    });
    + 548                });
    + 549 });
    + 550 });
    + 551    });
    + 552
    + 553});
    + 554
    + + \ No newline at end of file diff --git a/docs/src/hsNode/httpUtil.html b/docs/src/hsNode/httpUtil.html new file mode 100644 index 0000000..9402335 --- /dev/null +++ b/docs/src/hsNode/httpUtil.html @@ -0,0 +1,75 @@ + + +

    httpUtil.ts

    +
       1const http    = require('http');
    +   2
    +   3/**
    +   4 * @ngdoc object
    +   5 * @name hsNode.httpUtil
    +   6 * @description Convenience functions for http access, wrapped in Promises.
    +   7 * - {@link hsNode.httpUtil#methods_request request}
    +   8 */

    +   9
    +  10//===============================================================================
    +  11//  Low level Promise wrappers
    +  12 
    +  13/**
    +  14 * @ngdoc object
    +  15 * @name request
    +  16 * @methodOf hsNode.httpUtil
    +  17 * @description sends a http request and promises to return the result.
    +  18 * @param {object} options the options to pass along to the request
    +  19 * @param {object} postData optional data to post
    +  20 * @return {Promise} promise to provide the result of the request.
    +  21 */

    +  22export function request(options:any, postData?:any) {
    +  23    return new Promise((resolve:(out:string)=>void, reject:(e:any)=>void) => {
    +  24        let data = ''; 
    +  25        const req = http.request(options, (res:any) => {
    +  26            res.setEncoding('utf8');
    +  27            res.on('data', (chunk:string) => { data += chunk; });
    +  28            res.on('end', () => resolve(data));
    +  29        });
    +  30        req.on('error', (e:any) => reject(e));
    +  31
    +  32        // write data to request body
    +  33        if (postData !== undefined) { req.write(postData); }
    +  34        req.end();
    +  35    });
    +  36}
    +  37
    +  38/**
    +  39 * @ngdoc object
    +  40 * @name get
    +  41 * @methodOf hsNode.httpUtil
    +  42 * @description sends a http get request and promises to return the result.
    +  43 * @param {object} options the options to pass along to the get request
    +  44 * @return {Promise} promise to provide the result of the request.
    +  45 */

    +  46export function get(options:any) {
    +  47    return new Promise((resolve:(out:string)=>void, reject:(e:string)=>void) => {
    +  48        let data = ''; 
    +  49        const req = http.get(options, (res:any) => {
    +  50            res.setEncoding('utf8');
    +  51            res.on('data', (chunk:string) => { data += chunk; });
    +  52            res.on('end', () => resolve(data));
    +  53        });
    +  54
    +  55        req.on('error', (e:string) => reject(e));
    +  56    });
    +  57}
    +  58
    + + \ No newline at end of file diff --git a/docs/src/hsNode/index.html b/docs/src/hsNode/index.html new file mode 100644 index 0000000..698b3ed --- /dev/null +++ b/docs/src/hsNode/index.html @@ -0,0 +1,30 @@ + + +

    index.ts

    +
       1export { default as log }   from "./log";
    +   2export { default as date }  from "./date";
    +   3
    +   4import * as hsNode          from "./node";
    +   5import * as hsExcel         from "./excel";
    +   6export { hsExcel };
    +   7export { hsNode };
    +   8
    +   9
    +  10export *    from "./fsUtil";
    +  11export *    from "./cpUtil";
    +  12
    +  13
    + + \ No newline at end of file diff --git a/docs/src/hsNode/log.html b/docs/src/hsNode/log.html new file mode 100644 index 0000000..f74003b --- /dev/null +++ b/docs/src/hsNode/log.html @@ -0,0 +1,308 @@ + + +

    log.ts

    +
       1/**
    +   2 * @ngdoc object
    +   3 * @name hsNode.log
    +   4 * @description Logging convenience functions.
    +   5 * ## Usage
    +   6 * 

    +   7 * import log from './log';
    +   8 * log.info('by the way:'); // -> 20160817 09:59:08.032 info by the way:
    +   9 * log.error('oh dear!');   // -> 20160817 09:59:08.045 error *** oh dear!
    +  10 * 

    +  11 * 
    +  12 * ### Using the format template:
    +  13 * 

    +  14 * log.format('%MMM %DD %hh%mm%ss');
    +  15 * log.info('by the way:');  // -> Aug 17 095908 info by the way:
    +  16 * log.error('oh dear!');    // -> Aug 17 095908 error *** oh dear!
    +  17 * 

    +  18 * 
    +  19 * ### With module prefix:
    +  20 * 

    +  21 * import log from './log';
    +  22 * log.prefix('Main');
    +  23 * log.format('%hh%mm%ss');
    +  24 * log.info('by the way:');  // -> 09:59:08.032 Main info by the way:
    +  25 * log.error('oh dear!');    // -> 09:59:08.045 Main error *** oh dear!
    +  26 * 

    +  27 * 
    +  28 * ### Using a log file
    +  29 * 

    +  30 * log.format('%MM%DD');
    +  31 * log.info('by the way:'); // -> 0817 info by the way:
    +  32 * log.logFile('l%YY%MM');  // -> 0817 info now logging to file l1608.txt
    +  33 * log.error('oh dear!');   // -> 0817 error *** oh dear!
    +  34 * 

    +  35 * 
    +  36 * ## Reporting Levels:
    +  37 * - [DEBUG](#debug)
    +  38 * - [INFO](#info)
    +  39 * - [WARN](#warn)
    +  40 * - [ERROR](#error)
    +  41 * 
    +  42 * ## Reporting methods
    +  43 * - {@link hsNode.log#methods_debug debug()}
    +  44 * - {@link hsNode.log#methods_info info()}
    +  45 * - {@link hsNode.log#methods_warn warn()}
    +  46 * - {@link hsNode.log#methods_error error()}
    +  47 * 
    +  48 * ## Configurations:
    +  49 * - {@link hsNode.log#methods_level level()}
    +  50 * - {@link hsNode.log#methods_format format()}
    +  51 * - {@link hsNode.log#methods_prefix prefix()}
    +  52 * - {@link hsNode.log#methods_logFile logFile()}
    +  53 */

    +  54
    +  55/** importing nodejs file system function; needed to create logfiles */
    +  56import { date, hsNode, fsUtil } from "./";
    +  57
    +  58/**
    +  59 * @ngdoc property
    +  60 * @propertyOf hsNode.log 
    +  61 * @name DEBUG
    +  62 * @description Debug reporting level with importance 0
    +  63 */

    +  64const DEBUG         = Symbol('DEBUG');
    +  65/**
    +  66 * @ngdoc property
    +  67 * @name INFO
    +  68 * @propertyOf hsNode.log 
    +  69 * @description Info reporting level with importance 1
    +  70 */

    +  71const INFO          = Symbol('INFO');
    +  72/**
    +  73 * @ngdoc property
    +  74 * @name WARN
    +  75 * @propertyOf hsNode.log 
    +  76 * @description Info reporting level with importance 2
    +  77 */

    +  78const WARN          = Symbol('WARN');
    +  79/**
    +  80 * @ngdoc property
    +  81 * @propertyOf hsNode.log 
    +  82 * @name ERROR
    +  83 * @description Warning reporting level with importance 3
    +  84 */

    +  85const ERROR         = Symbol('ERROR');
    +  86
    +  87/**
    +  88 * Type definition for level descriptors
    +  89 */

    +  90interface LevelDesc { importance:number; sym:symbol; desc:string; };
    +  91
    +  92/** map of valid reporting levels */
    +  93const gLevels = {
    +  94    [DEBUG]:    {importance: 0, sym: DEBUG, desc: 'DEBUG'},
    +  95    [INFO]:     {importance: 1, sym: INFO,  desc: 'INFO'},
    +  96    [WARN]:     {importance: 2, sym: WARN,  desc: 'WARN'},
    +  97    [ERROR]:    {importance: 3, sym: ERROR, desc: 'ERROR'}
    +  98};
    +  99
    + 100/** current reporting level, same across all modules */
    + 101var gLevel:LevelDesc = (gLevel===undefined)? gLevels[INFO] : gLevel; 
    + 102console.log('set log level to ' + gLevel.sym.toString());
    + 103
    + 104/** current date format string. See [date module]('_date_.html') */
    + 105let gDateFormat   = '%YYYY%MM%DD %hh:%mm:%ss.%jjj';
    + 106
    + 107/** name of the current log file, or undefined */
    + 108let gLogFile: string; // initially disabled
    + 109
    + 110
    + 111function log() {
    + 112 let gPrefix = '';
    + 113    let gColors = true;
    + 114
    + 115 /**
    + 116  * @ngdoc object
    + 117  * @name level
    + 118  * @methodOf hsNode.log 
    + 119  * @param {String=} newLevel the new reporting level to set. 
    + 120  * If omitted, the method returns the currently set reporting level. 
    + 121  * @description sets the reporting level according to `newLevel`. 
    + 122  * Valid values are {@link hsNode.log.DEBUG DEBUG}, {@link hsNode.log.INFO INFO}, {@link hsNode.log.WARN WARN}, or {@link hsNode.log.ERROR ERROR}.
    + 123  * Subsequent reporting calls
    + 124  * will be filtered such that only calls with an importance at least the same as 
    + 125  * `newLevel` will be written to the log.
    + 126  * @return {Symbol} the new reporting level (DEBUG, INFO, ERROR)
    + 127  */

    + 128 function level(newLevel?:symbol):symbol {
    + 129     if (newLevel) { 
    + 130         if (gLevels[newLevel]) { 
    + 131          let oldLevel = gLevel;
    + 132             gLevel = gLevels[newLevel];
    + 133             let msg = 'new log level \'' + gLevel.desc.toUpperCase() + '\' (was ' + oldLevel.desc.toUpperCase() + ')';
    + 134             out((gLevel.sym === oldLevel.sym)?DEBUG : INFO, msg);
    + 135         }
    + 136         else { out(ERROR, "unkown level " + newLevel.toString() + '; log level remains ' + gLevel.sym.toString()); }
    + 137     }
    + 138     return gLevel.sym;
    + 139 }
    + 140
    + 141 /**
    + 142  * @ngdoc object
    + 143  * @name debug
    + 144  * @methodOf hsNode.log 
    + 145  * @param {string} msg the message to report.
    + 146  * @description reports an debug message to the log. 
    + 147  * The message will actually be reported to the log only if the current 
    + 148  * reporting level is DEBUG or lower.
    + 149  */

    + 150 function debug(msg:string) { out(DEBUG, msg); }
    + 151
    + 152 /**
    + 153  * @ngdoc object
    + 154  * @name info
    + 155  * @methodOf hsNode.log 
    + 156  * @param {string} msg the message to report.
    + 157  * @description reports an informational message to the log. 
    + 158  * The message will actually be reported to the log only if the current 
    + 159  * reporting level is INFO or lower.
    + 160  */

    + 161 function info(msg:string)  { out(INFO, msg); }
    + 162
    + 163 /**
    + 164  * @ngdoc object
    + 165  * @name warn
    + 166  * @methodOf hsNode.log 
    + 167  * @param {string} msg the message to report.
    + 168  * @description reports an warning message to the log. 
    + 169  * The message will actually be reported to the log only if the current 
    + 170  * reporting level is WARN or lower.
    + 171  */

    + 172 function warn(msg:string) { out(WARN, msg); }
    + 173
    + 174 /**
    + 175  * @ngdoc object
    + 176  * @name error
    + 177  * @methodOf hsNode.log 
    + 178  * @param {string} msg the message to report.
    + 179  * @description reports an error message to the log. 
    + 180  * The message will always be reported to the log.
    + 181  */

    + 182 function error(msg:string) { out(ERROR, msg); }
    + 183
    + 184 /**
    + 185  * @ngdoc function
    + 186  * @name dateFormat
    + 187  * @methodOf hsNode.log 
    + 188  * @param {String=} fmtStr the format string to use. 
    + 189  * @return {String} the currently set format string
    + 190  * @description sets the format string to use for logging. If no parameter is specified,
    + 191  * the function returns the currently set format string. The preset is '%YYYY%MM%DD %hh:%mm:%ss.%jjj'
    + 192     * For supported formats see {@link date date}.
    + 193  */

    + 194 function dateFormat(fmtStr?:string):string { 
    + 195     if (fmtStr) { gDateFormat = fmtStr; }
    + 196     return gDateFormat;
    + 197 }
    + 198
    + 199 /**
    + 200  * @ngdoc function
    + 201  * @name prefix
    + 202  * @methodOf hsNode.log 
    + 203  * @param {String=} prf the prefix to prepend. 
    + 204  * @description defines a prefix to be printed for each call to a log function. 
    + 205  * The return object contains all functions defined for export. 
    + 206  */

    + 207 function prefix(prf=''):void {
    + 208        gPrefix = prf? prf + ' ' : '';
    + 209 }
    + 210
    + 211 /**
    + 212  * @ngdoc function
    + 213  * @name logFile
    + 214  * @methodOf hsNode.log 
    + 215  * @param {String} [fileNameTemplate='log-%YYYY-%MM-%DD.txt'] a template to use for log file names. 
    + 216  * To disable logging, use file=''.
    + 217  * @description sets a new logfile name template. Logfiles are created using this template 
    + 218  * at the time of each log entry call. If the file exists, the log entry will be appended.
    + 219  * @return {Promise} promise to return the current logfile name template
    + 220  */

    + 221 function logFile(file='log-%YYYY-%MM-%DD.txt'):Promise {
    + 222        return Promise.resolve(file)
    + 223            .then(file => {
    + 224                if (file !== gLogFile) {
    + 225                    gLogFile = (file==='')? undefined : file;
    + 226                }
    + 227                if (!gLogFile) { info("disabling logfile"); return gLogFile; }
    + 228                if (gLogFile.indexOf('/')>=0) { 
    + 229                    const dir = gLogFile.substring(0, gLogFile.lastIndexOf('/'));
    + 230                    return fsUtil.pathExists(dir).then(exists => {
    + 231                        if (!exists) { 
    + 232                            gLogFile = undefined; 
    + 233                            warn(`path ${dir} doesn't exists; logfile disabled`); 
    + 234                        }
    + 235                        else { info(gLogFile? "now logging to file " + date(gLogFile) : "disabling logfile"); }
    + 236                        return gLogFile;
    + 237                    });
    + 238                }
    + 239                info("now logging to file " + date(gLogFile));
    + 240                return gLogFile;
    + 241            });
    + 242 }
    + 243
    + 244 function out(sym:symbol, msg:any) {
    + 245        const color = { ERROR: '\x1b[31m\x1b[1m', WARN: '\x1b[33m', DEBUG: '\x1b[36m', INFO: '\x1b[32m' };
    + 246 let desc = gLevels[sym];
    + 247     if (desc.importance >= gLevel.importance) {
    + 248         const dateStr = date(gDateFormat);
    + 249         let line = (typeof msg === 'string')? msg : hsNode.inspect(msg, null, gColors);
    + 250         line = gColors? ((color[sym]||"") + dateStr + ' ' + gPrefix + desc.desc + '\x1b[0m ' + line) :
    + 251                            (dateStr + ' ' + gPrefix + desc.desc + ' ' + line);
    + 252         console.log(line);
    + 253         if (msg.stack) { console.log(msg.stack); }
    + 254         if (gLogFile) {
    + 255          const filename = date(gLogFile);
    + 256          fsUtil.appendFile(filename, line+'\n').catch(e => { 
    + 257                    console.log(`error appending to file ${gLogFile}: ${e}`); 
    + 258                    throw new Error(e); });
    + 259         }
    + 260     }
    + 261 }
    + 262
    + 263    function defaultConfig(cfg:{colors?:boolean, logFile?:string, dateFormat?:string, level?:symbol }) {
    + 264        let colors = true;
    + 265        if (cfg.colors!==undefined)     { gColors = colors = cfg.colors; }     // true / false
    + 266        if (cfg.logFile!==undefined)    { logFile(cfg.logFile||undefined); }   // {logFile:null} => logFile(undefined)
    + 267        if (cfg.dateFormat!==undefined) { dateFormat(cfg.dateFormat); }        // e.g. '%YYYY%MM%DD %hh:%mm:%ss.%jjj'
    + 268        if (cfg.level!==undefined)      { level(cfg.level); }                  // e.g. INFO
    + 269     }
    + 270
    + 271 return {
    + 272 DEBUG:     DEBUG,
    + 273 INFO:     INFO,
    + 274 WARN:     WARN,
    + 275 ERROR:     ERROR,
    + 276 level:     level,
    + 277 debug:     debug,
    + 278 info:      info,
    + 279 warn:     warn,
    + 280 error:     error,
    + 281 dateFormat: dateFormat,
    + 282 prefix:     prefix,
    + 283 logFile:    logFile,
    + 284        config:     defaultConfig
    + 285 };
    + 286}
    + 287    
    + 288export default log();
    + 289
    + 290
    + 291
    + + \ No newline at end of file diff --git a/docs/src/hsNode/log.spec.html b/docs/src/hsNode/log.spec.html new file mode 100644 index 0000000..885d858 --- /dev/null +++ b/docs/src/hsNode/log.spec.html @@ -0,0 +1,149 @@ + + +

    log.spec.ts

    +
       1import { fsUtil, log, date }   from './';
    +   2
    +   3describe("log", () => {
    +   4    describe("message", () => {
    +   5        let gLog: any;
    +   6        let gMsg: string;
    +   7        
    +   8        function myLog(msg:string) {
    +   9            gMsg = msg;
    +  10    // gLog('received: '+ msg + '<<');
    +  11        }
    +  12        
    +  13        // avoid logging of level change
    +  14        function setLevel(level:symbol) {
    +  15            log.level(level);
    +  16            gMsg = undefined;
    +  17        }
    +  18
    +  19        beforeEach(function() {
    +  20            gLog = console.log;
    +  21            console.log = myLog;
    +  22            log.level(log.INFO);
    +  23            gMsg = undefined;
    +  24        });
    +  25        
    +  26        afterEach(function() {
    +  27            console.log = gLog;
    +  28        });
    +  29        
    +  30        describe('reporting functions', function() {
    +  31            it('should print info', function() {
    +  32                log.info("yes");
    +  33                expect(log.level()).toBe(log.INFO);
    +  34                expect(gMsg).toMatch(/INFO.*yes/);  
    +  35            });
    +  36            
    +  37            it('should print warning', function() {
    +  38                log.warn("alert");
    +  39                expect(log.level()).toBe(log.INFO);
    +  40                expect(gMsg).toMatch(/WARN.*alert/);  
    +  41            });
    +  42            
    +  43            it('should not print debug at INFO level', function() {
    +  44                setLevel(log.INFO);
    +  45                log.debug('yes');
    +  46                expect(gMsg).toBeUndefined();
    +  47            });
    +  48            
    +  49            it('should set DEBUG level', function() {
    +  50                expect(log.level()).toBe(log.INFO);
    +  51                log.level(log.DEBUG);
    +  52                expect(log.level()).toBe(log.DEBUG);
    +  53                expect(gMsg).toMatch(/new log level 'DEBUG' \(was INFO\)/);
    +  54            });
    +  55            
    +  56            it('should print info at DEBUG level', function() {
    +  57                setLevel(log.DEBUG);
    +  58                log.info('yes');
    +  59                expect(log.level()).toBe(log.DEBUG);
    +  60                expect(gMsg).toMatch(/INFO.*yes/);  
    +  61            });
    +  62            
    +  63            it('should print debug at DEBUG level', function() {
    +  64                log.level(log.DEBUG);
    +  65                expect(log.level()).toBe(log.DEBUG);
    +  66                expect(gMsg).toMatch(/new log level 'DEBUG' \(was INFO\)/);
    +  67                log.debug('yes');
    +  68                expect(gMsg).toMatch(/DEBUG.*yes/);  
    +  69            });
    +  70            
    +  71            it('should print error for invalid level', function() {
    +  72                log.level(Symbol('BOGUS'));
    +  73                expect(gMsg).toMatch(/ unkown level Symbol\(BOGUS\); log level remains Symbol\(INFO\)/);
    +  74                expect(log.level()).toBe(log.INFO);
    +  75            });
    +  76            
    +  77            it('should print error', function() {
    +  78                log.error('yes');
    +  79                expect(gMsg).toMatch(/ERROR.*yes/);
    +  80            });
    +  81        });
    +  82        
    +  83        describe('formatting', function() {
    +  84            it('should print prefix "test"', function() {
    +  85                log.prefix('test');
    +  86                log.info('yes');
    +  87                expect(gMsg).toMatch(/test INFO.*yes/);
    +  88            });
    +  89            
    +  90            it('should print date', function() {
    +  91                let date = new Date();
    +  92                log.config({dateFormat:'%M/%DD/%YY'});
    +  93                log.info('yes');
    +  94                expect(gMsg).toMatch((date.getFullYear()%100) + ' test INFO' );
    +  95                expect(gMsg).toMatch(/test INFO.*yes/);
    +  96            });
    +  97            
    +  98            it('should return dateFormat string', function() {
    +  99                expect(log.dateFormat()).toBe('%M/%DD/%YY');
    + 100            });
    + 101        });                    
    + 102
    + 103        describe('log file', function() {
    + 104            it('should be created next to Gruntfile for default path', done => {
    + 105                log.logFile().then(file => {
    + 106                    expect(file).toMatch(/log-%YYYY-%MM-%DD.txt/);
    + 107                    expect(gMsg).toMatch(/test INFO.*now logging to file/);
    + 108                    if (file) { fsUtil.remove(date(file)).catch(console.log); }
    + 109                    done();
    + 110                });
    + 111            });
    + 112            
    + 113            it('should be stopped for empty path', done => {
    + 114                log.logFile('').then(file => {
    + 115                    expect(file).not.toBeDefined();
    + 116                    expect(gMsg).toMatch(/test INFO.*disabling logfile/);
    + 117                    done();
    + 118                });
    + 119            });
    + 120            
    + 121            it('should be stopped for missing paths', done => {
    + 122                log.logFile('/missing/log.txt').then(file => {
    + 123                    expect(file).not.toBeDefined();
    + 124                    expect(gMsg).toMatch(/test WARN.*path .missing doesn't exists; logfile disabled/);
    + 125                    done();
    + 126                })
    + 127                .catch(() => {});
    + 128            });
    + 129        });
    + 130    });
    + 131});
    + 132
    + + \ No newline at end of file diff --git a/docs/src/hsNode/node.html b/docs/src/hsNode/node.html new file mode 100644 index 0000000..753340e --- /dev/null +++ b/docs/src/hsNode/node.html @@ -0,0 +1,72 @@ + + +

    node.ts

    +
       1/**
    +   2 * @ngdoc overview
    +   3 * @name hsNode
    +   4 * @description 
    +   5 * Utility Modules for use with Node.js
    +   6 * ======================================
    +   7 * Provides
    +   8 * - {@link hsNode.log log}: logging support 
    +   9 * - {@link hsNode.date date}: sprintf-style date formatting 
    +  10 * - {@link hsNode.excel excel}: reading tables from Excel files 
    +  11 * - {@link hsNode.hsLibs hsLibs}: NodeJS module wrapper for hs and hsData libraries 
    +  12 * 
    +  13 * # Test Status: NodeJS
    +  14 *  +  15 *  style="border:none; "
    +  16 *  width="130%" height="500px">
    +  17 *  
    +  18 */

    +  19
    +  20const util  = require('util');
    +  21
    +  22/**
    +  23 * @ngdoc function
    +  24 * @name inspect
    +  25 * @methodOf hsNode.hsLibs
    +  26 * @description inspects the provided obj using the node utilities inspect function.
    +  27 * @param {obejct} obj the object to inspect
    +  28 * @param {number} depth the depth-level to report on, or inifinite depth if omitted
    +  29 * @param {boolean} color the depth-level to report on, or inifinite depth if omitted
    +  30 * @return {string} a color-formatted string representing `obj`
    +  31 */

    +  32export function inspect(obj:any, depth:number=null, colors=true) {
    +  33    return util.inspect(obj, {colors:colors, depth:depth});
    +  34}
    +  35
    +  36/**
    +  37 * @ngdoc function
    +  38 * @name timeout
    +  39 * @methodOf hsNode.hsLibs
    +  40 * @description timeout promise for use in Promise.race().
    +  41 * @param {number} ms the milliseconds to wait before rejecting
    +  42 * @return {Promise} a Promise that rejects after `ms` 
    +  43 */

    +  44export function timeout(ms:number) { return new Promise((resolve, reject) => { setTimeout(reject, ms); }); }
    +  45
    +  46/**
    +  47 * @ngdoc function
    +  48 * @name delay
    +  49 * @methodOf hsNode.hsLibs
    +  50 * @description delay promise for use in delay(ms).then(doSomething).
    +  51 * @param number ms the milliseconds to wait before resolving
    +  52 * @return a Promise that resolves after `ms` 
    +  53 */

    +  54export function delay(ms:number)   { return new Promise(resolve => { setTimeout(resolve, ms); }); }
    +  55
    + + \ No newline at end of file diff --git a/docs/src/hsNode/node.spec.html b/docs/src/hsNode/node.spec.html new file mode 100644 index 0000000..faf57f3 --- /dev/null +++ b/docs/src/hsNode/node.spec.html @@ -0,0 +1,75 @@ + + +

    node.spec.ts

    +
       1import { hsNode } from './';
    +   2
    +   3describe("node", () => {
    +   4    describe("inspect", () => {
    +   5        it('should decompose {a:"yes", b:[1,2,3]}', () => {
    +   6            expect(hsNode.inspect({a:"yes", b:[1,2,3]}, null, false)).toEqual("{ a: 'yes', b: [ 1, 2, 3 ] }");
    +   7        });
    +   8        it('should report in color', () => {
    +   9            expect(hsNode.inspect({a:"yes", b:[1,2,3]})).not.toEqual(jasmine.stringMatching("{ a: 'yes', b: [ 1, 2, 3 ] }"));
    +  10            expect(hsNode.inspect({a:"yes", b:[1,2,3]})).toEqual(jasmine.stringMatching("'yes'"));
    +  11            expect(hsNode.inspect({a:"yes", b:[1,2,3]})).toEqual(jasmine.stringMatching("[ 1, 2, 3 ]"));
    +  12        });
    +  13        it('should report first level only', () => {
    +  14            expect(hsNode.inspect({a:"yes", b:[1,2,3]}, null, false)).toEqual("{ a: 'yes', b: [ 1, 2, 3 ] }");
    +  15            expect(hsNode.inspect({a:"yes", b:[1,2,3]}, 0, false)).toEqual("{ a: 'yes', b: [Array] }");
    +  16            expect(hsNode.inspect({a:"yes", b:[1,2,3]}, 1, false)).toEqual("{ a: 'yes', b: [ 1, 2, 3 ] }");
    +  17        });
    +  18    });
    +  19
    +  20    describe("timeout", () => {
    +  21        let reject: () => void; 
    +  22        let resolve:() => void;
    +  23        beforeEach(done => { 
    +  24            resolve = jasmine.createSpy("resolve");
    +  25            reject = jasmine.createSpy("reject");
    +  26            hsNode.timeout(100)
    +  27                .then(resolve)
    +  28                .catch(reject);
    +  29            setTimeout(done, 101);
    +  30        });
    +  31        
    +  32        it('should fail after 100ms', done => {
    +  33            expect(resolve).not.toHaveBeenCalled();
    +  34            expect(reject).toHaveBeenCalled();
    +  35            done();
    +  36        });
    +  37    });
    +  38
    +  39    describe("delay", () => {
    +  40        let reject: () => void; 
    +  41        let resolve:() => void;
    +  42        beforeEach(done => { 
    +  43            resolve = jasmine.createSpy("resolve");
    +  44            reject = jasmine.createSpy("reject");
    +  45            hsNode.delay(100)
    +  46                .then(resolve)
    +  47                .catch(reject);
    +  48            setTimeout(done, 101);
    +  49        });
    +  50        
    +  51        it('should resolve after 100ms', done => {
    +  52            expect(resolve).toHaveBeenCalled();
    +  53            expect(reject).not.toHaveBeenCalled();
    +  54            done();
    +  55        });
    +  56    });
    +  57});
    +  58
    + + \ No newline at end of file diff --git a/docs/src/hsStock/Home.html b/docs/src/hsStock/Home.html new file mode 100644 index 0000000..a8b8563 --- /dev/null +++ b/docs/src/hsStock/Home.html @@ -0,0 +1,65 @@ + + +

    Home.ts

    +
       1import { m }            from 'hslayout';
    +   2import { Layout }       from 'hslayout';
    +   3import { Menu }         from 'hswidget';
    +   4import { SelectorDesc } from 'hswidget';
    +   5import { Vnode}         from 'hslayout';
    +   6import { ViewPane }      from './view/ViewPane';
    +   7import { TradePane }     from './view/TradePane';
    +   8import { ImportPane }    from './view/ImportPane';
    +   9
    +  10const TitleHeight        = '30px'; 
    +  11
    +  12const modes = [
    +  13    {name: 'View',   css: '.hs-selectable-view'},
    +  14    {name: 'Trade',  css: '.hs-selectable-trade'},
    +  15    {name: 'Import', css: '.hs-selectable-import'}
    +  16];
    +  17
    +  18export const Home = {
    +  19    view: () =>  m('', [Site(), SiteFooter()])
    +  20};
    +  21
    +  22const Site = () => {
    +  23    let siteContent;
    +  24    switch(m.route.param('mode')) {
    +  25        case modes[2].name:  siteContent = ImportPane; break;
    +  26        case modes[1].name:   siteContent = TradePane; break;
    +  27        case modes[0].name:
    +  28        default:        siteContent = ViewPane; break;
    +  29    }
    +  30    return m(Layout, {rows: [TitleHeight, "fill"], css: '.hs-site', content: [
    +  31        m(SiteMenu, {css: 'hs-site-menu'}),
    +  32        m(siteContent),
    +  33    ]});
    +  34};
    +  35
    +  36const SiteMenu = { 
    +  37    view: (node: Vnode):Vnode => {
    +  38        return m(Menu, {desc: 
    +  39            items: modes.map((c:any) => c.name),
    +  40            itemCss: modes.map((c:any) => c.css),
    +  41            selectedItem: modes.find((md:any) => md.name === m.route.param('mode')).name,
    +  42            changed: (item:string) => m.route.set('/site/:mode/:symbol', {mode:item, symbol:0}) 
    +  43        }});
    +  44    }
    +  45};
    +  46
    +  47const SiteFooter = () => m('.hs-site-footer', '(c) Helpful Scripts');
    +  48
    + + \ No newline at end of file diff --git a/docs/src/hsStock/Router.html b/docs/src/hsStock/Router.html new file mode 100644 index 0000000..988112b --- /dev/null +++ b/docs/src/hsStock/Router.html @@ -0,0 +1,82 @@ + + +

    Router.ts

    +
       1
    +   2import { m }        from 'hslayout';
    +   3import { Home }     from './Home';
    +   4import { Button }   from 'hswidget';
    +   5
    +   6//const SAVE_URL      = '/cgi/save.js';
    +   7//const REGISTER_URL      = '/cgi/register.js';
    +   8
    +   9m.route.prefix("?");
    +  10
    +  11let authMode   = 'View';
    +  12let authSymbol = 'GOOG';
    +  13
    +  14const Auth = {
    +  15    username: "",
    +  16    password: "",
    +  17    
    +  18    setUsername: (value:string) => Auth.username = value,
    +  19    setPassword: (value:string) => Auth.password = value,
    +  20    login: function() {
    +  21        return m.request({
    +  22            url: `/stocks/private/test.json`,  
    +  23            user: Auth.username,
    +  24            password: Auth.password
    +  25        }).then(() => {
    +  26            console.log(`logged in as ${Auth.username}`);
    +  27            localStorage.setItem("auth-token", Auth.username);
    +  28            m.route.set(`/site/${authMode}/${authSymbol}`);
    +  29        }).catch((err:any) => {
    +  30            if (err.status === 401) {
    +  31                console.log('Authorization Error (401)');
    +  32            } else {
    +  33                console.log(err);
    +  34            }
    +  35        });
    +  36    }
    +  37};
    +  38
    +  39const Login = {
    +  40    view: function() {
    +  41        return m(".hs-form", [
    +  42            m("input[type=text][placeholder='Name']",         {oninput: m.withAttr("value", Auth.setUsername), value: Auth.username}),
    +  43            m("input[type=password][placeholder='Password']", {oninput: m.withAttr("value", Auth.setPassword), value: Auth.password}),
    +  44            m(Button, {name:'Login', onclick:Auth.login})
    +  45        ]);
    +  46    }
    +  47};
    +  48
    +  49
    +  50m.route(document.body, "/site/View", {
    +  51    "/site/:mode":           Home,
    +  52    "/site/:mode/:symbol":   Home,
    +  53    "/login": Login
    +  54});
    +  55
    +  56export function authenticated():boolean {
    +  57    if (!localStorage.getItem("auth-token")) { 
    +  58        authMode   = m.route.param('mode');
    +  59        authSymbol = m.route.param('symbol');
    +  60        m.route.set("/login"); 
    +  61        return false;
    +  62    } else {
    +  63        return true;
    +  64    }
    +  65}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/Site.html b/docs/src/hsStock/Site.html new file mode 100644 index 0000000..641aece --- /dev/null +++ b/docs/src/hsStock/Site.html @@ -0,0 +1,70 @@ + + +

    Site.ts

    +
       1/**
    +   2 * Site documentation
    +   3 */

    +   4
    +   5/** */
    +   6import * as hslayout  from 'hslayout';
    +   7
    +   8const TitleHeight   = '30px'; 
    +   9const FooterHeight  = '10px';  
    +  10
    +  11const myConfig = {
    +  12    Container: { // whole page
    +  13        rows:  [TitleHeight, "fill", FooterHeight],
    +  14        css: '.hs-site',
    +  15/*        
    +  16        content: [{
    +  17            Container: {
    +  18                columns: ['50%'],
    +  19                css: '.hs-site',
    +  20                content: 'Header2'
    +  21        }},{
    +  22            Container: {
    +  23                columns: ['50%'],
    +  24                css: '.hs-site',
    +  25                content: 'Main'
    +  26        }},{
    +  27            Container: {
    +  28                columns: ['50%'],
    +  29                css: '.hs-site',
    +  30                content: 'Footer'
    +  31        }}
    +  32        ] 
    +  33*/
                
    +  34        content: ['Header', 'Main Part', 'Footer']
    +  35    },
    +  36    route: {
    +  37        default: '/api',
    +  38        paths: [
    +  39            '/api',             // defines `http://localhost/#!/api/
    +  40            '/api/:lib',        // defines `http://localhost/#!/api/:hsLib
    +  41            '/api/:lib/:field'  // defines `http://localhost/#!/api/:hsLib/:id        
    +  42        ]
    +  43    }
    +  44}; 
    +  45
    +  46
    +  47export function init() {
    +  48    new hslayout.HsConfig([hslayout]).attachNodeTree(myConfig, document.body);
    +  49}
    +  50
    +  51
    +  52
    +  53
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/Assets.html b/docs/src/hsStock/controller/Assets.html new file mode 100644 index 0000000..a8ad037 --- /dev/null +++ b/docs/src/hsStock/controller/Assets.html @@ -0,0 +1,78 @@ + + +

    controller/Assets.ts

    +
       1import { m } from 'hslayout';
    +   2
    +   3const assetFile = 'private/transactions.json';
    +   4
    +   5const recode = {
    +   6    CASH: '_cash'
    +   7};
    +   8
    +   9export interface Transaction {
    +  10    /** the date of trade */
    +  11    Date: Date;
    +  12    /** the equity symbol being traded */
    +  13    symbol: string;
    +  14    /** the number of shares being bought (positive) or sold (negative) */
    +  15    change: number;
    +  16    /** the total number of shares after the transaction */
    +  17    total: number;
    +  18    price?: number;
    +  19    appliedSplits?: {[splitDateMS:number]: number};
    +  20}
    +  21
    +  22export interface TransactionList {
    +  23    [sym:string]: {
    +  24        /** most recent trade date */
    +  25        latestDate: Date;
    +  26        /** total shares after most recent trade */
    +  27        latestShares: number;
    +  28        trades: Transaction[];
    +  29    };
    +  30}
    +  31
    +  32function fileToList(data:any):TransactionList {
    +  33    const list: TransactionList = {};
    +  34    Object.keys(data).forEach((sym:string) => {
    +  35        sym = recode[sym] || sym;
    +  36        data[sym]
    +  37        .map((entry:any) => { 
    +  38            entry.Date = new Date(entry.date); 
    +  39            delete entry.date;
    +  40            return entry; 
    +  41        })
    +  42        .sort((a:any, b:any)=> a.Date < b.Date);
    +  43        const latestTrade = data[sym][data[sym].length-1];
    +  44        list[sym] = {
    +  45            latestDate:latestTrade.Date,
    +  46            latestShares: latestTrade.total,
    +  47            trades:[]
    +  48        };
    +  49        data[sym].forEach((trade:any) => {
    +  50            list[sym].trades.push(trade);
    +  51            if (typeof trade.Date === 'string') { trade.Date = new Date(trade.Date); }
    +  52        });
    +  53    });
    +  54    return list;
    +  55}
    +  56
    +  57export function readAssets(): Promise {
    +  58    return m.request({url: assetFile})
    +  59    .then(fileToList)
    +  60    .catch(console.log);
    +  61}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/Equities.html b/docs/src/hsStock/controller/Equities.html new file mode 100644 index 0000000..429c32f --- /dev/null +++ b/docs/src/hsStock/controller/Equities.html @@ -0,0 +1,195 @@ + + +

    controller/Equities.ts

    +
       1import { EquityList }       from './EquityList'; 
    +   2import { EquityLoader }     from './EquityLoader'; 
    +   3import { Transaction }      from './Assets';
    +   4import { DataSet }          from 'hsdata';
    +   5import { VenueIDs, 
    +   6         VenueSummary }     from './Venue';
    +   7
    +   8export interface Category {
    +   9    cat:      string;         // the category name
    +  10    equities: EquityItem[];   // array of equities in this category
    +  11}
    +  12
    +  13export interface ItemStats {
    +  14    /** most recent trade date */
    +  15    latestDate?:        Date;
    +  16    /** most recent trade price */
    +  17    latestPrice? :      number;
    +  18
    +  19    /* last close price */
    +  20    closePrice?:        number;
    +  21    /** last close date */
    +  22    closeDate?:         Date;
    +  23    /** last close volume */
    +  24    closeVolume?:       number;
    +  25
    +  26    /** since previous close */
    +  27    change?:            number;
    +  28    /** price-to-earnings ratio */
    +  29    peRatio?:           number;
    +  30    /** 52 week high */
    +  31    week52high?:        number;
    +  32    /** 52 week low */
    +  33    week52low?:         number;
    +  34    /** market capitalziation */
    +  35    marketCap?:         number;
    +  36    /** total cash (Trailing twelve months) */
    +  37    cash?:              number;
    +  38    /** total revenue (Trailing twelve months) */
    +  39    revenue?:           number;
    +  40    /** total earnings (Trailing twelve months) */
    +  41    EBITDA?:            number;
    +  42    /** latest Earnings per Share */
    +  43    latestEPS?:         number;
    +  44    /** date of latest Earnings per Share */
    +  45    latestEPSDate?:     Date;
    +  46    /** dividend rate */
    +  47    dividendRate?:      number;
    +  48    /** dividend rate */
    +  49    dividendYield?:     number; 
    +  50    /** date of dividend */
    +  51    exDividendDate?:    Date;
    +  52}
    +  53
    +  54export interface EquitySplit {
    +  55    date:           Date;
    +  56    ratio:          number; // refers to the split ratio. The split ratio is an inverse of the number of shares that a holder of the stock would have after the split divided by the number of shares that the holder had before. 
    +  57                            // For example: Split ratio of .5 = 2 for 1 split.
    +  58}
    +  59
    +  60export interface EquityItem {
    +  61    /** equity symbol, e.g. 'GOOG' */
    +  62    symbol: string; 
    +  63    /** equity name, e.g. 'Alphabet' */
    +  64    name:   string;
    +  65    /** investment category, e.g. 'Stocks' */
    +  66    cat:    string;
    +  67
    +  68    /** set of traders that do not know this symbol */
    +  69    invalid?: {};
    +  70    venues?:  VenueIDs[];
    +  71
    +  72    /** number of shares owned */
    +  73    shares?: number;
    +  74    /** transaction history */
    +  75    trades?:Transaction[];
    +  76
    +  77    company?: {
    +  78        /** industry sector */
    +  79        sector?:    string;
    +  80        /** primary trading exchange */
    +  81        primaryExchange?: string;
    +  82    };
    +  83
    +  84    stats?: ItemStats;
    +  85    quotes?: DataSet;
    +  86    intraday?: DataSet;
    +  87    otherStats?:  any;
    +  88    splits?: EquitySplit[];
    +  89    changed?: boolean;
    +  90}
    +  91
    +  92
    +  93export class Equities {
    +  94    private static assembleCategories(items:EquityItem[]):Category[] {
    +  95        const categories:Category[] = [];
    +  96        items.forEach((item:EquityItem) => {
    +  97            let cat:Category = categories[item.cat];
    +  98            if (!cat) {
    +  99                cat = categories[item.cat] = {
    + 100                    cat: item.cat,
    + 101                    equities: []
    + 102                };
    + 103                categories.push(cat);
    + 104            };
    + 105            cat.equities.push(item);
    + 106        });
    + 107        categories.forEach((c:Category) => {
    + 108            c.equities.sort((a:EquityItem, b:EquityItem) => {
    + 109                if (a.shares > 0 || b.shares > 0) {
    + 110                    const diff = (b.shares || 0) - (a.shares || 0);
    + 111                    if (diff !== 0) { return diff; }
    + 112                }
    + 113                return (a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0);
    + 114            });
    + 115        });
    + 116        return categories; 
    + 117    }
    + 118
    + 119    //------  private parts -----
    + 120    private static equityList: EquityList;
    + 121    private static equityLoader: EquityLoader;
    + 122
    + 123
    + 124    //------  public parts -----
    + 125    constructor() { 
    + 126        if (!Equities.equityList)    { Equities.equityList     = new EquityList(); }
    + 127        if (!Equities.equityLoader)  { 
    + 128            Equities.equityLoader  = new EquityLoader(Equities.equityList); 
    + 129            Equities.equityLoader.loadEquityList();
    + 130        }
    + 131    }
    + 132
    + 133    public addItem(item:EquityItem):EquityItem {
    + 134        item = Equities.equityList.addItem(item);
    + 135        Equities.equityLoader.loadLocal(item);
    + 136        EquityLoader.saveEquityList(Equities.equityList.getAllSymbols());
    + 137        return item;
    + 138    }
    + 139
    + 140    public removeItem(itemOrSymbol:EquityItem|string) {
    + 141        Equities.equityList.removeItem(itemOrSymbol);
    + 142        EquityLoader.saveEquityList(Equities.equityList.getAllSymbols());
    + 143    }
    + 144
    + 145    public getItem(sym:string) { return Equities.equityList.getItem(sym); }
    + 146
    + 147    public getCategories():Category[] { 
    + 148        return Equities.assembleCategories(
    + 149            Equities.equityList.getAllSymbols().map(Equities.equityList.getItem.bind(Equities.equityList))
    + 150        );
    + 151    }
    + 152
    + 153    public getFirstByCat(cat:string):EquityItem {
    + 154        const c = this.getCategories()[cat];
    + 155        if (c && c.equities.length>0) { return c.equities[0]; }
    + 156        else { return Equities.equityList.unkownEquity(); }
    + 157    }
    + 158
    + 159    public getMarketUpdate():Promise { 
    + 160        return Equities.equityLoader.marketUpdate()
    + 161        .catch((err:any) => {
    + 162            console.log(err);
    + 163            return false;
    + 164        })
    + 165        .then(() => true); 
    + 166    }
    + 167    public getVenueSymbols():Promise { 
    + 168        return EquityLoader.getTrader().requestSymbols(); 
    + 169    }
    + 170    public readSplits()      { return Equities.equityLoader.requestSplitsIfMissing(); }
    + 171
    + 172    public applySplitsToTrades(item:EquityItem) {
    + 173        return EquityLoader.applySplitsToTrades(item);
    + 174    }
    + 175}
    + 176
    + 177export const gEquities = new Equities();
    + 178
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/Equity.html b/docs/src/hsStock/controller/Equity.html new file mode 100644 index 0000000..9d6d766 --- /dev/null +++ b/docs/src/hsStock/controller/Equity.html @@ -0,0 +1,493 @@ + + +

    controller/Equity.ts

    +
       1import { DataSet, DataRow }      from 'hsdata';
    +   2import { Trader,
    +   3         TraderSplit }  from './Trader';
    +   4import { ms }           from 'hsutil'; 
    +   5import { load, save }   from '../fileIO';
    +   6import { Transaction }  from './Assets';
    +   7
    +   8const DEF_EQUITY_LIST   = 'defEquityList.json';
    +   9const EQUITY_LIST       = 'equityList.json';
    +  10const SAVE_PATH         = 'hsStock/data';   // relative to 'apps/', defines in save.js cgi
    +  11const LOAD_PATH         = 'data';           // relative to 'hsStock/', root of webapp location
    +  12
    +  13export interface Category {
    +  14    cat:      string;         // the category name
    +  15    equities: EquityItem[];   // array of equities in this category
    +  16}
    +  17
    +  18export interface ItemStats {
    +  19    /** most recent trade date */
    +  20    latestDate?:        Date;
    +  21    /** most recent trade price */
    +  22    latestPrice? :      number;
    +  23
    +  24    /* last close price */
    +  25    closePrice?:        number;
    +  26    /** last close date */
    +  27    closeDate?:         Date;
    +  28    /** last close volume */
    +  29    closeVolume?:       number;
    +  30
    +  31    /** since previous close */
    +  32    change?:            number;
    +  33    /** price-to-earnings ratio */
    +  34    peRatio?:           number;
    +  35    /** 52 week high */
    +  36    week52high?:        number;
    +  37    /** 52 week low */
    +  38    week52low?:         number;
    +  39    /** market capitalziation */
    +  40    marketCap?:         number;
    +  41    /** total cash (Trailing twelve months) */
    +  42    cash?:              number;
    +  43    /** total revenue (Trailing twelve months) */
    +  44    revenue?:           number;
    +  45    /** total earnings (Trailing twelve months) */
    +  46    EBITDA?:            number;
    +  47    /** latest Earnings per Share */
    +  48    latestEPS?:         number;
    +  49    /** date of latest Earnings per Share */
    +  50    latestEPSDate?:     Date;
    +  51    /** dividend rate */
    +  52    dividendRate?:      number;
    +  53    /** dividend rate */
    +  54    dividendYield?:     number; 
    +  55    /** date of dividend */
    +  56    exDividendDate?:    Date;
    +  57}
    +  58
    +  59export interface EquityItem {
    +  60    /** equity symbol, e.g. 'GOOG' */
    +  61    symbol: string; 
    +  62    /** equity name, e.g. 'Alphabet' */
    +  63    name:   string;
    +  64    /** investment category, e.g. 'Stocks' */
    +  65    cat:    string;
    +  66
    +  67    /** set of traders that do not know this symbol */
    +  68    invalid?: {};
    +  69
    +  70    /** number of shares owned */
    +  71    shares?: number;
    +  72    /** transaction history */
    +  73    trades?:Transaction[];
    +  74
    +  75    company?: {
    +  76        /** industry sector */
    +  77        sector?:    string;
    +  78        /** primary trading exchange */
    +  79        primaryExchange?: string;
    +  80    };
    +  81
    +  82    stats?: ItemStats;
    +  83    quotes?: DataSet;
    +  84    intraday?: DataSet;
    +  85    otherStats?:  any;
    +  86    splits?: TraderSplit[];
    +  87    changed?: boolean;
    +  88}
    +  89
    +  90function saveQuotes(item:EquityItem):Promise {
    +  91    return save(item.quotes, `${SAVE_PATH}/stock/quotes${item.symbol}.json`)
    +  92    .then(() => item);
    +  93}
    +  94
    +  95/** saves equity inof to symXXX.json file, skipping the quotes */
    +  96function saveMeta(item:EquityItem):EquityItem {
    +  97    const copyPropertiesToItem = (item:EquityItem, data:EquityItem):EquityItem => {
    +  98        Object.keys(item).forEach((k:string) => data[k] = item[k]); 
    +  99        return data;             // continue working with original item
    + 100    };
    + 101
    + 102    if (item.changed) {
    + 103        item.changed = undefined;
    + 104        console.log(`saving stock/sym${item.symbol}.json`);
    + 105        const copy = copyPropertiesToItem(item, {});
    + 106//        delete copy.intraday;
    + 107        delete copy.quotes;
    + 108        delete copy.trades;
    + 109        save(copy, `${SAVE_PATH}/stock/sym${item.symbol}.json`);
    + 110    }
    + 111    return item;
    + 112}
    + 113
    + 114function updateMetaFromTrader(item:EquityItem) {
    + 115//    console.log(`${item.symbol} id out of date`);
    + 116    item.changed = true;
    + 117    return EquityList.getTrader().getMeta(item);
    + 118};
    + 119
    + 120function checkProperties(item:EquityItem):EquityItem {
    + 121    if (item.company && item.company.sector) { 
    + 122        if (item.cat !== item.company.sector) {
    + 123            item.cat = item.company.sector;
    + 124            item.changed = true;
    + 125        }
    + 126    }
    + 127    item.stats.closePrice = item.stats.closePrice || (item.otherStats? item.otherStats.close : -1);
    + 128    if (!item.stats.closeDate) {
    + 129        if (item.otherStats) {
    + 130            item.stats.closeDate = new Date(item.otherStats.closeTime);
    + 131        } else {
    + 132            console.log(`not item.otherStats for ${item.symbol}`);
    + 133        }
    + 134    }
    + 135    if (item.stats['latestVolume']) { delete item.stats['latestVolume']; }
    + 136    return item;
    + 137}
    + 138
    + 139
    + 140function loadMeta(item:EquityItem):Promise {
    + 141    const copyPropertiesToItem = (data:EquityItem):EquityItem => {
    + 142        Object.keys(data).forEach((k:string) => item[k] = data[k]); 
    + 143        return item;             // continue working with original item
    + 144    };
    + 145
    + 146    function loadSplitsIfMissing (item:EquityItem):Promise {
    + 147        return (!item.splits || item.splits.length === 0)? 
    + 148            this.readSymSplit(item) : 
    + 149            Promise.resolve(item);
    + 150    }
    + 151
    + 152    return load(`${LOAD_PATH}/stock/sym${item.symbol}.json`)
    + 153        // if nothing on local server: ignore
    + 154        .catch(() => item)
    + 155        .then(updateMetaFromTrader)
    + 156        .then(copyPropertiesToItem)
    + 157        .then(checkProperties)
    + 158        .then(loadQuotesIfOutdated)
    + 159        .then(loadSplitsIfMissing.bind(gEquityList))
    + 160        .then(applySplitsToTrades)  // new splits are only loaded upon specific request
    + 161        .then(saveMeta);
    + 162}
    + 163
    + 164/** impute trades with share price */
    + 165function imputeTradesWithSharePrice(item:EquityItem):EquityItem {
    + 166    if (item.trades) {
    + 167        item.trades.forEach((trade:Transaction) => { 
    + 168            if (!(trade.Date instanceof Date)) { trade.Date = new Date(trade.Date); }        
    + 169            if (trade.price) {
    + 170                if (typeof trade.price === 'string') {
    + 171                    trade.price = parseFloat(trade.price);
    + 172                    item.changed = true;
    + 173                }
    + 174            } else {
    + 175                item.changed = true;
    + 176                const row:any = item.quotes.rows.find((t:any) => {
    + 177                    if (!(t[0] instanceof Date)) { t[0] = new Date(t[0]); }
    + 178                    return t[0]>trade.Date;
    + 179                });
    + 180                trade.price = row? row[2] : 20;
    + 181            }
    + 182        });
    + 183    }    
    + 184    return item;            
    + 185};
    + 186
    + 187function updateStats(item: EquityItem):EquityItem {
    + 188    if (item.quotes.rows.length > 0) {
    + 189        const date = item.stats.closeDate;
    + 190        const dCol = item.quotes.names.indexOf('Date');
    + 191        const vCol = item.quotes.names.indexOf('Volume');
    + 192        const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    + 193        if (new Date(latestRow[dCol]) === date) {
    + 194            item.stats.closeVolume = latestRow[vCol];
    + 195        }
    + 196    }
    + 197    return item;
    + 198}
    + 199
    + 200/** read quotes from trader */
    + 201function get5yrQuotesFromTrader(item:EquityItem):Promise {
    + 202    return EquityList.getTrader().getQuotes(item, '5y')
    + 203    .then((data:DataSet):EquityItem => { item.quotes = data; return item; })
    + 204    .then(saveQuotes);
    + 205}
    + 206
    + 207
    + 208function updateQuotesFromDataSet(data:DataSet, item:EquityItem):EquityItem {
    + 209    if (item.quotes.rows.length > 0) {
    + 210        const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    + 211        const dCol = item.quotes.names.indexOf('Date');
    + 212        const lastItemDate = new Date(latestRow[dCol]);
    + 213        data.rows.forEach((row:any[]) => {
    + 214            const rowDate = (typeof row[dCol] === 'string')? new Date(row[dCol]) : row[dCol];
    + 215            if (rowDate > lastItemDate) { item.quotes.rows.push(row); }
    + 216        });
    + 217    }
    + 218    return item;
    + 219}
    + 220
    + 221/** read quotes from trader */
    + 222function getMissingRecentQuotesAndSave(item:EquityItem):Promise {
    + 223    let timeCode;
    + 224    if (item.quotes.rows.length === 0) {
    + 225        timeCode = '5yr';
    + 226    } else {
    + 227        const dCol      = item.quotes.names.indexOf('Date');
    + 228        const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    + 229        const missingDays = ms.toDays(new Date().getTime() - new Date(latestRow[dCol]).getTime());
    + 230        if (missingDays > 720)  { timeCode = '5yr'; }
    + 231        if (missingDays > 360)  { timeCode = '2yr'; }
    + 232        if (missingDays > 170)  { timeCode = '1yr'; }
    + 233        if (missingDays > 80)   { timeCode = '6m'; }
    + 234        if (missingDays > 28)   { timeCode = '3m'; }
    + 235        if (missingDays > 1)    { timeCode = '1m'; }
    + 236    } 
    + 237    
    + 238    if (timeCode) {
    + 239        return EquityList.getTrader().getQuotes(item, timeCode)
    + 240        .then((data:DataSet):EquityItem => updateQuotesFromDataSet(data, item))
    + 241        .then(saveQuotes);
    + 242    } else {
    + 243        return Promise.resolve(item);
    + 244    }
    + 245}
    + 246
    + 247function getIntradayQuotes(item:EquityItem):Promise {
    + 248    return EquityList.getTrader().getQuotes(item, '1d')
    + 249    .then((data:DataSet):EquityItem => { 
    + 250        const dCol = data.names.indexOf('Data');
    + 251        item.intraday.names = data.names;
    + 252        item.intraday.rows  = data.rows.filter((row:DataRow) => row[dCol]);
    + 253        return item;
    + 254    });
    + 255}
    + 256
    + 257
    + 258function loadQuotesIfOutdated(item:EquityItem):Promise {
    + 259    /** adds a quotes DataSet to an item  */
    + 260    const addQuotesToItem = (quotes:DataSet):EquityItem=> { 
    + 261        item.quotes = quotes;
    + 262        return item;
    + 263    };
    + 264    return load(`${LOAD_PATH}/stock/quotes${item.symbol}.json`)
    + 265        .then(addQuotesToItem)
    + 266        .catch(() => get5yrQuotesFromTrader(item))
    + 267        .then(getMissingRecentQuotesAndSave)
    + 268        .then(getIntradayQuotes)
    + 269        .then(updateStats)
    + 270        .then(imputeTradesWithSharePrice)
    + 271        ;
    + 272}
    + 273
    + 274function applySplitsToTrades(item:EquityItem):EquityItem {    
    + 275    if (item.splits && item.trades) {
    + 276        item.splits.forEach((split:TraderSplit) => {
    + 277            if (typeof split.date === 'string') { split.date = new Date(split.date); }
    + 278            item.trades.forEach((trade:Transaction) => {
    + 279                if (trade.Date < split.date) {
    + 280                    trade.price *= split.ratio;
    + 281                }
    + 282            });
    + 283        });
    + 284    }
    + 285    return item;
    + 286}
    + 287
    + 288function loadSplits(item:EquityItem):Promise {
    + 289    const addSplitsToItem = (splits:TraderSplit[]):EquityItem => { item.splits = splits; return item; };
    + 290    if (item.splits && item.splits.length===0) { item.splits = undefined; }
    + 291    return (item.splits)? Promise.resolve(item) :
    + 292        EquityList.getTrader().getSplits(item)
    + 293        .then(addSplitsToItem);
    + 294}
    + 295
    + 296function EquityList2JSON(list:EquityList):any {
    + 297    const data:any = {};
    + 298    list.getCategories().forEach((c:Category) => {
    + 299        data[c.cat] = {};
    + 300        c.equities.forEach((e:EquityItem) => {
    + 301            data[c.cat][e.symbol] = e.name;
    + 302        });
    + 303    });
    + 304    return data;
    + 305
    + 306
    + 307
    + 308
    + 309export class EquityList {
    + 310    //------  Static  parts -----
    + 311    private static trader = new Trader();
    + 312    private static lastUpdate:Date;
    + 313    private static marketUpdated(since:Date): Promise {
    + 314        const closingHour = 16;     // venue closes at 4pm PT;
    + 315        return EquityList.trader.lastMarketUpdate()
    + 316        .then((lastUpdated:Date) => {
    + 317            const today = new Date();
    + 318            EquityList.lastUpdate = today;
    + 319            if (!since) { return true; }                // no recent update
    + 320            if (lastUpdated < since) { return false; }   // no updates since
    + 321            if ((today.getDay()+6)%7 < 5)  {            // Mo-Fri: during trading days
    + 322                if (today.getTime() - lastUpdated.getTime() > ms.fromHours(24))
    + 323                    { return true; }                    //    --> more than a day old
    + 324                if (lastUpdated.getHours() < closingHour-1) {       // during trading hours
    + 325                    if (today.getTime() - lastUpdated.getTime() > ms.fromHours(1))
    + 326                        { return true; }                //    --> more than 1h
    + 327                }
    + 328            } else {                                    // during Weekend:
    + 329                return true;                            //    --> update once
    + 330            }
    + 331            return false;
    + 332        })
    + 333        .catch((err) => {
    + 334            console.log(`no response from trader: ${err}`);
    + 335            return false;
    + 336        });
    + 337    }
    + 338
    + 339
    + 340    //------  private  parts -----
    + 341    private bySymbol   = <{string: EquityItem}>{};
    + 342
    + 343    private unkownEquity() { 
    + 344        return {cat:'unknown Cat', symbol:'????', name:'unknown'}; 
    + 345    }
    + 346
    + 347    private JsonToEquityList(data:any):EquityList {
    + 348        if (!data) { console.log('no data in JsonToEquityList'); }
    + 349        else {
    + 350            Object.keys(data).forEach((k:string) => {
    + 351                Object.keys(data[k]).forEach((e:string) => {
    + 352                    this.add({ symbol: e, name: data[k][e], cat: k, stats:{}, company:{}});
    + 353                });
    + 354            });   
    + 355        }
    + 356        return this;
    + 357    }
    + 358
    + 359    private add(item:EquityItem):EquityItem {
    + 360        item.invalid = item.invalid || {};
    + 361        const sym = item.symbol.toUpperCase();
    + 362        if (!this.bySymbol[sym]) {
    + 363            this.bySymbol[sym] = item;
    + 364        }
    + 365        return this.bySymbol[sym];
    + 366    };
    + 367
    + 368    private remove(itemOrSymbol:EquityItem|string) {
    + 369        const item = (typeof itemOrSymbol === 'string')? 
    + 370            this.bySymbol[itemOrSymbol.toUpperCase()] : this.bySymbol[(itemOrSymbol).symbol];
    + 371        delete this.bySymbol[item.symbol.toUpperCase()];
    + 372    }
    + 373
    + 374    private  saveEquityList():Promise {
    + 375        return save(EquityList2JSON(this), `${SAVE_PATH}/${EQUITY_LIST}`);
    + 376    }
    + 377
    + 378    private readSymSplit(item:EquityItem):Promise {
    + 379        return loadSplits(item)
    + 380        .then(saveMeta)
    + 381        .then(applySplitsToTrades)  // new splits are only loaded upon specific request
    + 382        .catch((err) => {
    + 383            console.log(`error in readSymSplit: ${err}`);
    + 384            return item;
    + 385        });
    + 386    }
    + 387
    + 388    //------  public parts -----
    + 389
    + 390    public static getTrader() { return EquityList.trader; }
    + 391
    + 392    public readSplits() {
    + 393        Object.keys(this.bySymbol).forEach((sym:string) => {
    + 394            this.readSymSplit(this.getItem(sym));
    + 395        });
    + 396    }
    + 397
    + 398    public clearInvalids() {
    + 399        Object.keys(this.bySymbol).forEach((sym:string) => {
    + 400            const item = this.getItem(sym);
    + 401            delete item.invalid;
    + 402            item.changed = true;
    + 403            saveMeta(item);
    + 404        });
    + 405    }
    + 406
    + 407    public getItem(symbol:string):EquityItem { 
    + 408        if (this.bySymbol[symbol]) { 
    + 409            return this.bySymbol[symbol]; 
    + 410        }
    + 411        return this.unkownEquity();
    + 412    }
    + 413
    + 414    public addItem(item:EquityItem):EquityItem {
    + 415        item = this.add(item);
    + 416        loadMeta(item);
    + 417        this.saveEquityList();
    + 418        return item;
    + 419    }
    + 420
    + 421    public removeItem(itemOrSymbol:EquityItem|string) {
    + 422        this.remove(itemOrSymbol);
    + 423        this.saveEquityList();
    + 424    }
    + 425
    + 426    public getCategories():Category[] { 
    + 427        const categories:Category[] = [];
    + 428        Object.keys(this.bySymbol).forEach((sym:string) => {
    + 429            const item = this.bySymbol[sym];
    + 430            let cat:Category = categories[item.cat];
    + 431            if (!cat) {
    + 432                cat = categories[item.cat] = {
    + 433                    cat: item.cat,
    + 434                    equities: []
    + 435                };
    + 436                categories.push(cat);
    + 437            };
    + 438            cat.equities.push(item);
    + 439        });
    + 440        categories.forEach((c:Category) => {
    + 441            c.equities.sort((a:EquityItem, b:EquityItem) => {
    + 442                if (a.shares > 0 || b.shares > 0) {
    + 443                    const diff = (b.shares || 0) - (a.shares || 0);
    + 444                    if (diff !== 0) { return diff; }
    + 445                }
    + 446                return (a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0);
    + 447            });
    + 448        });
    + 449        return categories; 
    + 450    }
    + 451
    + 452    public getFirstByCat(cat:string):EquityItem {
    + 453        const c = this.getCategories()[cat];
    + 454        if (c && c.equities.length>0) { return c.equities[0]; }
    + 455        else { return this.unkownEquity(); }
    + 456    }
    + 457
    + 458    public marketUpdate() {
    + 459        Object.keys(this.bySymbol).forEach((sym:string) => {
    + 460            const item = this.bySymbol[sym];
    + 461            load(item);
    + 462        });
    + 463    }
    + 464
    + 465    public loadEquityList():Promise {
    + 466        return load(`${LOAD_PATH}/${EQUITY_LIST}`)
    + 467        .catch(() => load(`${LOAD_PATH}/${DEF_EQUITY_LIST}`))
    + 468        .then((data:any) => this.JsonToEquityList.call(this, data))
    + 469        .then(() => EquityList.marketUpdated(EquityList.lastUpdate))
    + 470        .then((b:boolean) => b? this.marketUpdate() : '');
    + 471    }
    + 472}
    + 473
    + 474export const gEquityList = new EquityList();
    + 475gEquityList.loadEquityList();
    + 476
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/EquityList.html b/docs/src/hsStock/controller/EquityList.html new file mode 100644 index 0000000..faa972f --- /dev/null +++ b/docs/src/hsStock/controller/EquityList.html @@ -0,0 +1,120 @@ + + +

    controller/EquityList.ts

    +
       1import { Transaction }  from './Assets';
    +   2import { EquityItem }   from './Equities';
    +   3
    +   4
    +   5
    +   6export class EquityList {
    +   7    //------  Static  parts -----
    +   8   
    +   9    /** impute trades with share price */
    +  10    public static imputeTradesWithSharePrice(item:EquityItem):EquityItem {
    +  11        if (item.trades) {
    +  12            item.trades.forEach((trade:Transaction) => { 
    +  13                if (!(trade.Date instanceof Date)) { trade.Date = new Date(trade.Date); }        
    +  14                if (trade.price) {
    +  15                    if (typeof trade.price === 'string') {
    +  16                        trade.price = parseFloat(trade.price);
    +  17                        item.changed = true;
    +  18                    }
    +  19                } else if (item.quotes && item.quotes.rows) {
    +  20                    item.changed = true;
    +  21                    const row:any = item.quotes.rows.find((t:any) => {
    +  22                        if (!(t[0] instanceof Date)) { t[0] = new Date(t[0]); }
    +  23                        return t[0]>trade.Date;
    +  24                    });
    +  25                    trade.price = row? row[2] : 20;
    +  26                }
    +  27            });
    +  28        }    
    +  29        return item;            
    +  30    };
    +  31
    +  32    //------  private  parts -----
    +  33    private bySymbol   = <{string: EquityItem}>{};
    +  34
    +  35    //------  public parts -----
    +  36
    +  37    public clearInvalids() {
    +  38        Object.keys(this.bySymbol).forEach((sym:string) => {
    +  39            const item = this.getItem(sym);
    +  40            delete item.invalid;
    +  41            item.changed = true;
    +  42        });
    +  43    }
    +  44
    +  45    public unkownEquity() { 
    +  46        return {cat:'unknown Cat', symbol:'????', name:'unknown'}; 
    +  47    }
    +  48
    +  49    public newItem(sym:string):EquityItem { 
    +  50        const item = {
    +  51            symbol:sym, 
    +  52            cat:'unknown Cat', 
    +  53            name:'unknown',
    +  54            changed: true
    +  55        }; 
    +  56        return this.addItem(item);
    +  57    }
    +  58
    +  59
    +  60    public getAllSymbols():string[] {
    +  61        return Object.keys(this.bySymbol);
    +  62    }
    +  63
    +  64    public getItem(symbol:string):EquityItem { 
    +  65        if (!this || !this.bySymbol) {
    +  66            console.log('missing this');
    +  67        }
    +  68        return this.bySymbol[symbol] || this.unkownEquity();
    +  69    }
    +  70
    +  71    public addItem(item:EquityItem):EquityItem {
    +  72        const sym = item.symbol.toUpperCase();
    +  73        delete item.invalid;        // no longer used
    +  74        return this.bySymbol[sym] || (this.bySymbol[sym] = item);
    +  75    }
    +  76
    +  77    public removeItem(itemOrSymbol:EquityItem|string) {
    +  78        const item = (typeof itemOrSymbol === 'string')? 
    +  79            this.bySymbol[itemOrSymbol.toUpperCase()] : this.bySymbol[(itemOrSymbol).symbol];
    +  80        delete this.bySymbol[item.symbol.toUpperCase()];
    +  81    }
    +  82
    +  83    public checkProperties(item:EquityItem):EquityItem {
    +  84        if (item.company && item.company.sector) { 
    +  85            if (item.cat !== item.company.sector) {
    +  86                item.cat = item.company.sector;
    +  87                item.changed = true;
    +  88            }
    +  89        }
    +  90        item.stats.closePrice = item.stats.closePrice || (item.otherStats? item.otherStats.close : -1);
    +  91        if (!item.stats.closeDate) {
    +  92            if (item.otherStats) {
    +  93                item.stats.closeDate = new Date(item.otherStats.closeTime);
    +  94            } else {
    +  95                console.log(`not item.otherStats for ${item.symbol}`);
    +  96            }
    +  97        }
    +  98        if (item.stats['latestVolume']) { delete item.stats['latestVolume']; }
    +  99        return item;
    + 100    }
    + 101}
    + 102
    + 103
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/EquityLoader.html b/docs/src/hsStock/controller/EquityLoader.html new file mode 100644 index 0000000..923d05e --- /dev/null +++ b/docs/src/hsStock/controller/EquityLoader.html @@ -0,0 +1,345 @@ + + +

    controller/EquityLoader.ts

    +
       1import { DataSet }      from 'hsdata';
    +   2import { Trader }       from './Trader';
    +   3import { Transaction }  from './Assets';
    +   4import { EquityList }   from './EquityList';
    +   5import { EquitySplit }  from './Equities';
    +   6import { EquityItem }   from './Equities';
    +   7import { ms }           from 'hsutil'; 
    +   8import { load, save }   from '../fileIO';
    +   9
    +  10const DEF_EQUITY_LIST   = 'defEquityList.json';
    +  11const EQUITY_LIST       = 'equityList.json';
    +  12const SAVE_PATH         = 'hsStock/data';   // relative to 'apps/', defines in save.js cgi
    +  13const LOAD_PATH         = 'data';           // relative to 'hsStock/', root of webapp location
    +  14
    +  15
    +  16
    +  17function copyProperties(from:EquityItem, to:EquityItem):EquityItem {
    +  18    Object.keys(from).forEach((k:string) => to[k] = from[k]); 
    +  19    return to;             // continue working with original item
    +  20};
    +  21
    +  22/** saves equity inof to symXXX.json file, skipping the quotes */
    +  23function saveMeta(item:EquityItem):Promise {
    +  24    if (item.changed) {
    +  25        const copy = {
    +  26            symbol:     item.symbol, 
    +  27            name:       item.name,
    +  28            cat:        item.cat,
    +  29            venues:     item.venues,
    +  30            shares:     item.shares,
    +  31            trades:     item.trades,
    +  32            company:    item.company,
    +  33            stats:      item.stats,
    +  34            otherStats: item.otherStats,
    +  35            splits:     item.splits
    +  36        };
    +  37        return save(copy, `${SAVE_PATH}/stock/sym${item.symbol}.json`)
    +  38            .then(() => {
    +  39                console.log(`${new Date().getTime() %10000}: saved sym${item.symbol}.json to local`);
    +  40                item.changed = undefined;
    +  41                return item;
    +  42            });
    +  43    }
    +  44    return Promise.resolve(item); 
    +  45}
    +  46
    +  47
    +  48
    +  49function updateStats(item: EquityItem):EquityItem {
    +  50    if (item && item.quotes && item.quotes.rows && item.quotes.rows.length > 0) {
    +  51        const date = item.stats.closeDate;
    +  52        const dCol = item.quotes.colNames.indexOf('Date');
    +  53        const vCol = item.quotes.colNames.indexOf('Volume');
    +  54        const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    +  55        if (latestRow[dCol] === date) {
    +  56            item.stats.closeVolume = latestRow[vCol];
    +  57        }
    +  58    }
    +  59    return item;
    +  60}
    +  61
    +  62
    +  63function JsonToSymArray(data:any):string[] {
    +  64    if (!data) { 
    +  65        console.log('no data in JsonToSymArray'); 
    +  66    } else if(data.length > 0) {    // new format
    +  67        return data;
    +  68    } else {                        // old format
    +  69        const syms:string[] = [];
    +  70        Object.keys(data).forEach((k:string) => 
    +  71            Object.keys(data[k]).forEach((e:string) => syms.push(e))
    +  72        );   
    +  73        return syms;
    +  74    }
    +  75}
    +  76
    +  77
    +  78let trader:Trader;
    +  79
    +  80export class EquityLoader {
    +  81    //------  Static  parts -----
    +  82    private static lastUpdate:Date;
    +  83    public static getTrader() { return trader; }
    +  84    
    +  85    public static shouldUpdate(since:Date): Promise {
    +  86        const closingHour = 16;     // venue closes at 4pm PT;
    +  87        return trader.lastMarketUpdate()
    +  88        .then((lastUpdated:Date) => {
    +  89            const today = new Date();
    +  90            EquityLoader.lastUpdate = today;
    +  91            if (!since) { return true; }                // no recent update
    +  92            if (lastUpdated < since) { return false; }   // no updates since
    +  93            if ((today.getDay()+6)%7 < 5)  {            // Mo-Fri: during trading days
    +  94                if (today.getTime() - lastUpdated.getTime() > ms.fromHours(24))
    +  95                    { return true; }                    //    --> more than a day old
    +  96                if (lastUpdated.getHours() < closingHour-1) {       // during trading hours
    +  97                    if (today.getTime() - lastUpdated.getTime() > ms.fromHours(1))
    +  98                        { return true; }                //    --> more than 1h
    +  99                }
    + 100            } else {                                    // during Weekend:
    + 101                return true;                            //    --> update once
    + 102            }
    + 103            return false;
    + 104        })
    + 105        .catch((err) => {
    + 106            console.log(`no response from trader: ${err}`);
    + 107            return false;
    + 108        });
    + 109    }
    + 110
    + 111    public static applySplitsToTrades(item:EquityItem):EquityItem {   
    + 112        if (item.splits && item.trades) {
    + 113            item.splits.forEach((split:EquitySplit) => {
    + 114                if (typeof split.date === 'string') { split.date = new Date(split.date); }
    + 115                item.trades.forEach((trade:Transaction) => {
    + 116                    if (!trade.appliedSplits) { trade.appliedSplits = {}; }
    + 117                    if (!trade.appliedSplits[split.date.getTime()] && trade.Date < split.date) {
    + 118                        trade.price *= split.ratio;
    + 119                        trade.change /= split.ratio;
    + 120                        trade.total /= split.ratio;
    + 121                        trade.appliedSplits[split.date.getTime()] = split.ratio;
    + 122                        item.changed = true;
    + 123                    }
    + 124                });
    + 125            });
    + 126        }
    + 127        return item;
    + 128    }
    + 129
    + 130    public static filterQuotes(data:DataSet, dateColName:string, valColName:string) {
    + 131        let dateCol  = data.colNames.indexOf(dateColName);
    + 132        let closeCol = data.colNames.indexOf(valColName);
    + 133        const noNull = (r:any[]) => r[dateCol] !==undefined && r[dateCol] !==null &&
    + 134                                    r[closeCol]!==undefined && r[closeCol]!==null;
    + 135        data.rows = data.rows.filter(noNull);
    + 136        data.rows.map((r:any[]) => r[dateCol] = new Date(r[dateCol]));
    + 137    }
    + 138
    + 139    public static saveQuotes(item:EquityItem):Promise {
    + 140        console.log(`${new Date().getTime() %10000}: save ${item.quotes.rows.length} Quotes ${item.symbol} to local`);
    + 141        const result = {
    + 142            quotes:     item.quotes,
    + 143            intraday:   item.intraday
    + 144        };
    + 145        return save(result, `${SAVE_PATH}/stock/quotes${item.symbol}.json`)
    + 146        .catch((err:any) => {
    + 147            console.log(`error for in saveQuotes: ${err}`);
    + 148            console.log(item);
    + 149            return item;
    + 150        })
    + 151        .then(() => item);
    + 152    }
    + 153
    + 154    private static requestIntradayQuotes(item:EquityItem):Promise {
    + 155        return trader.requestQuotes(item, 1)
    + 156        .catch((err:any) => {
    + 157            console.error(`error in getIntradayQuotes: ${err}`);
    + 158            return item;
    + 159        });
    + 160    }
    + 161
    + 162
    + 163    private static requestSymSplitIfMissing(item:EquityItem):Promise {
    + 164        function addSplitsToItem(splits:EquitySplit[]):EquityItem { 
    + 165            if (!item.splits) { 
    + 166                item.splits = splits; 
    + 167            } else {
    + 168                splits.forEach((split:EquitySplit) => {
    + 169                    if (!item.splits.find((s:EquitySplit) => s.date === split.date)) { 
    + 170                        item.splits.push(split); 
    + 171                    }
    + 172                });
    + 173            }
    + 174            item.splits.sort((a:EquitySplit, b:EquitySplit) => a.date.getTime() - b.date.getTime()); 
    + 175            EquityLoader.applySplitsToTrades(item); // new splits are only loaded upon specific request
    + 176            return item; 
    + 177        };
    + 178
    + 179//        if (item.splits && item.splits.length===0) { item.splits = undefined; }
    + 180        
    + 181        return (item.splits)? Promise.resolve(item) :
    + 182            trader.requestSplits(item)
    + 183            .then(addSplitsToItem)
    + 184            .catch((err) => {
    + 185                console.log(`error in readSymSplit: ${err}`);
    + 186                return item;
    + 187            });
    + 188    }
    + 189
    + 190    public static saveEquityList(symbols:string[]):Promise {
    + 191        console.log(`${new Date().getTime() %10000}: saveEquityList to local`);
    + 192        return save(symbols, `${SAVE_PATH}/${EQUITY_LIST}`);
    + 193    }
    + 194
    + 195    //------  private  parts -----
    + 196    private list:EquityList;
    + 197
    + 198    private loadAllItemsLocal(items: EquityItem[]):Promise {
    + 199        return Promise.all(items
    + 200//            .filter(item => item.symbol==='AAPL')
    + 201            .map(item =>
    + 202                this.loadLocal(item)
    + 203                .then((item:EquityItem) => this.list.addItem(item))
    + 204                .catch(console.log)
    + 205            ))
    + 206        .then(()=>{});
    + 207    }
    + 208
    + 209
    + 210    //------  public parts -----
    + 211
    + 212    constructor(list:EquityList) {
    + 213        this.list = list;
    + 214        if (!trader) { 
    + 215            trader = new Trader(); 
    + 216            Trader.loadLocalVenues(LOAD_PATH, SAVE_PATH, '/venues.json');
    + 217        }
    + 218    }
    + 219
    + 220    /**
    + 221     * load the equity list, then load all equities 
    + 222     */

    + 223    public loadEquityList():Promise {
    + 224        console.log(`${new Date().getTime() %10000}: loadEquityList from local`);
    + 225        return load(`${LOAD_PATH}/${EQUITY_LIST}`)
    + 226        .catch(() => load(`${LOAD_PATH}/${DEF_EQUITY_LIST}`))
    + 227        .then(JsonToSymArray)
    + 228        .then((syms:string[]) => syms.map((sym) => this.list.newItem(sym)))
    + 229        .then(this.loadAllItemsLocal.bind(this));
    + 230    }
    + 231
    + 232    public requestSplitsIfMissing():Promise {
    + 233        return Promise.all(
    + 234            this.list.getAllSymbols().map((sym:string) => 
    + 235                EquityLoader.requestSymSplitIfMissing(this.list.getItem(sym))
    + 236                .then(saveMeta)
    + 237            )
    + 238        )
    + 239        .catch(console.log)
    + 240        .then(()=>{});
    + 241    }
    + 242
    + 243    public marketUpdate():Promise {
    + 244        return Promise.all(
    + 245            this.list.getAllSymbols()
    + 246//            .filter((s:string) => s==='AAPL')
    + 247            .map((sym:string) => this.loadRemote(this.list.getItem(sym))
    + 248            )
    + 249        )
    + 250        .then(()=>true)
    + 251        .catch((err:any) => {
    + 252            console.log(`error in marketUpdate: ${err}`);
    + 253            return false;
    + 254        });
    + 255    }
    + 256
    + 257    public loadLocal(item:EquityItem):Promise {
    + 258        /** adds a quotes DataSet to an item  */
    + 259        function addQuotesToItem(quotes:{quotes:DataSet, intraday:DataSet}):EquityItem { 
    + 260            if (quotes) {
    + 261                const q = quotes.quotes || quotes;
    + 262                item.quotes = {
    + 263                    colNames: q['colNames'] || q['names'],
    + 264                    rows:     q['rows']
    + 265                };
    + 266                item.intraday = quotes.intraday? quotes.intraday : 
    + 267                    { colNames: [], rows:[] }; 
    + 268            }
    + 269            return item;
    + 270        }
    + 271        function copyParts(data:EquityItem) {
    + 272            if (item.trades) { data.trades = item.trades; }
    + 273            copyProperties(data, item); 
    + 274            return item;         
    + 275        }
    + 276        function normalizeItem(item:EquityItem):Promise {
    + 277            if (item.quotes) {
    + 278                EquityLoader.filterQuotes(item.quotes, 'Date', 'Close');
    + 279            }
    + 280            if (item.intraday) {
    + 281                if (item.intraday['names']) {
    + 282                    item.intraday.colNames = item.intraday['names'];
    + 283                    delete item.intraday['names'];
    + 284                }
    + 285                EquityLoader.filterQuotes(item.intraday, 'Date', 'Low');
    + 286            }
    + 287            Trader.getVenue(item); // to initialize the venues in item
    + 288            EquityLoader.applySplitsToTrades(item);
    + 289            return saveMeta(item);
    + 290        }
    + 291        if (item.symbol === '????') {
    + 292            return Promise.resolve(item);
    + 293        } else {
    + 294            return load(`${LOAD_PATH}/stock/sym${item.symbol}.json`)
    + 295                .then(copyParts)
    + 296                .then(() => load(`${LOAD_PATH}/stock/quotes${item.symbol}.json`))
    + 297                .then(addQuotesToItem) 
    + 298                .then(normalizeItem)       
    + 299                .catch(() => item); // if nothing on local server: ignore
    + 300        }
    + 301    }
    + 302
    + 303    public loadRemote(item:EquityItem):Promise {
    + 304        const list = this.list;
    + 305        const copyPropertiesToItem = (data:EquityItem):EquityItem => {
    + 306            Object.keys(data).forEach((k:string) => item[k] = data[k]); 
    + 307            return item;             // continue working with original item
    + 308        };
    + 309
    + 310        return Promise.resolve(item)
    + 311            .then(trader.requestMeta)
    + 312            .then(copyPropertiesToItem)
    + 313            .then(list.checkProperties)
    + 314            .then(EquityLoader.getTrader().requestQuotes)
    + 315            .then(EquityLoader.saveQuotes)
    + 316            .then(EquityLoader.requestIntradayQuotes)
    + 317            .then(updateStats)
    + 318            .then(EquityList.imputeTradesWithSharePrice)
    + 319            .then(EquityLoader.requestSymSplitIfMissing)
    + 320            .then(saveMeta)
    + 321            .catch((err:any) => {
    + 322                console.error(`error in loadRemote: ${err}`);
    + 323                return item;
    + 324            });
    + 325    }
    + 326
    + 327}
    + 328
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/Loader.html b/docs/src/hsStock/controller/Loader.html new file mode 100644 index 0000000..d510321 --- /dev/null +++ b/docs/src/hsStock/controller/Loader.html @@ -0,0 +1,18 @@ + + +

    controller/Loader.ts

    +
       1
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/Trader.html b/docs/src/hsStock/controller/Trader.html new file mode 100644 index 0000000..a1d22ce --- /dev/null +++ b/docs/src/hsStock/controller/Trader.html @@ -0,0 +1,325 @@ + + +

    controller/Trader.ts

    +
       1import { EquityItem,
    +   2         EquitySplit }      from './Equities';
    +   3import { EquityLoader } from './EquityLoader';
    +   4import { VenueIDs,
    +   5         Venue,
    +   6         VenueSummary }     from './Venue';
    +   7import { IexVenue }         from './VenueIex';
    +   8import { ms }               from 'hsutil';
    +   9import { DataSet }          from 'hsdata';
    +  10import { load, save }       from '../fileIO';
    +  11
    +  12export interface TraderQuote {
    +  13    Date:           Date;
    +  14    close:          number;
    +  15    high:           number;
    +  16    low:            number;
    +  17    open:           number;
    +  18    volume:         number;
    +  19}
    +  20
    +  21export interface TraderIntraday {
    +  22    Date:           Date;
    +  23    high:           number;
    +  24    low:            number;
    +  25}
    +  26
    +  27export interface TraderSymbol {
    +  28    symbol: string;
    +  29    name:   string;  
    +  30}
    +  31
    +  32function createVenues():Venue[] {
    +  33    const vns:Venue[] = [];
    +  34    vns.push(vns[VenueIDs.IEX] = new IexVenue());
    +  35    return vns;
    +  36}
    +  37
    +  38    /** accessible by index, or by Venues.***  */
    +  39const venues:Venue[] = createVenues();
    +  40    
    +  41export const getVenue = (name: VenueIDs|number):Venue => venues[name];
    +  42
    +  43export const allVenueIDs = ():VenueIDs[] => venues.map(
    +  44    (venue:Venue) => venue.summary.venueID
    +  45);
    +  46
    +  47
    +  48/** converts and imputates trader quotes to a DataSet */
    +  49export function traderQuote2Dataset(dataIn:any[]):DataSet  {
    +  50    const names = ['Date', 'Open', 'Close', 'High', 'Low', 'Volume'];
    +  51    if (dataIn.length === 0) {
    +  52        console.log(`received no quotes ${(dataIn).url}`);
    +  53        return { colNames:names, rows:[]};
    +  54    } else {
    +  55        const rows  = dataIn
    +  56        .filter((e:any) => e.date)
    +  57        .map((e: any) => {
    +  58            if (e.minute) {
    +  59                const date = e.date? new Date(e.date + ' ' + e.minute) : undefined;
    +  60                return [
    +  61                    date, 
    +  62                    e.marketHigh,
    +  63                    e.marketLow
    +  64                ];
    +  65            } else {
    +  66                return [
    +  67                    e.date? new Date(e.date) : undefined,
    +  68                    e.close,
    +  69                    e.high || e.close,
    +  70                    e.low  || e.close,
    +  71                    e.open || e.close,
    +  72                    e.volume
    +  73                ];
    +  74            }
    +  75        });
    +  76        return { colNames:names, rows:rows};
    +  77    }
    +  78};
    +  79
    +  80
    +  81export class Trader { 
    +  82    //------  static  parts -----
    +  83
    +  84    /**
    +  85     * load local venue desciptor and update venue fields
    +  86     * data: { venueName:[TraderSymbol] }
    +  87     */

    +  88    private static updateLocalVenues(data:{[venueName:string]:TraderSymbol[]}) {
    +  89        Object.keys(data).map((ven:VenueIDs) => {
    +  90            if (getVenue(ven)) {
    +  91                const v:VenueSummary = getVenue(ven).summary;
    +  92                data[ven].map((e:TraderSymbol) => {
    +  93                    v.symbols.push(e.symbol);
    +  94                    v.names.push(e.name);
    +  95                    v.equities[e.symbol] = e;
    +  96                });
    +  97            } else {
    +  98                console.log(`unknown venue ${ven}`);
    +  99            }
    + 100        });
    + 101    }
    + 102
    + 103    public static loadLocalVenues(loadPath:string, savePath:string, file:string) {
    + 104        load(loadPath+file)
    + 105        .then(Trader.updateLocalVenues)
    + 106        .catch(() => {
    + 107            Promise.all(allVenueIDs().map((n:VenueIDs) => getVenue(n).requestSymbolsForVenue()))
    + 108            .catch(console.log)
    + 109            .then(()=> savePath+file)
    + 110            .then(Trader.saveLocalVenues);
    + 111        });                      
    + 112    }
    + 113
    + 114    private static saveLocalVenues(savePath:string) {
    + 115        const venues = {};
    + 116        allVenueIDs().map((n:VenueIDs) => {
    + 117            const summary:VenueSummary = getVenue(n).summary;
    + 118            venues[n] = Object.keys(summary.equities);
    + 119        });
    + 120        return save(venues, savePath)
    + 121        .catch(console.log);
    + 122    }
    + 123    
    + 124
    + 125    /**
    + 126     * adds quotes to item.intraday; overwriting item.intraday. 
    + 127     * @param quotes 
    + 128     * @param item 
    + 129     */

    + 130    private static addIntraday(quotes:TraderIntraday[], item:EquityItem):EquityItem {
    + 131        const names = ['Date', 'High', 'Low'];
    + 132        const rows  = quotes.map((t:TraderIntraday) => [t.Date, t.high, t.low]);
    + 133        item.intraday = {colNames:names, rows:rows};
    + 134        EquityLoader.filterQuotes(item.intraday, 'Date', 'Low');
    + 135        return item;
    + 136    }
    + 137
    + 138    /**
    + 139     * adds quotes to item.quotes; creating item.quotes if undefined. 
    + 140     * @param quotes 
    + 141     * @param item 
    + 142     */

    + 143    private static addQuotes(quotes:TraderQuote[], item:EquityItem):EquityItem {
    + 144        const  sortDate = ((r0:Date[], r1:Date[]) => r0[0].getTime() - r1[0].getTime());
    + 145        let lastItemDate = new Date('1/1/1980');
    + 146        if (!item.quotes) {
    + 147            item.quotes = {
    + 148                colNames: ['Date','Open','Close','High','Low','Volume'],
    + 149                rows: []
    + 150            };
    + 151        }
    + 152        const dCol = item.quotes.colNames.indexOf('Date');
    + 153        if (item.quotes.rows.length > 0) {
    + 154            item.quotes.rows.sort(sortDate);
    + 155//item.quotes.rows.map((r:any[]) => console.log(r[0]));            
    + 156            const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    + 157            lastItemDate = (typeof latestRow[dCol] === 'string')? new Date(latestRow[dCol]) : latestRow[dCol];
    + 158//console.log(`${item.name}: ${latestRow[0]} ${dCol} ${lastItemDate}`);            
    + 159        }
    + 160        quotes
    + 161            .sort((a:TraderQuote, b:TraderQuote) => a.Date.getTime() - b.Date.getTime())
    + 162            .map((q:TraderQuote) => {               // copy rows to item.quotes
    + 163                if (q.Date > lastItemDate) { 
    + 164                    item.quotes.rows.push([q.Date, q.open, q.close, q.high, q.low, q.volume]);
    + 165                }
    + 166            });
    + 167        if (item.quotes.rows.length > 0) {  // update item.stats
    + 168            const vCol = item.quotes.colNames.indexOf('Volume');
    + 169            const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    + 170            item.stats.closeVolume = latestRow[vCol];
    + 171            item.stats.closeDate   = latestRow[dCol];
    + 172        }
    + 173        return item;
    + 174    }
    + 175
    + 176    private static adjustMissingDays(item:EquityItem):number {
    + 177        if (!item.quotes || item.quotes.rows.length === 0) {
    + 178            return 10000;
    + 179        } else {
    + 180            const dCol      = item.quotes.colNames.indexOf('Date');
    + 181            const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    + 182            return ms.toDays(new Date().getTime() - new Date(latestRow[dCol]).getTime());
    + 183        }
    + 184    }
    + 185
    + 186
    + 187    //------  private  parts -----
    + 188
    + 189
    + 190    //------  public  parts -----
    + 191
    + 192    private static getVenueID(item:EquityItem):VenueIDs {
    + 193        if (!item.venues || item.venues.length===0) { 
    + 194            item.venues = [VenueIDs.IEX]; 
    + 195            item.changed = true;
    + 196        }
    + 197        return item.venues[0];
    + 198    }
    + 199
    + 200    public static getVenue(item:EquityItem):Venue {
    + 201        const venueID = Trader.getVenueID(item);
    + 202        return venueID? venues[venueID] : undefined;
    + 203    }
    + 204
    + 205    public static invalidateVenueID(item:EquityItem, venue:VenueIDs) {
    + 206        if (item.venues[venue]) { 
    + 207            console.log(`invalidating ${venue} for ${item.symbol}`);
    + 208            delete item.venues[venue]; 
    + 209            item.changed = true;
    + 210        }
    + 211    }
    + 212
    + 213    /**
    + 214     * constructs a Trader and loads the local 
    + 215     * @param loadPath 
    + 216     * @param savePath 
    + 217     * @param file 
    + 218     */

    + 219    constructor() {        
    + 220    }
    + 221
    + 222
    + 223
    + 224    public lastMarketUpdate(): Promise {
    + 225        return getVenue(0).requestMarketUpdate()
    + 226        .catch((err:any) => {
    + 227            console.log(err);
    + 228            return new Date();
    + 229        });
    + 230    }
    + 231
    + 232    /** 
    + 233     * initiates remote requests to the venues and updates `item` accordingly.
    + 234     * If `missingDays` is 1, intraday quotes will be requested.
    + 235     * Otherwise, appropriate daily quotes are requested to fill `item.quotes` as needed,
    + 236     * with a maximum of `missingDays`, if specified,
    + 237     * and intraday quoates will not be requested.
    + 238     * 
    + 239     * @return fully updated `item` as requested.
    + 240     */

    + 241    public requestQuotes(item:EquityItem, missingDays?:number):Promise {
    + 242
    + 243        const venue = Trader.getVenue(item);
    + 244        if (venue) {
    + 245            if (missingDays <= 1) { 
    + 246                return Promise.resolve(item)
    + 247                    .then(venue.requestIntradayVenue)
    + 248                    .then((q:TraderIntraday[]) => Trader.addIntraday(q, item))
    + 249                    .catch((err:any) => {
    + 250                        Trader.invalidateVenueID(item, venue.summary.venueID);
    + 251                        console.log(`error in requestIntraday ${item.symbol} for venue ${venue}: ${err}`);
    + 252                        return item;
    + 253                    });
    + 254            } else {
    + 255                missingDays = Trader.adjustMissingDays(item);
    + 256                return Promise.resolve()
    + 257                    .then(() => venue.requestQuotesVenue(item, missingDays))
    + 258                    .then((q:TraderQuote[]) => Trader.addQuotes(q, item))
    + 259                    .catch((err:any) => {
    + 260                        Trader.invalidateVenueID(item, venue.summary.venueID);
    + 261                        console.log(`error in requestQuotes ${item.symbol} for venue ${venue}: ${err}`);
    + 262                        return item;
    + 263                    });
    + 264            }
    + 265        } else {
    + 266            return Promise.resolve(item);
    + 267        }
    + 268    }
    + 269
    + 270    public requestSplits(item:EquityItem):Promise {
    + 271        const venue = Trader.getVenue(item);
    + 272        if (venue) { return venue.requestSplitsVenue(item)
    + 273            .catch((err:any) => {
    + 274                Trader.invalidateVenueID(item, venue.summary.venueID);
    + 275                console.log(`error in requestSplits ${item.symbol} for venue ${venue}: ${err}`);
    + 276                return [];
    + 277            });
    + 278        }
    + 279    }
    + 280
    + 281    public requestMeta(item:EquityItem):Promise {
    + 282        const venue = Trader.getVenue(item);
    + 283        if (venue) { return venue.requestMetaVenue(item)
    + 284            .catch((err:any) => {
    + 285                Trader.invalidateVenueID(item, venue.summary.venueID);
    + 286                console.log(`error in requestMeta ${item.symbol} for venue ${venue}: ${err}`);
    + 287                throw `error getting meta info for ${item.symbol}`;    
    + 288            });
    + 289        } else {
    + 290            throw `no venue defined for ${item.symbol}`;
    + 291        }
    + 292    }
    + 293
    + 294    public requestSymbols():Promise {
    + 295        return getVenue(0).requestSymbolsForVenue()
    + 296            .catch((err:any) => {
    + 297                console.log(`error in requestSymbols for venue ${getVenue(0)}: ${err}`);
    + 298                return getVenue(0).summary;
    + 299            });
    + 300    }
    + 301
    + 302    /*
    + 303
    + 304
    + 305
    + 306*/

    + 307}
    + 308
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/TraderIEX.html b/docs/src/hsStock/controller/TraderIEX.html new file mode 100644 index 0000000..450af28 --- /dev/null +++ b/docs/src/hsStock/controller/TraderIEX.html @@ -0,0 +1,311 @@ + + +

    controller/TraderIEX.ts

    +
       1import { TraderQuote,
    +   2         TraderReferences,
    +   3         TraderSymbol,
    +   4         TraderSplit,
    +   5         TraderProfile } from './Trader';
    +   6import { EquityItem }    from './Equity';
    +   7import { m }             from 'hslayout';
    +   8import { round }         from 'hsutil';
    +   9
    +  10interface IEXSymbols extends TraderSymbol {
    +  11    date:       string;
    +  12    isEnabled:  boolean;
    +  13    type:       string;     // refers to the common issue type of the stock. 
    +  14                            //  ad â€“ American Depository Receipt (ADR’s) 
    +  15                            //  re â€“ Real Estate Investment Trust (REIT’s) 
    +  16                            //  ce â€“ Closed end fund (Stock and Bond Fund) 
    +  17                            //  si â€“ Secondary Issue 
    +  18                            //  lp â€“ Limited Partnerships 
    +  19                            //  cs â€“ Common Stock 
    +  20                            //  et â€“ Exchange Traded Fund (ETF) 
    +  21                            //  (blank) = Not Available, i.e., Warrant, Note, or (non-filing) Closed Ended Funds
    +  22    iexId:      string;
    +  23}
    +  24
    +  25interface IEXMeta extends EquityItem {
    +  26    beta:               number; // 
    +  27    week52change:       number; // 
    +  28    shortInterest:      number; // 
    +  29    shortDate:          string; // 
    +  30    dividendRate:       number; // 
    +  31    dividendYield:      number; // 
    +  32    exDividendDate:     string; // 
    +  33    latestEPS:          number; // (Most recent quarter)
    +  34    latestEPSDate:      string; // 
    +  35    sharesOutstanding:  number; // 
    +  36    float:              number; // 
    +  37    returnOnEquity:     number; // (Trailing twelve months)
    +  38    consensusEPS:       number; // (Most recent quarter)
    +  39    numberOfEstimates:  number; // (Most recent quarter)
    +  40    EBITDA:             number; // (Trailing twelve months)
    +  41    revenue:            number; // (Trailing twelve months)
    +  42    grossProfit:        number; // (Trailing twelve months)
    +  43    cash:               number; // reers to total cash. (Trailing twelve months)
    +  44    debt:               number; // refers to total debt. (Trailing twelve months)
    +  45    ttmEPS:             number; // (Trailing twelve months)
    +  46    revenuePerShare:    number; // (Trailing twelve months)
    +  47    revenuePerEmployee: number; // (Trailing twelve months)
    +  48    peRatioHigh:        number; // 
    +  49    peRatioLow:         number; // 
    +  50    EPSSurpriseDollar:  number; // refers to the difference between actual EPS and consensus EPS in dollars.
    +  51    EPSSurprisePercent: number; // refers to the percent difference between actual EPS and consensus EPS.
    +  52    returnOnAssets:     number; // (Trailing twelve months)
    +  53    returnOnCapital:    number; // (Trailing twelve months)
    +  54    profitMargin:       number; // 
    +  55    priceToSales:       number; // 
    +  56    priceToBook:        number; // 
    +  57    day200MovingAvg:    number; // 
    +  58    day50MovingAvg:     number; // 
    +  59    institutionPercent: number; // represents top 15 institutions
    +  60    insiderPercent:     number; // 
    +  61    shortRatio:         number; // 
    +  62    year5ChangePercent: number; // 
    +  63    year2ChangePercent: number; // 
    +  64    year1ChangePercent: number; // 
    +  65    ytdChangePercent:   number; // 
    +  66    month6ChangePercent: number; // 
    +  67    month3ChangePercent: number; // 
    +  68    month1ChangePercent: number; // 
    +  69    day5ChangePercent:  number; // 
    +  70}
    +  71
    +  72
    +  73interface IEXQuote extends TraderQuote {
    +  74    change:         number;
    +  75    changeOverTime: number;
    +  76    changePercent:  number;
    +  77    label:          string; // "Oct 16"
    +  78    unadjustedVolume: number;
    +  79    vwap:           number;
    +  80}
    +  81
    +  82function processMarketsForLatestsUpdate(markets:any[]):Date {
    +  83    let maxDate:Date;
    +  84    markets.forEach((venue:any) => {
    +  85        const lastDate = new Date(venue.lastUpdated);
    +  86console.log(`venue '${venue.venueName}', ${round(venue.marketPercent*100, 2)}% of market, last traded at ${lastDate.toTimeString()}`);
    +  87        if (!maxDate || maxDate < lastDate) { maxDate =  lastDate; }
    +  88    });
    +  89    return maxDate;
    +  90}
    +  91
    +  92/**
    +  93 * https://iextrading.com/developer/docs/
    +  94 */

    +  95export class IexTrading implements TraderProfile {
    +  96    id = 'IEXTrading';
    +  97    base = 'https://api.iextrading.com/1.0';
    +  98    marketUpdateUrl = ()           => `${this.base}/market`;
    +  99    symbolsUrl      = ()           => `${this.base}/ref-data/symbols`;
    + 100    statsUrl        = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/stats`;
    + 101    metaUrl         = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/quote`;
    + 102    quoteUrl        = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/chart`;
    + 103    financialsUrl   = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/financials`;
    + 104    earningsUrl     = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/earnings`;
    + 105    dividendsUrl    = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/dividends/5y`;
    + 106    splitsUrl       = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/splits/5y`;
    + 107    logoUrl         = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/logo`;
    + 108    
    + 109    lastMarketUpdate(): Promise {
    + 110        return m.request({url:this.marketUpdateUrl()})
    + 111        .then(processMarketsForLatestsUpdate);
    + 112    }
    + 113
    + 114    normalizeStats = (data:any, item:EquityItem):EquityItem => {
    + 115//console.log(`receiving stock '${data.symbol}' stats`);   
    + 116        item.name                 = data.companyName;
    + 117        item.symbol               = data.symbol;
    + 118        item.cat                  = item.cat || 'Stocks';
    + 119        item.company              = item.company || {};
    + 120        item.stats                = item.stats || {};
    + 121        item.stats.week52high     = data.week52high;
    + 122        item.stats.week52low      = data.week52low;
    + 123        item.stats.latestEPS      = data.latestEPS;
    + 124        item.stats.latestEPSDate  = new Date(data.latestEPSDate);
    + 125        item.stats.marketCap      = data.marketcap;
    + 126        item.stats.cash           = data.cash;
    + 127        item.stats.revenue        = data.revenue;
    + 128        item.stats.EBITDA         = data.EBITDA;
    + 129        item.stats.exDividendDate = new Date(data.exDividendDate);
    + 130        item.stats.dividendRate   = data.dividendRate;
    + 131        item.stats.dividendYield  = data.dividendYield;
    + 132        item.otherStats = item.otherStats || {};
    + 133        delete data.otherStats;
    + 134        Object.keys(data).forEach((k:string) => ((item.stats[k]===undefined)? item.otherStats[k] = data[k] : ''));
    + 135        return item;
    + 136    }
    + 137
    + 138    normalizeMeta = (data:any, item:EquityItem):EquityItem => {
    + 139//console.log(`receiving stock '${data.symbol}' meta`);   
    + 140        item.name                    = data.companyName;
    + 141        item.symbol                  = data.symbol;
    + 142        item.cat                     = item.cat || 'Stocks';
    + 143        item.stats.latestDate        = data.latestTime? new Date(data.latestUpdate) : new Date();
    + 144        item.stats.latestPrice       = data.latestPrice;
    + 145        item.stats.closeDate         = new Date(data.closeTime);
    + 146        item.stats.closePrice        = data.close;
    + 147        item.stats.change            = data.change;
    + 148        item.company                 = item.company || {};
    + 149        item.company.sector          = data.sector;
    + 150        item.company.primaryExchange = data.primaryExchange;
    + 151        item.stats = item.stats || {};
    + 152        item.otherStats = item.otherStats || {};
    + 153        delete data.otherStats;
    + 154        Object.keys(data).forEach((k:string) => ((item.stats[k]===undefined)? item.otherStats[k] = data[k] : ''));
    + 155        return item;
    + 156    }
    + 157
    + 158    normalizeQuotes = (data:any[]):TraderQuote[] => {
    + 159        if (data) {
    + 160            data.sort((a:TraderQuote, b:TraderQuote) => Date.parse(a.Date) - Date.parse(b.Date));
    + 161        }
    + 162//console.log(`receiving stock quote for`);   
    + 163        return data;
    + 164    }
    + 165
    + 166    normalizeSymbols = (data:any[]):TraderReferences => {
    + 167        const result:TraderReferences = {symbols:[], names:[], equities:<{string:TraderSymbol}>{}};
    + 168        data.forEach((entry:any) => { 
    + 169            result.equities[`sym${entry.symbol}`] = entry; 
    + 170            result.symbols.push(entry.symbol);
    + 171            result.names.push(entry.name);
    + 172        });
    + 173        return result;
    + 174    }
    + 175
    + 176    normalizeSplits = (data:IEXSplit[]): TraderSplit[] => {
    + 177        if (data.length>0) {
    + 178            data.map((t:IEXSplit) => t.date = new Date(t.exDate));
    + 179            return data;
    + 180        }
    + 181        return undefined;
    + 182    }
    + 183};
    + 184
    + 185
    + 186interface IEXStat {
    + 187    companyName:            string;
    + 188    marketcap:              number; // is not calculated in real time.
    + 189    beta:                   number;
    + 190    week52high:             number;
    + 191    week52low:              number;
    + 192    week52change:           number;
    + 193    shortInterest:          number;
    + 194    shortDate:              string;
    + 195    dividendRate:           number;
    + 196    dividendYield:          number;
    + 197    exDividendDate:         string;
    + 198    latestEPS:              number; // (Most recent quarter)
    + 199    latestEPSDate:          string;
    + 200    sharesOutstanding:      number;
    + 201    float:                  number;
    + 202    returnOnEquity:         number; // (Trailing twelve months)
    + 203    consensusEPS:           number; // (Most recent quarter)
    + 204    numberOfEstimates:      number; // (Most recent quarter)
    + 205    symbol:                 string;
    + 206    EBITDA:                 number; // (Trailing twelve months)
    + 207    revenue:                number; // (Trailing twelve months)
    + 208    grossProfit:            number; // (Trailing twelve months)
    + 209    cash:                   number; // refers to total cash. (Trailing twelve months)
    + 210    debt:                   number; // refers to total debt. (Trailing twelve months)
    + 211    ttmEPS:                 number; // (Trailing twelve months)
    + 212    revenuePerShare:        number; // (Trailing twelve months)
    + 213    revenuePerEmployee:     number; // (Trailing twelve months)
    + 214    peRatioHigh:            number;
    + 215    peRatioLow:             number;
    + 216    EPSSurpriseDollar:      number; // refers to the difference between actual EPS and consensus EPS in dollars.
    + 217    EPSSurprisePercent:     number; // refers to the percent difference between actual EPS and consensus EPS.
    + 218    returnOnAssets:         number; // (Trailing twelve months)
    + 219    returnOnCapital:        number; // (Trailing twelve months)
    + 220    profitMargin:           number;
    + 221    priceToSales:           number;
    + 222    priceToBook:            number;
    + 223    day200MovingAvg:        number;
    + 224    day50MovingAvg:         number;
    + 225    institutionPercent:     number; // represents top 15 institutions
    + 226    insiderPercent:         number;
    + 227    shortRatio:             number;
    + 228    year5ChangePercent:     number;
    + 229    year2ChangePercent:     number;
    + 230    year1ChangePercent:     number;
    + 231    ytdChangePercent:       number;
    + 232    month6ChangePercent:    number;
    + 233    month3ChangePercent:    number;
    + 234    month1ChangePercent:    number;
    + 235    day5ChangePercent:      number;    
    + 236}
    + 237
    + 238interface IEXFinancials {
    + 239    reportDate:             string;
    + 240    grossProfit:            number;
    + 241    costOfRevenue:          number;
    + 242    operatingRevenue:       number;
    + 243    totalRevenue:           number;
    + 244    operatingIncome:        number;
    + 245    netIncome:              number;
    + 246    researchAndDevelopment: number;
    + 247    operatingExpense:       number;
    + 248    currentAssets:          number;
    + 249    totalAssets:            number;
    + 250    totalLiabilities:       number;
    + 251    currentCash:            number;
    + 252    currentDebt:            number;
    + 253    totalCash:              number;
    + 254    totalDebt:              number;
    + 255    shareholderEquity:      number;
    + 256    cashChange:             number;
    + 257    cashFlow:               number;
    + 258    operatingGainsLosses:   string;
    + 259}
    + 260
    + 261interface IEXEarnings {
    + 262    actualEPS:          number;
    + 263    consensusEPS:       number;
    + 264    estimatedEPS:       number;
    + 265    announceTime:       string;
    + 266    numberOfEstimates:  number;
    + 267    EPSSurpriseDollar:  number;
    + 268    EPSReportDate:      string;
    + 269    fiscalPeriod:       string;
    + 270    fiscalEndDate:      string;
    + 271}
    + 272
    + 273interface IEXDividends {
    + 274    exDate:         string; // refers to the dividend ex-date
    + 275    paymentDate:    string; // refers to the payment date
    + 276    recordDate:     string; // refers to the dividend record date
    + 277    declaredDate:   string; // refers to the dividend declaration date
    + 278    amount:         number; // refers to the payment amount
    + 279    type:           string; // refers to the dividend payment type (Dividend income, Interest income, Stock dividend, Short term capital gain, Medium term capital gain, Long term capital gain, Unspecified term capital gain)
    + 280    qualified:      string; // refers to the dividend income type 
    + 281                            // P = Partially qualified income 
    + 282                            // Q = Qualified income 
    + 283                            // N = Unqualified income 
    + 284                            // null = N/A or unknown
    + 285}
    + 286
    + 287export interface IEXSplit extends TraderSplit {
    + 288    exDate:         string; // refers to the split ex-date
    + 289    declaredDate:   string; // refers to the split declaration date
    + 290    recordDate:     string; // refers to the split record date
    + 291    paymentDate:    string; // refers to the split payment date
    + 292    toFactor:       string; // To factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    + 293    forFactor:      string; // For factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    + 294}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/Venue.html b/docs/src/hsStock/controller/Venue.html new file mode 100644 index 0000000..122e1b1 --- /dev/null +++ b/docs/src/hsStock/controller/Venue.html @@ -0,0 +1,68 @@ + + +

    controller/Venue.ts

    +
       1import { m }            from 'hslayout';
    +   2import { PacingQueue }  from 'hsutil';
    +   3import { TraderQuote,
    +   4         TraderIntraday,
    +   5         TraderSymbol } from './Trader';
    +   6import { EquityItem }   from './Equities';
    +   7import { EquitySplit }  from './Equities';
    +   8
    +   9
    +  10export enum VenueIDs {
    +  11    IEX = 'IEX'
    +  12}
    +  13
    +  14/** provides details on available equities for a venue */
    +  15export interface VenueSummary {
    +  16    venueID:    VenueIDs; 
    +  17    venueName:  string;
    +  18    symbols:    string[];
    +  19    names:      string[];
    +  20    equities:   {string:TraderSymbol};  // sym -> TraderSymbol
    +  21}
    +  22
    +  23
    +  24export abstract class Venue {
    +  25    protected static queue = new PacingQueue(10);
    +  26    protected static addPacedGet(url:string): Promise {
    +  27//console.log(`${new Date().getTime()%10000}: addPacedGet requesting ${url}`);
    +  28        return Venue.queue.add((ms:number) => {
    +  29//            console.log(`${new Date().getTime()%10000}: pacedGet(after ${ms} ms) requesting ${url}`);
    +  30            return m.request({url:url})
    +  31                .then((data:any) => {
    +  32                    console.log(`     ${new Date().getTime()%10000}: pacedGet received data from ${url}`);
    +  33                    return data;
    +  34                })
    +  35                .catch((err:any) => {
    +  36                    console.log(`*** ${new Date().getTime()%10000}: pacedGet error ${err} from ${url}`);
    +  37                });
    +  38        });
    +  39    }
    +  40
    +  41    constructor() {}
    +  42
    +  43    summary:        VenueSummary;
    +  44
    +  45    abstract requestMarketUpdate(): Promise;
    +  46    abstract requestMetaVenue(item:EquityItem):Promise;
    +  47    abstract requestQuotesVenue(item:EquityItem, missingDays:number):Promise;
    +  48    abstract requestIntradayVenue(item:EquityItem):Promise;
    +  49    abstract requestSplitsVenue(item:EquityItem):Promise;
    +  50    abstract requestSymbolsForVenue():Promise;
    +  51}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/controller/VenueIEX.html b/docs/src/hsStock/controller/VenueIEX.html new file mode 100644 index 0000000..41b6adc --- /dev/null +++ b/docs/src/hsStock/controller/VenueIEX.html @@ -0,0 +1,416 @@ + + +

    controller/VenueIEX.ts

    +
       1import { TraderQuote,
    +   2         TraderIntraday,
    +   3         TraderSymbol}      from './Trader';
    +   4import { VenueIDs,
    +   5         VenueSummary,
    +   6         Venue }   from './Venue';
    +   7import { EquityItem }       from './Equities';
    +   8import { EquitySplit }      from './Equities';
    +   9import { round }            from 'hsutil';
    +  10
    +  11
    +  12/**
    +  13 * # IEX Trading Venue.
    +  14 * https://iextrading.com/developer/docs/
    +  15 * 
    +  16 * Behaves passively, i.e. does not initiate any server calls without explicit requests.
    +  17 * All methods initating requests are named `request***`
    +  18 */

    +  19export class IexVenue extends Venue {
    +  20    private static base        = 'https://api.iextrading.com/1.0';
    +  21    private static symbolsUrl  =                 `${IexVenue.base}/ref-data/symbols`;
    +  22    private static marketUpdateUrl = ()       => `${IexVenue.base}/market`;
    +  23    private static quoteUrl    = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/chart`;
    +  24    private static splitsUrl   = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/splits/5y`;
    +  25    private static statsUrl    = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/stats`;
    +  26    private static metaUrl     = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/quote`;
    +  27//    private financialsUrl   = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/financials`;
    +  28//    private earningsUrl     = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/earnings`;
    +  29//    private dividendsUrl    = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/dividends/5y`;
    +  30//    private logoUrl         = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/logo`;
    +  31
    +  32    private static newSummary():VenueSummary {
    +  33       return {
    +  34            venueID:    VenueIDs.IEX, 
    +  35            venueName: 'IEXTrading',
    +  36            symbols:    [],
    +  37            names:      [],
    +  38            equities:   <{string:TraderSymbol}>{}
    +  39        };
    +  40    }
    +  41
    +  42    private static normalizeMeta (data:any, item:EquityItem):EquityItem {
    +  43        if (data) {
    +  44            item.name                    = data.companyName;
    +  45            item.symbol                  = data.symbol;
    +  46            item.cat                     = item.cat || 'Stocks';
    +  47            item.stats.latestDate        = data.latestTime? new Date(data.latestUpdate) : new Date();
    +  48            item.stats.latestPrice       = data.latestPrice;
    +  49            item.stats.closeDate         = new Date(data.closeTime);
    +  50            item.stats.closePrice        = data.close;
    +  51            item.stats.change            = data.change;
    +  52            item.company                 = item.company || {};
    +  53            item.company.sector          = data.sector;
    +  54            item.company.primaryExchange = data.primaryExchange;
    +  55            item.stats = item.stats || {};
    +  56            item.otherStats = item.otherStats || {};
    +  57            delete data.otherStats;
    +  58            Object.keys(data).forEach((k:string) => ((item.stats[k]===undefined)? item.otherStats[k] = data[k] : ''));
    +  59        }
    +  60        return item;
    +  61    }
    +  62
    +  63    private static normalizeStats = (data:any, item:EquityItem):EquityItem => {
    +  64        item.name                 = data.companyName || 'unkown company';
    +  65        item.symbol               = data.symbol;
    +  66        item.cat                  = item.cat || 'Stocks';
    +  67        item.company              = item.company || {};
    +  68        item.stats                = item.stats || {};
    +  69        item.stats.week52high     = data.week52high;
    +  70        item.stats.week52low      = data.week52low;
    +  71        item.stats.latestEPS      = data.latestEPS;
    +  72        item.stats.latestEPSDate  = new Date(data.latestEPSDate);
    +  73        item.stats.marketCap      = data.marketcap;
    +  74        item.stats.cash           = data.cash;
    +  75        item.stats.revenue        = data.revenue;
    +  76        item.stats.EBITDA         = data.EBITDA;
    +  77        item.stats.exDividendDate = new Date(data.exDividendDate);
    +  78        item.stats.dividendRate   = data.dividendRate;
    +  79        item.stats.dividendYield  = data.dividendYield;
    +  80        item.otherStats = item.otherStats || {};
    +  81        delete data.otherStats;
    +  82        Object.keys(data).forEach((k:string) => ((item.stats[k]===undefined)? item.otherStats[k] = data[k] : ''));
    +  83        return item;
    +  84    }
    +  85
    +  86    private static normalizeQuotes(data:any[]):TraderQuote[] {
    +  87        return data
    +  88            .filter((d:any) => d.date)   // remove nulls
    +  89            .map((d:any) => {
    +  90                return {
    +  91                    Date:   new Date(d.date),
    +  92                    high:   parseFloat(d.high),
    +  93                    low:    parseFloat(d.low),
    +  94                    open:   parseFloat(d.open),  
    +  95                    close:  parseFloat(d.close),
    +  96                    volume: parseFloat(d.volume)
    +  97                };
    +  98            }); // sorting willbe done in Trader
    +  99    }
    + 100
    + 101    private static normalizeIntraday(data:any[]):TraderIntraday[] {
    + 102        return !data? [] : 
    + 103            data.filter((d:any) => d.date && d.minute)   // remove nulls
    + 104                .filter((d:any) => d.marketVolume>0)
    + 105                .map((d:any) => {
    + 106                    return {
    + 107                        Date: new Date(d.date.slice(0,4), d.date.slice(4,6)-1, d.date.slice(-2), d.minute.slice(0,2), d.minute.slice(-2)),
    + 108                        high: parseFloat(d.marketHigh),
    + 109                        low:  parseFloat(d.marketLow)
    + 110                    };
    + 111                }); // sorting willbe done in Trader
    + 112    }
    + 113
    + 114    private static normalizeSplits(data:IEXSplit[]): EquitySplit[] {
    + 115        if (data && data.length>0) {
    + 116            data.map((t:IEXSplit) => t.date = new Date(t.exDate));
    + 117            return data;
    + 118        }
    + 119        return undefined;
    + 120    }
    + 121
    + 122    private static processMarketsForLatestUpdate(markets:any[]):Date {
    + 123        let maxDate:Date;
    + 124        let maxMarket = '??';
    + 125        markets.forEach((venue:any) => {
    + 126            const lastDate = new Date(venue.lastUpdated);
    + 127console.log(`venue '${venue.venueName}', ${round(venue.marketPercent*100, 2)}% of market, last traded at ${lastDate.toTimeString()}`);
    + 128            if (!maxDate || maxDate < lastDate) { 
    + 129                maxDate =  lastDate; 
    + 130                maxMarket = venue.venueName;
    + 131            }
    + 132        });
    + 133console.log('latest update: ${maxDate} on ${maxMarket}');
    + 134        return maxDate;
    + 135    }
    + 136
    + 137    private normalizeSymbols = (data:string[]):VenueSummary => {
    + 138console.log(`found ${data.length} symbols for ${this.summary.venueName}`);        
    + 139        data.forEach((entry:any) => { 
    + 140            this.summary.equities[`sym${entry.symbol}`] = entry; 
    + 141            this.summary.symbols.push(entry.symbol);
    + 142            this.summary.names.push(entry.name);
    + 143        });
    + 144        return this.summary;
    + 145    }
    + 146
    + 147
    + 148    constructor() {
    + 149        super();
    + 150        this.summary = IexVenue.newSummary();
    + 151    }
    + 152
    + 153    /** retrieves the date and time of the most recent transaction on 
    + 154     * any of the markets supported by the venue */

    + 155    requestMarketUpdate(): Promise {
    + 156        return Venue.addPacedGet(IexVenue.marketUpdateUrl())
    + 157        .then(IexVenue.processMarketsForLatestUpdate);
    + 158    }
    + 159
    + 160    requestMetaVenue(item:EquityItem):Promise {
    + 161        function request(url:string, type:string, normalize:(data:any, item:EquityItem)=>EquityItem): Promise {
    + 162            return Venue.addPacedGet(url)
    + 163                .then((data:any) => {
    + 164                    if(!data) { throw `no data for request ${url}`; }
    + 165                    return normalize(data, item);
    + 166                });
    + 167        }
    + 168
    + 169        const stats = IexVenue.statsUrl(item.symbol);
    + 170        const meta  = IexVenue.metaUrl(item.symbol);
    + 171        return Promise.resolve()
    + 172        .then(() => request(stats, 'stats', IexVenue.normalizeStats))
    + 173        .catch((err:any) => {
    + 174            console.log(`*** error in request stats for ${stats}: ${err}`);
    + 175        })
    + 176        .then(() => request(meta, 'meta', IexVenue.normalizeMeta));
    + 177    }
    + 178
    + 179    requestQuotesVenue(item:EquityItem, missingDays:number):Promise {
    + 180        let timeCode;
    + 181//        if (!item.quotes || item.quotes.rows.length === 0) {
    + 182//            timeCode = '5yr';
    + 183//        } else {
    + 184            if (missingDays > 1)    { timeCode = '1m'; }
    + 185            if (missingDays > 28)   { timeCode = '3m'; }
    + 186            if (missingDays > 80)   { timeCode = '6m'; }
    + 187//            if (missingDays > 170)  { timeCode = '1yr'; }
    + 188//            if (missingDays > 360)  { timeCode = '2yr'; }
    + 189//            if (missingDays > 720)  { timeCode = '5yr'; }
    + 190//        }
    + 191    
    + 192        const url = IexVenue.quoteUrl(item.symbol)+'/'+ timeCode;
    + 193        return (!timeCode)? 
    + 194            Promise.resolve([]) :
    + 195            Venue.addPacedGet(url).then(IexVenue.normalizeQuotes);
    + 196    }
    + 197
    + 198    requestIntradayVenue(item:EquityItem):Promise {
    + 199        const url = IexVenue.quoteUrl(item.symbol)+'/1d';
    + 200        return Venue.addPacedGet(url)
    + 201            .then(IexVenue.normalizeIntraday);
    + 202    }
    + 203
    + 204    requestSplitsVenue(item:EquityItem):Promise {
    + 205        const url = IexVenue.splitsUrl(item.symbol);
    + 206        return Venue.addPacedGet(url)
    + 207            .then(IexVenue.normalizeSplits);
    + 208    }
    + 209
    + 210    requestSymbolsForVenue():Promise {
    + 211        const url = IexVenue.symbolsUrl;
    + 212console.log(`getting Trader symbols ${url}`);        
    + 213        return Venue.addPacedGet(url)
    + 214            .then(this.normalizeSymbols);
    + 215    }
    + 216};
    + 217
    + 218
    + 219interface IEXSymbols extends TraderSymbol {
    + 220    date:       string;
    + 221    isEnabled:  boolean;
    + 222    type:       string;     // refers to the common issue type of the stock. 
    + 223                            //  ad â€“ American Depository Receipt (ADR’s) 
    + 224                            //  re â€“ Real Estate Investment Trust (REIT’s) 
    + 225                            //  ce â€“ Closed end fund (Stock and Bond Fund) 
    + 226                            //  si â€“ Secondary Issue 
    + 227                            //  lp â€“ Limited Partnerships 
    + 228                            //  cs â€“ Common Stock 
    + 229                            //  et â€“ Exchange Traded Fund (ETF) 
    + 230                            //  (blank) = Not Available, i.e., Warrant, Note, or (non-filing) Closed Ended Funds
    + 231    iexId:      string;
    + 232}
    + 233
    + 234interface IEXMeta extends EquityItem {
    + 235    beta:               number; // 
    + 236    week52change:       number; // 
    + 237    shortInterest:      number; // 
    + 238    shortDate:          string; // 
    + 239    dividendRate:       number; // 
    + 240    dividendYield:      number; // 
    + 241    exDividendDate:     string; // 
    + 242    latestEPS:          number; // (Most recent quarter)
    + 243    latestEPSDate:      string; // 
    + 244    sharesOutstanding:  number; // 
    + 245    float:              number; // 
    + 246    returnOnEquity:     number; // (Trailing twelve months)
    + 247    consensusEPS:       number; // (Most recent quarter)
    + 248    numberOfEstimates:  number; // (Most recent quarter)
    + 249    EBITDA:             number; // (Trailing twelve months)
    + 250    revenue:            number; // (Trailing twelve months)
    + 251    grossProfit:        number; // (Trailing twelve months)
    + 252    cash:               number; // reers to total cash. (Trailing twelve months)
    + 253    debt:               number; // refers to total debt. (Trailing twelve months)
    + 254    ttmEPS:             number; // (Trailing twelve months)
    + 255    revenuePerShare:    number; // (Trailing twelve months)
    + 256    revenuePerEmployee: number; // (Trailing twelve months)
    + 257    peRatioHigh:        number; // 
    + 258    peRatioLow:         number; // 
    + 259    EPSSurpriseDollar:  number; // refers to the difference between actual EPS and consensus EPS in dollars.
    + 260    EPSSurprisePercent: number; // refers to the percent difference between actual EPS and consensus EPS.
    + 261    returnOnAssets:     number; // (Trailing twelve months)
    + 262    returnOnCapital:    number; // (Trailing twelve months)
    + 263    profitMargin:       number; // 
    + 264    priceToSales:       number; // 
    + 265    priceToBook:        number; // 
    + 266    day200MovingAvg:    number; // 
    + 267    day50MovingAvg:     number; // 
    + 268    institutionPercent: number; // represents top 15 institutions
    + 269    insiderPercent:     number; // 
    + 270    shortRatio:         number; // 
    + 271    year5ChangePercent: number; // 
    + 272    year2ChangePercent: number; // 
    + 273    year1ChangePercent: number; // 
    + 274    ytdChangePercent:   number; // 
    + 275    month6ChangePercent: number; // 
    + 276    month3ChangePercent: number; // 
    + 277    month1ChangePercent: number; // 
    + 278    day5ChangePercent:  number; // 
    + 279}
    + 280
    + 281
    + 282interface IEXQuote extends TraderQuote {
    + 283    change:         number;
    + 284    changeOverTime: number;
    + 285    changePercent:  number;
    + 286    label:          string; // "Oct 16"
    + 287    unadjustedVolume: number;
    + 288    vwap:           number;
    + 289}
    + 290
    + 291interface IEXStat {
    + 292    companyName:            string;
    + 293    marketcap:              number; // is not calculated in real time.
    + 294    beta:                   number;
    + 295    week52high:             number;
    + 296    week52low:              number;
    + 297    week52change:           number;
    + 298    shortInterest:          number;
    + 299    shortDate:              string;
    + 300    dividendRate:           number;
    + 301    dividendYield:          number;
    + 302    exDividendDate:         string;
    + 303    latestEPS:              number; // (Most recent quarter)
    + 304    latestEPSDate:          string;
    + 305    sharesOutstanding:      number;
    + 306    float:                  number;
    + 307    returnOnEquity:         number; // (Trailing twelve months)
    + 308    consensusEPS:           number; // (Most recent quarter)
    + 309    numberOfEstimates:      number; // (Most recent quarter)
    + 310    symbol:                 string;
    + 311    EBITDA:                 number; // (Trailing twelve months)
    + 312    revenue:                number; // (Trailing twelve months)
    + 313    grossProfit:            number; // (Trailing twelve months)
    + 314    cash:                   number; // refers to total cash. (Trailing twelve months)
    + 315    debt:                   number; // refers to total debt. (Trailing twelve months)
    + 316    ttmEPS:                 number; // (Trailing twelve months)
    + 317    revenuePerShare:        number; // (Trailing twelve months)
    + 318    revenuePerEmployee:     number; // (Trailing twelve months)
    + 319    peRatioHigh:            number;
    + 320    peRatioLow:             number;
    + 321    EPSSurpriseDollar:      number; // refers to the difference between actual EPS and consensus EPS in dollars.
    + 322    EPSSurprisePercent:     number; // refers to the percent difference between actual EPS and consensus EPS.
    + 323    returnOnAssets:         number; // (Trailing twelve months)
    + 324    returnOnCapital:        number; // (Trailing twelve months)
    + 325    profitMargin:           number;
    + 326    priceToSales:           number;
    + 327    priceToBook:            number;
    + 328    day200MovingAvg:        number;
    + 329    day50MovingAvg:         number;
    + 330    institutionPercent:     number; // represents top 15 institutions
    + 331    insiderPercent:         number;
    + 332    shortRatio:             number;
    + 333    year5ChangePercent:     number;
    + 334    year2ChangePercent:     number;
    + 335    year1ChangePercent:     number;
    + 336    ytdChangePercent:       number;
    + 337    month6ChangePercent:    number;
    + 338    month3ChangePercent:    number;
    + 339    month1ChangePercent:    number;
    + 340    day5ChangePercent:      number;    
    + 341}
    + 342
    + 343interface IEXFinancials {
    + 344    reportDate:             string;
    + 345    grossProfit:            number;
    + 346    costOfRevenue:          number;
    + 347    operatingRevenue:       number;
    + 348    totalRevenue:           number;
    + 349    operatingIncome:        number;
    + 350    netIncome:              number;
    + 351    researchAndDevelopment: number;
    + 352    operatingExpense:       number;
    + 353    currentAssets:          number;
    + 354    totalAssets:            number;
    + 355    totalLiabilities:       number;
    + 356    currentCash:            number;
    + 357    currentDebt:            number;
    + 358    totalCash:              number;
    + 359    totalDebt:              number;
    + 360    shareholderEquity:      number;
    + 361    cashChange:             number;
    + 362    cashFlow:               number;
    + 363    operatingGainsLosses:   string;
    + 364}
    + 365
    + 366interface IEXEarnings {
    + 367    actualEPS:          number;
    + 368    consensusEPS:       number;
    + 369    estimatedEPS:       number;
    + 370    announceTime:       string;
    + 371    numberOfEstimates:  number;
    + 372    EPSSurpriseDollar:  number;
    + 373    EPSReportDate:      string;
    + 374    fiscalPeriod:       string;
    + 375    fiscalEndDate:      string;
    + 376}
    + 377
    + 378interface IEXDividends {
    + 379    exDate:         string; // refers to the dividend ex-date
    + 380    paymentDate:    string; // refers to the payment date
    + 381    recordDate:     string; // refers to the dividend record date
    + 382    declaredDate:   string; // refers to the dividend declaration date
    + 383    amount:         number; // refers to the payment amount
    + 384    type:           string; // refers to the dividend payment type (Dividend income, Interest income, Stock dividend, Short term capital gain, Medium term capital gain, Long term capital gain, Unspecified term capital gain)
    + 385    qualified:      string; // refers to the dividend income type 
    + 386                            // P = Partially qualified income 
    + 387                            // Q = Qualified income 
    + 388                            // N = Unqualified income 
    + 389                            // null = N/A or unknown
    + 390}
    + 391
    + 392export interface IEXSplit extends EquitySplit {
    + 393    exDate:         string; // refers to the split ex-date
    + 394    declaredDate:   string; // refers to the split declaration date
    + 395    recordDate:     string; // refers to the split record date
    + 396    paymentDate:    string; // refers to the split payment date
    + 397    toFactor:       string; // To factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    + 398    forFactor:      string; // For factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    + 399}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/fileIO.html b/docs/src/hsStock/fileIO.html new file mode 100644 index 0000000..ab2c084 --- /dev/null +++ b/docs/src/hsStock/fileIO.html @@ -0,0 +1,49 @@ + + +

    fileIO.ts

    +
       1
    +   2import { m }            from 'hslayout';
    +   3
    +   4const SAVE_URL          = '/cgi/save.js';
    +   5
    +   6export function save(data:any, fname:string):Promise {
    +   7    return m.request({
    +   8        method: 'PUT',
    +   9        url: `${SAVE_URL}?name=${fname}`,   // fname relative to 'apps/
    +  10        data: data
    +  11    })
    +  12    .then(() => data)                       // send `data` into next `then`
    +  13    .catch((err:any) => {
    +  14        console.log(`error saving to ${fname}`);
    +  15        console.log(err);
    +  16        console.log(err.stack);
    +  17        return data;
    +  18    });
    +  19}
    +  20
    +  21export function load(fname:string):Promise {
    +  22    return m.request({
    +  23        method: 'GET',
    +  24        url: fname                          // relative to 'apps//
    +  25    })
    +  26    .catch((err:any):null => {
    +  27        console.log(`error loading ${fname}`);
    +  28        return null;
    +  29    });
    +  30}
    +  31
    +  32
    + + \ No newline at end of file diff --git a/docs/src/hsStock/index.html b/docs/src/hsStock/index.html new file mode 100644 index 0000000..01b4587 --- /dev/null +++ b/docs/src/hsStock/index.html @@ -0,0 +1,25 @@ + + +

    index.ts

    +
       1/**
    +   2 * Progam entry point. Initiates loading the docsets and setting up a router structure
    +   3 */

    +   4
    +   5/** */
    +   6
    +   7import * as Router from './Router';
    +   8if (Router) {}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/overview.html b/docs/src/hsStock/overview.html new file mode 100644 index 0000000..533da82 --- /dev/null +++ b/docs/src/hsStock/overview.html @@ -0,0 +1,23 @@ + + +

    overview.ts

    +
       1/**
    +   2# hsStock
    +   3
    +   4*/

    +   5
    +   6/** */
    + + \ No newline at end of file diff --git a/docs/src/hsStock/saveToFile.html b/docs/src/hsStock/saveToFile.html new file mode 100644 index 0000000..e5a386c --- /dev/null +++ b/docs/src/hsStock/saveToFile.html @@ -0,0 +1,36 @@ + + +

    saveToFile.ts

    +
       1
    +   2import { m }            from 'hslayout';
    +   3
    +   4const SAVE_URL          = '/cgi/save.js';
    +   5
    +   6export function save(data:any, fname:string):Promise {
    +   7    return m.request({
    +   8        method: 'PUT',
    +   9        url: `${SAVE_URL}?name=${fname}`,   // fname relative to 'apps/
    +  10        data: data
    +  11    })
    +  12    .then(() => data)                       // send `data` into next `then`
    +  13    .catch((err:any) => {
    +  14        console.log(`error saving to ${fname}`);
    +  15        console.log(err);
    +  16        console.log(err.stack);
    +  17        return data;
    +  18    });
    +  19}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/server/convertInvestments.html b/docs/src/hsStock/server/convertInvestments.html new file mode 100644 index 0000000..8be6bd7 --- /dev/null +++ b/docs/src/hsStock/server/convertInvestments.html @@ -0,0 +1,20 @@ + + +

    server/convertInvestments.ts

    +
       1import { hsNode } from 'hsnode';
    +   2
    +   3console.log(hsNode);
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/Equity.html b/docs/src/hsStock/view/Equity.html new file mode 100644 index 0000000..965e2a3 --- /dev/null +++ b/docs/src/hsStock/view/Equity.html @@ -0,0 +1,242 @@ + + +

    view/Equity.ts

    +
       1import { m }            from 'hslayout';
    +   2import { Data,
    +   3         DataSet }      from 'hsgraph';
    +   4import { Trader,
    +   5         TraderQuote }  from './Trader';
    +   6
    +   7const DEF_EQUITY_LIST   = 'defEquityList.json';
    +   8const EQUITY_LIST       = 'equityList.json';
    +   9const SAVE_URL          = '../../cgi-bin/save.js';
    +  10
    +  11export interface Category {
    +  12    cat:      string;         // the category name
    +  13    equities: EquityItem[];   // array of equities in this category
    +  14}
    +  15
    +  16export interface EquityItem {
    +  17    /** equity symbol, e.g. 'GOOG' */
    +  18    symbol: string; 
    +  19    /** equity name, e.g. 'Alphabet' */
    +  20    name:   string;
    +  21    /** investment category, e.g. 'Stocks' */
    +  22    cat:    string;
    +  23
    +  24    company?: {
    +  25        /** industry sector */
    +  26        sector?:    string;
    +  27        /** primary trading exchange */
    +  28        primaryExchange?: string;
    +  29    };
    +  30
    +  31    stats?: {
    +  32        /** price-to-earnings ratio */
    +  33        peRatio?:           number;
    +  34        /** 52 week high */
    +  35        week52high?:        number;
    +  36        /** 52 week low */
    +  37        week52low?:         number;
    +  38        /** market capitalziation */
    +  39        marketCap?:         number;
    +  40        /** latest Earnings per Share */
    +  41        latestEPS?:         number;
    +  42        /** date of latest Earnings per Share */
    +  43        latestEPSDate?:     string;
    +  44        /** dividend rate */
    +  45        dividendRate?:      number;
    +  46        /** dividend rate */
    +  47        dividendYield?:     number; 
    +  48        /** date of dividend */
    +  49        exDividendDate?:    string;
    +  50    };
    +  51    quotes?: Data;
    +  52    otherStats?:  {};
    +  53}
    +  54
    +  55export class EquityList {
    +  56    //------  private  parts -----
    +  57    private bySymbol   = <{string: EquityItem}>{};
    +  58    private categories = [];
    +  59    private trader: Trader;
    +  60
    +  61    private addCategory(cat:string) {
    +  62        if (!this.categories[cat]) {
    +  63            const category:Category = { cat: cat, equities: [] };
    +  64            this.categories.push(category);
    +  65            this.categories[cat] = category;
    +  66        }
    +  67    }
    +  68
    +  69    private unkownEquity() { return {cat:'unknown Cat', symbol:'????', name:'unknown'}; }
    +  70
    +  71    private JSON2EquityList(data:any):EquityList {
    +  72        if (!data) { console.log('no data in JSON2EquityList'); }
    +  73        else {
    +  74            Object.keys(data).forEach((k:string) => {
    +  75                this.addCategory(k);
    +  76                Object.keys(data[k]).forEach((e:string) => {
    +  77                    this.add({ symbol: e, name: data[k][e], cat: k, stats:{}, company:{}});
    +  78                });
    +  79            });   
    +  80        }
    +  81        return this;
    +  82    }
    +  83
    +  84    private EquityList2JSON():any {
    +  85        const data:any = {};
    +  86        this.categories.forEach((c:Category) => {
    +  87            data[c.cat] = {};
    +  88            c.equities.forEach((e:EquityItem) => {
    +  89                data[c.cat][e.symbol] = e.name;
    +  90            });
    +  91        });
    +  92        return data;
    +  93    }
    +  94
    +  95    private add(item:EquityItem) {
    +  96        const sym = item.symbol.toUpperCase();
    +  97        if (!this.bySymbol[sym]) {
    +  98            this.bySymbol[sym] = item;
    +  99            if (!this.categories[item.cat]) { this.addCategory(item.cat); }
    + 100            this.categories[item.cat].equities.push(item);
    + 101        }
    + 102        this.loadMeta(item);
    + 103    };
    + 104
    + 105    private remove(itemOrSymbol:EquityItem|string) {
    + 106        const item = (typeof itemOrSymbol === 'string')? 
    + 107            this.bySymbol[itemOrSymbol.toUpperCase()] : this.bySymbol[(itemOrSymbol).symbol];
    + 108        this.bySymbol[item.symbol.toUpperCase()] = undefined;
    + 109        const i = this.categories[item.cat].equities.indexOf(item);
    + 110        if (i>=0) { this.categories[item.cat].equities.splice(i,1); }
    + 111    }
    + 112
    + 113    //------  public parts -----
    + 114
    + 115    constructor() {
    + 116        this.trader = new Trader();
    + 117    }
    + 118
    + 119    getItem(symbol:string):EquityItem { 
    + 120        if (this.bySymbol[symbol]) { 
    + 121            return this.bySymbol[symbol]; 
    + 122        }
    + 123        if (this.categories.length > 0) { 
    + 124            if (this.categories[0].equities.length > 0) { 
    + 125                return this.categories[0].equities[0]; 
    + 126            }
    + 127        }
    + 128        return this.unkownEquity();
    + 129    }
    + 130    getCategories():Category[] { return this.categories; }
    + 131    getFirstByCat(cat:string):EquityItem {
    + 132        const c = this.categories[cat];
    + 133        if (c && c.equities.length>0) { return c.equities[0]; }
    + 134        else { return this.unkownEquity(); }
    + 135    }
    + 136
    + 137    addItem(item:EquityItem) {
    + 138        this.add(item);
    + 139        this.saveEquityList();
    + 140    }
    + 141    removeItem(itemOrSymbol:EquityItem|string) {
    + 142        this.remove(itemOrSymbol);
    + 143        this.saveEquityList();
    + 144    }
    + 145    load(fname:string):Promise {
    + 146        return m.request({
    + 147            method: 'GET',
    + 148            url: 'data/'+fname                  // relative to 'apps//
    + 149        });
    + 150    }
    + 151    save(data:any, fname:string):Promise {
    + 152        return m.request({
    + 153            method: 'POST',
    + 154            url: `${SAVE_URL}?name=${fname}`,   // relative to 'apps//data/
    + 155            data: data
    + 156        })
    + 157        .then(() => data)                       // send `data` into next `then`
    + 158        .catch((err:any) => {
    + 159            console.log(`error saving to ${fname}`);
    + 160            console.log(err);
    + 161            console.log(err.stack);
    + 162            return data;
    + 163        });
    + 164    }
    + 165    loadEquityList():Promise {
    + 166        return this.load(EQUITY_LIST)
    + 167        .catch(() => this.load(DEF_EQUITY_LIST))
    + 168        .then((data:any) => this.JSON2EquityList.call(this, data));
    + 169    }
    + 170    saveEquityList():Promise {
    + 171        return this.save(this.EquityList2JSON.call(this), EQUITY_LIST);
    + 172    }
    + 173    loadMeta(item:EquityItem):Promise {
    + 174        return this.load(`stock/sym${item.symbol}.json`)
    + 175        .catch(() => 
    + 176            this.trader.getMeta(item.symbol)
    + 177            .then((data:EquityItem) => { 
    + 178                this.saveMeta(data, item.symbol);
    + 179                return data;
    + 180            }))
    + 181        .then((data:EquityItem) => {
    + 182            if (!data) { console.log('no data in JSON2EquityList'); }
    + 183            else {
    + 184                Object.keys(data).forEach((k:string) => item[k] = data[k]);
    + 185            }
    + 186            return item;
    + 187        });
    + 188    }
    + 189    saveMeta(data:any, sym:string):Promise {
    + 190        console.log(`saving stock/sym${sym}.json`);
    + 191        return this.save(data, `stock/sym${sym}.json`);
    + 192    }
    + 193    loadQuotes(item:EquityItem):Promise {
    + 194        const traderQuote2Dataset = (dataIn:TraderQuote[]) => {
    + 195            const dataOut:Data = new Data();
    + 196            dataOut.setData(
    + 197                dataIn.map((e: TraderQuote) => [e.date, e.open, e.close, e.high, e.low, e.volume]), 
    + 198                ['Date', 'Open', 'Close', 'High', 'Low', 'Volume']);
    + 199            return dataOut;
    + 200        };
    + 201        if (item.quotes && item.quotes.getData().length>0) {
    + 202            return Promise.resolve(item);
    + 203        } else {
    + 204            return this.load(`stock/quotes${item.symbol}.json`)
    + 205            .then((data:DataSet) => { 
    + 206                item.quotes = new Data(data);
    + 207                return item;
    + 208            })
    + 209            .catch(() => 
    + 210                this.trader.getQuotes(item, '5y')
    + 211                .then(traderQuote2Dataset)
    + 212                .then((data:Data) => {
    + 213                    item.quotes = data;
    + 214                    this.saveQuotes(item);
    + 215                    return item;
    + 216                })
    + 217            );
    + 218        }
    + 219    }
    + 220    saveQuotes(item:EquityItem):Promise {
    + 221        return this.save(item.quotes.export(), `stock/quotes${item.symbol}.json`);
    + 222    }
    + 223}
    + 224
    + 225
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/Header.html b/docs/src/hsStock/view/Header.html new file mode 100644 index 0000000..c3fd6db --- /dev/null +++ b/docs/src/hsStock/view/Header.html @@ -0,0 +1,31 @@ + + +

    view/Header.ts

    +
       1import { m, Vnode}  from 'hslayout';
    +   2import { Layout }   from 'hslayout';
    +   3import { Menu }     from 'hswidget';
    +   4
    +   5export class Header extends Layout {
    +   6    getComponents(node: Vnode): Vnode {
    +   7        const r = node.attrs.route;
    +   8        return m(Menu, {desc: { 
    +   9            items: ['View', 'Trade', 'Import'].map((c:any) => c),
    +  10            selectedItem: (r && r.mode)? r.mode : 0,
    +  11            select: (item:string) => m.route.set('/api/:mode/0', {mode:item}) 
    +  12        }});
    +  13    }     
    +  14}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/Import.html b/docs/src/hsStock/view/Import.html new file mode 100644 index 0000000..cd9564e --- /dev/null +++ b/docs/src/hsStock/view/Import.html @@ -0,0 +1,71 @@ + + +

    view/Import.ts

    +
       1import { m }            from 'hslayout';
    +   2import { EquityList }   from './Equity';
    +   3import { Trader }       from './Trader';
    +   4import { Button }       from 'hswidget';
    +   5
    +   6
    +   7let Symbols:string[] = []; 
    +   8
    +   9const trader = new Trader();
    +  10
    +  11export function tabImport(list:EquityList, symbol:string) {
    +  12    return m('.hs-left-nav', buttons(list));
    +  13}
    +  14
    +  15function buttons(list:EquityList) {
    +  16    function stockImport() {
    +  17        list.load('symbolList.json')
    +  18        .then((sList:string[]) => {
    +  19            function next(i:number) {
    +  20                trader.getMeta(sList[i])
    +  21                .then((data:any) => {
    +  22                    list.save(data, `stocks/sym${sList[i]}.json`);
    +  23                    return i;
    +  24                })
    +  25                .then((i:number) => {
    +  26                    if (i +  27                })
    +  28                .catch((err:any) => console.log(`i=${i}, sym=${sList[i]}, err=${err}`));
    +  29            }
    +  30            next(0);
    +  31        });   
    +  32    } 
    +  33
    +  34    function loadSymbols() {
    +  35        trader.getSymbols()
    +  36        .then((data:any) => {
    +  37            list.save(data.list, 'symbolList.json');
    +  38            Symbols = data.list;
    +  39            return data;
    +  40        })
    +  41        .then((data:any) => {
    +  42            list.save(data.set, 'symbolSet.json');
    +  43            return data;
    +  44        });
    +  45    }
    +  46
    +  47    return [
    +  48        m(Button, {name:'IEX Import', onclick:loadSymbols}),
    +  49        m(Button, {name:'Stock Import', onclick:stockImport}),
    +  50        m('', `${Symbols.length} records loaded`)
    +  51    ];
    +  52}
    +  53
    +  54
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/ImportPane.html b/docs/src/hsStock/view/ImportPane.html new file mode 100644 index 0000000..755c024 --- /dev/null +++ b/docs/src/hsStock/view/ImportPane.html @@ -0,0 +1,65 @@ + + +

    view/ImportPane.ts

    +
       1import { m, Vnode }         from 'hslayout';
    +   2import { Layout }           from 'hslayout';
    +   3import { gEquities,
    +   4         Equities }         from '../controller/Equities';
    +   5import { Button }           from 'hswidget';
    +   6import { VenueSummary }     from '../controller/Venue';
    +   7import { save }             from '../fileIO';
    +   8
    +   9
    +  10let Symbols:string[] = []; 
    +  11
    +  12export const ImportPane = {
    +  13    view: (node: Vnode): Vnode => {
    +  14        return m(Layout, {
    +  15            rows: ['50px'],
    +  16            css: '.hs-import-pane',
    +  17            content: buttons(gEquities)
    +  18        });
    +  19    }    
    +  20};
    +  21
    +  22
    +  23function buttons(list:Equities) {
    +  24    return [
    +  25        m(Button, {name:'get IEX Symbols', onclick:readSymbols}),
    +  26        m(Button, {name:'get Stock Splits', onclick:readSplits}),
    +  27//        m(Button, {name:'clear invalid venues', onclick:gEquities.clearInvalids.bind(gEquities)}),
    +  28        m(Button, {name:'Stock Import'}),
    +  29        m(Button, { 
    +  30//            style: 'left:150px; width:70px;',
    +  31            name: 'Update',
    +  32            onclick: () => gEquities.getMarketUpdate()            
    +  33        }),
    +  34        m('', `${Symbols.length} records loaded`)
    +  35    ];
    +  36}
    +  37
    +  38function readSplits() {
    +  39    gEquities.readSplits(); 
    +  40}
    +  41
    +  42function readSymbols() {
    +  43    gEquities.getVenueSymbols()
    +  44    .then((ref:VenueSummary) => {
    +  45        save(ref.equities, `hsStock/data/traderSymbols.json`);
    +  46    });
    +  47}
    +  48
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/LeftNav.html b/docs/src/hsStock/view/LeftNav.html new file mode 100644 index 0000000..686f6b1 --- /dev/null +++ b/docs/src/hsStock/view/LeftNav.html @@ -0,0 +1,45 @@ + + +

    view/LeftNav.ts

    +
       1import { Vnode}      from 'hslayout';
    +   2import { Layout }    from 'hslayout';
    +   3import { tabView }      from './ViewPane';
    +   4import { tabTrade }     from './TradePane';
    +   5import { tabImport }    from './ImportPane';
    +   6import { gEquityList }  from '../Site';
    +   7
    +   8export class LeftNav extends Layout { 
    +   9    getComponents(node: Vnode): Vnode {
    +  10        let mode:string = 'View';
    +  11        let symbol:string;
    +  12        let list = gEquityList;
    +  13        if (node.attrs && node.attrs.route) {
    +  14            mode = node.attrs.route.mode;
    +  15            symbol = node.attrs.route.symbol;
    +  16        }
    +  17        let content = '???';
    +  18        switch(mode) {
    +  19            case 'Import':  content = tabImport(list, symbol); break;
    +  20            case 'Trade':   content = tabTrade(list, symbol); break;
    +  21            case 'View':
    +  22            default:        content = tabView(list, symbol);
    +  23        }
    +  24        return content;
    +  25    }     
    +  26
    +  27
    +  28
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/Main.html b/docs/src/hsStock/view/Main.html new file mode 100644 index 0000000..6707903 --- /dev/null +++ b/docs/src/hsStock/view/Main.html @@ -0,0 +1,85 @@ + + +

    view/Main.ts

    +
       1import { m, Vnode}      from 'hslayout';
    +   2import { Layout }       from 'hslayout';
    +   3import { Graph,
    +   4         DataSet, 
    +   5         Series,
    +   6         Axes }         from 'hsgraph';
    +   7import { Collapsible,
    +   8         Button }       from 'hswidget';
    +   9import { EquityItem }   from './Equity';
    +  10import { gEquityList }  from '../Site';
    +  11
    +  12export class MainDetails extends Layout {
    +  13    getComponents(node: Vnode): Vnode {
    +  14        let symbol:string;
    +  15        let list = gEquityList;
    +  16        if (node.attrs && node.attrs.route) {
    +  17            symbol = node.attrs.route.symbol;
    +  18        }
    +  19        const item:EquityItem = list.getItem(symbol);
    +  20        return m('.hs-equity-detail', [
    +  21            m('.hs-equity-name', item.name),
    +  22            m('.hs-equity-symbol', item.symbol),
    +  23            m('.hs-equity-cat', item.cat),
    +  24            m('.hs-equity-cat', item.stats.peRatio),
    +  25            m('.hs-equity-cat', item.stats.week52high),
    +  26            m('.hs-equity-cat', item.stats.week52low),
    +  27            m('.hs-equity-cat', item.stats.marketCap),
    +  28            m('.hs-equity-cat', item.company.sector),
    +  29            m('.hs-equity-cat', item.company.primaryExchange),
    +  30            m('.hs-equity-cat', `${item.quotes?item.quotes.getData().length:0} quotes`)
    +  31        ]);
    +  32    }     
    +  33
    +  34
    +  35export class MainGraph extends Layout {
    +  36    getComponents(node: Vnode): Vnode {
    +  37        let symbol:string;
    +  38        let list = gEquityList;
    +  39        if (node.attrs && node.attrs.route) {
    +  40            symbol = node.attrs.route.symbol;
    +  41        }
    +  42        const item = list.getItem(symbol);
    +  43        const data:DataSet = item.quotes? item.quotes.export() : {names:['Date', 'Close'], rows:[['1/1/17',0], ['12/31/17', 1]]};
    +  44        return [m(Graph, {cfgFn: (cfg:any) => {
    +  45                cfg.chart.title.visible = false;
    +  46                cfg.axes.primary.x.scale.type = Axes.type.date;
    +  47                cfg.axes.primary.x.title.visible = false;
    +  48                cfg.axes.primary.x.scale.domain = ['auto', new Date()]; // always up to today
    +  49                cfg.axes.primary.y.scale.type = Axes.type.log;
    +  50                cfg.axes.primary.y.scale.domain = ['tight', 'tight']; // always up to today
    +  51                cfg.axes.primary.y.title.visible = false;
    +  52                cfg.axes.primary.y.ticks.minor.labels.visible = true;
    +  53                cfg.grid.minor.hor.visible = true;
    +  54                cfg.series.data   = data;
    +  55                cfg.series.defaultStyle.line.width = 1;
    +  56                cfg.series.series = [
    +  57                    { cols: ['Date', 'Close'], type: Series.plot.line },
    +  58                    { cols: ['Date', 'High'], type: Series.plot.line }
    +  59                ];
    +  60            }}),
    +  61            m(Collapsible, {css:'hs-stock-setting-overlay', components: [
    +  62                m('', 'Options:'),
    +  63                [m(Button, { name: 'option 1'}), m('', 'option 2')]
    +  64            ]})
    +  65        ];
    +  66    }     
    +  67
    +  68
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/MainDetails.html b/docs/src/hsStock/view/MainDetails.html new file mode 100644 index 0000000..390138d --- /dev/null +++ b/docs/src/hsStock/view/MainDetails.html @@ -0,0 +1,145 @@ + + +

    view/MainDetails.ts

    +
       1import { m, Vnode}      from 'hslayout';
    +   2import { Layout }       from 'hslayout';
    +   3import { gEquities,
    +   4         EquityItem }   from '../controller/Equities';
    +   5import { date, round }  from 'hsutil'; 
    +   6
    +   7const format = (n:number):string => {
    +   8    let result = ''+n;
    +   9    const limits =  [1000000000, 1000000, 1000, 1, 0.001, 0.000001, 0.000000001];
    +  10    const postfix = [' B',       ' M',    ' k', '', ' m',     ' Âµ',        ' n'];
    +  11
    +  12    limits.some((v:number, i:number) => {
    +  13        if (n>v) { 
    +  14            result = Math.round(n/v*10)/10+postfix[i];
    +  15            return true;
    +  16        }
    +  17        return false;
    +  18    });
    +  19    return result;
    +  20};
    +  21
    +  22/**
    +  23 * ## 
    +  24 */

    +  25export class CycleThrough {
    +  26    static state = {};
    +  27    static create(key:string, ...args:string[]) {
    +  28        return new CycleThrough(key, args);
    +  29    }
    +  30    key:string;
    +  31    args: string[];
    +  32    private constructor(key:string, args:string[]) {
    +  33        this.active = args[1]!==undefined;
    +  34        this.key    = key;
    +  35        this.args   = args;
    +  36    }
    +  37
    +  38    public active:boolean;
    +  39    public next = () => !this.active? '' : (CycleThrough.state[this.key] = ((CycleThrough.state[this.key] || 0)+1) % this.args.length);
    +  40    public get val() { return this.args[CycleThrough.state[this.key] || 0]; }
    +  41}
    +  42
    +  43function ellipses(str:string, limit:number):string { 
    +  44    return !str? str :
    +  45        str.length +  46}
    +  47
    +  48export class MainDetails extends Layout { 
    +  49    getComponents(node: Vnode): Vnode {
    +  50        const symbol  = m.route.param('symbol');
    +  51        const item:EquityItem = gEquities.getItem(symbol);
    +  52        const s = item.stats || {};
    +  53        const c = item.company || {};
    +  54        const divDate = (s.dividendRate && s.exDividendDate)? date('%MM/%D/%YY', new Date(s.exDividendDate)) : '';
    +  55        const pe = s.peRatio || round((s.latestPrice || 0) / s.latestEPS, 3);
    +  56        const latestDate = date('%MM/%DD/%YY: ', new Date(s.latestDate));
    +  57        const latestEPSDate = s.latestEPSDate? date('%MM/%D/%YY', new Date(s.latestEPSDate)) : '1/1/1970';
    +  58        const latestEPS     = s.latestEPS? `$${s.latestEPS}`: '--';
    +  59        const latestEPSRate = s.latestEPS? `${round(100*s.latestEPS/s.latestPrice,3)}%`: '--';
    +  60        const week52high    = s.week52high? `$${s.week52high}` : '--';
    +  61        const week52hgRatio = s.week52high? `${round(100*s.week52high/s.latestPrice,3)}%`: '--';
    +  62        const week52low     = s.week52low? `$${s.week52low}` : '--';
    +  63        const week52lwRatio = s.week52low? `${round(100*s.week52low/s.latestPrice,3)}%`: '--';
    +  64        const cols = [{ 
    +  65            css:'', 
    +  66            fields: [
    +  67                [`${item.cat}:`,                        ellipses(c.sector, 18)],
    +  68                ['Exchange:',                           ellipses(c.primaryExchange, 18)],
    +  69                ['Invested:',                           `${item.shares} shares`, `$${format(item.shares*(s.latestPrice || 0))}`]
    +  70        ]},{ 
    +  71            css:'', 
    +  72            fields: [
    +  73                ['Market Cap',                          `$${format(s.marketCap)}`],
    +  74                ['Revenue:',                            `$${format(s.revenue)}`],
    +  75                ['Profits:',                            `$${format(s.EBITDA)}`],
    +  76                ['Cash:',                               `$${format(s.cash)}`]
    +  77        ]},{ 
    +  78            css:'', 
    +  79            fields: [
    +  80                ['PE:',                                 `${pe || '--'}`],
    +  81                ['52 wk high:',                         week52high, week52hgRatio],
    +  82                ['52 wk low:',                          week52low,  week52lwRatio],
    +  83                ['Volume (shares):',                    `${format(s.closeVolume) || '--'}`]
    +  84        ]},{ 
    +  85            css:'.hs-equity-right-column', 
    +  86            fields: [
    +  87                [`Dividend ${divDate}:`,    `$${s.dividendRate}`,  `${round(s.dividendYield,3)}%`],
    +  88                [`EPS ${latestEPSDate}:`,   latestEPS, latestEPSRate]
    +  89        ]}];
    +  90        const change = CycleThrough.create('change', `$${s.change}`, `${round(100*s.change/s.latestPrice,3)}%`, 'hehe');
    +  91        return m(Layout, {
    +  92            css: '.hs-equity-detail',
    +  93            rows: ['30px', '80px'],
    +  94            content: [
    +  95                m(Layout, {
    +  96                    columns:['fill', '250px'],
    +  97                    content: [
    +  98                        m('span.hs-equity', [
    +  99                            m('span.hs-equity-name', item.name),
    + 100                            m('span.hs-equity-symbol', item.symbol)
    + 101                        ]),
    + 102                        m('span.hs-equity .hs-align-right', [
    + 103                            m('span', `${latestDate}`),
    + 104                            m('span.hs-equity-close', `$${s.latestPrice || 0}`),
    + 105                            m(`span.hs-equity-change ${s.change<0? '.hs-negative': '.hs-positive'} ${change.active?'.hs-link':''}`, {onclick: change.next}, `${change.val}`)
    + 106                        ])
    + 107                    ]
    + 108                }),
    + 109                m(Layout, {
    + 110                    css: '.hs-equity-detail-column',
    + 111                    columns:[],
    + 112                    content: cols.map((c:any, col:number) => m(Layout, {
    + 113                        columns:[],
    + 114                        content: [
    + 115                            m('', c.fields.map((e:[string, string]) => m('.hs-equity-cat', e[0]))),
    + 116                            m('', c.fields.map((e:[string, string], idx:number) => {
    + 117                                const t = CycleThrough.create(`${col}${idx}`, e[1], e[2]);
    + 118                                return m(`.hs-equity-cat .hs-align-right ${t.active?'.hs-link':''} ${c.css}`, {onclick: t.next}, t.val);
    + 119                            })) 
    + 120                        ]
    + 121                    }))
    + 122                })
    + 123            ]
    + 124        });
    + 125    }     
    + 126
    + 127
    + 128
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/MainGraph.html b/docs/src/hsStock/view/MainGraph.html new file mode 100644 index 0000000..d5d86b1 --- /dev/null +++ b/docs/src/hsStock/view/MainGraph.html @@ -0,0 +1,121 @@ + + +

    view/MainGraph.ts

    +
       1import { m, Vnode}      from 'hslayout';
    +   2import { Layout }       from 'hslayout';
    +   3import { Data,
    +   4         DataSet }      from 'hsdata';
    +   5import { Condition }    from 'hsdata';
    +   6import { 
    +   7//         Button,
    +   8         ToggleButton } from 'hswidget';
    +   9import { Graph,
    +  10         Series,
    +  11         Axes }         from 'hsgraph';
    +  12import { gEquities,
    +  13         EquityItem }   from '../controller/Equities';
    +  14
    +  15let limitDateIndex = 0;
    +  16
    +  17function getLimitDate(time:string):Date {
    +  18    const result = new Date();
    +  19    switch (time) {
    +  20        case 'max':  result.setFullYear(result.getFullYear()-30); break;
    +  21        case '40yr': result.setFullYear(result.getFullYear()-40); break;
    +  22        case '20yr': result.setFullYear(result.getFullYear()-20); break;
    +  23        case '10yr': result.setFullYear(result.getFullYear()-10); break;
    +  24        case '5yr':  result.setFullYear(result.getFullYear()-5); break;
    +  25        case '1yr':  result.setFullYear(result.getFullYear()-1); break;
    +  26        case '3mo':  result.setMonth(result.getMonth()-(3+result.getMonth()%3)); break;
    +  27        case '1mo':  result.setMonth(result.getMonth()-1); break;
    +  28        case '10d':  result.setDate(result.getDate()-10); break;
    +  29        case '1d':   result.setDate(result.getDate()-1); break;
    +  30    }
    +  31    result.setHours(0);
    +  32    return result;
    +  33}
    +  34
    +  35export class MainGraph extends Layout { 
    +  36    getComponents(node: Vnode): Vnode { 
    +  37        const timeWindows = ['1yr', '3mo', '1mo', '10d', '1d', '40yr', '20yr', '10yr', '5yr'];
    +  38        const limitDates = timeWindows.map(getLimitDate);
    +  39        let limitDate = limitDates[limitDateIndex];
    +  40console.log(`time ${limitDateIndex}: ${timeWindows[limitDateIndex]} ${limitDate.toDateString()}`);        
    +  41        let maxDate = new Date();
    +  42        const symbol = m.route.param('symbol');
    +  43        const item:EquityItem = gEquities.getItem(symbol);
    +  44        if (timeWindows[limitDateIndex]==='1d' && item.intraday) {
    +  45            limitDate = item.intraday.rows[0][0]; // the date
    +  46            maxDate = item.intraday.rows[item.intraday.rows.length-1][0];
    +  47        }
    +  48        const dataQuotes:DataSet = item.quotes? item.quotes : 
    +  49            {name:'Quotes', colNames:['Date', 'Close'], rows:[]};
    +  50        const dataIntra:DataSet = item.intraday? item.intraday : 
    +  51            {name:'Intraday', colNames:['Date', 'Close'], rows:[[]]};
    +  52        const shares:DataSet = Data.toDataSet(item.trades, 'Shares');
    +  53        const buyCond:Condition = { change: (c:number) => c>0};
    +  54        const sellCond:Condition = { change: (c:number) => c<0};
    +  55        const timeCond:Condition = { Date: (d:Date) => d>limitDate};
    +  56        return [m('.hs-layout-fill', { onmousemove:console.log}, m(Graph, { cfgFn: (cfg:any) => {
    +  57            cfg.graph.timeCond = timeCond;
    +  58            cfg.chart.title.visible = false;
    +  59            cfg.axes.primary.x.scale.type = Axes.type.date;
    +  60            cfg.axes.primary.x.title.visible = false;
    +  61            cfg.axes.primary.x.scale.domain = ['auto', 'tight']; // always up to today
    +  62            cfg.axes.primary.y.scale.type = Axes.type.log;
    +  63            cfg.axes.primary.y.scale.domain = ['tight', 'tight']; // always up to today
    +  64            cfg.axes.primary.y.title.visible = false;
    +  65            cfg.axes.primary.y.ticks.minor.labels.visible = true;
    +  66            cfg.grid.minor.hor.visible = true;
    +  67            cfg.series.data   = [dataQuotes, shares, dataIntra];
    +  68            cfg.series.defaultStyle.line.width = 1;
    +  69            cfg.series.series = [
    +  70                { x:'Date', y:'High', yBase:'Low', type: 'area', dataIndex:timeWindows[limitDateIndex]==='1d'?2:0},
    +  71                { x:'Date', y:'Close', type: 'line' },
    +  72                { x:'Date', y:'price', l:'change', type: 'marker', dataIndex:1, cond:buyCond },
    +  73                { x:'Date', y:'price', l:'change', type: 'marker', dataIndex:1, cond:sellCond }
    +  74            ];
    +  75            cfg.series.series[0].style.fill.color = '#ccf';
    +  76            cfg.series.series[1].style.line.color = '#008';
    +  77            cfg.series.series[2].style.line.visible = false;
    +  78            cfg.series.series[2].style.marker.shape = Series.marker.upTriangle;
    +  79            cfg.series.series[2].style.marker.color = '#0c0';
    +  80            cfg.series.series[2].style.label.color = '#0c0';
    +  81            cfg.series.series[2].style.marker.size = 8;
    +  82            cfg.series.series[2].vOffset = 5;   // em
    +  83            cfg.series.series[3].style.line.visible = false;
    +  84            cfg.series.series[3].style.marker.shape = Series.marker.downTriangle;
    +  85            cfg.series.series[3].style.marker.color = '#a00';
    +  86            cfg.series.series[3].style.label.color = '#a00';
    +  87            cfg.series.series[3].style.marker.size = 8;
    +  88            cfg.series.series[3].vOffset = 5;   // em 
    +  89        }})),
    +  90        m(ToggleButton, { 
    +  91            style: 'left:100px; width:35px;',
    +  92            desc: {
    +  93                items:timeWindows, 
    +  94                selectedItem: timeWindows[limitDateIndex],
    +  95                changed: (item:string) => {
    +  96                    const i = (timeWindows.indexOf(item) + 1) % timeWindows.length;
    +  97                    limitDateIndex = i;
    +  98                }
    +  99            }
    + 100        })
    + 101        ];
    + 102    }     
    + 103
    + 104
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/MainMenu.html b/docs/src/hsStock/view/MainMenu.html new file mode 100644 index 0000000..b2eff78 --- /dev/null +++ b/docs/src/hsStock/view/MainMenu.html @@ -0,0 +1,31 @@ + + +

    view/MainMenu.ts

    +
       1import { m, Vnode}  from 'hslayout';
    +   2import { Layout }   from 'hslayout';
    +   3import { Menu }     from 'hswidget';
    +   4
    +   5export class MainMenu extends Layout {
    +   6    getComponents(node: Vnode): Vnode {
    +   7        const r = node.attrs.route;
    +   8        return m(Menu, {desc: { 
    +   9            items: ['View', 'Trade', 'Import'].map((c:any) => c),
    +  10            selectedItem: (r && r.mode)? r.mode : 0,
    +  11            select: (item:string) => m.route.set('/api/:mode/0', {mode:item}) 
    +  12        }});
    +  13    }     
    +  14}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/Modal.html b/docs/src/hsStock/view/Modal.html new file mode 100644 index 0000000..9d6395a --- /dev/null +++ b/docs/src/hsStock/view/Modal.html @@ -0,0 +1,31 @@ + + +

    view/Modal.ts

    +
       1import { m, Vnode}      from 'hslayout';
    +   2
    +   3
    +   4export class Modal {
    +   5    private static modal:Vnode; 
    +   6    public static show() { Modal.modal = m(Modal); }
    +   7    view(node:Vnode) {
    +   8        return m('.hs-modal-frame', !Modal.modal? '': [
    +   9            m('.hs-modal-background', { onclick: () => { Modal.modal=undefined; }}, ''),
    +  10            m('.hs-modal-foreground', 'the form')
    +  11        ]);
    +  12    }
    +  13}
    +  14
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/SiteMenu.html b/docs/src/hsStock/view/SiteMenu.html new file mode 100644 index 0000000..6027c2b --- /dev/null +++ b/docs/src/hsStock/view/SiteMenu.html @@ -0,0 +1,31 @@ + + +

    view/SiteMenu.ts

    +
       1import { m, Vnode}  from 'hslayout';
    +   2import { Layout }   from 'hslayout';
    +   3import { Menu }     from 'hswidget';
    +   4
    +   5export class SiteMenu extends Layout {
    +   6    getComponents(node: Vnode): Vnode {
    +   7        const r = node.attrs.route;
    +   8        return m(Menu, {desc: { 
    +   9            items: ['View', 'Trade', 'Import'].map((c:any) => c),
    +  10            selectedItem: (r && r.mode)? r.mode : 0,
    +  11            select: (item:string) => m.route.set('/api/:mode/0', {mode:item}) 
    +  12        }});
    +  13    }     
    +  14}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/StockQuotes.html b/docs/src/hsStock/view/StockQuotes.html new file mode 100644 index 0000000..3ddb85f --- /dev/null +++ b/docs/src/hsStock/view/StockQuotes.html @@ -0,0 +1,103 @@ + + +

    view/StockQuotes.ts

    +
       1import { m }  from 'hslayout';
    +   2
    +   3/**
    +   4 * https://iextrading.com/developer/docs/
    +   5 */

    +   6const iexTrading = {
    +   7    base: 'https://api.iextrading.com/1.0',
    +   8    symbolsUrl: () => `${iexTrading.base}/ref-data/symbols`,
    +   9    metaUrl:   (sym:string) => `${iexTrading.base}/stock/${encodeURIComponent(sym)}/quote`,
    +  10    quoteUrl:   (sym:string) => `${iexTrading.base}/stock/${encodeURIComponent(sym)}/chart`,
    +  11    
    +  12    normalizeMeta: (data:any) => {
    +  13console.log('receiving stock meta');   
    +  14        const meta = {
    +  15            name:       data.companyName,
    +  16            symbol:     data.symbol,
    +  17            pe:         data.peRatio,
    +  18            week52High: data.week52High,
    +  19            week52Low:  data.week52Low,
    +  20            open:       data.open,
    +  21            close:      data.close,
    +  22            marketCap:  data.marketCap,
    +  23            sector:     data.sector,
    +  24            primaryExchange:  data.primaryExchange,
    +  25            change:     data.change
    +  26        };
    +  27        return meta;
    +  28    },
    +  29
    +  30    normalizeQuotes: (data:any) => {
    +  31console.log('receiving stock quote');   
    +  32        return data;
    +  33    },
    +  34
    +  35    normalizeSymbols: (data:any) => {
    +  36        const result = {list:[], set:{}};
    +  37        data.forEach((entry:any) => { 
    +  38            result.set[`sym${entry.symbol}`] = entry; 
    +  39            result.list.push(entry.symbol);
    +  40        });
    +  41        return result;
    +  42    }
    +  43};
    +  44
    +  45
    +  46export function getQuotes(sym:string):Promise {
    +  47    return m.request({
    +  48        method: 'GET',
    +  49        url: iexTrading.quoteUrl(sym)
    +  50    })
    +  51    .then(iexTrading.normalizeQuotes)
    +  52    .then((r:string) => {
    +  53        console.log(`load result: ${r}`);
    +  54    })
    +  55    .catch((err:any) => {
    +  56        console.log(`error requesting ${this.url}`);
    +  57        console.log(err);
    +  58        console.log(err.stack);
    +  59    });
    +  60}
    +  61
    +  62export function getMeta(sym:string):Promise {
    +  63    return m.request({
    +  64        method: 'GET',
    +  65        url: iexTrading.metaUrl(sym)
    +  66    })
    +  67    .then(iexTrading.normalizeMeta)
    +  68    .catch((err:any) => {
    +  69        console.log(`error requesting ${this.url}`);
    +  70        console.log(err);
    +  71        console.log(err.stack);
    +  72    });
    +  73}
    +  74
    +  75export function getSymbols():Promise {
    +  76    return m.request({
    +  77        method: 'GET',
    +  78        url: iexTrading.symbolsUrl()
    +  79    })
    +  80    .then(iexTrading.normalizeSymbols)
    +  81    .catch((err:any) => {
    +  82        console.log(`error requesting ${this.url}`);
    +  83        console.log(err);
    +  84        console.log(err.stack);
    +  85    });
    +  86}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/Trade.html b/docs/src/hsStock/view/Trade.html new file mode 100644 index 0000000..488856c --- /dev/null +++ b/docs/src/hsStock/view/Trade.html @@ -0,0 +1,24 @@ + + +

    view/Trade.ts

    +
       1import { m }            from 'hslayout';
    +   2import { EquityList }   from './Equity';
    +   3
    +   4export function tabTrade(list:EquityList, symbol:string) {
    +   5    return m('.hs-left-nav', 'Trade...');
    +   6}
    +   7
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/TradePane.html b/docs/src/hsStock/view/TradePane.html new file mode 100644 index 0000000..c1f9584 --- /dev/null +++ b/docs/src/hsStock/view/TradePane.html @@ -0,0 +1,128 @@ + + +

    view/TradePane.ts

    +
       1import { m, Vnode }     from 'hslayout';
    +   2import { Layout }       from 'hslayout';
    +   3import { Data }         from 'hsdata';
    +   4import { Graph,
    +   5         SeriesDef,
    +   6         Axes }         from 'hsgraph';
    +   7import { gEquities,
    +   8         Category,
    +   9         EquityItem }   from '../controller/Equities';
    +  10import { Transaction }  from '../controller/Assets';
    +  11
    +  12
    +  13export const TradePane = {
    +  14    view: (node: Vnode): Vnode => {
    +  15        return m(Layout, {
    +  16            columns: [],
    +  17            css: '.hs-trade-pane',
    +  18            content: [m(EquityShare)]
    +  19        });
    +  20    }    
    +  21};
    +  22/*
    +  23function getInvestments2():[Data, Data] {
    +  24    let investment = new Data({ colNames: ['Date', 'Total'], rows: [], name:'Investments'});
    +  25    let categories = new Data({ colNames: ['Date', 'Total'], rows: [], name:'Categories' });
    +  26
    +  27    // create columns
    +  28    gEquities.getCategories().map((cat:Category)=>{
    +  29        categories.colAdd(cat.cat);
    +  30        cat.equities.map((item:EquityItem) => investment.colAdd(item.symbol) );
    +  31    });
    +  32
    +  33    
    +  34    investment.sort('ascending', 'Date');
    +  35    categories.sort('ascending', 'Date');
    +  36    return [investment, categories];
    +  37}
    +  38*/

    +  39function getInvestments():[Data, Data] {
    +  40    let investment = new Data({ colNames: ['Date', 'Total'], rows: [], name:'Investments'});
    +  41    let categories = new Data({ colNames: ['Date', 'Total'], rows: [], name:'Categories' });
    +  42
    +  43    // create columns
    +  44    gEquities.getCategories().map((cat:Category)=>{
    +  45        categories.colAdd(cat.cat);
    +  46        cat.equities.map((item:EquityItem) => investment.colAdd(item.symbol) );
    +  47    });
    +  48
    +  49    // fill columns
    +  50    const dateCol = investment.colNumber('Date');
    +  51    const totalCol = investment.colNumber('Total');
    +  52    const investRows = investment.export().rows;
    +  53    const categRows  = categories.export().rows;
    +  54    gEquities.getCategories().map((cat:Category)=>{
    +  55        const catCol = categories.colNumber(cat.cat);
    +  56        cat.equities.map((item:EquityItem) => {
    +  57            const symCol = investment.colNumber(item.symbol);
    +  58            if (item.trades) {
    +  59                item.trades.map((trade:Transaction) => {
    +  60                    const invRow:any[] = investment.export().colNames.map(()=>undefined);
    +  61                    const catRow:any[] = categories.export().colNames.map(()=>undefined);
    +  62                    const value = trade.total * trade.price;
    +  63                    invRow[dateCol]  = trade.Date;
    +  64                    catRow[dateCol]  = trade.Date;
    +  65                    invRow[symCol]   = value;
    +  66                    catRow[catCol]   = value;
    +  67                    invRow[totalCol] = value;
    +  68                    catRow[totalCol] = value;
    +  69                    investRows.push(invRow);
    +  70                    categRows.push(catRow);
    +  71                });
    +  72            }
    +  73        });
    +  74    });
    +  75    investment.sort('ascending', 'Date');
    +  76    categories.sort('ascending', 'Date');
    +  77    return [investment, categories];
    +  78}
    +  79
    +  80
    +  81class EquityShare extends Layout {
    +  82    getComponents(node: Vnode): Vnode { 
    +  83        const impute = (val:number, c:number, i:number, rows:any[][]) =>
    +  84            (val !== null && val !== undefined)? val : ((i>0)? rows[i-1][c] : 0);
    +  85
    +  86        let [investment, categories] = getInvestments();
    +  87        const show = ['cats', 'stocks'][0];
    +  88        let dataSet = show==='cats'? categories : investment;
    +  89
    +  90        const names = dataSet.colNames();
    +  91        names.shift(); // remove Date
    +  92        dataSet = dataSet.map(names, impute); // all cols except Date
    +  93        names.shift(); // remove Total
    +  94
    +  95        return [m('.hs-layout-fill', { onmousemove:console.log}, m(Graph, { cfgFn: (cfg:any) => {
    +  96            cfg.series.data   = [dataSet];
    +  97            cfg.series.series = names.map((n:string, i:number):SeriesDef => {
    +  98                return { x:'Date', y:n, map:'shared', type: 'area'};
    +  99            });
    + 100            cfg.axes.primary.x.scale.type = Axes.type.date;
    + 101//            cfg.axes.primary.y.scale.type = Axes.type.percent;
    + 102            cfg.axes.primary.x.title.visible = false;
    + 103            cfg.axes.primary.x.scale.domain = ['tight', 'tight']; // always up to today
    + 104            cfg.axes.primary.y.scale.domain = [0, 1]; // always up to today
    + 105//            .concat([
    + 106//                { x:'Date', y:'Total', type: 'line' }
    + 107//            ]);
    + 108        }}))];
    + 109    }
    + 110}
    + 111
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/Trader.html b/docs/src/hsStock/view/Trader.html new file mode 100644 index 0000000..e9e5e51 --- /dev/null +++ b/docs/src/hsStock/view/Trader.html @@ -0,0 +1,110 @@ + + +

    view/Trader.ts

    +
       1import { m }                from 'hslayout';
    +   2import { TraderReferences }    from './Trader';
    +   3import { IexTrading }       from './TraderIEX';
    +   4import { EquityItem }       from './Equity';
    +   5
    +   6
    +   7
    +   8export interface TraderQuote {
    +   9    close:          number;
    +  10    date:           string;
    +  11    high:           number;
    +  12    low:            number;
    +  13    open:           number;
    +  14    volume:         number;
    +  15}
    +  16
    +  17export interface TraderProfile {
    +  18    base: string;
    +  19    symbolsUrl:                 () => string;
    +  20    statsUrl:         (sym:string) => string;
    +  21    metaUrl:          (sym:string) => string;
    +  22    quoteUrl:         (sym:string) => string;
    +  23    normalizeStats:     (data:any) => EquityItem;
    +  24    normalizeMeta:      (data:any) => EquityItem;
    +  25    normalizeQuotes:  (data:any[]) => TraderQuote[];
    +  26    normalizeSymbols: (data:any[]) => TraderReferences;
    +  27}
    +  28
    +  29export interface TraderSymbol {
    +  30    symbol: string;
    +  31    name:   string;
    +  32    
    +  33}
    +  34
    +  35export interface TraderReferences {
    +  36    symbols:    string[];
    +  37    names:      string[];
    +  38    equities:   {string:TraderSymbol};
    +  39}
    +  40
    +  41export class Trader {
    +  42    private trader: TraderProfile;
    +  43    constructor(trader='iexTrading') { 
    +  44        switch (trader) {
    +  45            case 'iexTrading':
    +  46            default: this.trader = new IexTrading(); 
    +  47        }
    +  48    }
    +  49
    +  50    getQuotes(item:EquityItem, date:string):Promise {
    +  51        const url = this.trader.quoteUrl(item.symbol)+'/'+ date;
    +  52        return m.request({ method: 'GET', url: url })
    +  53        .then(this.trader.normalizeQuotes)
    +  54        .catch((err:any) => {
    +  55            console.log(`error requesting ${url}`);
    +  56            console.log(err);
    +  57            console.log(err.stack);
    +  58        });
    +  59    }
    +  60
    +  61    getMeta(sym:string):Promise {
    +  62        let item:EquityItem;
    +  63        return m.request({ method: 'GET', url: this.trader.statsUrl(sym) })
    +  64        .then(this.trader.normalizeStats)
    +  65        .then((meta:EquityItem) => item = meta)
    +  66        .catch((err:any) => {
    +  67            console.log(`error requesting ${this.trader.metaUrl(sym)}`);
    +  68            console.log(err);
    +  69            console.log(err.stack);
    +  70        })
    +  71        .then(() => m.request({ method: 'GET', url: this.trader.metaUrl(sym) }))
    +  72        .then(this.trader.normalizeMeta)
    +  73        .then((meta:EquityItem) => item.company = meta.company)
    +  74        .catch((err:any) => {
    +  75            console.log(`error requesting ${this.trader.metaUrl(sym)}`);
    +  76            console.log(err);
    +  77            console.log(err.stack);
    +  78        })
    +  79        .then(() => item);
    +  80    }
    +  81
    +  82    getSymbols():Promise {
    +  83        const url = this.trader.symbolsUrl();
    +  84        return m.request({ method: 'GET', url: url })
    +  85        .then(this.trader.normalizeSymbols)
    +  86        .catch((err:any) => {
    +  87            console.log(`error requesting ${url}`);
    +  88            console.log(err);
    +  89            console.log(err.stack);
    +  90        });
    +  91    }
    +  92}
    +  93
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/TraderIEX.html b/docs/src/hsStock/view/TraderIEX.html new file mode 100644 index 0000000..4ca17e2 --- /dev/null +++ b/docs/src/hsStock/view/TraderIEX.html @@ -0,0 +1,281 @@ + + +

    view/TraderIEX.ts

    +
       1import { TraderQuote,
    +   2         TraderReferences,
    +   3         TraderSymbol,
    +   4         TraderProfile } from './Trader';
    +   5import { EquityItem }    from './Equity';
    +   6
    +   7interface IEXSymbols extends TraderSymbol {
    +   8    date:       string;
    +   9    isEnabled:  boolean;
    +  10    type:       string;     // refers to the common issue type of the stock. 
    +  11                            //  ad â€“ American Depository Receipt (ADR’s) 
    +  12                            //  re â€“ Real Estate Investment Trust (REIT’s) 
    +  13                            //  ce â€“ Closed end fund (Stock and Bond Fund) 
    +  14                            //  si â€“ Secondary Issue 
    +  15                            //  lp â€“ Limited Partnerships 
    +  16                            //  cs â€“ Common Stock 
    +  17                            //  et â€“ Exchange Traded Fund (ETF) 
    +  18                            //  (blank) = Not Available, i.e., Warrant, Note, or (non-filing) Closed Ended Funds
    +  19    iexId:      string;
    +  20}
    +  21
    +  22interface IEXMeta extends EquityItem {
    +  23    beta:               number; // 
    +  24    week52change:       number; // 
    +  25    shortInterest:      number; // 
    +  26    shortDate:          string; // 
    +  27    dividendRate:       number; // 
    +  28    dividendYield:      number; // 
    +  29    exDividendDate:     string; // 
    +  30    latestEPS:          number; // (Most recent quarter)
    +  31    latestEPSDate:      string; // 
    +  32    sharesOutstanding:  number; // 
    +  33    float:              number; // 
    +  34    returnOnEquity:     number; // (Trailing twelve months)
    +  35    consensusEPS:       number; // (Most recent quarter)
    +  36    numberOfEstimates:  number; // (Most recent quarter)
    +  37    EBITDA:             number; // (Trailing twelve months)
    +  38    revenue:            number; // (Trailing twelve months)
    +  39    grossProfit:        number; // (Trailing twelve months)
    +  40    cash:               number; // reers to total cash. (Trailing twelve months)
    +  41    debt:               number; // refers to total debt. (Trailing twelve months)
    +  42    ttmEPS:             number; // (Trailing twelve months)
    +  43    revenuePerShare:    number; // (Trailing twelve months)
    +  44    revenuePerEmployee: number; // (Trailing twelve months)
    +  45    peRatioHigh:        number; // 
    +  46    peRatioLow:         number; // 
    +  47    EPSSurpriseDollar:  number; // refers to the difference between actual EPS and consensus EPS in dollars.
    +  48    EPSSurprisePercent: number; // refers to the percent difference between actual EPS and consensus EPS.
    +  49    returnOnAssets:     number; // (Trailing twelve months)
    +  50    returnOnCapital:    number; // (Trailing twelve months)
    +  51    profitMargin:       number; // 
    +  52    priceToSales:       number; // 
    +  53    priceToBook:        number; // 
    +  54    day200MovingAvg:    number; // 
    +  55    day50MovingAvg:     number; // 
    +  56    institutionPercent: number; // represents top 15 institutions
    +  57    insiderPercent:     number; // 
    +  58    shortRatio:         number; // 
    +  59    year5ChangePercent: number; // 
    +  60    year2ChangePercent: number; // 
    +  61    year1ChangePercent: number; // 
    +  62    ytdChangePercent:   number; // 
    +  63    month6ChangePercent: number; // 
    +  64    month3ChangePercent: number; // 
    +  65    month1ChangePercent: number; // 
    +  66    day5ChangePercent:  number; // 
    +  67}
    +  68
    +  69
    +  70interface IEXQuote extends TraderQuote {
    +  71    change:         number;
    +  72    changeOverTime: number;
    +  73    changePercent:  number;
    +  74    label:          string; // "Oct 16"
    +  75    unadjustedVolume: number;
    +  76    vwap:           number;
    +  77}
    +  78
    +  79
    +  80/**
    +  81 * https://iextrading.com/developer/docs/
    +  82 */

    +  83export class IexTrading implements TraderProfile {
    +  84    base = 'https://api.iextrading.com/1.0';
    +  85    symbolsUrl    = ()           => `${this.base}/ref-data/symbols`;
    +  86    statsUrl      = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/stats`;
    +  87    metaUrl       = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/quote`;
    +  88    quoteUrl      = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/chart`;
    +  89    financialsUrl = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/financials`;
    +  90    earningsUrl   = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/earnings`;
    +  91    dividendsUrl  = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/dividends/5y`;
    +  92    splitsUrl     = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/splits/5y`;
    +  93    logoUrl       = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/logo`;
    +  94    
    +  95    normalizeStats:(data:any) => EquityItem = (data:any) => {
    +  96console.log(`receiving stock '${data.symbol}' stats`);   
    +  97        const meta:EquityItem = {
    +  98            name:           data.companyName,
    +  99            symbol:         data.symbol,
    + 100            cat:            'Stocks',
    + 101            company: {
    + 102            },
    + 103            stats: {
    + 104                week52high:     data.week52high,
    + 105                week52low:      data.week52low,
    + 106                latestEPS:      data.latestEPS,
    + 107                latestEPSDate:  data.latestEPSDate,
    + 108                marketCap:      data.marketcap,
    + 109                exDividendDate: data.exDividendDate,
    + 110                dividendRate:   data.dividendRate,
    + 111                dividendYield:  data.dividendYield
    + 112            },
    + 113            otherStats:     {}
    + 114        };
    + 115        Object.keys(data).forEach((k:string) => meta.otherStats[k] = data[k]);
    + 116        return meta;
    + 117    }
    + 118
    + 119    normalizeMeta:(data:any) => EquityItem = (data:any) => {
    + 120console.log(`receiving stock '${data.symbol}' meta`);   
    + 121        const meta = {
    + 122            name:       data.companyName,
    + 123            symbol:     data.symbol,
    + 124            cat:        'Stocks',
    + 125            company: {
    + 126                sector:             data.sector,
    + 127                primaryExchange:    data.primaryExchange
    + 128            },
    + 129            stats: {},
    + 130            otherStats:     {}
    + 131        };
    + 132        Object.keys(data).forEach((k:string) => meta.otherStats[k] = data[k]);
    + 133        return meta;
    + 134    }
    + 135
    + 136    normalizeQuotes:(data:any[]) => TraderQuote[] = (data:any[]) => {
    + 137        data.sort((a:TraderQuote, b:TraderQuote) => Date.parse(a.date) - Date.parse(b.date));
    + 138console.log(`receiving stock quote for`);   
    + 139        return data;
    + 140    }
    + 141
    + 142    normalizeSymbols:(data:any[]) => TraderReferences = (data:any[]) => {
    + 143        const result:TraderReferences = {symbols:[], names:[], equities:<{string:TraderSymbol}>{}};
    + 144        data.forEach((entry:any) => { 
    + 145            result.equities[`sym${entry.symbol}`] = entry; 
    + 146            result.symbols.push(entry.symbol);
    + 147            result.names.push(entry.name);
    + 148        });
    + 149        return result;
    + 150    }
    + 151};
    + 152
    + 153
    + 154interface IEXStat {
    + 155    companyName:            string;
    + 156    marketcap:              number; // is not calculated in real time.
    + 157    beta:                   number;
    + 158    week52high:             number;
    + 159    week52low:              number;
    + 160    week52change:           number;
    + 161    shortInterest:          number;
    + 162    shortDate:              string;
    + 163    dividendRate:           number;
    + 164    dividendYield:          number;
    + 165    exDividendDate:         string;
    + 166    latestEPS:              number; // (Most recent quarter)
    + 167    latestEPSDate:          string;
    + 168    sharesOutstanding:      number;
    + 169    float:                  number;
    + 170    returnOnEquity:         number; // (Trailing twelve months)
    + 171    consensusEPS:           number; // (Most recent quarter)
    + 172    numberOfEstimates:      number; // (Most recent quarter)
    + 173    symbol:                 string;
    + 174    EBITDA:                 number; // (Trailing twelve months)
    + 175    revenue:                number; // (Trailing twelve months)
    + 176    grossProfit:            number; // (Trailing twelve months)
    + 177    cash:                   number; // refers to total cash. (Trailing twelve months)
    + 178    debt:                   number; // refers to total debt. (Trailing twelve months)
    + 179    ttmEPS:                 number; // (Trailing twelve months)
    + 180    revenuePerShare:        number; // (Trailing twelve months)
    + 181    revenuePerEmployee:     number; // (Trailing twelve months)
    + 182    peRatioHigh:            number;
    + 183    peRatioLow:             number;
    + 184    EPSSurpriseDollar:      number; // refers to the difference between actual EPS and consensus EPS in dollars.
    + 185    EPSSurprisePercent:     number; // refers to the percent difference between actual EPS and consensus EPS.
    + 186    returnOnAssets:         number; // (Trailing twelve months)
    + 187    returnOnCapital:        number; // (Trailing twelve months)
    + 188    profitMargin:           number;
    + 189    priceToSales:           number;
    + 190    priceToBook:            number;
    + 191    day200MovingAvg:        number;
    + 192    day50MovingAvg:         number;
    + 193    institutionPercent:     number; // represents top 15 institutions
    + 194    insiderPercent:         number;
    + 195    shortRatio:             number;
    + 196    year5ChangePercent:     number;
    + 197    year2ChangePercent:     number;
    + 198    year1ChangePercent:     number;
    + 199    ytdChangePercent:       number;
    + 200    month6ChangePercent:    number;
    + 201    month3ChangePercent:    number;
    + 202    month1ChangePercent:    number;
    + 203    day5ChangePercent:      number;    
    + 204}
    + 205
    + 206interface IEXFinancials {
    + 207    reportDate:             string;
    + 208    grossProfit:            number;
    + 209    costOfRevenue:          number;
    + 210    operatingRevenue:       number;
    + 211    totalRevenue:           number;
    + 212    operatingIncome:        number;
    + 213    netIncome:              number;
    + 214    researchAndDevelopment: number;
    + 215    operatingExpense:       number;
    + 216    currentAssets:          number;
    + 217    totalAssets:            number;
    + 218    totalLiabilities:       number;
    + 219    currentCash:            number;
    + 220    currentDebt:            number;
    + 221    totalCash:              number;
    + 222    totalDebt:              number;
    + 223    shareholderEquity:      number;
    + 224    cashChange:             number;
    + 225    cashFlow:               number;
    + 226    operatingGainsLosses:   string;
    + 227}
    + 228
    + 229interface IEXEarnings {
    + 230    actualEPS:          number;
    + 231    consensusEPS:       number;
    + 232    estimatedEPS:       number;
    + 233    announceTime:       string;
    + 234    numberOfEstimates:  number;
    + 235    EPSSurpriseDollar:  number;
    + 236    EPSReportDate:      string;
    + 237    fiscalPeriod:       string;
    + 238    fiscalEndDate:      string;
    + 239}
    + 240
    + 241interface IEXDividends {
    + 242    exDate:         string; // refers to the dividend ex-date
    + 243    paymentDate:    string; // refers to the payment date
    + 244    recordDate:     string; // refers to the dividend record date
    + 245    declaredDate:   string; // refers to the dividend declaration date
    + 246    amount:         number; // refers to the payment amount
    + 247    type:           string; // refers to the dividend payment type (Dividend income, Interest income, Stock dividend, Short term capital gain, Medium term capital gain, Long term capital gain, Unspecified term capital gain)
    + 248    qualified:      string; // refers to the dividend income type 
    + 249                            // P = Partially qualified income 
    + 250                            // Q = Qualified income 
    + 251                            // N = Unqualified income 
    + 252                            // null = N/A or unknown
    + 253}
    + 254
    + 255interface IEXSplits {
    + 256    exDate:         string; // refers to the split ex-date
    + 257    declaredDate:   string; // refers to the split declaration date
    + 258    recordDate:     string; // refers to the split record date
    + 259    paymentDate:    string; // refers to the split payment date
    + 260    ratio:          number; // refers to the split ratio. The split ratio is an inverse of the number of shares that a holder of the stock would have after the split divided by the number of shares that the holder had before. 
    + 261                            // For example: Split ratio of .5 = 2 for 1 split.
    + 262    toFactor:       string; // To factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    + 263    forFactor:      string; // For factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    + 264}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/View.html b/docs/src/hsStock/view/View.html new file mode 100644 index 0000000..ddfea23 --- /dev/null +++ b/docs/src/hsStock/view/View.html @@ -0,0 +1,87 @@ + + +

    view/View.ts

    +
       1
    +   2import { m, Vnode}      from 'hslayout';
    +   3import { collapsible,
    +   4         AddButton, 
    +   5         RemoveButton }  from 'hswidget';
    +   6import { EquityList,
    +   7         Category,
    +   8         EquityItem }   from './Equity';
    +   9import { Trader }       from './Trader';
    +  10
    +  11export function tabView(list:EquityList, symbol:string) {
    +  12    return m('.hs-left-nav', list? navList(list, symbol) : 'left');
    +  13}
    +  14
    +  15const gRequests = {};
    +  16const trader = new Trader();
    +  17
    +  18/** creates the list if modules (`*.ts` files) */
    +  19function navList(list:EquityList, symbol:string):Vnode[] {    
    +  20    /** process a category, e.g. `Stocks`. */
    +  21
    +  22    const cats = list.getCategories().map((c:Category) => categoryEntry(c,list,symbol));
    +  23    return [m('.hs-left-nav-content', cats)];
    +  24}
    +  25
    +  26/** returns a Vnoide structure representing an investment category. */
    +  27function categoryEntry(c:Category, list:EquityList, symbol:string) {
    +  28    function addItem() {            
    +  29        const num = Math.floor(Math.random()*1000);
    +  30        list.addItem({
    +  31            symbol: 's'+num,
    +  32            cat: c.cat,
    +  33            name: c.cat+num
    +  34        });           
    +  35        m.route.set('/api/:mode/:symbol', {mode:'View', symbol:list.getFirstByCat(c.cat).symbol});
    +  36    }
    +  37
    +  38    /** returns a Vnode for an ivestment item, e.g. "Google" */
    +  39    function equityEntry(item:EquityItem) {
    +  40        function removeItem() { list.removeItem(item); }
    +  41
    +  42        if (!gRequests[item.symbol]) { // once only !
    +  43            gRequests[item.symbol] = true;
    +  44            list.loadMeta(item.symbol)
    +  45            .catch(() => 
    +  46                trader.getMeta(item.symbol)
    +  47                .then((data:any) => { 
    +  48                    list.saveMeta(data, item.symbol);
    +  49                    return data;
    +  50                }))
    +  51            .then((data:EquityItem) => 
    +  52                Object.keys(data).forEach((k:string) => item[k] = data[k]));
    +  53        }
    +  54        const selected = (item.symbol === symbol)? '.hs-left-nav-selected' : '';
    +  55        return m(`.hs-left-nav-entry ${selected}`, [
    +  56            m('a', { href:`/api/View/${item.symbol}`, oncreate: m.route.link, onupdate: m.route.link }, item.name),
    +  57            m(RemoveButton, { remove:removeItem })
    +  58        ]);
    +  59    }
    +  60
    +  61    const selected = (c.cat === list.getItem(symbol).cat)? '.hs-left-nav-selected' : '';
    +  62    return collapsible(`.hs-left-nav-module`, { isExpanded:selected }, [
    +  63        m('.hs-left-nav-module-name ${selected}', [
    +  64            m('a', { href:`/api/View/${list.getFirstByCat(c.cat).symbol}`, oncreate: m.route.link, onupdate: m.route.link }, c.cat),
    +  65            m(AddButton, { add:addItem })
    +  66        ]),
    +  67        c.equities.map(equityEntry)
    +  68    ]);
    +  69}
    +  70
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/ViewLeft.html b/docs/src/hsStock/view/ViewLeft.html new file mode 100644 index 0000000..443339a --- /dev/null +++ b/docs/src/hsStock/view/ViewLeft.html @@ -0,0 +1,149 @@ + + +

    view/ViewLeft.ts

    +
       1import { m, Vnode}      from 'hslayout';
    +   2import { Collapsible,
    +   3         AddButton, 
    +   4         Modal,
    +   5         TypeAhead,
    +   6         RemoveButton }  from 'hswidget';
    +   7import { gEquities,
    +   8         Equities,
    +   9         Category,
    +  10         EquityItem }   from '../controller/Equities';
    +  11import { authenticated } from '../Router';
    +  12import { readAssets,TransactionList }   from '../controller/Assets';
    +  13
    +  14let gAssets:TransactionList;
    +  15let ModalShow = false;
    +  16
    +  17export const ViewLeft = {
    +  18    view: (node: Vnode):Vnode => {
    +  19        const symbol  = m.route.param('symbol');
    +  20        return m('.hs-left-nav', [
    +  21            gEquities? navList(gEquities, symbol) : 'left',
    +  22            ModalShow? m(Modal, { 
    +  23                content: m(AddItemForm, {list:gEquities}),
    +  24                dismiss: () => ModalShow=false
    +  25            }) : undefined
    +  26        ]);
    +  27    }
    +  28};
    +  29
    +  30/** creates the list if modules (`*.ts` files) */
    +  31function navList(list:Equities, symbol:string):Vnode[] {    
    +  32    /** process a category, e.g. `Stocks`. */
    +  33
    +  34    if (authenticated()) { getAssets(list); }
    +  35    
    +  36    const cats = list.getCategories().map((c:Category) => categoryEntry(c,list,symbol));
    +  37    return m('.hs-left-nav-content', cats);
    +  38}
    +  39
    +  40/** returns a Vnoide structure representing an investment category. */
    +  41function categoryEntry(c:Category, list:Equities, symbol:string) {
    +  42    /** returns a Vnode for the category header */
    +  43    function catHeader():Vnode {
    +  44        return m('.hs-left-nav-module-name ${selected}', [
    +  45            m('a', { href:`/site/View/${symbol}`, oncreate:m.route.link, onupdate:m.route.link }, [
    +  46                c.equities.length + ' ',
    +  47                c.cat
    +  48            ]),
    +  49            m(AddButton, { onclick:()=> ModalShow=true })
    +  50        ]);
    +  51    }
    +  52
    +  53    /** returns a Vnode for an ivestment item, e.g. "Google" */
    +  54    function equityEntry(item:EquityItem):Vnode {
    +  55        function removeItem() { 
    +  56            list.removeItem(item); }
    +  57
    +  58        const selected = (item.symbol === symbol)? '.hs-left-nav-selected' : '';
    +  59        const unknown = (item.name !== item.symbol)? '' : '.hs-unkown-equity';
    +  60        return m(`.hs-left-nav-entry ${selected} ${unknown} ${item.shares>0?'.hs-owns-shares':''}`, [
    +  61            m('a', { href:`/site/View/${item.symbol}`, oncreate:m.route.link, onupdate:m.route.link }, [
    +  62                item.shares?item.shares+' ':'', item.name
    +  63            ]),
    +  64            m(RemoveButton, { onclick:removeItem })
    +  65        ]);
    +  66    }
    +  67
    +  68    // open the collapsible if it contains `symbol`. Otherwise leave it unchanged (undefined)
    +  69    const selected = (c.cat === list.getItem(symbol).cat)? '.hs-left-nav-selected' : undefined;
    +  70    return m(Collapsible, {css:`.hs-left-nav-module`, isExpanded:selected, components: [
    +  71        catHeader(),
    +  72        c.equities.map(equityEntry)
    +  73    ]});
    +  74}
    +  75
    +  76function getAssets(list:Equities) {
    +  77    if (!gAssets) {
    +  78        gAssets = {};
    +  79        readAssets()
    +  80        .then((tlist:TransactionList) => {
    +  81            gAssets = tlist;
    +  82            let numSyms = 0;
    +  83            let numTrades = 0;
    +  84            Object.keys(tlist).forEach((sym:string) => {
    +  85                numSyms++;
    +  86                numTrades += tlist[sym].trades.length;
    +  87                let item:EquityItem = list.getItem(sym);
    +  88                if (item.symbol === '????') {
    +  89                    item = list.addItem({ symbol: sym, cat: 'new', name: sym });
    +  90                }
    +  91                item.shares = tlist[sym].latestShares;
    +  92                item.trades = tlist[sym].trades;
    +  93                list.applySplitsToTrades(item);
    +  94            });
    +  95            console.log(`received assets list: ${numTrades} trades for ${numSyms} symbols`);
    +  96        });
    +  97    }
    +  98}
    +  99
    + 100class AddItemForm {
    + 101    list:Equities;
    + 102    symbol = '';
    + 103
    + 104    submit() {
    + 105        this.list.addItem({
    + 106            symbol: this.symbol,
    + 107            cat: 'Stocks',
    + 108            name: this.symbol
    + 109        });           
    + 110//        Modal.dismiss();
    + 111    };
    + 112        
    + 113    view(node:Vnode) {
    + 114//        const form = this;
    + 115        this.list = node.attrs.list;
    + 116        return m(TypeAhead, {list: '', onsubmit:(e:any) => {
    + 117            this.symbol = e.currentTarget.value;
    + 118            this.submit.apply(this);
    + 119        }});
    + 120/*            
    + 121        return m('.hs-form',  m('form', { onsubmit: () => form.submit.apply(this) }, [
    + 122            m('input[type="text"][placeholder="Symbol"][name="symbol"]', {
    + 123                value: form.symbol,
    + 124                onchange: function(e:any) {
    + 125                    form.symbol = e.currentTarget.value;
    + 126                }
    + 127            }),
    + 128            m(Button, {name:'add', onclick:() => form.submit.apply(this)})
    + 129        ]));
    + 130*/
            
    + 131    }
    + 132}
    + + \ No newline at end of file diff --git a/docs/src/hsStock/view/ViewPane.html b/docs/src/hsStock/view/ViewPane.html new file mode 100644 index 0000000..90de297 --- /dev/null +++ b/docs/src/hsStock/view/ViewPane.html @@ -0,0 +1,45 @@ + + +

    view/ViewPane.ts

    +
       1
    +   2import { m, Vnode}      from 'hslayout';
    +   3import { Layout }       from 'hslayout';
    +   4import { MainDetails }  from './MainDetails';
    +   5import { MainGraph }    from './MainGraph';
    +   6import { ViewLeft }     from './ViewLeft';
    +   7
    +   8const LeftNavWidth       = '200px'; 
    +   9const StocksDetailHeight = '110px'; 
    +  10
    +  11export const ViewPane = {
    +  12    view: (node: Vnode): Vnode => {
    +  13        return m(Layout, {
    +  14            columns: [LeftNavWidth, 'fill'],
    +  15            css: '.hs-view-pane',
    +  16            content: [
    +  17                m(ViewLeft), 
    +  18                m(Layout, {
    +  19                    css: '.hs-view-center', 
    +  20                    rows:[StocksDetailHeight,'fill'], 
    +  21                    content:[m(MainDetails), m(MainGraph)]
    +  22                })
    +  23            ]
    +  24        });
    +  25    }    
    +  26};
    +  27
    +  28
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/Checksum.html b/docs/src/hsUtil/Checksum.html new file mode 100644 index 0000000..c9f67c2 --- /dev/null +++ b/docs/src/hsUtil/Checksum.html @@ -0,0 +1,33 @@ + + +

    Checksum.ts

    +
       1/**
    +   2 * Creates a checksum on a string.
    +   3 * Adapted from https://stackoverflow.com/questions/811195/fast-open-source-checksum-for-small-strings
    +   4 */

    +   5
    +   6 /** 
    +   7  * fast implementation for short strings (20-500 chars)
    +   8  */

    +   9 export function shortCheckSum(s:string):string {
    +  10    var chk = 0x12345678;
    +  11    var len = s.length;
    +  12    for (var i = 0; i < len; i++) {
    +  13        chk += (s.charCodeAt(i) * (i + 1));
    +  14    }
    +  15    return (chk & 0xffffffff).toString(16);
    +  16 }
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/Date.html b/docs/src/hsUtil/Date.html new file mode 100644 index 0000000..de7f0c0 --- /dev/null +++ b/docs/src/hsUtil/Date.html @@ -0,0 +1,95 @@ + + +

    Date.ts

    +
       1/**
    +   2# Date formatting support. 
    +   3Formats are specified in a printf-style format string. 
    +   4## Supported Formats
    +   5- `%YY, %YYYY`           : two- or four-digit year, as '73', '1973'
    +   6- `%M, %MM, %MMM, %MMMM` : month of year as '2', '02', 'Feb', 'February'
    +   7- `%D, %DD`              : day of month as '5', '05' (1...31)
    +   8- `%DDD, %DDDD`          : day of week as 'Tue', 'Tuesday'
    +   9- `%h, %hh`              : hour of day as '7', '07 (0...23)
    +  10- `%m, %mm`              : minutes as '6', '06' (0..59)
    +  11- `%ss`                  : seconds as '09' (0...59)
    +  12- `%j, %jj, %jjj`        : milliseconds as '1', '15', '159'
    +  13 */

    +  14
    +  15 /** short and long month names */
    +  16const monthStr = [
    +  17    ['Jan', 'January'], ['Feb', 'February'], ['Mar', 'March'], ['Apr', 'April'], ['May', 'May'], ['Jun', 'June'],
    +  18    ['Jul', 'July'], ['Aug', 'August'], ['Sep', 'September'], ['Oct', 'October'], ['Nov', 'November'], ['Dec', 'December']];
    +  19
    +  20 /** short and long weekday names */
    +  21const dayStr = [
    +  22    ['Sun', 'Sunday'],['Mon', 'Monday'],['Tue', 'Tuesday'],['Wed', 'Wednesday'],['Thu', 'Thursday'],['Fri', 'Friday'],['Sat', 'Saturday']];
    +  23
    +  24/** add leading zeros to an integer until `digits` are reached */
    +  25function formatNumber(number:number, digits:number):string {
    +  26    var r = ''+number;
    +  27    while (r.length < digits) { r = "0" + r; }
    +  28    return r;
    +  29}
    +  30
    +  31
    +  32/**
    +  33 * ## Example:
    +  34 * 

    +  35 * date('%MM/%DD/%YY');           // -> 08/17/16 (using current date)
    +  36 * let d = new Date('7/4/2010');
    +  37 * date('%DDDD, %MM/%DD/%YY', d); // -> Sunday, 07/04/10
    +  38 * 

    +  39 * @param formatString the format string to use.
    +  40 * @param [date=new Date()] the date to format.
    +  41 * @returns a copy of `formatString` where all supported patterns are replaced by the respective values from `date`.
    +  42 */

    +  43export function date(formatString:string, date=new Date()):string {
    +  44    return isNaN( date.getTime() )?
    +  45        'invalid':
    +  46        formatString
    +  47            .replace(/%YYYY/g, ''+date.getFullYear())
    +  48            .replace(/%YY/g,   ''+(date.getFullYear()%100))
    +  49            .replace(/%MMMM/g,  monthStr[date.getMonth()][1])
    +  50            .replace(/%MMM/g,   monthStr[date.getMonth()][0])
    +  51            .replace(/%MM/g,   formatNumber(date.getMonth()+1,2))
    +  52            .replace(/%M/g,   ''+(date.getMonth()+1))
    +  53            .replace(/%DDDD/g,  dayStr[date.getDay()][1])
    +  54            .replace(/%DDD/g,   dayStr[date.getDay()][0])
    +  55            .replace(/%DD/g,   formatNumber(date.getDate(),2))
    +  56            .replace(/%D/g,   ''+date.getDate())
    +  57            .replace(/%hh/g,   formatNumber(date.getHours(),2))
    +  58            .replace(/%h/g,  ''+date.getHours())
    +  59            .replace(/%mm/g,   formatNumber(date.getMinutes(),2))
    +  60            .replace(/%m/g,   ''+date.getMinutes())
    +  61            .replace(/%ss/g,   formatNumber(date.getSeconds(),2))
    +  62            .replace(/%jjj/g,   formatNumber(date.getMilliseconds(),3))
    +  63            .replace(/%jj/g,   formatNumber(date.getMilliseconds()/10,2))
    +  64            .replace(/%j/g, formatNumber(date.getMilliseconds()/100,1));
    +  65}
    +  66
    +  67/** converts minutes, hours, days, weeks ... into milliseconds and back */ 
    +  68export const ms = {
    +  69    fromMinutes:    (min:number) => 1000*60*min,
    +  70    fromHours:      (h:number)   => 1000*60*60*h,
    +  71    fromDays:       (d:number)   => 1000*60*60*24*d,
    +  72    fromWeeks:      (w:number)   => 1000*60*60*24*7*w,
    +  73    toMinutes:      (ms:number)  => ms/(1000*60),
    +  74    toHours:        (ms:number)  => ms/(1000*60*60),
    +  75    toDays:         (ms:number)  => ms/(1000*60*60*24),
    +  76    toWeeks:        (ms:number)  => ms/(1000*60*60*24*7)
    +  77};
    +  78
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/Number.html b/docs/src/hsUtil/Number.html new file mode 100644 index 0000000..090281d --- /dev/null +++ b/docs/src/hsUtil/Number.html @@ -0,0 +1,34 @@ + + +

    Number.ts

    +
       1/**
    +   2 * # Number Formatting Support.
    +   3 * 
    +   4 * 
    +   5 */

    +   6
    +   7/**
    +   8 * rounds a number `n` to the specified `d` decimals and returns a string
    +   9 */

    +  10 export function round(n:number, d:number):string {
    +  11     if (isNaN(n)) { return ''; }
    +  12     if (n === 0) { return '0'; }
    +  13     const exp = Math.round(Math.log10(Math.abs(n)));
    +  14     if (exp > d) { return ''+n; }
    +  15     const base = Math.pow(10, d-exp);
    +  16     return ''+Math.round(n*base)/base;
    +  17 }
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/PacingQueue.html b/docs/src/hsUtil/PacingQueue.html new file mode 100644 index 0000000..3edc7f7 --- /dev/null +++ b/docs/src/hsUtil/PacingQueue.html @@ -0,0 +1,63 @@ + + +

    PacingQueue.ts

    +
       1/**
    +   2 * # PacingQueue
    +   3 * ensures that a functions in a sequence are not executed faster than a preset minimum delay
    +   4 */

    +   5
    +   6 /** */
    +   7export class PacingQueue {
    +   8    delayMS:number;
    +   9    queue = [];
    +  10    baseMS = Date.now();
    +  11    /**
    +  12     * @param delay the minimum number of milliseconds between executions of 
    +  13     * two registered functions; defaults to 100;
    +  14     */

    +  15    constructor(delayMS=100) {
    +  16        this.delayMS = delayMS; 
    +  17        this.next(this.queue); 
    +  18    }
    +  19
    +  20    private nextTimeout() {
    +  21        setTimeout(() => this.next(this.queue), this.delayMS);
    +  22    }
    +  23
    +  24    add(fn: (msSinceAdding:number) => any):Promise {
    +  25        return new Promise((resolve, reject) => {
    +  26            if (this.queue.length === 0) { this.nextTimeout(); }
    +  27            this.queue.push({fn:fn, resolve:resolve, reject:reject, time:Date.now()});
    +  28 });
    +  29    }
    +  30
    +  31    next(q:any[]) {
    +  32        if (q.length > 0) {
    +  33            const entry = q.shift();
    +  34            entry.resolve(
    +  35                entry.fn(Date.now() - entry.time)   // call the registered function with the actual delay 
    +  36                .catch((err:any) => {
    +  37                    console.log(`error calling paced function: ${err}`);
    +  38                    console.log(err.stack);
    +  39                    throw err;
    +  40                })
    +  41            );
    +  42            this.nextTimeout();
    +  43        }
    +  44    }
    +  45}
    +  46
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/TimedPromise.html b/docs/src/hsUtil/TimedPromise.html new file mode 100644 index 0000000..3c7c518 --- /dev/null +++ b/docs/src/hsUtil/TimedPromise.html @@ -0,0 +1,46 @@ + + +

    TimedPromise.ts

    +
       1/**
    +   2 * ## Helpful Script Utility Module
    +   3 * Provides convenience functions that don't depend on specific frameworks or libraries 
    +   4 */

    +   5
    +   6
    +   7/**
    +   8 * @description timeout promise for use in `Promise.race()`.
    +   9 * @param {number} ms the milliseconds to wait before rejecting
    +  10 * @return {Promise} a Promise that rejects after `ms` 
    +  11 */

    +  12export function timeout(ms:number):Promise { 
    +  13    return new Promise((resolve, reject) => { setTimeout(reject, ms); }); 
    +  14}
    +  15
    +  16/**
    +  17 * @description delay promise for use in `Promise.all(param).then(delay(ms)).then(doSomething)`.
    +  18 * `delay` passes the parameter received from the calling promise down to the resolving promise.
    +  19 * @param number ms the milliseconds to wait before resolving
    +  20 * @return a `Promise` that resolves after `ms` 
    +  21 */

    +  22export function delay(ms:number)   { 
    +  23    return (args:T):Promise => {
    +  24        return new Promise((resolve:(args:T)=>void) => { 
    +  25            setTimeout(() => { resolve(args); }, ms); 
    +  26        }); 
    +  27    };
    +  28}
    +  29
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/hsChecksum.html b/docs/src/hsUtil/hsChecksum.html new file mode 100644 index 0000000..ea7adbd --- /dev/null +++ b/docs/src/hsUtil/hsChecksum.html @@ -0,0 +1,33 @@ + + +

    hsChecksum.ts

    +
       1/**
    +   2 * Creates a checksum on a string.
    +   3 * Adapted from https://stackoverflow.com/questions/811195/fast-open-source-checksum-for-small-strings
    +   4 */

    +   5
    +   6 /** 
    +   7  * fast implementation for short strings (20-500 chars)
    +   8  */

    +   9 export function shortCheckSum(s:string):string {
    +  10    var chk = 0x12345678;
    +  11    var len = s.length;
    +  12    for (var i = 0; i < len; i++) {
    +  13        chk += (s.charCodeAt(i) * (i + 1));
    +  14    }
    +  15    return (chk & 0xffffffff).toString(16);
    +  16 }
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/hsTimedPromise.html b/docs/src/hsUtil/hsTimedPromise.html new file mode 100644 index 0000000..5c6f3b0 --- /dev/null +++ b/docs/src/hsUtil/hsTimedPromise.html @@ -0,0 +1,46 @@ + + +

    hsTimedPromise.ts

    +
       1/**
    +   2 * ## Helpful Script Utility Module
    +   3 * Provides convenience functions that don't depend on specific frameworks or libraries 
    +   4 */

    +   5
    +   6
    +   7/**
    +   8 * @description timeout promise for use in `Promise.race()`.
    +   9 * @param {number} ms the milliseconds to wait before rejecting
    +  10 * @return {Promise} a Promise that rejects after `ms` 
    +  11 */

    +  12export function timeout(ms:number):Promise { 
    +  13    return new Promise((resolve, reject) => { setTimeout(reject, ms); }); 
    +  14}
    +  15
    +  16/**
    +  17 * @description delay promise for use in `Promise.all(param).then(delay(ms)).then(doSomething)`.
    +  18 * `delay` passes the parameter received from the calling promise down to the resolving promise.
    +  19 * @param number ms the milliseconds to wait before resolving
    +  20 * @return a `Promise` that resolves after `ms` 
    +  21 */

    +  22export function delay(ms:number)   { 
    +  23    return (args:Promise):Promise => {
    +  24        return new Promise((resolve:any) => { 
    +  25            setTimeout(() => { resolve(args); }, ms); 
    +  26        }); 
    +  27    };
    +  28}
    +  29
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/hsUtil.html b/docs/src/hsUtil/hsUtil.html new file mode 100644 index 0000000..cfe3679 --- /dev/null +++ b/docs/src/hsUtil/hsUtil.html @@ -0,0 +1,52 @@ + + +

    hsUtil.ts

    +
       1/**
    +   2 * ## Helpful Script Utility Module
    +   3 * Provides convenience functions that don't depend on specific frameworks or libraries 
    +   4 */

    +   5
    +   6
    +   7/**
    +   8 * @ngdoc function
    +   9 * @name timeout
    +  10 * @methodOf hsNode.hsLibs
    +  11 * @description timeout promise for use in Promise.race().
    +  12 * @param {number} ms the milliseconds to wait before rejecting
    +  13 * @return {Promise} a Promise that rejects after `ms` 
    +  14 */

    +  15export function timeout(ms:number) { 
    +  16    return new Promise((resolve, reject) => { setTimeout(reject, ms); }); 
    +  17}
    +  18
    +  19/**
    +  20 * @ngdoc function
    +  21 * @name delay
    +  22 * @methodOf hsNode.hsLibs
    +  23 * @description delay promise for use in Promise.all(param).then(delay(ms)).then(doSomething).
    +  24 * `delay` passes the paremeter received from the calling promise down to the following promise.
    +  25 * @param number ms the milliseconds to wait before resolving
    +  26 * @return a Promise that resolves after `ms` 
    +  27 */

    +  28export function delay(ms:number)   { 
    +  29    return (args:any) => {
    +  30        return new Promise((resolve:any) => { 
    +  31            setTimeout(() => { resolve(args); }, ms); 
    +  32        }); 
    +  33    };
    +  34}
    +  35
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/index.html b/docs/src/hsUtil/index.html new file mode 100644 index 0000000..1a76aeb --- /dev/null +++ b/docs/src/hsUtil/index.html @@ -0,0 +1,24 @@ + + +

    index.ts

    +
       1export { timeout, delay } from './TimedPromise';
    +   2export { markDown }       from './showdown';
    +   3export { shortCheckSum }  from './Checksum';
    +   4export { date, ms }       from './Date';
    +   5export { round }          from './Number';
    +   6export { PacingQueue }    from './PacingQueue';
    +   7
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/overview.html b/docs/src/hsUtil/overview.html new file mode 100644 index 0000000..804e55f --- /dev/null +++ b/docs/src/hsUtil/overview.html @@ -0,0 +1,30 @@ + + +

    overview.ts

    +
       1/**
    +   2 * # hsUtil
    +   3 * 
    +   4 * Helpful Scripts utility functions that are framework independent. 
    +   5 * 
    +   6 * ## Index
    +   7 * -   {@link TimedPromise TimedPromise} functions that provide delays and timeouts for promises.
    +   8 * -   {@link CheckSum CheckSum} a quick checksum implementation for small strings
    +   9 * -   {@link Date Date} printf-style date formatting function
    +  10 * -   {@link showdown showdown} an ES6 wrapper for the showdown library
    +  11 */

    +  12
    +  13 /** */
    + + \ No newline at end of file diff --git a/docs/src/hsUtil/showdown.html b/docs/src/hsUtil/showdown.html new file mode 100644 index 0000000..41ae29d --- /dev/null +++ b/docs/src/hsUtil/showdown.html @@ -0,0 +1,24 @@ + + +

    showdown.ts

    +
       1const showdown  = require('showdown');
    +   2
    +   3const converter = new showdown.Converter();
    +   4
    +   5export function markDown(text:string) { 
    +   6    return converter.makeHtml(text);
    +   7}
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/AddRemove.html b/docs/src/hsWidget/AddRemove.html new file mode 100644 index 0000000..bed15e5 --- /dev/null +++ b/docs/src/hsWidget/AddRemove.html @@ -0,0 +1,48 @@ + + +

    AddRemove.ts

    +
       1/**
    +   2 * # AddRemove Buttons
    +   3 * Adds `+` and `-` buttons to add or remove items from a list.
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as 
    +   7 * ```
    +   8 *  m('div', [
    +   9 *      m('div', 'main content row'),
    +  10 *      m(AddButton, { onclick: })
    +  11 *  ]),
    +  12 * ```
    +  13 * 
    +  14 * ### Attributes (node.attrs):
    +  15 * - `onclick`: function to call when button is pressed 
    +  16 */

    +  17
    +  18 /** */
    +  19import { m, Vnode}      from 'hslayout';
    +  20
    +  21export class AddButton {
    +  22    view(node:Vnode):Vnode {
    +  23        return m('.hs-add-button', { onclick:node.attrs.onclick }, '');
    +  24    }
    +  25}
    +  26
    +  27export class RemoveButton {
    +  28    view(node:Vnode):Vnode {
    +  29        return m('.hs-remove-button', { onclick:node.attrs.onclick }, '');
    +  30    }
    +  31}
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/Button.html b/docs/src/hsWidget/Button.html new file mode 100644 index 0000000..06b0059 --- /dev/null +++ b/docs/src/hsWidget/Button.html @@ -0,0 +1,74 @@ + + +

    Button.ts

    +
       1/**
    +   2 * # Button Widget
    +   3 * A simple button widget
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as `m(Button, {name:, onclick:});`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - `onclick:() => void` function to execute when button is clicked
    +  10 * - `name: string` name to show as button text
    +  11 * - `css: string` css class to assign to button tag
    +  12 * - `style: string` style string to apply to button tag
    +  13 * 
    +  14 * ### Example
    +  15 * 
    +  16 * 
    +  17 * let clicked = 0;
    +  18 * 
    +  19 * m.mount(root, {view: () => m('.hs-white', [
    +  20 *    m('h4', 'Please click:'),
    +  21 *    m(hswidget.Button, { desc: {
    +  22 *        name: 'click me',
    +  23 *        clicked: () => clicked++
    +  24 *    }}),
    +  25 * ])});
    +  26 * 
    +  27 * 

    +  28 * 
    +  29 */

    +  30
    +  31/** */
    +  32import { Vnode }     from 'hslayout';
    +  33import { ToggleButton } from './ToggleButton';
    +  34
    +  35/**
    +  36 * # Button Widget
    +  37 * A simple button widget
    +  38 * 
    +  39 * ### Profile
    +  40 * invoked as `m(Button, {name:, onclick:});`
    +  41 * 
    +  42 * ### Attributes (node.attrs):
    +  43 * attribtues as defined in {@link ToggleButton.ToggleButton `ToggleButton`}, 
    +  44 * except for `items` and `changed`, which are replaced by 
    +  45 * - `name: string` name to show as button text (in lieu of `items`)
    +  46 * - `clicked:() => void` function to execute when button is clicked
    +  47 */

    +  48export class Button extends ToggleButton {
    +  49    view(node: Vnode) {
    +  50        const desc = node.attrs.desc;
    +  51        desc.items = [desc.name || 'button'];
    +  52        desc.changed = desc.clicked;
    +  53        return super.view(node);
    +  54    }
    +  55}
    +  56
    +  57
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/Collapsible.html b/docs/src/hsWidget/Collapsible.html new file mode 100644 index 0000000..054d912 --- /dev/null +++ b/docs/src/hsWidget/Collapsible.html @@ -0,0 +1,93 @@ + + +

    Collapsible.ts

    +
       1/**
    +   2 * # Collapsible Widget
    +   3 * returns a Vnode that can be toggled to expand and contract by clicking on the first `component`.
    +   4 * 
    +   5 * ### Invocation
    +   6 * invoked as 
    +   7 * ```
    +   8 * m(Collapsible, { css:, isExpanded:true, components:[
    +   9 *     m('div', 'the title'),
    +  10 *     ['body item1', 'body item2', 'body item3']
    +  11 * ]})
    +  12 * ```
    +  13 * 
    +  14 * ### Attributes (node.attrs):
    +  15 * - `css`: optional; the css class to assign to the entire Collapsible div
    +  16 * - `isExpanded`: optional; boolean indicating if the Collapsible is initially expanded
    +  17 * - `components`: array of two components: 
    +  18 *     - `component[0]` is the title of the Collapsible. This will remain visible and can be clicked 
    +  19 *       on to expand or contract the remaining components
    +  20 *     - `component[1]` an array of Vnodes that will be collapsed or expanded.
    +  21 * 
    +  22 * ### Example
    +  23 * 
    +  24 * 
    +  25 * m.mount(root, {view: () => m('.hs-white', [
    +  26 *    m(hswidget.Collapsible, { css:'.myExample', components: [
    +  27 *       m('.myTitle', 'click me to toggle'), [
    +  28 *          m('.myItem', 'body item1'), 
    +  29 *          m('.myItem', 'body item2'), 
    +  30 *          m('.myItem', 'body item3')
    +  31 *       ]
    +  32 *    ]}),
    +  33 *    m('', 'This is a background text that will be pushed down by the Collapsible')
    +  34 * ])});
    +  35 * 
    +  36 * 
    +  37 * div { margin-top: 5px; }
    +  38 * .myTitle {
    +  39 *    display: inline-block;
    +  40 *    border-radius: 0px 4px;
    +  41 *    padding: 1px;
    +  42 *    border-bottom: 1px solid blue;
    +  43 *    width: auto;
    +  44 * }
    +  45 * 
    +  46 * 

    +  47 */

    +  48
    +  49 /** */
    +  50import { m, Vnode } from 'hslayout';
    +  51
    +  52export class Collapsible {
    +  53    expanded = false;
    +  54    toggle() {
    +  55        this.expanded = !this.expanded;
    +  56    }
    +  57    view(node:Vnode) {
    +  58        const css        = node.attrs.css;
    +  59        const components = node.attrs.components;
    +  60        const preArrow   = node.attrs.preArrow;
    +  61        const postArrow  = node.attrs.postArrow;
    +  62        if (node.attrs.isExpanded!==undefined) {
    +  63            this.expanded = node.attrs.isExpanded;
    +  64        }
    +  65        const expCSS = this.expanded?'hs-collapsible-expanded':'';
    +  66        return m(`.hs-collapsible ${css} ${expCSS}`, { onclick:this.toggle.bind(this)}, [
    +  67            m('.hs-collapsible-title',[
    +  68                !preArrow? m('') : m(`.hs-collapsible-pre .hs-collapsible-arrow-${this.expanded?'down' : 'right'}`),
    +  69                components[0],
    +  70                !postArrow? m('') : m(`.hs-collapsible-post .hs-collapsible-arrow-${this.expanded?'down' : 'left'}`),
    +  71            ]),
    +  72            components[1]? m('.hs-collapsible-content', components[1].map((c:any) =>m('',c))) : undefined
    +  73        ]);
    +  74    }
    +  75}
    +  76
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/CornerButton.html b/docs/src/hsWidget/CornerButton.html new file mode 100644 index 0000000..7aac5aa --- /dev/null +++ b/docs/src/hsWidget/CornerButton.html @@ -0,0 +1,120 @@ + + +

    CornerButton.ts

    +
       1/**
    +   2 * # Corner Button
    +   3 * creates a button at the corner of a positioned panel.
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as `m(CornerButton, {  })`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - `onclick: ()=>void` a function that is called when the modal box is dismissed
    +  10 * 
    +  11 * ### Example
    +  12 * 
    +  13 * 
    +  14 * const buttons = {}
    +  15 * m.mount(root, {view: () => m('', Object.keys(hswidget.ButtonSymbols).map(
    +  16 *      (b) => m('.myPositioned', [
    +  17 *          buttons[b]? m('.myClicked', 'Yayy!!') : m('', b),
    +  18 *          m(hswidget.CornerButton, { symbol:hswidget.CornerButton.getSymbol(b), onclick:click(b) })
    +  19 *      ])
    +  20 * ))});
    +  21 * 
    +  22 * function click(button) {
    +  23 *      return () => {
    +  24 *          buttons[button] = true;
    +  25 *          setTimeout(reset(button), 800);
    +  26 *      }
    +  27 * }
    +  28 * 
    +  29 * function reset(button) {
    +  30 *      return () => {
    +  31 *          buttons[button] = false;
    +  32 *          m.redraw();
    +  33 *      }
    +  34 * }
    +  35 * 
    +  36 * 
    +  37 * .myClicked { background-color: #efe; }
    +  38 * .myPositioned { 
    +  39 *      position: relative; 
    +  40 *      display: inline-block;
    +  41 *      box-sizing: border-box;
    +  42 *      background-color: #fff; 
    +  43 *      text-align: center;
    +  44 *      font-size: 70%;
    +  45 *      margin:  2px;
    +  46 *      padding-top: 20px;
    +  47 *      height: 50px;
    +  48 *      width:  50px;
    +  49 * }
    +  50 * .hs-corner-button { color: #008; }
    +  51 * 
    +  52 * 

    +  53 */

    +  54
    +  55 /** */
    +  56import { m, Vnode}  from 'hslayout'; 
    +  57
    +  58export const ButtonSymbols = {
    +  59    cross:      { sym: '×' },
    +  60    minus:      { sym: '−'},
    +  61    plus:       { sym: '+'},
    +  62    dLeft:      { sym: '«'},
    +  63    dRight:     { sym: '»'},
    +  64    left:       { sym: '‹'},
    +  65    right:      { sym: '›'},
    +  66    leftTri:    { sym: '◂'},
    +  67    rightTri:   { sym: '▸'},
    +  68    upTri:      { sym: '▴'},
    +  69    downTri:    { sym: '▾'},
    +  70    up:         { sym: '∧'},
    +  71    down:       { sym: '∨'},
    +  72    lArrow:     { sym: '←'},
    +  73    rArrow:     { sym: '→'},
    +  74    uArrow:     { sym: '↑'},
    +  75    dArrow:     { sym: '↓'},
    +  76    empty:      { sym: '○'},
    +  77    emptySlash: { sym: '∅'},
    +  78    oSlash:     { sym: 'ø'},
    +  79    o:          { sym: 'ο'},
    +  80    lines3:     { sym: '≡'},
    +  81    sum:        { sym: 'Σ'},
    +  82    ellipsis:   { sym: '…'},
    +  83    vertEllips: { sym: '⁝'},
    +  84    bullet:     { sym: '•'},
    +  85    enter:      { sym: '↵'},
    +  86    again:      { sym: '↻'},
    +  87    start:      { sym: '⇱'},
    +  88    end:        { sym: '⇲'}
    +  89};
    +  90
    +  91export class CornerButton {
    +  92    constructor(protected symbol='-') {}
    +  93    static getSymbol(name:string) {
    +  94        return ButtonSymbols[name]? ButtonSymbols[name].sym : '';
    +  95    }
    +  96    view(node:Vnode) {
    +  97        return m('.hs-corner-button', 
    +  98            { onclick: node.attrs.onclick }, 
    +  99            m.trust(node.attrs.symbol));
    + 100    }
    + 101}
    + 102
    + 103
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/DropOver.html b/docs/src/hsWidget/DropOver.html new file mode 100644 index 0000000..8297f6b --- /dev/null +++ b/docs/src/hsWidget/DropOver.html @@ -0,0 +1,87 @@ + + +

    DropOver.ts

    +
       1/**
    +   2 * # DropOver Widget
    +   3 * returns a Vnode that can be toggled to expand on top of existing content.
    +   4 * 
    +   5 * ### Invocation
    +   6 * invoked as 
    +   7 * ```
    +   8 * m(DropOver, { css:, dir:DropOver.right, components:[
    +   9 *     m('div', 'the title'),
    +  10 *     ['body item1', 'body item2', 'body item3']
    +  11 * ]})
    +  12 * ```
    +  13 * 
    +  14 * ### Attributes (node.attrs):
    +  15 * - `css`: the css class to assign to the entire Collapsible div
    +  16 * - `dir`: the direction in which the `DropOver` expands; defaults to DropOver.down
    +  17 * - `components`: array of two components: 
    +  18 *     - `component[0]` is the title of the DropOver. This will remain visible and can be clicked 
    +  19 *       on to expand the remaining components
    +  20 *     - `component[1]` an *array of Vnodes* that will be expanded.
    +  21 * 
    +  22 * ### Example
    +  23 * 
    +  24 * 
    +  25 * const clicked = e => console.log(e);
    +  26 * m.mount(root, {view: () => m(hslayout.Layout, {
    +  27 *     rows:["100%"],
    +  28 *     content:[
    +  29 *         m(hswidget.DropOver, { css:'.myExample', components: [
    +  30 *              m('.myTitle', 'click me to open'),
    +  31 *              [
    +  32 *                  m('.myItem', {onclick: clicked}, 'body item1'), 
    +  33 *                  m('.myItem', {onclick: clicked}, 'body item2'), 
    +  34 *                  m('.myItem', {onclick: clicked}, 'body item3')
    +  35 *              ]
    +  36 *         ]}),
    +  37 *     ]
    +  38 * })});
    +  39 * 
    +  40 * 

    +  41 */

    +  42
    +  43 /** */
    +  44import { m, Vnode } from 'hslayout';
    +  45
    +  46export class DropOver {
    +  47    static left  = 'left';
    +  48    static right = 'right';
    +  49    static up    = 'up';
    +  50    static down  = 'down';
    +  51
    +  52    expanded = false;
    +  53    toggle() {
    +  54        this.expanded = !this.expanded;
    +  55    }
    +  56    view(node:Vnode) {
    +  57        const css        = node.attrs.css;
    +  58        const components = node.attrs.components;
    +  59        if (node.attrs.isExpanded!==undefined) {
    +  60            this.expanded = node.attrs.isExpanded;
    +  61        }
    +  62        return m(`.hs-dropover ${css}`, { onclick:()=>this.expanded = !this.expanded}, [
    +  63            components[0],
    +  64            components[1]? m('.hs-dropover-content', 
    +  65                { class: this.expanded?'hs-dropover-expanded':'' }, 
    +  66                components[1].map((c:any) =>c)) : undefined
    +  67        ]);
    +  68    }
    +  69}
    +  70
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/Menu.html b/docs/src/hsWidget/Menu.html new file mode 100644 index 0000000..83e1db6 --- /dev/null +++ b/docs/src/hsWidget/Menu.html @@ -0,0 +1,83 @@ + + +

    Menu.ts

    +
       1/**
    +   2 * # Menu Widget
    +   3 * Creates a simple menu with several items.
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as `m(Menu, { desc: })`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - `desc:` {@link Menu.MenuDesc MenuDesc}
    +  10 *     - `items: string[]`                  the items on the menu
    +  11 *     - `changed: (item:string) => void`   called when item clicked
    +  12 *     - `defaultItem?: number|string`      the currently selected item, by index or name
    +  13 *     - `itemCSS?: string[]`               css to apply to items;
    +  14 * - `css?: string`                         css class to assign to button group
    +  15 * - `style?: string`                       style string to apply to button tag
    +  16 * - `size?: string | string[]`             sizes to layout menu items; 
    +  17 * 
    +  18 * ### Example
    +  19 * 
    +  20 * 
    +  21 * const items = ['One', 'Two', 'Three'];
    +  22 * const content   = ['1st', '2nd', '3rd'];
    +  23 * let  theContent = content[1];
    +  24 * 
    +  25 * m.mount(root, {view: () => m(hslayout.Layout, {
    +  26 *     rows:["30px", "fill"],
    +  27 *     content:[
    +  28 *         m(hswidget.Menu, {desc: {
    +  29 *             items: items,
    +  30 *             defaultItem: 'Two',
    +  31 *             changed: item => 
    +  32 *                theContent = content[items.indexOf(item)]
    +  33 *         }}),
    +  34 *         m(hslayout.Layout, { css:'myMain', content: theContent })
    +  35 *     ]
    +  36 * })});
    +  37 *
    +  38 * 
    +  39 * 
    +  40 * .myMain { 
    +  41 *    border:1px solid #ddd;
    +  42 *    border-top: 0px solid #ddd;
    +  43 * } 
    +  44 * .hs-selectable { 
    +  45 *     background-color: #f4f4e8; 
    +  46 * }
    +  47 * .hs-selected { 
    +  48 *     background-color: #eed; 
    +  49 *     border-width:0px;
    +  50 * }
    +  51 * 
    +  52 * 

    +  53 */

    +  54
    +  55 /** */
    +  56import { Vnode }        from 'hslayout';
    +  57import { RadioButton }  from './RadioButton';
    +  58
    +  59
    +  60/**
    +  61 * Creates a simple menu with several items, as configured by the desc:SelectorDesc object passed as a parameter. 
    +  62 */

    +  63export class Menu extends RadioButton {
    +  64    view(node: Vnode): Vnode { return this.viewGroup('.hs-menu', node); }
    +  65};
    +  66
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/Menu.spec.html b/docs/src/hsWidget/Menu.spec.html new file mode 100644 index 0000000..0fd7df1 --- /dev/null +++ b/docs/src/hsWidget/Menu.spec.html @@ -0,0 +1,66 @@ + + +

    Menu.spec.ts

    +
       1
    +   2const hslayout = require('hslayout');
    +   3const m = hslayout.m;
    +   4const o = hslayout.o;
    +   5
    +   6const hsMenu = require("../src/Menu");
    +   7const Menu = hsMenu.Menu;
    +   8
    +   9const left  = ['0%', '25%', '50%', '75%'];
    +  10const right = ['75%', '50%', '25%', '0%'];
    +  11const title = ['1a', '2a', '3a', '4a']; 
    +  12
    +  13o.spec('hsMenu', () => {
    +  14    let menu:any;
    +  15    o.before(() => {
    +  16        const md = { 
    +  17            items: title,
    +  18            changed: (item:string) => { console.log('selected'); }
    +  19        };
    +  20        m.mount(o.root, {view: () => m(Menu, { desc: md }) }); 
    +  21        menu = o.root.childNodes[0];
    +  22    });
    +  23
    +  24    o('Menu', () => {
    +  25        o(menu).notEquals(undefined)('creation');
    +  26        o(menu.className.indexOf('hs-menu')).notEquals(-1)("is menu");
    +  27        o(menu.className.indexOf('hs-layout')).notEquals(-1)("is layout");
    +  28    });
    +  29
    +  30    o('Menu Items', () => {
    +  31        const cn = menu.childNodes;
    +  32        o(cn.length).equals(4)("has 4 menu items");
    +  33        cn.forEach((c:any, i:any) => {
    +  34            o(c.className.indexOf('hs-selectable')).notEquals(-1)(`item ${i+1} menu-item class`);
    +  35            o(c.className.indexOf('hs-layout')).notEquals(-1)(`item ${i+1} layout class`);
    +  36            o(c.className.includes('hs-selected')).equals((i===0)?true:false)(`item ${i+1} selected class`);
    +  37            o(c.style.left).equals(left[i])(`item ${i+1} left`);
    +  38            o(c.style.right).equals(right[i])(`item ${i+1} right`);
    +  39            o(c.style.top).equals('0%')(`item ${i+1} top`);
    +  40            o(c.style.bottom).equals('0%')(`item ${i+1} bottom`);
    +  41            o(c.childNodes.length).equals(1)(`item ${i+1} num children`);
    +  42            o(c.childNodes[0].className).equals('hs-leaf')(`item ${i+1} child leaf`);
    +  43            o(c.childNodes[0].childNodes[0].nodeValue).equals(title[i])(`item ${i+1} child leaf text`);
    +  44        });
    +  45    });
    +  46
    +  47});
    +  48
    +  49
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/Modal.html b/docs/src/hsWidget/Modal.html new file mode 100644 index 0000000..6914a81 --- /dev/null +++ b/docs/src/hsWidget/Modal.html @@ -0,0 +1,68 @@ + + +

    Modal.ts

    +
       1/**
    +   2 * # Modal Widget
    +   3 * returns a Vnode that covers the entire window. 
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as `m(Modal, {  })`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - `width?:  string` the `px` or `%` of the window width to use, or 'auto' if omitted.
    +  10 * - `height?: string` the `px` or `%` of the window height to use, or 'auto' if omitted.
    +  11 * - `content: Vnode` the mithril node to show as content of the modal
    +  12 * - `dismiss: ()=>void` a function that is called when the modal box is dismissed
    +  13 * 
    +  14 * ### Example
    +  15 * 
    +  16 * 
    +  17 * let showModal = false;
    +  18 * m.mount(root, {view: () => m('.hs-white', [
    +  19 *      m('h4', {onclick:() => showModal = true }, 'click me'),
    +  20 *      showModal? m(hswidget.Modal, { 
    +  21 *          width:  '300px',
    +  22 *          height: '200px',
    +  23 *          dismiss: () => showModal = false,
    +  24 *          content: m('', 'click border to release') 
    +  25 *      }) : undefined
    +  26 *    ])
    +  27 * });
    +  28 * 
    +  29 * 

    +  30 */

    +  31
    +  32 /** */
    +  33import { m, Vnode}  from 'hslayout'; 
    +  34import { ToolbarButton } from './ToolbarButton';
    +  35
    +  36export class Modal {
    +  37    view(node:Vnode) {
    +  38        const w = node.attrs.width  || 'auto';
    +  39        const h = node.attrs.height || 'auto';
    +  40        const attrs = { style: `width:${w}; height:${h};`};
    +  41        return m('.hs-modal-frame', [
    +  42            m('.hs-modal-background', { onclick: node.attrs.dismiss}, ''),
    +  43            m('.hs-modal-foreground', attrs, !node.attrs.content? 'modal pane' : [
    +  44                node.attrs.content,
    +  45//                m('.hs-modal-close', { onclick: node.attrs.dismiss }, m.trust('×')) 
    +  46                m(ToolbarButton, { onclick: node.attrs.dismiss, symbol:ToolbarButton.getSymbol('cross') }) 
    +  47            ])
    +  48        ]);
    +  49    }
    +  50}
    +  51
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/OneOfButtons.html b/docs/src/hsWidget/OneOfButtons.html new file mode 100644 index 0000000..faf07a2 --- /dev/null +++ b/docs/src/hsWidget/OneOfButtons.html @@ -0,0 +1,39 @@ + + +

    OneOfButtons.ts

    +
       1/**
    +   2 * # OneOfButtons Widget
    +   3 * A set of adjoint buttons, one of which can be active at a time
    +   4 * 
    +   5 * ### Invocation
    +   6 * invoked as `m(OneOfButtons, {names:[], initial:, onclick:})`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - onclick: function to execute when button is clicked
    +  10 * - name: name to show as button text
    +  11 */

    +  12
    +  13/** */
    +  14import { m, Vnode }     from 'hslayout';
    +  15
    +  16
    +  17export class Button {
    +  18    view(node: Vnode) {
    +  19        return m('.hs-button-group', {onclick:node.attrs.onclick},  node.attrs.name || 'button');
    +  20    }
    +  21}
    +  22
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/RadioButton.html b/docs/src/hsWidget/RadioButton.html new file mode 100644 index 0000000..b23b3cd --- /dev/null +++ b/docs/src/hsWidget/RadioButton.html @@ -0,0 +1,89 @@ + + +

    RadioButton.ts

    +
       1/**
    +   2 * # Button Widget
    +   3 * A simple button widget
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as `m(Button, {name:, onclick:});`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - `onclick:() => void` function to execute when button is clicked
    +  10 * - `name: string` name to show as button text
    +  11 * - `css: string` css class to assign to button tag
    +  12 * - `style: string` style string to apply to button tag
    +  13 * 
    +  14 * ### Example
    +  15 * 
    +  16 * 
    +  17 * let clicked = 0;
    +  18 * let radio = '';
    +  19 * let toggle = '';
    +  20 * 
    +  21 * m.mount(root, {view: () => m('.hs-white', [
    +  22 *    m('h4', `Select Radio Station: ${radio}`),
    +  23 *    m(hswidget.RadioButtons, { desc: {
    +  24 *        items: ['1st', '2nd','3rd'],
    +  25 *        changed: (item) => radio = item
    +  26 *    }})
    +  27 * ])});
    +  28 * 
    +  29 * 

    +  30 * 
    +  31 */

    +  32
    +  33/** */
    +  34import { m, Vnode }     from 'hslayout';
    +  35import { Layout }       from 'hslayout';
    +  36import { Selector }     from './Selector';
    +  37import { oneOfItems }   from './Selector';
    +  38import { SelectorDesc } from './Selector';
    +  39
    +  40/**
    +  41 * # Radio Button Widget
    +  42 * A group of buttons with one or none selected
    +  43 * 
    +  44 * ### Profile
    +  45 * invoked as `m(RadioButton, {desc: { items:[], changed:}});`
    +  46 * 
    +  47 * ### Attributes (node.attrs):
    +  48 * - `desc:` see {@link Selector.SelectorDesc SelectorDesc}
    +  49 *     - `changed:(item:string) => void`    function to execute when button is selected
    +  50 *     - `selectedItem?: number|string`     the currently selected item, by index or name
    +  51 *     - `items: string[]`                  names to individual buttons to show
    +  52 *     - `itemCss?:string[]`                css to apply to each item;
    +  53 * - `css?: string`                         css class to assign to button group
    +  54 * - `style?: string`                       style string to apply to button tag
    +  55 * - `size?: string | string[]`             sizes to layout menu items; 
    +  56 */

    +  57export class RadioButton extends Selector {
    +  58    viewGroup(css:string, node: Vnode) {
    +  59        const desc:SelectorDesc = this.init(node.attrs.desc, oneOfItems);
    +  60        node.attrs.desc = undefined;
    +  61        css = `${css} ${node.attrs.css || ''}`;
    +  62        const style = node.attrs.style || '';
    +  63
    +  64        return m(css, {style:style}, m(Layout, {
    +  65            columns: [],
    +  66            content: desc.items.map((l:string, i:number) => this.renderItem(desc, i))
    +  67        }));
    +  68    }
    +  69    view(node: Vnode): Vnode { return this.viewGroup('.hs-radio-buttons', node); }
    +  70}
    +  71
    +  72
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/Selector.html b/docs/src/hsWidget/Selector.html new file mode 100644 index 0000000..e0dd91d --- /dev/null +++ b/docs/src/hsWidget/Selector.html @@ -0,0 +1,177 @@ + + +

    Selector.ts

    +
       1/**
    +   2 * # Abstract Selector
    +   3 * Creates a Selector with several Selectables.
    +   4 * The `updateSelected` property determines how selecting an item affects 
    +   5 * the `isSelected` status of all other items. Preconfigured options are
    +   6 * -  {@link Selector.oneOfItems oneOfItems}
    +   7 * -  {@link Selector.anyItems   anyItems}
    +   8 * 
    +   9 * 
    +  10 * ### Invocation
    +  11 * implementation dependant
    +  12 * 
    +  13 * ### Attributes (node.attrs):
    +  14 * - desc: {@link Selector.SelectorDesc SelectorDesc}
    +  15 *     - items: string[];                // the items on the selector
    +  16 *     - defaultItem?: number|string;    // the initial selected item, by index or name
    +  17 *     - changed: (item:string) => void; // called when selection changed
    +  18 *     - itemCss?:string[];              // css to apply to items;
    +  19 */

    +  20
    +  21 /** */
    +  22import { m } from 'hslayout';
    +  23
    +  24/** passed into Menu from the calling application */
    +  25export interface SelectorDesc {
    +  26    /** the items on the menu */
    +  27    items: string[];
    +  28    /** optional array of css styles; each will be applied to the respective item  */
    +  29    itemCss?: string[];
    +  30    /** the initial selected item */
    +  31    defaultItem?: string|number;
    +  32    /** the function to call when the selection changes */
    +  33    changed: (item:string) => void;
    +  34    /** the function to call if this item receives a mouseDown event */
    +  35    mouseDown?: (item:string) => void;
    +  36    /** the function to call if this item receives a mouseUp event */
    +  37    mouseUp?: (item:string) => void;
    +  38}
    +  39
    +  40/** interface of the parameter passed to a `Selectable` */
    +  41export interface SelectableDesc {
    +  42    /** the item's title */
    +  43    title: string;
    +  44    /** the item's select status */
    +  45    isSelected: boolean;
    +  46    /** optional css class to use */
    +  47    css?: string;
    +  48    /** optional style string to apply */
    +  49    style?: string;
    +  50    /** the function to call if this item is clicked */
    +  51    clicked?: (item:string) => void;
    +  52    /** the function to call if this item receives a mouseDown event */
    +  53    mouseDown?: (item:string) => void;
    +  54    /** the function to call if this item receives a mouseUp event */
    +  55    mouseUp?: (item:string) => void;
    +  56}
    +  57
    +  58export type selectFn = (items:{string:SelectableDesc}, title:string) => void;
    +  59
    +  60/** 
    +  61 * called to update selection after the item with title `title` was selected.
    +  62 * `oneOfItems` ensures that `title` will be selected and all others deselected
    +  63 */

    +  64export function oneOfItems(items:{string:SelectableDesc}, title:string) {
    +  65    Object.keys(this.items).forEach((key:string) => { 
    +  66        this.items[key].isSelected = (key===title); 
    +  67    });
    +  68}
    +  69
    +  70/** 
    +  71 * called to update selection after the item with title `title` was selected.
    +  72 * `anyItems` ensures that `title` will be selected independant of all others
    +  73 */

    +  74export function anyItems(items:{string:SelectableDesc}, title:string) {
    +  75    this.items[title].isSelected = !this.items[title].isSelected; 
    +  76}
    +  77
    +  78
    +  79/**
    +  80 * Creates a simple menu with several items, as configured by the desc:SelectorDesc object passed as a parameter. 
    +  81 */

    +  82export abstract class Selector {
    +  83    /** 
    +  84     * determines which function to use to updatye selections after events.
    +  85     * Pre-configured function include:
    +  86     * - oneOfItems: default; only one item of the set can be selected at a time
    +  87     * - anyItem: each item can individually be selected. Pressing an item again will deselect it.
    +  88     */

    +  89    private updateSelected:selectFn = [oneOfItems, anyItems][0];
    +  90
    +  91    protected selectedItem: string; 
    +  92
    +  93    /** instance variable, keeping a list of menu items and a `select` function for tracking which item is selected. */
    +  94    private items = <{string:SelectableDesc}>{};
    +  95
    +  96    init(desc:SelectorDesc, updateSelected:selectFn = oneOfItems):SelectorDesc {
    +  97        this.updateSelected = updateSelected.bind(this);
    +  98        desc.items = desc.items || [];
    +  99        desc.changed = desc.changed || ((item:string) => console.log(`missing changed() function for menu item ${item}`));
    + 100        this.checkSelectedItem(desc);
    + 101        return desc;
    + 102    };
    + 103
    + 104    /** ensures that `selectedItem` is defined and is a string */
    + 105    checkSelectedItem(desc:SelectorDesc) {
    + 106        if (this.selectedItem === undefined) {
    + 107            if (typeof desc.defaultItem === 'number') { 
    + 108                this.selectedItem = desc.items[desc.defaultItem % desc.items.length];
    + 109            } else {
    + 110                this.selectedItem = desc.defaultItem || desc.items[0];
    + 111            }
    + 112        }
    + 113    }
    + 114
    + 115    internalStateUpdate(desc:SelectorDesc, item:string) {
    + 116        this.selectedItem = item;
    + 117        this.checkSelectedItem(desc);
    + 118        this.updateSelected(this.items, this.selectedItem); // local housekeeping: make sure the item's style shows correct selection
    + 119    }
    + 120
    + 121    renderItem(desc:SelectorDesc, i:number) {
    + 122        const reactor = (callback:(itm:string)=>void) => (item:string) => {
    + 123            this.internalStateUpdate(desc, item);
    + 124            if (typeof callback === 'function') { 
    + 125                callback(item);  // trigger any actions from the selection
    + 126            }     
    + 127        }; 
    + 128        const l:string = desc.items[i] || '';
    + 129        const itemCss = desc.itemCss || [];
    + 130
    + 131        this.checkSelectedItem(desc);
    + 132        return selectable({ 
    + 133            title: l, 
    + 134            css: itemCss[i],        // possibly undefined
    + 135            isSelected: this.selectedItem? (l.toLowerCase() === this.selectedItem.toLowerCase()) : false, 
    + 136            mouseDown: reactor(desc.mouseDown),
    + 137            mouseUp: reactor(desc.mouseUp),
    + 138            clicked: reactor(desc.changed)
    + 139        });
    + 140    }
    + 141};
    + 142
    + 143/**
    + 144 * Creates a Selectable as part of the `Selector`, 
    + 145 * as configured by the desc:SelectableDesc object passed as a parameter.
    + 146 * Selectables can be in one of two states, selected or not selected. 
    + 147 * @return an `.hs-selectable` node
    + 148 */

    + 149export function selectable(childDesc:SelectableDesc) {
    + 150    const css           = childDesc.css || '';
    + 151    const cssSelected   = `${childDesc.isSelected?'hs-selected': ''}`;
    + 152    const onclick       = childDesc.clicked?   () => { childDesc.clicked(childDesc.title); }   : undefined;
    + 153    const onmousedown   = childDesc.mouseDown? () => { childDesc.mouseDown(childDesc.title); } : undefined;
    + 154    const onmouseup     = childDesc.mouseUp?   () => { childDesc.mouseUp(childDesc.title); }   : undefined;
    + 155    return m(`.hs-selectable ${css} ${cssSelected}`, 
    + 156        { style: childDesc.style, onclick:onclick, onmousedown:onmousedown, onmouseup:onmouseup },
    + 157        childDesc.title
    + 158    );
    + 159}
    + 160
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/ToggleButton.html b/docs/src/hsWidget/ToggleButton.html new file mode 100644 index 0000000..fd460e8 --- /dev/null +++ b/docs/src/hsWidget/ToggleButton.html @@ -0,0 +1,99 @@ + + +

    ToggleButton.ts

    +
       1/**
    +   2 * # Button Widget
    +   3 * A simple button widget
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as `m(Button, {name:, onclick:});`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - `onclick:() => void` function to execute when button is clicked
    +  10 * - `name: string` name to show as button text
    +  11 * - `css: string` css class to assign to button tag
    +  12 * - `style: string` style string to apply to button tag
    +  13 * 
    +  14 * ### Example
    +  15 * 
    +  16 * 
    +  17 * let clicked = 0;
    +  18 * let radio = '';
    +  19 * let toggle = '';
    +  20 * 
    +  21 * m.mount(root, {view: () => m('.hs-white', [
    +  22 *    m('h4', `Please Toggle: (currently ${toggle})`),
    +  23 *    m(hswidget.ToggleButton, { desc: {
    +  24 *        items: ['1st', '2nd','3rd'],
    +  25 *        changed: (item) => toggle = item
    +  26 *    }})
    +  27 * ])});
    +  28 * 
    +  29 * 

    +  30 * 
    +  31 */

    +  32
    +  33/** */
    +  34import { m, Vnode }     from 'hslayout';
    +  35import { Selector }     from './Selector';
    +  36import { oneOfItems }   from './Selector';
    +  37
    +  38/**
    +  39 * # ToggleButton Widget
    +  40 * A button widget that toggle through a set of items, or states and 
    +  41 * shows the current state as button title
    +  42 * 
    +  43 * ### Profile
    +  44 * invoked as `m(ToggleButton, {desc: { items:[], changed:}});`
    +  45 * 
    +  46 * ### Attributes (node.attrs):
    +  47 * - `desc:` see {@link Selector.SelectorDesc SelectorDesc}
    +  48 *     - `changed:(item:string) => void` function to execute when button is selected
    +  49 *     - `selectedItem?: number|string` the currently selected item, by index or name
    +  50 *     - `items: string[]` names of individual states to toggle through
    +  51 *     - `itemCss?:string[]` css to apply to each item;
    +  52 * - `css?: string` css class to assign to button group
    +  53 * - `style?: string` style string to apply to button tag
    +  54 */

    +  55export class ToggleButton extends Selector {
    +  56    private toggleIndex = -1;
    +  57    private mouseDown = '';
    +  58    view(node: Vnode): Vnode {
    +  59        const desc = this.init(node.attrs.desc, oneOfItems);
    +  60        node.attrs.desc = undefined;
    +  61        const css = node.attrs.css || '';
    +  62        const style = node.attrs.style || '';
    +  63
    +  64        // insert click update into passed click function
    +  65        const parentChanged = desc.changed;
    +  66        desc.changed = ((item:string) => {
    +  67            this.toggleIndex = (this.toggleIndex+1) % desc.items.length;
    +  68            item = desc.items[this.toggleIndex];
    +  69            this.internalStateUpdate(desc, item);
    +  70            if (parentChanged) { parentChanged(item); }
    +  71        });
    +  72
    +  73        if (this.toggleIndex<0) { this.toggleIndex = 0; }
    +  74
    +  75        desc.mouseDown = () => this.mouseDown = '.hs-button-pressed';
    +  76        desc.mouseUp   = () => this.mouseDown = '';
    +  77
    +  78        return m(`.hs-toggle-button${css}${this.mouseDown}`, { style:style}, m('span', 
    +  79            this.renderItem(desc, this.toggleIndex)
    +  80        ));
    +  81    }
    +  82}
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/ToolbarButton.html b/docs/src/hsWidget/ToolbarButton.html new file mode 100644 index 0000000..19ad9ac --- /dev/null +++ b/docs/src/hsWidget/ToolbarButton.html @@ -0,0 +1,147 @@ + + +

    ToolbarButton.ts

    +
       1/**
    +   2 * # Toolbar Button
    +   3 * creates a set of buttons at the corner of a positioned panel.
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as `m(ToolbarButtons, {  })`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - `symbols: string | string[]` a symbol, or array of symbols 
    +  10 * - `onclick: ()=>void` a function that is called when the modal box is dismissed
    +  11 * 
    +  12 * ### Example
    +  13 * 
    +  14 * 
    +  15 * const buttons = {}
    +  16 * const keys = Object.keys(hswidget.ButtonSymbols);
    +  17 * const symbols = [];
    +  18 * let batch = [];
    +  19 * for (let i=0; i +  20 *    if (i % 4 === 0) {
    +  21 *       batch = []
    +  22 *       symbol.push(batch);
    +  23 *    }
    +  24 *    batch.push(keys[i]);
    +  25 * }
    +  26 * 
    +  27 * m.mount(root, {view: () => m('', [
    +  28 *    m('', keys.map(
    +  29 *       (b) => m('.myPositioned', [
    +  30 *          buttons[b]? m('.myClicked', 'Yayy!!') : m('', b),
    +  31 *          m(hswidget.ToolbarButtons, { symbol:hswidget.ToolbarButtons.getSymbol(b), onclick:click(b) })
    +  32 *       ])
    +  33 *    )), 
    +  34 *    m('', symbols.map(
    +  35 *       (batch) => m('.myPositioned', [
    +  36 *          m(hswidget.ToolbarButtons, { symbol:batch.map(b => hswidget.ToolbarButtons.getSymbol(b)), onclick:click(b) })
    +  37 *       ])
    +  38 *    ))
    +  39 * ])});
    +  40 * 
    +  41 * function click(button) {
    +  42 *      return () => {
    +  43 *          buttons[button] = true;
    +  44 *          setTimeout(reset(button), 800);
    +  45 *      }
    +  46 * }
    +  47 * 
    +  48 * function reset(button) {
    +  49 *      return () => {
    +  50 *          buttons[button] = false;
    +  51 *          m.redraw();
    +  52 *      }
    +  53 * }
    +  54 * 
    +  55 * 
    +  56 * .myClicked { background-color: #efe; }
    +  57 * .myPositioned { 
    +  58 *      position: relative; 
    +  59 *      display: inline-block;
    +  60 *      box-sizing: border-box;
    +  61 *      background-color: #fff; 
    +  62 *      text-align: center;
    +  63 *      font-size: 70%;
    +  64 *      margin:  2px;
    +  65 *      padding-top: 20px;
    +  66 *      height: 50px;
    +  67 *      width:  50px;
    +  68 * }
    +  69 * .hs-corner-button { color: #008; }
    +  70 * 
    +  71 * 

    +  72 */

    +  73
    +  74 /** */
    +  75import { m, Vnode}  from 'hslayout'; 
    +  76
    +  77export const ButtonSymbols = {
    +  78    cross:      { sym: '×' },
    +  79    minus:      { sym: '−'},
    +  80    plus:       { sym: '+'},
    +  81    dLeft:      { sym: '«'},
    +  82    dRight:     { sym: '»'},
    +  83    left:       { sym: '‹'},
    +  84    right:      { sym: '›'},
    +  85    leftTri:    { sym: '◂'},
    +  86    rightTri:   { sym: '▸'},
    +  87    upTri:      { sym: '▴'},
    +  88    downTri:    { sym: '▾'},
    +  89    up:         { sym: '∧'},
    +  90    down:       { sym: '∨'},
    +  91    lArrow:     { sym: '←'},
    +  92    rArrow:     { sym: '→'},
    +  93    uArrow:     { sym: '↑'},
    +  94    dArrow:     { sym: '↓'},
    +  95    empty:      { sym: '○'},
    +  96    emptySlash: { sym: '∅'},
    +  97    oSlash:     { sym: 'ø'},
    +  98    o:          { sym: 'ο'},
    +  99    lines3:     { sym: '≡'},
    + 100    sum:        { sym: 'Σ'},
    + 101    ellipsis:   { sym: '…'},
    + 102    vertEllips: { sym: '⁝'},
    + 103    bullet:     { sym: '•'},
    + 104    enter:      { sym: '↵'},
    + 105    again:      { sym: '↻'},
    + 106    start:      { sym: '⇱'},
    + 107    end:        { sym: '⇲'}
    + 108};
    + 109
    + 110export class ToolbarButton {
    + 111    constructor(protected symbol='-') {}
    + 112    static getSymbol(name:string) {
    + 113        return ButtonSymbols[name]? ButtonSymbols[name].sym : '';
    + 114    }
    + 115    view(node:Vnode) {
    + 116        if (node.attrs.symbol.length) {
    + 117            return node.attrs.symbol.map((sym:string) => 
    + 118                m('.hs-corner-button', 
    + 119                    { onclick: node.attrs.onclick }, 
    + 120                    m.trust(sym))
    + 121            );
    + 122        } else {
    + 123            return m('.hs-corner-button', 
    + 124                { onclick: node.attrs.onclick }, 
    + 125                m.trust(node.attrs.symbol));
    + 126        }
    + 127    }
    + 128}
    + 129
    + 130
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/TypeAhead.html b/docs/src/hsWidget/TypeAhead.html new file mode 100644 index 0000000..90837a1 --- /dev/null +++ b/docs/src/hsWidget/TypeAhead.html @@ -0,0 +1,150 @@ + + +

    TypeAhead.ts

    +
       1/**
    +   2 * # TypeAhead
    +   3 * Provides a search box with a type-ahead dropdown to show valid options that match the current search input.
    +   4 * 
    +   5 * ### Profile
    +   6 * invoked as `m(hswidget.TypeAhead, {  });`
    +   7 * 
    +   8 * ### Attributes (node.attrs):
    +   9 * - `list: string | string[]` the list to search in. If `list` is a string, it serves
    +  10 *    as a URL to a `json` file containing an array of search terms. Else, if it is a 
    +  11 *    string[] it serves directly as an array of search terms
    +  12 * - `placeholder: string` an indicator what to enter in the search box
    +  13 * - `onsubmit: (term:string) => void`  a function to call when a term is submitted
    +  14 * - `autofocus: boolean` whether the search box automatically gets the focus
    +  15 * 
    +  16 * ### Example
    +  17 * 
    +  18 * 
    +  19 * let hero = '';
    +  20 * let friend = '';
    +  21 * m.mount(root, {view: () => m('.hs-white', [
    +  22 *      m('h4', hero.length? `Selected: ${hero}` : 'Local List: Search for a Superhero'),
    +  23 *      m(hswidget.TypeAhead, { 
    +  24 *         placeholder: 'favorite hero',
    +  25 *         onsubmit: item => hero = item,
    +  26 *         list: ['Batman', 'Superman', 'Spiderman', 'Hulk']
    +  27 *      }),
    +  28 *      m('h4', friend.length? `Selected: ${friend}` : 'Remote List: Search for a Friend'),
    +  29 *      m(hswidget.TypeAhead, { 
    +  30 *         placeholder: 'best friend',
    +  31 *         onsubmit: item => friend = item,
    +  32 *         autofocus: true,
    +  33 *         list: 'example/search.json'
    +  34 *      })
    +  35 *   ])
    +  36 * });
    +  37 * 
    +  38 * 

    +  39 * 
    +  40 */

    +  41
    +  42 /** */
    +  43import { m, Vnode } from 'hslayout';
    +  44
    +  45// emphasize literal matches as *bold* in the drop down list
    +  46function emphasize(item:string, match:string) {
    +  47    const re = new RegExp(match, 'gi');
    +  48    const decorations = item
    +  49        .replace(re, (m:string) => `${m}`)
    +  50        .split('<')
    +  51        .map((s:string) => {
    +  52            if (s.startsWith('/b>')) { 
    +  53                return m('span', {name:item}, s.slice(3)); 
    +  54            } else if (s.startsWith('b>')) {
    +  55                return m('b', {name:item}, s.slice(2));
    +  56            } else {
    +  57                return m('span', {name:item}, s);
    +  58            }
    +  59        });
    +  60    return m('span', decorations); 
    +  61}
    +  62
    +  63class GetList {
    +  64    public list:string[] = [];
    +  65    private captureList(list:any[], map:(l:any[])=>string[]) {
    +  66        this.list = map? map(list) : list;
    +  67    }
    +  68    constructor(list:string|string[], map?:(item:any[])=>string[]) {
    +  69        if (typeof list === 'string') {
    +  70            m.request({ method: "GET", url: list })
    +  71            .then((data:any[]) => this.captureList(data, map));
    +  72        } else {
    +  73            this.captureList(list, map);
    +  74        }
    +  75    }
    +  76}
    +  77
    +  78export class TypeAhead {
    +  79    typeAheadList:string[] = [];
    +  80    hidden = true;
    +  81    value = '';
    +  82    inputNode:any;
    +  83    view(node:Vnode) {
    +  84        const gl = new GetList(node.attrs.list);
    +  85        const nosubmit = () => console.log('no submit function defined');
    +  86        const submit = (v:string) => node.attrs.onsubmit? node.attrs.onsubmit(v) : nosubmit();
    +  87        const select = (e:any) => { if (e) { 
    +  88            submit(e.target.attributes.name.value);
    +  89            this.inputNode.value = '';
    +  90            this.hidden = true;
    +  91        }};
    +  92        const input = (e:any) => {
    +  93            const n = this.inputNode = e.target;
    +  94            const input = this.value = n.value;
    +  95            const withinInput = new RegExp(`${input}`, 'gi');
    +  96            const beginningOfInput = new RegExp(`^${input}`, 'gi');
    +  97            this.typeAheadList = gl.list.filter((l:string) => l.match(withinInput));
    +  98            n.value = this.typeAheadList.filter((l:string) => l.match(beginningOfInput))[0] || input; 
    +  99            this.hidden = n.value.length===0; 
    + 100            let pos = input.length;
    + 101            n.setSelectionRange(pos, n.value.length);
    + 102        };
    + 103        const keyPressed = (e:any) => {
    + 104            const n = this.inputNode = e.target;
    + 105            if (e.code === 'Enter') {
    + 106                submit(n.value);
    + 107                n.value = '';
    + 108                 this.hidden = true;
    + 109            } else if (e.code === 'Backspace') {
    + 110                const input = n.firstChild.data;
    + 111                if (input.length > 0) {
    + 112                    n.value = input.slice(0);
    + 113                }
    + 114            }
    + 115        };
    + 116        const inputNode = m(`input.hs-typeahead-input${this.value?'.hs-typeahead-value' : '.hs-typeahead-placeholder'}`, 
    + 117            {
    + 118                contenteditable:true,
    + 119                placeholder:    node.attrs.placeholder,
    + 120                autofocus:      node.attrs.autofocus || true,
    + 121                onkeydown:      keyPressed.bind(this),
    + 122                oninput:        input.bind(this)
    + 123            }, 
    + 124            m.trust(this.value?this.value : node.attrs.placeholder));
    + 125
    + 126        return m('.hs-form', [
    + 127            inputNode, 
    + 128            this.hidden? undefined : 
    + 129                m('.hs-typeahead-list', this.typeAheadList.map((l:string) => 
    + 130                    m('', { onclick: select.bind(this) }, emphasize(l, this.value))))
    + 131        ]);
    + 132    }
    + 133}
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/example/start.html b/docs/src/hsWidget/example/start.html new file mode 100644 index 0000000..b1f60b6 --- /dev/null +++ b/docs/src/hsWidget/example/start.html @@ -0,0 +1,19 @@ + + +

    example/start.ts

    +
       1import { Menu } from '../';
    +   2if (Menu) {}
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/index.html b/docs/src/hsWidget/index.html new file mode 100644 index 0000000..d33bc16 --- /dev/null +++ b/docs/src/hsWidget/index.html @@ -0,0 +1,38 @@ + + +

    index.ts

    +
       1/**
    +   2 * @description hsWidgets: Library of UI screen elements.
    +   3 */

    +   4
    +   5/**
    +   6 * 
    +   7 */

    +   8export { Menu }         from './Menu'; 
    +   9export { SelectorDesc } from './Selector'; 
    +  10export { Button }       from './Button'; 
    +  11export { RadioButton }  from './RadioButton'; 
    +  12export { ToggleButton } from './ToggleButton'; 
    +  13export { ToolbarButton,
    +  14         ButtonSymbols
    +  15        }               from './ToolbarButton';
    +  16export { AddButton, 
    +  17         RemoveButton } from './AddRemove'; 
    +  18export { Collapsible }  from './Collapsible'; 
    +  19export { Modal }        from './Modal'; 
    +  20export { TypeAhead }    from './TypeAhead'; 
    +  21
    + + \ No newline at end of file diff --git a/docs/src/hsWidget/overview.html b/docs/src/hsWidget/overview.html new file mode 100644 index 0000000..f54243b --- /dev/null +++ b/docs/src/hsWidget/overview.html @@ -0,0 +1,192 @@ + + +

    overview.ts

    +
       1/**
    +   2# hsWidgets 
    +   3Provides various UI widgets:
    +   4
    +   5| Widget | Description |
    +   6|========|=============|
    +   7|   {@link Menu.Menu Menu} | A group of horizontal menu items that can trigger actions |
    +   8|   {@link Button.Button Button} | A simple button widget |
    +   9|   {@link Collapsible Collapsible} | A panel that will expand znd collapse when the title is clicked |
    +  10|   {@link Modal Modal} | A modal panel that will cover the entire window until released. |
    +  11|   {@link AddRemove AddButton} | An inline `+` button that will open a form for adding new elements. |
    +  12|   {@link AddRemove RemoveButton} | An inline `-` button that will remove an item. |
    +  13|   {@link TypeAhead TypeAhead} | A TypeAhead search input form. |
    +  14
    +  15 * 
    +  16 * 
    +  17 * const render = () => m.mount(root, {view: () => m('.hs-white', [
    +  18 * 
    +  19 *    m('h2.myGapButtons', 'Buttons'),
    +  20 *    m('h4', `Please click: (${clicked}-times clicked)`),
    +  21 *    m(hswidget.Button, { desc: {
    +  22 *        name: 'click me',
    +  23 *        clicked: () => clicked++
    +  24 *    }}),
    +  25 *    m('h4', `Select Radio Station: ${radio}`),
    +  26 *    m(hswidget.RadioButton, { desc: {
    +  27 *        items: ['1st', '2nd','3rd'],
    +  28 *        changed: (item) => radio = item
    +  29 *    }}),
    +  30 *    m('h4', `Please Toggle between 1st, 2nd, and 3rd`),
    +  31 *    m(hswidget.ToggleButton, { desc: {
    +  32 *        items: ['1st', '2nd','3rd'],
    +  33 *        changed: (item) => toggle = item
    +  34 *    }}),
    +  35 * 
    +  36 *    m('h2.myGapMenus', 'Menus'),
    +  37 *    m('h4', 'Please select:'),
    +  38 *    m(hswidget.Menu, { css: '.myMenu', desc: {
    +  39 *       items: menuItems,
    +  40 *       defaultItem: 'Two',
    +  41 *       changed: (item) => theContent = content[menuItems.indexOf(item)]
    +  42 *    }}),
    +  43 *    m('myMenuMain', theContent),
    +  44 * 
    +  45 *    m('h2.myGapModal', 'Modal Dialog Box'),
    +  46 *    m('h4', {onclick:() => showModal = true }, 'Click me to open a modal box'),
    +  47 *    showModal? m(hswidget.Modal, {
    +  48 *       width:  '300px',
    +  49 *       height: '200px',
    +  50 *       dismiss: () => showModal = false,
    +  51 *       content: m('', 'click on border or on the x to release')
    +  52 *    }) : undefined,
    +  53 * 
    +  54 *    m('h2.myGapCollapsibless', 'Collapsibles'),
    +  55 *    m(hswidget.Collapsible, { css:'.myCollapsible', components: [
    +  56 *       m('.myTitle', 'click me to toggle - no arrows'), content 
    +  57 *    ]}),
    +  58 *    m(hswidget.Collapsible, { css:'.myCollapsible', preArrow:true, components: [
    +  59 *       m('.myTitle', 'click me to toggle - left arrow'), content 
    +  60 *    ]}),
    +  61 *    m(hswidget.Collapsible, { css:'.myCollapsible', postArrow:true, components: [
    +  62 *       m('.myTitle', 'click me to toggle - right arrow'), content 
    +  63 *    ]}),
    +  64 *    m(hswidget.Collapsible, { css:'.myCollapsible', preArrow:true, postArrow:true, components: [
    +  65 *       m('.myTitle', 'click me to toggle - both arrows'), content
    +  66 *    ]}),
    +  67 *    m('', 'Background text, will be pushed down by the Collapsible'),
    +  68 * 
    +  69 *    m('h2.myGapTypeAhead', 'Typeahead Search'),
    +  70 *    m('h4', 'In-Memory List: ' + hero.length? `Selected: ${hero}` : 'Search for a Superhero'),
    +  71 *    m(hswidget.TypeAhead, { 
    +  72 *       placeholder: 'favorite hero',
    +  73 *       onsubmit: item => hero = item,
    +  74 *       list: ['Batman', 'Superman', 'Spiderman', 'Hulk']
    +  75 *    }),
    +  76 *    m('h4', `Remote List: ${friend.length? 'Selected: '+ friend : 'Search for a Friend'}`),
    +  77 *    m(hswidget.TypeAhead, { 
    +  78 *       placeholder: 'best friend',
    +  79 *       onsubmit: item => friend = item,
    +  80 *       autofocus: true,
    +  81 *       list: 'example/search.json'
    +  82 *    }),
    +  83 *
    +  84 *    m('h2.myGapCornerButtons', 'Corner Buttons'),
    +  85 *    m('h4', lastCornerButton),
    +  86 *    m('', Object.keys(hswidget.ButtonSymbols).map(
    +  87 *       (b) => m('.myCornerPositioned', [
    +  88 *          buttons[b]? m('.myCornerClicked', 'Yayy!!') : m('', b),
    +  89 *          m(hswidget.ToolbarButtons, { symbol:hswidget.ToolbarButtons.getSymbol(b), onclick:click(b) })
    +  90 *       ])
    +  91 *    )),
    +  92 * ])});
    +  93 * 
    +  94 * 
    +  95 * //--------------------------------------
    +  96 * // supporting variables:
    +  97 * const menuItems = ['One', 'Two', 'Three'];
    +  98 * const content   = ['1st', '2nd', '3rd'];
    +  99 * let  theContent = content[1];
    + 100 * let clicked = 0;
    + 101 * let radio = '';
    + 102 * let toggle = '';
    + 103 * const buttons = {};
    + 104 * let lastCornerButton = '';
    + 105 * let showModal = false;
    + 106 * let hero = '';
    + 107 * let friend = '';
    + 108 * 
    + 109 * const click = (button) => () => {
    + 110 *    lastCornerButton = '';
    + 111 *    if (hswidget.ButtonSymbols[button]) {
    + 112 *       lastCornerButton = m.trust(`last button pressed: ${hswidget.ButtonSymbols[button].sym}`);
    + 113 *       buttons[button] = true;
    + 114 *       setTimeout(reset(button), 800);
    + 115 *    }
    + 116 * };
    + 117 * 
    + 118 * const reset = (button) => () => {
    + 119 *    buttons[button] = false;
    + 120 *    m.redraw();
    + 121 * }
    + 122 *
    + 123 * render();
    + 124 * 
    + 125 *
    + 126 * 
    + 127 * .myMenuMain { 
    + 128 *    border:1px solid #ddd;
    + 129 *    border-top: 0px solid #ddd;
    + 130 * } 
    + 131 * .myMenu .hs-selectable { 
    + 132 *     background-color: #eef; 
    + 133 * }
    + 134 * .myMenu .hs-selected { 
    + 135 *     background-color: #ddf; 
    + 136 *     border-width:0px;
    + 137 * }
    + 138 * .myCollapsible {
    + 139 *     margin-bottom: 5px;
    + 140 * }
    + 141 * .myCollapsible .hs-collapsible-title {
    + 142 *     font-weight:bold;
    + 143 *     padding-left: 3px;
    + 144 *     background-color: #eee;
    + 145 * }
    + 146 * .myCollapsible .hs-collapsible-expanded {
    + 147 *     margin-left: 10px;
    + 148 * }
    + 149 * .myCornerClicked { background-color: #efe; }
    + 150 * .myCornerPositioned { 
    + 151 *      position: relative; 
    + 152 *      display: inline-block;
    + 153 *      box-sizing: border-box;
    + 154 *      background-color: #eee; 
    + 155 *      text-align: center;
    + 156 *      font-size: 70%;
    + 157 *      margin:  2px;
    + 158 *      padding-top: 20px;
    + 159 *      height: 50px;
    + 160 *      width:  50px;
    + 161 * }
    + 162 * .hs-corner-button { color: #008; }
    + 163 * 
    + 164 * .myGapButtons        { margin-top: 90px; }
    + 165 * .myGapMenus          { margin-top: 80px; }
    + 166 * .myGapModal          { margin-top: 50px; }
    + 167 * .myGapCollapsibless  { margin-top: 115px; }
    + 168 * .myGapTypeAhead      { margin-top: 130px; }
    + 169 * .myGapCornerButtons  { margin-top: 105px; }
    + 170 * 
    + 171 * 
    + 172*/

    + 173
    + 174/** */
    + 175
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/AddRemove.html b/docs/src/hsWidgets/AddRemove.html new file mode 100644 index 0000000..6abc12c --- /dev/null +++ b/docs/src/hsWidgets/AddRemove.html @@ -0,0 +1,36 @@ + + +

    AddRemove.ts

    +
       1/**
    +   2 * # AddRemove Buttons
    +   3 * Adds '+' and '-' buttons to add or remove items from a list.
    +   4 */

    +   5
    +   6 /** */
    +   7import { m, Vnode}      from 'hslayout';
    +   8
    +   9export class AddButton {
    +  10    view(node:Vnode):Vnode {
    +  11        return m('.hs-add-button', { onclick:node.attrs.add }, '');
    +  12    }
    +  13}
    +  14
    +  15export class RemoveButton {
    +  16    view(node:Vnode):Vnode {
    +  17        return m('.hs-remove-button', { onclick:node.attrs.remove }, '');
    +  18    }
    +  19}
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/Button.html b/docs/src/hsWidgets/Button.html new file mode 100644 index 0000000..7c64052 --- /dev/null +++ b/docs/src/hsWidgets/Button.html @@ -0,0 +1,32 @@ + + +

    Button.ts

    +
       1/**
    +   2 * # Button Widget
    +   3 * invoked as `m(Button, {name:, onclick:})`
    +   4 */

    +   5
    +   6/** */
    +   7import { m, Vnode }     from 'hslayout';
    +   8
    +   9
    +  10export class Button {
    +  11    view(node: Vnode) {
    +  12        return m('.hs-button', {onclick:node.attrs.onclick},  node.attrs.name || 'button');
    +  13    }
    +  14}
    +  15
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/Collapsible.html b/docs/src/hsWidgets/Collapsible.html new file mode 100644 index 0000000..cf64495 --- /dev/null +++ b/docs/src/hsWidgets/Collapsible.html @@ -0,0 +1,54 @@ + + +

    Collapsible.ts

    +
       1/**
    +   2 * # Collapsible
    +   3 * 
    +   4 */

    +   5
    +   6 /** */
    +   7import { m, Vnode } from 'hslayout';
    +   8
    +   9const expanded: {string?:boolean} = {};
    +  10
    +  11const getKey = () => 'hs'+Math.floor(Math.random()*2000000);
    +  12
    +  13/**
    +  14 * returns a Vnode that can be toggled to expand and contract by clicking on the first `component`.
    +  15 * @param css the css class to assign to the entire collapsible div
    +  16 * @param attrs optional attributes list:
    +  17 * - isExpanded: boolean indicates if the collapsible is initially expanded
    +  18 * @param components array of two components: 
    +  19 * - component[0] is the title of the collapsible. This will remain visible and cabn be clicked 
    +  20 *   on to expand or contract the remaining components
    +  21 * - component[1] a Vnode or an array of Vnodes that will be collapsed or expanded.
    +  22 */

    +  23export function collapsible(css:string, attrs:any, components:Vnode[]) {
    +  24    function toggle() {
    +  25        expanded[key] = !expanded[key];
    +  26//        m.redraw();
    +  27    }
    +  28    if (!components) { components = attrs; attrs = undefined; }
    +  29    const key = getKey();
    +  30    if (attrs.isExpanded) { expanded[key] = true; }
    +  31    return m(`.hs-collapsible ${css}`, { onclick:toggle}, [
    +  32            components[0],
    +  33            !components[1]? undefined : m('.hs-collapsible-content', { 
    +  34                class: expanded[key]?'':'hs-collapsed'
    +  35            }, components[1].map((c:any) =>c))
    +  36        ]);
    +  37}
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/Menu.html b/docs/src/hsWidgets/Menu.html new file mode 100644 index 0000000..f51a002 --- /dev/null +++ b/docs/src/hsWidgets/Menu.html @@ -0,0 +1,142 @@ + + +

    Menu.ts

    +
       1/**
    +   2 * # hsMenu
    +   3 * Creates a simple menu with several items.
    +   4 * The `Menu` object is passed into `Mithril`'s m function with a `MenuDesc` object:
    +   5 * ```
    +   6 * interface MenuDesc {
    +   7 *    items: string[];                // the items on the menu
    +   8 *    select: (item:string) => void;  // called when item clicked
    +   9 *    selectedItem?: string;          // the currently selected item
    +  10 *    size?:string[];                 // size to layout menu items
    +  11 * }
    +  12 * ```
    +  13 * 
    +  14 * ## Example
    +  15 * 
    +  16 * 
    +  17 * const items = ['One', 'Two', 'Three'];
    +  18 * const content   = ['1st', '2nd', '3rd'];
    +  19 * let  theContent = content[1];
    +  20 * 
    +  21 * m.mount(root, {view: () => m(hslayout.Container, {
    +  22 *     rows:["30px", "fill"],
    +  23 *     content:[
    +  24 *         m(widget.Menu, {desc: {
    +  25 *             items: items,
    +  26 *             selectedItem: 'Two',
    +  27 *             select: item => 
    +  28 *                theContent = content[items.indexOf(item)]
    +  29 *         }}),
    +  30 *         m(hslayout.Container, { css:'myMain', content: theContent })
    +  31 *     ]
    +  32 * })});
    +  33 *
    +  34 * 
    +  35 * 
    +  36 * .myMain { 
    +  37 *    border:1px solid #ddd;
    +  38 *    border-top: 0px solid #ddd;
    +  39 * } 
    +  40 * .hs-menu-item-selected { 
    +  41 *     background-color: #eed; 
    +  42 *     border-width:0px;
    +  43 * }
    +  44 * 
    +  45 * 

    +  46 */

    +  47
    +  48 /** */
    +  49import { Container, m, Vnode } from 'hslayout';
    +  50
    +  51/** passed into Menu from the calling application */
    +  52export interface MenuDesc {
    +  53    /** the items on the menu */
    +  54    items: string[];
    +  55    /** the currently selected item */
    +  56    selectedItem?: string;
    +  57    /** the function to call when the selection changes */
    +  58    select: (item:string) => void;
    +  59    /** optional array of size strings used to layout the menu items; defaults to `[ ]` */
    +  60    size?:string[];
    +  61}
    +  62
    +  63/** interface of the parameter passed to a `MenuItem` */
    +  64export interface MenuItemDesc {
    +  65    /** the item's title */
    +  66    title: string;
    +  67    /** the item's select status */
    +  68    isSelected: boolean;
    +  69    /** the function to call if this item is selected */
    +  70    clicked: (item:string) => void;
    +  71}
    +  72
    +  73/**
    +  74 * Creates a simple menu with several items, as configured by the desc:MenuDesc object passed as a parameter. 
    +  75 */

    +  76export class Menu extends Container {
    +  77    /** instance variable, keeping a list of menu items and a `select` function for tracking which item is selected. */
    +  78    menu = { 
    +  79        items:<{string:MenuItemDesc}> {},
    +  80        select: (title:string) => {
    +  81            Object.keys(this.menu.items).forEach((key:string) => { 
    +  82                this.menu.items[key].isSelected = (key===title); 
    +  83            });
    +  84        }
    +  85    };
    +  86
    +  87    getComponents(node: Vnode): Vnode {
    +  88        const _menu = this.menu;
    +  89        const desc = node.attrs.desc;
    +  90        node.attrs.desc = undefined;
    +  91
    +  92        desc.selectedItem = desc.selectedItem || desc.items[0];
    +  93        node.attrs.columns = desc.size || [];
    +  94        node.attrs.css = '.hs-menu';
    +  95        return desc.items.map((l:string) => {
    +  96            _menu.items[l] = _menu.items[l] || { 
    +  97                title: l, 
    +  98                isSelected: l === desc.selectedItem, 
    +  99                clicked:(item:string) => {
    + 100                    desc.selectedItem = item;
    + 101                    _menu.select(item); // local housekeeping: make sure the item's style shows correct selection
    + 102                    if (typeof desc.select === 'function') { 
    + 103                        desc.select(item);  // trigger any actions form the selection
    + 104                    }     
    + 105                }
    + 106            }; 
    + 107            return m(MenuItem, { desc:_menu.items[l] });
    + 108        });
    + 109    }
    + 110};
    + 111
    + 112/**
    + 113 * Creates a menu item as part of the menu, as configured by the desc:MenuItemDesc object passed as a parameter.
    + 114 */

    + 115class MenuItem extends Container {
    + 116    getComponents(node: Vnode): Vnode {
    + 117        const desc:MenuItemDesc = node.attrs.desc;
    + 118        node.attrs.desc = undefined;
    + 119        node.attrs.css = `.hs-menu-item ${desc.isSelected?'hs-menu-item-selected': ''}`;
    + 120        node.attrs.onclick = () => { desc.clicked(desc.title); };
    + 121        return desc.title;
    + 122    }
    + 123};
    + 124
    + 125
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/Menu.spec.html b/docs/src/hsWidgets/Menu.spec.html new file mode 100644 index 0000000..441ea29 --- /dev/null +++ b/docs/src/hsWidgets/Menu.spec.html @@ -0,0 +1,66 @@ + + +

    Menu.spec.ts

    +
       1
    +   2const hslayout = require('hslayout');
    +   3const m = hslayout.m;
    +   4const o = hslayout.o;
    +   5
    +   6const hsMenu = require("../src/Menu");
    +   7const Menu = hsMenu.Menu;
    +   8
    +   9const left  = ['0%', '25%', '50%', '75%'];
    +  10const right = ['75%', '50%', '25%', '0%'];
    +  11const title = ['1a', '2a', '3a', '4a']; 
    +  12
    +  13o.spec('hsMenu', () => {
    +  14    let menu:any;
    +  15    o.before(() => {
    +  16        const md = { 
    +  17            items: title,
    +  18            select: (item:string) => { console.log('selected'); }
    +  19        };
    +  20        m.mount(o.root, {view: () => m(Menu, { desc: md }) }); 
    +  21        menu = o.root.childNodes[0];
    +  22    });
    +  23
    +  24    o('Menu', () => {
    +  25        o(menu).notEquals(undefined)('creation');
    +  26        o(menu.className.indexOf('hs-menu')).notEquals(-1)("is menu");
    +  27        o(menu.className.indexOf('hs-layout')).notEquals(-1)("is layout");
    +  28    });
    +  29
    +  30    o('Menu Items', () => {
    +  31        const cn = menu.childNodes;
    +  32        o(cn.length).equals(4)("has 4 menu items");
    +  33        cn.forEach((c:any, i:any) => {
    +  34            o(c.className.indexOf('hs-menu-item')).notEquals(-1)(`item ${i+1} menu-item class`);
    +  35            o(c.className.indexOf('hs-layout')).notEquals(-1)(`item ${i+1} layout class`);
    +  36            o(c.className.includes('hs-menu-item-selected')).equals((i===0)?true:false)(`item ${i+1} selected class`);
    +  37            o(c.style.left).equals(left[i])(`item ${i+1} left`);
    +  38            o(c.style.right).equals(right[i])(`item ${i+1} right`);
    +  39            o(c.style.top).equals('0%')(`item ${i+1} top`);
    +  40            o(c.style.bottom).equals('0%')(`item ${i+1} bottom`);
    +  41            o(c.childNodes.length).equals(1)(`item ${i+1} num children`);
    +  42            o(c.childNodes[0].className).equals('hs-leaf')(`item ${i+1} child leaf`);
    +  43            o(c.childNodes[0].childNodes[0].nodeValue).equals(title[i])(`item ${i+1} child leaf text`);
    +  44        });
    +  45    });
    +  46
    +  47});
    +  48
    +  49
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/Modal.html b/docs/src/hsWidgets/Modal.html new file mode 100644 index 0000000..5aa93f9 --- /dev/null +++ b/docs/src/hsWidgets/Modal.html @@ -0,0 +1,32 @@ + + +

    Modal.ts

    +
       1import { m, Vnode}      from 'hslayout';
    +   2
    +   3
    +   4export class Modal {
    +   5    private static modal:Vnode; 
    +   6    public static show()    { Modal.modal = m(Modal); }
    +   7    public static dismiss() { Modal.modal = undefined; }
    +   8    view(node:Vnode) {
    +   9        return m('.hs-modal-frame', !Modal.modal? '': [
    +  10            m('.hs-modal-background', { onclick: () => { Modal.modal=undefined; }}, ''),
    +  11            m('.hs-modal-foreground', node.attrs.content || 'modal pane')
    +  12        ]);
    +  13    }
    +  14}
    +  15
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/css/Button.html b/docs/src/hsWidgets/css/Button.html new file mode 100644 index 0000000..5fd4e34 --- /dev/null +++ b/docs/src/hsWidgets/css/Button.html @@ -0,0 +1,32 @@ + + +

    css/Button.ts

    +
       1/**
    +   2 * # Button Widget
    +   3 * invoked as `m(Button, {name:, onclick:})`
    +   4 */

    +   5
    +   6/** */
    +   7import { m, Vnode }     from 'hslayout';
    +   8
    +   9
    +  10export class Button {
    +  11    view(node: Vnode) {
    +  12        return m('.hs-button', {onclick:node.attrs.onclick},  node.attrs.name || 'button');
    +  13    }
    +  14}
    +  15
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/example/start.html b/docs/src/hsWidgets/example/start.html new file mode 100644 index 0000000..b1f60b6 --- /dev/null +++ b/docs/src/hsWidgets/example/start.html @@ -0,0 +1,19 @@ + + +

    example/start.ts

    +
       1import { Menu } from '../';
    +   2if (Menu) {}
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/index.html b/docs/src/hsWidgets/index.html new file mode 100644 index 0000000..52b933e --- /dev/null +++ b/docs/src/hsWidgets/index.html @@ -0,0 +1,27 @@ + + +

    index.ts

    +
       1/**
    +   2 * @description hsWidgets: Library of UI screen elements.
    +   3 */

    +   4
    +   5/**
    +   6 * 
    +   7 */

    +   8export { Menu, MenuDesc }  from './Menu'; 
    +   9export { collapsible }     from './Collapsible'; 
    +  10
    + + \ No newline at end of file diff --git a/docs/src/hsWidgets/overview.html b/docs/src/hsWidgets/overview.html new file mode 100644 index 0000000..5f47fd6 --- /dev/null +++ b/docs/src/hsWidgets/overview.html @@ -0,0 +1,28 @@ + + +

    overview.ts

    +
       1/**
    +   2# hsWidgets 
    +   3Provides various UI widgets:
    +   4| Widget | Description |
    +   5|========|=============|
    +   6| .{@link hsGraph:hsMenu Menus} | A group of horizontal menu items that can trigger actions |
    +   7
    +   8*/

    +   9
    +  10/** */
    +  11
    + + \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100755 index b8c851a..0000000 --- a/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "hsdatab", - "version": "2.0.2", - "main": "./index.js", - "types": "./index.d.ts", - "keywords": [ - "" - ], - "description": "Helpful Scripts simple cross-framework data table management and filtering utilities ", - "author": { - "name": "masterscripter", - "email": "helpfulscripts@gmail.com" - }, - "scripts": {}, - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/HelpfulScripts/hsDatab.git" - }, - "engines": { - "node": ">= 0.10.0" - }, - "plugins": [ - "plugins/markdown" - ], - "dependencies": {} -} diff --git a/sharedGruntConfig.js b/sharedGruntConfig.js deleted file mode 100644 index 22d19ea..0000000 --- a/sharedGruntConfig.js +++ /dev/null @@ -1,290 +0,0 @@ -const path = require('path'); -const webpack = require("webpack"); -//const webpackConfig = require('./webpack.config'); - -const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); - -module.exports = (grunt, dir, dependencies, type) => { - const pkg = grunt.file.readJSON(dir+'/package.json'); - const slash = pkg.name.lastIndexOf('/'); - const lib = slash<0? pkg.name : pkg.name.slice(slash+1); - const libPath = lib.toLowerCase(); - console.log(dir); - - // These plugins provide necessary tasks. - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-less'); - grunt.loadNpmTasks('grunt-typedoc'); - grunt.loadNpmTasks('grunt-tslint'); - grunt.loadNpmTasks('grunt-ts'); - grunt.loadNpmTasks('grunt-webpack'); - - //------ Add Doc Tasks - grunt.registerTask('doc', ['clean:docs', 'typedoc', 'copy:docs']); - - //------ Add Staging Tasks - grunt.registerTask('stage', [`${(type === 'app')? 'copy:stageApp': 'copy:deployLib'}`]); - - //------ Add Test Tasks - grunt.registerTask('ospec', () => { require('child_process').spawnSync('npm', ['test'], {stdio: 'inherit'}); }); - if (type === 'node') { - grunt.loadNpmTasks('grunt-jasmine-node-coverage'); - grunt.registerTask('test', ['clean:test', 'copy:test', 'build-specES5', 'jasmine_node' ]); } - else { - grunt.registerTask('test', ['clean:test', 'copy:test', 'build-spec', /*'ospec'*/ ]); - } - - //------ Add Build Tasks - grunt.registerTask('build-html', ['copy:build']); - grunt.registerTask('build-css', ['less']); - grunt.registerTask('build-example', ['clean:example', 'copy:example', 'ts:example', 'less:example', 'webpack:exampleDev']); - grunt.registerTask('build-app', ['copy:example', 'webpack:appDev']); - grunt.registerTask('build-js', ['tslint:src', 'ts:src']); - grunt.registerTask('build-es5', ['tslint:src', 'ts:srcES5']); - grunt.registerTask('build-jsMin', ['ts:srcMin']); - grunt.registerTask('build-spec', ['tslint:spec', 'ts:test']); - grunt.registerTask('build-specES5', ['tslint:spec', 'ts:testES5']); - - let buildTasks = ['clean:src', 'build-html', 'build-css']; - switch (type) { - case 'node': buildTasks = buildTasks.concat(['build-es5', 'copy:example']); break; - case 'util': buildTasks = buildTasks.concat(['build-js']); break; - case 'app': buildTasks = buildTasks.concat(['build-js', 'build-app']); break; - case 'lib': - default: buildTasks = buildTasks.concat(['build-js', 'build-example']); break; - } - grunt.registerTask('build', buildTasks); - grunt.registerTask('buildMin', ['build-jsMin']); - - //------ Add other MultiTasks - grunt.registerTask('make', ['build', 'test', 'doc', 'stage']); - grunt.registerTask('once', ['make']); - grunt.registerTask('default', ['make', 'watch']); - grunt.registerTask('product', ['buildMin', 'webpack:appProd', 'stage']); - - //------ Add general help - grunt.registerTask('h', 'help on grunt options', function() { - grunt.log.writeln(` grunt: \t make, then watch`); - grunt.log.writeln(` grunt once: \t make only, don't watch`); - grunt.log.writeln(` grunt make: \t build, test, doc, and stage`); - grunt.log.writeln(` grunt product: make optimized, don't watch; relevant for apps only`); - }); - - //------ Add Task Configurations - return { - pkg: grunt.file.readJSON(dir+'/package.json'), - libPath: grunt.config.process(lib).toLowerCase(), - banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + - '<%= grunt.template.today("yyyy-mm-dd") %>\n' + - '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' + - '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + - ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n', - clean: { - src: ['_dist'], - docs: ['_dist/docs'], - test: ['_dist/**/tests'], - example:['_example', '_dist/example'] - }, - copy: { - build: { expand:true, cwd:'src/', - src:['*.html'], dest:'_dist/' - }, - example:{ expand:true, cwd: 'src/example', - src:['**/*', '!**/*.ts'], dest:'_dist/example' - }, - deployLib: { files: [ - { expand:true, cwd: '_dist/src', - src:['**/*'], dest:`node_modules/${libPath}/` }, - { expand:true, cwd: './', - src:['./package.json'], dest:`node_modules/${libPath}/` } - ]}, - stageApp: { files: [ - { expand:true, cwd: '_dist/src', - src:['**/*.css*'], dest:'_dist' }, - { expand:true, cwd: './', - src:['./package.json'], dest:`node_modules/${libPath}/` } - ]}, - docs: { files: [ - { expand:true, cwd: '_dist/docs', - src:['**/*.json'], dest:`node_modules/${libPath}/docs`}, - { expand:true, cwd: './', - src:['*.md'], dest:`node_modules/${libPath}`} - ]}, - test: { files: [ - { expand:true, cwd:'_dist/', - src:['*.js', '*.css', '*.html'], dest:'_dist/test/' - }, - { cwd:'example/', expand:true, src:['*.json'], dest:'_dist/test/'} - ]} - }, - less: { - options: { - sourceMap: true - }, - css: { - files: { - '_dist/src/<%= pkg.name %>.css': 'src/css/<%= pkg.name %>.less' - } - }, - example: { - files: { - '_dist/example/<%= pkg.name %>.css': `src/example/${libPath}.less` - } - } - }, - tslint: { - options: { - configuration: __dirname+'/tslint.json', - force: false, - fix: false - }, - src: { - src: ["src/**/*.ts", "!src/**/*.spec.ts"] - }, - spec: { - src: ["src/**/*.spec.ts"] - } - }, - ts: { - src : { - outDir: "_dist/src", - src: ["src/**/*.ts", "!src/**/*.spec.ts", "!src/example/*.ts"], - tsconfig: __dirname+'/tsconfigGrunt.json' - }, - srcES5 : { - outDir: "_dist/src", - src: ["src/**/*.ts", "!src/**/*.spec.ts", "!src/example/*.ts"], - tsconfig: __dirname+'/tsconfigGruntES5.json' - }, - srcMin : { - outDir: "_dist/src", - src: ["src/**/*.ts", "!src/**/*.spec.ts", "!src/example/*.ts"], - tsconfig: __dirname+'/tsconfigProduct.json' - }, - example : { - outDir: "_example", - src: ["src/example/*.ts"], - tsconfig: __dirname+'/tsconfigGrunt.json' - }, - test : { - outDir: "_dist/tests", - src: ["src/**/*.spec.ts"], - tsconfig: __dirname+'/tsconfigGrunt.json' - }, - testES5 : { - outDir: "_dist/tests", - src: ["src/**/*.spec.ts"], - tsconfig: __dirname+'/tsconfigGruntES5.json' - } - }, - typedoc: { - code: { - options: { - target: 'es6', - module: 'commonjs', - moduleResolution: "node", - json: `_dist/docs/${lib}.json`, - out: '_dist/docs', - mode: 'modules', - name: `${lib}` - }, - src: ['src/**/*.ts'] - } - }, - jasmine_node: { - options: { forceExit: true }, - all: { - options: { - projectRoot: '_dist/tests', - coverage: { - reportDir: '_dist/docs/tests', - relativize: true, - includeAllSources: true, - report: ['html'] - }, - jasmine: { - spec_dir: '', - spec_files: [ - '_dist/tests/*.spec.js' - ] - } - }, - src: ['_dist/test/**/*.js'] - } - }, - - webpack: { - options: { - stats: !process.env.NODE_ENV || process.env.NODE_ENV === 'development' - }, - appProd: { - entry: './_dist/src/index.js', - output: { - filename: `${lib}.js`, - path: path.resolve(dir, './_dist') - }, - plugins: [ - new UglifyJsPlugin({ - uglifyOptions: { - ecma: 6, - mangle:false - } - }) - ] - }, - appDev: { - entry: './_dist/src/index.js', - devtool: "inline-source-map", - output: { - filename: `${lib}.js`, - path: path.resolve(dir, './_dist') - } - }, - - exampleProd: { - entry: './_example/example/start.js', - output: { - filename: `${lib}.js`, - path: path.resolve(dir, '_dist/example') - } - }, - exampleDev: { - entry: './_example/example/start.js', - devtool: "inline-source-map", - output: { - filename: `${lib}.js`, - path: path.resolve(dir, '_dist/example') - } - } - }, - watch: { - dependencies: { - files: dependencies.map(d => `./node_modules/${d.toLowerCase()}/index.js`), - tasks: ['make'] - }, - gruntfile: { - files: ['Gruntfile.js', __dirname+'/sharedGruntConfig.js'], - tasks: ['make'] - }, - js: { - files: ['src/**/*.ts', '!src/**/*.spec.ts', '!src/**/*.less'], - tasks: ['make'] - }, - less: { - files: ['src/**/*.less'], - tasks: ['build-css', 'stage'] - }, - html: { - files: ['src/**/*.html'], - tasks: ['build-html', 'stage'] - }, - specs: { - files: ['src/**/*.spec.ts'], - tasks: ['test'] - } - } - } -}; - diff --git a/src/Data.ts b/src/Data.ts deleted file mode 100644 index 3c83a09..0000000 --- a/src/Data.ts +++ /dev/null @@ -1,540 +0,0 @@ -/** - */ - - /** */ -import { Condition, filter } from './DataFilters'; - -/** defines a [min-max] range */ -export type NumRange = [number, number]; - -/** defines a numeric domain that includes all values of a column */ -export type NumDomain = [number, number]; - -/** defines a Date domain that includes all values of a column */ -export type DateDomain = [Date, Date]; - -/** defines a categorical domain that includes all values of a column */ -export type NameDomain = string[]; - -/** defines a generic domain that can be any of the typed domains. */ -export type Domain = NumDomain | DateDomain | NameDomain; - -/** defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array */ -export type ColumnReference = number|string; - -/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */ -export type DataVal = number|string|Date; - -/** a single row of column values */ -export type DataRow = DataVal[]; - -/** a JSON format data set, using arrays of names and rows */ -export interface DataSet { - /** an optional name for the data set */ - name?: string; - /** an array of column names. Each name matches the column with the same index in DataRow */ - colNames: string[]; - /** rows of data */ - rows: DataRow[]; -} - -/** a JSON format data set, using an array of {name:value, ...} literals*/ -export type DataLiteralSet = Array; - -interface TypeStruct { type: string; count: number;}; - -interface MetaStruct { - name: string; // column name - column: number; // column index - accessed: boolean; // has column data been accessed? - cast: boolean; // has column data been cast - types: TypeStruct[]; // data types, sorted by likelihood -} - -export type sortFn = (x:any, y:any) => number; -export type mapFn = (colVal:any, colIndex?:number, rowIndex?:number, rows?:any[][]) => any; - -/** - * # Data - * A simple in-memory database that holds data in rows of columns. - * - */ -export class Data { - //---------------------------- - // public part - //---------------------------- - public static type = { - number: 'number data', - name: 'name data', - date: 'date data', - currency: 'currency data', - percent: 'percent data', - nominal: 'nominal data' - }; - - public static toDataSet(data:DataLiteralSet, name?:string):DataSet { - data = data || [{}]; - const names = Object.keys(data[0]); - const rows = data.map((r:any) => - names.map((n:string) => r[n])); - return { rows:rows, colNames:names, name:name||undefined }; - } - - constructor(data?:DataSet) { - this.import(data); - } - - /** - * @return the `name` field for this data base, if any - */ - public getName():string { - return this.name; - } - - /** - * Imports data from an object literal `data` - * @param data the data set to import - */ - public import(data:DataSet) { - this.name = data.name; - this.setData(data.rows, data.colNames); - } - - /** - * Exports to an object literal - */ - public export():DataSet { - return { - rows: this.getData(), - colNames:this.colNames() - }; - } - - /** - * returns the 2D array underlying the data base. - */ - public getData():DataRow[] { - return this.data; - } - - /** - * Returns the values in the specified column as a new array. - * @param col the column to return. - */ - public getColumn(col:ColumnReference): DataVal[] { - const cn = this.colNumber(col); - return this.data.map((row:DataRow) => row[cn]); - } - - /** - * adds a new column to the data set. if `newCol` already exists, - * the column index is returned withoput change. - * @param col the name of the new column - * @return the index for the new column - */ - public colAdd(col:string):number { - let m = this.getMeta(col); - if (m === undefined) { - m = this.meta[col] = {}; - m.name = col; - m.column = this.meta.length; - this.meta.push(m); // access name by both column name and index - m.cast = false; // has not been cast yet - m.accessed = false; // has not been accessed yet - } - return m.column; - } - - /** - * initializes the specifed column with values, adding a new column if needed. - * If `val`is a function, it is called as ``` - * val(colValue:DataVal, rowIndex:number, row:DataRow) - * ``` - * @param col the column to initialize - * @param initializer the value to initialize with, or a function whose return - * value is used to initialize the column - */ - public colInitialize(col:ColumnReference, initializer:any) { - const cn = this.colNumber(col); - if (!cn && typeof col === 'string') { this.colAdd(col); } - const fn = typeof initializer === 'function'; - if (cn!==undefined) { - this.data.map((r:DataRow, i:number) => - r[cn] = fn? initializer(r[cn], i, r) : initializer - ); - } - } - - /** - * returns the column index of the specified column. - * `col` can be either an index or a name. - * @param column the data column, name or index, for which to return the index. - * @return the column number or `undefined`. - */ - public colNumber(col:ColumnReference) { - const m = this.getMeta(col); - if (!m) { return undefined; } - else { - m.accessed = true; - return m.column; - } - } - - /** - * returns the column name for the specified column. - * `col` can be either an index or a name. - * @param column the data column, name or index. - * @return the column name or `undefined`. - */ - public colName(col:ColumnReference) { - var m = this.getMeta(col); - if (!m) { return undefined; } - m.accessed = true; - return m.name; - } - - /** - * returns the names for all columns. - * @return an array of strings with the names. - */ - public colNames():string[] { - return this.meta.map((m:MetaStruct) => m.name); - } - - /** - * returns the column type for the specified column. - * `col` can be either an index or a name. - * @param column the data column, name or index. - * @return the column type. - */ - public colType(col:ColumnReference) { - const meta = this.getMeta(col); - return meta? meta.types[0].type : Data.type.name; - } - - /** - * modifies `domain` to include all values in column `col`. - * @param col the column name or index - * @param domain the - */ - public findDomain(col:ColumnReference, domain:Domain) { - if (col === undefined) { // use array index as domain - domain[0] = 0; - domain[1] = this.data.length-1; - } else { - const c = this.colNumber(col); - const type = this.colType(col); - if (this.data === undefined) { - console.log('no data'); - } - switch(type) { - case Data.type.nominal: - this.data.forEach((r:DataRow) => { - const nomDom = domain; - if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); } - }); - break; - default: - this.data.forEach((r:DataRow) => { - let v:number = r[c]; - if (v!==undefined && v!==null) { - domain[0] = (vdomain[1])? v : domain[1]; - } - }); - } - } - } - - public castData() { - this.meta.forEach((c:MetaStruct) => { - const col = c.column; - if (!c.cast) { - this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col])); - } - c.cast = true; - }); - } - - /** - * filters this data set and returns a new data set with a - * shallow copy of rows that pass the `condition`. - * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions. - * @param condition filters - * @return a new Data object with rows that pass the filter - */ - public filter(condition:Condition):Data { - return filter(this, condition); - } - - /** - * @description Sorts the rows of values based on the result of the `sortFn`, - * which behaves similarly to the Array.sort method. - * Two modes are supported: - * # Array Mode - * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. - * This allows for complex sorts, combining conditions across multiple columns. - * ``` - * data.sort((row1, row2) => row1[5] - row2[5] ); - * ``` - * # Column mode - * If `col` is specified, either as index or by column name, the respective column value is passed - * into `sortFn`. This allows filtering for simple conditions.
    - * **The specified column will be automatically cast prior to sorting**
    - * `data.sort('Date', function(val1, val2) { return val1 - val2; });` - * @param col optional; the data column to use for sorting. - * @param sortFn a function to implement the conditions, - * follows the same specifications as the function passed to Array.sort(). - * Some predefined sort function can be invoked by providing a - * respective string instead of a function. The following functions are defined: - - - -
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.
    - * @return the Data object in order to allow for chaining. - */ - public sort(sortFn:string|sortFn, col?:ColumnReference):Data { - let fn = sortFn; - if (!col) { - this.data.sort(fn); - } else { - col = this.colNumber(col); - if (sortFn === 'descending') { fn = (a:any, b:any) => (b>a)?1:((b (ba)?-1:0); } - this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); - } - return this; - } - - /** - * Maps one or more columns in each rows of values based - * on the result of the `mapFn`, which behaves similarly to the Array.map() method. - * Two modes are supported: - * # Array Mode - * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. - * This allows for complex mapping combining conditions across multiple columns. - * ``` - * data.map(function(values){ - * values[1] = values[3] * values[5]; - * return values; - * }); - * ``` - * Be sure to return the `values` array as a result. - * # Column mode - * If `col` is specified, either as index or by column name, the respective column value is passed - * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping. - * ``` - * data.map('Price', function(value, i, values) { - * return value * 2; - * }); - * ``` - * @param col the data column, or columns, to apply the mapping to. - * @param mapFn a function to implement the mapping, - * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where - * - `val`: the column value in the current row - * - `c`: the column index in the current row - * - `i`: the row index - * - `rows`: the rows being iterated over -` * - * follows the same specifications as the function passed to Array.map().
    - * For column mode, some predefined map functions can be invoked by providing a - * respective string instead of a function. The following functions are defined: - - - -
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.
    - * @return a new Data object containing the mapping. - */ - public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data { - const noop = (val:any) => val; - const cumulate = () => { - let sum=0; - return (val:number, i:number) => { sum += +val; return sum; }; - }; - function getFn() { - let fn; // define fn inside each col loop to ensure initialization - switch (mapFn) { - case 'cumulate': fn = cumulate(); break; - case 'noop': fn = noop; break; - default: fn = mapFn; - } - return fn; - } - - let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()}); - - const names = col['length']? col : [col]; - names.map((cn:ColumnReference) => { - const c = this.colNumber(cn); - let fn = getFn(); // define fn inside each col loop to ensure initialization - result.data = result.data.map((row:any[], i:number, rows:any[][]) => { - row[c] = fn(row[c], c, i, rows); - return row; - }); - }); - return result; - } - - //---------------------------- - // private part - //---------------------------- - private data: DataRow[] = []; - private meta: MetaStruct[] = []; - private name: string; - - private getMeta(col:ColumnReference):MetaStruct { - if (!this.meta) { this.meta = []; } - if (!this.meta[col]) { return undefined; } - this.meta[col].accessed = true; - return this.meta[col]; - } - - /** - * sets `data` to the existing data set. If data has previously been set, - * `data` will be added to the end of the list if all `names` match those of the - * existing set. - * @param data the data to add - * @param names an array of names that match the columns - * @param autoType unless set to false, the method will attempt to determine the - * type of data and automatically cast data points to their correct value - */ - private setData(data:DataRow[], names:string[], autoType=true):void { - this.meta = []; - this.data = data; - if (!names) { - console.log(); - } - names.forEach((col:string) => this.colAdd(col)); - names.forEach((col:string) => this.findTypes(col)); - this.castData(); - } - - /** - * Determines the type of data in `col`. An array of counts is created for all - * encountered types, sorted by descending frequency. THe most likely type in position 0 - * of the array is returned. - * @param col the index of the column to be typed. - * @return the most likely type of data in `col`. - */ - private findTypes(col:ColumnReference):string { - const m = this.getMeta(col); - const types:TypeStruct[] = []; - Object.keys(Data.type).forEach((t:string) => { - const ts = { type: Data.type[t], count: 0 }; - types.push(ts); - types[Data.type[t]] = ts; - }); - for (let v of this.allRows(col)) { - const t = this.findType(v); - if (t !== null) { types[t].count++; } - } - types.sort(function(a:TypeStruct, b:TypeStruct) { - if (a.type==='currency'&&a.count>0) { return -1; } - if (b.type==='currency'&&b.count>0) { return 1; } - return b.count - a.count; - }); - m.types = types; - return types[0].type; - } - - /** - * @description determines the data type. Supported types are - * ``` - * 'date': sample represents a Date, either as a Date object or a String - * 'number': sample represents a number - * 'percent': sample represents a percentage (special case of a real number) - * 'nominal': sample represents a nominal (ordinal or categorical) value - * ``` - * @param val the value to bve typed. - * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample - */ - private findType(val:DataVal) { - if (val && val!=='') { - if (val instanceof Date) { return Data.type.date; } // if val is already a date - if (typeof val === 'number') { return Data.type.number; } // if val is already a number - - // else: val is a string: - const strVal = ''+val; - if (''+parseFloat(strVal) === strVal) { return Data.type.number; } - if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; } - if (strVal.endsWith('%') && !isNaN(parseFloat(strVal))) { return Data.type.percent; } - if (!isNaN(this.toDate(strVal).getTime())) { return Data.type.date; } - - // european large number currency representation: '$dd,ddd[,ddd]' - if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { - if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { - return Data.type.currency; - } - } - switch (strVal.toLowerCase()) { - case "null": break; - case "#ref!": break; - default: if (val.length>0) { return Data.type.nominal; } - } - } - return null; - } - - /** - * A generator that provides the specified column value for each row in `Data` in sequence. - * @param column - */ - private * allRows(column:ColumnReference):Iterable { - const c = this.colNumber(column); - for (let r=0; rval; } - else { d = new Date(val); } - let yr=d.getFullYear(); - if (yr < 100) { - yr += 1900; - d.setFullYear( (yr < limitYear)? yr+100 : yr); - } - return d; - } - - /** - * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` - * does not match any of the previous keywords, no casting occurs. - * @param sample The value to cast. - * @returns The result of the cast. - * @description Casts the sample to the specified data type. - */ - private castVal(type:string, val:DataVal):DataVal { - switch (type) { - case Data.type.date: if (val instanceof Date) { return val; } - val = this.toDate(val); - if (isNaN(val.getTime())) { val = null; } - break; - case Data.type.percent: if (typeof val === 'string') { - const num = parseFloat(val); - val = (val).endsWith('%')? num/100 : num; - } - if (isNaN(val)) { val = null; } - break; - case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits - if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); } - /* falls through */ - case Data.type.number: if (typeof val === 'string') { val = parseFloat(val); } - if (isNaN(val)) { val = null; } - break; - default: val = ''+val; - } - return val; - } -} \ No newline at end of file diff --git a/src/DataFilters.ts b/src/DataFilters.ts deleted file mode 100644 index 18a2261..0000000 --- a/src/DataFilters.ts +++ /dev/null @@ -1,254 +0,0 @@ - -/** -* -* The HsData object will feature its own column meta information, as well as -* a copy of the rows array which allows for `filter` and `sort` operations. -* However, the column arrays will be shared with the original HsData object in order to be memory efficient. -* This means that `map` and `newColumn` operations on the new object will affect the original object or any -* object derived via `query`. -* @description executes a query on the data. Each row in the data is checked and those for which -* `conditions` is true are returned as a new HsData object. -* -* ## General Condition -* ``` -* Condition = -* IndexCondition -> conditions on the row index -* || RecursiveCondition -> (set of) conditions on column values -* ``` -* -* ## IndexCondition -* ``` -* IndexCondition = -* rowIndex:number -> true if row index matches -* ``` -* -* ## RecursiveCondition -* ``` -* RecursiveCondition = -* OrCondition -> OR: true if any compound condition is true -* || AndCondition -> AND: true if all compound conditions are true -* -* OrCondition = -> OR: true if -* AndCondition[] -> any of the AndConditions are true -* || IndexCondition[] -> any of thr IndexConditions are true -* -* AndCondition = -> AND: true if -* SetAndCondition -> all SetAndConditions are true -* || TermAndCondition -> or if all TermAndConditions are true -* -* SetAndCondition = { -> AND: true if all sub-conditions are true -* 'or': RecursiveCondition -> true if any RecursiveCondition is true -* || 'and': RecursiveCondition -> true if all RecursiveCondition are true -* || 'not': RecursiveCondition -> true if the condition is false -* -* TermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true -* colDesc:colValue -> true if colValue matches -* || colDesc:[colValue, ...] -> true if any of the colValues match -* || colDesc:function(value,row) -> true if function returns true -* } -* -* colDesc = either column name or index -* ``` -* -* ## Practical Tips -* ``` -* {'or': [recurCond, ...]} -> OR, same as [recurCond, ...] -* || {'or': {SetCond, ...}} -> OR, same as [SetCond, ...] -* || {'and': [recurCond, ...]} -> AND, true if all recurCond are true -* || {'and': {SetCond, ...}} -> AND, same as {SetCond, ...} -* || {'not': {SetCond, ...}} -> NAND: true if the SetCond are true -* || {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true -* ``` -* -* # Example -* -* -* const colNames = ['Name', 'Value', 'Start', 'End']; -* const rows = [ -* ['Harry', '100', '3/1/14', '11/20/14'], -* ['Mary', '1500', '7/1/14', '9/30/14'], -* ['Peter', '400', '5/20/14', '4/30/15'], -* ['Jane', '700', '11/13/14', '8/15/15'] -* ] -* const data = new hsdata.Data({colNames:colNames, rows:rows}); -* -* queries = [ -* ['0', undefined, 'undefined query => pass all'], -* ['1', [], 'empty OR: [] => fail all'], -* ['2', {}, 'empty AND: {} => pass all'], -* ['3', 1, '2nd row: pass row 1'], -* ['4', [1,3], '2nd+4th: pass rows: 1 and 3'], -* ['5', {Name:"Jane"}, 'Name is Jane'], -* ['6', {1:1500}, 'Column 2 is 1500'], -* ['7', {Name:["Peter", "Jane"]}, 'Name is Peter or Jane'], -* ['8', [{Name:"Peter"}, {Value:1500}], 'Name is Peter or Value is 1500'], -* ['9', {or:{Name:"Peter", Value:1500}}, 'OR: same as 8:'], -* ['A', {or:[{Name:"Peter"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'], -* ['B', {Name:"Peter", Value:400}, 'Name is Peter and Value is 400'], -* ['C', {and:{Name:"Peter", Value:400}}, 'AND: {Name is Peter, Value is 400}'], -* ['D', {and:{Name:"Peter", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'], -* ['E', {and:[{Name:"Peter"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'], -* ['F', {and:[{Name:"Peter"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'], -* ['G', {not:{Name:"Peter", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'], -* ['H', {not:{Name:"Peter", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'], -* ['I', {not:[{Name:"Peter"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'], -* ['J', {Name:(v) => v.length===4}, 'Name has 4 letters'] -* ]; -* -* m.mount(root, { -* view:() => m('', [ -* m('h3', 'Given the data set:'), -* m('table#data', [ -* m('tr', colNames.map(n => m('th', n))), -* ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())])) -* ]), -* m('h3', 'The following queries yield:'), -* m('table', [ -* m('tr', [m('th','#'), m('th','Query'), m('th',"Live Result, by 'Name' field")]), -* ...queries.map(q => { -* const result = data.filter(q[1]).getColumn('Name').join(', '); -* return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]); -* }) -* ]) -* ]) -* }); -* -* -* $exampleID { height: 600px; } -* #data th { width:15%; } -* table { -* font-size: 10pt; -* margin-left: 10px; -* } -* -* -*/ - -/** */ -import { Data, - DataVal, - DataRow -} from './Data'; - -export type Condition = IndexCondition | RecursiveCondition; - -/** true if row index matches the number(s) */ -export type IndexCondition = number; - -export type RecursiveCondition = AndCondition | OrCondition; -export type OrCondition = AndCondition[] | IndexCondition[]; -export type AndCondition = SetAndCondition | TermAndCondition; - -export interface SetAndCondition { - or?: RecursiveCondition; - and?:RecursiveCondition; - not?:RecursiveCondition; -}; - -export interface TermAndCondition { - [colDesc:string]: - DataVal - | DataVal[] - | TermConditionFunction - ; -}; - -export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean; - - -function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { - const col = colNumber(name); - const valIsFunction = (typeof val === 'function'); - const valIsArray = ((typeof val === 'object') && (val.length!==undefined)); - if (isNaN(col)) { - console.log(`column name '${name}' cannot be resolved in terminal condition ${name}=${val}`); - console.log(row); - return false; // -> this condition is not met; - } else if (valIsFunction) { - // query true if function evaluates to true - return val(row[col], row); - } else if (valIsArray) { - // query true if empty array, or at least one c true - return (val.length === 0) || val.some((v:any) => row[col] === v); - } else { // object: all conditions have to be met, unless specified as or - return (row[col] === val); - } -} - -/** - * applies `condition` to a row of data and returns `true` if the row passes. - * @param condition the complex condition to test against - * @param r the row index in the data set - * @param row the row values - * @param and - */ -function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and=true):boolean { - let orResult = false; - let andResult= true; - // undefined condition is TRUE - if (condition===undefined) { return true; } - - // Simple Index Condition on row index: - else if (typeof condition === 'number') { return (condition === r); } - - // Recursive Condition - OR: [...], AND {...}: - else if (typeof condition === 'object') { - // array -> or condition on a list of row indices or compound conditions - const mc = condition; - - // OR condition: [...] - if (mc.length !== undefined) { - return (mc.length === 0)? - // empty OR is false: - false : - // else: OR is true if any sub-condition is met - mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, false)); - } - // AND condition: {...} - else { - for (const name in condition) { - let conditionMet = and; // initialize with false for OR, and true for AND conjunction - const setCond = condition; - - // resolve SetConditions: - switch (name) { - case 'or': conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break; - case 'and': conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break; - case 'not': conditionMet = !resolveCondition(setCond.not, row, r, colNumber, true); break; - default: conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); - } - if (conditionMet) { orResult = true; if(!and) { break; }} // OR conjunction: exit for name loop if condition met - else { andResult = false; if(and) { break; }} // AND conjunction: exit for name loop if condition not met - } - } - } else { - console.error(`unrecognized condition: ${JSON.stringify(condition)}`); - return false; - } - return and? andResult : orResult; -} - -export type ReduceFn = (keep:boolean, row:DataRow, i:number) => void; - -export function filter(data:Data, cond:Condition, reduceFn?:string|ReduceFn):Data { - const noop = () => 0; - const colNumber = (name:string):number => data.colNumber(name); - let fn:ReduceFn; - switch (reduceFn) { - default: fn = (typeof reduceFn === 'function')? reduceFn : noop; - } - try { - return new Data({ - name: data.getName(), - colNames: data.colNames(), - rows:data.getData().filter((row:DataRow, i:number) => { - const keep = resolveCondition(cond, row, i, colNumber); - if (fn) { fn(keep, row, i); } - return keep; - }) - }); - } catch(err) { - console.log(err); - console.log(err.stack); - } -} diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index d2b3579..0000000 --- a/src/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -export { NumRange, - NumDomain, - DateDomain, - NameDomain, - Domain, - ColumnReference, - DataVal, - DataRow, - DataSet - } from './Data'; - -export { Data } from './Data'; -export { Condition} from './DataFilters'; - diff --git a/src/overview.ts b/src/overview.ts deleted file mode 100644 index 2c6f1a7..0000000 --- a/src/overview.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * # hsData - * - * Helpful Scripts data management functions that are framework independent. - * - * ## Data Types - * -   {@link Data.NumRange NumRange} defines a single [min, max] numeric range. - * -   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column - * -   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column - * -   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column - * -   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains. - * -   {@link Data.ColSpecifier ColSpecifier} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array - * -   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array - * -   {@link Data.DataRow DataRow} a single row of column values - * - * ## Data Class - * -   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions - */ - - /** */ - - diff --git a/tsconfigGrunt.json b/tsconfigGrunt.json deleted file mode 100644 index 0135a6d..0000000 --- a/tsconfigGrunt.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "es6", - "rootDir": "./src", - "moduleResolution": "node", - "inlineSourceMap": true, - "removeComments": true, - "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true, - "declaration": true - }, - "compileOnSave": true, - "include": [], - "exclude": ["**/node_modules"] -} diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 5694204..0000000 --- a/tslint.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "rules": { - "no-unused-expression": true, - "no-duplicate-variable": true, - "no-unused-variable": true, - "curly": true, - "class-name": true, - "semicolon": ["always"], - "triple-equals": true - } -} \ No newline at end of file From 41b9b123c8b77f71ef2fb78e50dc829d11a62a48 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 2 Jun 2018 22:12:18 -0700 Subject: [PATCH 02/17] centralized docs --- docs/example/defEquityList.json | 10 - docs/example/equityList.json | 10 - docs/example/hsGraph.js | 10647 -------------- docs/example/hsLayout.css | 88 - docs/example/hsLayout.css.map | 1 - docs/example/hsLayout.js | 6527 --------- docs/example/hsWidget.js | 6867 --------- docs/example/index.json | 13 - docs/example/layout.html | 11 - docs/example/search.json | 6 - docs/hsDoc.css | 1062 -- docs/hsDoc.js | 12128 ---------------- docs/index.html | 11 - docs/indexGH.html | 11 + docs/src/hsData/Data.html | 557 - docs/src/hsData/DataFilters.html | 272 - docs/src/hsData/DataTypes.html | 48 - docs/src/hsData/index.html | 32 - docs/src/hsData/overview.html | 40 - docs/src/hsDoc/DocSets.html | 168 - docs/src/hsDoc/Site.html | 78 - docs/src/hsDoc/index.html | 27 - docs/src/hsDoc/markdown.html | 100 - docs/src/hsDoc/overview.html | 161 - docs/src/hsDoc/view/DocsMenu.html | 56 - docs/src/hsDoc/view/LeftNav.html | 171 - docs/src/hsDoc/view/MainComment.html | 171 - docs/src/hsDoc/view/MainDetail.html | 181 - docs/src/hsDoc/view/MainExample.html | 285 - docs/src/hsDoc/view/MainExample.spec.html | 33 - docs/src/hsDoc/view/Parts.html | 218 - docs/src/hsDoc/view/Tooltip.html | 25 - docs/src/hsGraph/Axes.html | 450 - docs/src/hsGraph/AxesCfg.html | 234 - docs/src/hsGraph/AxesDefaultCfg.html | 181 - docs/src/hsGraph/AxesTypes.html | 110 - docs/src/hsGraph/Canvas.html | 89 - docs/src/hsGraph/Chart.html | 148 - docs/src/hsGraph/Config.html | 40 - docs/src/hsGraph/Data.html | 351 - docs/src/hsGraph/Graph.html | 404 - docs/src/hsGraph/Grid.html | 139 - docs/src/hsGraph/Legend.html | 73 - docs/src/hsGraph/Plot.html | 106 - docs/src/hsGraph/PlotArea.html | 105 - docs/src/hsGraph/PlotBar.html | 115 - docs/src/hsGraph/PlotLine.html | 68 - docs/src/hsGraph/PlotMarkers.html | 71 - docs/src/hsGraph/SVGElem.html | 312 - docs/src/hsGraph/Scale.html | 299 - docs/src/hsGraph/Series.html | 380 - docs/src/hsGraph/SeriesLine.html | 18 - docs/src/hsGraph/example/start.html | 19 - docs/src/hsGraph/hsGraph.html | 182 - docs/src/hsGraph/index.html | 26 - docs/src/hsGraph/overview.html | 94 - docs/src/hsLayout/example/columns.x.html | 88 - docs/src/hsLayout/example/config.x.html | 82 - docs/src/hsLayout/example/layout.x.html | 138 - docs/src/hsLayout/example/start.html | 19 - docs/src/hsLayout/hsConfig.html | 274 - docs/src/hsLayout/index.html | 31 - docs/src/hsLayout/mithril.html | 43 - docs/src/hsLayout/overview.html | 95 - docs/src/hsLayout/view/Container.html | 159 - docs/src/hsLayout/view/Layout.html | 153 - docs/src/hsLayout/view/Layouter.html | 148 - docs/src/hsLayout/view/PillaredLayout.html | 359 - .../hsLayout/view/PillaredLayout.spec.html | 101 - docs/src/hsLayout/view/PillaredLayouter.html | 360 - .../hsLayout/view/PillaredLayouter.spec.html | 101 - docs/src/hsLayout/view/TileLayout.html | 156 - docs/src/hsLayout/view/TileLayouter.html | 180 - docs/src/hsLayout/view/Tokens.html | 75 - docs/src/hsNode/cpUtil.html | 59 - docs/src/hsNode/cpUtil.spec.html | 80 - docs/src/hsNode/date.html | 89 - docs/src/hsNode/date.spec.html | 59 - docs/src/hsNode/excel.html | 282 - docs/src/hsNode/excel.spec.html | 152 - docs/src/hsNode/fsUtil.html | 307 - docs/src/hsNode/fsUtil.spec.html | 571 - docs/src/hsNode/httpUtil.html | 75 - docs/src/hsNode/index.html | 30 - docs/src/hsNode/log.html | 308 - docs/src/hsNode/log.spec.html | 149 - docs/src/hsNode/node.html | 72 - docs/src/hsNode/node.spec.html | 75 - docs/src/hsStock/Home.html | 65 - docs/src/hsStock/Router.html | 82 - docs/src/hsStock/Site.html | 70 - docs/src/hsStock/controller/Assets.html | 78 - docs/src/hsStock/controller/Equities.html | 195 - docs/src/hsStock/controller/Equity.html | 493 - docs/src/hsStock/controller/EquityList.html | 120 - docs/src/hsStock/controller/EquityLoader.html | 345 - docs/src/hsStock/controller/Loader.html | 18 - docs/src/hsStock/controller/Trader.html | 325 - docs/src/hsStock/controller/TraderIEX.html | 311 - docs/src/hsStock/controller/Venue.html | 68 - docs/src/hsStock/controller/VenueIEX.html | 416 - docs/src/hsStock/fileIO.html | 49 - docs/src/hsStock/index.html | 25 - docs/src/hsStock/overview.html | 23 - docs/src/hsStock/saveToFile.html | 36 - .../hsStock/server/convertInvestments.html | 20 - docs/src/hsStock/view/Equity.html | 242 - docs/src/hsStock/view/Header.html | 31 - docs/src/hsStock/view/Import.html | 71 - docs/src/hsStock/view/ImportPane.html | 65 - docs/src/hsStock/view/LeftNav.html | 45 - docs/src/hsStock/view/Main.html | 85 - docs/src/hsStock/view/MainDetails.html | 145 - docs/src/hsStock/view/MainGraph.html | 121 - docs/src/hsStock/view/MainMenu.html | 31 - docs/src/hsStock/view/Modal.html | 31 - docs/src/hsStock/view/SiteMenu.html | 31 - docs/src/hsStock/view/StockQuotes.html | 103 - docs/src/hsStock/view/Trade.html | 24 - docs/src/hsStock/view/TradePane.html | 128 - docs/src/hsStock/view/Trader.html | 110 - docs/src/hsStock/view/TraderIEX.html | 281 - docs/src/hsStock/view/View.html | 87 - docs/src/hsStock/view/ViewLeft.html | 149 - docs/src/hsStock/view/ViewPane.html | 45 - docs/src/hsUtil/Checksum.html | 33 - docs/src/hsUtil/Date.html | 95 - docs/src/hsUtil/Number.html | 34 - docs/src/hsUtil/PacingQueue.html | 63 - docs/src/hsUtil/TimedPromise.html | 46 - docs/src/hsUtil/hsChecksum.html | 33 - docs/src/hsUtil/hsTimedPromise.html | 46 - docs/src/hsUtil/hsUtil.html | 52 - docs/src/hsUtil/index.html | 24 - docs/src/hsUtil/overview.html | 30 - docs/src/hsUtil/showdown.html | 24 - docs/src/hsWidget/AddRemove.html | 48 - docs/src/hsWidget/Button.html | 74 - docs/src/hsWidget/Collapsible.html | 93 - docs/src/hsWidget/CornerButton.html | 120 - docs/src/hsWidget/DropOver.html | 87 - docs/src/hsWidget/Menu.html | 83 - docs/src/hsWidget/Menu.spec.html | 66 - docs/src/hsWidget/Modal.html | 68 - docs/src/hsWidget/OneOfButtons.html | 39 - docs/src/hsWidget/RadioButton.html | 89 - docs/src/hsWidget/Selector.html | 177 - docs/src/hsWidget/ToggleButton.html | 99 - docs/src/hsWidget/ToolbarButton.html | 147 - docs/src/hsWidget/TypeAhead.html | 150 - docs/src/hsWidget/example/start.html | 19 - docs/src/hsWidget/index.html | 38 - docs/src/hsWidget/overview.html | 192 - docs/src/hsWidgets/AddRemove.html | 36 - docs/src/hsWidgets/Button.html | 32 - docs/src/hsWidgets/Collapsible.html | 54 - docs/src/hsWidgets/Menu.html | 142 - docs/src/hsWidgets/Menu.spec.html | 66 - docs/src/hsWidgets/Modal.html | 32 - docs/src/hsWidgets/css/Button.html | 32 - docs/src/hsWidgets/example/start.html | 19 - docs/src/hsWidgets/index.html | 27 - docs/src/hsWidgets/overview.html | 28 - 163 files changed, 11 insertions(+), 55989 deletions(-) delete mode 100644 docs/example/defEquityList.json delete mode 100644 docs/example/equityList.json delete mode 100644 docs/example/hsGraph.js delete mode 100644 docs/example/hsLayout.css delete mode 100644 docs/example/hsLayout.css.map delete mode 100644 docs/example/hsLayout.js delete mode 100644 docs/example/hsWidget.js delete mode 100644 docs/example/index.json delete mode 100644 docs/example/layout.html delete mode 100644 docs/example/search.json delete mode 100644 docs/hsDoc.css delete mode 100644 docs/hsDoc.js delete mode 100644 docs/index.html create mode 100644 docs/indexGH.html delete mode 100644 docs/src/hsData/Data.html delete mode 100644 docs/src/hsData/DataFilters.html delete mode 100644 docs/src/hsData/DataTypes.html delete mode 100644 docs/src/hsData/index.html delete mode 100644 docs/src/hsData/overview.html delete mode 100644 docs/src/hsDoc/DocSets.html delete mode 100644 docs/src/hsDoc/Site.html delete mode 100644 docs/src/hsDoc/index.html delete mode 100644 docs/src/hsDoc/markdown.html delete mode 100644 docs/src/hsDoc/overview.html delete mode 100644 docs/src/hsDoc/view/DocsMenu.html delete mode 100644 docs/src/hsDoc/view/LeftNav.html delete mode 100644 docs/src/hsDoc/view/MainComment.html delete mode 100644 docs/src/hsDoc/view/MainDetail.html delete mode 100644 docs/src/hsDoc/view/MainExample.html delete mode 100644 docs/src/hsDoc/view/MainExample.spec.html delete mode 100644 docs/src/hsDoc/view/Parts.html delete mode 100644 docs/src/hsDoc/view/Tooltip.html delete mode 100644 docs/src/hsGraph/Axes.html delete mode 100644 docs/src/hsGraph/AxesCfg.html delete mode 100644 docs/src/hsGraph/AxesDefaultCfg.html delete mode 100644 docs/src/hsGraph/AxesTypes.html delete mode 100644 docs/src/hsGraph/Canvas.html delete mode 100644 docs/src/hsGraph/Chart.html delete mode 100644 docs/src/hsGraph/Config.html delete mode 100644 docs/src/hsGraph/Data.html delete mode 100644 docs/src/hsGraph/Graph.html delete mode 100644 docs/src/hsGraph/Grid.html delete mode 100644 docs/src/hsGraph/Legend.html delete mode 100644 docs/src/hsGraph/Plot.html delete mode 100644 docs/src/hsGraph/PlotArea.html delete mode 100644 docs/src/hsGraph/PlotBar.html delete mode 100644 docs/src/hsGraph/PlotLine.html delete mode 100644 docs/src/hsGraph/PlotMarkers.html delete mode 100644 docs/src/hsGraph/SVGElem.html delete mode 100644 docs/src/hsGraph/Scale.html delete mode 100644 docs/src/hsGraph/Series.html delete mode 100644 docs/src/hsGraph/SeriesLine.html delete mode 100644 docs/src/hsGraph/example/start.html delete mode 100644 docs/src/hsGraph/hsGraph.html delete mode 100644 docs/src/hsGraph/index.html delete mode 100644 docs/src/hsGraph/overview.html delete mode 100644 docs/src/hsLayout/example/columns.x.html delete mode 100644 docs/src/hsLayout/example/config.x.html delete mode 100644 docs/src/hsLayout/example/layout.x.html delete mode 100644 docs/src/hsLayout/example/start.html delete mode 100644 docs/src/hsLayout/hsConfig.html delete mode 100644 docs/src/hsLayout/index.html delete mode 100644 docs/src/hsLayout/mithril.html delete mode 100644 docs/src/hsLayout/overview.html delete mode 100644 docs/src/hsLayout/view/Container.html delete mode 100644 docs/src/hsLayout/view/Layout.html delete mode 100644 docs/src/hsLayout/view/Layouter.html delete mode 100644 docs/src/hsLayout/view/PillaredLayout.html delete mode 100644 docs/src/hsLayout/view/PillaredLayout.spec.html delete mode 100644 docs/src/hsLayout/view/PillaredLayouter.html delete mode 100644 docs/src/hsLayout/view/PillaredLayouter.spec.html delete mode 100644 docs/src/hsLayout/view/TileLayout.html delete mode 100644 docs/src/hsLayout/view/TileLayouter.html delete mode 100644 docs/src/hsLayout/view/Tokens.html delete mode 100644 docs/src/hsNode/cpUtil.html delete mode 100644 docs/src/hsNode/cpUtil.spec.html delete mode 100644 docs/src/hsNode/date.html delete mode 100644 docs/src/hsNode/date.spec.html delete mode 100644 docs/src/hsNode/excel.html delete mode 100644 docs/src/hsNode/excel.spec.html delete mode 100644 docs/src/hsNode/fsUtil.html delete mode 100644 docs/src/hsNode/fsUtil.spec.html delete mode 100644 docs/src/hsNode/httpUtil.html delete mode 100644 docs/src/hsNode/index.html delete mode 100644 docs/src/hsNode/log.html delete mode 100644 docs/src/hsNode/log.spec.html delete mode 100644 docs/src/hsNode/node.html delete mode 100644 docs/src/hsNode/node.spec.html delete mode 100644 docs/src/hsStock/Home.html delete mode 100644 docs/src/hsStock/Router.html delete mode 100644 docs/src/hsStock/Site.html delete mode 100644 docs/src/hsStock/controller/Assets.html delete mode 100644 docs/src/hsStock/controller/Equities.html delete mode 100644 docs/src/hsStock/controller/Equity.html delete mode 100644 docs/src/hsStock/controller/EquityList.html delete mode 100644 docs/src/hsStock/controller/EquityLoader.html delete mode 100644 docs/src/hsStock/controller/Loader.html delete mode 100644 docs/src/hsStock/controller/Trader.html delete mode 100644 docs/src/hsStock/controller/TraderIEX.html delete mode 100644 docs/src/hsStock/controller/Venue.html delete mode 100644 docs/src/hsStock/controller/VenueIEX.html delete mode 100644 docs/src/hsStock/fileIO.html delete mode 100644 docs/src/hsStock/index.html delete mode 100644 docs/src/hsStock/overview.html delete mode 100644 docs/src/hsStock/saveToFile.html delete mode 100644 docs/src/hsStock/server/convertInvestments.html delete mode 100644 docs/src/hsStock/view/Equity.html delete mode 100644 docs/src/hsStock/view/Header.html delete mode 100644 docs/src/hsStock/view/Import.html delete mode 100644 docs/src/hsStock/view/ImportPane.html delete mode 100644 docs/src/hsStock/view/LeftNav.html delete mode 100644 docs/src/hsStock/view/Main.html delete mode 100644 docs/src/hsStock/view/MainDetails.html delete mode 100644 docs/src/hsStock/view/MainGraph.html delete mode 100644 docs/src/hsStock/view/MainMenu.html delete mode 100644 docs/src/hsStock/view/Modal.html delete mode 100644 docs/src/hsStock/view/SiteMenu.html delete mode 100644 docs/src/hsStock/view/StockQuotes.html delete mode 100644 docs/src/hsStock/view/Trade.html delete mode 100644 docs/src/hsStock/view/TradePane.html delete mode 100644 docs/src/hsStock/view/Trader.html delete mode 100644 docs/src/hsStock/view/TraderIEX.html delete mode 100644 docs/src/hsStock/view/View.html delete mode 100644 docs/src/hsStock/view/ViewLeft.html delete mode 100644 docs/src/hsStock/view/ViewPane.html delete mode 100644 docs/src/hsUtil/Checksum.html delete mode 100644 docs/src/hsUtil/Date.html delete mode 100644 docs/src/hsUtil/Number.html delete mode 100644 docs/src/hsUtil/PacingQueue.html delete mode 100644 docs/src/hsUtil/TimedPromise.html delete mode 100644 docs/src/hsUtil/hsChecksum.html delete mode 100644 docs/src/hsUtil/hsTimedPromise.html delete mode 100644 docs/src/hsUtil/hsUtil.html delete mode 100644 docs/src/hsUtil/index.html delete mode 100644 docs/src/hsUtil/overview.html delete mode 100644 docs/src/hsUtil/showdown.html delete mode 100644 docs/src/hsWidget/AddRemove.html delete mode 100644 docs/src/hsWidget/Button.html delete mode 100644 docs/src/hsWidget/Collapsible.html delete mode 100644 docs/src/hsWidget/CornerButton.html delete mode 100644 docs/src/hsWidget/DropOver.html delete mode 100644 docs/src/hsWidget/Menu.html delete mode 100644 docs/src/hsWidget/Menu.spec.html delete mode 100644 docs/src/hsWidget/Modal.html delete mode 100644 docs/src/hsWidget/OneOfButtons.html delete mode 100644 docs/src/hsWidget/RadioButton.html delete mode 100644 docs/src/hsWidget/Selector.html delete mode 100644 docs/src/hsWidget/ToggleButton.html delete mode 100644 docs/src/hsWidget/ToolbarButton.html delete mode 100644 docs/src/hsWidget/TypeAhead.html delete mode 100644 docs/src/hsWidget/example/start.html delete mode 100644 docs/src/hsWidget/index.html delete mode 100644 docs/src/hsWidget/overview.html delete mode 100644 docs/src/hsWidgets/AddRemove.html delete mode 100644 docs/src/hsWidgets/Button.html delete mode 100644 docs/src/hsWidgets/Collapsible.html delete mode 100644 docs/src/hsWidgets/Menu.html delete mode 100644 docs/src/hsWidgets/Menu.spec.html delete mode 100644 docs/src/hsWidgets/Modal.html delete mode 100644 docs/src/hsWidgets/css/Button.html delete mode 100644 docs/src/hsWidgets/example/start.html delete mode 100644 docs/src/hsWidgets/index.html delete mode 100644 docs/src/hsWidgets/overview.html diff --git a/docs/example/defEquityList.json b/docs/example/defEquityList.json deleted file mode 100644 index 4e1244a..0000000 --- a/docs/example/defEquityList.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Stocks": { - "GOOG": "Alphabet", - "MSFT": "Microsoft", - "AAPL": "Apple" - }, - "Bonds": {}, - "ETFs": {}, - "Indices":{} -} \ No newline at end of file diff --git a/docs/example/equityList.json b/docs/example/equityList.json deleted file mode 100644 index 4e1244a..0000000 --- a/docs/example/equityList.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Stocks": { - "GOOG": "Alphabet", - "MSFT": "Microsoft", - "AAPL": "Apple" - }, - "Bonds": {}, - "ETFs": {}, - "Indices":{} -} \ No newline at end of file diff --git a/docs/example/hsGraph.js b/docs/example/hsGraph.js deleted file mode 100644 index c3e4b83..0000000 --- a/docs/example/hsGraph.js +++ /dev/null @@ -1,10647 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__view_PillaredLayouter__ = __webpack_require__(21); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__view_TileLayouter__ = __webpack_require__(22); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__view_Layout__ = __webpack_require__(23); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Layout", function() { return __WEBPACK_IMPORTED_MODULE_2__view_Layout__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__view_Tokens__ = __webpack_require__(4); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "FILL", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["b"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "px", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["g"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "pc", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["f"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "LayoutToken", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["d"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__view_Layouter__ = __webpack_require__(3); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Layouter", function() { return __WEBPACK_IMPORTED_MODULE_4__view_Layouter__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__hsConfig__ = __webpack_require__(36); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "HsConfig", function() { return __WEBPACK_IMPORTED_MODULE_5__hsConfig__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__mithril__ = __webpack_require__(7); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "m", function() { return __WEBPACK_IMPORTED_MODULE_6__mithril__["a"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "o", function() { return __WEBPACK_IMPORTED_MODULE_6__mithril__["b"]; }); - -if (__WEBPACK_IMPORTED_MODULE_0__view_PillaredLayouter__) { } - -if (__WEBPACK_IMPORTED_MODULE_1__view_TileLayouter__) { } - - - - - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxLQUFLLE9BQU8sTUFBVSx5QkFBeUIsQ0FBQztBQUFNLElBQUcsT0FBTyxFQUFFLEdBQUU7QUFDM0UsT0FBTyxLQUFLLEtBQUssTUFBWSxxQkFBcUIsQ0FBQztBQUFVLElBQUcsS0FBSyxFQUFFLEdBQUU7QUFFekUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFTLGVBQWUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQ1osV0FBVyxFQUFFLE1BQU8sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBVSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVUsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxDQUFDLEVBQVMsQ0FBQyxFQUFFLE1BQU8sV0FBVyxDQUFBIn0= - -/***/ }), -/* 1 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["d"] = round; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return TextHAlign; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return TextVAlign; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); - -function round(num) { - const result = num.toFixed(1); - if (result === 'Infinity') { - return '1e20'; - } - return result; -} -var TextHAlign; -(function (TextHAlign) { - TextHAlign["start"] = "start"; - TextHAlign["middle"] = "middle"; - TextHAlign["end"] = "end"; -})(TextHAlign || (TextHAlign = {})); -var TextVAlign; -(function (TextVAlign) { - TextVAlign["top"] = "top"; - TextVAlign["center"] = "center"; - TextVAlign["bottom"] = "bottom"; -})(TextVAlign || (TextVAlign = {})); -class SVGElem { - text(cfg, text) { - let yShift = 0; - let hAlign = cfg.xpos; - switch (cfg.xpos) { - case TextHAlign.start: break; - case TextHAlign.end: break; - case TextHAlign.middle: - default: - hAlign = TextHAlign.middle; - break; - } - switch (cfg.ypos) { - case TextVAlign.top: - yShift = 0.7; - break; - case TextVAlign.center: - yShift = 0.35; - break; - case TextVAlign.bottom: - default: - yShift = 0; - break; - } - const param = { - x: cfg.x || '', - y: cfg.y || '', - dx: round(cfg.hOffset || 0) + 'em', - dy: round((cfg.vOffset || 0) + yShift) + 'em', - style: `text-anchor:${hAlign}; ${cfg.style || ''}`, - class: cfg.cssClass, - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('text', param, text); - } - rect(tl, area, style, title) { - if (area.w < 0) { - tl.x += area.w; - area.w = -area.w; - } - if (area.h < 0) { - tl.y += area.h; - area.h = -area.h; - } - const param = { - x: round(tl.x), y: round(tl.y), - width: round(area.w) + (area.wunit || ''), - height: round(area.h) + (area.hunit || ''), - style: style - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('rect', param), Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title); - } - circle(c, r, style, title) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('circle', { cx: round(c.x), cy: round(c.y), r: round(r), style: style }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); - } - clipRect(tl, area, id) { - const param = { - x: round(tl.x), y: round(tl.y), - width: round(area.w) + (area.wunit || ''), - height: round(area.h) + (area.hunit || '') - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('defs', Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('clipPath', { id: id }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('rect', param))); - } - line(x0, x1, y0, y1, cssClass) { - const param = { - x1: round(x0), y1: round(y0), - x2: round(x1), y2: round(y1), - class: cssClass - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); - } - horLine(x0, x1, y, cssClass) { - const param = { - x1: round(x0), y1: round(y), - x2: round(x1), y2: round(y), - class: cssClass - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); - } - verLine(x, y0, y1, cssClass) { - const param = { - x1: round(x), y1: round(y0), - x2: round(x), y2: round(y1), - class: cssClass - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); - } - polyline(data, x, y, scales, id, style, title) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polyline', { - 'clip-path': id ? `url(#${id})` : undefined, - style: style, - points: data.map((row) => `${round(scales.x.convert(row[x]))},${round(scales.y.convert(row[y]))}`).join(' ') - }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); - } - polygon(dataFore, dataBack, x, yFore, yBack, scales, id, style, title) { - const indexed = (x === undefined); - const sx = (_x) => round(scales.x.convert(_x)); - const sy = (_y) => round(scales.y.convert(_y)); - const clip = id ? `url(#${id})` : undefined; - const points = dataFore.map((row, i) => `${sx(indexed ? i : row[x])},${sy(row[yFore])}`) - .concat(dataBack.map((row, i) => `${sx(indexed ? (dataBack.length - i - 1) : row[x])},${sy(yBack ? row[yBack] : 0)}`)).join(' '); - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polygon', { 'clip-path': clip, style: style, points: points }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); - } - shape(points, id, style, title) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polyline', { - 'clip-path': id ? `url(#${id})` : undefined, - style: style, - points: points.map((row) => `${round(row[0])},${round(row[1])}`).join(' ') - }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = SVGElem; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU1ZHRWxlbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9TVkdFbGVtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxDQUFDLEVBQVMsTUFBTSxVQUFVLENBQUM7QUF3RXBDLE1BQU0sZ0JBQWlCLEdBQVU7SUFDN0IsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QixJQUFJLE1BQU0sS0FBSyxVQUFVLEVBQUU7UUFDdkIsT0FBTyxNQUFNLENBQUM7S0FDakI7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNsQixDQUFDO0FBRUQsTUFBTSxDQUFOLElBQVksVUFJWDtBQUpELFdBQVksVUFBVTtJQUNsQiw2QkFBaUIsQ0FBQTtJQUNqQiwrQkFBa0IsQ0FBQTtJQUNsQix5QkFBZSxDQUFBO0FBQ25CLENBQUMsRUFKVyxVQUFVLEtBQVYsVUFBVSxRQUlyQjtBQUVELE1BQU0sQ0FBTixJQUFZLFVBSVg7QUFKRCxXQUFZLFVBQVU7SUFDbEIseUJBQWUsQ0FBQTtJQUNmLCtCQUFrQixDQUFBO0lBQ2xCLCtCQUFrQixDQUFBO0FBQ3RCLENBQUMsRUFKVyxVQUFVLEtBQVYsVUFBVSxRQUlyQjtBQUVELE1BQU07SUFNRixJQUFJLENBQUMsR0FBWSxFQUFFLElBQVc7UUFDMUIsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ2YsSUFBSSxNQUFNLEdBQWMsR0FBRyxDQUFDLElBQUksQ0FBQztRQUNqQyxRQUFPLEdBQUcsQ0FBQyxJQUFJLEVBQUU7WUFDYixLQUFLLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBRSxNQUFNO1lBQzlCLEtBQUssVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFJLE1BQU07WUFDOUIsS0FBSyxVQUFVLENBQUMsTUFBTSxDQUFDO1lBQ3ZCO2dCQUFlLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDO2dCQUFDLE1BQU07U0FDcEQ7UUFDRCxRQUFPLEdBQUcs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 - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1,eval)("this"); -} catch(e) { - // This works if the window reference is available - if(typeof window === "object") - g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), -/* 3 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Tokens__ = __webpack_require__(4); - -class Layouter { - constructor(areaDesc) { - this.areaDesc = areaDesc; - this.spacing = 0; - } - static translate(params) { - if (params.length === 0) { - params.push(''); - } - return params.map((param) => { - if (typeof param === 'string') { - if (param.endsWith('px')) { - return Object(__WEBPACK_IMPORTED_MODULE_0__Tokens__["g" /* px */])(parseInt(param)); - } - if (param.endsWith('%')) { - return Object(__WEBPACK_IMPORTED_MODULE_0__Tokens__["f" /* pc */])(parseInt(param)); - } - if (param.toLowerCase() === 'fill') { - return __WEBPACK_IMPORTED_MODULE_0__Tokens__["b" /* FILL */]; - } - } - else { - return param; - } - }); - } - static register(keyword, style) { - Layouter.layoutStyles[keyword] = style; - } - static createLayout(attrs, components) { - let css = ''; - Object.keys(Layouter.layoutStyles).some(key => { - if (attrs[key]) { - css = new Layouter.layoutStyles[key](Layouter.translate(attrs[key])).getStyles(components); - attrs[key] = undefined; - return true; - } - return false; - }); - return css; - } - ; -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Layouter; - -Layouter.layoutStyles = {}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5b3V0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdmlldy9MYXlvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFhQSxPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxVQUFVLENBQUM7QUF5QnhDLE1BQU07SUF5RUYsWUFBbUIsUUFBc0I7UUFBdEIsYUFBUSxHQUFSLFFBQVEsQ0FBYztRQVJ6QyxZQUFPLEdBQUcsQ0FBQyxDQUFDO0lBUWdDLENBQUM7SUF6RHJDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBd0I7UUFDN0MsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7U0FBRTtRQUM3QyxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFnQixFQUFFLEVBQUU7WUFDbkMsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUU7Z0JBQzNCLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRTtvQkFBRSxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFBRTtnQkFDekQsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO29CQUFFLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO2lCQUFFO2dCQUN4RCxJQUFJLEtBQUssQ0FBQyxXQUFXLEVBQUUsS0FBRyxNQUFNLEVBQUU7b0JBQUUsT0FBTyxJQUFJLENBQUM7aUJBQUM7YUFDcEQ7aUJBQU07Z0JBQ0gsT0FBTyxLQUFLLENBQUM7YUFDaEI7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFXTSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQWMsRUFBRSxLQUFxQjtRQUV4RCxRQUFRLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUMzQyxDQUFDO0lBVU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxLQUFTLEVBQUUsVUFBdUI7UUFDekQsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBQ2IsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQzFDLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUNaLEdBQUcsR0FBRyxJQUFJLFFBQVEsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDM0YsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsQ0FBQztnQkFDdkIsT0FBTyxJQUFJLENBQUM7YUFDZjtZQUNELE9BQU8sS0FBSyxDQUFDO1FBQ2pCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0lBVzRDLENBQUM7O0FBcEV2QyxxQkFBWSxHQUF1QixFQUFFLENBQUMifQ== - -/***/ }), -/* 4 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["g"] = px; -/* harmony export (immutable) */ __webpack_exports__["f"] = pc; -class LayoutToken { - constructor(size) { - this.size = size; - } - getSize() { return this.size; } -} -/* harmony export (immutable) */ __webpack_exports__["d"] = LayoutToken; - -class DefinedToken extends LayoutToken { - constructor(size) { super(size); } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = DefinedToken; - -class FillToken extends LayoutToken { - constructor() { super(-1); } -} -/* harmony export (immutable) */ __webpack_exports__["c"] = FillToken; - -class PixelToken extends DefinedToken { - constructor(size) { super(size); } -} -/* harmony export (immutable) */ __webpack_exports__["e"] = PixelToken; - -class PercentToken extends DefinedToken { - constructor(size) { super(size); } -} -/* unused harmony export PercentToken */ - -function px(px) { return new PixelToken(px); } -function pc(pc) { return new PercentToken(pc); } -const FILL = new FillToken(); -/* harmony export (immutable) */ __webpack_exports__["b"] = FILL; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9rZW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvVG9rZW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE1BQU07SUFDRixZQUFvQixJQUFZO1FBQVosU0FBSSxHQUFKLElBQUksQ0FBUTtJQUFHLENBQUM7SUFDN0IsT0FBTyxLQUFLLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Q0FDekM7QUFLRCxNQUFNLG1CQUE2QixTQUFRLFdBQVc7SUFDbEQsWUFBWSxJQUFZLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUM3QztBQUtELE1BQU0sZ0JBQWlCLFNBQVEsV0FBVztJQUN0QyxnQkFBZ0IsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0NBQy9CO0FBS0QsTUFBTSxpQkFBa0IsU0FBUSxZQUFZO0lBQ3hDLFlBQVksSUFBVyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Q0FDNUM7QUFLRCxNQUFNLG1CQUFvQixTQUFRLFlBQVk7SUFDMUMsWUFBWSxJQUFXLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUM1QztBQU1ELE1BQU0sYUFBYSxFQUFTLElBQU0sT0FBTyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFNOUQsTUFBTSxhQUFhLEVBQVMsSUFBTSxPQUFPLElBQUksWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUtoRSxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQyJ9 - -/***/ }), -/* 5 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); - -; - -function getCrossAt(cross, scale) { - let crossesAt; - switch (cross) { - case 'min': - crossesAt = scale.domain()[0]; - break; - case 'max': - crossesAt = scale.domain()[1]; - break; - default: crossesAt = cross || 0; - } - return scale.convert(crossesAt); -} -class Axes extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { - static defaultConfig(cfg) { - function scaleCfg() { - return { - type: Axes.type.linear, - domain: ['auto', 'auto'] - }; - } - function labelCfg(primary, x, major) { - return { - visible: major, text: '', - xpos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].end : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].start), - ypos: x ? (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].bottom) : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].center, - hOffset: x ? 0 : (primary ? -0.7 : 0.7), - vOffset: x ? (primary ? 0.7 : -0.7) : 0 - }; - } - function markCfg(primary, major) { - return { - visible: major, - length: (primary ? 1 : -1) * (major ? 10 : 5) - }; - } - function titleCfg(primary, x) { - return { - visible: true, text: (x ? 'x' : 'y') + (primary ? '' : '2'), - xpos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].end : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].start), - ypos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].bottom : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top), - hOffset: x ? -2 : (primary ? 0 : 0.3), - vOffset: x ? (primary ? 0.4 : -1.2) : (primary ? -0.5 : 0.7) - }; - } - function axisCfg(primary, x) { - return { - visible: primary ? true : false, - crossesAt: primary ? 'min' : 'max', - scale: scaleCfg(), - title: titleCfg(primary, x), - ticks: { - major: { - marks: markCfg(primary, true), - labels: labelCfg(primary, x, true), - labelFmt: undefined - }, - minor: { - marks: markCfg(primary, false), - labels: labelCfg(primary, x, false), - labelFmt: undefined - } - } - }; - } - cfg.axes = { - primary: { - x: axisCfg(true, true), - y: axisCfg(true, false) - }, - secondary: { - x: axisCfg(false, true), - y: axisCfg(false, false) - } - }; - } - static adjustConfig(cfg) { - } - drawAxisLine(x, range, cross) { - return x ? this.horLine(range[0], range[1], cross, 'hs-graph-axis-line') : - this.verLine(cross, range[0], range[1], 'hs-graph-axis-line'); - } - drawTitle(x, ttlCfg, type, range, cross) { - ttlCfg.cssClass = 'hs-graph-axis-title'; - const xy = { transform: `translate(${x ? range[1] : cross}, ${x ? cross : range[1]})` }; - return !ttlCfg.visible ? undefined : - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('g', xy, this.text(ttlCfg, ttlCfg.text)); - } - drawTickMarks(x, type, crossesAt, scale, ticks, cfg) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${type}-tick-marks` }, !cfg.marks.visible ? '' : ticks.marks.map((t) => { - return x ? this.verLine(scale.convert(t), crossesAt, crossesAt + cfg.marks.length) : - this.horLine(crossesAt, crossesAt - cfg.marks.length, scale.convert(t)); - })); - } - drawTickLabels(x, type, crossesAt, scale, ticks, cfg) { - scale.setLabelFormat(cfg.labelFmt); - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${type}-tick-label` }, !cfg.labels.visible ? '' : ticks.labels.map((t) => { - const v = scale.convert(t.pos); - const xy = { transform: `translate(${x ? v : crossesAt}, ${x ? crossesAt : v})` }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('g', xy, this.text(cfg.labels, t.text)); - })); - } - drawAxis(dir, scales, type, axisCfg) { - const x = dir === 'x'; - const range = scales[dir].range(); - const cfg = axisCfg[type][dir]; - scales[dir].scaleType(cfg.scale.type); - const crossesAt = getCrossAt(cfg.crossesAt, scales[x ? 'y' : 'x']); - const ticks = scales[dir].ticks(); - return !cfg.visible ? undefined : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${dir} hs-graph-axis-${type}` }, [ - this.drawAxisLine(x, range, crossesAt), - this.drawTitle(x, cfg.title, type, range, crossesAt), - this.drawTickMarks(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor), - this.drawTickMarks(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major), - this.drawTickLabels(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor), - this.drawTickLabels(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major) - ]); - } - view(node) { - const cfg = node.attrs.cfg; - const scales = node.attrs.scales; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-axis' }, [ - this.drawAxis('x', scales.primary, 'primary', cfg), - this.drawAxis('y', scales.primary, 'primary', cfg), - this.drawAxis('x', scales.secondary, 'secondary', cfg), - this.drawAxis('y', scales.secondary, 'secondary', cfg) - ]); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Axes; - -Axes.type = { - linear: 'linear axis', - log: 'log axis', - date: 'date axis', - index: 'index axis', - percent: 'percent axis', - ordinal: 'ordinal axis', - nominal: 'nominal axis' -}; -class ExampleLinearAxis { -} -class ExampleLogAxis { -} -class ExampleDateAxis { -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXhlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9BeGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZEQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQU8sVUFBVSxDQUFDO0FBVXBDLENBQUM7QUFLRCxPQUFPLEVBQUUsT0FBTyxFQUNQLFVBQVUsRUFDVixVQUFVLEVBQ0osTUFBVSxXQUFXLENBQUM7QUFRckMsb0JBQW9CLEtBQW1CLEVBQUUsS0FBVztJQUNoRCxJQUFJLFNBQWdCLENBQUM7SUFDckIsUUFBUSxLQUFLLEVBQUU7UUFDWCxLQUFLLEtBQUs7WUFBRSxTQUFTLEdBQVcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTTtRQUN6RCxLQUFLLEtBQUs7WUFBRSxTQUFTLEdBQVcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTTtRQUN6RCxPQUFPLENBQUMsQ0FBSSxTQUFTLEdBQVcsS0FBSyxJQUFJLENBQUMsQ0FBQztLQUM5QztJQUNELE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUNwQyxDQUFDO0FBRUQsTUFBTSxXQUFZLFNBQVEsT0FBTztJQWtHN0IsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFVO1FBQzNCO1lBQ0ksT0FBTztnQkFDSCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO2dCQUN0QixNQUFNLEVBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDO2FBQ2xDLENBQUM7UUFDTixDQUFDO1FBQ0Qsa0JBQWtCLE9BQWUsRUFBRSxDQUFTLEVBQUUsS0FBYTtZQUN2RCxPQUFPO2dCQUNILE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7Z0JBQ3hCLElBQUksRUFBRSxDQUFDLENBQUEsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxD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 - -/***/ }), -/* 6 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Series__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_hsutil__ = __webpack_require__(8); - - - - -class Plot extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { - drawLine(clipID, data, x, y, scales, sStyle, title) { - const style = `stroke: ${sStyle.line.color}; stroke-width:${sStyle.line.width};`; - return !sStyle.line.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-line', '') : this.polyline(data, x, y, scales, clipID, style, title); - } - drawMarker(clipID, data, x, y, scales, sStyle, title) { - const mrk = __WEBPACK_IMPORTED_MODULE_2__Series__["a" /* Series */].marker; - let style = `fill:${sStyle.marker.color}`; - return !sStyle.marker.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-marker', '') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series-markers' }, data.map((p) => { - const cx = scales.x.convert(p[x]); - const cy = scales.y.convert(p[y]); - const r = sStyle.marker.size; - switch (sStyle.marker.shape) { - case mrk.circle: - return this.circle({ x: cx, y: cy }, r, style, title); - case mrk.square: - return this.rect({ x: cx - r, y: cy - r }, { w: 2 * r, h: 2 * r }, style, title); - case mrk.diamond: - return this.shape([[cx - r, cy], [cx, cy + r], [cx + r, cy], [cx, cy - r]], undefined, style, title); - case mrk.upTriangle: - return this.shape([[cx - r, cy + r], [cx + r, cy + r], [cx, cy - r]], undefined, style, title); - case mrk.downTriangle: - return this.shape([[cx - r, cy - r], [cx + r, cy - r], [cx, cy + r]], undefined, style, title); - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`.unkown-marker-${sStyle.marker.shape}`, ''); - })); - } - drawLabel(clipID, data, x, y, lbl, scales, sDef) { - const sStyle = sDef.style; - const cfg = { - text: '', - cssClass: ``, - style: `fill:${sStyle.label.color}`, - xpos: __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle, - ypos: __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].center, - hOffset: sDef.hOffset, - vOffset: sDef.vOffset - }; - return !sStyle.marker.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-marker', '') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series-labels' }, data.map((p) => { - cfg.x = '' + scales.x.convert(p[x]); - cfg.y = '' + scales.y.convert(p[y]); - return this.text(cfg, Object(__WEBPACK_IMPORTED_MODULE_3_hsutil__["d" /* round */])(p[lbl], 3)); - })); - } - drawArea(clipID, data, x, yFore, yBack, scales, sStyle, title) { - if (sStyle.fill.visible) { - const style = `fill: ${sStyle.fill.color};`; - const drawFore = data; - const drawBack = data.slice().reverse(); - return this.polygon(drawFore, drawBack, x, yFore, yBack, scales, clipID, style, title); - } - else { - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-line', ''); - } - } - setDefaults(data, series, scales) { - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Plot; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxvdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9QbG90LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sRUFBRSxDQUFDLEVBQVEsTUFBVyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLE9BQU8sRUFFUCxVQUFVLEVBQ1YsVUFBVSxFQUFFLE1BQVEsV0FBVyxDQUFDO0FBSXpDLE9BQU8sRUFBRSxNQUFNLEVBRUssTUFBUyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFhLFFBQVEsQ0FBQztBQUV0QyxNQUFNLFdBQXFCLFNBQVEsT0FBTztJQUN0QyxRQUFRLENBQUMsTUFBYSxFQUFFLElBQWMsRUFBRSxDQUFRLEVBQUUsQ0FBUSxFQUFFLE1BQWMsRUFBRSxNQUFrQixFQUFFLEtBQWE7UUFDekcsTUFBTSxLQUFLLEdBQUcsV0FBVyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssa0JBQWtCLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUM7UUFDakYsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDbkgsQ0FBQztJQUVELFVBQVUsQ0FBQyxNQUFhLEVBQUUsSUFBYyxFQUFFLENBQVEsRUFBRSxDQUFRLEVBQUUsTUFBYyxFQUFFLE1BQWtCLEVBQUUsS0FBYTtRQUMzRyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzFCLElBQUksS0FBSyxHQUFHLFFBQVEsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMxQyxPQUFPLENBQUMsTUFBTSxDQUFD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 - -/***/ }), -/* 7 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return o; }); -if (!global['window']) { - console.log('creating non-browser polyfill'); - global['window'] = __webpack_require__(24)(); - global['document'] = window.document; -} -const m = __webpack_require__(30); -/* harmony export (immutable) */ __webpack_exports__["a"] = m; - -const o = __webpack_require__(31); -o.root = window.document.createElement("div"); - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWl0aHJpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taXRocmlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEVBQUU7SUFDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO0lBRTdDLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxPQUFPLENBQUMsbUNBQW1DLENBQUMsRUFBRSxDQUFDO0lBQ2xFLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDO0NBRXhDO0FBS0QsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQU9wQyxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUN6QyxDQUFDLENBQUMsSUFBSSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBRTlDLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyJ9 -/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(2))) - -/***/ }), -/* 8 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__TimedPromise__ = __webpack_require__(39); -/* unused harmony reexport timeout */ -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return __WEBPACK_IMPORTED_MODULE_0__TimedPromise__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__showdown__ = __webpack_require__(40); -/* unused harmony reexport markDown */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Checksum__ = __webpack_require__(42); -/* unused harmony reexport shortCheckSum */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Date__ = __webpack_require__(43); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_3__Date__["a"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return __WEBPACK_IMPORTED_MODULE_3__Date__["b"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Number__ = __webpack_require__(44); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return __WEBPACK_IMPORTED_MODULE_4__Number__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__PacingQueue__ = __webpack_require__(45); -/* unused harmony reexport PacingQueue */ - - - - - - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVksWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTyxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsTUFBWSxRQUFRLENBQUM7QUFDeEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFlLFVBQVUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQVMsZUFBZSxDQUFDIn0= - -/***/ }), -/* 9 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Axes__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__PlotLine__ = __webpack_require__(47); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__PlotMarkers__ = __webpack_require__(48); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__PlotBar__ = __webpack_require__(49); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__PlotArea__ = __webpack_require__(50); - - - - - - - -function copyDefault(target, source, defaults) { - Object.keys(source).forEach((key) => { - if (typeof source[key] === 'object') { - if (target[key] === undefined) { - target[key] = {}; - } - copyDefault(target[key], source[key], defaults); - } - else { - if (target[key] === undefined) { - target[key] = source[key]; - } - if (target[key] === 'default') { - target[key] = defaults[key]; - } - } - }); -} -class Series extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { - static defaultConfig(cfg) { - cfg.series = new SeriesConfig(); - } - static adjustConfig(cfg) { - cfg.series.series.forEach((s) => { - if (s.x === undefined) { - cfg.axes.primary.x.title.hOffset = 0; - cfg.axes.primary.x.scale.type = __WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */].type.index; - cfg.grid.minor.ver.visible = false; - } - }); - } - drawClipRect(clipID, scales) { - return !clipID ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('') : this.clipRect({ x: scales.x.range()[0], y: scales.y.range()[1] }, { - w: scales.x.range()[1] - scales.x.range()[0], - h: scales.y.range()[0] - scales.y.range()[1] - }, clipID); - } - view(node) { - const cfg = node.attrs.cfg; - const scales = node.attrs.scales.primary; - const data = node.attrs.data; - const clipID = cfg.clip ? 'hs' + Math.floor(Math.random() * 10000) : undefined; - cfg.series.map((s) => { - if (s.map === Series.map.shared) { - s.ySum = '$sum'; - data[s.dataIndex].colAdd(s.ySum); - data[s.dataIndex].colInitialize(s.ySum, 0); - } - }); - cfg.series.map((s) => { - const dt = data[s.dataIndex]; - if (s.map === Series.map.shared) { - const valCol = dt.colNumber(s.y); - dt.colInitialize(s.ySum, (v, i, row) => { return v + row[valCol]; }); - } - if (s.map) { - s.yBase = '$' + s.map; - dt.colAdd(s.yBase); - dt.colInitialize(s.yBase, 0); - } - }); - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series' }, [ - this.drawClipRect(clipID, scales), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', cfg.series.map((s, i) => { - const dt = data[s.dataIndex]; - const type = Series.plot[s.type] || Series.plot.line; - type.setDefaults(dt, s, scales); - const d = s.cond ? dt.filter(s.cond) : dt; - const plot = type.plot(d, s, scales, i, clipID); - if (s.map) { - const valCol = d.colNumber(s.y); - d.colInitialize(s.yBase, (v, i, row) => { return v + row[valCol]; }); - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-series-${i}` }, plot); - })) - ]); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Series; - -Series.marker = { - circle: Symbol('circle marker'), - square: Symbol('square marker'), - diamond: Symbol('diamond marker'), - upTriangle: Symbol('upward triangle marker'), - downTriangle: Symbol('downward triangle marker') -}; -Series.plot = { - line: new __WEBPACK_IMPORTED_MODULE_3__PlotLine__["a" /* PlotLine */](), - marker: new __WEBPACK_IMPORTED_MODULE_4__PlotMarkers__["a" /* PlotMarkers */](), - bar: new __WEBPACK_IMPORTED_MODULE_5__PlotBar__["a" /* PlotBar */](), - area: new __WEBPACK_IMPORTED_MODULE_6__PlotArea__["a" /* PlotArea */]() -}; -Series.map = { - stacked: 'stacked', - shared: 'shared' -}; -class SeriesConfig { - constructor() { - this.seriesDefs = []; - this.clip = true; - this.defaultStyle = { - line: { color: 'default', visible: true, width: 2 }, - marker: { color: 'default', visible: false, size: 10, shape: Series.marker.circle }, - label: { color: 'default', visible: false }, - fill: { color: 'default', visible: false }, - bar: { color: 'default', visible: false, width: 50, offset: 30 } - }; - this.defaultColors = ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f', '#000', '#444', '#888', '#ccc']; - } - set series(cfg) { - const defStyle = this.defaultStyle; - const defColors = this.defaultColors; - cfg.forEach((s) => { - s.type = s.type || 'line'; - s.style = s.style || {}; - s.dataIndex = s.dataIndex || 0; - const defaults = { - color: defColors[this.seriesDefs.length] - }; - copyDefault(s.style, defStyle, defaults); - this.seriesDefs.push(s); - switch (s.type) { - case 'line': - s.style.line.visible = true; - break; - case 'marker': - s.style.marker.visible = true; - break; - case 'area': - s.style.fill.visible = true; - break; - case 'bar': - s.style.fill.visible = true; - break; - } - }); - } - get series() { return this.seriesDefs; } -} -/* unused harmony export SeriesConfig */ - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VyaWVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1Nlcmllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFvQkEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFXLFVBQVUsQ0FBQztBQU14QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQVcsV0FBVyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBYyxRQUFRLENBQUM7QUFFdEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFVLFlBQVksQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU8sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBVyxXQUFXLENBQUM7QUFDekMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFVLFlBQVksQ0FBQztBQUcxQyxxQkFBcUIsTUFBVSxFQUFFLE1BQVUsRUFBRSxRQUFZO0lBQ3JELE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBVSxFQUFFLEVBQUU7UUFDdkMsSUFBSSxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxRQUFRLEVBQUU7WUFDakMsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7YUFBRTtZQUNwRCxXQUFXLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztTQUNuRDthQUFNO1lBQ0gsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7YUFBRTtZQUM3RCxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxTQUFTLEVBQUU7Z0JBQUUsTUFBTSxDQUFD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 - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function parseURL(url, root) { - var data = {} - var protocolIndex = url.indexOf("://") - var pathnameIndex = protocolIndex > -1 ? url.indexOf("/", protocolIndex + 3) : url.indexOf("/") - var searchIndex = url.indexOf("?") - var hashIndex = url.indexOf("#") - if ((pathnameIndex > searchIndex && searchIndex > -1) || (pathnameIndex > hashIndex && hashIndex > -1)) pathnameIndex = -1 - if (searchIndex > hashIndex && hashIndex > -1) searchIndex = -1 - var pathnameEnd = searchIndex > -1 ? searchIndex : hashIndex > -1 ? hashIndex : url.length - if (protocolIndex > -1) { - //it's a full URL - if (pathnameIndex < 0) pathnameIndex = url.length - var portIndex = url.indexOf(":", protocolIndex + 1) - if (portIndex < 0) portIndex = pathnameIndex - data.protocol = url.slice(0, protocolIndex + 1) - data.hostname = url.slice(protocolIndex + 3, portIndex) - data.port = url.slice(portIndex + 1, pathnameIndex) - data.pathname = url.slice(pathnameIndex, pathnameEnd) || "/" - } - else { - data.protocol = root.protocol - data.hostname = root.hostname - data.port = root.port - if (pathnameIndex === 0) { - //it's an absolute path - data.pathname = url.slice(pathnameIndex, pathnameEnd) || "/" - } - else if (searchIndex !== 0 && hashIndex !== 0) { - //it's a relative path - var slashIndex = root.pathname.lastIndexOf("/") - var path = slashIndex > -1 ? root.pathname.slice(0, slashIndex + 1) : "./" - var normalized = url.slice(0, pathnameEnd).replace(/^\.$/, root.pathname.slice(slashIndex + 1)).replace(/^\.\//, "") - var dotdot = /\/[^\/]+?\/\.{2}/g - var pathname = path + normalized - pathname = path + normalized - while (dotdot.test(pathname)) pathname = pathname.replace(dotdot, "") - pathname = pathname.replace(/\/\.\//g, "/").replace(/^(\/\.{2})+/, "") || "/" - data.pathname = pathname - } - } - var searchEnd = hashIndex > -1 ? hashIndex : url.length - data.search = searchIndex > -1 ? url.slice(searchIndex, searchEnd) : "" - data.hash = hashIndex > -1 ? url.slice(hashIndex) : "" - return data -} - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(setImmediate) { - -module.exports = typeof setImmediate === "function" ? setImmediate : setTimeout - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12).setImmediate)) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global) {var apply = Function.prototype.apply; - -// DOM APIs, for completeness - -exports.setTimeout = function() { - return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); -}; -exports.setInterval = function() { - return new Timeout(apply.call(setInterval, window, arguments), clearInterval); -}; -exports.clearTimeout = -exports.clearInterval = function(timeout) { - if (timeout) { - timeout.close(); - } -}; - -function Timeout(id, clearFn) { - this._id = id; - this._clearFn = clearFn; -} -Timeout.prototype.unref = Timeout.prototype.ref = function() {}; -Timeout.prototype.close = function() { - this._clearFn.call(window, this._id); -}; - -// Does not start the time, just sets up the members needed. -exports.enroll = function(item, msecs) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = msecs; -}; - -exports.unenroll = function(item) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = -1; -}; - -exports._unrefActive = exports.active = function(item) { - clearTimeout(item._idleTimeoutId); - - var msecs = item._idleTimeout; - if (msecs >= 0) { - item._idleTimeoutId = setTimeout(function onTimeout() { - if (item._onTimeout) - item._onTimeout(); - }, msecs); - } -}; - -// setimmediate attaches itself to the global object -__webpack_require__(26); -// On some exotic environments, it's not clear which object `setimmeidate` was -// able to install onto. Search each possibility in the same order as the -// `setimmediate` library. -exports.setImmediate = (typeof self !== "undefined" && self.setImmediate) || - (typeof global !== "undefined" && global.setImmediate) || - (this && this.setImmediate); -exports.clearImmediate = (typeof self !== "undefined" && self.clearImmediate) || - (typeof global !== "undefined" && global.clearImmediate) || - (this && this.clearImmediate); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 14 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__DataFilters__ = __webpack_require__(38); - -; -class Data { - constructor(data) { - this.data = []; - this.meta = []; - this.import(data); - } - static toDataSet(data, name) { - data = data || [{}]; - const names = Object.keys(data[0]); - const rows = data.map((r) => names.map((n) => r[n])); - return { rows: rows, colNames: names, name: name || undefined }; - } - getName() { - return this.name; - } - import(data) { - this.name = data.name; - this.setData(data.rows, data.colNames); - } - export() { - return { - rows: this.getData(), - colNames: this.colNames() - }; - } - getData() { - return this.data; - } - getColumn(col) { - const cn = this.colNumber(col); - return this.data.map((row) => row[cn]); - } - colAdd(col) { - let m = this.getMeta(col); - if (m === undefined) { - m = this.meta[col] = {}; - m.name = col; - m.column = this.meta.length; - this.meta.push(m); - m.cast = false; - m.accessed = false; - } - return m.column; - } - colInitialize(col, initializer) { - const cn = this.colNumber(col); - if (!cn && typeof col === 'string') { - this.colAdd(col); - } - const fn = typeof initializer === 'function'; - if (cn !== undefined) { - this.data.map((r, i) => r[cn] = fn ? initializer(r[cn], i, r) : initializer); - } - } - colNumber(col) { - const m = this.getMeta(col); - if (!m) { - return undefined; - } - else { - m.accessed = true; - return m.column; - } - } - colName(col) { - var m = this.getMeta(col); - if (!m) { - return undefined; - } - m.accessed = true; - return m.name; - } - colNames() { - return this.meta.map((m) => m.name); - } - colType(col) { - const meta = this.getMeta(col); - return meta ? meta.types[0].type : Data.type.name; - } - findDomain(col, domain) { - if (col === undefined) { - domain[0] = 0; - domain[1] = this.data.length - 1; - } - else { - const c = this.colNumber(col); - const type = this.colType(col); - if (this.data === undefined) { - console.log('no data'); - } - switch (type) { - case Data.type.nominal: - this.data.forEach((r) => { - const nomDom = domain; - if (nomDom.indexOf('' + r[c]) < 0) { - nomDom.push('' + r[c]); - } - }); - break; - default: - this.data.forEach((r) => { - let v = r[c]; - if (v !== undefined && v !== null) { - domain[0] = (v < domain[0]) ? v : domain[0]; - domain[1] = (v > domain[1]) ? v : domain[1]; - } - }); - } - } - } - castData() { - this.meta.forEach((c) => { - const col = c.column; - if (!c.cast) { - this.data.forEach((row) => row[col] = this.castVal(c.types[0].type, row[col])); - } - c.cast = true; - }); - } - filter(condition) { - return Object(__WEBPACK_IMPORTED_MODULE_0__DataFilters__["a" /* filter */])(this, condition); - } - sort(sortFn, col) { - let fn = sortFn; - if (!col) { - this.data.sort(fn); - } - else { - col = this.colNumber(col); - if (sortFn === 'descending') { - fn = (a, b) => (b > a) ? 1 : ((b < a) ? -1 : 0); - } - if (sortFn === 'ascending') { - fn = (a, b) => (b < a) ? 1 : ((b > a) ? -1 : 0); - } - this.data.sort((r1, r2) => fn(r1[col], r2[col])); - } - return this; - } - map(col, mapFn) { - const noop = (val) => val; - const cumulate = () => { - let sum = 0; - return (val, i) => { sum += +val; return sum; }; - }; - function getFn() { - let fn; - switch (mapFn) { - case 'cumulate': - fn = cumulate(); - break; - case 'noop': - fn = noop; - break; - default: fn = mapFn; - } - return fn; - } - let result = new Data({ colNames: this.colNames(), rows: this.data.slice(), name: this.getName() }); - const names = col['length'] ? col : [col]; - names.map((cn) => { - const c = this.colNumber(cn); - let fn = getFn(); - result.data = result.data.map((row, i, rows) => { - row[c] = fn(row[c], c, i, rows); - return row; - }); - }); - return result; - } - getMeta(col) { - if (!this.meta) { - this.meta = []; - } - if (!this.meta[col]) { - return undefined; - } - this.meta[col].accessed = true; - return this.meta[col]; - } - setData(data, names, autoType = true) { - this.meta = []; - this.data = data; - if (!names) { - console.log(); - } - names.forEach((col) => this.colAdd(col)); - names.forEach((col) => this.findTypes(col)); - this.castData(); - } - findTypes(col) { - const m = this.getMeta(col); - const types = []; - Object.keys(Data.type).forEach((t) => { - const ts = { type: Data.type[t], count: 0 }; - types.push(ts); - types[Data.type[t]] = ts; - }); - for (let v of this.allRows(col)) { - const t = this.findType(v); - if (t !== null) { - types[t].count++; - } - } - types.sort(function (a, b) { - if (a.type === 'currency' && a.count > 0) { - return -1; - } - if (b.type === 'currency' && b.count > 0) { - return 1; - } - return b.count - a.count; - }); - m.types = types; - return types[0].type; - } - findType(val) { - if (val && val !== '') { - if (val instanceof Date) { - return Data.type.date; - } - if (typeof val === 'number') { - return Data.type.number; - } - const strVal = '' + val; - if ('' + parseFloat(strVal) === strVal) { - return Data.type.number; - } - if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { - return Data.type.currency; - } - if (strVal.endsWith('%') && !isNaN(parseFloat(strVal))) { - return Data.type.percent; - } - if (!isNaN(this.toDate(strVal).getTime())) { - return Data.type.date; - } - if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { - if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { - return Data.type.currency; - } - } - switch (strVal.toLowerCase()) { - case "null": break; - case "#ref!": break; - default: if (val.length > 0) { - return Data.type.nominal; - } - } - } - return null; - } - *allRows(column) { - const c = this.colNumber(column); - for (let r = 0; r < this.data.length; r++) { - yield this.data[r][c]; - } - } - toDate(val, limitYear = 1970) { - let d; - if (val instanceof Date) { - d = val; - } - else { - d = new Date(val); - } - let yr = d.getFullYear(); - if (yr < 100) { - yr += 1900; - d.setFullYear((yr < limitYear) ? yr + 100 : yr); - } - return d; - } - castVal(type, val) { - switch (type) { - case Data.type.date: - if (val instanceof Date) { - return val; - } - val = this.toDate(val); - if (isNaN(val.getTime())) { - val = null; - } - break; - case Data.type.percent: - if (typeof val === 'string') { - const num = parseFloat(val); - val = val.endsWith('%') ? num / 100 : num; - } - if (isNaN(val)) { - val = null; - } - break; - case Data.type.currency: - if (typeof val === 'string') { - val = val.replace(/[^eE\+\-\.\d]/g, ''); - } - case Data.type.number: - if (typeof val === 'string') { - val = parseFloat(val); - } - if (isNaN(val)) { - val = null; - } - break; - default: val = '' + val; - } - return val; - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Data; - -Data.type = { - number: 'number data', - name: 'name data', - date: 'date data', - currency: 'currency data', - percent: 'percent data', - nominal: 'nominal data' -}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGF0YS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9EYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLE9BQU8sRUFBYSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUF1Q0UsQ0FBQztBQWtCckQsTUFBTTtJQXFCRixZQUFZLElBQWE7UUEwU2pCLFNBQUksR0FBaUIsRUFBRSxDQUFDO1FBQ3hCLFNBQUksR0FBaUIsRUFBRSxDQUFDO1FBMVM1QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3RCLENBQUM7SUFWTSxNQUFNLENBQUMsU0FBUyxDQUFDLElBQW1CLEVBQUUsSUFBWTtRQUNyRCxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDcEIsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBSyxFQUFFLEVBQUUsQ0FDNUIsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQyxPQUFPLEVBQUUsSUFBSSxFQUFDLElBQUksRUFBRSxRQUFRLEVBQUMsS0FBSyxFQUFFLElBQUksRUFBQyxJQUFJLElBQUUsU0FBUyxFQUFFLENBQUM7SUFDL0QsQ0FBQztJQVNNLE9BQU87UUFDVixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDckIsQ0FBQztJQU1NLE1BQU0sQ0FBQyxJQUFZO1FBQ3RCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFLTSxN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 - -/***/ }), -/* 15 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Axes__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_hsutil__ = __webpack_require__(8); - - -function addTickNumber(t, v) { - t.labels.push({ pos: v, text: '' + Math.round(v * 1000000) / 1000000 }); -} -function addTickDate(t, v, fmt) { - t.labels.push({ pos: v.getTime(), text: Object(__WEBPACK_IMPORTED_MODULE_1_hsutil__["a" /* date */])(fmt, v) }); -} -function linScaleTickMarks(dom, ticks, numTicks) { - function addTicks(unit, ticks) { - let exp = Math.pow(10, Math.floor(Math.log10(unit))); - unit = Math.floor(unit / exp) * exp; - const min = Math.floor(dom[0] / unit) * unit; - const max = Math.ceil(dom[1] / unit) * unit; - for (let v = min; v <= max; v += unit) { - addTickNumber(ticks, v); - } - return unit; - } - const majorUnit = addTicks((dom[1] - dom[0]) / numTicks, ticks.major); - addTicks(majorUnit / numTicks, ticks.minor); -} -function percentScaleTickMarks(dom, ticks, numTicks) { - const formatPercent = (m) => m.text = `${Math.round(m.pos) * 100}%`; - linScaleTickMarks(dom, ticks, numTicks); - ticks.major.labels.forEach(formatPercent); - ticks.minor.labels.forEach(formatPercent); -} -function logScaleTickMarks(dom, ticks) { - dom[0] = Math.max(dom[0], 1e-20); - dom[1] = Math.max(dom[1], 1e-20); - let dif = Math.pow(10, Math.floor(Math.log10(dom[1] - dom[0]))); - let min = Math.pow(10, Math.floor(Math.log10(dom[0]))); - let max = Math.pow(10, Math.ceil(Math.log10(dom[1]))); - if (dif > min) { - for (let v = min; v <= max; v *= 10) { - for (let i = 1; i <= 20; i++) { - if (i === 1 && v * i < max) { - addTickNumber(ticks.major, v * i); - } - else if (i % 10 === 0) { } - else if (i < 10) { - addTickNumber(ticks.minor, v * i); - } - else if (i % 2 === 0) { - addTickNumber(ticks.minor, v * i); - } - } - } - } - else { - min = Math.floor(dom[0] / dif) * dif; - max = Math.ceil(dom[1] / dif) * dif; - if ((max - min) / dif < 4) { - dif /= 2; - } - for (let v = min; v <= max; v += dif) { - addTickNumber(ticks.major, v); - } - addTickNumber(ticks.major, min); - addTickNumber(ticks.major, max); - } -} -const tickCategories = [ - [10, 0, 0, 0], [5, 0, 0, 0], [2, 0, 0, 0], [1, 0, 0, 0], [0, 6, 0, 0], [0, 3, 0, 0], [0, 1, 0, 0], [0, 0, 7, 0], [0, 0, 1, 0], [0, 0, 0, 4], [0, 0, 0, 1] -]; -function dateScaleTickMarks(dom, ticks, fmt = '%MM/%DD/%YY') { - function addDates(i, tickDefs) { - const createDate = (idx) => new Date(Math.floor(dateDom[idx].getFullYear() / modYr) * modYr + (idx ? incYr : 0), (incYr > 0) ? 0 : Math.floor(dateDom[idx].getMonth() / modMo) * modMo + (idx ? incMo : 0), (incMo > 0) ? 1 : (dateDom[idx].getDate() - ((incDay === 7) ? dateDom[idx].getDay() : 0)) + (idx ? incDay : 0), (incDay > 0) ? 0 : (dateDom[idx].getHours()) + (idx ? incHour : 0)); - const incYr = tickCategories[i][0]; - const incMo = tickCategories[i][1]; - const incDay = tickCategories[i][2]; - const incHour = tickCategories[i][3]; - const modYr = incYr || 1; - const modMo = incMo || 1; - const date0 = createDate(0); - const date1 = createDate(1); - fmt = incHour ? '%hh:%mm' : '%MM/%DD/%YY'; - for (let d = date0; d <= date1; d = new Date(d.getFullYear() + incYr, d.getMonth() + incMo, d.getDate() + incDay, d.getHours() + incHour)) { - addTickDate(tickDefs, d, fmt); - } - } - const dateDom = [ - (typeof dom[0] === 'number') ? new Date(dom[0]) : dom[0], - (typeof dom[1] === 'number') ? new Date(dom[1]) : dom[1] - ]; - if (isNaN(dateDom[0].getTime())) { - dateDom[0] = new Date('1/1/1980'); - } - if (isNaN(dateDom[1].getTime())) { - dateDom[0] = new Date(); - } - const d = dateDom[1].getTime() - dateDom[0].getTime(); - tickCategories.some((cat, i) => { - const dMin = __WEBPACK_IMPORTED_MODULE_1_hsutil__["c" /* ms */].fromDays((cat[0] * 365 + cat[1] * 30 + cat[2])) + __WEBPACK_IMPORTED_MODULE_1_hsutil__["c" /* ms */].fromHours(cat[3]); - if (d > 3 * dMin) { - addDates(i, ticks.major); - addDates(Math.min(i + 1, tickCategories.length - 1), ticks.minor); - return true; - } - else { - return false; - } - }); -} -function createTickLabels(type, domain, numTicks, fmt) { - const sort = (a, b) => a.pos - b.pos; - function sortTicks() { - ticks.minor.labels.sort(sort); - ticks.major.labels.sort(sort); - } - ; - const dom = [domain[0], domain[1]]; - const ticks = { - major: { marks: [], labels: [] }, - minor: { marks: [], labels: [] } - }; - switch (type) { - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: - logScaleTickMarks(dom, ticks); - sortTicks(); - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: - dateScaleTickMarks(dom, ticks, fmt); - sortTicks(); - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: - percentScaleTickMarks(dom, ticks, numTicks); - sortTicks(); - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: - default: - linScaleTickMarks(dom, ticks, numTicks); - sortTicks(); - } - return ticks; -} -class Scale { - constructor(cfg) { - this.cfg = cfg; - this.typeVal = __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear; - this.rangeVal = [0, 1]; - this.domVal = [0, 1]; - this.domMinAuto = 0; - this.domMaxAuto = 0; - this.scaleType(cfg.type); - this.domain(cfg.domain); - } - setLabelFormat(labelFmt) { - this.labelFmt = labelFmt; - } - range(r) { - if (r) { - this.rangeVal = r; - } - return this.rangeVal; - } - domain(dom) { - if (dom) { - if (this.scaleType() === __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date) { - if (typeof dom[0] === 'string' || typeof dom[1] === 'string') { - this.domVal[0] = (dom[0] === 'auto') ? 0 : Date.parse(dom[0]); - this.domVal[1] = (dom[1] === 'auto') ? 1 : Date.parse(dom[1]); - } - } - else { - this.domVal[0] = (dom[0] === 'auto') ? 0 : dom[0]; - this.domVal[1] = (dom[1] === 'auto') ? 1 : dom[1]; - } - switch (dom[0]) { - case 'tight': - this.domMinAuto = 2; - break; - case 'auto': - this.domMinAuto = 1; - break; - default: this.domMinAuto = 0; - } - switch (dom[1]) { - case 'tight': - this.domMaxAuto = 2; - break; - case 'auto': - this.domMaxAuto = 1; - break; - default: this.domMaxAuto = 0; - } - } - if (this.typeVal === __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log) { - if (this.domVal[1] <= 0) { - this.domVal[1] = 10; - } - if (this.domVal[0] <= 0) { - this.domVal[0] = this.domVal[1] / 10; - } - } - return this.domVal; - } - scaleType(s) { - if (s) { - this.typeVal = s; - } - return this.typeVal; - } - setAutoDomain(dom) { - const ticks = createTickLabels(this.scaleType(), dom, 4, this.labelFmt); - switch (this.domMinAuto) { - case 1: - this.domVal[0] = ticks.major.labels[0] ? ticks.major.labels[0].pos : dom[0]; - break; - case 2: - this.domVal[0] = dom[0]; - break; - } - switch (this.domMaxAuto) { - case 1: - this.domVal[1] = ticks.major.labels[ticks.major.labels.length - 1].pos; - break; - case 2: - this.domVal[1] = dom[1]; - break; - } - } - ticks(numTicks = 4) { - function marksFromLabels(ticks, type) { - switch (type) { - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: - const numLabels = ticks.major.labels.length; - ticks.major.marks = Array(numLabels + 1).fill(1).map((e, i) => i - 0.5); - ticks.minor.marks = ticks.minor.labels ? ticks.minor.labels.map((l) => l.pos) : []; - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: - default: - ticks.major.marks = ticks.major.labels ? ticks.major.labels.map((l) => l.pos) : []; - ticks.minor.marks = ticks.minor.labels ? ticks.minor.labels.map((l) => l.pos) : []; - } - } - const dom = [this.domain()[0], this.domain()[1]]; - const inRange = (t) => t.pos >= dom[0] && t.pos <= dom[1]; - const ticks = createTickLabels(this.scaleType(), this.domain(), numTicks, this.labelFmt); - ticks.minor.labels = ticks.minor.labels.filter(inRange); - ticks.major.labels = ticks.major.labels.filter(inRange); - if (ticks.major.labels.length === 0) { - ticks.major.labels = ticks.minor.labels; - ticks.minor.labels = []; - } - marksFromLabels(ticks, this.scaleType()); - return ticks; - } - convert(domVal) { - const dom = this.domain(); - const range = this.range(); - const domMin = dom[0]; - const domMax = dom[1]; - let result; - switch (this.scaleType()) { - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: - result = Math.log(domVal / domMin) / Math.log(domMax / domMin) * (range[1] - range[0]) + range[0]; - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: - default: - result = (domVal - domMin) / (domMax - domMin) * (range[1] - range[0]) + range[0]; - } - return result; - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Scale; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2NhbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU2NhbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFjLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxNQUFVLFFBQVEsQ0FBQztBQU90Qyx1QkFBdUIsQ0FBVSxFQUFFLENBQVE7SUFDdkMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUMsT0FBTyxDQUFDLEdBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztBQUN0RSxDQUFDO0FBRUQscUJBQXFCLENBQVUsRUFBRSxDQUFNLEVBQUUsR0FBVTtJQUMvQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQzNELENBQUM7QUFJRCwyQkFBMkIsR0FBWSxFQUFFLEtBQVcsRUFBRSxRQUFlO0lBQ2pFLGtCQUFrQixJQUFXLEVBQUUsS0FBYztRQUN6QyxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JELElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxHQUFHLENBQUMsR0FBQyxHQUFHLENBQUM7UUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUMsSUFBSSxDQUFDO1FBQ3pDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQztRQUN4QyxLQUFLLElBQUksQ0FBQyxHQUFDLEdBQUcsRUFBRSxDQUFDLElBQUUsR0FBRyxFQUFFLENBQUMsSUFBRSxJQUFJLEVBQUU7WUFBRSxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQUU7UUFDN0QsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUNELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RFLFFBQVEsQ0FBQyxTQUFTLEdBQUcsUUFBUSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNoRCxDQUFDO0FBRUQsK0JBQStCLEdBQVksRUFBRSxLQUFXLEVBQUUsUUFBZTtJQUNyRSxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFDLEdBQUcsR0FBRyxDQUFDO0lBQzVFLGlCQUFpQixDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDeEMsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQzFDLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUU5QyxDQUFDO0FBRUQsMkJBQTJCLEdBQVksRUFBRSxLQUFXO0lBQ2hELEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNqQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDakMsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEUsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2RCxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RELElBQUksR0FBRyxHQUFHLEdBQUcsRUFBRTtRQUNYLEtBQUssSUFBSSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFFLEVBQUUsRUFBRTtZQUM3QixLQUFLLElBQUksQ0FBQyxHQUFDLENBQUMsRUFBRSxDQUFDLElBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN0QixJQUFJLENBQUMsS0FBRyxDQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsR0FBQyxHQUFHLEVBQUU7b0JBQUUsYUFBYSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUFFO3FCQUNyRCxJQUFJLENBQUMsR0FBQyxFQUFFLEtBQUcsQ0FBQyxFQUFFLEdBQUU7cUJBQ2hCLElBQUksQ0FBQyxHQUFDLEVBQUUs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 - -/***/ }), -/* 16 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); - - -class Grid extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { - static defaultConfig(cfg) { - cfg.grid = { - major: { - hor: { visible: true }, - ver: { visible: true } - }, - minor: { - hor: { visible: false }, - ver: { visible: false } - } - }; - } - static adjustConfig(cfg) { - } - drawHorGrid(cfg, scale, range, ticks) { - return !cfg.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-hor' }, ticks.marks.map((t) => this.horLine(range[0], range[1], scale.convert(t)))); - } - drawVerGrid(cfg, scale, range, ticks) { - return !cfg.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-ver' }, ticks.marks.map((t) => this.verLine(scale.convert(t), range[0], range[1]))); - } - view(node) { - const cfg = node.attrs.cfg; - const scales = node.attrs.scales; - const ps = scales.primary; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid' }, [ - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-minor' }, [ - this.drawHorGrid(cfg.minor.hor, ps.y, ps.x.range(), ps.y.ticks().minor), - this.drawVerGrid(cfg.minor.ver, ps.x, ps.y.range(), ps.x.ticks().minor) - ]), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-major' }, [ - this.drawHorGrid(cfg.major.hor, ps.y, ps.x.range(), ps.y.ticks().major), - this.drawVerGrid(cfg.major.ver, ps.x, ps.y.range(), ps.x.ticks().major) - ]) - ]); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Grid; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR3JpZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9HcmlkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlCQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQVcsVUFBVSxDQUFDO0FBR3hDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBVyxXQUFXLENBQUM7QUF5QnpDLE1BQU0sV0FBWSxTQUFRLE9BQU87SUFxQjdCLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVTtRQUMzQixHQUFHLENBQUMsSUFBSSxHQUFnQjtZQUNwQixLQUFLLEVBQUU7Z0JBQ0gsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFDLElBQUksRUFBRTtnQkFDckIsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFDLElBQUksRUFBRTthQUN4QjtZQUNELEtBQUssRUFBRTtnQkFDSCxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUMsS0FBSyxFQUFFO2dCQUN0QixHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUMsS0FBSyxFQUFFO2FBQ3pCO1NBQ0osQ0FBQztJQUNOLENBQUM7SUFNRCxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQVU7SUFDOUIsQ0FBQztJQUtPLFdBQVcsQ0FBQyxHQUFxQixFQUFFLEtBQVcsRUFBRSxLQUFjLEVBQUUsS0FBYztRQUNsRixPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLG1CQUFtQixFQUFFLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUMxRixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUNyRCxDQUFDLENBQUM7SUFDUCxDQUFDO0lBS08sV0FBVyxDQUFDLEdBQXFCLEVBQUUsS0FBVyxFQUFFLEtBQWMsRUFBRSxLQUFjO1FBQ2xGLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMsbUJBQW1CLEVBQUUsRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQzFGLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQ3JELENBQUMsQ0FBQztJQUNQLENBQUM7SUFHRCxJQUFJLENBQUMsSUFBWTtRQUNiLE1BQU0sR0FBRyxHQUFlLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO1FBQ3ZDLE1BQU0sTUFBTSxHQUFVLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQ3hDLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFDMUIsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLGVBQWUsRUFBQyxFQUFFO1lBQ3RDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMscUJBQXFCLEVBQUUsRUFBRTtnQkFDdEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLENBQUM7Z0JBQ3ZFLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDO2FBQzFFLENBQUM7WUFDRixDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLHFCQUFxQixFQUFFLEVBQUU7Z0JBQ3RDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDO2dCQUN2RSxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLEtBQUssQ0FBQzthQUMxRSxDQUFDO1NBQ0wsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztDQUNKIn0= - -/***/ }), -/* 17 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); - -; -class Legend { - static defaultConfig(cfg) { - cfg.legend = {}; - } - static adjustConfig(cfg) { - } - view(node) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-legend', width: '100%', height: '100%' }); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Legend; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGVnZW5kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL0xlZ2VuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFnQkEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFPLFVBQVUsQ0FBQztBQU9uQyxDQUFDO0FBRUYsTUFBTTtJQWFGLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVTtRQUMzQixHQUFHLENBQUMsTUFBTSxHQUFpQixFQUMxQixDQUFDO0lBQ04sQ0FBQztJQU1ELE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBVTtJQUU5QixDQUFDO0lBRUQsSUFBSSxDQUFDLElBQVk7UUFDYixPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMsaUJBQWlCLEVBQUUsS0FBSyxFQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQztJQUM3RSxDQUFDO0NBQ0oifQ== - -/***/ }), -/* 18 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0____ = __webpack_require__(19); - -if (__WEBPACK_IMPORTED_MODULE_0____["a" /* Graph */]) { } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXhhbXBsZS9zdGFydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQzVCLElBQUksS0FBSyxFQUFFLEdBQUUifQ== - -/***/ }), -/* 19 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Graph__ = __webpack_require__(20); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return __WEBPACK_IMPORTED_MODULE_0__Graph__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Series__ = __webpack_require__(9); -/* unused harmony reexport Series */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Axes__ = __webpack_require__(5); -/* unused harmony reexport Axes */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Scale__ = __webpack_require__(15); -/* unused harmony reexport Scale */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Grid__ = __webpack_require__(16); -/* unused harmony reexport Grid */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Legend__ = __webpack_require__(17); -/* unused harmony reexport Legend */ - - - - - - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFTLFNBQVMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsTUFBTSxFQUVMLE1BQWUsVUFBVSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBVSxRQUFRLENBQUM7QUFDbEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFTLFNBQVMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQVUsUUFBUSxDQUFDO0FBQ2xDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBUSxVQUFVLENBQUMifQ== - -/***/ }), -/* 20 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_hsdata__ = __webpack_require__(37); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Axes__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Scale__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Canvas__ = __webpack_require__(46); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Series__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Chart__ = __webpack_require__(51); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Grid__ = __webpack_require__(16); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__Legend__ = __webpack_require__(17); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__SVGElem__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10_hsutil__ = __webpack_require__(8); - - - - - - - - - - - -const viewBoxWidth = 1000; -let viewBoxHeight = 700; -function copy(def) { - let result = {}; - Object.keys(def).map((k) => { - if (typeof def[k] === 'object' && !Array.isArray(def[k]) && def[k] !== null) { - result[k] = copy(def[k]); - } - else { - result[k] = def[k]; - } - }); - return result; -} -class Graph extends __WEBPACK_IMPORTED_MODULE_9__SVGElem__["a" /* SVGElem */] { - constructor() { - super(...arguments); - this.marginOffset = { - left: 0, - right: 0, - top: 0, - bottom: 0 - }; - } - static makeConfig(userCfg) { - const cfg = {}; - Graph.defaultConfig(cfg); - __WEBPACK_IMPORTED_MODULE_4__Canvas__["a" /* Canvas */].defaultConfig(cfg); - __WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */].defaultConfig(cfg); - __WEBPACK_IMPORTED_MODULE_5__Series__["a" /* Series */].defaultConfig(cfg); - __WEBPACK_IMPORTED_MODULE_7__Grid__["a" /* Grid */].defaultConfig(cfg); - __WEBPACK_IMPORTED_MODULE_6__Chart__["a" /* Chart */].defaultConfig(cfg); - __WEBPACK_IMPORTED_MODULE_8__Legend__["a" /* Legend */].defaultConfig(cfg); - if (userCfg) { - try { - userCfg(cfg); - } - catch (e) { - console.log('error in usercfg'); - console.log(e); - console.log(e.stack); - } - } - return cfg; - } - static defaultConfig(cfg) { - cfg.graph = { - margin: { - top: 10, - left: 10, - bottom: 10, - right: 10 - }, - timeCond: {} - }; - } - static adjustConfig(cfg) { - __WEBPACK_IMPORTED_MODULE_4__Canvas__["a" /* Canvas */].adjustConfig(cfg); - __WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */].adjustConfig(cfg); - __WEBPACK_IMPORTED_MODULE_5__Series__["a" /* Series */].adjustConfig(cfg); - __WEBPACK_IMPORTED_MODULE_7__Grid__["a" /* Grid */].adjustConfig(cfg); - __WEBPACK_IMPORTED_MODULE_6__Chart__["a" /* Chart */].adjustConfig(cfg); - __WEBPACK_IMPORTED_MODULE_8__Legend__["a" /* Legend */].adjustConfig(cfg); - } - createPlotArea(cfgm) { - const tl = { - x: cfgm.left + this.marginOffset.left, - y: cfgm.top + this.marginOffset.top - }; - const br = { - x: viewBoxWidth - cfgm.right - this.marginOffset.right, - y: viewBoxHeight - cfgm.bottom - this.marginOffset.bottom - }; - return { tl: tl, br: br }; - } - createData(cfg) { - if (!cfg.series.data) { - console.log('cfg.series.data not set'); - } - if (!(cfg.series.data.length > 0)) { - console.log('cfg.series.data not initialised with array of DataSets'); - } - const timeCond = cfg.graph.timeCond; - return cfg.series.data.map((d) => ((d instanceof __WEBPACK_IMPORTED_MODULE_1_hsdata__["a" /* Data */]) ? d : new __WEBPACK_IMPORTED_MODULE_1_hsdata__["a" /* Data */](d)).filter(timeCond)); - } - createScales(axes) { - if (!this.scales) { - this.scales = { - primary: { x: new __WEBPACK_IMPORTED_MODULE_3__Scale__["a" /* Scale */](axes.primary.x.scale), y: new __WEBPACK_IMPORTED_MODULE_3__Scale__["a" /* Scale */](axes.primary.y.scale) }, - secondary: { x: new __WEBPACK_IMPORTED_MODULE_3__Scale__["a" /* Scale */](axes.secondary.x.scale), y: new __WEBPACK_IMPORTED_MODULE_3__Scale__["a" /* Scale */](axes.secondary.y.scale) } - }; - } - return this.scales; - } - adjustRange(plotArea, scales) { - scales.primary.x.range([plotArea.tl.x, plotArea.br.x]); - scales.primary.y.range([plotArea.br.y, plotArea.tl.y]); - scales.secondary.x.range([plotArea.tl.x, plotArea.br.x]); - scales.secondary.y.range([plotArea.br.y, plotArea.tl.y]); - } - adjustHeight(node) { - if (node.dom && node.dom.parentElement) { - const p = node.dom.parentElement; - const temp = viewBoxWidth * p.clientHeight / p.clientWidth; - if (!isNaN(temp) && temp !== viewBoxHeight) { - viewBoxHeight = temp; - } - } - } - adjustMargins(cfg) { - const cfgm = cfg.graph.margin; - function getBBox(css) { - const elems = document.getElementsByClassName(css); - const box = Array.prototype.map.call(elems, (e) => e.getBBox()); - if (box && box[0]) { - margin.t = Math.max(margin.t, cfgm.top - box[0].y); - margin.l = Math.max(margin.l, cfgm.left - box[0].x); - margin.b = Math.max(margin.b, box[0].y + box[0].height + cfgm.bottom - viewBoxHeight); - margin.r = Math.max(margin.r, box[0].x + box[0].width + cfgm.right - viewBoxWidth); - } - margin.t = Math.min(margin.t, 40); - margin.b = 30; - margin.l = 40; - } - const margin = { t: -1e6, l: -1e6, b: -1e6, r: -1e6 }; - getBBox('hs-graph-axis'); - getBBox('hs-graph-chart'); - this.marginOffset.top += Math.max(margin.t); - this.marginOffset.left += Math.max(margin.l); - this.marginOffset.bottom += Math.max(margin.b); - this.marginOffset.right += Math.max(margin.r); - } - onupdate(node) { - this.adjustHeight(node); - } - oncreate(node) { - window.addEventListener("resize", function () { __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].redraw(); }); - this.adjustHeight(node); - Promise.resolve(node.attrs.cfg) - .then(Object(__WEBPACK_IMPORTED_MODULE_10_hsutil__["b" /* delay */])(10)) - .then(this.adjustMargins.bind(this)) - .then(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].redraw); - } - adjustDomains(cfg, scales, data) { - const domains = [[1e20, -1e20], [1e20, -1e20]]; - cfg.series.map((s) => { - if (s.x) { - data[s.dataIndex].findDomain(s.x, domains[0]); - } - else { - domains[0][0] = 0; - domains[0][1] = data[s.dataIndex].export().rows.length - 1; - } - if (s.y) { - data[s.dataIndex].findDomain(s.y, domains[1]); - } - if (s.yBase) { - data[s.dataIndex].findDomain(s.yBase, domains[1]); - } - }); - scales.primary.x.setAutoDomain(domains[0]); - scales.primary.y.setAutoDomain(domains[1]); - } - view(node) { - const cfgFn = node.attrs.cfgFn; - const cfg = Graph.makeConfig(cfgFn); - const plotArea = this.createPlotArea(cfg.graph.margin); - const scales = this.createScales(cfg.axes); - this.adjustRange(plotArea, scales); - const data = this.createData(cfg); - this.adjustDomains(cfg.series, scales, data); - Graph.adjustConfig(cfg); - node.attrs.cfg = cfg; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph', width: '100%', height: '100%', - viewBox: `0 0 ${Object(__WEBPACK_IMPORTED_MODULE_9__SVGElem__["d" /* round */])(viewBoxWidth)} ${Object(__WEBPACK_IMPORTED_MODULE_9__SVGElem__["d" /* round */])(viewBoxHeight)}` }, [ - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_4__Canvas__["a" /* Canvas */], { cfg: cfg.canvas }), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_6__Chart__["a" /* Chart */], { cfg: cfg.chart, plotArea: plotArea }), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_7__Grid__["a" /* Grid */], { cfg: cfg.grid, scales: scales }), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */], { cfg: cfg.axes, scales: scales }), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_5__Series__["a" /* Series */], { cfg: cfg.series, scales: scales, data: data }), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_8__Legend__["a" /* Legend */], { cfg: cfg.legend }) - ]); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Graph; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR3JhcGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvR3JhcGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBaUVBLE9BQU8sRUFBRSxDQUFDLEVBQVEsTUFBVyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLElBQUksRUFFTyxNQUFTLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQWMsUUFBUSxDQUFDO0FBR3RDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBYSxTQUFTLENBQUM7QUFDdkMsT0FBTyxFQUFFLE1BQU0sRUFDUSxNQUFNLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsTUFBTSxFQUVRLE1BQU0sVUFBVSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxLQUFLLEVBQ1EsTUFBTyxTQUFTLENBQUM7QUFDdkMsT0FBTyxFQUFFLElBQUksRUFDUyxNQUFPLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsTUFBTSxFQUNRLE1BQU0sVUFBVSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxPQUFPLEVBR1AsS0FBSyxFQUFFLE1BQWEsV0FBVyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBYSxRQUFRLENBQUM7QUFFdEMsTUFBTSxZQUFZLEdBQVcsSUFBSSxDQUFDO0FBQ2xDLElBQU0sYUFBYSxHQUFVLEdBQUcsQ0FBQztBQWlEakMsY0FBYyxHQUFPO0lBQ2pCLElBQUksTUFBTSxHQUFPLEVBQUUsQ0FBQztJQUNwQixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFO1FBQzlCLElBQUksT0FBTyxHQUFHLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLEtBQUcsSUFBSSxFQUFFO1lBQ3ZFLE1BQU0sQ0FBQyxD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 - -/***/ }), -/* 21 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Layouter__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tokens__ = __webpack_require__(4); - - -const PillarLayouts = [ - 'columns', 'rows' -]; -/* harmony export (immutable) */ __webpack_exports__["PillarLayouts"] = PillarLayouts; - -const cParams = { - columns: { - cssClass: '.hs-column-layout', - fields: ['top', 'bottom', 'left', 'right', 'height', 'width'] - }, - rows: { - cssClass: '.hs-row-layout', - fields: ['left', 'right', 'top', 'bottom', 'width', 'height'] - } -}; -class PillarLayouter extends __WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */] { - constructor(params, areaDesc) { - super(areaDesc); - this.areaDesc = areaDesc; - this.fields = params.fields; - this.cssClass = params.cssClass; - let n = areaDesc.length - 1; - let first = 0; - let last = 0; - this.unit = areaDesc.some((area) => (area instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["e" /* PixelToken */])) ? - this.unitPixel : this.unitPercent; - areaDesc.some((area, i) => ((areaDesc[i] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? ++first < 0 : true)); - areaDesc.some((area, i) => ((areaDesc[n - i] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? ++last < 0 : true)); - this.firstFixed = first; - this.lastFixed = Math.min(last, areaDesc.length - first); - } - ; - getSizes(num) { - const first = this.firstFixed; - const last = this.lastFixed; - const desc = this.areaDesc; - const len = desc.length; - return [...Array(num).keys()].map((i) => { - let size = null; - let t = null; - if (i > num - 1 - last) { - size = desc[len - (num - i)].getSize(); - t = 'end'; - } - else if (i < first) { - size = desc[i].getSize(); - t = 'start'; - } - else if (len > 0 && len === first) { - size = desc[len - 1].getSize(); - t = 'start'; - } - return { size: size, code: t, fields: {} }; - }); - } - unitPercent(num) { - let f = this.fields; - let max = 100.0; - let styles = this.getSizes(num); - styles.forEach(style => { if (style.size) { - max = max - style.size; - num--; - } }); - let defDim = max / num; - function pass(styles, ix0, ix1, breakCond) { - let sumDim = 0; - styles.some(style => { - let size = style.size || defDim; - if (breakCond(style.code)) { - return true; - } - style.fields[ix0] = sumDim + '%'; - sumDim += size; - style.fields[ix1] = (100 - sumDim) + '%'; - style.fields[f[5]] = 'auto'; - return false; - }); - } - pass(styles, f[2], f[3], (e) => e === 'end'); - pass(styles.reverse(), f[3], f[2], (e) => e !== 'end'); - return styles.reverse(); - } - ; - unitPixel(num) { - let styles = this.getSizes(num); - let f = this.fields; - let defDim = 100.0 / num; - let sumDim = 0; - styles.some((style, i) => { - if (style.code === 'start') { - style.fields[f[2]] = sumDim + 'px'; - sumDim += style.size + (this.spacing || 0) + (this.spacing || 0); - style.fields[f[3]] = 'auto'; - style.fields[f[5]] = style.size + 'px'; - } - else if (style.code === null) { - style.fields[f[2]] = (sumDim > 0) ? (sumDim + 'px') : (i * defDim + '%'); - sumDim = -1; - style.fields[f[3]] = (100 - (i + 1) * defDim) + '%'; - style.fields[f[5]] = 'auto'; - } - else if (style.code === 'end') { - return true; - } - return false; - }); - sumDim = 0; - styles.slice().reverse().some((style, i) => { - style.fields[f[3]] = sumDim + 'px'; - if (style.code === 'end') { - sumDim += style.size + (this.spacing || 0) + (this.spacing || 0); - style.fields[f[2]] = 'auto'; - style.fields[f[5]] = style.size + 'px'; - } - else { - if (sumDim > 0 && style.code !== 'start') { - style.fields[f[5]] = 'auto'; - } - return true; - } - return false; - }); - return styles; - } - ; - getStyles(components) { - let f = this.fields; - let styles = this.unit(components.length); - components.map((c, i) => { - c.style = `${f[0]}:0%; ${f[1]}:0%; `; - Object.keys(styles[i].fields).forEach((st) => { c.style += `${st}: ${styles[i].fields[st]};`; }); - }); - return this.cssClass; - } - ; -} -; -class Columns extends PillarLayouter { - constructor(areaDesc) { - super(cParams[PillarLayouts[0]], areaDesc); - this.areaDesc = areaDesc; - } - ; -} -; -class Rows extends PillarLayouter { - constructor(areaDesc) { - super(cParams[PillarLayouts[1]], areaDesc); - this.areaDesc = areaDesc; - } - ; -} -; -__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register(PillarLayouts[0], Columns); -__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register(PillarLayouts[1], Rows); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGlsbGFyZWRMYXlvdXRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy92aWV3L1BpbGxhcmVkTGF5b3V0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBMkNBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBWSxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUFlLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBUyxVQUFVLENBQUM7QUFnQnBFLE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRztJQUN6QixTQUFTLEVBQUUsTUFBTTtDQUNwQixDQUFDO0FBS0YsTUFBTSxPQUFPLEdBQUc7SUFDWixPQUFPLEVBQWdCO1FBQ25CLFFBQVEsRUFBRSxtQkFBbUI7UUFDN0IsTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUM7S0FDaEU7SUFDRCxJQUFJLEVBQWdCO1FBQ2hCLFFBQVEsRUFBRSxnQkFBZ0I7UUFDMUIsTUFBTSxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUM7S0FDaEU7Q0FDSixDQUFDO0FBT0Ysb0JBQThCLFNBQVEsUUFBUTtJQWExQyxZQUFZLE1BQW1CLEVBQVMsUUFBc0I7UUFDMUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRG9CLGFBQVEsR0FBUixRQUFRLENBQWM7UUFFMUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzVCLElBQUksQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztRQUVoQyxJQUFJLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQztRQUMxQixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxJQUFJLElBQUksR0FBSSxDQUFDLENBQUM7UUFFZCxJQUFJLENBQUMsSUFB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 - -/***/ }), -/* 22 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Layouter__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tokens__ = __webpack_require__(4); - - -class Tiles extends __WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */] { - constructor(areaDesc) { - super(areaDesc); - this.areaDesc = areaDesc; - this.unit = areaDesc.some((area) => (area instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["e" /* PixelToken */])) ? - this.unitPixel : this.unitPercent; - } - ; - unitPercent(num) { - const desc = this.areaDesc; - const fill = this.areaDesc.some(a => (a instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["c" /* FillToken */])); - const root = Math.sqrt(num); - const rows = Math.round(root); - let cols = Math.floor(root); - if (root > cols) { - cols++; - } - let width = (desc[0] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[0].getSize() : undefined; - let height = (desc[1] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[1].getSize() : width; - width = width || 100 / cols; - height = height || 100 / rows; - let left = 0; - let top = 0; - let styles = [...Array(num).keys()].map(i => { - let r = 'auto'; - let w = width + '%'; - let b = 'auto'; - let h = height + '%'; - if ((left + 2 * width) > 100 && fill) { - r = '0%'; - w = 'auto'; - } - if ((top + 2 * height) > 100 && fill) { - b = '0%'; - h = 'auto'; - } - const style = ` - top: ${Math.floor(top)}%; bottom:${b}; - left: ${left}%; right:${r}; - width: ${w}; height: ${h}; - `; - if (Math.round(left += width) > 100 - Math.floor(width)) { - left = 0; - top += height; - } - return style; - }); - return styles; - } - ; - unitPixel(num) { - const desc = this.areaDesc; - const root = Math.sqrt(num); - const rows = Math.round(root); - let cols = Math.floor(root); - if (root > cols) { - cols++; - } - let width = (desc[0] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[0].getSize() : undefined; - let height = (desc[1] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[1].getSize() : width; - width = width || 100 / cols; - height = height || 100 / rows; - let left = 0; - let top = 0; - let styles = [...Array(num).keys()].map(i => { - let r = 'auto'; - let w = width + 'px'; - let b = 'auto'; - let h = height + 'px'; - const style = ` - top: ${Math.floor(top)}%; bottom:${b}; - left: ${left}%; right:${r}; - width: ${w}; height: ${h}; - `; - if (Math.round(left += width) > 100 - Math.floor(width)) { - left = 0; - top += height; - } - return style; - }); - return styles; - } - ; - getStyles(components) { - let styles = this.unit(components.length); - components.map((c, i) => { - c.style = styles[i]; - }); - return '.hs-tile-layout'; - } - ; -} -; -__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register('tiles', Tiles); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGlsZUxheW91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvVGlsZUxheW91dGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZEQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVksWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBZSxTQUFTLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFTLFVBQVUsQ0FBQztBQU8vRSxXQUFZLFNBQVEsUUFBUTtJQVF4QixZQUFtQixRQUFzQjtRQUNyQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFERCxhQUFRLEdBQVIsUUFBUSxDQUFjO1FBSXJDLElBQUksQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQWdCLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxZQUFZLFVBQVUsQ0FBQyxDQUFDLENBQUEsQ0FBQztZQUMxRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFDLENBQUM7SUFBQSxDQUFDO0lBRU0sV0FBVyxDQUFDLEdBQVU7UUFDMUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUMzQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxZQUFZLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDL0QsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzlCLElBQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDOUIsSUFBSSxJQUFJLEdBQUcsSUFBSSxFQUFFO1lBQUUsSUFBSSxFQUFFLENBQUM7U0FB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 - -/***/ }), -/* 23 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__mithril__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Layouter__ = __webpack_require__(3); - - -class Layout { - getComponents(node) { - return !Array.isArray(node.attrs.content) ? node.attrs.content : - node.attrs.content.map((c) => { - if (c.compClass) { - c.attrs.route = node.attrs.route; - return Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(c.compClass, c.attrs); - } - else { - return c; - } - }); - } - getCSS(node) { - return node.attrs.css || ''; - } - normalizeContent(components) { - if (typeof components === 'string') { - return [Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])('.hs-leaf', __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].trust(components))]; - } - if (components.length > 0) { - return components.map((comp) => (comp instanceof Layout) ? comp : Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(Layout, { content: comp })); - } - return [components]; - } - view(node) { - const content = this.normalizeContent(this.getComponents(node)); - let css = __WEBPACK_IMPORTED_MODULE_1__Layouter__["a" /* Layouter */].createLayout(node.attrs, content); - const attrs = { - style: node.style, - route: node.attrs.route, - onclick: node.attrs.onclick - }; - node.attrs.route = undefined; - if (node.attrs.href) { - attrs.href = node.attrs.href; - attrs.oncreate = __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].route.link; - attrs.onupdate = __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].route.link; - } - return Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(`.hs-layout ${css} ${this.getCSS(node)}`, attrs, content.map((c) => c)); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Layout; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5b3V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvTGF5b3V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlCQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQVcsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBWSxZQUFZLENBQUM7QUF5QjVDLE1BQU07SUFvQlEsYUFBYSxDQUFDLElBQVU7UUFDOUIsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMzRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFLLEVBQUUsRUFBRTtnQkFDN0IsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFO29CQUNiLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO29CQUNqQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztpQkFDbEM7cUJBQU07b0JBQ0gsT0FBTyxDQUFDLENBQUM7aUJBQ1o7WUFDTCxDQUFDLENBQUMsQ0FBQztJQUNYLENBQUM7SUFRUyxNQUFNLENBQUMsSUFBVTtRQUN2QixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQztJQUNoQyxDQUFDO0lBR08sZ0JBQWdCLENBQUMsVUFBNkM7UUFDbEUsSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUU7WUFDaEMsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDL0M7UUFDRCxJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFFO1lBQ3JCLE9BQU8sVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQXlCLEVBQVEsRUFBRSxDQUNsRCxDQUFDLElBQUksWUFBWSxNQUFNLENBQUMsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUMsT0FBTyxFQUFDLElBQUksRUFBQyxDQUFDLENBQ2pFLENBQUM7U0FDTDtRQUVELE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBcUJELElBQUksQ0FBQyxJQUFVO1FBQ1gsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNoRSxJQUFJLEdBQUcsR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDckQsTUFBTSxLQUFLLEdBQU87WUFDZCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSztZQUN2QixPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPO1NBQzlCLENBQUM7UUFDRixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUM7UUFDN0IsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRTtZQUNqQixLQUFLLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO1lBQzdCLEtBQUssQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7WUFDOUIsS0FBSyxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztTQUNqQztRQUNELE9BQU8sQ0FBQyxDQUFDLGNBQWMsR0FBRyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RixDQUFDO0NBQ0oifQ== - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var pushStateMock = __webpack_require__(25) -var domMock = __webpack_require__(27) -var xhrMock = __webpack_require__(28) - -module.exports = function(env) { - env = env || {} - var $window = env.window = {} - - var dom = domMock() - var xhr = xhrMock() - for (var key in dom) if (!$window[key]) $window[key] = dom[key] - for (var key in xhr) if (!$window[key]) $window[key] = xhr[key] - pushStateMock(env) - - return $window -} - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var parseURL = __webpack_require__(10) -var callAsync = __webpack_require__(11) - -function debouncedAsync(f) { - var ref - return function() { - if (ref != null) return - ref = callAsync(function(){ - ref = null - f() - }) - } -} - -module.exports = function(options) { - if (options == null) options = {} - - var $window = options.window || {} - var protocol = options.protocol || "http:" - var hostname = options.hostname || "localhost" - var port = "" - var pathname = "/" - var search = "" - var hash = "" - - var past = [{url: getURL(), isNew: true, state: null, title: null}], future = [] - - function getURL() { - if (protocol === "file:") return protocol + "//" + pathname + search + hash - return protocol + "//" + hostname + prefix(":", port) + pathname + search + hash - } - function setURL(value) { - var data = parseURL(value, {protocol: protocol, hostname: hostname, port: port, pathname: pathname}) - var isNew = false - if (data.protocol != null && data.protocol !== protocol) protocol = data.protocol, isNew = true - if (data.hostname != null && data.hostname !== hostname) hostname = data.hostname, isNew = true - if (data.port != null && data.port !== port) port = data.port, isNew = true - if (data.pathname != null && data.pathname !== pathname) pathname = data.pathname, isNew = true - if (data.search != null && data.search !== search) search = data.search, isNew = true - if (data.hash != null && data.hash !== hash) { - hash = data.hash - if (!isNew) { - hashchange() - } - } - return isNew - } - - function prefix(prefix, value) { - if (value === "") return "" - return (value.charAt(0) !== prefix ? prefix : "") + value - } - function _hashchange() { - if (typeof $window.onhashchange === "function") $window.onhashchange({type: "hashchange"}) - } - var hashchange = debouncedAsync(_hashchange) - function popstate() { - if (typeof $window.onpopstate === "function") $window.onpopstate({type: "popstate", state: $window.history.state}) - } - function unload() { - if (typeof $window.onunload === "function") $window.onunload({type: "unload"}) - } - - $window.location = { - get protocol() { - return protocol - }, - get hostname() { - return hostname - }, - get port() { - return port - }, - get pathname() { - return pathname - }, - get search() { - return search - }, - get hash() { - return hash - }, - get origin() { - if (protocol === "file:") return "null" - return protocol + "//" + hostname + prefix(":", port) - }, - get host() { - if (protocol === "file:") return "" - return hostname + prefix(":", port) - }, - get href() { - return getURL() - }, - - set protocol(value) { - throw new Error("Protocol is read-only") - }, - set hostname(value) { - unload() - past.push({url: getURL(), isNew: true}) - future = [] - hostname = value - }, - set port(value) { - if (protocol === "file:") throw new Error("Port is read-only under `file://` protocol") - unload() - past.push({url: getURL(), isNew: true}) - future = [] - port = value - }, - set pathname(value) { - if (protocol === "file:") throw new Error("Pathname is read-only under `file://` protocol") - unload() - past.push({url: getURL(), isNew: true}) - future = [] - pathname = prefix("/", value) - }, - set search(value) { - unload() - past.push({url: getURL(), isNew: true}) - future = [] - search = prefix("?", value) - }, - set hash(value) { - var oldHash = hash - past.push({url: getURL(), isNew: false}) - future = [] - hash = prefix("#", value) - if (oldHash != hash) hashchange() - }, - - set origin(value) { - //origin is writable but ignored - }, - set host(value) { - //host is writable but ignored in Chrome - }, - set href(value) { - var url = getURL() - var isNew = setURL(value) - if (isNew) { - setURL(url) - unload() - setURL(value) - } - past.push({url: url, isNew: isNew}) - future = [] - }, - } - $window.history = { - pushState: function(state, title, url) { - past.push({url: getURL(), isNew: false, state: state, title: title}) - future = [] - setURL(url) - }, - replaceState: function(state, title, url) { - var entry = past[past.length - 1] - entry.state = state - entry.title = title - setURL(url) - }, - back: function() { - if (past.length > 1) { - var entry = past.pop() - if (entry.isNew) unload() - future.push({url: getURL(), isNew: false, state: entry.state, title: entry.title}) - setURL(entry.url) - if (!entry.isNew) popstate() - } - }, - forward: function() { - var entry = future.pop() - if (entry != null) { - if (entry.isNew) unload() - past.push({url: getURL(), isNew: false, state: entry.state, title: entry.title}) - setURL(entry.url) - if (!entry.isNew) popstate() - } - }, - get state() { - return past.length === 0 ? null : past[past.length - 1].state - }, - } - $window.onpopstate = null, - $window.onhashchange = null, - $window.onunload = null - - return $window -} - - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, undefined) { - "use strict"; - - if (global.setImmediate) { - return; - } - - var nextHandle = 1; // Spec says greater than zero - var tasksByHandle = {}; - var currentlyRunningATask = false; - var doc = global.document; - var registerImmediate; - - function setImmediate(callback) { - // Callback can either be a function or a string - if (typeof callback !== "function") { - callback = new Function("" + callback); - } - // Copy function arguments - var args = new Array(arguments.length - 1); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i + 1]; - } - // Store and register the task - var task = { callback: callback, args: args }; - tasksByHandle[nextHandle] = task; - registerImmediate(nextHandle); - return nextHandle++; - } - - function clearImmediate(handle) { - delete tasksByHandle[handle]; - } - - function run(task) { - var callback = task.callback; - var args = task.args; - switch (args.length) { - case 0: - callback(); - break; - case 1: - callback(args[0]); - break; - case 2: - callback(args[0], args[1]); - break; - case 3: - callback(args[0], args[1], args[2]); - break; - default: - callback.apply(undefined, args); - break; - } - } - - function runIfPresent(handle) { - // From the spec: "Wait until any invocations of this algorithm started before this one have completed." - // So if we're currently running a task, we'll need to delay this invocation. - if (currentlyRunningATask) { - // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a - // "too much recursion" error. - setTimeout(runIfPresent, 0, handle); - } else { - var task = tasksByHandle[handle]; - if (task) { - currentlyRunningATask = true; - try { - run(task); - } finally { - clearImmediate(handle); - currentlyRunningATask = false; - } - } - } - } - - function installNextTickImplementation() { - registerImmediate = function(handle) { - process.nextTick(function () { runIfPresent(handle); }); - }; - } - - function canUsePostMessage() { - // The test against `importScripts` prevents this implementation from being installed inside a web worker, - // where `global.postMessage` means something completely different and can't be used for this purpose. - if (global.postMessage && !global.importScripts) { - var postMessageIsAsynchronous = true; - var oldOnMessage = global.onmessage; - global.onmessage = function() { - postMessageIsAsynchronous = false; - }; - global.postMessage("", "*"); - global.onmessage = oldOnMessage; - return postMessageIsAsynchronous; - } - } - - function installPostMessageImplementation() { - // Installs an event handler on `global` for the `message` event: see - // * https://developer.mozilla.org/en/DOM/window.postMessage - // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages - - var messagePrefix = "setImmediate$" + Math.random() + "$"; - var onGlobalMessage = function(event) { - if (event.source === global && - typeof event.data === "string" && - event.data.indexOf(messagePrefix) === 0) { - runIfPresent(+event.data.slice(messagePrefix.length)); - } - }; - - if (global.addEventListener) { - global.addEventListener("message", onGlobalMessage, false); - } else { - global.attachEvent("onmessage", onGlobalMessage); - } - - registerImmediate = function(handle) { - global.postMessage(messagePrefix + handle, "*"); - }; - } - - function installMessageChannelImplementation() { - var channel = new MessageChannel(); - channel.port1.onmessage = function(event) { - var handle = event.data; - runIfPresent(handle); - }; - - registerImmediate = function(handle) { - channel.port2.postMessage(handle); - }; - } - - function installReadyStateChangeImplementation() { - var html = doc.documentElement; - registerImmediate = function(handle) { - // Create a - - \ No newline at end of file diff --git a/docs/example/search.json b/docs/example/search.json deleted file mode 100644 index 56736a6..0000000 --- a/docs/example/search.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - "John", - "Jane", - "Peter", - "Mary" -] \ No newline at end of file diff --git a/docs/hsDoc.css b/docs/hsDoc.css deleted file mode 100644 index 67c8c2a..0000000 --- a/docs/hsDoc.css +++ /dev/null @@ -1,1062 +0,0 @@ -.hs-layout { - left: 0%; - top: 0%; - width: 100%; - height: 100%; - position: absolute; - display: block; - overflow: scroll; -} -.hs-row-layout > .hs-layout { - box-sizing: border-box; -} -.hs-column-layout > .hs-layout { - box-sizing: border-box; -} -.hs-tile-layout > .hs-layout { - box-sizing: border-box; -} -.hs-layout-frame { - position: relative; -} -.hs-layout-fill { - position: relative; - padding: 0; - margin: 0; - width: 100%; - height: 100%; -} -.hs-align-left { - text-align: left; -} -.hs-align-right { - text-align: right; -} -.hs-align-center { - text-align: center; -} -/*# sourceMappingURL=hsLayout.css.map */ -.hs-menu { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; - box-sizing: content-box; - height: 30px; - background-color: transparent; -} -.hs-menu .hs-layout { - overflow: hidden; - border-left: 0.5px solid white; - border-right: 0.5px solid white; -} -.hs-menu .hs-layout:first-child { - border-left: none; -} -.hs-menu .hs-layout:last-child { - border-right: none; -} -.hs-menu .hs-selectable { - overflow: hidden; - padding: 5px 0px 5px 10px; - background-color: #eee; -} -.hs-menu .hs-selected { - background-color: #fff; - font-weight: bold; -} -.hs-collapsible-arrow { - width: 0; - height: 0; - display: inline-block; -} -.hs-collapsible-arrow-right { - width: 0; - height: 0; - display: inline-block; - border-left: 7px solid #666; - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - padding-right: 3px; -} -.hs-collapsible-arrow-down { - width: 0; - height: 0; - display: inline-block; - border-left: 7px solid #666; - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - padding-right: 3px; - transform: rotate(90deg); -} -.hs-collapsible-arrow-up { - width: 0; - height: 0; - display: inline-block; - border-left: 7px solid #666; - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - padding-right: 3px; - transform: rotate(-90deg); -} -.hs-collapsible-arrow-left { - width: 0; - height: 0; - display: inline-block; - border-left: 7px solid #666; - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - padding-right: 3px; - transform: rotate(180deg); -} -.hs-collapsible { - position: relative; -} -.hs-collapsible-title div { - display: inline-block; -} -.hs-collapsible-title div.hs-collapsible-pre { - position: absolute; - margin-right: auto; - left: 3px; - top: 3.5px; -} -.hs-collapsible-title div.hs-collapsible-pre + div { - margin-left: 13px; -} -.hs-collapsible-title div.hs-collapsible-post { - position: absolute; - margin-left: auto; - right: 3px; - top: 3.5px; -} -.hs-collapsible-content { - left: 5px; - position: relative; - overflow: hidden; - height: 0%; - max-height: 0%; -} -.hs-collapsible-expanded .hs-collapsible-content { - height: auto; - max-height: 100%; - transition: all 0.3s ease-in-out; -} -.hs-dropover { - position: relative; -} -.hs-dropover-content { - left: 5px; - position: relative; - transition: all 0.3s ease-in-out; - overflow: hidden; - max-height: 0%; -} -.hs-dropover-content.hs-dropover-expanded { - max-height: 100%; -} -.hs-abstract-button-group { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; -} -.hs-abstract-button { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; -} -.hs-button { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; - margin-left: 5px; - margin-right: 5px; - height: 30px; - border-radius: 6px; - box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); - color: white; - font-weight: bold; - background-color: #48f; -} -.hs-button:hover { - background-color: #2a78ff; -} -.hs-button.hs-button-pressed { - background-color: #aac9ff; -} -.hs-button span { - vertical-align: middle; - line-height: 30px; -} -.hs-button-group { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; - overflow: hidden; - border-radius: 6px; - box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); - background-color: transparent; - height: 30px; -} -.hs-button-group .hs-selectable { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; - line-height: 30px; - background: linear-gradient(to bottom, #eee, #dde); -} -.hs-button-group .hs-selectable.hs-selected { - background: initial; - background-color: #48f; - font-weight: bold; - color: white; -} -.hs-button-group > .hs-layout > :first-child > .hs-selectable { - border-left: none; - border-top-left-radius: 6px; - border-bottom-left-radius: 6px; -} -.hs-button-group > .hs-layout > :last-child > .hs-selectable { - border-right: none; - border-top-right-radius: 6px; - border-bottom-right-radius: 6px; -} -.hs-radio-buttons { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; - overflow: hidden; - border-radius: 6px; - box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); - background-color: transparent; - height: 30px; -} -.hs-radio-buttons .hs-selectable { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; - line-height: 30px; - background: linear-gradient(to bottom, #eee, #dde); -} -.hs-radio-buttons .hs-selectable.hs-selected { - background: initial; - background-color: #48f; - font-weight: bold; - color: white; -} -.hs-radio-buttons > .hs-layout > :first-child > .hs-selectable { - border-left: none; - border-top-left-radius: 6px; - border-bottom-left-radius: 6px; -} -.hs-radio-buttons > .hs-layout > :last-child > .hs-selectable { - border-right: none; - border-top-right-radius: 6px; - border-bottom-right-radius: 6px; -} -.hs-toggle-button { - position: relative; - margin: 0px; - box-sizing: border-box; - text-align: center; - vertical-align: middle; - margin-left: 5px; - margin-right: 5px; - height: 30px; - border-radius: 6px; - box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); - color: white; - font-weight: bold; - background-color: #48f; -} -.hs-toggle-button:hover { - background-color: #2a78ff; -} -.hs-toggle-button.hs-button-pressed { - background-color: #aac9ff; -} -.hs-toggle-button span { - vertical-align: middle; - line-height: 30px; -} -.hs-toggle-button span { - vertical-align: middle; - line-height: 30px; -} -.hs-corner-button { - position: absolute; - top: 0; - right: 0; - font-size: 16pt; - line-height: 20px; - width: 20px; - height: 20px; - border-bottom-left-radius: 5px; - border-top-right-radius: 10px; - text-align: center; - vertical-align: middle; -} -.hs-modal-background { - position: fixed; - left: 0%; - right: 0%; - top: 0%; - bottom: 0%; - background-color: rgba(16, 16, 16, 0.6); - z-index: 998; -} -.hs-modal-foreground { - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - padding: 10px; - background-color: white; - border-radius: 10px; - z-index: 999; - width: auto; - height: auto; -} -.hs-add-button { - position: absolute; - top: 0; - right: 0; - width: 1em; -} -.hs-add-button::before { - content: '+'; -} -.hs-add-button:hover { - font-weight: bold; -} -.hs-remove-button { - position: absolute; - top: -0.5em; - right: 0; - width: 1em; -} -.hs-remove-button::before { - content: '_'; -} -.hs-remove-button:hover { - font-weight: bold; -} -.hs-form { - position: relative; -} -.hs-typeahead-input { - position: relative; - left: 5px; - right: 5px; - top: 0; - box-shadow: 0 0 5px 0px #ccc; - border: 1px solid #ccf; - border-radius: 4px; - padding: 4px; - font-size: 16px; -} -.hs-typeahead-input.hs-typeahead-value { - color: #66f; -} -.hs-typeahead-input.hs-typeahead-placeholder { - color: #ccc; -} -.hs-typeahead-list { - position: absolute; - z-index: 9999; - left: 20px; - width: 200px; - border: 1px solid #aaf; - box-shadow: 0 0 5px 0px #ccc inset; - background-color: white; -} -.hs-typeahead-list div { - padding: 5px; -} -.hs-typeahead-list div:hover { - text-shadow: 0 0 3px #88f; -} -/*# sourceMappingURL=hsWidget.css.map */ -.hs-graph { - font-size: 20px; - position: absolute; -} -.hs-graph-canvas { - fill: none; -} -.hs-graph-axis { - stroke: black; -} -.hs-graph-axis text { - fill: black; - stroke: none; -} -.hs-graph-axis-title { - font-size: 120%; -} -.hs-graph-axis-x .hs-graph-axis-title { - text-anchor: end; -} -.hs-graph-axis-y .hs-graph-axis-title { - text-anchor: middle; -} -.hs-graph-axis-tick-label text { - font-size: 80%; -} -.hs-graph-axis-major-tick-label text { - font-size: 80%; -} -.hs-graph-axis-minor-tick-label text { - font-size: 80%; -} -.hs-graph-axis-minor-tick-label text { - font-size: 80%; -} -.hs-graph-grid line { - stroke-width: 1; -} -.hs-graph-grid-major line { - stroke: #ccc; -} -.hs-graph-grid-minor line { - stroke: #eee; -} -.hs-graph-series { - fill: none; -} -.hs-graph-series-labels { - font-size: 70%; -} -.hs-graph-chart { - fill: white; -} -.hs-graph-chart text { - fill: black; - stroke: none; -} -.hs-graph-chart-title { - font-size: 140%; -} -/*# sourceMappingURL=hsGraph.css.map */ -body { - color: black; -} -.hs-layout { - margin: 0; - padding: 0; -} -th { - text-align: left; -} -.hs-tooltip { - position: relative; - display: inline; -} -.hs-tooltip span { - position: absolute; - white-space: nowrap; - padding-left: 5px; - padding-right: 5px; - font-size: 12px; - color: #FFFFFF; - background: #000; - height: 1.6em; - line-height: 1.6em; - text-align: center; - visibility: hidden; - border-radius: 5px; - box-shadow: -1px 4px 6px #888; -} -.hs-tooltip span:after { - content: ''; - position: absolute; - width: 0; - height: 0; -} -.hs-tooltip span.hs-tooltip-left:after { - top: 50%; - left: 100%; - margin-top: -5px; - border-left: 5px solid #000; - border-top: 5px solid transparent; - border-bottom: 5px solid transparent; -} -.hs-tooltip span.hs-tooltip-right:after { - top: 50%; - right: 100%; - margin-top: -5px; - border-right: 5px solid #000; - border-top: 5px solid transparent; - border-bottom: 5px solid transparent; -} -.hs-tooltip span.hs-tooltip-top:after { - top: 100%; - left: 50%; - margin-left: -5px; - border-top: 5px solid #000; - border-right: 5px solid transparent; - border-left: 5px solid transparent; -} -.hs-tooltip span.hs-tooltip-bottom:after { - bottom: 100%; - left: 50%; - margin-left: -5px; - border-bottom: 5px solid #000; - border-right: 5px solid transparent; - border-left: 5px solid transparent; -} -.hs-tooltip:hover span { - visibility: visible; - opacity: 1; - z-index: 999; -} -.hs-tooltip:hover span.hs-tooltip-left { - right: 100%; - top: 50%; - margin-top: -5px; -} -.hs-tooltip:hover span.hs-tooltip-right { - left: 100%; - top: 50%; - margin-top: -5px; - margin-left: 5px; -} -.hs-tooltip:hover span.hs-tooltip-top { - bottom: 1.6em; - left: 0%; -} -.hs-tooltip:hover span.hs-tooltip-bottom { - top: 1.6em; - left: 0%; - margin-top: 5px; -} -.hs-site-header .hs-site-title { - padding: 5px 10px; - border-bottom: 1px solid #ccc; -} -.hs-site-header .hs-menu .hs-selectable { - border-left: 0.5px solid white; - border-right: rgba(255, 255, 255, 0); - border-bottom: 1px solid #ccc; -} -.hs-site-header .hs-menu .hs-selected { - border-bottom: 1px solid white; -} -.hs-left { - /* - a.hs-left-nav-selected { - background-color: @SelectColor; - &:hover { - background-color: darken(@HoverColor, 10%); - } - } -*/ -} -.hs-left a { - text-decoration: none; - color: black; -} -.hs-left a :link, -.hs-left a :visited { - text-decoration: none; -} -.hs-left .hs-left-nav { - padding: 0px 5px 0 5px; - font-size: 0.8em; - list-style-type: none; -} -.hs-left .hs-library-name { - font-size: 1.6em; - font-weight: bold; - padding: 0.3em 10px; - margin: 2px 0; - height: 0.8em; -} -.hs-left .hs-library-name:hover { - background-color: #eef; -} -.hs-left .hs-left-nav-module { - margin-top: 5px; - margin-bottom: 10px; - border: 1px solid #aaa; - border-radius: 5px; - overflow: hidden; -} -.hs-left .hs-left-nav-module .hs-collapsible-title { - padding-left: 5px; - font-size: 1.2em; - background-color: #eee; -} -.hs-left .hs-left-nav-module .hs-collapsible-title:hover { - background-color: #ccc; -} -.hs-left .hs-left-nav-module.hs-collapsible-expanded .hs-collapsible-title { - background-color: #cfc; -} -.hs-left .hs-left-nav-header { - padding-right: 5px; - text-align: right; - font-style: italic; - background-color: #eef; -} -.hs-left .hs-left-nav-entries { - border-top: 1px solid #ccc; -} -.hs-left .hs-left-nav-entry { - padding-left: 5px; - background-color: transparent; -} -.hs-left .hs-left-nav-entry:hover { - background-color: #fee; -} -.hs-left .hs-left-nav-exported { - color: #44f; - font-weight: bold; -} -.hs-item-padding { - padding: 10px 0.4em 10px 0em; -} -.hs-item-title { - background-color: #eef; - border-top: 1px solid #d5d5ff; - border-bottom: 1px solid #d5d5ff; - margin-top: 5px; - padding: 10px 0.4em 10px 0em; - padding-left: 5px; -} -.hs-item-name { - font-weight: bold; - color: #008; - font-size: 1.1em; -} -.hs-item-unknown-type { - color: #f44; -} -.hs-item-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; -} -.hs-item-export-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; -} -.hs-item-public-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; - color: #484; -} -.hs-item-private-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; - color: #844; -} -.hs-item-protected-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; - color: #884; -} -.hs-item-static-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; - color: #888; -} -.hs-item-constructorProperty-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; - color: #848; -} -.hs-item-optional-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; - color: #aaa; -} -.hs-item-unknown-flag { - color: #44f; - padding: 10px 0.4em 10px 0em; - color: #f44; - font-weight: bold; -} -.hs-item-kind { - font-style: italic; - padding: 10px 0.4em 10px 0em; -} -.hs-item-extends { - padding: 10px 0.4em 10px 0em; - padding-left: 0.3em; -} -.hs-item-extensions { - padding: 10px 0.4em 10px 0em; -} -.hs-item-extension { - padding: 10px 0.4em 10px 0em; -} -.hs-item-unknown-kind { - color: #f44; -} -.hs-item-signature { - font-size: 1em; -} -.hs-item-signature .hs-item-name { - padding: 0; -} -.hs-item-default { - font-size: 90%; - background-color: #fff; - padding: 2px; - border-radius: 4px; - font-weight: bold; -} -.hs-item-sig-type { - border-radius: 4px; - background-color: #ddb; - padding: 2px 4px; - margin-left: 2px; - margin-right: 2px; - font-size: 0.9em; -} -.hs-item-sig-type :link { - text-decoration: none; -} -.hs-item-type-instrinct { - font-style: italic; - color: #800; -} -.hs-item-optional:after { - content: '?'; - font-style: italic; - font-weight: bold; -} -.hs-item-sig-param { - margin: 0 2px; -} -.hs-item-sig-param .hs-item-name { - color: #008; - font-size: 1em; - font-weight: normal; -} -.hs-item-member-source { - float: right; - padding: 10px 0em; - margin-right: 10px; - bottom: 3px; - font-size: 0.7em; -} -.hs-item-comment { - margin-left: 5px; - margin-right: 5px; - font-size: 0.9em; - padding: 5px 0px 10px 0px; -} -.hs-item-comment h1 { - margin-top: 1.3em; - margin-bottom: 1em; - font-size: 2em; - color: #336; -} -.hs-item-comment h2 { - margin-top: 1em; - margin-bottom: 0.6em; - font-size: 1.6em; - color: #336; -} -.hs-item-comment h3 { - margin-top: 1em; - margin-bottom: 0.6em; - font-size: 1.4em; - color: #336; -} -.hs-item-comment h4 { - margin-top: 1em; - margin-bottom: 0.4em; - font-size: 1.1em; - color: #336; -} -.hs-item-comment pre { - margin-top: 5px; -} -.hs-item-comment-special { - margin: 4px 0; - line-height: 1.6em; - font-size: 1em; -} -.hs-item-comment-special .hs-item-comment-tag { - font-size: 0.9em; - background-color: #eee; - border: 1px solid #aae; - border-radius: 2px; - width: 200px; - margin-right: 10px; -} -.hs-item-comment-special .hs-item-comment-tag:after { - content: ':'; -} -.hs-item-comment-desc { - line-height: 1.3em; - margin-top: 5px; - margin-bottom: 10px; -} -.hs-item-comment-desc li, -.hs-item-comment-desc p { - margin: 5px 0 0 0; -} -.hs-item-comment-desc ul { - margin: 0 0 10px 0; -} -.hs-item-comment-params { - display: inline-block; -} -.hs-item-comment-param { - line-height: 1.6em; - margin-top: 5px; - margin-bottom: 5px; - background-color: #eee; - border-radius: 5px; -} -.hs-item-comment-return { - line-height: 1.6em; - margin-top: 5px; - margin-bottom: 5px; - background-color: #eee; - border-radius: 5px; - margin-top: 0px; -} -.hs-item-comment-tag { - padding: 3px 5px; - font-weight: bold; - font-size: 1.1em; - color: #000; -} -.hs-item-comment-return .hs-item-comment-tag { - color: #00A; -} -.hs-item-public .hs-item-comment-return .hs-item-comment-tag { - color: #060; -} -.hs-item-comment-text { - padding: 3px 5px; - color: #000; -} -.hs-item-comment-return .hs-item-comment-text { - color: #00A; -} -.hs-item-public .hs-item-comment-return .hs-item-comment-text { - color: #060; -} -.hs-item-comment-default-value { - font-style: italic; -} -.hs-code-indent { - display: inline-block; - width: 20px; -} -.hs-main-detail { - border-left: 1px solid #ccc; -} -.hs-item-detail { - list-style-type: none; - margin-top: 50px; -} -.hs-item-members { - font-size: 1em; -} -.hs-item-member-title { - background-color: #e0e0ef; - font-size: 1.3em; - font-weight: bold; - padding: 5px 0 5px 0; - margin: 4px 0; -} -.hs-item-member-title span { - margin-left: 5px; - margin-right: 5px; -} -.hs-item-desc { - padding-left: 0.5em; -} -.hs-item-variable { - background: linear-gradient(to bottom, #e0e0ef 30%, rgba(255, 255, 255, 0)); -} -.hs-item-title .hs-item-variable { - background-image: none; -} -.hs-item-member.hs-item-public .hs-item-member-title { - background-color: #e0efe0; - color: #060; -} -.hs-item-member.hs-item-public .hs-item-variable { - background: linear-gradient(to bottom, #e0efe0 30%, rgba(255, 255, 255, 0)); -} -.hs-item-member.hs-item-static .hs-item-member-title { - background-color: #efefe0; - color: #600; -} -.hs-item-member.hs-item-static .hs-item-variable { - background: linear-gradient(to bottom, #efefe0 30%, rgba(255, 255, 255, 0)); -} -.hs-item-child { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-member-type { - display: inline; -} -.hs-item-class { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-interface { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-constructor { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-external-module { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-alias { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-property { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-accessors { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-parameter { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-object-literal { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-variable { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-method { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-function { - padding: 4px 0 10px 0px; - font-size: 1em; -} -.hs-item-inherited { - background-color: #f8f8f8; - font-size: 80%; - color: #444; -} -.hs-item-inherited.hs-item-member-title { - background-color: #eef; - font-size: 100%; -} -.hs-item-inherited .hs-item-inherited-from { - font-style: italic; -} -.hs-item-unknown-member { - padding: 4px 0 10px 0px; - font-size: 1em; - background-color: #f00; - color: #fff; - font-weight: bold; -} -pre { - padding-left: 10px; - margin-right: 10px; - border-radius: 4px; - background-color: #f4f4f4; -} -pre code { - padding: 0; -} -code { - color: #800; - background-color: #f4f4f4; - border-radius: 4px; - padding: 3px; -} -example { - display: block; - height: 300px; - width: 100%; - padding: 5px; - box-sizing: border-box; -} -example .hs-execution { - background-color: #eed; -} -example .hs-execution div { - margin: 0px; -} -example .hs-execution .hs-leaf { - padding: 5px; -} -example .hs-execution .hs-white { - position: absolute; - background-color: white; - padding-left: 5px; - left: 5px; - top: 0; - bottom: 0; - right: 0; -} -example .hs-source .hs-menu .hs-selectable { - background-color: white; -} -example .hs-source .hs-menu .hs-selectable.hs-selected { - background-color: #dde; -} -example .hs-source .hs-source-main { - background-color: #dde; - font-size: 12px; -} -example .hs-source .hs-selected { - background-color: #dde; -} -example pre { - padding-left: 10px; -} -example > .hs-column-layout > .hs-layout:last-child { - border-left: 3px solid white; -} -example code, -example pre { - background-color: transparent; - color: black; - line-height: 18px; -} -.hs-site-footer { - font-size: 50%; - color: #888; -} -body { - font-family: Arial, sans-serif; - font-size: 16px; -} -.hs-indent { - margin-left: 5px; - margin-right: 5px; -} -/*# sourceMappingURL=hsDoc.css.map */ \ No newline at end of file diff --git a/docs/hsDoc.js b/docs/hsDoc.js deleted file mode 100644 index 4503fad..0000000 --- a/docs/hsDoc.js +++ /dev/null @@ -1,12128 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 27); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__view_PillaredLayouter__ = __webpack_require__(29); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__view_TileLayouter__ = __webpack_require__(30); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__view_Layout__ = __webpack_require__(31); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Layout", function() { return __WEBPACK_IMPORTED_MODULE_2__view_Layout__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__view_Tokens__ = __webpack_require__(5); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "FILL", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["b"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "px", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["g"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "pc", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["f"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "LayoutToken", function() { return __WEBPACK_IMPORTED_MODULE_3__view_Tokens__["d"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__view_Layouter__ = __webpack_require__(4); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Layouter", function() { return __WEBPACK_IMPORTED_MODULE_4__view_Layouter__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__hsConfig__ = __webpack_require__(44); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "HsConfig", function() { return __WEBPACK_IMPORTED_MODULE_5__hsConfig__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__mithril__ = __webpack_require__(11); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "m", function() { return __WEBPACK_IMPORTED_MODULE_6__mithril__["a"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "o", function() { return __WEBPACK_IMPORTED_MODULE_6__mithril__["b"]; }); - -if (__WEBPACK_IMPORTED_MODULE_0__view_PillaredLayouter__) { } - -if (__WEBPACK_IMPORTED_MODULE_1__view_TileLayouter__) { } - - - - - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxLQUFLLE9BQU8sTUFBVSx5QkFBeUIsQ0FBQztBQUFNLElBQUcsT0FBTyxFQUFFLEdBQUU7QUFDM0UsT0FBTyxLQUFLLEtBQUssTUFBWSxxQkFBcUIsQ0FBQztBQUFVLElBQUcsS0FBSyxFQUFFLEdBQUU7QUFFekUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFTLGVBQWUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQ1osV0FBVyxFQUFFLE1BQU8sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBVSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVUsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxDQUFDLEVBQVMsQ0FBQyxFQUFFLE1BQU8sV0FBVyxDQUFBIn0= - -/***/ }), -/* 1 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["d"] = round; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return TextHAlign; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return TextVAlign; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); - -function round(num) { - const result = num.toFixed(1); - if (result === 'Infinity') { - return '1e20'; - } - return result; -} -var TextHAlign; -(function (TextHAlign) { - TextHAlign["start"] = "start"; - TextHAlign["middle"] = "middle"; - TextHAlign["end"] = "end"; -})(TextHAlign || (TextHAlign = {})); -var TextVAlign; -(function (TextVAlign) { - TextVAlign["top"] = "top"; - TextVAlign["center"] = "center"; - TextVAlign["bottom"] = "bottom"; -})(TextVAlign || (TextVAlign = {})); -class SVGElem { - text(cfg, text) { - let yShift = 0; - let hAlign = cfg.xpos; - switch (cfg.xpos) { - case TextHAlign.start: break; - case TextHAlign.end: break; - case TextHAlign.middle: - default: - hAlign = TextHAlign.middle; - break; - } - switch (cfg.ypos) { - case TextVAlign.top: - yShift = 0.7; - break; - case TextVAlign.center: - yShift = 0.35; - break; - case TextVAlign.bottom: - default: - yShift = 0; - break; - } - const param = { - x: cfg.x || '', - y: cfg.y || '', - dx: round(cfg.hOffset || 0) + 'em', - dy: round((cfg.vOffset || 0) + yShift) + 'em', - style: `text-anchor:${hAlign}; ${cfg.style || ''}`, - class: cfg.cssClass, - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('text', param, text); - } - rect(tl, area, style, title) { - if (area.w < 0) { - tl.x += area.w; - area.w = -area.w; - } - if (area.h < 0) { - tl.y += area.h; - area.h = -area.h; - } - const param = { - x: round(tl.x), y: round(tl.y), - width: round(area.w) + (area.wunit || ''), - height: round(area.h) + (area.hunit || ''), - style: style - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('rect', param), Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title); - } - circle(c, r, style, title) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('circle', { cx: round(c.x), cy: round(c.y), r: round(r), style: style }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); - } - clipRect(tl, area, id) { - const param = { - x: round(tl.x), y: round(tl.y), - width: round(area.w) + (area.wunit || ''), - height: round(area.h) + (area.hunit || '') - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('defs', Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('clipPath', { id: id }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('rect', param))); - } - line(x0, x1, y0, y1, cssClass) { - const param = { - x1: round(x0), y1: round(y0), - x2: round(x1), y2: round(y1), - class: cssClass - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); - } - horLine(x0, x1, y, cssClass) { - const param = { - x1: round(x0), y1: round(y), - x2: round(x1), y2: round(y), - class: cssClass - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); - } - verLine(x, y0, y1, cssClass) { - const param = { - x1: round(x), y1: round(y0), - x2: round(x), y2: round(y1), - class: cssClass - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('line', param); - } - polyline(data, x, y, scales, id, style, title) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polyline', { - 'clip-path': id ? `url(#${id})` : undefined, - style: style, - points: data.map((row) => `${round(scales.x.convert(row[x]))},${round(scales.y.convert(row[y]))}`).join(' ') - }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); - } - polygon(dataFore, dataBack, x, yFore, yBack, scales, id, style, title) { - const indexed = (x === undefined); - const sx = (_x) => round(scales.x.convert(_x)); - const sy = (_y) => round(scales.y.convert(_y)); - const clip = id ? `url(#${id})` : undefined; - const points = dataFore.map((row, i) => `${sx(indexed ? i : row[x])},${sy(row[yFore])}`) - .concat(dataBack.map((row, i) => `${sx(indexed ? (dataBack.length - i - 1) : row[x])},${sy(yBack ? row[yBack] : 0)}`)).join(' '); - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polygon', { 'clip-path': clip, style: style, points: points }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); - } - shape(points, id, style, title) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('polyline', { - 'clip-path': id ? `url(#${id})` : undefined, - style: style, - points: points.map((row) => `${round(row[0])},${round(row[1])}`).join(' ') - }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('title', title)); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = SVGElem; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU1ZHRWxlbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9TVkdFbGVtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxDQUFDLEVBQVMsTUFBTSxVQUFVLENBQUM7QUF3RXBDLE1BQU0sZ0JBQWlCLEdBQVU7SUFDN0IsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QixJQUFJLE1BQU0sS0FBSyxVQUFVLEVBQUU7UUFDdkIsT0FBTyxNQUFNLENBQUM7S0FDakI7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNsQixDQUFDO0FBRUQsTUFBTSxDQUFOLElBQVksVUFJWDtBQUpELFdBQVksVUFBVTtJQUNsQiw2QkFBaUIsQ0FBQTtJQUNqQiwrQkFBa0IsQ0FBQTtJQUNsQix5QkFBZSxDQUFBO0FBQ25CLENBQUMsRUFKVyxVQUFVLEtBQVYsVUFBVSxRQUlyQjtBQUVELE1BQU0sQ0FBTixJQUFZLFVBSVg7QUFKRCxXQUFZLFVBQVU7SUFDbEIseUJBQWUsQ0FBQTtJQUNmLCtCQUFrQixDQUFBO0lBQ2xCLCtCQUFrQixDQUFBO0FBQ3RCLENBQUMsRUFKVyxVQUFVLEtBQVYsVUFBVSxRQUlyQjtBQUVELE1BQU07SUFNRixJQUFJLENBQUMsR0FBWSxFQUFFLElBQVc7UUFDMUIsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ2YsSUFBSSxNQUFNLEdBQWMsR0FBRyxDQUFDLElBQUksQ0FBQztRQUNqQyxRQUFPLEdBQUcsQ0FBQyxJQUFJLEVBQUU7WUFDYixLQUFLLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBRSxNQUFNO1lBQzlCLEtBQUssVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFJLE1BQU07WUFDOUIsS0FBSyxVQUFVLENBQUMsTUFBTSxDQUFDO1lBQ3ZCO2dCQUFlLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDO2dCQUFDLE1BQU07U0FDcEQ7UUFDRCxRQUFPLEdB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 - -/***/ }), -/* 2 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__TimedPromise__ = __webpack_require__(58); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return __WEBPACK_IMPORTED_MODULE_0__TimedPromise__["b"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return __WEBPACK_IMPORTED_MODULE_0__TimedPromise__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__showdown__ = __webpack_require__(59); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "markDown", function() { return __WEBPACK_IMPORTED_MODULE_1__showdown__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Checksum__ = __webpack_require__(60); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "shortCheckSum", function() { return __WEBPACK_IMPORTED_MODULE_2__Checksum__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Date__ = __webpack_require__(61); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "date", function() { return __WEBPACK_IMPORTED_MODULE_3__Date__["a"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ms", function() { return __WEBPACK_IMPORTED_MODULE_3__Date__["b"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Number__ = __webpack_require__(62); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "round", function() { return __WEBPACK_IMPORTED_MODULE_4__Number__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__PacingQueue__ = __webpack_require__(63); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "PacingQueue", function() { return __WEBPACK_IMPORTED_MODULE_5__PacingQueue__["a"]; }); - - - - - - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVksWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTyxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsTUFBWSxRQUFRLENBQUM7QUFDeEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFlLFVBQVUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQVMsZUFBZSxDQUFDIn0= - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1,eval)("this"); -} catch(e) { - // This works if the window reference is available - if(typeof window === "object") - g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), -/* 4 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Tokens__ = __webpack_require__(5); - -class Layouter { - constructor(areaDesc) { - this.areaDesc = areaDesc; - this.spacing = 0; - } - static translate(params) { - if (params.length === 0) { - params.push(''); - } - return params.map((param) => { - if (typeof param === 'string') { - if (param.endsWith('px')) { - return Object(__WEBPACK_IMPORTED_MODULE_0__Tokens__["g" /* px */])(parseInt(param)); - } - if (param.endsWith('%')) { - return Object(__WEBPACK_IMPORTED_MODULE_0__Tokens__["f" /* pc */])(parseInt(param)); - } - if (param.toLowerCase() === 'fill') { - return __WEBPACK_IMPORTED_MODULE_0__Tokens__["b" /* FILL */]; - } - } - else { - return param; - } - }); - } - static register(keyword, style) { - Layouter.layoutStyles[keyword] = style; - } - static createLayout(attrs, components) { - let css = ''; - Object.keys(Layouter.layoutStyles).some(key => { - if (attrs[key]) { - css = new Layouter.layoutStyles[key](Layouter.translate(attrs[key])).getStyles(components); - attrs[key] = undefined; - return true; - } - return false; - }); - return css; - } - ; -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Layouter; - -Layouter.layoutStyles = {}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5b3V0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdmlldy9MYXlvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFhQSxPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxVQUFVLENBQUM7QUF5QnhDLE1BQU07SUF5RUYsWUFBbUIsUUFBc0I7UUFBdEIsYUFBUSxHQUFSLFFBQVEsQ0FBYztRQVJ6QyxZQUFPLEdBQUcsQ0FBQyxDQUFDO0lBUWdDLENBQUM7SUF6RHJDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBd0I7UUFDN0MsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7U0FBRTtRQUM3QyxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFnQixFQUFFLEVBQUU7WUFDbkMsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUU7Z0JBQzNCLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRTtvQkFBRSxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFBRTtnQkFDekQsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO29CQUFFLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO2lCQUFFO2dCQUN4RCxJQUFJLEtBQUssQ0FBQyxXQUFXLEVBQUUsS0FBRyxNQUFNLEVBQUU7b0JBQUUsT0FBTyxJQUFJLENBQUM7aUJBQUM7YUFDcEQ7aUJBQU07Z0JBQ0gsT0FBTyxLQUFLLENBQUM7YUFDaEI7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFXTSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQWMsRUFBRSxLQUFxQjtRQUV4RCxRQUFRLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUMzQyxDQUFDO0lBVU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxLQUFTLEVBQUUsVUFBdUI7UUFDekQsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBQ2IsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQzFDLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUNaLEdBQUcsR0FBRyxJQUFJLFFBQVEsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDM0YsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsQ0FBQztnQkFDdkIsT0FBTyxJQUFJLENBQUM7YUFDZjtZQUNELE9BQU8sS0FBSyxDQUFDO1FBQ2pCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0lBVzRDLENBQUM7O0FBcEV2QyxxQkFBWSxHQUF1QixFQUFFLENBQUMifQ== - -/***/ }), -/* 5 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["g"] = px; -/* harmony export (immutable) */ __webpack_exports__["f"] = pc; -class LayoutToken { - constructor(size) { - this.size = size; - } - getSize() { return this.size; } -} -/* harmony export (immutable) */ __webpack_exports__["d"] = LayoutToken; - -class DefinedToken extends LayoutToken { - constructor(size) { super(size); } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = DefinedToken; - -class FillToken extends LayoutToken { - constructor() { super(-1); } -} -/* harmony export (immutable) */ __webpack_exports__["c"] = FillToken; - -class PixelToken extends DefinedToken { - constructor(size) { super(size); } -} -/* harmony export (immutable) */ __webpack_exports__["e"] = PixelToken; - -class PercentToken extends DefinedToken { - constructor(size) { super(size); } -} -/* unused harmony export PercentToken */ - -function px(px) { return new PixelToken(px); } -function pc(pc) { return new PercentToken(pc); } -const FILL = new FillToken(); -/* harmony export (immutable) */ __webpack_exports__["b"] = FILL; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9rZW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvVG9rZW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE1BQU07SUFDRixZQUFvQixJQUFZO1FBQVosU0FBSSxHQUFKLElBQUksQ0FBUTtJQUFHLENBQUM7SUFDN0IsT0FBTyxLQUFLLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Q0FDekM7QUFLRCxNQUFNLG1CQUE2QixTQUFRLFdBQVc7SUFDbEQsWUFBWSxJQUFZLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUM3QztBQUtELE1BQU0sZ0JBQWlCLFNBQVEsV0FBVztJQUN0QyxnQkFBZ0IsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0NBQy9CO0FBS0QsTUFBTSxpQkFBa0IsU0FBUSxZQUFZO0lBQ3hDLFlBQVksSUFBVyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Q0FDNUM7QUFLRCxNQUFNLG1CQUFvQixTQUFRLFlBQVk7SUFDMUMsWUFBWSxJQUFXLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUM1QztBQU1ELE1BQU0sYUFBYSxFQUFTLElBQU0sT0FBTyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFNOUQsTUFBTSxhQUFhLEVBQVMsSUFBTSxPQUFPLElBQUksWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUtoRSxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQyJ9 - -/***/ }), -/* 6 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); - -const FILE = './data/index.json'; -class DocSets { - static add(content) { - const lib = content.name; - DocSets.gList.set.push(lib); - DocSets.gList.set.sort(); - DocSets.gList.index[lib] = {}; - recursiveIndex(content, DocSets.gList.index[lib], lib); - } - static loadList(file) { - file = file || FILE; - return DocSets.loadIndexSet(file); - } - static get(lib, id = 0) { - if (lib) { - if (DocSets.gList.index[lib]) { - return DocSets.gList.index[lib][id + '']; - } - else { - return DocSets.gList.set; - } - } - else { - return DocSets.gList.set; - } - } - static loadIndexSet(file) { - return __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].request({ method: "GET", url: file }) - .then((result) => { - DocSets.gTitle = result.title; - let i = file.lastIndexOf('/'); - const dir = file.substring(0, i + 1); - return Promise.all(result.docs.map((f) => loadDocSet(dir, f))); - }) - .catch(console.log); - } - static title() { return DocSets.gTitle; } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = DocSets; - -DocSets.gList = { set: [], index: {} }; -; -function loadDocSet(dir, file) { - return __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].request({ method: "GET", url: dir + file }) - .then((r) => { - DocSets.add(r); - }) - .catch(console.log); -} -function recursiveIndex(content, index, lib, path = '') { - function getNewPath(content) { - content.name = content.name.replace(/["'](.+)["']|(.+)/g, "$1$2"); - const elName = content.name.match(/([^\/]+)$/)[1]; - content.name = elName; - return content.fullPath = (path === '') ? elName : `${path}.${elName}`; - } - function markIfModule(content) { - if (content.comment && content.comment.tags) { - content.comment.tags.forEach((tag) => { - if (tag.tag === 'module') { - content.innerModule = tag.text.trim(); - } - }); - } - } - content.lib = lib; - if (typeof content === 'object' && content.name) { - const newPath = getNewPath(content); - markIfModule(content); - index[content.id + ''] = content; - if (newPath.length > 0) { - index[newPath] = content; - } - if (content.children) { - content.children.map((c) => recursiveIndex(c, index, lib, newPath)); - } - if (content.signatures) { - content.signatures.map((c) => recursiveIndex(c, index, lib, newPath)); - } - if (content.parameters) { - content.parameters.map((c) => recursiveIndex(c, index, lib, newPath)); - } - if (content.type && content.type.declaration && content.type.declaration.children) { - content.type.declaration.children.map((c) => recursiveIndex(c, index, lib, newPath)); - } - } -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG9jU2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9Eb2NTZXRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVNBLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBUyxVQUFVLENBQUM7QUFNaEMsTUFBTSxJQUFJLEdBQVUsbUJBQW1CLENBQUM7QUFPeEMsTUFBTTtJQU1LLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBVztRQUN6QixNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDO1FBQ3pCLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN6QixPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDOUIsY0FBYyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBT00sTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFZO1FBQy9CLElBQUksR0FBRyxJQUFJLElBQUksSUFBSSxDQUFDO1FBRXBCLE9BQU8sT0FBTyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBU00sTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFXLEVBQUUsS0FBaUIsQ0FBQztRQUM3QyxJQUFJLEdBQUcsRUFBRTtZQUNMLElBQUksT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7Z0JBQzFCLE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFDLEVBQUUsQ0FBQyxDQUFDO2FBQzFDO2lCQUFNO2dCQUNILE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FB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 - -/***/ }), -/* 7 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Menu__ = __webpack_require__(46); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Menu", function() { return __WEBPACK_IMPORTED_MODULE_0__Menu__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Button__ = __webpack_require__(47); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Button", function() { return __WEBPACK_IMPORTED_MODULE_1__Button__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__RadioButton__ = __webpack_require__(17); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return __WEBPACK_IMPORTED_MODULE_2__RadioButton__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__ToggleButton__ = __webpack_require__(18); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ToggleButton", function() { return __WEBPACK_IMPORTED_MODULE_3__ToggleButton__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__CornerButton__ = __webpack_require__(19); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "CornerButton", function() { return __WEBPACK_IMPORTED_MODULE_4__CornerButton__["b"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ButtonSymbols", function() { return __WEBPACK_IMPORTED_MODULE_4__CornerButton__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__AddRemove__ = __webpack_require__(48); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "AddButton", function() { return __WEBPACK_IMPORTED_MODULE_5__AddRemove__["a"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "RemoveButton", function() { return __WEBPACK_IMPORTED_MODULE_5__AddRemove__["b"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Collapsible__ = __webpack_require__(49); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Collapsible", function() { return __WEBPACK_IMPORTED_MODULE_6__Collapsible__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Modal__ = __webpack_require__(50); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Modal", function() { return __WEBPACK_IMPORTED_MODULE_7__Modal__["a"]; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__TypeAhead__ = __webpack_require__(51); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "TypeAhead", function() { return __WEBPACK_IMPORTED_MODULE_8__TypeAhead__["a"]; }); - - - - - - - - - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFjLFFBQVEsQ0FBQztBQUV0QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQVksVUFBVSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTyxlQUFlLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxZQUFZLEVBQ1osYUFBYSxFQUNiLE1BQW9CLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxTQUFTLEVBQ1QsWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTyxlQUFlLENBQUM7QUFDN0MsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFhLFNBQVMsQ0FBQztBQUN2QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQVMsYUFBYSxDQUFDIn0= - -/***/ }), -/* 8 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["b"] = oneOfItems; -/* unused harmony export anyItems */ -/* unused harmony export selectable */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); - -function oneOfItems(items, title) { - Object.keys(this.items).forEach((key) => { - this.items[key].isSelected = (key === title); - }); -} -function anyItems(items, title) { - this.items[title].isSelected = !this.items[title].isSelected; -} -class Selector { - constructor() { - this.updateSelected = [oneOfItems, anyItems][0]; - this.items = {}; - } - init(desc, updateSelected = oneOfItems) { - this.updateSelected = updateSelected.bind(this); - desc.items = desc.items || []; - desc.changed = desc.changed || ((item) => console.log(`missing changed() function for menu item ${item}`)); - this.checkSelectedItem(desc); - return desc; - } - ; - checkSelectedItem(desc) { - if (this.selectedItem === undefined) { - if (typeof desc.defaultItem === 'number') { - this.selectedItem = desc.items[desc.defaultItem % desc.items.length]; - } - else { - this.selectedItem = desc.defaultItem || desc.items[0]; - } - } - } - internalStateUpdate(desc, item) { - this.selectedItem = item; - this.checkSelectedItem(desc); - this.updateSelected(this.items, this.selectedItem); - } - renderItem(desc, i) { - const reactor = (callback) => (item) => { - this.internalStateUpdate(desc, item); - if (typeof callback === 'function') { - callback(item); - } - }; - const l = desc.items[i] || ''; - const itemCss = desc.itemCss || []; - this.checkSelectedItem(desc); - return selectable({ - title: l, - css: itemCss[i], - isSelected: this.selectedItem ? (l.toLowerCase() === this.selectedItem.toLowerCase()) : false, - mouseDown: reactor(desc.mouseDown), - mouseUp: reactor(desc.mouseUp), - clicked: reactor(desc.changed) - }); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Selector; - -; -function selectable(childDesc) { - const css = childDesc.css || ''; - const cssSelected = `${childDesc.isSelected ? 'hs-selected' : ''}`; - const onclick = childDesc.clicked ? () => { childDesc.clicked(childDesc.title); } : undefined; - const onmousedown = childDesc.mouseDown ? () => { childDesc.mouseDown(childDesc.title); } : undefined; - const onmouseup = childDesc.mouseUp ? () => { childDesc.mouseUp(childDesc.title); } : undefined; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`.hs-selectable ${css} ${cssSelected}`, { style: childDesc.style, onclick: onclick, onmousedown: onmousedown, onmouseup: onmouseup }, childDesc.title); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VsZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvU2VsZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBcUJBLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxVQUFVLENBQUM7QUEwQzdCLE1BQU0scUJBQXFCLEtBQTZCLEVBQUUsS0FBWTtJQUNsRSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFVLEVBQUUsRUFBRTtRQUMzQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsR0FBRyxDQUFDLEdBQUcsS0FBRyxLQUFLLENBQUMsQ0FBQztJQUMvQyxDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUFNRCxNQUFNLG1CQUFtQixLQUE2QixFQUFFLEtBQVk7SUFDaEUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxVQUFVLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLFVBQVUsQ0FBQztBQUNqRSxDQUFDO0FBTUQsTUFBTTtJQUFOO1FBT1ksbUJBQWMsR0FBWSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUtwRCxVQUFLLEdBQTRCLEVBQUUsQ0FBQztJQStDaEQsQ0FBQztJQTdDRyxJQUFJLENBQUMsSUFBaUIsRUFBRSxpQkFBMEIsVUFBVTtRQUN4RCxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEQsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLElBQVcsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0Q0FBNEMsSUFB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 - -/***/ }), -/* 9 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); - -; - -function getCrossAt(cross, scale) { - let crossesAt; - switch (cross) { - case 'min': - crossesAt = scale.domain()[0]; - break; - case 'max': - crossesAt = scale.domain()[1]; - break; - default: crossesAt = cross || 0; - } - return scale.convert(crossesAt); -} -class Axes extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { - static defaultConfig(cfg) { - function scaleCfg() { - return { - type: Axes.type.linear, - domain: ['auto', 'auto'] - }; - } - function labelCfg(primary, x, major) { - return { - visible: major, text: '', - xpos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].end : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].start), - ypos: x ? (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].bottom) : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].center, - hOffset: x ? 0 : (primary ? -0.7 : 0.7), - vOffset: x ? (primary ? 0.7 : -0.7) : 0 - }; - } - function markCfg(primary, major) { - return { - visible: major, - length: (primary ? 1 : -1) * (major ? 10 : 5) - }; - } - function titleCfg(primary, x) { - return { - visible: true, text: (x ? 'x' : 'y') + (primary ? '' : '2'), - xpos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].end : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].start), - ypos: x ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top : (primary ? __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].bottom : __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].top), - hOffset: x ? -2 : (primary ? 0 : 0.3), - vOffset: x ? (primary ? 0.4 : -1.2) : (primary ? -0.5 : 0.7) - }; - } - function axisCfg(primary, x) { - return { - visible: primary ? true : false, - crossesAt: primary ? 'min' : 'max', - scale: scaleCfg(), - title: titleCfg(primary, x), - ticks: { - major: { - marks: markCfg(primary, true), - labels: labelCfg(primary, x, true), - labelFmt: undefined - }, - minor: { - marks: markCfg(primary, false), - labels: labelCfg(primary, x, false), - labelFmt: undefined - } - } - }; - } - cfg.axes = { - primary: { - x: axisCfg(true, true), - y: axisCfg(true, false) - }, - secondary: { - x: axisCfg(false, true), - y: axisCfg(false, false) - } - }; - } - static adjustConfig(cfg) { - } - drawAxisLine(x, range, cross) { - return x ? this.horLine(range[0], range[1], cross, 'hs-graph-axis-line') : - this.verLine(cross, range[0], range[1], 'hs-graph-axis-line'); - } - drawTitle(x, ttlCfg, type, range, cross) { - ttlCfg.cssClass = 'hs-graph-axis-title'; - const xy = { transform: `translate(${x ? range[1] : cross}, ${x ? cross : range[1]})` }; - return !ttlCfg.visible ? undefined : - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('g', xy, this.text(ttlCfg, ttlCfg.text)); - } - drawTickMarks(x, type, crossesAt, scale, ticks, cfg) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${type}-tick-marks` }, !cfg.marks.visible ? '' : ticks.marks.map((t) => { - return x ? this.verLine(scale.convert(t), crossesAt, crossesAt + cfg.marks.length) : - this.horLine(crossesAt, crossesAt - cfg.marks.length, scale.convert(t)); - })); - } - drawTickLabels(x, type, crossesAt, scale, ticks, cfg) { - scale.setLabelFormat(cfg.labelFmt); - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${type}-tick-label` }, !cfg.labels.visible ? '' : ticks.labels.map((t) => { - const v = scale.convert(t.pos); - const xy = { transform: `translate(${x ? v : crossesAt}, ${x ? crossesAt : v})` }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('g', xy, this.text(cfg.labels, t.text)); - })); - } - drawAxis(dir, scales, type, axisCfg) { - const x = dir === 'x'; - const range = scales[dir].range(); - const cfg = axisCfg[type][dir]; - scales[dir].scaleType(cfg.scale.type); - const crossesAt = getCrossAt(cfg.crossesAt, scales[x ? 'y' : 'x']); - const ticks = scales[dir].ticks(); - return !cfg.visible ? undefined : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-axis-${dir} hs-graph-axis-${type}` }, [ - this.drawAxisLine(x, range, crossesAt), - this.drawTitle(x, cfg.title, type, range, crossesAt), - this.drawTickMarks(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor), - this.drawTickMarks(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major), - this.drawTickLabels(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor), - this.drawTickLabels(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major) - ]); - } - view(node) { - const cfg = node.attrs.cfg; - const scales = node.attrs.scales; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-axis' }, [ - this.drawAxis('x', scales.primary, 'primary', cfg), - this.drawAxis('y', scales.primary, 'primary', cfg), - this.drawAxis('x', scales.secondary, 'secondary', cfg), - this.drawAxis('y', scales.secondary, 'secondary', cfg) - ]); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Axes; - -Axes.type = { - linear: 'linear axis', - log: 'log axis', - date: 'date axis', - index: 'index axis', - percent: 'percent axis', - ordinal: 'ordinal axis', - nominal: 'nominal axis' -}; -class ExampleLinearAxis { -} -class ExampleLogAxis { -} -class ExampleDateAxis { -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXhlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9BeGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZEQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQU8sVUFBVSxDQUFDO0FBVXBDLENBQUM7QUFLRCxPQUFPLEVBQUUsT0FBTyxFQUNQLFVBQVUsRUFDVixVQUFVLEVBQ0osTUFBVSxXQUFXLENBQUM7QUFRckMsb0JBQW9CLEtBQW1CLEVBQUUsS0FBVztJQUNoRCxJQUFJLFNBQWdCLENBQUM7SUFDckIsUUFBUSxLQUFLLEVBQUU7UUFDWCxLQUFLLEtBQUs7WUFBRSxTQUFTLEdBQVcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTTtRQUN6RCxLQUFLLEtBQUs7WUFBRSxTQUFTLEdBQVcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTTtRQUN6RCxPQUFPLENBQUMsQ0FBSSxTQUFTLEdBQVcsS0FBSyxJQUFJLENBQUMsQ0FBQztLQUM5QztJQUNELE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUNwQyxDQUFDO0FBRUQsTUFBTSxXQUFZLFNBQVEsT0FBTztJQWtHN0IsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFVO1FBQzNCO1lBQ0ksT0FBTztnQkFDSCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO2dCQUN0QixNQUFNLEVBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDO2FBQ2xDLENBQUM7UUFDTixDQUFDO1FBQ0Qsa0JBQWtCLE9BQWUsRUFBRSxDQUFTLEVBQUUsS0FBYTtZQUN2RCxPQUFPO2dCQUNILE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7Z0JBQ3hCLElBQUksRUFBRSxDQUFDLENBQUEsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FB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 - -/***/ }), -/* 10 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Series__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_hsutil__ = __webpack_require__(2); - - - - -class Plot extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { - drawLine(clipID, data, x, y, scales, sStyle, title) { - const style = `stroke: ${sStyle.line.color}; stroke-width:${sStyle.line.width};`; - return !sStyle.line.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-line', '') : this.polyline(data, x, y, scales, clipID, style, title); - } - drawMarker(clipID, data, x, y, scales, sStyle, title) { - const mrk = __WEBPACK_IMPORTED_MODULE_2__Series__["a" /* Series */].marker; - let style = `fill:${sStyle.marker.color}`; - return !sStyle.marker.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-marker', '') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series-markers' }, data.map((p) => { - const cx = scales.x.convert(p[x]); - const cy = scales.y.convert(p[y]); - const r = sStyle.marker.size; - switch (sStyle.marker.shape) { - case mrk.circle: - return this.circle({ x: cx, y: cy }, r, style, title); - case mrk.square: - return this.rect({ x: cx - r, y: cy - r }, { w: 2 * r, h: 2 * r }, style, title); - case mrk.diamond: - return this.shape([[cx - r, cy], [cx, cy + r], [cx + r, cy], [cx, cy - r]], undefined, style, title); - case mrk.upTriangle: - return this.shape([[cx - r, cy + r], [cx + r, cy + r], [cx, cy - r]], undefined, style, title); - case mrk.downTriangle: - return this.shape([[cx - r, cy - r], [cx + r, cy - r], [cx, cy + r]], undefined, style, title); - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`.unkown-marker-${sStyle.marker.shape}`, ''); - })); - } - drawLabel(clipID, data, x, y, lbl, scales, sDef) { - const sStyle = sDef.style; - const cfg = { - text: '', - cssClass: ``, - style: `fill:${sStyle.label.color}`, - xpos: __WEBPACK_IMPORTED_MODULE_1__SVGElem__["b" /* TextHAlign */].middle, - ypos: __WEBPACK_IMPORTED_MODULE_1__SVGElem__["c" /* TextVAlign */].center, - hOffset: sDef.hOffset, - vOffset: sDef.vOffset - }; - return !sStyle.marker.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-marker', '') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series-labels' }, data.map((p) => { - cfg.x = '' + scales.x.convert(p[x]); - cfg.y = '' + scales.y.convert(p[y]); - return this.text(cfg, Object(__WEBPACK_IMPORTED_MODULE_3_hsutil__["round"])(p[lbl], 3)); - })); - } - drawArea(clipID, data, x, yFore, yBack, scales, sStyle, title) { - if (sStyle.fill.visible) { - const style = `fill: ${sStyle.fill.color};`; - const drawFore = data; - const drawBack = data.slice().reverse(); - return this.polygon(drawFore, drawBack, x, yFore, yBack, scales, clipID, style, title); - } - else { - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.invisible-line', ''); - } - } - setDefaults(data, series, scales) { - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Plot; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxvdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9QbG90LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sRUFBRSxDQUFDLEVBQVEsTUFBVyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLE9BQU8sRUFFUCxVQUFVLEVBQ1YsVUFBVSxFQUFFLE1BQVEsV0FBVyxDQUFDO0FBSXpDLE9BQU8sRUFBRSxNQUFNLEVBRUssTUFBUyxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFhLFFBQVEsQ0FBQztBQUV0QyxNQUFNLFdBQXFCLFNBQVEsT0FBTztJQUN0QyxRQUFRLENBQUMsTUFBYSxFQUFFLElBQWMsRUFBRSxDQUFRLEVBQUUsQ0FBUSxFQUFFLE1BQWMsRUFBRSxNQUFrQixFQUFFLEtBQWE7UUFDekcsTUFBTSxLQUFLLEdBQUcsV0FBVyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssa0JBQWtCLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUM7UUFDakYsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDbkgsQ0FBQztJQUVELFVBQVUsQ0FBQyxNQUFhLEVBQUUsSUFBYyxFQUFFLENBQVEsRUFBRSxDQUFRLEVBQUUsTUFBYyxFQUFFLE1BQWtCLEVBQUUsS0FBYTtRQUMzRyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzFCLElBQUksS0FBSyxHQUFHLFFBQVEsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMxQyxPQUFPLENBQUMsTUFBTSxD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 - -/***/ }), -/* 11 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return o; }); -if (!global['window']) { - console.log('creating non-browser polyfill'); - global['window'] = __webpack_require__(32)(); - global['document'] = window.document; -} -const m = __webpack_require__(38); -/* harmony export (immutable) */ __webpack_exports__["a"] = m; - -const o = __webpack_require__(39); -o.root = window.document.createElement("div"); - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWl0aHJpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taXRocmlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEVBQUU7SUFDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO0lBRTdDLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxPQUFPLENBQUMsbUNBQW1DLENBQUMsRUFBRSxDQUFDO0lBQ2xFLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDO0NBRXhDO0FBS0QsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQU9wQyxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUN6QyxDQUFDLENBQUMsSUFBSSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBRTlDLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyJ9 -/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(3))) - -/***/ }), -/* 12 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Axes__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__PlotLine__ = __webpack_require__(68); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__PlotMarkers__ = __webpack_require__(69); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__PlotBar__ = __webpack_require__(70); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__PlotArea__ = __webpack_require__(71); - - - - - - - -function copyDefault(target, source, defaults) { - Object.keys(source).forEach((key) => { - if (typeof source[key] === 'object') { - if (target[key] === undefined) { - target[key] = {}; - } - copyDefault(target[key], source[key], defaults); - } - else { - if (target[key] === undefined) { - target[key] = source[key]; - } - if (target[key] === 'default') { - target[key] = defaults[key]; - } - } - }); -} -class Series extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { - static defaultConfig(cfg) { - cfg.series = new SeriesConfig(); - } - static adjustConfig(cfg) { - cfg.series.series.forEach((s) => { - if (s.x === undefined) { - cfg.axes.primary.x.title.hOffset = 0; - cfg.axes.primary.x.scale.type = __WEBPACK_IMPORTED_MODULE_2__Axes__["a" /* Axes */].type.index; - cfg.grid.minor.ver.visible = false; - } - }); - } - drawClipRect(clipID, scales) { - return !clipID ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('') : this.clipRect({ x: scales.x.range()[0], y: scales.y.range()[1] }, { - w: scales.x.range()[1] - scales.x.range()[0], - h: scales.y.range()[0] - scales.y.range()[1] - }, clipID); - } - view(node) { - const cfg = node.attrs.cfg; - const scales = node.attrs.scales.primary; - const data = node.attrs.data; - const clipID = cfg.clip ? 'hs' + Math.floor(Math.random() * 10000) : undefined; - cfg.series.map((s) => { - if (s.map === Series.map.shared) { - s.ySum = '$sum'; - data[s.dataIndex].colAdd(s.ySum); - data[s.dataIndex].colInitialize(s.ySum, 0); - } - }); - cfg.series.map((s) => { - const dt = data[s.dataIndex]; - if (s.map === Series.map.shared) { - const valCol = dt.colNumber(s.y); - dt.colInitialize(s.ySum, (v, i, row) => { return v + row[valCol]; }); - } - if (s.map) { - s.yBase = '$' + s.map; - dt.colAdd(s.yBase); - dt.colInitialize(s.yBase, 0); - } - }); - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-series' }, [ - this.drawClipRect(clipID, scales), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', cfg.series.map((s, i) => { - const dt = data[s.dataIndex]; - const type = Series.plot[s.type] || Series.plot.line; - type.setDefaults(dt, s, scales); - const d = s.cond ? dt.filter(s.cond) : dt; - const plot = type.plot(d, s, scales, i, clipID); - if (s.map) { - const valCol = d.colNumber(s.y); - d.colInitialize(s.yBase, (v, i, row) => { return v + row[valCol]; }); - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: `hs-graph-series-${i}` }, plot); - })) - ]); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Series; - -Series.marker = { - circle: Symbol('circle marker'), - square: Symbol('square marker'), - diamond: Symbol('diamond marker'), - upTriangle: Symbol('upward triangle marker'), - downTriangle: Symbol('downward triangle marker') -}; -Series.plot = { - line: new __WEBPACK_IMPORTED_MODULE_3__PlotLine__["a" /* PlotLine */](), - marker: new __WEBPACK_IMPORTED_MODULE_4__PlotMarkers__["a" /* PlotMarkers */](), - bar: new __WEBPACK_IMPORTED_MODULE_5__PlotBar__["a" /* PlotBar */](), - area: new __WEBPACK_IMPORTED_MODULE_6__PlotArea__["a" /* PlotArea */]() -}; -Series.map = { - stacked: 'stacked', - shared: 'shared' -}; -class SeriesConfig { - constructor() { - this.seriesDefs = []; - this.clip = true; - this.defaultStyle = { - line: { color: 'default', visible: true, width: 2 }, - marker: { color: 'default', visible: false, size: 10, shape: Series.marker.circle }, - label: { color: 'default', visible: false }, - fill: { color: 'default', visible: false }, - bar: { color: 'default', visible: false, width: 50, offset: 30 } - }; - this.defaultColors = ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f', '#000', '#444', '#888', '#ccc']; - } - set series(cfg) { - const defStyle = this.defaultStyle; - const defColors = this.defaultColors; - cfg.forEach((s) => { - s.type = s.type || 'line'; - s.style = s.style || {}; - s.dataIndex = s.dataIndex || 0; - const defaults = { - color: defColors[this.seriesDefs.length] - }; - copyDefault(s.style, defStyle, defaults); - this.seriesDefs.push(s); - switch (s.type) { - case 'line': - s.style.line.visible = true; - break; - case 'marker': - s.style.marker.visible = true; - break; - case 'area': - s.style.fill.visible = true; - break; - case 'bar': - s.style.fill.visible = true; - break; - } - }); - } - get series() { return this.seriesDefs; } -} -/* unused harmony export SeriesConfig */ - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VyaWVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL1Nlcmllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFvQkEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFXLFVBQVUsQ0FBQztBQU14QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQVcsV0FBVyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBYyxRQUFRLENBQUM7QUFFdEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFVLFlBQVksQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU8sZUFBZSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBVyxXQUFXLENBQUM7QUFDekMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFVLFlBQVksQ0FBQztBQUcxQyxxQkFBcUIsTUFBVSxFQUFFLE1BQVUsRUFBRSxRQUFZO0lBQ3JELE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBVSxFQUFFLEVBQUU7UUFDdkMsSUFBSSxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxRQUFRLEVBQUU7WUFDakMsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7YUFBRTtZQUNwRCxXQUFXLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztTQUNuRDthQUFNO1lBQ0gsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7YUFBRTtZQUM3RCxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxTQUFTLEVBQUU7Z0JBQUUsTUFBTSxD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 - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function parseURL(url, root) { - var data = {} - var protocolIndex = url.indexOf("://") - var pathnameIndex = protocolIndex > -1 ? url.indexOf("/", protocolIndex + 3) : url.indexOf("/") - var searchIndex = url.indexOf("?") - var hashIndex = url.indexOf("#") - if ((pathnameIndex > searchIndex && searchIndex > -1) || (pathnameIndex > hashIndex && hashIndex > -1)) pathnameIndex = -1 - if (searchIndex > hashIndex && hashIndex > -1) searchIndex = -1 - var pathnameEnd = searchIndex > -1 ? searchIndex : hashIndex > -1 ? hashIndex : url.length - if (protocolIndex > -1) { - //it's a full URL - if (pathnameIndex < 0) pathnameIndex = url.length - var portIndex = url.indexOf(":", protocolIndex + 1) - if (portIndex < 0) portIndex = pathnameIndex - data.protocol = url.slice(0, protocolIndex + 1) - data.hostname = url.slice(protocolIndex + 3, portIndex) - data.port = url.slice(portIndex + 1, pathnameIndex) - data.pathname = url.slice(pathnameIndex, pathnameEnd) || "/" - } - else { - data.protocol = root.protocol - data.hostname = root.hostname - data.port = root.port - if (pathnameIndex === 0) { - //it's an absolute path - data.pathname = url.slice(pathnameIndex, pathnameEnd) || "/" - } - else if (searchIndex !== 0 && hashIndex !== 0) { - //it's a relative path - var slashIndex = root.pathname.lastIndexOf("/") - var path = slashIndex > -1 ? root.pathname.slice(0, slashIndex + 1) : "./" - var normalized = url.slice(0, pathnameEnd).replace(/^\.$/, root.pathname.slice(slashIndex + 1)).replace(/^\.\//, "") - var dotdot = /\/[^\/]+?\/\.{2}/g - var pathname = path + normalized - pathname = path + normalized - while (dotdot.test(pathname)) pathname = pathname.replace(dotdot, "") - pathname = pathname.replace(/\/\.\//g, "/").replace(/^(\/\.{2})+/, "") || "/" - data.pathname = pathname - } - } - var searchEnd = hashIndex > -1 ? hashIndex : url.length - data.search = searchIndex > -1 ? url.slice(searchIndex, searchEnd) : "" - data.hash = hashIndex > -1 ? url.slice(hashIndex) : "" - return data -} - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(setImmediate) { - -module.exports = typeof setImmediate === "function" ? setImmediate : setTimeout - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(15).setImmediate)) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global) {var apply = Function.prototype.apply; - -// DOM APIs, for completeness - -exports.setTimeout = function() { - return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); -}; -exports.setInterval = function() { - return new Timeout(apply.call(setInterval, window, arguments), clearInterval); -}; -exports.clearTimeout = -exports.clearInterval = function(timeout) { - if (timeout) { - timeout.close(); - } -}; - -function Timeout(id, clearFn) { - this._id = id; - this._clearFn = clearFn; -} -Timeout.prototype.unref = Timeout.prototype.ref = function() {}; -Timeout.prototype.close = function() { - this._clearFn.call(window, this._id); -}; - -// Does not start the time, just sets up the members needed. -exports.enroll = function(item, msecs) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = msecs; -}; - -exports.unenroll = function(item) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = -1; -}; - -exports._unrefActive = exports.active = function(item) { - clearTimeout(item._idleTimeoutId); - - var msecs = item._idleTimeout; - if (msecs >= 0) { - item._idleTimeoutId = setTimeout(function onTimeout() { - if (item._onTimeout) - item._onTimeout(); - }, msecs); - } -}; - -// setimmediate attaches itself to the global object -__webpack_require__(34); -// On some exotic environments, it's not clear which object `setimmeidate` was -// able to install onto. Search each possibility in the same order as the -// `setimmediate` library. -exports.setImmediate = (typeof self !== "undefined" && self.setImmediate) || - (typeof global !== "undefined" && global.setImmediate) || - (this && this.setImmediate); -exports.clearImmediate = (typeof self !== "undefined" && self.clearImmediate) || - (typeof global !== "undefined" && global.clearImmediate) || - (this && this.clearImmediate); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 17 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Selector__ = __webpack_require__(8); - - - - -class RadioButton extends __WEBPACK_IMPORTED_MODULE_1__Selector__["a" /* Selector */] { - viewGroup(css, node) { - const desc = this.init(node.attrs.desc, __WEBPACK_IMPORTED_MODULE_1__Selector__["b" /* oneOfItems */]); - node.attrs.desc = undefined; - css = `${css} ${node.attrs.css || ''}`; - const style = node.attrs.style || ''; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(css, { style: style }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(__WEBPACK_IMPORTED_MODULE_0_hslayout__["Layout"], { - columns: [], - content: desc.items.map((l, i) => this.renderItem(desc, i)) - })); - } - view(node) { return this.viewGroup('.hs-radio-buttons', node); } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = RadioButton; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmFkaW9CdXR0b24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvUmFkaW9CdXR0b24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBaUNBLE9BQU8sRUFBRSxDQUFDLEVBQVMsTUFBVSxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFZLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVUsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBUSxZQUFZLENBQUM7QUFvQjFDLE1BQU0sa0JBQW1CLFNBQVEsUUFBUTtJQUNyQyxTQUFTLENBQUMsR0FBVSxFQUFFLElBQVc7UUFDN0IsTUFBTSxJQUFJLEdBQWdCLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDakUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEdBQUcsU0FBUyxDQUFDO1FBQzVCLEdBQUcsR0FBRyxHQUFHLEdBQUcsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUN2QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7UUFFckMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUMsS0FBSyxFQUFDLEtBQUssRUFBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7WUFDbkMsT0FBTyxFQUFFLEVBQUU7WUFDWCxPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFRLEVBQUUsQ0FBUSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztTQUM1RSxDQUFDLENBQUMsQ0FBQztJQUNSLENBQUM7SUFDRCxJQUFJLENBQUMsSUFBVyxJQUFXLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Q0FDakYifQ== - -/***/ }), -/* 18 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Selector__ = __webpack_require__(8); - - - -class ToggleButton extends __WEBPACK_IMPORTED_MODULE_1__Selector__["a" /* Selector */] { - constructor() { - super(...arguments); - this.toggleIndex = -1; - this.mouseDown = ''; - } - view(node) { - const desc = this.init(node.attrs.desc, __WEBPACK_IMPORTED_MODULE_1__Selector__["b" /* oneOfItems */]); - node.attrs.desc = undefined; - const css = node.attrs.css || ''; - const style = node.attrs.style || ''; - const parentChanged = desc.changed; - desc.changed = ((item) => { - this.toggleIndex = (this.toggleIndex + 1) % desc.items.length; - item = desc.items[this.toggleIndex]; - this.internalStateUpdate(desc, item); - if (parentChanged) { - parentChanged(item); - } - }); - if (this.toggleIndex < 0) { - this.toggleIndex = 0; - } - desc.mouseDown = () => this.mouseDown = '.hs-button-pressed'; - desc.mouseUp = () => this.mouseDown = ''; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`.hs-toggle-button${css}${this.mouseDown}`, { style: style }, Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', this.renderItem(desc, this.toggleIndex))); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = ToggleButton; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9nZ2xlQnV0dG9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL1RvZ2dsZUJ1dHRvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFpQ0EsT0FBTyxFQUFFLENBQUMsRUFBUyxNQUFVLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVUsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBUSxZQUFZLENBQUM7QUFtQjFDLE1BQU0sbUJBQW9CLFNBQVEsUUFBUTtJQUExQzs7UUFDWSxnQkFBVyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ2pCLGNBQVMsR0FBRyxFQUFFLENBQUM7SUF5QjNCLENBQUM7SUF4QkcsSUFBSSxDQUFDLElBQVc7UUFDWixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3BELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLFNBQVMsQ0FBQztRQUM1QixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUM7UUFDakMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDO1FBR3JDLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDbkMsSUFBSSxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsSUFBVyxFQUFFLEVBQUU7WUFDNUIsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLEdBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7WUFDNUQsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ3BDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDckMsSUFBSSxhQUFhLEVBQUU7Z0JBQUUsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO2FBQUU7UUFDL0MsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLElBQUksQ0FBQyxXQUFXLEdBQUMsQ0FBQyxFQUFFO1lBQUUsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7U0FBRTtRQUVqRCxJQUFJLENBQUMsU0FBUyxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUcsb0JBQW9CLENBQUM7UUFDN0QsSUFBSSxDQUFDLE9BQU8sR0FBSyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQztRQUUzQyxPQUFPLENBQUMsQ0FBQyxvQkFBb0IsR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBQyxLQUFLLEVBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUN6RSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQzFDLENBQUMsQ0FBQztJQUNQLENBQUM7Q0FDSiJ9 - -/***/ }), -/* 19 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); - -const ButtonSymbols = { - cross: { sym: '×' }, - minus: { sym: '−' }, - plus: { sym: '+' }, - dLeft: { sym: '«' }, - dRight: { sym: '»' }, - left: { sym: '‹' }, - right: { sym: '›' }, - leftTri: { sym: '◂' }, - rightTri: { sym: '▸' }, - upTri: { sym: '▴' }, - downTri: { sym: '▾' }, - up: { sym: '∧' }, - down: { sym: '∨' }, - lArrow: { sym: '←' }, - rArrow: { sym: '→' }, - uArrow: { sym: '↑' }, - dArrow: { sym: '↓' }, - empty: { sym: '○' }, - emptySlash: { sym: '∅' }, - oSlash: { sym: 'ø' }, - o: { sym: 'ο' }, - lines3: { sym: '≡' }, - sum: { sym: 'Σ' }, - ellipsis: { sym: '…' }, - vertEllips: { sym: '⁝' }, - bullet: { sym: '•' }, - enter: { sym: '↵' }, - again: { sym: '↻' }, - start: { sym: '⇱' }, - end: { sym: '⇲' } -}; -/* harmony export (immutable) */ __webpack_exports__["a"] = ButtonSymbols; - -class CornerButton { - constructor(symbol = '-') { - this.symbol = symbol; - } - static getSymbol(name) { - return ButtonSymbols[name] ? ButtonSymbols[name].sym : ''; - } - view(node) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('.hs-corner-button', { onclick: node.attrs.onclick }, __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].trust(node.attrs.symbol)); - } -} -/* harmony export (immutable) */ __webpack_exports__["b"] = CornerButton; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29ybmVyQnV0dG9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0Nvcm5lckJ1dHRvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUF1REEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFPLFVBQVUsQ0FBQztBQUVwQyxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUc7SUFDekIsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRTtJQUM5QixLQUFLLEVBQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLElBQUksRUFBUSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUM7SUFDdkIsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLElBQUksRUFBUSxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUM7SUFDOUIsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBQztJQUM5QixPQUFPLEVBQUssRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLFFBQVEsRUFBSSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUM7SUFDN0IsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixPQUFPLEVBQUssRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLEVBQUUsRUFBVSxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUM7SUFDM0IsSUFBSSxFQUFRLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBQztJQUMxQixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFDO0lBQzVCLE1BQU0sRUFBTSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUM7SUFDNUIsTUFBTSxFQUFNLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBQztJQUM1QixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFDO0lBQzVCLEtBQUssRUFBTyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUM7SUFDN0IsVUFBVSxFQUFFLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFDO0lBQzlCLENBQUMsRUFBVyxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUM7SUFDL0IsTUFBTSxFQUFNLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixHQUFHLEVBQVMsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLFFBQVEsRUFBSSxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUM7SUFDOUIsVUFBVSxFQUFFLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixNQUFNLEVBQU0sRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFDO0lBQzVCLEtBQUssRUFBTyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUM7SUFDN0IsS0FBSyxFQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQztJQUM3QixLQUFLLEVBQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDO0lBQzdCLEdBQUcsRUFBUyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUM7Q0FDaEMsQ0FBQztBQUVGLE1BQU07SUFDRixZQUFzQixTQUFPLEdBQUc7UUFBVixXQUFNLEdBQU4sTUFBTSxDQUFJO0lBQUcsQ0FBQztJQUNwQyxNQUFNLENBQUMsU0FBUyxDQUFDLElBQVc7UUFDeEIsT0FBTyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUEsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUM3RCxDQUFDO0lBQ0QsSUFBSSxDQUFDLElBQVU7UUFDWCxPQUFPLENBQUMsQ0FBQyxtQkFBbUIsRUFDeEIsRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFDL0IsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQztDQUNKIn0= - -/***/ }), -/* 20 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["b"] = flags; -/* harmony export (immutable) */ __webpack_exports__["e"] = kindString; -/* harmony export (immutable) */ __webpack_exports__["d"] = itemName; -/* unused harmony export itemTooltip */ -/* harmony export (immutable) */ __webpack_exports__["a"] = extensionOf; -/* harmony export (immutable) */ __webpack_exports__["c"] = inheritedFrom; -/* harmony export (immutable) */ __webpack_exports__["i"] = sourceLink; -/* harmony export (immutable) */ __webpack_exports__["f"] = libLink; -/* harmony export (immutable) */ __webpack_exports__["h"] = signature; -/* unused harmony export defaultVal */ -/* harmony export (immutable) */ __webpack_exports__["j"] = type; -/* harmony export (immutable) */ __webpack_exports__["g"] = makeID; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tooltip__ = __webpack_require__(53); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__DocSets__ = __webpack_require__(6); - - - -const SourceBase = 'src/'; -function flags(mdl, ignore = []) { - const ignoreExportInKind = ['Method', 'Property']; - const knownFlags = { - isExported: 'export', - isExternal: 'external', - isPublic: 'public', - isPrivate: 'private', - isProtected: 'protected', - isConstructorProperty: 'constructorProperty', - isStatic: 'static', - isOptional: 'optional' - }; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-flags', !mdl.flags ? [] : - Object.keys(mdl.flags).map((f) => { - let ign = false; - let flag = knownFlags[f]; - if (flag === undefined) { - flag = f; - } - else { - ign = (ignore.indexOf(flag) >= 0); - } - if (flag === 'export' && ignoreExportInKind.indexOf(mdl.kindString) >= 0) { - ign = true; - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`span.hs-item-${ign ? 'ignore' : (flag === f ? 'unknown' : flag)}-flag`, ign ? undefined : flag); - })); -} -function kindString(mdl) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-kind', mdl.kindString); -} -function itemName(mdl, sub) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', !mdl.fullPath ? sub.name : libLink('a', mdl.lib, mdl.fullPath, sub.name)); -} -function itemTooltip(mdl) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', Object(__WEBPACK_IMPORTED_MODULE_1__Tooltip__["a" /* tooltip */])(mdl.name, 'class name and then some', 'bottom')); -} -function extensionOf(mdl) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-extensions', !mdl.extendedTypes ? undefined : [ - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-extends', 'extends'), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', mdl.extendedTypes.map((t, i) => Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-extension', [ - libLink('a', mdl.lib, __WEBPACK_IMPORTED_MODULE_2__DocSets__["a" /* DocSets */].get(mdl.lib, t.id).fullPath, t.name), - mdl.extendedTypes.map.length > (i + 1) ? ', ' : '' - ]))), - ]); -} -function inheritedFrom(mdl) { - if (mdl.inheritedFrom) { - let parent = __WEBPACK_IMPORTED_MODULE_2__DocSets__["a" /* DocSets */].get(mdl.lib, mdl.inheritedFrom.id); - parent = __WEBPACK_IMPORTED_MODULE_2__DocSets__["a" /* DocSets */].get(mdl.lib, parent.fullPath.substring(0, parent.fullPath.lastIndexOf('.'))); - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-inherited-from', [ - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', 'inherited from '), - libLink('a', parent.lib, parent.fullPath, parent.name) - ]); - } - else { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-inherited-from', undefined); - } -} -function sourceLink(mdl) { - const source = mdl.sources ? mdl.sources[0] : undefined; - if (source) { - let file = (source.fileName || '').replace('.ts', '.html'); - const index = file.indexOf(mdl.lib); - if (index > 0) { - file = file.substr(index); - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-member-source', Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('a', { href: `${SourceBase}${mdl.lib}/${file}#${Math.max(0, source.line - 5)}`, target: "_blank" }, '[source]')); - } - else { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-member-source', ''); - } -} -function libLink(css, lib, id, name) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(css, { href: `/api/${lib}/${id}`, oncreate: __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].route.link, onupdate: __WEBPACK_IMPORTED_MODULE_0_hslayout__["m"].route.link }, name); -} -; -function signature(s, mdl) { - const comma = (i) => (i > 0) ? ', ' : ''; - function optional(flags) { - return (flags && flags.isOptional) ? '.hs-item-optional' : ''; - } - let sig = []; - if (s) { - if (s.parameters) { - sig = s.parameters.map((p, i) => Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', [ - comma(i), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-sig-param', [ - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])(`span.hs-item-name${optional(p.flags)}`, p.name), - type(p, mdl.lib) - ]) - ])); - } - switch (mdl.kindString) { - case 'Method': - case 'Function': - case 'Constructor': - sig.unshift(Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', '(')); - sig.push(Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', ')')); - break; - default: - } - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-signature', sig); -} -function defaultVal(s, lib) { - if (s && s.defaultValue) { - let val = ` = ${s.defaultValue}`.replace(/{/gi, '{ ').replace(/}/gi, ' }'); - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-default', val); - } - else { - return; - } -} -function type(t, lib) { - function _type(tt) { - switch (tt.type) { - case undefined: return ''; - case 'array': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-array', ['Array<', _type(tt.elementType), '>']); - case 'tuple': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-tuple', [ - '[ ', - ...tt.elements.map((e, i) => [i > 0 ? ', ' : undefined, _type(e)]), - ' ]' - ]); - case 'intrinsic': - case 'instrinct': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-instrinct', tt.id ? libLink('span', lib, tt.fullPath, tt.name) : tt.name); - case 'stringLiteral': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-string-literal', tt.type); - case 'union': return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-union', [...tt.types.map((e, i) => [i > 0 ? ' | ' : undefined, _type(e)])]); - case 'reference': - let refRes = tt.name; - if (tt.id) { - const typeRef = __WEBPACK_IMPORTED_MODULE_2__DocSets__["a" /* DocSets */].get(lib, tt.id); - if (typeRef.typeArguments) { - refRes = typeRef.name + '<' + typeRef.typeArguments.map(_type).join(', ') + '>'; - } - else if (typeRef.id) { - refRes = libLink('a', lib, typeRef.fullPath, typeRef.name); - } - else { - refRes = typeRef.name; - } - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-reference', refRes); - case 'reflection': - let rflRes; - if (tt.declaration) { - rflRes = !tt.declaration.children ? tt.declaration.kindString : - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-reflection', [ - '{ ', - ...tt.declaration.children.map((c, i) => [i > 0 ? ', ' : undefined, c.name, ': ', _type(c.type)]), - ' }' - ]); - } - else { - rflRes = 'UNKNOWN'; - } - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-type-reflection', rflRes); - default: - console.log('unknown type ' + tt.type); - console.log(t); - return t.type; - } - } - try { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span', !t.type ? '' : [ - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-name', ':'), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('span.hs-item-sig-type', _type(t.type)), - defaultVal(t, lib) - ]); - } - catch (e) { - console.log(e); - console.log(e.trace); - } -} -function makeID(section, mdl) { - let result = section ? section + '_' : ''; - result = (result + (mdl.name || '')).toLowerCase(); - return (result !== '') ? result : undefined; -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFydHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdmlldy9QYXJ0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQU0sVUFBVSxDQUFDO0FBQ25DLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDcEMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUVyQyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUM7QUFJMUIsTUFBTSxnQkFBZ0IsR0FBTyxFQUFFLFNBQWdCLEVBQUU7SUFDN0MsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUNsRCxNQUFNLFVBQVUsR0FBRztRQUNmLFVBQVUsRUFBYyxRQUFRO1FBQ2hDLFVBQVUsRUFBYyxVQUFVO1FBQ2xDLFFBQVEsRUFBZ0IsUUFBUTtRQUNoQyxTQUFTLEVBQWUsU0FBUztRQUNqQyxXQUFXLEVBQWEsV0FBVztRQUNuQyxxQkFBcUIsRUFBRyxxQkFBcUI7UUFDN0MsUUFBUSxFQUFnQixRQUFRO1FBQ2hDLFVBQVUsRUFBYyxVQUFVO0tBQ3JDLENBQUM7SUFDRixPQUFPLENBQUMsQ0FBQyxvQkFBb0IsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzNDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFO1lBQ3BDLElBQUksR0FBRyxHQUFHLEtBQUssQ0FBQztZQUNoQixJQUFJLElBQUksR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDekIsSUFBSSxJQUFJLEtBQUssU0FBUyxFQUFFO2dCQUFFLElBQUksR0FBRyxDQUFDLENBQUM7YUFBRTtpQkFDaEM7Z0JBQUUsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFD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 - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_RESULT__;;/*! showdown 02-06-2017 */ -(function(){ -/** - * Created by Tivie on 13-07-2015. - */ - -function getDefaultOpts (simple) { - 'use strict'; - - var defaultOptions = { - omitExtraWLInCodeBlocks: { - defaultValue: false, - describe: 'Omit the default extra whiteline added to code blocks', - type: 'boolean' - }, - noHeaderId: { - defaultValue: false, - describe: 'Turn on/off generated header id', - type: 'boolean' - }, - prefixHeaderId: { - defaultValue: false, - describe: 'Specify a prefix to generated header ids', - type: 'string' - }, - ghCompatibleHeaderId: { - defaultValue: false, - describe: 'Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)', - type: 'boolean' - }, - headerLevelStart: { - defaultValue: false, - describe: 'The header blocks level start', - type: 'integer' - }, - parseImgDimensions: { - defaultValue: false, - describe: 'Turn on/off image dimension parsing', - type: 'boolean' - }, - simplifiedAutoLink: { - defaultValue: false, - describe: 'Turn on/off GFM autolink style', - type: 'boolean' - }, - excludeTrailingPunctuationFromURLs: { - defaultValue: false, - describe: 'Excludes trailing punctuation from links generated with autoLinking', - type: 'boolean' - }, - literalMidWordUnderscores: { - defaultValue: false, - describe: 'Parse midword underscores as literal underscores', - type: 'boolean' - }, - literalMidWordAsterisks: { - defaultValue: false, - describe: 'Parse midword asterisks as literal asterisks', - type: 'boolean' - }, - strikethrough: { - defaultValue: false, - describe: 'Turn on/off strikethrough support', - type: 'boolean' - }, - tables: { - defaultValue: false, - describe: 'Turn on/off tables support', - type: 'boolean' - }, - tablesHeaderId: { - defaultValue: false, - describe: 'Add an id to table headers', - type: 'boolean' - }, - ghCodeBlocks: { - defaultValue: true, - describe: 'Turn on/off GFM fenced code blocks support', - type: 'boolean' - }, - tasklists: { - defaultValue: false, - describe: 'Turn on/off GFM tasklist support', - type: 'boolean' - }, - smoothLivePreview: { - defaultValue: false, - describe: 'Prevents weird effects in live previews due to incomplete input', - type: 'boolean' - }, - smartIndentationFix: { - defaultValue: false, - description: 'Tries to smartly fix indentation in es6 strings', - type: 'boolean' - }, - disableForced4SpacesIndentedSublists: { - defaultValue: false, - description: 'Disables the requirement of indenting nested sublists by 4 spaces', - type: 'boolean' - }, - simpleLineBreaks: { - defaultValue: false, - description: 'Parses simple line breaks as
    (GFM Style)', - type: 'boolean' - }, - requireSpaceBeforeHeadingText: { - defaultValue: false, - description: 'Makes adding a space between `#` and the header text mandatory (GFM Style)', - type: 'boolean' - }, - ghMentions: { - defaultValue: false, - description: 'Enables github @mentions', - type: 'boolean' - }, - ghMentionsLink: { - defaultValue: 'https://github.com/{u}', - description: 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.', - type: 'string' - }, - encodeEmails: { - defaultValue: true, - description: 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities', - type: 'boolean' - }, - openLinksInNewWindow: { - defaultValue: false, - description: 'Open all links in new windows', - type: 'boolean' - } - }; - if (simple === false) { - return JSON.parse(JSON.stringify(defaultOptions)); - } - var ret = {}; - for (var opt in defaultOptions) { - if (defaultOptions.hasOwnProperty(opt)) { - ret[opt] = defaultOptions[opt].defaultValue; - } - } - return ret; -} - -function allOptionsOn () { - 'use strict'; - var options = getDefaultOpts(true), - ret = {}; - for (var opt in options) { - if (options.hasOwnProperty(opt)) { - ret[opt] = true; - } - } - return ret; -} - -/** - * Created by Tivie on 06-01-2015. - */ - -// Private properties -var showdown = {}, - parsers = {}, - extensions = {}, - globalOptions = getDefaultOpts(true), - setFlavor = 'vanilla', - flavor = { - github: { - omitExtraWLInCodeBlocks: true, - simplifiedAutoLink: true, - excludeTrailingPunctuationFromURLs: true, - literalMidWordUnderscores: true, - strikethrough: true, - tables: true, - tablesHeaderId: true, - ghCodeBlocks: true, - tasklists: true, - disableForced4SpacesIndentedSublists: true, - simpleLineBreaks: true, - requireSpaceBeforeHeadingText: true, - ghCompatibleHeaderId: true, - ghMentions: true - }, - original: { - noHeaderId: true, - ghCodeBlocks: false - }, - ghost: { - omitExtraWLInCodeBlocks: true, - parseImgDimensions: true, - simplifiedAutoLink: true, - excludeTrailingPunctuationFromURLs: true, - literalMidWordUnderscores: true, - strikethrough: true, - tables: true, - tablesHeaderId: true, - ghCodeBlocks: true, - tasklists: true, - smoothLivePreview: true, - simpleLineBreaks: true, - requireSpaceBeforeHeadingText: true, - ghMentions: false, - encodeEmails: true - }, - vanilla: getDefaultOpts(true), - allOn: allOptionsOn() - }; - -/** - * helper namespace - * @type {{}} - */ -showdown.helper = {}; - -/** - * TODO LEGACY SUPPORT CODE - * @type {{}} - */ -showdown.extensions = {}; - -/** - * Set a global option - * @static - * @param {string} key - * @param {*} value - * @returns {showdown} - */ -showdown.setOption = function (key, value) { - 'use strict'; - globalOptions[key] = value; - return this; -}; - -/** - * Get a global option - * @static - * @param {string} key - * @returns {*} - */ -showdown.getOption = function (key) { - 'use strict'; - return globalOptions[key]; -}; - -/** - * Get the global options - * @static - * @returns {{}} - */ -showdown.getOptions = function () { - 'use strict'; - return globalOptions; -}; - -/** - * Reset global options to the default values - * @static - */ -showdown.resetOptions = function () { - 'use strict'; - globalOptions = getDefaultOpts(true); -}; - -/** - * Set the flavor showdown should use as default - * @param {string} name - */ -showdown.setFlavor = function (name) { - 'use strict'; - if (!flavor.hasOwnProperty(name)) { - throw Error(name + ' flavor was not found'); - } - showdown.resetOptions(); - var preset = flavor[name]; - setFlavor = name; - for (var option in preset) { - if (preset.hasOwnProperty(option)) { - globalOptions[option] = preset[option]; - } - } -}; - -/** - * Get the currently set flavor - * @returns {string} - */ -showdown.getFlavor = function () { - 'use strict'; - return setFlavor; -}; - -/** - * Get the options of a specified flavor. Returns undefined if the flavor was not found - * @param {string} name Name of the flavor - * @returns {{}|undefined} - */ -showdown.getFlavorOptions = function (name) { - 'use strict'; - if (flavor.hasOwnProperty(name)) { - return flavor[name]; - } -}; - -/** - * Get the default options - * @static - * @param {boolean} [simple=true] - * @returns {{}} - */ -showdown.getDefaultOptions = function (simple) { - 'use strict'; - return getDefaultOpts(simple); -}; - -/** - * Get or set a subParser - * - * subParser(name) - Get a registered subParser - * subParser(name, func) - Register a subParser - * @static - * @param {string} name - * @param {function} [func] - * @returns {*} - */ -showdown.subParser = function (name, func) { - 'use strict'; - if (showdown.helper.isString(name)) { - if (typeof func !== 'undefined') { - parsers[name] = func; - } else { - if (parsers.hasOwnProperty(name)) { - return parsers[name]; - } else { - throw Error('SubParser named ' + name + ' not registered!'); - } - } - } -}; - -/** - * Gets or registers an extension - * @static - * @param {string} name - * @param {object|function=} ext - * @returns {*} - */ -showdown.extension = function (name, ext) { - 'use strict'; - - if (!showdown.helper.isString(name)) { - throw Error('Extension \'name\' must be a string'); - } - - name = showdown.helper.stdExtName(name); - - // Getter - if (showdown.helper.isUndefined(ext)) { - if (!extensions.hasOwnProperty(name)) { - throw Error('Extension named ' + name + ' is not registered!'); - } - return extensions[name]; - - // Setter - } else { - // Expand extension if it's wrapped in a function - if (typeof ext === 'function') { - ext = ext(); - } - - // Ensure extension is an array - if (!showdown.helper.isArray(ext)) { - ext = [ext]; - } - - var validExtension = validate(ext, name); - - if (validExtension.valid) { - extensions[name] = ext; - } else { - throw Error(validExtension.error); - } - } -}; - -/** - * Gets all extensions registered - * @returns {{}} - */ -showdown.getAllExtensions = function () { - 'use strict'; - return extensions; -}; - -/** - * Remove an extension - * @param {string} name - */ -showdown.removeExtension = function (name) { - 'use strict'; - delete extensions[name]; -}; - -/** - * Removes all extensions - */ -showdown.resetExtensions = function () { - 'use strict'; - extensions = {}; -}; - -/** - * Validate extension - * @param {array} extension - * @param {string} name - * @returns {{valid: boolean, error: string}} - */ -function validate (extension, name) { - 'use strict'; - - var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension', - ret = { - valid: true, - error: '' - }; - - if (!showdown.helper.isArray(extension)) { - extension = [extension]; - } - - for (var i = 0; i < extension.length; ++i) { - var baseMsg = errMsg + ' sub-extension ' + i + ': ', - ext = extension[i]; - if (typeof ext !== 'object') { - ret.valid = false; - ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given'; - return ret; - } - - if (!showdown.helper.isString(ext.type)) { - ret.valid = false; - ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given'; - return ret; - } - - var type = ext.type = ext.type.toLowerCase(); - - // normalize extension type - if (type === 'language') { - type = ext.type = 'lang'; - } - - if (type === 'html') { - type = ext.type = 'output'; - } - - if (type !== 'lang' && type !== 'output' && type !== 'listener') { - ret.valid = false; - ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"'; - return ret; - } - - if (type === 'listener') { - if (showdown.helper.isUndefined(ext.listeners)) { - ret.valid = false; - ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"'; - return ret; - } - } else { - if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) { - ret.valid = false; - ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method'; - return ret; - } - } - - if (ext.listeners) { - if (typeof ext.listeners !== 'object') { - ret.valid = false; - ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given'; - return ret; - } - for (var ln in ext.listeners) { - if (ext.listeners.hasOwnProperty(ln)) { - if (typeof ext.listeners[ln] !== 'function') { - ret.valid = false; - ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln + - ' must be a function but ' + typeof ext.listeners[ln] + ' given'; - return ret; - } - } - } - } - - if (ext.filter) { - if (typeof ext.filter !== 'function') { - ret.valid = false; - ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given'; - return ret; - } - } else if (ext.regex) { - if (showdown.helper.isString(ext.regex)) { - ext.regex = new RegExp(ext.regex, 'g'); - } - if (!(ext.regex instanceof RegExp)) { - ret.valid = false; - ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given'; - return ret; - } - if (showdown.helper.isUndefined(ext.replace)) { - ret.valid = false; - ret.error = baseMsg + '"regex" extensions must implement a replace string or function'; - return ret; - } - } - } - return ret; -} - -/** - * Validate extension - * @param {object} ext - * @returns {boolean} - */ -showdown.validateExtension = function (ext) { - 'use strict'; - - var validateExtension = validate(ext, null); - if (!validateExtension.valid) { - console.warn(validateExtension.error); - return false; - } - return true; -}; - -/** - * showdownjs helper functions - */ - -if (!showdown.hasOwnProperty('helper')) { - showdown.helper = {}; -} - -/** - * Check if var is string - * @static - * @param {string} a - * @returns {boolean} - */ -showdown.helper.isString = function (a) { - 'use strict'; - return (typeof a === 'string' || a instanceof String); -}; - -/** - * Check if var is a function - * @static - * @param {*} a - * @returns {boolean} - */ -showdown.helper.isFunction = function (a) { - 'use strict'; - var getType = {}; - return a && getType.toString.call(a) === '[object Function]'; -}; - -/** - * isArray helper function - * @static - * @param {*} a - * @returns {boolean} - */ -showdown.helper.isArray = function (a) { - 'use strict'; - return a.constructor === Array; -}; - -/** - * Check if value is undefined - * @static - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - */ -showdown.helper.isUndefined = function (value) { - 'use strict'; - return typeof value === 'undefined'; -}; - -/** - * ForEach helper function - * Iterates over Arrays and Objects (own properties only) - * @static - * @param {*} obj - * @param {function} callback Accepts 3 params: 1. value, 2. key, 3. the original array/object - */ -showdown.helper.forEach = function (obj, callback) { - 'use strict'; - // check if obj is defined - if (showdown.helper.isUndefined(obj)) { - throw new Error('obj param is required'); - } - - if (showdown.helper.isUndefined(callback)) { - throw new Error('callback param is required'); - } - - if (!showdown.helper.isFunction(callback)) { - throw new Error('callback param must be a function/closure'); - } - - if (typeof obj.forEach === 'function') { - obj.forEach(callback); - } else if (showdown.helper.isArray(obj)) { - for (var i = 0; i < obj.length; i++) { - callback(obj[i], i, obj); - } - } else if (typeof (obj) === 'object') { - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - callback(obj[prop], prop, obj); - } - } - } else { - throw new Error('obj does not seem to be an array or an iterable object'); - } -}; - -/** - * Standardidize extension name - * @static - * @param {string} s extension name - * @returns {string} - */ -showdown.helper.stdExtName = function (s) { - 'use strict'; - return s.replace(/[_?*+\/\\.^-]/g, '').replace(/\s/g, '').toLowerCase(); -}; - -function escapeCharactersCallback (wholeMatch, m1) { - 'use strict'; - var charCodeToEscape = m1.charCodeAt(0); - return '¨E' + charCodeToEscape + 'E'; -} - -/** - * Callback used to escape characters when passing through String.replace - * @static - * @param {string} wholeMatch - * @param {string} m1 - * @returns {string} - */ -showdown.helper.escapeCharactersCallback = escapeCharactersCallback; - -/** - * Escape characters in a string - * @static - * @param {string} text - * @param {string} charsToEscape - * @param {boolean} afterBackslash - * @returns {XML|string|void|*} - */ -showdown.helper.escapeCharacters = function (text, charsToEscape, afterBackslash) { - 'use strict'; - // First we have to escape the escape characters so that - // we can build a character class out of them - var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])'; - - if (afterBackslash) { - regexString = '\\\\' + regexString; - } - - var regex = new RegExp(regexString, 'g'); - text = text.replace(regex, escapeCharactersCallback); - - return text; -}; - -var rgxFindMatchPos = function (str, left, right, flags) { - 'use strict'; - var f = flags || '', - g = f.indexOf('g') > -1, - x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')), - l = new RegExp(left, f.replace(/g/g, '')), - pos = [], - t, s, m, start, end; - - do { - t = 0; - while ((m = x.exec(str))) { - if (l.test(m[0])) { - if (!(t++)) { - s = x.lastIndex; - start = s - m[0].length; - } - } else if (t) { - if (!--t) { - end = m.index + m[0].length; - var obj = { - left: {start: start, end: s}, - match: {start: s, end: m.index}, - right: {start: m.index, end: end}, - wholeMatch: {start: start, end: end} - }; - pos.push(obj); - if (!g) { - return pos; - } - } - } - } - } while (t && (x.lastIndex = s)); - - return pos; -}; - -/** - * matchRecursiveRegExp - * - * (c) 2007 Steven Levithan - * MIT License - * - * Accepts a string to search, a left and right format delimiter - * as regex patterns, and optional regex flags. Returns an array - * of matches, allowing nested instances of left/right delimiters. - * Use the "g" flag to return all matches, otherwise only the - * first is returned. Be careful to ensure that the left and - * right format delimiters produce mutually exclusive matches. - * Backreferences are not supported within the right delimiter - * due to how it is internally combined with the left delimiter. - * When matching strings whose format delimiters are unbalanced - * to the left or right, the output is intentionally as a - * conventional regex library with recursion support would - * produce, e.g. "<" and ">" both produce ["x"] when using - * "<" and ">" as the delimiters (both strings contain a single, - * balanced instance of ""). - * - * examples: - * matchRecursiveRegExp("test", "\\(", "\\)") - * returns: [] - * matchRecursiveRegExp(">>t<>", "<", ">", "g") - * returns: ["t<>", ""] - * matchRecursiveRegExp("
    test
    ", "]*>", "", "gi") - * returns: ["test"] - */ -showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) { - 'use strict'; - - var matchPos = rgxFindMatchPos (str, left, right, flags), - results = []; - - for (var i = 0; i < matchPos.length; ++i) { - results.push([ - str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end), - str.slice(matchPos[i].match.start, matchPos[i].match.end), - str.slice(matchPos[i].left.start, matchPos[i].left.end), - str.slice(matchPos[i].right.start, matchPos[i].right.end) - ]); - } - return results; -}; - -/** - * - * @param {string} str - * @param {string|function} replacement - * @param {string} left - * @param {string} right - * @param {string} flags - * @returns {string} - */ -showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) { - 'use strict'; - - if (!showdown.helper.isFunction(replacement)) { - var repStr = replacement; - replacement = function () { - return repStr; - }; - } - - var matchPos = rgxFindMatchPos(str, left, right, flags), - finalStr = str, - lng = matchPos.length; - - if (lng > 0) { - var bits = []; - if (matchPos[0].wholeMatch.start !== 0) { - bits.push(str.slice(0, matchPos[0].wholeMatch.start)); - } - for (var i = 0; i < lng; ++i) { - bits.push( - replacement( - str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end), - str.slice(matchPos[i].match.start, matchPos[i].match.end), - str.slice(matchPos[i].left.start, matchPos[i].left.end), - str.slice(matchPos[i].right.start, matchPos[i].right.end) - ) - ); - if (i < lng - 1) { - bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start)); - } - } - if (matchPos[lng - 1].wholeMatch.end < str.length) { - bits.push(str.slice(matchPos[lng - 1].wholeMatch.end)); - } - finalStr = bits.join(''); - } - return finalStr; -}; - -/** - * Returns the index within the passed String object of the first occurrence of the specified regex, - * starting the search at fromIndex. Returns -1 if the value is not found. - * - * @param {string} str string to search - * @param {RegExp} regex Regular expression to search - * @param {int} [fromIndex = 0] Index to start the search - * @returns {Number} - * @throws InvalidArgumentError - */ -showdown.helper.regexIndexOf = function (str, regex, fromIndex) { - 'use strict'; - if (!showdown.helper.isString(str)) { - throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string'; - } - if (regex instanceof RegExp === false) { - throw 'InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp'; - } - var indexOf = str.substring(fromIndex || 0).search(regex); - return (indexOf >= 0) ? (indexOf + (fromIndex || 0)) : indexOf; -}; - -/** - * Splits the passed string object at the defined index, and returns an array composed of the two substrings - * @param {string} str string to split - * @param {int} index index to split string at - * @returns {[string,string]} - * @throws InvalidArgumentError - */ -showdown.helper.splitAtIndex = function (str, index) { - 'use strict'; - if (!showdown.helper.isString(str)) { - throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string'; - } - return [str.substring(0, index), str.substring(index)]; -}; - -/** - * Obfuscate an e-mail address through the use of Character Entities, - * transforming ASCII characters into their equivalent decimal or hex entities. - * - * Since it has a random component, subsequent calls to this function produce different results - * - * @param {string} mail - * @returns {string} - */ -showdown.helper.encodeEmailAddress = function (mail) { - 'use strict'; - var encode = [ - function (ch) { - return '&#' + ch.charCodeAt(0) + ';'; - }, - function (ch) { - return '&#x' + ch.charCodeAt(0).toString(16) + ';'; - }, - function (ch) { - return ch; - } - ]; - - mail = mail.replace(/./g, function (ch) { - if (ch === '@') { - // this *must* be encoded. I insist. - ch = encode[Math.floor(Math.random() * 2)](ch); - } else { - var r = Math.random(); - // roughly 10% raw, 45% hex, 45% dec - ch = ( - r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch) - ); - } - return ch; - }); - - return mail; -}; - -/** - * POLYFILLS - */ -// use this instead of builtin is undefined for IE8 compatibility -if (typeof(console) === 'undefined') { - console = { - warn: function (msg) { - 'use strict'; - alert(msg); - }, - log: function (msg) { - 'use strict'; - alert(msg); - }, - error: function (msg) { - 'use strict'; - throw msg; - } - }; -} - -/** - * Common regexes. - * We declare some common regexes to improve performance - */ -showdown.helper.regexes = { - asteriskAndDash: /([*_])/g -}; - -/** - * Created by Estevao on 31-05-2015. - */ - -/** - * Showdown Converter class - * @class - * @param {object} [converterOptions] - * @returns {Converter} - */ -showdown.Converter = function (converterOptions) { - 'use strict'; - - var - /** - * Options used by this converter - * @private - * @type {{}} - */ - options = {}, - - /** - * Language extensions used by this converter - * @private - * @type {Array} - */ - langExtensions = [], - - /** - * Output modifiers extensions used by this converter - * @private - * @type {Array} - */ - outputModifiers = [], - - /** - * Event listeners - * @private - * @type {{}} - */ - listeners = {}, - - /** - * The flavor set in this converter - */ - setConvFlavor = setFlavor; - - _constructor(); - - /** - * Converter constructor - * @private - */ - function _constructor () { - converterOptions = converterOptions || {}; - - for (var gOpt in globalOptions) { - if (globalOptions.hasOwnProperty(gOpt)) { - options[gOpt] = globalOptions[gOpt]; - } - } - - // Merge options - if (typeof converterOptions === 'object') { - for (var opt in converterOptions) { - if (converterOptions.hasOwnProperty(opt)) { - options[opt] = converterOptions[opt]; - } - } - } else { - throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions + - ' was passed instead.'); - } - - if (options.extensions) { - showdown.helper.forEach(options.extensions, _parseExtension); - } - } - - /** - * Parse extension - * @param {*} ext - * @param {string} [name=''] - * @private - */ - function _parseExtension (ext, name) { - - name = name || null; - // If it's a string, the extension was previously loaded - if (showdown.helper.isString(ext)) { - ext = showdown.helper.stdExtName(ext); - name = ext; - - // LEGACY_SUPPORT CODE - if (showdown.extensions[ext]) { - console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' + - 'Please inform the developer that the extension should be updated!'); - legacyExtensionLoading(showdown.extensions[ext], ext); - return; - // END LEGACY SUPPORT CODE - - } else if (!showdown.helper.isUndefined(extensions[ext])) { - ext = extensions[ext]; - - } else { - throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.'); - } - } - - if (typeof ext === 'function') { - ext = ext(); - } - - if (!showdown.helper.isArray(ext)) { - ext = [ext]; - } - - var validExt = validate(ext, name); - if (!validExt.valid) { - throw Error(validExt.error); - } - - for (var i = 0; i < ext.length; ++i) { - switch (ext[i].type) { - - case 'lang': - langExtensions.push(ext[i]); - break; - - case 'output': - outputModifiers.push(ext[i]); - break; - } - if (ext[i].hasOwnProperty('listeners')) { - for (var ln in ext[i].listeners) { - if (ext[i].listeners.hasOwnProperty(ln)) { - listen(ln, ext[i].listeners[ln]); - } - } - } - } - - } - - /** - * LEGACY_SUPPORT - * @param {*} ext - * @param {string} name - */ - function legacyExtensionLoading (ext, name) { - if (typeof ext === 'function') { - ext = ext(new showdown.Converter()); - } - if (!showdown.helper.isArray(ext)) { - ext = [ext]; - } - var valid = validate(ext, name); - - if (!valid.valid) { - throw Error(valid.error); - } - - for (var i = 0; i < ext.length; ++i) { - switch (ext[i].type) { - case 'lang': - langExtensions.push(ext[i]); - break; - case 'output': - outputModifiers.push(ext[i]); - break; - default:// should never reach here - throw Error('Extension loader error: Type unrecognized!!!'); - } - } - } - - /** - * Listen to an event - * @param {string} name - * @param {function} callback - */ - function listen (name, callback) { - if (!showdown.helper.isString(name)) { - throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given'); - } - - if (typeof callback !== 'function') { - throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given'); - } - - if (!listeners.hasOwnProperty(name)) { - listeners[name] = []; - } - listeners[name].push(callback); - } - - function rTrimInputText (text) { - var rsp = text.match(/^\s*/)[0].length, - rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm'); - return text.replace(rgx, ''); - } - - /** - * Dispatch an event - * @private - * @param {string} evtName Event name - * @param {string} text Text - * @param {{}} options Converter Options - * @param {{}} globals - * @returns {string} - */ - this._dispatch = function dispatch (evtName, text, options, globals) { - if (listeners.hasOwnProperty(evtName)) { - for (var ei = 0; ei < listeners[evtName].length; ++ei) { - var nText = listeners[evtName][ei](evtName, text, this, options, globals); - if (nText && typeof nText !== 'undefined') { - text = nText; - } - } - } - return text; - }; - - /** - * Listen to an event - * @param {string} name - * @param {function} callback - * @returns {showdown.Converter} - */ - this.listen = function (name, callback) { - listen(name, callback); - return this; - }; - - /** - * Converts a markdown string into HTML - * @param {string} text - * @returns {*} - */ - this.makeHtml = function (text) { - //check if text is not falsy - if (!text) { - return text; - } - - var globals = { - gHtmlBlocks: [], - gHtmlMdBlocks: [], - gHtmlSpans: [], - gUrls: {}, - gTitles: {}, - gDimensions: {}, - gListLevel: 0, - hashLinkCounts: {}, - langExtensions: langExtensions, - outputModifiers: outputModifiers, - converter: this, - ghCodeBlocks: [] - }; - - // This lets us use ¨ trema as an escape char to avoid md5 hashes - // The choice of character is arbitrary; anything that isn't - // magic in Markdown will work. - text = text.replace(/¨/g, '¨T'); - - // Replace $ with ¨D - // RegExp interprets $ as a special character - // when it's in a replacement string - text = text.replace(/\$/g, '¨D'); - - // Standardize line endings - text = text.replace(/\r\n/g, '\n'); // DOS to Unix - text = text.replace(/\r/g, '\n'); // Mac to Unix - - // Stardardize line spaces (nbsp causes trouble in older browsers and some regex flavors) - text = text.replace(/\u00A0/g, ' '); - - if (options.smartIndentationFix) { - text = rTrimInputText(text); - } - - // Make sure text begins and ends with a couple of newlines: - text = '\n\n' + text + '\n\n'; - - // detab - text = showdown.subParser('detab')(text, options, globals); - - /** - * Strip any lines consisting only of spaces and tabs. - * This makes subsequent regexs easier to write, because we can - * match consecutive blank lines with /\n+/ instead of something - * contorted like /[ \t]*\n+/ - */ - text = text.replace(/^[ \t]+$/mg, ''); - - //run languageExtensions - showdown.helper.forEach(langExtensions, function (ext) { - text = showdown.subParser('runExtension')(ext, text, options, globals); - }); - - // run the sub parsers - text = showdown.subParser('hashPreCodeTags')(text, options, globals); - text = showdown.subParser('githubCodeBlocks')(text, options, globals); - text = showdown.subParser('hashHTMLBlocks')(text, options, globals); - text = showdown.subParser('hashCodeTags')(text, options, globals); - text = showdown.subParser('stripLinkDefinitions')(text, options, globals); - text = showdown.subParser('blockGamut')(text, options, globals); - text = showdown.subParser('unhashHTMLSpans')(text, options, globals); - text = showdown.subParser('unescapeSpecialChars')(text, options, globals); - - // attacklab: Restore dollar signs - text = text.replace(/¨D/g, '$$'); - - // attacklab: Restore tremas - text = text.replace(/¨T/g, '¨'); - - // Run output modifiers - showdown.helper.forEach(outputModifiers, function (ext) { - text = showdown.subParser('runExtension')(ext, text, options, globals); - }); - - return text; - }; - - /** - * Set an option of this Converter instance - * @param {string} key - * @param {*} value - */ - this.setOption = function (key, value) { - options[key] = value; - }; - - /** - * Get the option of this Converter instance - * @param {string} key - * @returns {*} - */ - this.getOption = function (key) { - return options[key]; - }; - - /** - * Get the options of this Converter instance - * @returns {{}} - */ - this.getOptions = function () { - return options; - }; - - /** - * Add extension to THIS converter - * @param {{}} extension - * @param {string} [name=null] - */ - this.addExtension = function (extension, name) { - name = name || null; - _parseExtension(extension, name); - }; - - /** - * Use a global registered extension with THIS converter - * @param {string} extensionName Name of the previously registered extension - */ - this.useExtension = function (extensionName) { - _parseExtension(extensionName); - }; - - /** - * Set the flavor THIS converter should use - * @param {string} name - */ - this.setFlavor = function (name) { - if (!flavor.hasOwnProperty(name)) { - throw Error(name + ' flavor was not found'); - } - var preset = flavor[name]; - setConvFlavor = name; - for (var option in preset) { - if (preset.hasOwnProperty(option)) { - options[option] = preset[option]; - } - } - }; - - /** - * Get the currently set flavor of this converter - * @returns {string} - */ - this.getFlavor = function () { - return setConvFlavor; - }; - - /** - * Remove an extension from THIS converter. - * Note: This is a costly operation. It's better to initialize a new converter - * and specify the extensions you wish to use - * @param {Array} extension - */ - this.removeExtension = function (extension) { - if (!showdown.helper.isArray(extension)) { - extension = [extension]; - } - for (var a = 0; a < extension.length; ++a) { - var ext = extension[a]; - for (var i = 0; i < langExtensions.length; ++i) { - if (langExtensions[i] === ext) { - langExtensions[i].splice(i, 1); - } - } - for (var ii = 0; ii < outputModifiers.length; ++i) { - if (outputModifiers[ii] === ext) { - outputModifiers[ii].splice(i, 1); - } - } - } - }; - - /** - * Get all extension of THIS converter - * @returns {{language: Array, output: Array}} - */ - this.getAllExtensions = function () { - return { - language: langExtensions, - output: outputModifiers - }; - }; -}; - -/** - * Turn Markdown link shortcuts into XHTML tags. - */ -showdown.subParser('anchors', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('anchors.before', text, options, globals); - - var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) { - if (showdown.helper.isUndefined(title)) { - title = ''; - } - linkId = linkId.toLowerCase(); - - // Special case for explicit empty url - if (wholeMatch.search(/\(? ?(['"].*['"])?\)$/m) > -1) { - url = ''; - } else if (!url) { - if (!linkId) { - // lower-case and turn embedded newlines into spaces - linkId = linkText.toLowerCase().replace(/ ?\n/g, ' '); - } - url = '#' + linkId; - - if (!showdown.helper.isUndefined(globals.gUrls[linkId])) { - url = globals.gUrls[linkId]; - if (!showdown.helper.isUndefined(globals.gTitles[linkId])) { - title = globals.gTitles[linkId]; - } - } else { - return wholeMatch; - } - } - - //url = showdown.helper.escapeCharacters(url, '*_', false); // replaced line to improve performance - url = url.replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback); - - var result = ''; - - return result; - }; - - // First, handle reference-style links: [link text] [id] - text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag); - - // Next, inline-style links: [link text](url "optional title") - // cases with crazy urls like ./image/cat1).png - text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g, - writeAnchorTag); - - // normal cases - text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]??(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g, - writeAnchorTag); - - // handle reference-style shortcuts: [link text] - // These must come last in case you've also got [link test][1] - // or [link test](/foo) - text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag); - - // Lastly handle GithubMentions if option is enabled - if (options.ghMentions) { - text = text.replace(/(^|\s)(\\)?(@([a-z\d\-]+))(?=[.!?;,[\]()]|\s|$)/gmi, function (wm, st, escape, mentions, username) { - if (escape === '\\') { - return st + mentions; - } - - //check if options.ghMentionsLink is a string - if (!showdown.helper.isString(options.ghMentionsLink)) { - throw new Error('ghMentionsLink option must be a string'); - } - var lnk = options.ghMentionsLink.replace(/\{u}/g, username); - return st + '' + mentions + ''; - }); - } - - text = globals.converter._dispatch('anchors.after', text, options, globals); - return text; -}); - -// url allowed chars [a-z\d_.~:/?#[]@!$&'()*+,;=-] - -var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)()(?=\s|$)(?!["<>])/gi, - simpleURLRegex2 = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]]?)(?=\s|$)(?!["<>])/gi, - //simpleURLRegex3 = /\b(((https?|ftp):\/\/|www\.)[a-z\d.-]+\.[a-z\d_.~:/?#\[\]@!$&'()*+,;=-]+?)([.!?()]?)(?=\s|$)(?!["<>])/gi, - delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>/gi, - simpleMailRegex = /(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gmi, - delimMailRegex = /<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi, - - replaceLink = function (options) { - 'use strict'; - - return function (wm, link, m2, m3, trailingPunctuation) { - var lnkTxt = link, - append = '', - target = ''; - if (/^www\./i.test(link)) { - link = link.replace(/^www\./i, 'http://www.'); - } - if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) { - append = trailingPunctuation; - } - if (options.openLinksInNewWindow) { - target = ' target="¨E95Eblank"'; - } - return '' + lnkTxt + '' + append; - }; - }, - - replaceMail = function (options, globals) { - 'use strict'; - return function (wholeMatch, b, mail) { - var href = 'mailto:'; - b = b || ''; - mail = showdown.subParser('unescapeSpecialChars')(mail, options, globals); - if (options.encodeEmails) { - href = showdown.helper.encodeEmailAddress(href + mail); - mail = showdown.helper.encodeEmailAddress(mail); - } else { - href = href + mail; - } - return b + '' + mail + ''; - }; - }; - -showdown.subParser('autoLinks', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('autoLinks.before', text, options, globals); - - text = text.replace(delimUrlRegex, replaceLink(options)); - text = text.replace(delimMailRegex, replaceMail(options, globals)); - - text = globals.converter._dispatch('autoLinks.after', text, options, globals); - - return text; -}); - -showdown.subParser('simplifiedAutoLinks', function (text, options, globals) { - 'use strict'; - - if (!options.simplifiedAutoLink) { - return text; - } - - text = globals.converter._dispatch('simplifiedAutoLinks.before', text, options, globals); - - if (options.excludeTrailingPunctuationFromURLs) { - text = text.replace(simpleURLRegex2, replaceLink(options)); - } else { - text = text.replace(simpleURLRegex, replaceLink(options)); - } - text = text.replace(simpleMailRegex, replaceMail(options, globals)); - - text = globals.converter._dispatch('simplifiedAutoLinks.after', text, options, globals); - - return text; -}); - -/** - * These are all the transformations that form block-level - * tags like paragraphs, headers, and list items. - */ -showdown.subParser('blockGamut', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('blockGamut.before', text, options, globals); - - // we parse blockquotes first so that we can have headings and hrs - // inside blockquotes - text = showdown.subParser('blockQuotes')(text, options, globals); - text = showdown.subParser('headers')(text, options, globals); - - // Do Horizontal Rules: - text = showdown.subParser('horizontalRule')(text, options, globals); - - text = showdown.subParser('lists')(text, options, globals); - text = showdown.subParser('codeBlocks')(text, options, globals); - text = showdown.subParser('tables')(text, options, globals); - - // We already ran _HashHTMLBlocks() before, in Markdown(), but that - // was to escape raw HTML in the original Markdown source. This time, - // we're escaping the markup we've just created, so that we don't wrap - //

    tags around block-level tags. - text = showdown.subParser('hashHTMLBlocks')(text, options, globals); - text = showdown.subParser('paragraphs')(text, options, globals); - - text = globals.converter._dispatch('blockGamut.after', text, options, globals); - - return text; -}); - -showdown.subParser('blockQuotes', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('blockQuotes.before', text, options, globals); - - text = text.replace(/((^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) { - var bq = m1; - - // attacklab: hack around Konqueror 3.5.4 bug: - // "----------bug".replace(/^-/g,"") == "bug" - bq = bq.replace(/^[ \t]*>[ \t]?/gm, '¨0'); // trim one level of quoting - - // attacklab: clean up hack - bq = bq.replace(/¨0/g, ''); - - bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines - bq = showdown.subParser('githubCodeBlocks')(bq, options, globals); - bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse - - bq = bq.replace(/(^|\n)/g, '$1 '); - // These leading spaces screw with

     content, so we need to fix that:
    -    bq = bq.replace(/(\s*
    [^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
    -      var pre = m1;
    -      // attacklab: hack around Konqueror 3.5.4 bug:
    -      pre = pre.replace(/^  /mg, '¨0');
    -      pre = pre.replace(/¨0/g, '');
    -      return pre;
    -    });
    -
    -    return showdown.subParser('hashBlock')('
    \n' + bq + '\n
    ', options, globals); - }); - - text = globals.converter._dispatch('blockQuotes.after', text, options, globals); - return text; -}); - -/** - * Process Markdown `
    ` blocks.
    - */
    -showdown.subParser('codeBlocks', function (text, options, globals) {
    -  'use strict';
    -
    -  text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
    -
    -  // sentinel workarounds for lack of \A and \Z, safari\khtml bug
    -  text += '¨0';
    -
    -  var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g;
    -  text = text.replace(pattern, function (wholeMatch, m1, m2) {
    -    var codeblock = m1,
    -        nextChar = m2,
    -        end = '\n';
    -
    -    codeblock = showdown.subParser('outdent')(codeblock, options, globals);
    -    codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);
    -    codeblock = showdown.subParser('detab')(codeblock, options, globals);
    -    codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
    -    codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
    -
    -    if (options.omitExtraWLInCodeBlocks) {
    -      end = '';
    -    }
    -
    -    codeblock = '
    ' + codeblock + end + '
    '; - - return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar; - }); - - // strip sentinel - text = text.replace(/¨0/, ''); - - text = globals.converter._dispatch('codeBlocks.after', text, options, globals); - return text; -}); - -/** - * - * * Backtick quotes are used for spans. - * - * * You can use multiple backticks as the delimiters if you want to - * include literal backticks in the code span. So, this input: - * - * Just type ``foo `bar` baz`` at the prompt. - * - * Will translate to: - * - *

    Just type foo `bar` baz at the prompt.

    - * - * There's no arbitrary limit to the number of backticks you - * can use as delimters. If you need three consecutive backticks - * in your code, use four for delimiters, etc. - * - * * You can use spaces to get literal backticks at the edges: - * - * ... type `` `bar` `` ... - * - * Turns to: - * - * ... type `bar` ... - */ -showdown.subParser('codeSpans', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('codeSpans.before', text, options, globals); - - if (typeof(text) === 'undefined') { - text = ''; - } - text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, - function (wholeMatch, m1, m2, m3) { - var c = m3; - c = c.replace(/^([ \t]*)/g, ''); // leading whitespace - c = c.replace(/[ \t]*$/g, ''); // trailing whitespace - c = showdown.subParser('encodeCode')(c, options, globals); - return m1 + '' + c + ''; - } - ); - - text = globals.converter._dispatch('codeSpans.after', text, options, globals); - return text; -}); - -/** - * Convert all tabs to spaces - */ -showdown.subParser('detab', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('detab.before', text, options, globals); - - // expand first n-1 tabs - text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width - - // replace the nth with two sentinels - text = text.replace(/\t/g, '¨A¨B'); - - // use the sentinel to anchor our regex so it doesn't explode - text = text.replace(/¨B(.+?)¨A/g, function (wholeMatch, m1) { - var leadingText = m1, - numSpaces = 4 - leadingText.length % 4; // g_tab_width - - // there *must* be a better way to do this: - for (var i = 0; i < numSpaces; i++) { - leadingText += ' '; - } - - return leadingText; - }); - - // clean up sentinels - text = text.replace(/¨A/g, ' '); // g_tab_width - text = text.replace(/¨B/g, ''); - - text = globals.converter._dispatch('detab.after', text, options, globals); - return text; -}); - -/** - * Smart processing for ampersands and angle brackets that need to be encoded. - */ -showdown.subParser('encodeAmpsAndAngles', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('encodeAmpsAndAngles.before', text, options, globals); - - // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: - // http://bumppo.net/projects/amputator/ - text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&'); - - // Encode naked <'s - text = text.replace(/<(?![a-z\/?$!])/gi, '<'); - - // Encode < - text = text.replace(/ - text = text.replace(/>/g, '>'); - - text = globals.converter._dispatch('encodeAmpsAndAngles.after', text, options, globals); - return text; -}); - -/** - * Returns the string, with after processing the following backslash escape sequences. - * - * attacklab: The polite way to do this is with the new escapeCharacters() function: - * - * text = escapeCharacters(text,"\\",true); - * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); - * - * ...but we're sidestepping its use of the (slow) RegExp constructor - * as an optimization for Firefox. This function gets called a LOT. - */ -showdown.subParser('encodeBackslashEscapes', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('encodeBackslashEscapes.before', text, options, globals); - - text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback); - text = text.replace(/\\([`*_{}\[\]()>#+.!~=|-])/g, showdown.helper.escapeCharactersCallback); - - text = globals.converter._dispatch('encodeBackslashEscapes.after', text, options, globals); - return text; -}); - -/** - * Encode/escape certain characters inside Markdown code runs. - * The point is that in code, these characters are literals, - * and lose their special Markdown meanings. - */ -showdown.subParser('encodeCode', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('encodeCode.before', text, options, globals); - - // Encode all ampersands; HTML entities are not - // entities within a Markdown code span. - text = text - .replace(/&/g, '&') - // Do the angle bracket song and dance: - .replace(//g, '>') - // Now, escape characters that are magic in Markdown: - .replace(/([*_{}\[\]\\=~-])/g, showdown.helper.escapeCharactersCallback); - - text = globals.converter._dispatch('encodeCode.after', text, options, globals); - return text; -}); - -/** - * Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they - * don't conflict with their use in Markdown for code, italics and strong. - */ -showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.before', text, options, globals); - - // Build a regex to find HTML tags and comments. See Friedl's - // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. - var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi; - - text = text.replace(regex, function (wholeMatch) { - return wholeMatch - .replace(/(.)<\/?code>(?=.)/g, '$1`') - .replace(/([\\`*_~=|])/g, showdown.helper.escapeCharactersCallback); - }); - - text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.after', text, options, globals); - return text; -}); - -/** - * Handle github codeblocks prior to running HashHTML so that - * HTML contained within the codeblock gets escaped properly - * Example: - * ```ruby - * def hello_world(x) - * puts "Hello, #{x}" - * end - * ``` - */ -showdown.subParser('githubCodeBlocks', function (text, options, globals) { - 'use strict'; - - // early exit if option is not enabled - if (!options.ghCodeBlocks) { - return text; - } - - text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals); - - text += '¨0'; - - text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) { - var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n'; - - // First parse the github code block - codeblock = showdown.subParser('encodeCode')(codeblock, options, globals); - codeblock = showdown.subParser('detab')(codeblock, options, globals); - codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines - codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace - - codeblock = '
    ' + codeblock + end + '
    '; - - codeblock = showdown.subParser('hashBlock')(codeblock, options, globals); - - // Since GHCodeblocks can be false positives, we need to - // store the primitive text and the parsed text in a global var, - // and then return a token - return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n'; - }); - - // attacklab: strip sentinel - text = text.replace(/¨0/, ''); - - return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals); -}); - -showdown.subParser('hashBlock', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('hashBlock.before', text, options, globals); - text = text.replace(/(^\n+|\n+$)/g, ''); - text = '\n\n¨K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n'; - text = globals.converter._dispatch('hashBlock.after', text, options, globals); - return text; -}); - -/** - * Hash and escape elements that should not be parsed as markdown - */ -showdown.subParser('hashCodeTags', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('hashCodeTags.before', text, options, globals); - - var repFunc = function (wholeMatch, match, left, right) { - var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right; - return '¨C' + (globals.gHtmlSpans.push(codeblock) - 1) + 'C'; - }; - - // Hash naked - text = showdown.helper.replaceRecursiveRegExp(text, repFunc, ']*>', '', 'gim'); - - text = globals.converter._dispatch('hashCodeTags.after', text, options, globals); - return text; -}); - -showdown.subParser('hashElement', function (text, options, globals) { - 'use strict'; - - return function (wholeMatch, m1) { - var blockText = m1; - - // Undo double lines - blockText = blockText.replace(/\n\n/g, '\n'); - blockText = blockText.replace(/^\n/, ''); - - // strip trailing blank lines - blockText = blockText.replace(/\n+$/g, ''); - - // Replace the element text with a marker ("¨KxK" where x is its key) - blockText = '\n\n¨K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n'; - - return blockText; - }; -}); - -showdown.subParser('hashHTMLBlocks', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('hashHTMLBlocks.before', text, options, globals); - - var blockTags = [ - 'pre', - 'div', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'blockquote', - 'table', - 'dl', - 'ol', - 'ul', - 'script', - 'noscript', - 'form', - 'fieldset', - 'iframe', - 'math', - 'style', - 'section', - 'header', - 'footer', - 'nav', - 'article', - 'aside', - 'address', - 'audio', - 'canvas', - 'figure', - 'hgroup', - 'output', - 'video', - 'p' - ], - repFunc = function (wholeMatch, match, left, right) { - var txt = wholeMatch; - // check if this html element is marked as markdown - // if so, it's contents should be parsed as markdown - if (left.search(/\bmarkdown\b/) !== -1) { - txt = left + globals.converter.makeHtml(match) + right; - } - return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n'; - }; - - for (var i = 0; i < blockTags.length; ++i) { - - var opTagPos, - rgx1 = new RegExp('^ {0,3}<' + blockTags[i] + '\\b[^>]*>', 'im'), - patLeft = '<' + blockTags[i] + '\\b[^>]*>', - patRight = ''; - // 1. Look for the first position of the first opening HTML tag in the text - while ((opTagPos = showdown.helper.regexIndexOf(text, rgx1)) !== -1) { - //2. Split the text in that position - var subTexts = showdown.helper.splitAtIndex(text, opTagPos), - //3. Match recursively - newSubText1 = showdown.helper.replaceRecursiveRegExp(subTexts[1], repFunc, patLeft, patRight, 'im'); - - // prevent an infinite loop - if (newSubText1 === subTexts[1]) { - break; - } - text = subTexts[0].concat(newSubText1); - } - } - // HR SPECIAL CASE - text = text.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, - showdown.subParser('hashElement')(text, options, globals)); - - // Special case for standalone HTML comments - text = showdown.helper.replaceRecursiveRegExp(text, function (txt) { - return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n'; - }, '^ {0,3}', 'gm'); - - // PHP and ASP-style processor instructions ( and <%...%>) - text = text.replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, - showdown.subParser('hashElement')(text, options, globals)); - - text = globals.converter._dispatch('hashHTMLBlocks.after', text, options, globals); - return text; -}); - -/** - * Hash span elements that should not be parsed as markdown - */ -showdown.subParser('hashHTMLSpans', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('hashHTMLSpans.before', text, options, globals); - - function hashHTMLSpan (html) { - return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C'; - } - - // Hash Self Closing tags - text = text.replace(/<[^>]+?\/>/gi, function (wm) { - return hashHTMLSpan(wm); - }); - - // Hash tags without properties - text = text.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g, function (wm) { - return hashHTMLSpan(wm); - }); - - // Hash tags with properties - text = text.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g, function (wm) { - return hashHTMLSpan(wm); - }); - - // Hash self closing tags without /> - text = text.replace(/<[^>]+?>/gi, function (wm) { - return hashHTMLSpan(wm); - }); - - /*showdown.helper.matchRecursiveRegExp(text, ']*>', '', 'gi');*/ - - text = globals.converter._dispatch('hashHTMLSpans.after', text, options, globals); - return text; -}); - -/** - * Unhash HTML spans - */ -showdown.subParser('unhashHTMLSpans', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('unhashHTMLSpans.before', text, options, globals); - - for (var i = 0; i < globals.gHtmlSpans.length; ++i) { - var repText = globals.gHtmlSpans[i], - // limiter to prevent infinite loop (assume 10 as limit for recurse) - limit = 0; - - while (/¨C(\d+)C/.test(repText)) { - var num = RegExp.$1; - repText = repText.replace('¨C' + num + 'C', globals.gHtmlSpans[num]); - if (limit === 10) { - break; - } - ++limit; - } - text = text.replace('¨C' + i + 'C', repText); - } - - text = globals.converter._dispatch('unhashHTMLSpans.after', text, options, globals); - return text; -}); - -/** - * Hash and escape
     elements that should not be parsed as markdown
    - */
    -showdown.subParser('hashPreCodeTags', function (text, options, globals) {
    -  'use strict';
    -  text = globals.converter._dispatch('hashPreCodeTags.before', text, options, globals);
    -
    -  var repFunc = function (wholeMatch, match, left, right) {
    -    // encode html entities
    -    var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;
    -    return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
    -  };
    -
    -  // Hash 
    
    -  text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^ {0,3}]*>\\s*]*>', '^ {0,3}\\s*
    ', 'gim'); - - text = globals.converter._dispatch('hashPreCodeTags.after', text, options, globals); - return text; -}); - -showdown.subParser('headers', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('headers.before', text, options, globals); - - var headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart), - ghHeaderId = options.ghCompatibleHeaderId, - - // Set text-style headers: - // Header 1 - // ======== - // - // Header 2 - // -------- - // - setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm, - setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm; - - text = text.replace(setextRegexH1, function (wholeMatch, m1) { - - var spanGamut = showdown.subParser('spanGamut')(m1, options, globals), - hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"', - hLevel = headerLevelStart, - hashBlock = '' + spanGamut + ''; - return showdown.subParser('hashBlock')(hashBlock, options, globals); - }); - - text = text.replace(setextRegexH2, function (matchFound, m1) { - var spanGamut = showdown.subParser('spanGamut')(m1, options, globals), - hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"', - hLevel = headerLevelStart + 1, - hashBlock = '' + spanGamut + ''; - return showdown.subParser('hashBlock')(hashBlock, options, globals); - }); - - // atx-style headers: - // # Header 1 - // ## Header 2 - // ## Header 2 with closing hashes ## - // ... - // ###### Header 6 - // - var atxStyle = (options.requireSpaceBeforeHeadingText) ? /^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm : /^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm; - - text = text.replace(atxStyle, function (wholeMatch, m1, m2) { - var hText = m2; - if (options.customizedHeaderId) { - hText = m2.replace(/\s?\{([^{]+?)}\s*$/, ''); - } - - var span = showdown.subParser('spanGamut')(hText, options, globals), - hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"', - hLevel = headerLevelStart - 1 + m1.length, - header = '' + span + ''; - - return showdown.subParser('hashBlock')(header, options, globals); - }); - - function headerId (m) { - var title; - - // It is separate from other options to allow combining prefix and customized - if (options.customizedHeaderId) { - var match = m.match(/\{([^{]+?)}\s*$/); - if (match && match[1]) { - m = match[1]; - } - } - - // Prefix id to prevent causing inadvertent pre-existing style matches. - if (showdown.helper.isString(options.prefixHeaderId)) { - title = options.prefixHeaderId + m; - } else if (options.prefixHeaderId === true) { - title = 'section ' + m; - } else { - title = m; - } - - if (ghHeaderId) { - title = title - .replace(/ /g, '-') - // replace previously escaped chars (&, ¨ and $) - .replace(/&/g, '') - .replace(/¨T/g, '') - .replace(/¨D/g, '') - // replace rest of the chars (&~$ are repeated as they might have been escaped) - // borrowed from github's redcarpet (some they should produce similar results) - .replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g, '') - .toLowerCase(); - } else { - title = title - .replace(/[^\w]/g, '') - .toLowerCase(); - } - - if (globals.hashLinkCounts[title]) { - title = title + '-' + (globals.hashLinkCounts[title]++); - } else { - globals.hashLinkCounts[title] = 1; - } - return title; - } - - text = globals.converter._dispatch('headers.after', text, options, globals); - return text; -}); - -/** - * Turn Markdown link shortcuts into XHTML tags. - */ -showdown.subParser('horizontalRule', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('horizontalRule.before', text, options, globals); - - var key = showdown.subParser('hashBlock')('
    ', options, globals); - text = text.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm, key); - text = text.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm, key); - text = text.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm, key); - - text = globals.converter._dispatch('horizontalRule.after', text, options, globals); - return text; -}); - -/** - * Turn Markdown image shortcuts into tags. - */ -showdown.subParser('images', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('images.before', text, options, globals); - - var inlineRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g, - crazyRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g, - referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g, - refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g; - - function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) { - - var gUrls = globals.gUrls, - gTitles = globals.gTitles, - gDims = globals.gDimensions; - - linkId = linkId.toLowerCase(); - - if (!title) { - title = ''; - } - // Special case for explicit empty url - if (wholeMatch.search(/\(? ?(['"].*['"])?\)$/m) > -1) { - url = ''; - - } else if (url === '' || url === null) { - if (linkId === '' || linkId === null) { - // lower-case and turn embedded newlines into spaces - linkId = altText.toLowerCase().replace(/ ?\n/g, ' '); - } - url = '#' + linkId; - - if (!showdown.helper.isUndefined(gUrls[linkId])) { - url = gUrls[linkId]; - if (!showdown.helper.isUndefined(gTitles[linkId])) { - title = gTitles[linkId]; - } - if (!showdown.helper.isUndefined(gDims[linkId])) { - width = gDims[linkId].width; - height = gDims[linkId].height; - } - } else { - return wholeMatch; - } - } - - altText = altText - .replace(/"/g, '"') - //altText = showdown.helper.escapeCharacters(altText, '*_', false); - .replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback); - //url = showdown.helper.escapeCharacters(url, '*_', false); - url = url.replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback); - var result = '' + altText + 'x "optional title") - // cases with crazy urls like ./image/cat1).png - text = text.replace(crazyRegExp, writeImageTag); - - // normal cases - text = text.replace(inlineRegExp, writeImageTag); - - // handle reference-style shortcuts: |[img text] - text = text.replace(refShortcutRegExp, writeImageTag); - - text = globals.converter._dispatch('images.after', text, options, globals); - return text; -}); - -showdown.subParser('italicsAndBold', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('italicsAndBold.before', text, options, globals); - - // it's faster to have 3 separate regexes for each case than have just one - // because of backtracing, in some cases, it could lead to an exponential effect - // called "catastrophic backtrace". Ominous! - - function parseInside (txt, left, right) { - if (options.simplifiedAutoLink) { - txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals); - } - return left + txt + right; - } - - // Parse underscores - if (options.literalMidWordUnderscores) { - text = text.replace(/\b___(\S[\s\S]*)___\b/g, function (wm, txt) { - return parseInside (txt, '', ''); - }); - text = text.replace(/\b__(\S[\s\S]*)__\b/g, function (wm, txt) { - return parseInside (txt, '', ''); - }); - text = text.replace(/\b_(\S[\s\S]*?)_\b/g, function (wm, txt) { - return parseInside (txt, '', ''); - }); - } else { - text = text.replace(/___(\S[\s\S]*?)___/g, function (wm, m) { - return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; - }); - text = text.replace(/__(\S[\s\S]*?)__/g, function (wm, m) { - return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; - }); - text = text.replace(/_([^\s_][\s\S]*?)_/g, function (wm, m) { - // !/^_[^_]/.test(m) - test if it doesn't start with __ (since it seems redundant, we removed it) - return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; - }); - } - - // Now parse asterisks - if (options.literalMidWordAsterisks) { - text = text.trim().replace(/(?:^| +)\*{3}(\S[\s\S]*?)\*{3}(?: +|$)/g, function (wm, txt) { - return parseInside (txt, ' ', ' '); - }); - text = text.trim().replace(/(?:^| +)\*{2}(\S[\s\S]*?)\*{2}(?: +|$)/g, function (wm, txt) { - return parseInside (txt, ' ', ' '); - }); - text = text.trim().replace(/(?:^| +)\*{1}(\S[\s\S]*?)\*{1}(?: +|$)/g, function (wm, txt) { - return parseInside (txt, ' ', '' + (wm.slice(-1) === ' ' ? ' ' : '')); - }); - } else { - text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) { - return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; - }); - text = text.replace(/\*\*(\S[\s\S]*?)\*\*/g, function (wm, m) { - return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; - }); - text = text.replace(/\*([^\s*][\s\S]*?)\*/g, function (wm, m) { - // !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it) - return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; - }); - } - - - text = globals.converter._dispatch('italicsAndBold.after', text, options, globals); - return text; -}); - -/** - * Form HTML ordered (numbered) and unordered (bulleted) lists. - */ -showdown.subParser('lists', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('lists.before', text, options, globals); - - /** - * Process the contents of a single ordered or unordered list, splitting it - * into individual list items. - * @param {string} listStr - * @param {boolean} trimTrailing - * @returns {string} - */ - function processListItems (listStr, trimTrailing) { - // The $g_list_level global keeps track of when we're inside a list. - // Each time we enter a list, we increment it; when we leave a list, - // we decrement. If it's zero, we're not in a list anymore. - // - // We do this because when we're not inside a list, we want to treat - // something like this: - // - // I recommend upgrading to version - // 8. Oops, now this line is treated - // as a sub-list. - // - // As a single paragraph, despite the fact that the second line starts - // with a digit-period-space sequence. - // - // Whereas when we're inside a list (or sub-list), that line will be - // treated as the start of a sub-list. What a kludge, huh? This is - // an aspect of Markdown's syntax that's hard to parse perfectly - // without resorting to mind-reading. Perhaps the solution is to - // change the syntax rules such that sub-lists must start with a - // starting cardinal number; e.g. "1." or "a.". - globals.gListLevel++; - - // trim trailing blank lines: - listStr = listStr.replace(/\n{2,}$/, '\n'); - - // attacklab: add sentinel to emulate \z - listStr += '¨0'; - - var rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm, - isParagraphed = (/\n[ \t]*\n(?!¨0)/.test(listStr)); - - // Since version 1.5, nesting sublists requires 4 spaces (or 1 tab) indentation, - // which is a syntax breaking change - // activating this option reverts to old behavior - if (options.disableForced4SpacesIndentedSublists) { - rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm; - } - - listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) { - checked = (checked && checked.trim() !== ''); - - var item = showdown.subParser('outdent')(m4, options, globals), - bulletStyle = ''; - - // Support for github tasklists - if (taskbtn && options.tasklists) { - bulletStyle = ' class="task-list-item" style="list-style-type: none;"'; - item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () { - var otp = '
  • a
  • - // instead of: - //
    • - - a
    - // So, to prevent it, we will put a marker (¨A)in the beginning of the line - // Kind of hackish/monkey patching, but seems more effective than overcomplicating the list parser - item = item.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g, function (wm2) { - return '¨A' + wm2; - }); - - // m1 - Leading line or - // Has a double return (multi paragraph) or - // Has sublist - if (m1 || (item.search(/\n{2,}/) > -1)) { - item = showdown.subParser('githubCodeBlocks')(item, options, globals); - item = showdown.subParser('blockGamut')(item, options, globals); - } else { - // Recursion for sub-lists: - item = showdown.subParser('lists')(item, options, globals); - item = item.replace(/\n$/, ''); // chomp(item) - item = showdown.subParser('hashHTMLBlocks')(item, options, globals); - // Colapse double linebreaks - item = item.replace(/\n\n+/g, '\n\n'); - // replace double linebreaks with a placeholder - item = item.replace(/\n\n/g, '¨B'); - if (isParagraphed) { - item = showdown.subParser('paragraphs')(item, options, globals); - } else { - item = showdown.subParser('spanGamut')(item, options, globals); - } - item = item.replace(/¨B/g, '\n\n'); - } - - // now we need to remove the marker (¨A) - item = item.replace('¨A', ''); - // we can finally wrap the line in list item tags - item = '' + item + '\n'; - - return item; - }); - - // attacklab: strip sentinel - listStr = listStr.replace(/¨0/g, ''); - - globals.gListLevel--; - - if (trimTrailing) { - listStr = listStr.replace(/\s+$/, ''); - } - - return listStr; - } - - /** - * Check and parse consecutive lists (better fix for issue #142) - * @param {string} list - * @param {string} listType - * @param {boolean} trimTrailing - * @returns {string} - */ - function parseConsecutiveLists (list, listType, trimTrailing) { - // check if we caught 2 or more consecutive lists by mistake - // we use the counterRgx, meaning if listType is UL we look for OL and vice versa - var olRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?\d+\.[ \t]/gm : /^ {0,3}\d+\.[ \t]/gm, - ulRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?[*+-][ \t]/gm : /^ {0,3}[*+-][ \t]/gm, - counterRxg = (listType === 'ul') ? olRgx : ulRgx, - result = ''; - - if (list.search(counterRxg) !== -1) { - (function parseCL (txt) { - var pos = txt.search(counterRxg); - if (pos !== -1) { - // slice - result += '\n<' + listType + '>\n' + processListItems(txt.slice(0, pos), !!trimTrailing) + '\n'; - - // invert counterType and listType - listType = (listType === 'ul') ? 'ol' : 'ul'; - counterRxg = (listType === 'ul') ? olRgx : ulRgx; - - //recurse - parseCL(txt.slice(pos)); - } else { - result += '\n<' + listType + '>\n' + processListItems(txt, !!trimTrailing) + '\n'; - } - })(list); - } else { - result = '\n<' + listType + '>\n' + processListItems(list, !!trimTrailing) + '\n'; - } - - return result; - } - - // add sentinel to hack around khtml/safari bug: - // http://bugs.webkit.org/show_bug.cgi?id=11231 - text += '¨0'; - - if (globals.gListLevel) { - text = text.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm, - function (wholeMatch, list, m2) { - var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; - return parseConsecutiveLists(list, listType, true); - } - ); - } else { - text = text.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm, - function (wholeMatch, m1, list, m3) { - var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; - return parseConsecutiveLists(list, listType, false); - } - ); - } - - // strip sentinel - text = text.replace(/¨0/, ''); - text = globals.converter._dispatch('lists.after', text, options, globals); - return text; -}); - -/** - * Remove one level of line-leading tabs or spaces - */ -showdown.subParser('outdent', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('outdent.before', text, options, globals); - - // attacklab: hack around Konqueror 3.5.4 bug: - // "----------bug".replace(/^-/g,"") == "bug" - text = text.replace(/^(\t|[ ]{1,4})/gm, '¨0'); // attacklab: g_tab_width - - // attacklab: clean up hack - text = text.replace(/¨0/g, ''); - - text = globals.converter._dispatch('outdent.after', text, options, globals); - return text; -}); - -/** - * - */ -showdown.subParser('paragraphs', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('paragraphs.before', text, options, globals); - // Strip leading and trailing lines: - text = text.replace(/^\n+/g, ''); - text = text.replace(/\n+$/g, ''); - - var grafs = text.split(/\n{2,}/g), - grafsOut = [], - end = grafs.length; // Wrap

    tags - - for (var i = 0; i < end; i++) { - var str = grafs[i]; - // if this is an HTML marker, copy it - if (str.search(/¨(K|G)(\d+)\1/g) >= 0) { - grafsOut.push(str); - - // test for presence of characters to prevent empty lines being parsed - // as paragraphs (resulting in undesired extra empty paragraphs) - } else if (str.search(/\S/) >= 0) { - str = showdown.subParser('spanGamut')(str, options, globals); - str = str.replace(/^([ \t]*)/g, '

    '); - str += '

    '; - grafsOut.push(str); - } - } - - /** Unhashify HTML blocks */ - end = grafsOut.length; - for (i = 0; i < end; i++) { - var blockText = '', - grafsOutIt = grafsOut[i], - codeFlag = false; - // if this is a marker for an html block... - // use RegExp.test instead of string.search because of QML bug - while (/¨(K|G)(\d+)\1/.test(grafsOutIt)) { - var delim = RegExp.$1, - num = RegExp.$2; - - if (delim === 'K') { - blockText = globals.gHtmlBlocks[num]; - } else { - // we need to check if ghBlock is a false positive - if (codeFlag) { - // use encoded version of all text - blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text, options, globals); - } else { - blockText = globals.ghCodeBlocks[num].codeblock; - } - } - blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs - - grafsOutIt = grafsOutIt.replace(/(\n\n)?¨(K|G)\d+\2(\n\n)?/, blockText); - // Check if grafsOutIt is a pre->code - if (/^]*>\s*]*>/.test(grafsOutIt)) { - codeFlag = true; - } - } - grafsOut[i] = grafsOutIt; - } - text = grafsOut.join('\n'); - // Strip leading and trailing lines: - text = text.replace(/^\n+/g, ''); - text = text.replace(/\n+$/g, ''); - return globals.converter._dispatch('paragraphs.after', text, options, globals); -}); - -/** - * Run extension - */ -showdown.subParser('runExtension', function (ext, text, options, globals) { - 'use strict'; - - if (ext.filter) { - text = ext.filter(text, globals.converter, options); - - } else if (ext.regex) { - // TODO remove this when old extension loading mechanism is deprecated - var re = ext.regex; - if (!(re instanceof RegExp)) { - re = new RegExp(re, 'g'); - } - text = text.replace(re, ext.replace); - } - - return text; -}); - -/** - * These are all the transformations that occur *within* block-level - * tags like paragraphs, headers, and list items. - */ -showdown.subParser('spanGamut', function (text, options, globals) { - 'use strict'; - - text = globals.converter._dispatch('spanGamut.before', text, options, globals); - text = showdown.subParser('codeSpans')(text, options, globals); - text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals); - text = showdown.subParser('encodeBackslashEscapes')(text, options, globals); - - // Process anchor and image tags. Images must come first, - // because ![foo][f] looks like an anchor. - text = showdown.subParser('images')(text, options, globals); - text = showdown.subParser('anchors')(text, options, globals); - - // Make links out of things like `` - // Must come after anchors, because you can use < and > - // delimiters in inline links like [this](). - text = showdown.subParser('autoLinks')(text, options, globals); - text = showdown.subParser('italicsAndBold')(text, options, globals); - text = showdown.subParser('strikethrough')(text, options, globals); - text = showdown.subParser('simplifiedAutoLinks')(text, options, globals); - - // we need to hash HTML tags inside spans - text = showdown.subParser('hashHTMLSpans')(text, options, globals); - - // now we encode amps and angles - text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals); - - // Do hard breaks - if (options.simpleLineBreaks) { - // GFM style hard breaks - text = text.replace(/\n/g, '
    \n'); - } else { - // Vanilla hard breaks - text = text.replace(/ +\n/g, '
    \n'); - } - - text = globals.converter._dispatch('spanGamut.after', text, options, globals); - return text; -}); - -showdown.subParser('strikethrough', function (text, options, globals) { - 'use strict'; - - function parseInside (txt) { - if (options.simplifiedAutoLink) { - txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals); - } - return '' + txt + ''; - } - - if (options.strikethrough) { - text = globals.converter._dispatch('strikethrough.before', text, options, globals); - text = text.replace(/(?:~){2}([\s\S]+?)(?:~){2}/g, function (wm, txt) { return parseInside(txt); }); - text = globals.converter._dispatch('strikethrough.after', text, options, globals); - } - - return text; -}); - -/** - * Strips link definitions from text, stores the URLs and titles in - * hash references. - * Link defs are in the form: ^[id]: url "optional title" - */ -showdown.subParser('stripLinkDefinitions', function (text, options, globals) { - 'use strict'; - - var regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm; - - // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug - text += '¨0'; - - text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) { - linkId = linkId.toLowerCase(); - globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url, options, globals); // Link IDs are case-insensitive - - if (blankLines) { - // Oops, found blank lines, so it's not a title. - // Put back the parenthetical statement we stole. - return blankLines + title; - - } else { - if (title) { - globals.gTitles[linkId] = title.replace(/"|'/g, '"'); - } - if (options.parseImgDimensions && width && height) { - globals.gDimensions[linkId] = { - width: width, - height: height - }; - } - } - // Completely remove the definition from the text - return ''; - }); - - // attacklab: strip sentinel - text = text.replace(/¨0/, ''); - - return text; -}); - -showdown.subParser('tables', function (text, options, globals) { - 'use strict'; - - if (!options.tables) { - return text; - } - - var tableRgx = /^ {0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|¨0)/gm; - - function parseStyles (sLine) { - if (/^:[ \t]*--*$/.test(sLine)) { - return ' style="text-align:left;"'; - } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) { - return ' style="text-align:right;"'; - } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) { - return ' style="text-align:center;"'; - } else { - return ''; - } - } - - function parseHeaders (header, style) { - var id = ''; - header = header.trim(); - if (options.tableHeaderId) { - id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"'; - } - header = showdown.subParser('spanGamut')(header, options, globals); - - return '' + header + '\n'; - } - - function parseCells (cell, style) { - var subText = showdown.subParser('spanGamut')(cell, options, globals); - return '' + subText + '\n'; - } - - function buildTable (headers, cells) { - var tb = '\n\n\n', - tblLgn = headers.length; - - for (var i = 0; i < tblLgn; ++i) { - tb += headers[i]; - } - tb += '\n\n\n'; - - for (i = 0; i < cells.length; ++i) { - tb += '\n'; - for (var ii = 0; ii < tblLgn; ++ii) { - tb += cells[i][ii]; - } - tb += '\n'; - } - tb += '\n
    \n'; - return tb; - } - - text = globals.converter._dispatch('tables.before', text, options, globals); - - // find escaped pipe characters - text = text.replace(/\\(\|)/g, showdown.helper.escapeCharactersCallback); - - // parse tables - text = text.replace(tableRgx, function (rawTable) { - - var i, tableLines = rawTable.split('\n'); - - // strip wrong first and last column if wrapped tables are used - for (i = 0; i < tableLines.length; ++i) { - if (/^ {0,3}\|/.test(tableLines[i])) { - tableLines[i] = tableLines[i].replace(/^ {0,3}\|/, ''); - } - if (/\|[ \t]*$/.test(tableLines[i])) { - tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, ''); - } - } - - var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}), - rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}), - rawCells = [], - headers = [], - styles = [], - cells = []; - - tableLines.shift(); - tableLines.shift(); - - for (i = 0; i < tableLines.length; ++i) { - if (tableLines[i].trim() === '') { - continue; - } - rawCells.push( - tableLines[i] - .split('|') - .map(function (s) { - return s.trim(); - }) - ); - } - - if (rawHeaders.length < rawStyles.length) { - return rawTable; - } - - for (i = 0; i < rawStyles.length; ++i) { - styles.push(parseStyles(rawStyles[i])); - } - - for (i = 0; i < rawHeaders.length; ++i) { - if (showdown.helper.isUndefined(styles[i])) { - styles[i] = ''; - } - headers.push(parseHeaders(rawHeaders[i], styles[i])); - } - - for (i = 0; i < rawCells.length; ++i) { - var row = []; - for (var ii = 0; ii < headers.length; ++ii) { - if (showdown.helper.isUndefined(rawCells[i][ii])) { - - } - row.push(parseCells(rawCells[i][ii], styles[ii])); - } - cells.push(row); - } - - return buildTable(headers, cells); - }); - - text = globals.converter._dispatch('tables.after', text, options, globals); - - return text; -}); - -/** - * Swap back in all the special characters we've hidden. - */ -showdown.subParser('unescapeSpecialChars', function (text, options, globals) { - 'use strict'; - text = globals.converter._dispatch('unescapeSpecialChars.before', text, options, globals); - - text = text.replace(/¨E(\d+)E/g, function (wholeMatch, m1) { - var charCodeToReplace = parseInt(m1); - return String.fromCharCode(charCodeToReplace); - }); - - text = globals.converter._dispatch('unescapeSpecialChars.after', text, options, globals); - return text; -}); - -var root = this; - -// CommonJS/nodeJS Loader -if (typeof module !== 'undefined' && module.exports) { - module.exports = showdown; - -// AMD Loader -} else if (true) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { - 'use strict'; - return showdown; - }).call(exports, __webpack_require__, exports, module), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - -// Regular Browser loader -} else { - root.showdown = showdown; -} -}).call(this); - -//# sourceMappingURL=showdown.js.map - - -/***/ }), -/* 22 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Data__ = __webpack_require__(23); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Data", function() { return __WEBPACK_IMPORTED_MODULE_0__Data__["a"]; }); - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBV0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFFBQVEsQ0FBQyJ9 - -/***/ }), -/* 23 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__DataFilters__ = __webpack_require__(66); - -; -class Data { - constructor(data) { - this.data = []; - this.meta = []; - this.import(data); - } - static toDataSet(data, name) { - data = data || [{}]; - const names = Object.keys(data[0]); - const rows = data.map((r) => names.map((n) => r[n])); - return { rows: rows, colNames: names, name: name || undefined }; - } - getName() { - return this.name; - } - import(data) { - this.name = data.name; - this.setData(data.rows, data.colNames); - } - export() { - return { - rows: this.getData(), - colNames: this.colNames() - }; - } - getData() { - return this.data; - } - getColumn(col) { - const cn = this.colNumber(col); - return this.data.map((row) => row[cn]); - } - colAdd(col) { - let m = this.getMeta(col); - if (m === undefined) { - m = this.meta[col] = {}; - m.name = col; - m.column = this.meta.length; - this.meta.push(m); - m.cast = false; - m.accessed = false; - } - return m.column; - } - colInitialize(col, initializer) { - const cn = this.colNumber(col); - if (!cn && typeof col === 'string') { - this.colAdd(col); - } - const fn = typeof initializer === 'function'; - if (cn !== undefined) { - this.data.map((r, i) => r[cn] = fn ? initializer(r[cn], i, r) : initializer); - } - } - colNumber(col) { - const m = this.getMeta(col); - if (!m) { - return undefined; - } - else { - m.accessed = true; - return m.column; - } - } - colName(col) { - var m = this.getMeta(col); - if (!m) { - return undefined; - } - m.accessed = true; - return m.name; - } - colNames() { - return this.meta.map((m) => m.name); - } - colType(col) { - const meta = this.getMeta(col); - return meta ? meta.types[0].type : Data.type.name; - } - findDomain(col, domain) { - if (col === undefined) { - domain[0] = 0; - domain[1] = this.data.length - 1; - } - else { - const c = this.colNumber(col); - const type = this.colType(col); - if (this.data === undefined) { - console.log('no data'); - } - switch (type) { - case Data.type.nominal: - this.data.forEach((r) => { - const nomDom = domain; - if (nomDom.indexOf('' + r[c]) < 0) { - nomDom.push('' + r[c]); - } - }); - break; - default: - this.data.forEach((r) => { - let v = r[c]; - if (v !== undefined && v !== null) { - domain[0] = (v < domain[0]) ? v : domain[0]; - domain[1] = (v > domain[1]) ? v : domain[1]; - } - }); - } - } - } - castData() { - this.meta.forEach((c) => { - const col = c.column; - if (!c.cast) { - this.data.forEach((row) => row[col] = this.castVal(c.types[0].type, row[col])); - } - c.cast = true; - }); - } - filter(condition) { - return Object(__WEBPACK_IMPORTED_MODULE_0__DataFilters__["a" /* filter */])(this, condition); - } - sort(sortFn, col) { - let fn = sortFn; - if (!col) { - this.data.sort(fn); - } - else { - col = this.colNumber(col); - if (sortFn === 'descending') { - fn = (a, b) => (b > a) ? 1 : ((b < a) ? -1 : 0); - } - if (sortFn === 'ascending') { - fn = (a, b) => (b < a) ? 1 : ((b > a) ? -1 : 0); - } - this.data.sort((r1, r2) => fn(r1[col], r2[col])); - } - return this; - } - map(col, mapFn) { - const noop = (val) => val; - const cumulate = () => { - let sum = 0; - return (val, i) => { sum += +val; return sum; }; - }; - function getFn() { - let fn; - switch (mapFn) { - case 'cumulate': - fn = cumulate(); - break; - case 'noop': - fn = noop; - break; - default: fn = mapFn; - } - return fn; - } - let result = new Data({ colNames: this.colNames(), rows: this.data.slice(), name: this.getName() }); - const names = col['length'] ? col : [col]; - names.map((cn) => { - const c = this.colNumber(cn); - let fn = getFn(); - result.data = result.data.map((row, i, rows) => { - row[c] = fn(row[c], c, i, rows); - return row; - }); - }); - return result; - } - getMeta(col) { - if (!this.meta) { - this.meta = []; - } - if (!this.meta[col]) { - return undefined; - } - this.meta[col].accessed = true; - return this.meta[col]; - } - setData(data, names, autoType = true) { - this.meta = []; - this.data = data; - if (!names) { - console.log(); - } - names.forEach((col) => this.colAdd(col)); - names.forEach((col) => this.findTypes(col)); - this.castData(); - } - findTypes(col) { - const m = this.getMeta(col); - const types = []; - Object.keys(Data.type).forEach((t) => { - const ts = { type: Data.type[t], count: 0 }; - types.push(ts); - types[Data.type[t]] = ts; - }); - for (let v of this.allRows(col)) { - const t = this.findType(v); - if (t !== null) { - types[t].count++; - } - } - types.sort(function (a, b) { - if (a.type === 'currency' && a.count > 0) { - return -1; - } - if (b.type === 'currency' && b.count > 0) { - return 1; - } - return b.count - a.count; - }); - m.types = types; - return types[0].type; - } - findType(val) { - if (val && val !== '') { - if (val instanceof Date) { - return Data.type.date; - } - if (typeof val === 'number') { - return Data.type.number; - } - const strVal = '' + val; - if ('' + parseFloat(strVal) === strVal) { - return Data.type.number; - } - if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { - return Data.type.currency; - } - if (strVal.endsWith('%') && !isNaN(parseFloat(strVal))) { - return Data.type.percent; - } - if (!isNaN(this.toDate(strVal).getTime())) { - return Data.type.date; - } - if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { - if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { - return Data.type.currency; - } - } - switch (strVal.toLowerCase()) { - case "null": break; - case "#ref!": break; - default: if (val.length > 0) { - return Data.type.nominal; - } - } - } - return null; - } - *allRows(column) { - const c = this.colNumber(column); - for (let r = 0; r < this.data.length; r++) { - yield this.data[r][c]; - } - } - toDate(val, limitYear = 1970) { - let d; - if (val instanceof Date) { - d = val; - } - else { - d = new Date(val); - } - let yr = d.getFullYear(); - if (yr < 100) { - yr += 1900; - d.setFullYear((yr < limitYear) ? yr + 100 : yr); - } - return d; - } - castVal(type, val) { - switch (type) { - case Data.type.date: - if (val instanceof Date) { - return val; - } - val = this.toDate(val); - if (isNaN(val.getTime())) { - val = null; - } - break; - case Data.type.percent: - if (typeof val === 'string') { - const num = parseFloat(val); - val = val.endsWith('%') ? num / 100 : num; - } - if (isNaN(val)) { - val = null; - } - break; - case Data.type.currency: - if (typeof val === 'string') { - val = val.replace(/[^eE\+\-\.\d]/g, ''); - } - case Data.type.number: - if (typeof val === 'string') { - val = parseFloat(val); - } - if (isNaN(val)) { - val = null; - } - break; - default: val = '' + val; - } - return val; - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Data; - -Data.type = { - number: 'number data', - name: 'name data', - date: 'date data', - currency: 'currency data', - percent: 'percent data', - nominal: 'nominal data' -}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGF0YS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9EYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLE9BQU8sRUFBYSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUF1Q0UsQ0FBQztBQWtCckQsTUFBTTtJQXFCRixZQUFZLElBQWE7UUEwU2pCLFNBQUksR0FBaUIsRUFBRSxDQUFDO1FBQ3hCLFNBQUksR0FBaUIsRUFBRSxDQUFDO1FBMVM1QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3RCLENBQUM7SUFWTSxNQUFNLENBQUMsU0FBUyxDQUFDLElBQW1CLEVBQUUsSUFBWTtRQUNyRCxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDcEIsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBSyxFQUFFLEVBQUUsQ0FDNUIsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuQyxPQUFPLEVBQUUsSUFBSSxFQUFDLElBQUksRUFBRSxRQUFRLEVBQUMsS0FBSyxFQUFFLElBQUksRUFBQyxJQUFJLElBQUUsU0FBUyxFQUFFLENBQUM7SUFDL0QsQ0FBQztJQVNNLE9BQU87UUFDVixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDckIsQ0FBQztJQU1NLE1BQU0sQ0FBQyxJQUFZO1FBQ3RCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFLTSxN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 - -/***/ }), -/* 24 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Axes__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_hsutil__ = __webpack_require__(2); - - -function addTickNumber(t, v) { - t.labels.push({ pos: v, text: '' + Math.round(v * 1000000) / 1000000 }); -} -function addTickDate(t, v, fmt) { - t.labels.push({ pos: v.getTime(), text: Object(__WEBPACK_IMPORTED_MODULE_1_hsutil__["date"])(fmt, v) }); -} -function linScaleTickMarks(dom, ticks, numTicks) { - function addTicks(unit, ticks) { - let exp = Math.pow(10, Math.floor(Math.log10(unit))); - unit = Math.floor(unit / exp) * exp; - const min = Math.floor(dom[0] / unit) * unit; - const max = Math.ceil(dom[1] / unit) * unit; - for (let v = min; v <= max; v += unit) { - addTickNumber(ticks, v); - } - return unit; - } - const majorUnit = addTicks((dom[1] - dom[0]) / numTicks, ticks.major); - addTicks(majorUnit / numTicks, ticks.minor); -} -function percentScaleTickMarks(dom, ticks, numTicks) { - const formatPercent = (m) => m.text = `${Math.round(m.pos) * 100}%`; - linScaleTickMarks(dom, ticks, numTicks); - ticks.major.labels.forEach(formatPercent); - ticks.minor.labels.forEach(formatPercent); -} -function logScaleTickMarks(dom, ticks) { - dom[0] = Math.max(dom[0], 1e-20); - dom[1] = Math.max(dom[1], 1e-20); - let dif = Math.pow(10, Math.floor(Math.log10(dom[1] - dom[0]))); - let min = Math.pow(10, Math.floor(Math.log10(dom[0]))); - let max = Math.pow(10, Math.ceil(Math.log10(dom[1]))); - if (dif > min) { - for (let v = min; v <= max; v *= 10) { - for (let i = 1; i <= 20; i++) { - if (i === 1 && v * i < max) { - addTickNumber(ticks.major, v * i); - } - else if (i % 10 === 0) { } - else if (i < 10) { - addTickNumber(ticks.minor, v * i); - } - else if (i % 2 === 0) { - addTickNumber(ticks.minor, v * i); - } - } - } - } - else { - min = Math.floor(dom[0] / dif) * dif; - max = Math.ceil(dom[1] / dif) * dif; - if ((max - min) / dif < 4) { - dif /= 2; - } - for (let v = min; v <= max; v += dif) { - addTickNumber(ticks.major, v); - } - addTickNumber(ticks.major, min); - addTickNumber(ticks.major, max); - } -} -const tickCategories = [ - [10, 0, 0, 0], [5, 0, 0, 0], [2, 0, 0, 0], [1, 0, 0, 0], [0, 6, 0, 0], [0, 3, 0, 0], [0, 1, 0, 0], [0, 0, 7, 0], [0, 0, 1, 0], [0, 0, 0, 4], [0, 0, 0, 1] -]; -function dateScaleTickMarks(dom, ticks, fmt = '%MM/%DD/%YY') { - function addDates(i, tickDefs) { - const createDate = (idx) => new Date(Math.floor(dateDom[idx].getFullYear() / modYr) * modYr + (idx ? incYr : 0), (incYr > 0) ? 0 : Math.floor(dateDom[idx].getMonth() / modMo) * modMo + (idx ? incMo : 0), (incMo > 0) ? 1 : (dateDom[idx].getDate() - ((incDay === 7) ? dateDom[idx].getDay() : 0)) + (idx ? incDay : 0), (incDay > 0) ? 0 : (dateDom[idx].getHours()) + (idx ? incHour : 0)); - const incYr = tickCategories[i][0]; - const incMo = tickCategories[i][1]; - const incDay = tickCategories[i][2]; - const incHour = tickCategories[i][3]; - const modYr = incYr || 1; - const modMo = incMo || 1; - const date0 = createDate(0); - const date1 = createDate(1); - fmt = incHour ? '%hh:%mm' : '%MM/%DD/%YY'; - for (let d = date0; d <= date1; d = new Date(d.getFullYear() + incYr, d.getMonth() + incMo, d.getDate() + incDay, d.getHours() + incHour)) { - addTickDate(tickDefs, d, fmt); - } - } - const dateDom = [ - (typeof dom[0] === 'number') ? new Date(dom[0]) : dom[0], - (typeof dom[1] === 'number') ? new Date(dom[1]) : dom[1] - ]; - if (isNaN(dateDom[0].getTime())) { - dateDom[0] = new Date('1/1/1980'); - } - if (isNaN(dateDom[1].getTime())) { - dateDom[0] = new Date(); - } - const d = dateDom[1].getTime() - dateDom[0].getTime(); - tickCategories.some((cat, i) => { - const dMin = __WEBPACK_IMPORTED_MODULE_1_hsutil__["ms"].fromDays((cat[0] * 365 + cat[1] * 30 + cat[2])) + __WEBPACK_IMPORTED_MODULE_1_hsutil__["ms"].fromHours(cat[3]); - if (d > 3 * dMin) { - addDates(i, ticks.major); - addDates(Math.min(i + 1, tickCategories.length - 1), ticks.minor); - return true; - } - else { - return false; - } - }); -} -function createTickLabels(type, domain, numTicks, fmt) { - const sort = (a, b) => a.pos - b.pos; - function sortTicks() { - ticks.minor.labels.sort(sort); - ticks.major.labels.sort(sort); - } - ; - const dom = [domain[0], domain[1]]; - const ticks = { - major: { marks: [], labels: [] }, - minor: { marks: [], labels: [] } - }; - switch (type) { - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: - logScaleTickMarks(dom, ticks); - sortTicks(); - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: - dateScaleTickMarks(dom, ticks, fmt); - sortTicks(); - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: - percentScaleTickMarks(dom, ticks, numTicks); - sortTicks(); - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: - default: - linScaleTickMarks(dom, ticks, numTicks); - sortTicks(); - } - return ticks; -} -class Scale { - constructor(cfg) { - this.cfg = cfg; - this.typeVal = __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear; - this.rangeVal = [0, 1]; - this.domVal = [0, 1]; - this.domMinAuto = 0; - this.domMaxAuto = 0; - this.scaleType(cfg.type); - this.domain(cfg.domain); - } - setLabelFormat(labelFmt) { - this.labelFmt = labelFmt; - } - range(r) { - if (r) { - this.rangeVal = r; - } - return this.rangeVal; - } - domain(dom) { - if (dom) { - if (this.scaleType() === __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date) { - if (typeof dom[0] === 'string' || typeof dom[1] === 'string') { - this.domVal[0] = (dom[0] === 'auto') ? 0 : Date.parse(dom[0]); - this.domVal[1] = (dom[1] === 'auto') ? 1 : Date.parse(dom[1]); - } - } - else { - this.domVal[0] = (dom[0] === 'auto') ? 0 : dom[0]; - this.domVal[1] = (dom[1] === 'auto') ? 1 : dom[1]; - } - switch (dom[0]) { - case 'tight': - this.domMinAuto = 2; - break; - case 'auto': - this.domMinAuto = 1; - break; - default: this.domMinAuto = 0; - } - switch (dom[1]) { - case 'tight': - this.domMaxAuto = 2; - break; - case 'auto': - this.domMaxAuto = 1; - break; - default: this.domMaxAuto = 0; - } - } - if (this.typeVal === __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log) { - if (this.domVal[1] <= 0) { - this.domVal[1] = 10; - } - if (this.domVal[0] <= 0) { - this.domVal[0] = this.domVal[1] / 10; - } - } - return this.domVal; - } - scaleType(s) { - if (s) { - this.typeVal = s; - } - return this.typeVal; - } - setAutoDomain(dom) { - const ticks = createTickLabels(this.scaleType(), dom, 4, this.labelFmt); - switch (this.domMinAuto) { - case 1: - this.domVal[0] = ticks.major.labels[0] ? ticks.major.labels[0].pos : dom[0]; - break; - case 2: - this.domVal[0] = dom[0]; - break; - } - switch (this.domMaxAuto) { - case 1: - this.domVal[1] = ticks.major.labels[ticks.major.labels.length - 1].pos; - break; - case 2: - this.domVal[1] = dom[1]; - break; - } - } - ticks(numTicks = 4) { - function marksFromLabels(ticks, type) { - switch (type) { - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: - const numLabels = ticks.major.labels.length; - ticks.major.marks = Array(numLabels + 1).fill(1).map((e, i) => i - 0.5); - ticks.minor.marks = ticks.minor.labels ? ticks.minor.labels.map((l) => l.pos) : []; - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: - default: - ticks.major.marks = ticks.major.labels ? ticks.major.labels.map((l) => l.pos) : []; - ticks.minor.marks = ticks.minor.labels ? ticks.minor.labels.map((l) => l.pos) : []; - } - } - const dom = [this.domain()[0], this.domain()[1]]; - const inRange = (t) => t.pos >= dom[0] && t.pos <= dom[1]; - const ticks = createTickLabels(this.scaleType(), this.domain(), numTicks, this.labelFmt); - ticks.minor.labels = ticks.minor.labels.filter(inRange); - ticks.major.labels = ticks.major.labels.filter(inRange); - if (ticks.major.labels.length === 0) { - ticks.major.labels = ticks.minor.labels; - ticks.minor.labels = []; - } - marksFromLabels(ticks, this.scaleType()); - return ticks; - } - convert(domVal) { - const dom = this.domain(); - const range = this.range(); - const domMin = dom[0]; - const domMax = dom[1]; - let result; - switch (this.scaleType()) { - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.log: - result = Math.log(domVal / domMin) / Math.log(domMax / domMin) * (range[1] - range[0]) + range[0]; - break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.nominal: break; - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.date: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.percent: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.index: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.ordinal: - case __WEBPACK_IMPORTED_MODULE_0__Axes__["a" /* Axes */].type.linear: - default: - result = (domVal - domMin) / (domMax - domMin) * (range[1] - range[0]) + range[0]; - } - return result; - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Scale; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2NhbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvU2NhbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFjLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxNQUFVLFFBQVEsQ0FBQztBQU90Qyx1QkFBdUIsQ0FBVSxFQUFFLENBQVE7SUFDdkMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxFQUFFLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUMsT0FBTyxDQUFDLEdBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztBQUN0RSxDQUFDO0FBRUQscUJBQXFCLENBQVUsRUFBRSxDQUFNLEVBQUUsR0FBVTtJQUMvQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQzNELENBQUM7QUFJRCwyQkFBMkIsR0FBWSxFQUFFLEtBQVcsRUFBRSxRQUFlO0lBQ2pFLGtCQUFrQixJQUFXLEVBQUUsS0FBYztRQUN6QyxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JELElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxHQUFHLENBQUMsR0FBQyxHQUFHLENBQUM7UUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUMsSUFBSSxDQUFDO1FBQ3pDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQztRQUN4QyxLQUFLLElBQUksQ0FBQyxHQUFDLEdBQUcsRUFBRSxDQUFDLElBQUUsR0FBRyxFQUFFLENBQUMsSUFBRSxJQUFJLEVBQUU7WUFBRSxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQUU7UUFDN0QsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUNELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RFLFFBQVEsQ0FBQyxTQUFTLEdBQUcsUUFBUSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNoRCxDQUFDO0FBRUQsK0JBQStCLEdBQVksRUFBRSxLQUFXLEVBQUUsUUFBZTtJQUNyRSxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFDLEdBQUcsR0FBRyxDQUFDO0lBQzVFLGlCQUFpQixDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDeEMsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQzFDLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUU5QyxDQUFDO0FBRUQsMkJBQTJCLEdBQVksRUFBRSxLQUFXO0lBQ2hELEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNqQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDakMsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEUsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2RCxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RELElBQUksR0FBRyxHQUFHLEdBQUcsRUFBRTtRQUNYLEtBQUssSUFBSSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFFLEVBQUUsRUFBRTtZQUM3QixLQUFLLElBQUksQ0FBQyxHQUFDLENBQUMsRUFBRSxDQUFDLElBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN0QixJQUFJLENBQUMsS0FBRyxDQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsR0FBQyxHQUFHLEVBQUU7b0JBQUUsYUFBYSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUFFO3FCQUNyRCxJQUFJLENBQUMsR0FBQyxFQUFFLEtBQUcsQ0FBQyxFQUFFLEdBQUU7cUJBQ2hCLElBQUksQ0FBQyxHQUFDLEVB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 - -/***/ }), -/* 25 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__SVGElem__ = __webpack_require__(1); - - -class Grid extends __WEBPACK_IMPORTED_MODULE_1__SVGElem__["a" /* SVGElem */] { - static defaultConfig(cfg) { - cfg.grid = { - major: { - hor: { visible: true }, - ver: { visible: true } - }, - minor: { - hor: { visible: false }, - ver: { visible: false } - } - }; - } - static adjustConfig(cfg) { - } - drawHorGrid(cfg, scale, range, ticks) { - return !cfg.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-hor' }, ticks.marks.map((t) => this.horLine(range[0], range[1], scale.convert(t)))); - } - drawVerGrid(cfg, scale, range, ticks) { - return !cfg.visible ? Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg') : Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-ver' }, ticks.marks.map((t) => this.verLine(scale.convert(t), range[0], range[1]))); - } - view(node) { - const cfg = node.attrs.cfg; - const scales = node.attrs.scales; - const ps = scales.primary; - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid' }, [ - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-minor' }, [ - this.drawHorGrid(cfg.minor.hor, ps.y, ps.x.range(), ps.y.ticks().minor), - this.drawVerGrid(cfg.minor.ver, ps.x, ps.y.range(), ps.x.ticks().minor) - ]), - Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-grid-major' }, [ - this.drawHorGrid(cfg.major.hor, ps.y, ps.x.range(), ps.y.ticks().major), - this.drawVerGrid(cfg.major.ver, ps.x, ps.y.range(), ps.x.ticks().major) - ]) - ]); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Grid; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR3JpZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9HcmlkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlCQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQVcsVUFBVSxDQUFDO0FBR3hDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBVyxXQUFXLENBQUM7QUF5QnpDLE1BQU0sV0FBWSxTQUFRLE9BQU87SUFxQjdCLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVTtRQUMzQixHQUFHLENBQUMsSUFBSSxHQUFnQjtZQUNwQixLQUFLLEVBQUU7Z0JBQ0gsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFDLElBQUksRUFBRTtnQkFDckIsR0FBRyxFQUFFLEVBQUUsT0FBTyxFQUFDLElBQUksRUFBRTthQUN4QjtZQUNELEtBQUssRUFBRTtnQkFDSCxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUMsS0FBSyxFQUFFO2dCQUN0QixHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUMsS0FBSyxFQUFFO2FBQ3pCO1NBQ0osQ0FBQztJQUNOLENBQUM7SUFNRCxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQVU7SUFDOUIsQ0FBQztJQUtPLFdBQVcsQ0FBQyxHQUFxQixFQUFFLEtBQVcsRUFBRSxLQUFjLEVBQUUsS0FBYztRQUNsRixPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLG1CQUFtQixFQUFFLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUMxRixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUNyRCxDQUFDLENBQUM7SUFDUCxDQUFDO0lBS08sV0FBVyxDQUFDLEdBQXFCLEVBQUUsS0FBVyxFQUFFLEtBQWMsRUFBRSxLQUFjO1FBQ2xGLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMsbUJBQW1CLEVBQUUsRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQzFGLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQ3JELENBQUMsQ0FBQztJQUNQLENBQUM7SUFHRCxJQUFJLENBQUMsSUFBWTtRQUNiLE1BQU0sR0FBRyxHQUFlLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO1FBQ3ZDLE1BQU0sTUFBTSxHQUFVLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQ3hDLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFDMUIsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLGVBQWUsRUFBQyxFQUFFO1lBQ3RDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMscUJBQXFCLEVBQUUsRUFBRTtnQkFDdEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLENBQUM7Z0JBQ3ZFLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDO2FBQzFFLENBQUM7WUFDRixDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFDLHFCQUFxQixFQUFFLEVBQUU7Z0JBQ3RDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUFDO2dCQUN2RSxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLEtBQUssQ0FBQzthQUMxRSxDQUFDO1NBQ0wsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztDQUNKIn0= - -/***/ }), -/* 26 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); - -; -class Legend { - static defaultConfig(cfg) { - cfg.legend = {}; - } - static adjustConfig(cfg) { - } - view(node) { - return Object(__WEBPACK_IMPORTED_MODULE_0_hslayout__["m"])('svg', { class: 'hs-graph-legend', width: '100%', height: '100%' }); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Legend; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGVnZW5kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0xlZ2VuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFnQkEsT0FBTyxFQUFFLENBQUMsRUFBUSxNQUFPLFVBQVUsQ0FBQztBQU9uQyxDQUFDO0FBRUYsTUFBTTtJQWFGLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVTtRQUMzQixHQUFHLENBQUMsTUFBTSxHQUFpQixFQUMxQixDQUFDO0lBQ04sQ0FBQztJQU1ELE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBVTtJQUU5QixDQUFDO0lBRUQsSUFBSSxDQUFDLElBQVk7UUFDYixPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUMsaUJBQWlCLEVBQUUsS0FBSyxFQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQztJQUM3RSxDQUFDO0NBQ0oifQ== - -/***/ }), -/* 27 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Site__ = __webpack_require__(28); - -Object(__WEBPACK_IMPORTED_MODULE_0__Site__["a" /* init */])(); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBS0EsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUU5QixJQUFJLEVBQUUsQ0FBQyJ9 - -/***/ }), -/* 28 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = init; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_hslayout__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__view_DocsMenu__ = __webpack_require__(45); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__view_LeftNav__ = __webpack_require__(52); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__view_MainDetail__ = __webpack_require__(54); - - - - -const TitleHeight = '30px'; -const FooterHeight = '10px'; -const LeftNavWidth = '200px'; -const SiteName = 'HSDocs'; -const myConfig = { - Layout: { - rows: [TitleHeight, "fill", FooterHeight], - css: '.hs-site', - content: [{ - Layout: { - columns: [LeftNavWidth, "fill"], - css: '.hs-site-header', - content: [ - { Layout: { - css: '.hs-site-title', - content: SiteName, - href: '/api/' - } }, - { DocsMenu: { docSet: "./data/index.json" } } - ] - } - }, { - Layout: { - columns: [LeftNavWidth, "fill"], - content: [ - { LeftNav: {} }, - { MainDetail: {} } - ] - } - }, - { Layout: { - css: '.hs-site-footer', - content: '(c) Helpful Scripts' - } } - ] - }, - route: { - default: '/api', - paths: [ - '/api', - '/api/:lib', - '/api/:lib/:field' - ] - } -}; -function init() { - new __WEBPACK_IMPORTED_MODULE_0_hslayout__["HsConfig"]([__WEBPACK_IMPORTED_MODULE_0_hslayout__, __WEBPACK_IMPORTED_MODULE_1__view_DocsMenu__, __WEBPACK_IMPORTED_MODULE_2__view_LeftNav__, __WEBPACK_IMPORTED_MODULE_3__view_MainDetail__]).attachNodeTree(myConfig, document.body); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2l0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9TaXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sS0FBSyxRQUFRLE1BQU8sVUFBVSxDQUFDO0FBQ3RDLE9BQU8sS0FBSyxNQUFNLE1BQU8saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxLQUFLLElBQUksTUFBUyxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEtBQUssSUFBSSxNQUFTLG1CQUFtQixDQUFDO0FBRzdDLE1BQU0sV0FBVyxHQUFLLE1BQU0sQ0FBQztBQUM3QixNQUFNLFlBQVksR0FBSSxNQUFNLENBQUM7QUFDN0IsTUFBTSxZQUFZLEdBQUksT0FBTyxDQUFDO0FBQzlCLE1BQU0sUUFBUSxHQUFRLFFBQVEsQ0FBQztBQUUvQixNQUFNLFFBQVEsR0FBRztJQUNiLE1BQU0sRUFBRTtRQUNKLElBQUksRUFBRyxDQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsWUFBWSxDQUFDO1FBQzFDLEdBQUcsRUFBRSxVQUFVO1FBQ2YsT0FBTyxFQUFFLENBQUM7Z0JBQ04sTUFBTSxFQUFDO29CQUNILE9BQU8sRUFBRSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUM7b0JBQy9CLEdBQUcsRUFBRSxpQkFBaUI7b0JBQ3RCLE9BQU8sRUFBRTt3QkFDTCxFQUFFLE1BQU0sRUFBSztnQ0FDVCxHQUFHLEVBQUUsZ0JBQWdCO2dDQUNyQixPQUFPLEVBQUUsUUFBUTtnQ0FDakIsSUFBSSxFQUFDLE9BQU87NkJBQ2YsRUFBQzt3QkFDRixFQUFFLFFBQVEsRUFBSyxFQUFFLE1BQU0sRUFBQyxtQkFBbUIsRUFBQyxFQUFDO3FCQUNoRDtpQkFDSjthQUFDLEVBQUM7Z0JBQ0gsTUFBTSxFQUFDO29CQUNILE9BQU8sRUFBRSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUM7b0JBQy9CLE9BQU8sRUFBRTt3QkFDTCxFQUFFLE9BQU8sRUFBSyxFQUFFLEVBQUM7d0JBQ2pCLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBQztxQkFDcEI7aUJBQ0o7YUFBQztZQUNGLEVBQUUsTUFBTSxFQUFFO29CQUNOLEdBQUcsRUFBRSxpQkFBaUI7b0JBQ3RCLE9BQU8sRUFBRSxxQkFBcUI7aUJBQ2pDLEVBQUM7U0FDTDtLQUNKO0lBQ0QsS0FBSyxFQUFFO1FBQ0gsT0FBTyxFQUFFLE1BQU07UUFDZixLQUFLLEVBQUU7WUFDSCxNQUFNO1lBQ04sV0FBVztZQUNYLGtCQUFrQjtTQUNyQjtLQUNKO0NBQ0osQ0FBQztBQUdGLE1BQU07SUFDRixJQUFJLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2xHLENBQUMifQ== - -/***/ }), -/* 29 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Layouter__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tokens__ = __webpack_require__(5); - - -const PillarLayouts = [ - 'columns', 'rows' -]; -/* harmony export (immutable) */ __webpack_exports__["PillarLayouts"] = PillarLayouts; - -const cParams = { - columns: { - cssClass: '.hs-column-layout', - fields: ['top', 'bottom', 'left', 'right', 'height', 'width'] - }, - rows: { - cssClass: '.hs-row-layout', - fields: ['left', 'right', 'top', 'bottom', 'width', 'height'] - } -}; -class PillarLayouter extends __WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */] { - constructor(params, areaDesc) { - super(areaDesc); - this.areaDesc = areaDesc; - this.fields = params.fields; - this.cssClass = params.cssClass; - let n = areaDesc.length - 1; - let first = 0; - let last = 0; - this.unit = areaDesc.some((area) => (area instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["e" /* PixelToken */])) ? - this.unitPixel : this.unitPercent; - areaDesc.some((area, i) => ((areaDesc[i] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? ++first < 0 : true)); - areaDesc.some((area, i) => ((areaDesc[n - i] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? ++last < 0 : true)); - this.firstFixed = first; - this.lastFixed = Math.min(last, areaDesc.length - first); - } - ; - getSizes(num) { - const first = this.firstFixed; - const last = this.lastFixed; - const desc = this.areaDesc; - const len = desc.length; - return [...Array(num).keys()].map((i) => { - let size = null; - let t = null; - if (i > num - 1 - last) { - size = desc[len - (num - i)].getSize(); - t = 'end'; - } - else if (i < first) { - size = desc[i].getSize(); - t = 'start'; - } - else if (len > 0 && len === first) { - size = desc[len - 1].getSize(); - t = 'start'; - } - return { size: size, code: t, fields: {} }; - }); - } - unitPercent(num) { - let f = this.fields; - let max = 100.0; - let styles = this.getSizes(num); - styles.forEach(style => { if (style.size) { - max = max - style.size; - num--; - } }); - let defDim = max / num; - function pass(styles, ix0, ix1, breakCond) { - let sumDim = 0; - styles.some(style => { - let size = style.size || defDim; - if (breakCond(style.code)) { - return true; - } - style.fields[ix0] = sumDim + '%'; - sumDim += size; - style.fields[ix1] = (100 - sumDim) + '%'; - style.fields[f[5]] = 'auto'; - return false; - }); - } - pass(styles, f[2], f[3], (e) => e === 'end'); - pass(styles.reverse(), f[3], f[2], (e) => e !== 'end'); - return styles.reverse(); - } - ; - unitPixel(num) { - let styles = this.getSizes(num); - let f = this.fields; - let defDim = 100.0 / num; - let sumDim = 0; - styles.some((style, i) => { - if (style.code === 'start') { - style.fields[f[2]] = sumDim + 'px'; - sumDim += style.size + (this.spacing || 0) + (this.spacing || 0); - style.fields[f[3]] = 'auto'; - style.fields[f[5]] = style.size + 'px'; - } - else if (style.code === null) { - style.fields[f[2]] = (sumDim > 0) ? (sumDim + 'px') : (i * defDim + '%'); - sumDim = -1; - style.fields[f[3]] = (100 - (i + 1) * defDim) + '%'; - style.fields[f[5]] = 'auto'; - } - else if (style.code === 'end') { - return true; - } - return false; - }); - sumDim = 0; - styles.slice().reverse().some((style, i) => { - style.fields[f[3]] = sumDim + 'px'; - if (style.code === 'end') { - sumDim += style.size + (this.spacing || 0) + (this.spacing || 0); - style.fields[f[2]] = 'auto'; - style.fields[f[5]] = style.size + 'px'; - } - else { - if (sumDim > 0 && style.code !== 'start') { - style.fields[f[5]] = 'auto'; - } - return true; - } - return false; - }); - return styles; - } - ; - getStyles(components) { - let f = this.fields; - let styles = this.unit(components.length); - components.map((c, i) => { - c.style = `${f[0]}:0%; ${f[1]}:0%; `; - Object.keys(styles[i].fields).forEach((st) => { c.style += `${st}: ${styles[i].fields[st]};`; }); - }); - return this.cssClass; - } - ; -} -; -class Columns extends PillarLayouter { - constructor(areaDesc) { - super(cParams[PillarLayouts[0]], areaDesc); - this.areaDesc = areaDesc; - } - ; -} -; -class Rows extends PillarLayouter { - constructor(areaDesc) { - super(cParams[PillarLayouts[1]], areaDesc); - this.areaDesc = areaDesc; - } - ; -} -; -__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register(PillarLayouts[0], Columns); -__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register(PillarLayouts[1], Rows); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGlsbGFyZWRMYXlvdXRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy92aWV3L1BpbGxhcmVkTGF5b3V0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBMkNBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBWSxZQUFZLENBQUM7QUFDNUMsT0FBTyxFQUFlLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBUyxVQUFVLENBQUM7QUFnQnBFLE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRztJQUN6QixTQUFTLEVBQUUsTUFBTTtDQUNwQixDQUFDO0FBS0YsTUFBTSxPQUFPLEdBQUc7SUFDWixPQUFPLEVBQWdCO1FBQ25CLFFBQVEsRUFBRSxtQkFBbUI7UUFDN0IsTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUM7S0FDaEU7SUFDRCxJQUFJLEVBQWdCO1FBQ2hCLFFBQVEsRUFBRSxnQkFBZ0I7UUFDMUIsTUFBTSxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUM7S0FDaEU7Q0FDSixDQUFDO0FBT0Ysb0JBQThCLFNBQVEsUUFBUTtJQWExQyxZQUFZLE1BQW1CLEVBQVMsUUFBc0I7UUFDMUQsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRG9CLGFBQVEsR0FBUixRQUFRLENBQWM7UUFFMUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzVCLElBQUksQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztRQUVoQyxJQUFJLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQztRQUMxQixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDZCxJQUFJLElBQUksR0FBSSxDQUFDLENBQUM7UUFFZCxJQUFJLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFnQixFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksWUFBWSxVQUFVLENBQUMsQ0FBQyxDQUFBLENBQUM7WUFDMUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQztRQUd0QyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBZ0IsRUFBRSxDQUFRLEVBQUUsRUFBRSxDQUN6QyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxZQUFjLFlBQVksQ0FBQyxDQUFBLENBQUMsQ0FBQyxFQUFFLEtBQUssR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFHakUsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQWdCLEVBQUUsQ0FBUSxFQUFFLEVBQUUsQ0FDekMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFlBQVksWUFBWSxDQUFDLENBQUEsQ0FBQyxDQUFDLEVBQUUsSUFBSSxHQUFDLENBQUMsQ0FBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUVqRSxJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQztRQUN4QixJQUFJLENBQUMsU0FBUyxHQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxNQUFNLEdBQUMsS0FBSyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUFBLENBQUM7SUFTTSxRQUFRLENBQUMsR0FBVTtRQUN2QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxHQUFJLElBQUksQ0FBQyxTQUFTLENBQUM7UUFDN0IsTUFBTSxJQUFJLEdBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUM1QixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBRXhCLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVEsRUFBRSxFQUFFO1lBQzNDLElBQUksSUFBSSxHQUFVLElBQUksQ0FBQztZQUN2QixJQUFJLENBQUMsR0FBRyxJQUFJLENBQUM7WUFDYixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUMsQ0FBQyxHQUFDLElBQUksRUFBRztnQkFBRSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUFDLENBQUMsR0FBRyxLQUFLLENBQUM7YUFBRTtpQkFDcEUsSUFBSSxDQUFDLEdBQUcsS0FBSyxFQUFHO2dCQUFFLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQUMsQ0FBQyxHQUFHLE9BQU8sQ0FBQzthQUFFO2lCQUMxRCxJQUFJLEdBQUcsR0FBQyxDQUFDLElBQUksR0FBRyxLQUFHLEtBQUssRUFBQztnQkFBRSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFBQyxDQUFDLEdBQUcsT0FBTyxDQUFDO2FBQUU7WUFDNUUsT0FBTyxFQUFDLElBQUksRUFBQyxJQUFJLEVBQUUsSUFBSSxFQUFDLENBQUMsRUFBRSxNQUFNLEVBQUMsRUFBRSxFQUFDLENBQUM7UUFDMUMsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRU8sV0FBVyxDQUFDLEdBQVU7UUFDMUIsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUNwQixJQUFJLEdBQUcsR0FBRyxLQUFLLENBQUM7UUFDaEIsSUFBSSxNQUFNLEdBQWdCLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFN0MsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLElBQUksS0FBSyxDQUFDLElBQUksRUFBRTtZQUFFLEdBQUcsR0FBRyxHQUFHLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztZQUFDLEdBQUcsRUFBRSxDQUFDO1NBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNoRixJQUFJLE1BQU0sR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO1FBRXZCLGNBQWMsTUFBbUIsRUFBRSxHQUFVLEVBQUUsR0FBVSxFQUFFLFNBQWdDO1lBQ3ZGLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQztZQUNmLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQ2hCLElBQUksSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDO2dCQUNoQyxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUU7b0JBQUUsT0FBTyxJQUFJLENBQUM7aUJBQUU7Z0JBQzNDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxHQUFDLEdBQUcsQ0FBQztnQkFDL0IsTUFBTSxJQUFJLElBQUksQ0FBQztnQkFDZixLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxHQUFDLE1BQU0sQ0FBQyxHQUFDLEdBQUcsQ0FBQztnQkFDckMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUM7Z0JBQzVCLE9BQU8sS0FBSyxDQUFDO1lBQ2pCLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztRQUVELElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFHLEtBQUssQ0FBQyxDQUFDO1FBQ2xELElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFHLEtBQUssQ0FBQyxDQUFDO1FBQzVELE9BQU8sTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzVCLENBQUM7SUFBQSxDQUFDO0lBRU0sU0FBUyxDQUFDLEdBQVU7UUFDeEIsSUFBSSxNQUFNLEdBQWdCLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDN0MsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUVwQixJQUFJLE1BQU0sR0FBRyxLQUFLLEdBQUMsR0FBRyxDQUFDO1FBR3ZCLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQztRQUNmLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDckIsSUFBSSxLQUFLLENBQUMsSUFBSSxLQUFHLE9BQU8sRUFBRTtnQkFDdEIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLEdBQUUsSUFBSSxDQUFDO2dCQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUNqRSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQztnQkFDNUIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxHQUFFLElBQUksQ0FBQzthQUN6QztpQkFBTSxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssSUFBSSxFQUFFO2dCQUM1QixLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxDQUFBLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDO2dCQUNuRSxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBQ1osS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUM7Z0JBQzlDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDO2FBQy9CO2lCQUFNLElBQUksS0FBSyxDQUFDLElBQUksS0FBRyxLQUFLLEVBQUU7Z0JBQUUsT0FBTyxJQUFJLENBQUM7YUFBRTtZQUMvQyxPQUFPLEtBQUssQ0FBQztRQUNqQixDQUFDLENBQUMsQ0FBQztRQUdILE1BQU0sR0FBRyxDQUFDLENBQUM7UUFDWCxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3ZDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxHQUFHLElBQUksQ0FBQztZQUNuQyxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssS0FBSyxFQUFFO2dCQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUNqRSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQztnQkFDNUIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxHQUFDLElBQUksQ0FBQzthQUN4QztpQkFBTTtnQkFDSCxJQUFJLE1BQU0sR0FBQyxDQUFDLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUU7b0JBQ3BDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDO2lCQUMvQjtnQkFDRCxPQUFPLElBQUksQ0FBQzthQUNmO1lBQ0QsT0FBTyxLQUFLLENBQUM7UUFDakIsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLE1BQU0sQ0FBQztJQUNsQixDQUFDO0lBQUEsQ0FBQztJQVFRLFNBQVMsQ0FBQyxVQUE4QjtRQUM5QyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3BCLElBQUksTUFBTSxHQUFnQixJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN2RCxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBYyxFQUFFLENBQVEsRUFBRSxFQUFFO1lBQ3hDLENBQUMsQ0FBQyxLQUFLLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7WUFDckMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBUyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUMsS0FBSyxJQUFJLEdBQUcsRUFBRSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzVHLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ3pCLENBQUM7SUFBQSxDQUFDO0NBQ0w7QUFBQSxDQUFDO0FBc0RGLGFBQWMsU0FBUSxjQUFjO0lBQ2hDLFlBQW1CLFFBQXNCO1FBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUFyRSxhQUFRLEdBQVIsUUFBUSxDQUFjO0lBQWlELENBQUM7SUFBQSxDQUFDO0NBQy9GO0FBQUEsQ0FBQztBQXNERixVQUFXLFNBQVEsY0FBYztJQUM3QixZQUFtQixRQUFzQjtRQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFBckUsYUFBUSxHQUFSLFFBQVEsQ0FBYztJQUFpRCxDQUFDO0lBQUEsQ0FBQztDQUMvRjtBQUFBLENBQUM7QUFFRixRQUFRLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQztBQUM3QyxRQUFRLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsRUFBSyxJQUFJLENBQUMsQ0FBQyJ9 - -/***/ }), -/* 30 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Layouter__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Tokens__ = __webpack_require__(5); - - -class Tiles extends __WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */] { - constructor(areaDesc) { - super(areaDesc); - this.areaDesc = areaDesc; - this.unit = areaDesc.some((area) => (area instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["e" /* PixelToken */])) ? - this.unitPixel : this.unitPercent; - } - ; - unitPercent(num) { - const desc = this.areaDesc; - const fill = this.areaDesc.some(a => (a instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["c" /* FillToken */])); - const root = Math.sqrt(num); - const rows = Math.round(root); - let cols = Math.floor(root); - if (root > cols) { - cols++; - } - let width = (desc[0] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[0].getSize() : undefined; - let height = (desc[1] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[1].getSize() : width; - width = width || 100 / cols; - height = height || 100 / rows; - let left = 0; - let top = 0; - let styles = [...Array(num).keys()].map(i => { - let r = 'auto'; - let w = width + '%'; - let b = 'auto'; - let h = height + '%'; - if ((left + 2 * width) > 100 && fill) { - r = '0%'; - w = 'auto'; - } - if ((top + 2 * height) > 100 && fill) { - b = '0%'; - h = 'auto'; - } - const style = ` - top: ${Math.floor(top)}%; bottom:${b}; - left: ${left}%; right:${r}; - width: ${w}; height: ${h}; - `; - if (Math.round(left += width) > 100 - Math.floor(width)) { - left = 0; - top += height; - } - return style; - }); - return styles; - } - ; - unitPixel(num) { - const desc = this.areaDesc; - const root = Math.sqrt(num); - const rows = Math.round(root); - let cols = Math.floor(root); - if (root > cols) { - cols++; - } - let width = (desc[0] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[0].getSize() : undefined; - let height = (desc[1] instanceof __WEBPACK_IMPORTED_MODULE_1__Tokens__["a" /* DefinedToken */]) ? desc[1].getSize() : width; - width = width || 100 / cols; - height = height || 100 / rows; - let left = 0; - let top = 0; - let styles = [...Array(num).keys()].map(i => { - let r = 'auto'; - let w = width + 'px'; - let b = 'auto'; - let h = height + 'px'; - const style = ` - top: ${Math.floor(top)}%; bottom:${b}; - left: ${left}%; right:${r}; - width: ${w}; height: ${h}; - `; - if (Math.round(left += width) > 100 - Math.floor(width)) { - left = 0; - top += height; - } - return style; - }); - return styles; - } - ; - getStyles(components) { - let styles = this.unit(components.length); - components.map((c, i) => { - c.style = styles[i]; - }); - return '.hs-tile-layout'; - } - ; -} -; -__WEBPACK_IMPORTED_MODULE_0__Layouter__["a" /* Layouter */].register('tiles', Tiles); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGlsZUxheW91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvVGlsZUxheW91dGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZEQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQVksWUFBWSxDQUFDO0FBQzVDLE9BQU8sRUFBZSxTQUFTLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFTLFVBQVUsQ0FBQztBQU8vRSxXQUFZLFNBQVEsUUFBUTtJQVF4QixZQUFtQixRQUFzQjtRQUNyQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFERCxhQUFRLEdBQVIsUUFBUSxDQUFjO1FBSXJDLElBQUksQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQWdCLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxZQUFZLFVBQVUsQ0FBQyxDQUFDLENBQUEsQ0FBQztZQUMxRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFDLENBQUM7SUFBQSxDQUFDO0lBRU0sV0FBVyxDQUFDLEdBQVU7UUFDMUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUMzQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxZQUFZLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDL0QsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzlCLElBQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDOUIsSUFBSSxJQUFJLEdBQUcsSUFBSSxFQUFFO1lBQUUsSUFBSSxFQUFFLENBQUM7U0FB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 - -/***/ }), -/* 31 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__mithril__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Layouter__ = __webpack_require__(4); - - -class Layout { - getComponents(node) { - return !Array.isArray(node.attrs.content) ? node.attrs.content : - node.attrs.content.map((c) => { - if (c.compClass) { - c.attrs.route = node.attrs.route; - return Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(c.compClass, c.attrs); - } - else { - return c; - } - }); - } - getCSS(node) { - return node.attrs.css || ''; - } - normalizeContent(components) { - if (typeof components === 'string') { - return [Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])('.hs-leaf', __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].trust(components))]; - } - if (components.length > 0) { - return components.map((comp) => (comp instanceof Layout) ? comp : Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(Layout, { content: comp })); - } - return [components]; - } - view(node) { - const content = this.normalizeContent(this.getComponents(node)); - let css = __WEBPACK_IMPORTED_MODULE_1__Layouter__["a" /* Layouter */].createLayout(node.attrs, content); - const attrs = { - style: node.style, - route: node.attrs.route, - onclick: node.attrs.onclick - }; - node.attrs.route = undefined; - if (node.attrs.href) { - attrs.href = node.attrs.href; - attrs.oncreate = __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].route.link; - attrs.onupdate = __WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */].route.link; - } - return Object(__WEBPACK_IMPORTED_MODULE_0__mithril__["a" /* m */])(`.hs-layout ${css} ${this.getCSS(node)}`, attrs, content.map((c) => c)); - } -} -/* harmony export (immutable) */ __webpack_exports__["a"] = Layout; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5b3V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZpZXcvTGF5b3V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWlCQSxPQUFPLEVBQUUsQ0FBQyxFQUFRLE1BQVcsWUFBWSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBWSxZQUFZLENBQUM7QUF5QjVDLE1BQU07SUFvQlEsYUFBYSxDQUFDLElBQVU7UUFDOUIsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMzRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFLLEVBQUUsRUFBRTtnQkFDN0IsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFO29CQUNiLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO29CQUNqQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztpQkFDbEM7cUJBQU07b0JBQ0gsT0FBTyxDQUFDLENBQUM7aUJBQ1o7WUFDTCxDQUFDLENBQUMsQ0FBQztJQUNYLENBQUM7SUFRUyxNQUFNLENBQUMsSUFBVTtRQUN2QixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQztJQUNoQyxDQUFDO0lBR08sZ0JBQWdCLENBQUMsVUFBNkM7UUFDbEUsSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUU7WUFDaEMsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDL0M7UUFDRCxJQUFJLFVBQVUsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFFO1lBQ3JCLE9BQU8sVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQXlCLEVBQVEsRUFBRSxDQUNsRCxDQUFDLElBQUksWUFBWSxNQUFNLENBQUMsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUMsT0FBTyxFQUFDLElBQUksRUFBQyxDQUFDLENBQ2pFLENBQUM7U0FDTDtRQUVELE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBcUJELElBQUksQ0FBQyxJQUFVO1FBQ1gsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNoRSxJQUFJLEdBQUcsR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDckQsTUFBTSxLQUFLLEdBQU87WUFDZCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSztZQUN2QixPQUFPLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPO1NBQzlCLENBQUM7UUFDRixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUM7UUFDN0IsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRTtZQUNqQixLQUFLLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO1lBQzdCLEtBQUssQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7WUFDOUIsS0FBSyxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztTQUNqQztRQUNELE9BQU8sQ0FBQyxDQUFDLGNBQWMsR0FBRyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RixDQUFDO0NBQ0oifQ== - -/***/ }), -/* 32 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var pushStateMock = __webpack_require__(33) -var domMock = __webpack_require__(35) -var xhrMock = __webpack_require__(36) - -module.exports = function(env) { - env = env || {} - var $window = env.window = {} - - var dom = domMock() - var xhr = xhrMock() - for (var key in dom) if (!$window[key]) $window[key] = dom[key] - for (var key in xhr) if (!$window[key]) $window[key] = xhr[key] - pushStateMock(env) - - return $window -} - -/***/ }), -/* 33 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var parseURL = __webpack_require__(13) -var callAsync = __webpack_require__(14) - -function debouncedAsync(f) { - var ref - return function() { - if (ref != null) return - ref = callAsync(function(){ - ref = null - f() - }) - } -} - -module.exports = function(options) { - if (options == null) options = {} - - var $window = options.window || {} - var protocol = options.protocol || "http:" - var hostname = options.hostname || "localhost" - var port = "" - var pathname = "/" - var search = "" - var hash = "" - - var past = [{url: getURL(), isNew: true, state: null, title: null}], future = [] - - function getURL() { - if (protocol === "file:") return protocol + "//" + pathname + search + hash - return protocol + "//" + hostname + prefix(":", port) + pathname + search + hash - } - function setURL(value) { - var data = parseURL(value, {protocol: protocol, hostname: hostname, port: port, pathname: pathname}) - var isNew = false - if (data.protocol != null && data.protocol !== protocol) protocol = data.protocol, isNew = true - if (data.hostname != null && data.hostname !== hostname) hostname = data.hostname, isNew = true - if (data.port != null && data.port !== port) port = data.port, isNew = true - if (data.pathname != null && data.pathname !== pathname) pathname = data.pathname, isNew = true - if (data.search != null && data.search !== search) search = data.search, isNew = true - if (data.hash != null && data.hash !== hash) { - hash = data.hash - if (!isNew) { - hashchange() - } - } - return isNew - } - - function prefix(prefix, value) { - if (value === "") return "" - return (value.charAt(0) !== prefix ? prefix : "") + value - } - function _hashchange() { - if (typeof $window.onhashchange === "function") $window.onhashchange({type: "hashchange"}) - } - var hashchange = debouncedAsync(_hashchange) - function popstate() { - if (typeof $window.onpopstate === "function") $window.onpopstate({type: "popstate", state: $window.history.state}) - } - function unload() { - if (typeof $window.onunload === "function") $window.onunload({type: "unload"}) - } - - $window.location = { - get protocol() { - return protocol - }, - get hostname() { - return hostname - }, - get port() { - return port - }, - get pathname() { - return pathname - }, - get search() { - return search - }, - get hash() { - return hash - }, - get origin() { - if (protocol === "file:") return "null" - return protocol + "//" + hostname + prefix(":", port) - }, - get host() { - if (protocol === "file:") return "" - return hostname + prefix(":", port) - }, - get href() { - return getURL() - }, - - set protocol(value) { - throw new Error("Protocol is read-only") - }, - set hostname(value) { - unload() - past.push({url: getURL(), isNew: true}) - future = [] - hostname = value - }, - set port(value) { - if (protocol === "file:") throw new Error("Port is read-only under `file://` protocol") - unload() - past.push({url: getURL(), isNew: true}) - future = [] - port = value - }, - set pathname(value) { - if (protocol === "file:") throw new Error("Pathname is read-only under `file://` protocol") - unload() - past.push({url: getURL(), isNew: true}) - future = [] - pathname = prefix("/", value) - }, - set search(value) { - unload() - past.push({url: getURL(), isNew: true}) - future = [] - search = prefix("?", value) - }, - set hash(value) { - var oldHash = hash - past.push({url: getURL(), isNew: false}) - future = [] - hash = prefix("#", value) - if (oldHash != hash) hashchange() - }, - - set origin(value) { - //origin is writable but ignored - }, - set host(value) { - //host is writable but ignored in Chrome - }, - set href(value) { - var url = getURL() - var isNew = setURL(value) - if (isNew) { - setURL(url) - unload() - setURL(value) - } - past.push({url: url, isNew: isNew}) - future = [] - }, - } - $window.history = { - pushState: function(state, title, url) { - past.push({url: getURL(), isNew: false, state: state, title: title}) - future = [] - setURL(url) - }, - replaceState: function(state, title, url) { - var entry = past[past.length - 1] - entry.state = state - entry.title = title - setURL(url) - }, - back: function() { - if (past.length > 1) { - var entry = past.pop() - if (entry.isNew) unload() - future.push({url: getURL(), isNew: false, state: entry.state, title: entry.title}) - setURL(entry.url) - if (!entry.isNew) popstate() - } - }, - forward: function() { - var entry = future.pop() - if (entry != null) { - if (entry.isNew) unload() - past.push({url: getURL(), isNew: false, state: entry.state, title: entry.title}) - setURL(entry.url) - if (!entry.isNew) popstate() - } - }, - get state() { - return past.length === 0 ? null : past[past.length - 1].state - }, - } - $window.onpopstate = null, - $window.onhashchange = null, - $window.onunload = null - - return $window -} - - -/***/ }), -/* 34 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, undefined) { - "use strict"; - - if (global.setImmediate) { - return; - } - - var nextHandle = 1; // Spec says greater than zero - var tasksByHandle = {}; - var currentlyRunningATask = false; - var doc = global.document; - var registerImmediate; - - function setImmediate(callback) { - // Callback can either be a function or a string - if (typeof callback !== "function") { - callback = new Function("" + callback); - } - // Copy function arguments - var args = new Array(arguments.length - 1); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i + 1]; - } - // Store and register the task - var task = { callback: callback, args: args }; - tasksByHandle[nextHandle] = task; - registerImmediate(nextHandle); - return nextHandle++; - } - - function clearImmediate(handle) { - delete tasksByHandle[handle]; - } - - function run(task) { - var callback = task.callback; - var args = task.args; - switch (args.length) { - case 0: - callback(); - break; - case 1: - callback(args[0]); - break; - case 2: - callback(args[0], args[1]); - break; - case 3: - callback(args[0], args[1], args[2]); - break; - default: - callback.apply(undefined, args); - break; - } - } - - function runIfPresent(handle) { - // From the spec: "Wait until any invocations of this algorithm started before this one have completed." - // So if we're currently running a task, we'll need to delay this invocation. - if (currentlyRunningATask) { - // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a - // "too much recursion" error. - setTimeout(runIfPresent, 0, handle); - } else { - var task = tasksByHandle[handle]; - if (task) { - currentlyRunningATask = true; - try { - run(task); - } finally { - clearImmediate(handle); - currentlyRunningATask = false; - } - } - } - } - - function installNextTickImplementation() { - registerImmediate = function(handle) { - process.nextTick(function () { runIfPresent(handle); }); - }; - } - - function canUsePostMessage() { - // The test against `importScripts` prevents this implementation from being installed inside a web worker, - // where `global.postMessage` means something completely different and can't be used for this purpose. - if (global.postMessage && !global.importScripts) { - var postMessageIsAsynchronous = true; - var oldOnMessage = global.onmessage; - global.onmessage = function() { - postMessageIsAsynchronous = false; - }; - global.postMessage("", "*"); - global.onmessage = oldOnMessage; - return postMessageIsAsynchronous; - } - } - - function installPostMessageImplementation() { - // Installs an event handler on `global` for the `message` event: see - // * https://developer.mozilla.org/en/DOM/window.postMessage - // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages - - var messagePrefix = "setImmediate$" + Math.random() + "$"; - var onGlobalMessage = function(event) { - if (event.source === global && - typeof event.data === "string" && - event.data.indexOf(messagePrefix) === 0) { - runIfPresent(+event.data.slice(messagePrefix.length)); - } - }; - - if (global.addEventListener) { - global.addEventListener("message", onGlobalMessage, false); - } else { - global.attachEvent("onmessage", onGlobalMessage); - } - - registerImmediate = function(handle) { - global.postMessage(messagePrefix + handle, "*"); - }; - } - - function installMessageChannelImplementation() { - var channel = new MessageChannel(); - channel.port1.onmessage = function(event) { - var handle = event.data; - runIfPresent(handle); - }; - - registerImmediate = function(handle) { - channel.port2.postMessage(handle); - }; - } - - function installReadyStateChangeImplementation() { - var html = doc.documentElement; - registerImmediate = function(handle) { - // Create a - - \ No newline at end of file diff --git a/docs/indexGH.html b/docs/indexGH.html new file mode 100644 index 0000000..ae78047 --- /dev/null +++ b/docs/indexGH.html @@ -0,0 +1,11 @@ + + + + + HS Docs + + + + + + \ No newline at end of file diff --git a/docs/src/hsData/Data.html b/docs/src/hsData/Data.html deleted file mode 100644 index 490c8c7..0000000 --- a/docs/src/hsData/Data.html +++ /dev/null @@ -1,557 +0,0 @@ - - -

    Data.ts

    -
       1/**
    -   2 */

    -   3
    -   4 /** */
    -   5import { Condition, filter } from './DataFilters';
    -   6
    -   7/** defines a [min-max] range */
    -   8export type NumRange = [number, number];
    -   9
    -  10/** defines a numeric domain that includes all values of a column */
    -  11export type NumDomain = [number, number];
    -  12
    -  13/** defines a Date domain that includes all values of a column */
    -  14export type DateDomain = [Date, Date];
    -  15
    -  16/** defines a categorical domain that includes all values of a column */
    -  17export type NameDomain = string[];
    -  18
    -  19/** defines a generic domain that can be any of the typed domains. */
    -  20export type Domain = NumDomain | DateDomain | NameDomain;
    -  21
    -  22/** defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    -  23export type ColumnReference = number|string;
    -  24
    -  25/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    -  26export type DataVal = number|string|Date;
    -  27
    -  28/** a single row of column values */
    -  29export type DataRow = DataVal[];
    -  30
    -  31/** a JSON format data set, using arrays of names and rows */
    -  32export interface DataSet {
    -  33    /** an optional name for the data set */
    -  34    name?:  string;
    -  35    /** an array of column names. Each name matches the column with the same index in DataRow */
    -  36    colNames:  string[];   
    -  37    /** rows of data */
    -  38    rows:   DataRow[];
    -  39}
    -  40
    -  41/** a JSON format data set, using an array of {name:value, ...} literals*/
    -  42export type DataLiteralSet = Array;
    -  43
    -  44interface TypeStruct { type: string; count: number;};
    -  45
    -  46interface MetaStruct {
    -  47    name:       string;         // column name
    -  48    column:     number;         // column index
    -  49    accessed:   boolean;        // has column data been accessed?
    -  50    cast:       boolean;        // has column data been cast 
    -  51    types:      TypeStruct[];   // data types, sorted by likelihood
    -  52}
    -  53
    -  54export type sortFn = (x:any, y:any) => number;
    -  55export type mapFn  = (colVal:any, colIndex?:number, rowIndex?:number, rows?:any[][]) => any;
    -  56
    -  57/**
    -  58 * # Data
    -  59 * A simple in-memory database that holds data in rows of columns.
    -  60 * 
    -  61 */

    -  62export class Data {
    -  63    //----------------------------
    -  64    // public part
    -  65    //----------------------------
    -  66    public static type = {
    -  67        number:     'number data',
    -  68        name:       'name data',
    -  69        date:       'date data',
    -  70        currency:   'currency data',
    -  71        percent:    'percent data',
    -  72        nominal:    'nominal data'
    -  73    };
    -  74
    -  75    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    -  76        data = data || [{}];
    -  77        const names = Object.keys(data[0]);
    -  78        const rows = data.map((r:any) => 
    -  79            names.map((n:string) => r[n]));
    -  80        return { rows:rows, colNames:names, name:name||undefined };
    -  81    }
    -  82
    -  83    constructor(data?:DataSet) {
    -  84        this.import(data);
    -  85    }
    -  86
    -  87    /**
    -  88     * @return the `name` field for this data base, if any
    -  89     */

    -  90    public getName():string {
    -  91        return this.name;
    -  92    }
    -  93
    -  94    /**
    -  95     * Imports data from an object literal `data`
    -  96     * @param data the data set to import
    -  97     */

    -  98    public import(data:DataSet) {
    -  99        this.name = data.name;
    - 100        this.setData(data.rows, data.colNames);
    - 101    }
    - 102
    - 103    /**
    - 104     * Exports to an object literal
    - 105     */

    - 106    public export():DataSet {
    - 107        return {
    - 108            rows: this.getData(),
    - 109            colNames:this.colNames()
    - 110        };
    - 111    }
    - 112
    - 113    /**
    - 114     * returns the 2D array underlying the data base.
    - 115     */

    - 116    public getData():DataRow[] {
    - 117        return this.data;
    - 118    }
    - 119
    - 120    /**
    - 121     * Returns the values in the specified column as a new array.
    - 122     * @param col the column to return.
    - 123     */

    - 124    public getColumn(col:ColumnReference): DataVal[] {
    - 125        const cn = this.colNumber(col);
    - 126        return this.data.map((row:DataRow) => row[cn]);
    - 127    }
    - 128
    - 129    /**
    - 130     * adds a new column to the data set. if `newCol` already exists, 
    - 131     * the column index is returned withoput change.
    - 132     * @param col the name of the new column
    - 133     * @return the index for the new column
    - 134     */

    - 135    public colAdd(col:string):number {
    - 136        let m = this.getMeta(col);
    - 137        if (m === undefined) { 
    - 138            m = this.meta[col] = {};
    - 139            m.name   = col; 
    - 140            m.column = this.meta.length;
    - 141            this.meta.push(m);      // access name by both column name and index
    - 142            m.cast     = false;         // has not been cast yet
    - 143            m.accessed = false;         // has not been accessed yet
    - 144        }
    - 145        return m.column;
    - 146    }
    - 147
    - 148    /**
    - 149     * initializes the specifed column with values, adding a new column if needed. 
    - 150     * If `val`is a function, it is called as ```
    - 151     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    - 152     * ```
    - 153     * @param col the column to initialize
    - 154     * @param initializer the value to initialize with, or a function whose return
    - 155     * value is used to initialize the column
    - 156     */

    - 157    public colInitialize(col:ColumnReference, initializer:any) {
    - 158        const cn = this.colNumber(col);
    - 159        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    - 160        const fn = typeof initializer === 'function';
    - 161        if (cn!==undefined) {
    - 162            this.data.map((r:DataRow, i:number) =>
    - 163                r[cn] = fn? initializer(r[cn], i, r) : initializer
    - 164            );
    - 165        }
    - 166    }
    - 167
    - 168    /**
    - 169     * returns the column index of the specified column. 
    - 170     * `col` can be either an index or a name.
    - 171     * @param column the data column, name or index, for which to return the index. 
    - 172     * @return the column number or `undefined`.
    - 173     */

    - 174    public colNumber(col:ColumnReference) {
    - 175        const m = this.getMeta(col);
    - 176        if (!m) { return undefined; }
    - 177        else {
    - 178            m.accessed = true; 
    - 179            return m.column; 
    - 180        }
    - 181    }
    - 182    
    - 183    /**
    - 184     * returns the column name for the specified column. 
    - 185     * `col` can be either an index or a name.
    - 186     * @param column the data column, name or index. 
    - 187     * @return the column name or `undefined`.
    - 188     */

    - 189    public colName(col:ColumnReference) {
    - 190        var m = this.getMeta(col);
    - 191        if (!m) { return undefined; }
    - 192        m.accessed = true; 
    - 193        return m.name; 
    - 194    }
    - 195
    - 196    /**
    - 197     * returns the names for all columns. 
    - 198     * @return an array of strings with the names.
    - 199     */

    - 200    public colNames():string[] {
    - 201        return this.meta.map((m:MetaStruct) => m.name); 
    - 202    }
    - 203
    - 204    /**
    - 205     * returns the column type for the specified column. 
    - 206     * `col` can be either an index or a name.
    - 207     * @param column the data column, name or index. 
    - 208     * @return the column type.
    - 209     */

    - 210    public colType(col:ColumnReference) { 
    - 211        const meta = this.getMeta(col);
    - 212        return meta? meta.types[0].type : Data.type.name;
    - 213    }
    - 214
    - 215    /**
    - 216     * modifies `domain` to include all values in column `col`.
    - 217     * @param col the column name or index 
    - 218     * @param domain the 
    - 219     */

    - 220    public findDomain(col:ColumnReference, domain:Domain) {
    - 221        if (col === undefined) { // use array index as domain
    - 222            domain[0] = 0;
    - 223            domain[1] = this.data.length-1;
    - 224        } else {
    - 225            const c = this.colNumber(col);
    - 226            const type = this.colType(col);
    - 227            if (this.data === undefined) {
    - 228                console.log('no data'); 
    - 229            }
    - 230            switch(type) {
    - 231                case Data.type.nominal: 
    - 232                    this.data.forEach((r:DataRow) => {
    - 233                        const nomDom = domain;
    - 234                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    - 235                    });
    - 236                    break;
    - 237                default: 
    - 238                    this.data.forEach((r:DataRow) => {
    - 239                        let v:number = r[c];
    - 240                        if (v!==undefined && v!==null) {
    - 241                            domain[0] = (v - 242                            domain[1] = (v>domain[1])? v : domain[1];
    - 243                        }
    - 244                    });
    - 245            }
    - 246        }
    - 247    }
    - 248
    - 249    public castData() {
    - 250        this.meta.forEach((c:MetaStruct) => {
    - 251            const col = c.column;
    - 252            if (!c.cast) {
    - 253                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    - 254            }
    - 255            c.cast = true;
    - 256        });
    - 257    }
    - 258
    - 259    /**
    - 260     * filters this data set and returns a new data set with a 
    - 261     * shallow copy of rows that pass the `condition`.
    - 262     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    - 263     * @param condition filters 
    - 264     * @return a new Data object with rows that pass the filter
    - 265     */

    - 266    public filter(condition:Condition):Data {
    - 267        return filter(this, condition);
    - 268    }
    - 269
    - 270    /**
    - 271     * @description Sorts the rows of values based on the result of the `sortFn`, 
    - 272     * which behaves similarly to the Array.sort method.  
    - 273     * Two modes are supported:
    - 274     * # Array Mode
    - 275     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    - 276     * This allows for complex sorts, combining conditions across multiple columns.
    - 277     * ```
    - 278     * data.sort((row1, row2) => row1[5] - row2[5] );
    - 279     * ```
    - 280     * # Column mode
    - 281     * If `col` is specified, either as index or by column name, the respective column value is passed
    - 282     * into `sortFn`. This allows filtering for simple conditions.

    - 283     * **The specified column will be automatically cast prior to sorting**

    - 284     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    - 285     * @param col optional; the data column to use for sorting. 
    - 286     * @param sortFn a function to implement the conditions, 
    - 287     * follows the same specifications as the function passed to Array.sort(). 
    - 288     * Some predefined sort function can be invoked by providing a 
    - 289     * respective string instead of a function. The following functions are defined:
    - 290        
    - 291        
    - 292        
    - 293        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    - 294     * @return the Data object in order to allow for chaining.
    - 295     */

    - 296    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    - 297        let fn = sortFn;
    - 298        if (!col) {
    - 299            this.data.sort(fn);
    - 300        } else {
    - 301            col = this.colNumber(col);
    - 302            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b - 303            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    - 304            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    - 305        }
    - 306        return this;
    - 307    }
    - 308
    - 309    /** 
    - 310    *  Maps one or more columns in each rows of values based 
    - 311     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    - 312     * Two modes are supported:
    - 313     * # Array Mode
    - 314     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    - 315     * This allows for complex mapping combining conditions across multiple columns.
    - 316     * ```
    - 317     * data.map(function(values){ 
    - 318     *    values[1] = values[3] * values[5]; 
    - 319     *    return values; 
    - 320     * });
    - 321     * ```
    - 322     * Be sure to return the `values` array as a result.
    - 323     * # Column mode
    - 324     * If `col` is specified, either as index or by column name, the respective column value is passed
    - 325     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    - 326     * ```
    - 327     * data.map('Price', function(value, i, values) { 
    - 328     *    return value * 2; 
    - 329     * });
    - 330     * ```
    - 331     * @param col the data column, or columns, to apply the mapping to. 
    - 332     * @param mapFn a function to implement the mapping,
    - 333     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    - 334     * - `val`: the column value in the current row
    - 335     * - `c`: the column index in the current row
    - 336     * - `i`: the row index 
    - 337     * - `rows`: the rows being iterated over
    - 338`    * 
    - 339     * follows the same specifications as the function passed to Array.map().

    - 340     * For column mode, some predefined map functions can be invoked by providing a 
    - 341     * respective string instead of a function. The following functions are defined:
    - 342        
    - 343        
    - 344        
    - 345        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    - 346     * @return a new Data object containing the mapping.
    - 347     */

    - 348    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    - 349        const noop = (val:any) => val;
    - 350        const cumulate = () => { 
    - 351            let sum=0; 
    - 352            return (val:number, i:number) => { sum += +val; return sum; };
    - 353        };
    - 354        function getFn() {
    - 355            let fn; // define fn inside each col loop to ensure initialization
    - 356            switch (mapFn) {
    - 357                case 'cumulate': fn = cumulate(); break;
    - 358                case 'noop':     fn = noop; break;
    - 359                default:         fn = mapFn;
    - 360            }
    - 361            return fn;
    - 362        }
    - 363
    - 364        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    - 365
    - 366        const names = col['length']? col : [col];            
    - 367        names.map((cn:ColumnReference) => {
    - 368            const c = this.colNumber(cn);
    - 369            let fn = getFn(); // define fn inside each col loop to ensure initialization
    - 370            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    - 371                row[c] = fn(row[c], c, i, rows); 
    - 372                return row;
    - 373            });
    - 374        });
    - 375        return result;
    - 376    }
    - 377
    - 378    //----------------------------
    - 379    // private part
    - 380    //----------------------------
    - 381    private data: DataRow[]    = [];
    - 382    private meta: MetaStruct[] = [];
    - 383    private name: string;
    - 384
    - 385    private getMeta(col:ColumnReference):MetaStruct { 
    - 386        if (!this.meta) { this.meta = []; }
    - 387        if (!this.meta[col]) { return undefined; }
    - 388        this.meta[col].accessed = true;
    - 389        return this.meta[col]; 
    - 390    }
    - 391
    - 392    /**
    - 393     * sets `data` to the existing data set. If data has previously been set, 
    - 394     * `data` will be added to the end of the list if all `names`  match those of the 
    - 395     * existing set. 
    - 396     * @param data the data to add
    - 397     * @param names an array of names that match the columns
    - 398     * @param autoType unless set to false, the method will attempt to determine the 
    - 399     * type of data and automatically cast data points to their correct value
    - 400     */

    - 401    private setData(data:DataRow[], names:string[], autoType=true):void {
    - 402        this.meta = [];
    - 403        this.data = data;
    - 404        if (!names) {
    - 405            console.log();
    - 406        }
    - 407        names.forEach((col:string) => this.colAdd(col));
    - 408        names.forEach((col:string) => this.findTypes(col));
    - 409        this.castData();
    - 410    }
    - 411
    - 412    /**
    - 413     * Determines the type of data in `col`. An array of counts is created for all
    - 414     * encountered types, sorted by descending frequency. THe most likely type in position 0
    - 415     * of the array is returned.
    - 416     * @param col the index of the column to be typed. 
    - 417     * @return the most likely type of data in `col`.
    - 418     */

    - 419    private findTypes(col:ColumnReference):string {
    - 420        const m = this.getMeta(col);
    - 421        const types:TypeStruct[] = [];
    - 422        Object.keys(Data.type).forEach((t:string) => {
    - 423            const ts = { type: Data.type[t], count: 0 }; 
    - 424            types.push(ts);
    - 425            types[Data.type[t]] = ts;
    - 426        });
    - 427        for (let v of this.allRows(col)) {
    - 428            const t = this.findType(v);
    - 429            if (t !== null) { types[t].count++; }
    - 430        }
    - 431        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    - 432            if (a.type==='currency'&&a.count>0) { return -1; }
    - 433            if (b.type==='currency'&&b.count>0) { return 1; }
    - 434            return b.count - a.count;
    - 435        });
    - 436        m.types = types;
    - 437        return types[0].type;
    - 438    }
    - 439
    - 440    /**
    - 441     * @description determines the data type. Supported types are 
    - 442     * ```
    - 443     * 'date':    sample represents a Date, either as a Date object or a String 
    - 444     * 'number':  sample represents a number
    - 445     * 'percent': sample represents a percentage (special case of a real number)
    - 446     * 'nominal': sample represents a nominal (ordinal or categorical) value
    - 447     * ```
    - 448     * @param val the value to bve typed.
    - 449     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    - 450     */

    - 451    private findType(val:DataVal) {
    - 452        if (val && val!=='') {
    - 453            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    - 454            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    - 455
    - 456            // else: val is a string:
    - 457            const strVal = ''+val;
    - 458            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    - 459            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    - 460            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    - 461            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    - 462
    - 463            // european large number currency representation: '$dd,ddd[,ddd]'
    - 464            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    - 465                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    - 466                    return Data.type.currency; 
    - 467                }
    - 468            }
    - 469            switch (strVal.toLowerCase()) {
    - 470                case "null": break;
    - 471                case "#ref!": break;
    - 472                default: if (val.length>0) { return Data.type.nominal; }
    - 473            }
    - 474        }
    - 475        return null;
    - 476    }    
    - 477
    - 478    /**
    - 479     * A generator that provides the specified column value for each row in `Data` in sequence. 
    - 480     * @param column 
    - 481     */

    - 482    private * allRows(column:ColumnReference):Iterable {
    - 483        const c = this.colNumber(column);
    - 484        for (let r=0; r - 485            yield this.data[r][c];
    - 486        }
    - 487    }
    - 488
    - 489    /**
    - 490     * @param val the string to convert to a date
    - 491     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    - 492     * @returns a new Date object parsed from `str`.
    - 493     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    - 494     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    - 495     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    - 496     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    - 497     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    - 498     */

    - 499    private toDate(val:DataVal, limitYear=1970):Date {
    - 500        let d:Date;
    - 501        if (val instanceof Date) { d = val; }
    - 502                            else { d = new Date(val); }   
    - 503        let yr=d.getFullYear();
    - 504        if (yr < 100) { 
    - 505            yr += 1900; 
    - 506            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    - 507        }
    - 508        return d;
    - 509    }
    - 510
    - 511    /**
    - 512     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    - 513     * does not match any of the previous keywords, no casting occurs.
    - 514     * @param sample The value to cast.
    - 515     * @returns The result of the cast. 
    - 516     * @description Casts the sample to the specified data type.
    - 517     */

    - 518    private castVal(type:string, val:DataVal):DataVal {
    - 519        switch (type) {
    - 520            case Data.type.date:    if (val instanceof Date) { return val; }
    - 521                            val = this.toDate(val);
    - 522                            if (isNaN(val.getTime())) { val = null; }
    - 523                            break;
    - 524            case Data.type.percent: if (typeof val === 'string') {
    - 525                                const num = parseFloat(val);
    - 526                                val = (val).endsWith('%')? num/100 : num;
    - 527                            } 
    - 528                            if (isNaN(val)) { val = null; }
    - 529                            break;
    - 530            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    - 531             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    - 532             /* falls through */
    - 533            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    - 534                            if (isNaN(val)) { val = null; }
    - 535                            break;
    - 536            default:        val = ''+val;
    - 537        }
    - 538        return val;
    - 539     }     
    - 540}
    - - \ No newline at end of file diff --git a/docs/src/hsData/DataFilters.html b/docs/src/hsData/DataFilters.html deleted file mode 100644 index d4c08f7..0000000 --- a/docs/src/hsData/DataFilters.html +++ /dev/null @@ -1,272 +0,0 @@ - - -

    DataFilters.ts

    -
       1
    -   2/**
    -   3
    -   4* The HsData object will feature its own column meta information, as well as 
    -   5* a copy of the rows array which allows for `filter` and `sort` operations. 
    -   6* However, the column arrays will be shared with the original HsData object in order to be memory efficient.
    -   7* This means that `map` and `newColumn` operations on the new object will affect the original object or any 
    -   8* object derived via `query`.  
    -   9* @description executes a query on the data. Each row in the data is checked and those for which
    -  10* `conditions` is true are returned as a new HsData object. 
    -  11*  
    -  12* ## General Condition
    -  13* ```
    -  14* Condition = 
    -  15*    IndexCondition            -> conditions on the row index
    -  16* || RecursiveCondition        -> (set of) conditions on column values
    -  17* ```
    -  18
    -  19* ## IndexCondition
    -  20* ```
    -  21* IndexCondition =
    -  22*    rowIndex:number           -> true if row index matches
    -  23* ```
    -  24
    -  25* ## RecursiveCondition
    -  26* ```
    -  27* RecursiveCondition =
    -  28*    OrCondition               -> OR: true if any compound condition is true
    -  29* || AndCondition              -> AND: true if all compound conditions are true
    -  30
    -  31* OrCondition =                -> OR: true if
    -  32*    AndCondition[]               -> any of the AndConditions are true
    -  33* || IndexCondition[]             -> any of thr IndexConditions are true
    -  34
    -  35* AndCondition =               -> AND: true if
    -  36*    SetAndCondition              -> all SetAndConditions are true
    -  37* || TermAndCondition             -> or if all TermAndConditions are true
    -  38*
    -  39* SetAndCondition = {          -> AND: true if all sub-conditions are true
    -  40*    'or':  RecursiveCondition    -> true if any RecursiveCondition is true
    -  41* || 'and': RecursiveCondition    -> true if all RecursiveCondition are true
    -  42* || 'not': RecursiveCondition    -> true if the condition is false
    -  43*
    -  44* TermAndCondition = {         -> Terminal AND: true if all terminal sub-conditions are true
    -  45*    colDesc:colValue             -> true if colValue matches 
    -  46* || colDesc:[colValue, ...]      -> true if any of the colValues match
    -  47* || colDesc:function(value,row)  -> true if function returns true 
    -  48* }
    -  49
    -  50* colDesc = either column name or index
    -  51* ```
    -  52
    -  53* ## Practical Tips
    -  54* ```
    -  55*    {'or': [recurCond, ...]}    -> OR, same as [recurCond, ...]
    -  56* || {'or': {SetCond, ...}}      -> OR, same as [SetCond, ...]
    -  57* || {'and': [recurCond, ...]}   -> AND, true if all recurCond are true
    -  58* || {'and': {SetCond, ...}}     -> AND, same as {SetCond, ...}
    -  59* || {'not': {SetCond, ...}}     -> NAND: true if the SetCond are true
    -  60* || {'not': [recurCond, ...]}   -> NOR: true if any of the recurCond are true
    -  61* ```
    -  62*      
    -  63* # Example
    -  64
    -  65
    -  66* const colNames = ['Name', 'Value', 'Start', 'End'];
    -  67* const rows = [
    -  68*   ['Harry', '100', '3/1/14', '11/20/14'], 
    -  69*   ['Mary', '1500', '7/1/14',  '9/30/14'],
    -  70*   ['Peter', '400', '5/20/14', '4/30/15'],  
    -  71*   ['Jane', '700', '11/13/14', '8/15/15']
    -  72* ]
    -  73* const data = new hsdata.Data({colNames:colNames, rows:rows});
    -  74
    -  75* queries = [
    -  76*   ['0', undefined,                           'undefined query => pass all'],
    -  77*   ['1', [],                                  'empty OR:  []   => fail all'],
    -  78*   ['2', {},                                  'empty AND: {}   => pass all'],
    -  79*   ['3', 1,                                   '2nd row: pass row 1'],
    -  80*   ['4', [1,3],                               '2nd+4th: pass rows: 1 and 3'],
    -  81*   ['5', {Name:"Jane"},                       'Name is Jane'],
    -  82*   ['6', {1:1500},                            'Column 2 is 1500'],
    -  83*   ['7', {Name:["Peter", "Jane"]},            'Name is Peter or Jane'],
    -  84*   ['8', [{Name:"Peter"}, {Value:1500}],      'Name is Peter or Value is 1500'],
    -  85*   ['9', {or:{Name:"Peter", Value:1500}},     'OR:  same as 8:'],
    -  86*   ['A', {or:[{Name:"Peter"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],
    -  87*   ['B', {Name:"Peter", Value:400},           'Name is Peter and Value is 400'],
    -  88*   ['C', {and:{Name:"Peter", Value:400}},     'AND: {Name is Peter, Value is 400}'],
    -  89*   ['D', {and:{Name:"Peter", Value:1500}},    'AND: {Name is Peter, Value is 1500}'],
    -  90*   ['E', {and:[{Name:"Peter"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],
    -  91*   ['F', {and:[{Name:"Peter"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],
    -  92*   ['G', {not:{Name:"Peter", Value:400}},     'NAND: not {Name is Peter and Value is 400}'],
    -  93*   ['H', {not:{Name:"Peter", Value:1500}},    'NAND: not {Name is Peter and Value is 1500}'],
    -  94*   ['I', {not:[{Name:"Peter"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],
    -  95*   ['J', {Name:(v) => v.length===4},          'Name has 4 letters']
    -  96* ];
    -  97*
    -  98* m.mount(root, { 
    -  99*   view:() => m('', [
    - 100*       m('h3', 'Given the data set:'),
    - 101*       m('table#data', [
    - 102*           m('tr', colNames.map(n => m('th', n))),
    - 103*           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    - 104*       ]),
    - 105*       m('h3', 'The following queries yield:'),
    - 106*       m('table', [
    - 107*           m('tr', [m('th','#'), m('th','Query'), m('th',"Live Result, by 'Name' field")]),
    - 108*           ...queries.map(q => {
    - 109*               const result = data.filter(q[1]).getColumn('Name').join(', ');
    - 110*               return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);
    - 111*           })
    - 112*       ])
    - 113*   ])
    - 114* });
    - 115
    - 116
    - 117*   $exampleID { height: 600px; }
    - 118*   #data th { width:15%; }
    - 119*   table { 
    - 120*       font-size: 10pt;
    - 121*       margin-left: 10px;
    - 122*   }
    - 123
    - 124*      
    - 125*/

    - 126
    - 127/** */
    - 128import { Data,
    - 129         DataVal,
    - 130         DataRow
    - 131} from './Data'; 
    - 132
    - 133export type Condition = IndexCondition | RecursiveCondition;
    - 134
    - 135/** true if row index matches the number(s) */
    - 136export type IndexCondition = number;
    - 137
    - 138export type RecursiveCondition = AndCondition | OrCondition;
    - 139export type OrCondition = AndCondition[] | IndexCondition[];
    - 140export type AndCondition = SetAndCondition | TermAndCondition;
    - 141
    - 142export interface SetAndCondition {
    - 143    or?: RecursiveCondition;
    - 144    and?:RecursiveCondition;
    - 145    not?:RecursiveCondition;
    - 146};
    - 147
    - 148export interface TermAndCondition { 
    - 149    [colDesc:string]: 
    - 150        DataVal 
    - 151      | DataVal[]
    - 152      | TermConditionFunction
    - 153    ;
    - 154};
    - 155
    - 156export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean;
    - 157
    - 158
    - 159function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { 
    - 160    const col = colNumber(name);
    - 161    const valIsFunction = (typeof val === 'function');
    - 162    const valIsArray = ((typeof val === 'object') && (val.length!==undefined));
    - 163    if (isNaN(col)) { 
    - 164        console.log(`column name '${name}' cannot be resolved in terminal condition ${name}=${val}`);
    - 165        console.log(row);
    - 166        return false; // -> this condition is not met;
    - 167    } else if (valIsFunction) { 
    - 168        // query true if function evaluates to true
    - 169        return val(row[col], row);
    - 170    } else if (valIsArray) {
    - 171        // query true if empty array, or at least one c true
    - 172        return (val.length === 0) || val.some((v:any) => row[col] === v); 
    - 173    } else { // object: all conditions have to be met, unless specified as or
    - 174        return (row[col] === val); 
    - 175    }
    - 176}
    - 177
    - 178/**
    - 179 * applies `condition` to a row of data and returns `true` if the row passes.
    - 180 * @param condition the complex condition to test against
    - 181 * @param r the row index in the data set
    - 182 * @param row the row values 
    - 183 * @param and 
    - 184 */

    - 185function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and=true):boolean { 
    - 186    let orResult = false;
    - 187    let andResult= true;          
    - 188    // undefined condition is TRUE
    - 189    if (condition===undefined) { return true; }
    - 190    
    - 191    // Simple Index Condition on row index:
    - 192    else if (typeof condition === 'number') { return (condition === r); }
    - 193
    - 194    // Recursive Condition - OR: [...], AND {...}: 
    - 195    else if (typeof condition === 'object') {
    - 196        // array -> or condition on a list of row indices or compound conditions
    - 197        const mc = condition;
    - 198
    - 199        // OR condition: [...] 
    - 200        if (mc.length !== undefined) {            
    - 201            return (mc.length === 0)? 
    - 202                // empty OR is false:
    - 203                false : 
    - 204                // else: OR is true if any sub-condition is met
    - 205                mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, false));
    - 206        } 
    - 207        // AND condition: {...}
    - 208        else { 
    - 209            for (const name in condition) {
    - 210                let conditionMet = and; // initialize with false for OR, and true for AND conjunction
    - 211                const setCond = condition;
    - 212                
    - 213                // resolve SetConditions:
    - 214                switch (name) {
    - 215                    case 'or':  conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break;
    - 216                    case 'and': conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break;
    - 217                    case 'not': conditionMet = !resolveCondition(setCond.not, row, r, colNumber, true); break;
    - 218                    default:    conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); 
    - 219                }
    - 220                if (conditionMet) { orResult  = true;  if(!and) { break; }} // OR conjunction: exit for name loop if condition met
    - 221                             else { andResult = false; if(and)  { break; }} // AND conjunction: exit for name loop if condition not met
    - 222            }
    - 223        }    
    - 224    } else {
    - 225        console.error(`unrecognized condition: ${JSON.stringify(condition)}`);
    - 226        return false;
    - 227    }
    - 228    return and? andResult : orResult;
    - 229}
    - 230
    - 231export type ReduceFn = (keep:boolean, row:DataRow, i:number) => void;
    - 232
    - 233export function filter(data:Data, cond:Condition, reduceFn?:string|ReduceFn):Data {
    - 234    const noop = () => 0;
    - 235    const colNumber = (name:string):number => data.colNumber(name);
    - 236    let fn:ReduceFn;
    - 237    switch (reduceFn) {
    - 238        default: fn = (typeof reduceFn === 'function')? reduceFn : noop;
    - 239    } 
    - 240    try {
    - 241        return new Data({
    - 242            name:     data.getName(),
    - 243            colNames: data.colNames(), 
    - 244            rows:data.getData().filter((row:DataRow, i:number) => {
    - 245                const keep = resolveCondition(cond, row, i, colNumber);
    - 246                if (fn) { fn(keep, row, i); }
    - 247                return keep;
    - 248            })
    - 249        });
    - 250    } catch(err) {
    - 251        console.log(err);
    - 252        console.log(err.stack);
    - 253    }
    - 254}
    - 255
    - - \ No newline at end of file diff --git a/docs/src/hsData/DataTypes.html b/docs/src/hsData/DataTypes.html deleted file mode 100644 index 9e2f184..0000000 --- a/docs/src/hsData/DataTypes.html +++ /dev/null @@ -1,48 +0,0 @@ - - -

    DataTypes.ts

    -
       1/** defines a [min-max] range */
    -   2export type NumRange = [number, number];
    -   3
    -   4/** defines a numeric domain that includes all values of a column */
    -   5export type NumDomain = [number, number];
    -   6
    -   7/** defines a Date domain that includes all values of a column */
    -   8export type DateDomain = [Date, Date];
    -   9
    -  10/** defines a categorical domain that includes all values of a column */
    -  11export type NameDomain = string[];
    -  12
    -  13/** defines a generic domain that can be any of the typed domains. */
    -  14export type Domain = NumDomain | DateDomain | NameDomain;
    -  15
    -  16/** defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    -  17export type ColSpecifier = number|string;
    -  18
    -  19/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    -  20export type DataVal = number|string|Date;
    -  21
    -  22/** a single row of column values */
    -  23export type DataRow = DataVal[];
    -  24
    -  25/** a JSON format data set */
    -  26export interface DataSet {
    -  27    rows:DataRow[];
    -  28    names:ColSpecifier[];   
    -  29}
    -  30
    -  31
    - - \ No newline at end of file diff --git a/docs/src/hsData/index.html b/docs/src/hsData/index.html deleted file mode 100644 index f59d1fa..0000000 --- a/docs/src/hsData/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - -

    index.ts

    -
       1export { NumRange,
    -   2         NumDomain,
    -   3         DateDomain,
    -   4         NameDomain,
    -   5         Domain,
    -   6         ColumnReference,
    -   7         DataVal,
    -   8         DataRow,
    -   9         DataSet
    -  10        }       from './Data';
    -  11
    -  12export { Data } from './Data';
    -  13export { Condition} from './DataFilters';
    -  14
    -  15
    - - \ No newline at end of file diff --git a/docs/src/hsData/overview.html b/docs/src/hsData/overview.html deleted file mode 100644 index 25c079d..0000000 --- a/docs/src/hsData/overview.html +++ /dev/null @@ -1,40 +0,0 @@ - - -

    overview.ts

    -
       1/**
    -   2 * # hsData
    -   3 * 
    -   4 * Helpful Scripts data management functions that are framework independent. 
    -   5 * 
    -   6 * ## Data Types
    -   7 * -   {@link Data.NumRange NumRange} defines a single [min, max] numeric range.
    -   8 * -   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column
    -   9 * -   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column
    -  10 * -   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column
    -  11 * -   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains.
    -  12 * -   {@link Data.ColSpecifier ColSpecifier} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array 
    -  13 * -   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array
    -  14 * -   {@link Data.DataRow DataRow} a single row of column values
    -  15 * 
    -  16 * ## Data Class
    -  17 * -   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions
    -  18 */

    -  19
    -  20 /** */
    -  21
    -  22 
    -  23
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/DocSets.html b/docs/src/hsDoc/DocSets.html deleted file mode 100644 index 413b078..0000000 --- a/docs/src/hsDoc/DocSets.html +++ /dev/null @@ -1,168 +0,0 @@ - - -

    DocSets.ts

    -
       1/**
    -   2 * DocSets.ts. Loads the doc.json files to process and display as documentation.
    -   3 * Processing occurs in these steps:
    -   4 * 1. Load the index.json file that contains a list of doc.json files to load, one for each library to show
    -   5 * 2. Load each doc.json file, which describes a library
    -   6 * 3. Call DocSets.add to add the library name to the registry and create an index of entries for the library
    -   7 */

    -   8
    -   9/** */
    -  10import { m }    from 'hslayout';
    -  11
    -  12/**
    -  13 * the default location for the index .json files, relative to the web page:
    -  14 * `'./data/index.json'`
    -  15 */

    -  16const FILE:string = './data/index.json';
    -  17
    -  18
    -  19/**
    -  20 * DocSets object. Keeps a list of registered docsets and 
    -  21 * provides access to elements of each docset.
    -  22 */

    -  23export class DocSets { 
    -  24    /** Contains references to the docsets and all elements per docset, accessible per ID. */
    -  25    private static gList = <{set:string[], index:{}}>{set:[], index:{}};
    -  26    private static gTitle: string;
    -  27
    -  28    /** Adds the docset in `content` to the `gList` */
    -  29    public static add(content:any) {
    -  30        const lib = content.name;
    -  31        DocSets.gList.set.push(lib);
    -  32        DocSets.gList.set.sort();
    -  33        DocSets.gList.index[lib] = {};
    -  34        recursiveIndex(content, DocSets.gList.index[lib], lib);
    -  35    }
    -  36
    -  37    /**
    -  38     * loads an index set and the docsets it contains from driectory `dir`.
    -  39     * @param file the optional directory to read from. If unspecified, 
    -  40     * read from the index file specified by {@link DocSets.FILE `FILE`}.
    -  41     */

    -  42    public static loadList(file?:string):Promise {
    -  43        file = file || FILE;   
    -  44//console.log('requesting docSet ' + file);
    -  45        return DocSets.loadIndexSet(file); 
    -  46    }
    -  47
    -  48    /**
    -  49     * returns the specified documentation element.
    -  50     * When called without parameters, a string[] of available docSets is returned.
    -  51     * When called with only `lib` specified, the corresponding docSet overview is returned.
    -  52     * @param lib specifies the docset to scan. 
    -  53     * @param id specifies the element within the docSet, either by its id number, or by its path
    -  54     */

    -  55    public static get(lib?:string, id:number|string=0) { 
    -  56        if (lib) {
    -  57            if (DocSets.gList.index[lib]) { 
    -  58                return DocSets.gList.index[lib][id+'']; 
    -  59            } else {
    -  60                return DocSets.gList.set; 
    -  61            }
    -  62        } else {
    -  63            return DocSets.gList.set; 
    -  64        }
    -  65    }
    -  66
    -  67    /**
    -  68     * Loads `index.json` from the directory specified in `dir`.
    -  69     * Each entry in the index is interpreted as a docset and loaded.
    -  70     * @param dir the directory to read from
    -  71     * @param file the index file to read
    -  72     */

    -  73    private static loadIndexSet(file:string):Promise { 
    -  74        return m.request({ method: "GET", url: file })
    -  75            .then((result:any) =>  {
    -  76//console.log('received index');
    -  77                DocSets.gTitle = result.title;
    -  78                let i = file.lastIndexOf('/');
    -  79                const dir = file.substring(0,i+1);
    -  80                return Promise.all(result.docs.map((f:string) => loadDocSet(dir, f)));            
    -  81            })
    -  82            .catch(console.log);
    -  83    }
    -  84
    -  85
    -  86    public static title() { return DocSets.gTitle; }
    -  87};
    -  88
    -  89/**
    -  90 * Loads a docset specified by file from the directory `dir`. 
    -  91 * Once received, the docset is registered in `modules` via the `add` method.
    -  92 * @param dir the directory to read from
    -  93 * @param file the `json` file to load as docset
    -  94 */

    -  95function loadDocSet(dir:string, file:string):Promise {
    -  96    return m.request({ method: "GET", url: dir+file })
    -  97        .then((r:any) => {
    -  98// console.log('received ' + dir+file);
    -  99            DocSets.add(r);
    - 100        })
    - 101        .catch(console.log);
    - 102}
    - 103
    - 104/**
    - 105 * recurses through the docset and registers all `children` entries of an entry by id,
    - 106 * starting with the root entry.
    - 107 * @param content the docset object literal to traverse
    - 108 * @param index the index in which to register the entries
    - 109 * @param lib the docset name, used for name validation
    - 110 */

    - 111function recursiveIndex(content:any, index:any, lib:string, path='') {
    - 112    function getNewPath(content:any) {
    - 113        content.name = content.name.replace(/["'](.+)["']|(.+)/g, "$1$2");  // remove quotes 
    - 114        const elName  = content.name.match(/([^\/]+)$/)[1];         // name = part after last /
    - 115        content.name = elName;
    - 116        return content.fullPath = (path==='')? elName : `${path}.${elName}`;
    - 117    }
    - 118
    - 119    function markIfModule(content:any) {
    - 120        if (content.comment && content.comment.tags) {
    - 121            content.comment.tags.forEach((tag:any) => {
    - 122                if (tag.tag === 'module') {
    - 123                    content.innerModule = tag.text.trim();
    - 124                }
    - 125            });
    - 126        }
    - 127    }
    - 128    content.lib = lib;
    - 129    if (typeof content === 'object' && content.name) {
    - 130        const newPath = getNewPath(content);
    - 131
    - 132        markIfModule(content);
    - 133
    - 134        index[content.id+''] = content;
    - 135        if (newPath.length>0) { index[newPath] = content; }
    - 136
    - 137        if (content.children) {
    - 138            content.children.map((c:any) => recursiveIndex(c, index, lib, newPath));
    - 139        }
    - 140        if (content.signatures) {
    - 141            content.signatures.map((c:any) => recursiveIndex(c, index, lib, newPath));
    - 142        }
    - 143        if (content.parameters) {
    - 144            content.parameters.map((c:any) => recursiveIndex(c, index, lib, newPath));
    - 145        }
    - 146        if (content.type && content.type.declaration && content.type.declaration.children) {
    - 147            content.type.declaration.children.map((c:any) => recursiveIndex(c, index, lib, newPath));
    - 148        }
    - 149    }
    - 150}
    - 151
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/Site.html b/docs/src/hsDoc/Site.html deleted file mode 100644 index 1a6fd6f..0000000 --- a/docs/src/hsDoc/Site.html +++ /dev/null @@ -1,78 +0,0 @@ - - -

    Site.ts

    -
       1/**
    -   2 * Site documentation
    -   3 */

    -   4
    -   5/** */
    -   6import * as hslayout  from 'hslayout';
    -   7import * as header  from './view/DocsMenu';
    -   8import * as left    from './view/LeftNav';
    -   9import * as main    from './view/MainDetail';
    -  10
    -  11
    -  12const TitleHeight   = '30px'; 
    -  13const FooterHeight  = '10px';  
    -  14const LeftNavWidth  = '200px';
    -  15const SiteName      = 'HSDocs'; 
    -  16 
    -  17const myConfig = {
    -  18    Layout: { // whole page
    -  19        rows:  [TitleHeight, "fill", FooterHeight],
    -  20        css: '.hs-site',
    -  21        content: [{
    -  22            Layout:{ // top row
    -  23                columns: [LeftNavWidth, "fill"],
    -  24                css: '.hs-site-header',
    -  25                content: [
    -  26                    { Layout:    { 
    -  27                        css: '.hs-site-title',
    -  28                        content: SiteName, 
    -  29                        href:'/api/' 
    -  30                    }},
    -  31                    { DocsMenu:    { docSet:"./data/index.json"}}
    -  32                ]                
    -  33            }},{
    -  34            Layout:{ // main part
    -  35                columns: [LeftNavWidth, "fill"], 
    -  36                content: [
    -  37                    { LeftNav:    {}},
    -  38                    { MainDetail: {}}
    -  39                ]                
    -  40            }},
    -  41            { Layout: { // footer
    -  42                css: '.hs-site-footer',
    -  43                content: '(c) Helpful Scripts'
    -  44            }}
    -  45        ] 
    -  46    },
    -  47    route: {
    -  48        default: '/api',
    -  49        paths: [
    -  50            '/api',             // defines `http://localhost/#!/api/
    -  51            '/api/:lib',        // defines `http://localhost/#!/api/:hsLib
    -  52            '/api/:lib/:field'  // defines `http://localhost/#!/api/:hsLib/:id        
    -  53        ]
    -  54    }
    -  55}; 
    -  56
    -  57
    -  58export function init() {
    -  59    new hslayout.HsConfig([hslayout, header, left, main]).attachNodeTree(myConfig, document.body);
    -  60}
    -  61
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/index.html b/docs/src/hsDoc/index.html deleted file mode 100644 index 0b2e58d..0000000 --- a/docs/src/hsDoc/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - -

    index.ts

    -
       1/**
    -   2 * Progam entry point. Initiates loading the docsets and setting up a router structure
    -   3 */

    -   4
    -   5/** */
    -   6import { init } from './Site';
    -   7
    -   8init();
    -   9
    -  10
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/markdown.html b/docs/src/hsDoc/markdown.html deleted file mode 100644 index 0de823c..0000000 --- a/docs/src/hsDoc/markdown.html +++ /dev/null @@ -1,100 +0,0 @@ - - -

    markdown.ts

    -
       1const showdown  = require('showdown');
    -   2
    -   3/**
    -   4 * process a markdown comment string and returns the equivalent html syntax. 
    -   5 * @param text the comment to markdown
    -   6 * @param short if true, only the first paragraph is returned
    -   7 * @return the marked down comment
    -   8 */

    -   9export function markDown(text:string, short:boolean=false, currentRoute:string):string {
    -  10    const converter = new showdown.Converter({
    -  11        tables:                 true,   // enables |...| style tables; requires 2nd |---| line
    -  12        ghCompatibleHeaderId:   true,   // github-style dash-separated header IDs
    -  13        smartIndentationFix:    true,   // fixes ES6 template indentations
    -  14        takslists:              true,   // enable - [ ] task; doesn't seem to work.
    -  15        strikethrough:          true    // enables ~~text~~
    -  16    });
    -  17    let result = (!text)? '' : converter.makeHtml(text);
    -  18    if (short) {
    -  19        const i = result.indexOf('

    ');
    -  20        if (i>0) { result = result.substring(0, i); }
    -  21    }
    -  22    result = substituteLinks(result, currentRoute);
    -  23    return result;
    -  24}
    -  25
    -  26/**
    -  27 * replaces link statements in the comment with hyperlink references.
    -  28 * The format of a link statement is "{@link *docset*:*path* linked text}", where
    -  29 * - *docset* is the name of the docset
    -  30 * - *path* is the structural path of a component with steps on the path separated by a period,
    -  31 *    following the pattern *module*.*entity*.*member* with
    -  32 *     - *module* = the name of the module file
    -  33 *     - *entity* = [*class* | *function* | *variable*]
    -  34 *     - *member* = [*method* | *variable*]
    -  35 * - if *path* is omittied, or is `overview`, the library overview will be shown.
    -  36 *   
    -  37 * Examples: 
    -  38 * - '{@link hsDoc: Doc Overview}' -> {@link hsDoc: Doc Overview}
    -  39 * - '{@link hsDoc:DocSets.DocSets.add the `adds` function}' --> {@link hsDoc:DocSets.DocSets.add the `adds` function}
    -  40 * 
    -  41 * @param comment the comment in which to replace the links
    -  42 * @return the comment with substituted links 
    -  43 */

    -  44function substituteLinks(comment:string, currentRoute:string):string {
    -  45    function deconstructRoute(route:string) {
    -  46        let lib, mod;
    -  47        route.replace(/\/([^\/.]*)\/([^\/\s]*$)/gi, (match, ...args) => {
    -  48            lib = args[0];
    -  49            mod = args[1];
    -  50            return '';
    -  51        }); 
    -  52        return [lib, mod];
    -  53    }
    -  54
    -  55    function getLibMod(path:string) {
    -  56        let lib, mod, frag; 
    -  57        if (path.indexOf(':')>0) {
    -  58            [lib, mod] = path.split(':');
    -  59        } else  {
    -  60            lib = defLib;
    -  61            mod = path;
    -  62        }
    -  63        if (mod.indexOf('#')>0) {
    -  64            [mod, frag] = mod.split('#');
    -  65        }
    -  66        return [lib, mod, frag];       
    -  67    }
    -  68
    -  69    let [defLib] = deconstructRoute(currentRoute);
    -  70
    -  71    // regex: requires whitespace before {@link; otherwise treated as quoted '{@link...}'
    -  72    comment = comment.replace(/\s{@link ([\S]*)\s*(.+)}/gi, (match, ...args) => {
    -  73        const path = args[0];
    -  74        const text = args[1];
    -  75        let [lib, module] = getLibMod(path);        
    -  76        return (module === '' || module === '0' || module === 'overview')?
    -  77                ` ${text}
    ` :
    -  78                ` ${text}`;
    -  79    });
    -  80    return comment;
    -  81
    -  82}
    -  83
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/overview.html b/docs/src/hsDoc/overview.html deleted file mode 100644 index 3a7a95f..0000000 --- a/docs/src/hsDoc/overview.html +++ /dev/null @@ -1,161 +0,0 @@ - - -

    overview.ts

    -
       1/**
    -   2# hsDoc
    -   3___
    -   4hsDoc.js is a code documentation viewer for [Typescript](https://www.typescriptlang.org) projects.
    -   5It renders JSON documentation files as created by [typedoc](http://typedoc.org).
    -   6
    -   7## Creating the Documentation DocSet
    -   8Follow the instruction for `typedoc` in commenting the code and set the `json` option to create a 
    -   9json file containing the documentation. See the Configuration section below for details.
    -  10
    -  11In addition to the documented source files, `hsDoc` recognizes a special **`overview.ts`** file 
    -  12that will be displayed as a project overview. 
    -  13For this to work, `typedoc` requires the file to have two separate comment entries.
    -  14If the second comment is missing, `typedoc` will not generate a comment in the DocSet.
    -  15
    -  16DocSets are shown as menu tabs across the top of the window. To include a DocSet in the menu, ensure that the 
    -  17corresponding documentation `.json` file is copied into the `data` folder inside the `hsDoc` staging location 
    -  18for the http server. Then edit the `index.json` file to include the documentation file name in the "docs" section. 
    -  19
    -  20### Modules
    -  21Each source file is considered to be a `module`. Modules are shown in the left-hand overview panel of the main `hsDoc` window.
    -  22Alternatively, a `@module` statement in the summary comment at the top of a file will create, or add to, a module of the specified name.
    -  23This encourages to separate code into files without cluttering the overview.
    -  24
    -  25### Linking across the docsets
    -  26Links to items across the docsets can be placed via a link directive: 
    -  27- "{@link [*docset*:]*module*.*item* linked text}", 
    -  28where
    -  29 - *docset* optional; the name of the docset. If omitted, a link within the current docSet will be created
    -  30 - *module* is name of the module to link to; 
    -  31   if *module* is `overview`, or unspecified, the link will point to the docset overview page.
    -  32 - *item* is the name, or period-separated path, of the item within the module. 
    -  33 - *linked text* is displayed with a link to path within module
    -  34
    -  35Examples:
    -  36- '{@link overview Overview of hsDoc docSet}' -> {@link overview Overview of hsDoc docSet}
    -  37- '{@link hsDoc: Overview of hsDoc docSet}' -> {@link hsDoc: Overview of hsDoc docSet}
    -  38- '{@link hsDoc:DocSets.DocSets.add the `adds` function}' --> {@link hsDoc:DocSets.DocSets.add the `adds` function}
    -  39- '{@link DocSets.DocSets.add the `adds` function}' --> {@link DocSets.DocSets.add the `adds` function}
    -  40
    -  41
    -  42### Mithril Code Examples
    -  43 * `hsDoc` supports creating inline code examples in comment sections as explained 
    -  44 * in the {@link hsDoc:MainExample MainExample overview}.
    -  45 * 
    -  46 * 
    -  47 * let tl = [10, 10];
    -  48 * 
    -  49 * const rnd = () => Math.floor(80*Math.random());
    -  50 * 
    -  51 * function click() { tl = tl.map(i => rnd()); }
    -  52 * 
    -  53 * m.mount(root, {
    -  54 *     view: () => m('.myBlock', {
    -  55 *         onclick:click, 
    -  56 *         style:`top:${tl[0]}%; left:${tl[1]}%;`
    -  57 *     }, m('', 'click me'))})
    -  58 * 
    -  59 * 
    -  60 * .myBlock {
    -  61 *     text-align:center;
    -  62 *     color: white;
    -  63 *     background-color: red;
    -  64 *     position:relative;
    -  65 *     width:  20%;
    -  66 *     height: 30%;
    -  67 * }
    -  68 * .myBlock div {
    -  69 *     padding-top: 40%;
    -  70 * }
    -  71 * 
    -  72 * 

    -  73
    -  74## Configuring typedoc
    -  75As an example, we use grunt-typedoc with the following configuration:
    -  76
    -  77### tsconfig.json:
    -  78A `tsconfig.json` file seems to be required by typedoc. The file can be empty
    -  79
    -  80### Gruntfile:
    -  81module.exports = function(grunt) {
    -  82    ...
    -  83    typedoc: {
    -  84        code: {
    -  85            options: {
    -  86                tsconfig: 'typedoc.json',
    -  87                json:   './docs/hsDocs.json',
    -  88                out:    './docs',
    -  89                mode:   'modules',
    -  90                name:   'hsDoc'
    -  91            }
    -  92            src: ['src/*.ts', '!src/*.spec.ts']
    -  93        }
    -  94    },
    -  95
    -  96   ...
    -  97   grunt.loadNpmTasks('grunt-typedoc');
    -  98   ...
    -  99   grunt.registerTask('doc', ['typedoc']);
    - 100}
    - 101

    - 102
    - 103## Setting up the web app
    - 1041. Create an **`index.html`** in the directory to serve from (web-app directory): 
    - 105
    - 106
    - 107
    - 108
    - 109
    - 110

    - 111
    - 1122. Copy **`hsDocs.js`** and **`styles.css`** into the same directory
    - 113
    - 1143. Create a subdirectory **`data`** and copy the docsets into it, including **`hsDocs.json`**
    - 115
    - 1164. Create a list of docsets to render in a new file **`index.json`** inside **`data`**:
    - 117
    - 118{
    - 119    "docs": [
    - 120        "hsDocs.json",
    - 121        ...
    - 122    ],
    - 123    "title": "HS Libraries"   // will be displayed at the top left corner
    - 124}

    - 125
    - 1265. Point a browser to the web-app directory
    - 127
    - 128## Dependencies
    - 129### For creating the docsets:
    - 130- [typedoc](http://typedoc.org)
    - 131
    - 132### For rendering the docsets:
    - 133- [Mithril](https://mithril.js.org)
    - 134- [showdown](https://github.com/showdownjs/showdown)
    - 135- [hsLayout]
    - 136- [webpack]
    - 137
    - 138## Structural Code Overview
    - 139The main entry point for the web-app is index.ts, which initiates loading the docsets 
    - 140and sets up a mithril {@link hsDoc:Router router} 
    - 141
    - 142*/

    - 143
    - 144/** */
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/view/DocsMenu.html b/docs/src/hsDoc/view/DocsMenu.html deleted file mode 100644 index cdd20ab..0000000 --- a/docs/src/hsDoc/view/DocsMenu.html +++ /dev/null @@ -1,56 +0,0 @@ - - -

    view/DocsMenu.ts

    -
       1import { m, Vnode, Layout }  from 'hslayout';
    -   2import { DocSets }              from '../DocSets'; 
    -   3import { Menu, SelectorDesc }       from 'hswidget';
    -   4
    -   5/**
    -   6 * Creates the title menu for selecting between the different docsets.
    -   7 * Instantiate the DocsMenu via a standard `mithril` call:```
    -   8 *    m(DocsMenu, { docSet:})
    -   9 * ```
    -  10 * DocsMenu performs the following actions:
    -  11 * - for the first call of the view lifecycle hook, the available docSets are loaded.
    -  12 *   DocsMenu searches for an index `json` file at the location specified in the 
    -  13 *   `docSet` field of the `node.attrs` parameter. If none is specified, the 
    -  14 *   default is used as specified in the {@link hsDoc:DocSets.FILE DocSets FILE} setting.
    -  15 * - DocsMenu retrieves all available docSets via {@link hsDoc:DocSets.DocSets.get DocSets.get}.
    -  16 * - DocsMenu creates a `SelectorDesc` structure with a {@link hsWidget:hsSelector.SelectorDesc.changed `changed`} callback that initiates a route change 
    -  17 *   to the selected docSet
    -  18 */

    -  19export class DocsMenu extends Layout {
    -  20    docSet = '';
    -  21
    -  22    private getDesc(attrs:any):SelectorDesc { 
    -  23        if (this.docSet !== attrs.docSet) {
    -  24            this.docSet = attrs.docSet;
    -  25            DocSets.loadList(attrs.docSet);
    -  26        }
    -  27        const items = DocSets.get(); 
    -  28        return {
    -  29            items: items.map((c:string) => c),
    -  30            defaultItem: (attrs.route && attrs.route.lib)? attrs.route.lib : items[0],
    -  31            changed: (item:string) => m.route.set('/api/:lib/0', {lib:item})
    -  32        };
    -  33    }
    -  34
    -  35    getComponents(node:Vnode):Vnode {
    -  36        const desc:SelectorDesc = this.getDesc(node.attrs);
    -  37        return m(Menu, {desc: desc});
    -  38    }
    -  39}
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/view/LeftNav.html b/docs/src/hsDoc/view/LeftNav.html deleted file mode 100644 index ed4f037..0000000 --- a/docs/src/hsDoc/view/LeftNav.html +++ /dev/null @@ -1,171 +0,0 @@ - - -

    view/LeftNav.ts

    -
       1/**
    -   2 * LeftNav: Responsible for constructing the left-hand navigation pane. 
    -   3 */

    -   4
    -   5/** */
    -   6import { m, Vnode}  from 'hslayout';
    -   7import { Layout }from 'hslayout';
    -   8import { Collapsible }from 'hswidget';
    -   9import { DocSets } from '../DocSets'; 
    -  10import { libLink } from './Parts'; 
    -  11
    -  12
    -  13/**
    -  14 * Constructs the left-hand navigation pane
    -  15 */

    -  16export class LeftNav extends Layout {
    -  17    getComponents(node: Vnode): Vnode {
    -  18        let lib:string;
    -  19        let field:string;
    -  20        if (node.attrs && node.attrs.route) {
    -  21            lib = node.attrs.route.lib;
    -  22            field = node.attrs.route.field;
    -  23        }
    -  24        const docSet = DocSets.get(lib, 0) || {name:'unknown', id:0};
    -  25        return m('.hs-left', [m('.hs-left-nav', navList(docSet, field))]);
    -  26    } 
    -  27}
    -  28
    -  29/** creates the list if modules (`*.ts` files) */
    -  30function navList(docSet:any, field:string):Vnode[] {
    -  31    /** */
    -  32    function collectModules(docSet:any) {
    -  33        const modulesByName = {};
    -  34        docSet.modules = [];
    -  35        if (docSet.children) {
    -  36            docSet.children.forEach((c:any) => {
    -  37                // don't show modules from other projects (isExternal flag) or modules on the ignore list
    -  38                if (!(c.flags && c.flags.isExternal) && !ignoreModules[c.name]) {
    -  39                    const name = c.innerModule? c.innerModule : c.name;
    -  40                    let module = modulesByName[name];
    -  41                    if (!module) {  // new module
    -  42                        docSet.modules.push(module = modulesByName[name] = { 
    -  43                            name: name,
    -  44                            lib: docSet.lib,
    -  45                            fullPath: docSet.fullPath + '.'+ name,
    -  46                            groups:[]
    -  47                        });
    -  48                    }
    -  49                    // get existing module groups
    -  50                    const groups = {};
    -  51                    module.groups.forEach((g:any) => groups[g.title] = g); 
    -  52                    // for each group in child:
    -  53                    if (c.groups) { c.groups.forEach((g:any) => {
    -  54                        let group = groups[g.title]; // get existing 
    -  55                        if (!group) {                 //  else create new
    -  56                            group = groups[g.title] = {
    -  57                                children:[],
    -  58                                kind: g.kind,
    -  59                                title: g.title
    -  60                            };
    -  61                        module.groups.push(group);
    -  62                        }
    -  63                        group.children = group.children.concat(g.children);
    -  64                    });}
    -  65                }
    -  66            });
    -  67        }
    -  68    }
    -  69    /** 
    -  70     * processes a module, i.e. a `.ts` file.
    -  71     */

    -  72    function externalModule(mdl:any) {
    -  73        let selected = false;
    -  74        if (field===''+mdl.id || field.indexOf(mdl.fullPath) === 0) { selected=true; }
    -  75
    -  76        return m(Collapsible, {css:`.hs-left-nav-module`, preArrow: true, isExpanded:selected, components:[
    -  77            m(`${selected?'.hs-left-nav-selected':''}`, libLink(`a.hs-left-nav-module-name `, mdl.lib, mdl.fullPath, mdl.name)),
    -  78            !mdl.groups? undefined : mdl.groups.map((g:any) => entries(g, mdl, field))
    -  79        ]});
    -  80    }
    -  81
    -  82    if (docSet.kind === 0) { // External DocSets
    -  83        collectModules(docSet);
    -  84//        const modules = docSet.children? docSet.children.map(externalModule) : ['no children'];
    -  85        const modules = docSet.modules.map(externalModule);
    -  86        modules.unshift(m('.hs-left-nav-header', 'Modules'));
    -  87        return [m('.hs-left-nav-content', modules)];
    -  88    }
    -  89}
    -  90
    -  91/**
    -  92 * modules to ignore in the list
    -  93 */

    -  94const ignoreModules = {
    -  95    overview:   true,   // the project overview.ts file
    -  96    index:      true    // the index.ts file
    -  97};
    -  98
    -  99//const expanded: {string?:boolean} = {};
    - 100
    - 101/**
    - 102 * processes a group of entries, e.g. Variables, Functions, or Classes.
    - 103 * @param group the group structure within the docset
    - 104 * @param mdl the entire module docset
    - 105 * @param field the field ID to be displayed on the main panel
    - 106 */

    - 107function entries(group:any, mdl:any, field:string) {
    - 108    function moduleGet(c:any) {
    - 109        return DocSets.get(mdl.lib, c);
    - 110    }
    - 111    /**
    - 112     * processes one entry within a group, e.g. one variable, function, or class.
    - 113     */

    - 114    function entry(mod:any) { 
    - 115        const selected = (field===''+mod.id || field===mod.fullPath)? '.hs-left-nav-selected' : '';
    - 116        const exported = (mod.flags && mod.flags.isExported);
    - 117        const statik   = (mod.flags && mod.flags.isStatic);
    - 118        const css = `a.hs-left-nav-entry ${selected} ${exported?'.hs-left-nav-exported' : ''}`;
    - 119        return (!exported && group.title==='Variables')? '' :   // ignore local module variables
    - 120            m('', [
    - 121                statik? 'static': '',
    - 122                libLink(css, mod.lib, mod.fullPath, mod.name)
    - 123            ]);
    - 124    }
    - 125
    - 126    function empty(mod:any) { return mod !== ''; }
    - 127
    - 128    let grp = [];
    - 129    if (group && group.children) {
    - 130        grp = group.children
    - 131            .map(moduleGet)         // replace id reference by module
    - 132            .sort(exportAscending)  // sort: exported first, then alphabetically
    - 133            .map(entry)             // replace module by vnode structure
    - 134            .filter(empty);         // filter empty elements
    - 135        if (grp.length > 0) { // add an entries header if there are elements
    - 136            grp.unshift(m('.hs-left-nav-header', group.title));
    - 137        }
    - 138    }
    - 139    return (grp.length > 1)? m(`.hs-left-nav-entries`, grp) : '';
    - 140}
    - 141
    - 142/**
    - 143 * sorting function: sort first by exported status, then alphabetically.
    - 144 */

    - 145function exportAscending(a:any, b:any):boolean|number {
    - 146    if (a.flags && b.flags) {
    - 147        if (a.flags.isExported && b.flags.isExported) { return a.name > b.name; }
    - 148        else if (a.flags.isExported) { return -1; }
    - 149        else if (b.flags.isExported) { return 1; }
    - 150        else { return a.name > b.name; }
    - 151    } else { return a.name > b.name; }
    - 152}
    - 153
    - 154
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/view/MainComment.html b/docs/src/hsDoc/view/MainComment.html deleted file mode 100644 index 8aaf21b..0000000 --- a/docs/src/hsDoc/view/MainComment.html +++ /dev/null @@ -1,171 +0,0 @@ - - -

    view/MainComment.ts

    -
       1/**
    -   2 * Processing of comments.
    -   3 */

    -   4
    -   5/** */
    -   6import { m, Vnode } from 'hslayout';
    -   7import { markDown } from '../markdown';
    -   8import { example }  from './MainExample';
    -   9
    -  10/**
    -  11 * Main comment processing. The result appears directly below the title in the main panel.
    -  12 * Function parameters are not reported in short form here since it is assumed they will be listed 
    -  13 * individually below the main comment
    -  14 * @param mdl the module to scan for comments
    -  15 * @return a vnode representing the comment entries
    -  16 */

    -  17export function commentLong(mdl:any):Vnode { 
    -  18    let content:any[] = [];
    -  19    if (mdl.comment) {
    -  20        content.push(textOrShortTextOrDescription(mdl.comment, false));
    -  21        content.push(returns(mdl.comment, false));
    -  22        content.push(commentRemainder(mdl.comment));
    -  23    }
    -  24    return m('.hs-item-comment', content);
    -  25}
    -  26
    -  27/**
    -  28 * Shortended comment processing. This form is used to report on subitems below the main panel item.
    -  29 * If `short` is true, only the first paragraph of the main comment will be returned. Otherwise, 
    -  30 * this function creates a full comment including an inline list of parameters and the return value
    -  31 * @param mdl the module to scan for comments
    -  32 * @param short if true, only the first paragraph of the main comment is processed.
    -  33 * @return a vnode representing the comment entries
    -  34 */

    -  35export function comment(mdl:any, short=false):Vnode {
    -  36    let content:any[] = [];
    -  37    if (mdl.comment) {
    -  38        content.push(textOrShortTextOrDescription(mdl.comment, short));
    -  39        if (!short) {
    -  40            content.push(otherCommentTags(mdl.comment));
    -  41            if (mdl.parameters) {
    -  42                content = content.concat(mainCommentParams(mdl.parameters));
    -  43            }
    -  44        }
    -  45        content.push(returns(mdl.comment, false));
    -  46        content.push(commentRemainder(mdl.comment));
    -  47    }
    -  48    return m('.hs-item-comment', content);
    -  49
    -  50
    -  51/**
    -  52 * Report the item's description. This can come in different forms that are all handled here:
    -  53 * - comment.shortText: 
    -  54 * - comment.text: 
    -  55 * - comment.tags[{tag:'description}, text:]
    -  56 * Any resulting comment will be translated from markdown to html and returned as a `Vnode`.
    -  57 * @param comment the comment object to parse
    -  58 * @param short boolean; if true, only the first paragraph of the description will be returned
    -  59 */

    -  60function textOrShortTextOrDescription(comment:any, short:boolean):Vnode {
    -  61    let text = (comment.shortText || '');
    -  62    if (comment.text) { text += '\n'+ (comment.text || ''); }
    -  63    if (comment.tags) {
    -  64        comment.tags.map((tag:any) => {if (tag.tag==='description') { text = tag.text;}} );
    -  65    }
    -  66    text = text.replace(//gi, short? '' : example({}));
    -  67    return m('.hs-item-comment-desc', prettifyCode(text, short));
    -  68}
    -  69
    -  70/**
    -  71 * creates the `returns` message for a function or method.
    -  72 */

    -  73function returns(comment:any, short:boolean):Vnode {
    -  74    let text = comment.returns;
    -  75    return m('.hs-item-comment-return', !text? '': [            
    -  76        m('span.hs-item-comment-tag', 'returns:'), 
    -  77        m('span.hs-item-comment-text', text)
    -  78    ]);
    -  79}
    -  80
    -  81function commentRemainder(comment:any):string|Vnode {
    -  82    return m('', Object.keys(comment).map((tag:any) => {
    -  83            switch(tag) {
    -  84                case 'tags':        // already handled
    -  85                case 'shortText':   // already handled
    -  86                case 'text':        // already handled
    -  87                case 'description': // already handled
    -  88                case 'returns':     // already handled
    -  89                        return '';
    -  90                default: return m('.hs-item-comment-special', [
    -  91                    m('span.hs-item-comment-tag', tag), 
    -  92                    m('span.hs-item-comment-text', comment[tag])
    -  93                ]);;
    -  94            }
    -  95    }));
    -  96}
    -  97
    -  98function otherCommentTags(comment:any):string|Vnode {
    -  99    return m('', !comment.tags? [] : comment.tags.map((tag:any) => {
    - 100        switch(tag.tag) {
    - 101            case 'description': return ''; // skip since already handled
    - 102            default: return m('.hs-item-comment-special', [
    - 103                m('span.hs-item-comment-tag', tag.tag), 
    - 104                m('span.hs-item-comment-text', tag.text)
    - 105            ]);
    - 106        }
    - 107    }));
    - 108}
    - 109
    - 110function mainCommentParams(params:any):Vnode {
    - 111    return m('.hs-item-comment-params',  params.map((par:any) =>
    - 112        m('.hs-item-comment-param', [
    - 113            m('span.hs-item-comment-tag', par.name+':'), 
    - 114            m('span.hs-item-comment-text', !par.comment? '' :
    - 115                ((par.defaultValue!==undefined)? `[default: ${par.defaultValue}] ` : '') + par.comment.text
    - 116            )
    - 117        ])
    - 118    ));
    - 119}
    - 120
    - 121/**
    - 122 * finds segments of `...` in `comment` and replaces them with a prettified version.
    - 123 * Currently the function performs two operations:
    - 124 * - add indentation for brackets {...}
    - 125 * - wrap the <code>...</code> part within <pre>...</pre> brackets
    - 126 * @param comment the comment comment 
    - 127 */

    - 128function prettifyCode(comment:string, short:boolean):Vnode { 
    - 129//    const indentSpaces = 2;
    - 130    let result = comment;
    - 131
    - 132    function braceIndenting(text:string): string {
    - 133        let indent = 0;
    - 134        const result = text
    - 135            .substring(6, text.length-7)    // remove  and 
    - 136            .trim()
    - 137            .replace(/(<)/g, '<').replace(/(>)/g, '>')
    - 138            .split('\n')
    - 139            .map((l:string) => {
    - 140                let oldIndent = indent;
    - 141                let k = l.trim();
    - 142                indent += Math.max(-1, Math.min(1, k.split('{').length - k.split('}').length)); 
    - 143                indent += Math.max(-1, Math.min(1, k.split('[').length - k.split(']').length)); 
    - 144                return ''.repeat(((indent < oldIndent)?indent:oldIndent)) + k;
    - 145            })
    - 146            .join('\n')
    - 147            .trim();
    - 148        return '
    ' + result + '
    ';
    - 149    }
    - 150
    - 151    result = result.replace(/([\S\s]*?)<\/code>/gi, braceIndenting);
    - 152    return m.trust(markDown(result, short, m.route.get()));
    - 153}
    - 154
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/view/MainDetail.html b/docs/src/hsDoc/view/MainDetail.html deleted file mode 100644 index fe2f999..0000000 --- a/docs/src/hsDoc/view/MainDetail.html +++ /dev/null @@ -1,181 +0,0 @@ - - -

    view/MainDetail.ts

    -
       1import { m, Vnode}      from 'hslayout';
    -   2import { Layout }    from 'hslayout';
    -   3import { DocSets }      from '../DocSets'; 
    -   4import { comment, commentLong }  from './MainComment';
    -   5import { flags, sourceLink, signature, type, 
    -   6         extensionOf, inheritedFrom,
    -   7         kindString, itemName, makeID } 
    -   8                        from './Parts'; 
    -   9
    -  10
    -  11/**
    -  12 * Creates Documentation on the main panel 
    -  13 */

    -  14export class MainDetail extends Layout { 
    -  15    getComponents(node:Vnode): Vnode {
    -  16        let lib, field;
    -  17        if (node.attrs.route) {
    -  18            lib = node.attrs.route.lib;
    -  19            field = node.attrs.route.field;
    -  20        }
    -  21        node.attrs.route = undefined;
    -  22
    -  23        let result = getOverview(lib, field) || itemDoc(DocSets.get(lib, field) || ''); 
    -  24        return m('.hs-main-detail', [result]); 
    -  25    }
    -  26}
    -  27
    -  28/**
    -  29 * Checks if the project overview is being requested and returns the overview, 
    -  30 * or `undefined` if not available
    -  31 * @param mdl the module name to check
    -  32 * @return Vnode containing the overview file, or `undefined`
    -  33 */

    -  34function getOverview(lib:string, mdl:string):Vnode {
    -  35    if (mdl === '0' || mdl === '') {  //show module overview
    -  36        mdl = DocSets.get(lib, `${lib}.overview`);
    -  37        if (mdl) { // if project has an overview:
    -  38            return overviewDoc(mdl); 
    -  39        }
    -  40    }
    -  41    return undefined;
    -  42}
    -  43
    -  44/**
    -  45 * Creates documentation for standard items in the main panel
    -  46 * @param mdl the module to document on the main panel
    -  47 */

    -  48function itemDoc(mdl:any) {
    -  49    const sig = mdl.signatures? mdl.signatures[0] : mdl;
    -  50    return m('.hs-item-doc', [
    -  51        title(mdl, sig),
    -  52        commentLong(sig),
    -  53        members(sig, sig)
    -  54    ]);
    -  55}
    -  56
    -  57/**
    -  58 * Creates documentation for the project overview in the main panel
    -  59 * @param mdl the module to document on the main panel
    -  60 */

    -  61function overviewDoc(mdl:any) {
    -  62    const sig = mdl.signatures? mdl.signatures[0] : mdl;
    -  63    return m('.hs-item-doc', [
    -  64        commentLong(sig),
    -  65    ]);
    -  66}
    -  67
    -  68/**
    -  69 * renders the title of the main panel
    -  70 * @param mdl the module to document 
    -  71 * @param sig a signature of the module, or the the module itself
    -  72 */

    -  73function title(mdl:any, sig:any): Vnode { 
    -  74    return m('.hs-item-title', {id: makeID('title', mdl)}, itemDescriptor(mdl, sig)); 
    -  75}
    -  76
    -  77function members(mdl:any, sig:any): Vnode {
    -  78    if (mdl.groups) {
    -  79        return m('.hs-item-members', [
    -  80            ...mdl.groups.map((g:any) => member(g, mdl.lib, true, true)),
    -  81            ...mdl.groups.map((g:any) => member(g, mdl.lib, true, false)),
    -  82            ...mdl.groups.map((g:any) => member(g, mdl.lib, false, true)),
    -  83            ...mdl.groups.map((g:any) => member(g, mdl.lib, false, false))
    -  84        ]);
    -  85    } else if (mdl.parameters) {
    -  86        return m('.hs-item-members', parameter(mdl.parameters, mdl.lib));
    -  87    } else {
    -  88        return m('.hs-item-members');
    -  89    }
    -  90}
    -  91
    -  92function parameter(g:any[], lib:string): Vnode {
    -  93    let content = g.map((c:any) => m('.hs-item-parameter', {id:makeID('parameter', c)}, itemChild(c)));
    -  94    content.unshift(m('.hs-item-member-title', {id:'parameters'}, m('span', 'Parameters')));
    -  95    return m('.hs-item-member', content);
    -  96}
    -  97
    -  98function member(group:any, lib:string, statc:boolean, publc: boolean): Vnode {
    -  99    const resolve           = ((c:number) => DocSets.get(lib, c));
    - 100    const directChildren    = ((mdl:any) => !mdl['inheritedFrom']);
    - 101    const inheritedChildren = ((mdl:any) =>  mdl['inheritedFrom']);
    - 102    const groupMap = {
    - 103        'External modules': '.hs-item-external-module',
    - 104        'Constructors':     '.hs-item-constructor',
    - 105        'Classes':          '.hs-item-class',          
    - 106        'Interfaces':       '.hs-item-interface',          
    - 107        'Functions':        '.hs-item-function',          
    - 108        'Methods':          '.hs-item-method',          
    - 109        'Variables':        '.hs-item-variable',
    - 110        'Object literals':  '.hs-item-object-literal',
    - 111        'Properties':       '.hs-item-property',
    - 112        'Type aliases':     '.hs-item-alias',          
    - 113        'Accessors':        '.hs-item-accessors'        
    - 114    };
    - 115    const fn = groupMap[group.title] || '.hs-item-unknown-member';
    - 116    const isPublic = (flags:any) => flags.isPublic || (flags.isExported && !flags.isPrivate);
    - 117
    - 118    const content = group.children
    - 119        .map(resolve)
    - 120        .filter(directChildren)
    - 121        .filter((mdl:any) => statc? mdl.flags.isStatic : !mdl.flags.isStatic)
    - 122        .filter((mdl:any) => publc? isPublic(mdl.flags) : !isPublic(mdl.flags))
    - 123        .map((mdl:any) => m(fn, {id:makeID(group.title, mdl)}, itemChild(mdl)));
    - 124    const inherited = group.children
    - 125        .map(resolve)
    - 126        .filter(inheritedChildren)
    - 127        .filter((mdl:any) => statc? mdl.flags.isStatic : !mdl.flags.isStatic)
    - 128        .filter((mdl:any) => publc? mdl.flags.isPublic : !mdl.flags.isPublic)
    - 129        .map((mdl:any) => m(`.hs-item-inherited ${fn}`, {id:makeID(group.title, mdl)}, itemChild(mdl)));
    - 130
    - 131    const publStr = publc?'Public':'Protected or Private';
    - 132    const statStr = statc?'Static':''; 
    - 133    if (inherited.length>0) {
    - 134        inherited.unshift(m('.hs-item-inherited .hs-item-member-title', m('span', `${publStr} ${statStr} Inherited ${group.title}`)));
    - 135    }
    - 136    if (content.length>0) {
    - 137        content.unshift(m('.hs-item-member-title', {id:group.title.toLowerCase()}, m('span', `${publStr} ${statStr} ${group.title}`)));
    - 138    }
    - 139    return m(`.hs-item-member ${statc?'.hs-item-static':''} ${publc?'.hs-item-public':''}`, content.concat(inherited));
    - 140}
    - 141
    - 142function itemDescriptor(mdl:any, sig:any):Vnode {
    - 143    try { return m('.hs-item-desc', [ 
    - 144            flags(mdl),
    - 145            kindString(mdl),
    - 146            itemName(mdl, mdl),
    - 147            signature(sig, mdl),
    - 148            type(sig,  mdl.lib),
    - 149            extensionOf(mdl),
    - 150            inheritedFrom(mdl),
    - 151            sourceLink(mdl)
    - 152        ]);
    - 153    }
    - 154    catch(e) { console.log(e); console.log(mdl); }
    - 155}
    - 156
    - 157function itemChild(mdl:any, sig=mdl): Vnode[] {
    - 158    return mdl.signatures? 
    - 159        mdl.signatures.map((s:any) => m('.hs-item-child-signature',[itemDescriptor(mdl, s), comment(s, true)])) : 
    - 160        [itemDescriptor(mdl, sig), comment(sig,true)];
    - 161}
    - 162
    - 163
    - 164
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/view/MainExample.html b/docs/src/hsDoc/view/MainExample.html deleted file mode 100644 index 7c29c09..0000000 --- a/docs/src/hsDoc/view/MainExample.html +++ /dev/null @@ -1,285 +0,0 @@ - - -

    view/MainExample.ts

    -
       1/**
    -   2 * Comment sections may contain code examples that are placed within <example> tags.
    -   3 * 
    -   4 * `hsDoc` will interpret and execute Javascript instructions within a <`file name='script.js'`> tag.
    -   5 * and stylesheet instructions with a <`file name='style.css'`> tag, as in following example:
    -   6 * 
    -   7 *     <example> 
    -   8 *     
    -   9 *     m.mount(root, { 
    -  10 *         view:() => m(hslayout.Layout, { columns:[], 
    -  11 *             content:['first line','second line')]
    -  12 *         })
    -  13 *     });
    -  14 *     
    -  15 * 
    -  16 *     
    -  17 *     .hsLeaf { 
    -  18 *         color: blue; 
    -  19 *     }
    -  20 *     
    -  21 *     </example>
    -  22 * 
     
    -  23 * 
    -  24 * ### Scripts 
    -  25 * Scripts are expected to mount a `mithril Vnode` on a root DOM element using `m.mount` or `m.render`. 
    -  26 * Do not use `m.route` as only a single call is allowed per web app and that is used to manage the 
    -  27 * main hsDoc site menu and navigation.
    -  28 * 
    -  29 * hsDoc internally uses the [global `Function` object][Function] to parse and execute the script. 
    -  30 * Thus the script has access only to global objects and to objects provided
    -  31 * as parameters in the `Function` constructor. hsDoc currently provides the following namespaces as parameters
    -  32 * for use in the scripts:
    -  33 * - **m**: the `Mithril` m function    
    -  34 * - **layout**: the {@link hsLayout: `hsLayout`} namespace, providing functions to layout the browser window.
    -  35 * - **widget**: the {@link hsGraph: `hsGraph`} namespace, providing various UI widget functions.
    -  36 * - additionally, the parameter **root** is provided as the DOM element to mount to.
    -  37 * 
    -  38 * [Function]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
    -  39 * 
    -  40 * ### Styles
    -  41 * Styles will be automatically sandboxed so they are valid only within the enclosing example tags. 
    -  42 * This is achieved by prefixing css tags with a unique exmple ID and allows multiple examples to co-exist on the same page.
    -  43 * In the DOM, the example ID is assgned top the <example> tag.
    -  44 * Use `$exampleID` as css tag in the `css` section of the example to refer to the <example> element, 
    -  45 * as shown below.
    -  46 * 
    -  47 * ### Example
    -  48 * 
    -  49 * 
    -  50 * m.mount(root, { 
    -  51 *     view:() => m(hslayout.Layout, {
    -  52 *         css:'.myExample', 
    -  53 *         columns:[], 
    -  54 *         content:[
    -  55 *             'third line',
    -  56 *             'fourth line'
    -  57 *         ]
    -  58 *     })
    -  59 * });
    -  60 * 
    -  61 * 
    -  62 * $exampleID { height: 200px;}
    -  63 * .hs-layout { 
    -  64 *     margin:0; 
    -  65 * }
    -  66 * .myExample { 
    -  67 *     color: red; 
    -  68 *     font-weight:bold; 
    -  69 * }
    -  70 * 
    -  71 * 

    -  72 */

    -  73
    -  74/** */
    -  75import { m }                from 'hslayout';
    -  76import { Menu, SelectorDesc }   from 'hswidget';
    -  77import { Layout }        from 'hslayout';
    -  78import { shortCheckSum }    from 'hsutil'; 
    -  79import { delay }            from 'hsutil'; 
    -  80import * as hslayout        from 'hslayout';
    -  81import * as hswidget        from 'hswidget';
    -  82import * as hsgraph         from 'hsgraph';
    -  83import * as hsdata          from 'hsdata';
    -  84import * as hsutil          from 'hsutil';
    -  85
    -  86
    -  87/**
    -  88 * describes an executable comment example
    -  89 */

    -  90interface CommentDescriptor { 
    -  91    exampleID: string;                  // example tag ID
    -  92    menuID:    string;                  // menu tag ID
    -  93    desc:   SelectorDesc;               // menu items
    -  94    attrs?: {string?:string};           // 
    -  95    pages:  {string?:string};           // page content for each menu item
    -  96    executeScript?: (root:any) => void; // the example code to execute
    -  97    executeSource?: '';                 // the source code to execute
    -  98    activeSrcPage:string;               // the active page for the source display
    -  99}
    - 100
    - 101/**
    - 102 * Map containing various exampkle configurations 
    - 103 */

    - 104const gInitialized:{string?:CommentDescriptor} = {};
    - 105
    - 106/**
    - 107 * creates the example configuration, generates the DOM hook, and sets up the example execution.
    - 108 * `example` takes a context map of the form `{ name:module, ...}` and return a function 
    - 109 * that can be used in calls to `string.replace`as in the following example:
    - 110 * 

    - 111 * import * as layout from "layout";
    - 112 * text = text.replace(/([\S\s]*?)<\/example>/gi, example({layout:layout}));
    - 113 * 

    - 114 * The modules `m`, `hsLayout`, and `hsGraph` will be added by default as 
    - 115 * ` { m: m, layout: layout, widget: widget } `
    - 116 * @param example the example string extracted from the comment, including the `` tags.
    - 117 * @param context the context in which the example script should be run, expressed as `name`:`namespace` pairs.
    - 118 */

    - 119export function example(context:any) { 
    - 120    context.m        = m;
    - 121    context.hslayout = hslayout;
    - 122    context.hswidget = hswidget;
    - 123    context.hsgraph  = hsgraph;
    - 124    context.hsdata   = hsdata;
    - 125    context.hsutil   = hsutil;
    - 126    const libNames = Object.keys(context);
    - 127    const modules = libNames.map(n => context[n]);
    - 128    return (exmpl:string) => { 
    - 129        const instance = shortCheckSum(exmpl);
    - 130        let IDs = gInitialized[instance]; 
    - 131        if (!IDs) {
    - 132            IDs = gInitialized[instance] = initDesc(() => addExample(IDs)   // called when source menu changes
    - 133                .then(executeScript) 
    - 134                .catch(executeError)
    - 135            );
    - 136            IDs.executeSource = exmpl;
    - 137            try {
    - 138                const scriptFn = new Function('root', ...libNames, getCommentDescriptor(IDs, exmpl));    
    - 139                IDs.executeScript = (root:any) => scriptFn(root, ...modules);
    - 140            }
    - 141            catch(e) { console.log('creating script:' + e); }
    - 142        }
    - 143        if (document.getElementById(IDs.menuID)) { 
    - 144        } else {
    - 145            addExample(IDs).then(executeScript).catch(executeError);
    - 146        }
    - 147
    - 148        const frameHeight = (IDs.attrs? IDs.attrs.height : undefined) || '300px';
    - 149        const wrapWithID = (css:string) => css==='$exampleID'? `#${IDs.exampleID}`: `#${IDs.menuID} ${css}`;
    - 150
    - 151        // prefix css selectors with ID of main execution area to sandbox the scope
    - 152        // (^|}): start of string or end of previous style def
    - 153        // \s*?: any white spaces
    - 154        // (\S*?): capturing group: css name
    - 155        // \s*?{: whitespaces, followed by start of style def
    - 156        const style = (!IDs.pages['css'])? '':                              // empty if no css defined
    - 157                      IDs.pages['css'].replace(/(^|})\s*?(\S*?)\s*?{/gi,    // otherwise wrap each css statement
    - 158                         (x:string, ...args:any[]) => x.replace(args[1], wrapWithID(args[1]))
    - 159        );
    - 160        return ``;
    - 161    };
    - 162}
    - 163
    - 164/**
    - 165 * creates the example configuration 
    - 166 */

    - 167function initDesc(fn:any):CommentDescriptor {
    - 168    return {
    - 169        exampleID:  getNewID(),    // example tag ID
    - 170        menuID:     getNewID(),    // main execution area tag ID
    - 171        desc:
    - 172            items:[],
    - 173            selectedItem: 'js',
    - 174            changed: fn,
    - 175            size: ["50px"]
    - 176        },
    - 177        pages:{},
    - 178        activeSrcPage: undefined
    - 179    };
    - 180}
    - 181
    - 182/** creates a new random example ID for each call. */
    - 183function getNewID():string { 
    - 184    return 'hs'+Math.floor(1000000*Math.random());
    - 185}
    - 186
    - 187/** asynchronously adds the example structure on the page and then executed the script. */
    - 188function addExample(IDs:CommentDescriptor):Promise {
    - 189    return Promise.resolve(IDs).then(addExampleStructure).then(delay(1)); 
    - 190}
    - 191
    - 192/**
    - 193 * returns a parameterless function that can be called via setTimeout to 
    - 194 * mount the menu and execute the script function provided in `IDs`. 
    - 195 * @param IDs the `CommentDescriptor` to execute on. 
    - 196 */

    - 197function addExampleStructure(IDs:CommentDescriptor):CommentDescriptor { 
    - 198    let item = IDs.activeSrcPage || 'js';
    - 199    const root = document.getElementById(IDs.exampleID);
    - 200
    - 201    IDs.desc.changed = (newItem:string) => {
    - 202        item = IDs.activeSrcPage = newItem;
    - 203    };
    - 204
    - 205    m.mount(root, {view: () => m(Layout, { 
    - 206        columns: ["50%"],
    - 207        content: [
    - 208            m(Layout, {
    - 209                content: m('.hs-layout .hs-execution', {id:IDs.menuID}, 'placeholder')
    - 210            }),
    - 211            m(Layout, {
    - 212                rows:["30px", "fill"],
    - 213                css: '.hs-source',
    - 214                content:[
    - 215                    m(Menu, {desc: IDs.desc, size:['50px'] }),
    - 216                    m(Layout, { content: m('.hs-layout .hs-source-main', m.trust(`
    ${IDs.pages[item]}
    `))})
    - 217                ]
    - 218            })
    - 219        ]})
    - 220    });
    - 221    return IDs;
    - 222}
    - 223
    - 224/**
    - 225 * execute the provided script 
    - 226 * @param IDs provides the context in which the script is exceuted/
    - 227 */

    - 228function executeScript(IDs:CommentDescriptor) {
    - 229    const root = document.getElementById(IDs.menuID);
    - 230    try { IDs.executeScript(root); }
    - 231    catch(e) { 
    - 232        console.log("error executing script: " + e); 
    - 233        console.log(IDs.executeSource);
    - 234        console.log(e.stack);
    - 235    }
    - 236    m.redraw();
    - 237    return IDs;
    - 238}
    - 239
    - 240function executeError(e:any) {
    - 241    console.log('rejection executing script:');
    - 242    console.log(e);
    - 243}
    - 244 
    - 245/**
    - 246 * Fills in all fields of the CommentDescriptor provided as `IDs`.
    - 247 * @param IDs the CommentDescriptor to complete
    - 248 * @param example the example string, including  tag
    - 249 * @return the script to execute, as a string
    - 250 */

    - 251function getCommentDescriptor(IDs:CommentDescriptor, example:string):string {
    - 252    let result = '';
    - 253    let attrs = example.match(/)/i);
    - 254    if (attrs && attrs[1]) { 
    - 255        const at = attrs[1].split('=');
    - 256        IDs.attrs =  {[at[0]]: at[1]};
    - 257    }
    - 258    example.replace(/([\S\s]*?)<\/file>/gi, function(text:string) {
    - 259        const args = [...arguments];
    - 260        const content = args[2].trim(); // the part between  and 
    - 261        IDs.desc.items.push(args[1]);   // record available extensions, i.e. 'js', 'html', etc 
    - 262        IDs.pages[args[1]] = content;   // associate the content with the extension
    - 263        return result;
    - 264    });
    - 265    return IDs.pages['js'];
    - 266}
    - 267
    - 268
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/view/MainExample.spec.html b/docs/src/hsDoc/view/MainExample.spec.html deleted file mode 100644 index 1d3378b..0000000 --- a/docs/src/hsDoc/view/MainExample.spec.html +++ /dev/null @@ -1,33 +0,0 @@ - - -

    view/MainExample.spec.ts

    -
       1const hslayout = require('hslayout');
    -   2const m = hslayout.m;
    -   3const o = hslayout.o;
    -   4
    -   5
    -   6o.spec('example', () => {
    -   7    let docsMenu:any;
    -   8    o.before(() => {
    -   9        m.mount(o.root, {view: () => m('', '')});
    -  10        docsMenu = o.root.childNodes[0];
    -  11    }); 
    -  12    o('DocsMenu exists', () => {
    -  13        o(docsMenu===undefined).equals(false)('should be defined');
    -  14    });
    -  15});
    -  16
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/view/Parts.html b/docs/src/hsDoc/view/Parts.html deleted file mode 100644 index fff6508..0000000 --- a/docs/src/hsDoc/view/Parts.html +++ /dev/null @@ -1,218 +0,0 @@ - - -

    view/Parts.ts

    -
       1import { m, Vnode} from 'hslayout';
    -   2import { tooltip } from './Tooltip';
    -   3import { DocSets } from '../DocSets'; 
    -   4
    -   5const SourceBase = 'src/'; 
    -   6
    -   7
    -   8// TODO: sort flags in array to garantee sequence of printing
    -   9export function flags(mdl:any, ignore:string[]=[]) {
    -  10    const ignoreExportInKind = ['Method', 'Property'];
    -  11    const knownFlags = {
    -  12        isExported:             'export',
    -  13        isExternal:             'external', // 
    -  14        isPublic:               'public',
    -  15        isPrivate:              'private',
    -  16        isProtected:            'protected',
    -  17        isConstructorProperty:  'constructorProperty',
    -  18        isStatic:               'static',
    -  19        isOptional:             'optional'
    -  20    };
    -  21    return m('span.hs-item-flags', !mdl.flags? [] : 
    -  22        Object.keys(mdl.flags).map((f:string) => {
    -  23            let ign = false;
    -  24            let flag = knownFlags[f];
    -  25            if (flag === undefined) { flag = f; }
    -  26            else { ign = (ignore.indexOf(flag) >= 0); }
    -  27            if (flag === 'export' && ignoreExportInKind.indexOf(mdl.kindString)>=0) { ign = true; }
    -  28            return m(`span.hs-item-${ign?'ignore':(flag===f?'unknown':flag)}-flag`, ign? undefined : flag);
    -  29        })
    -  30    );
    -  31}
    -  32
    -  33export function kindString(mdl:any) {
    -  34    return m('span.hs-item-kind', mdl.kindString);
    -  35}
    -  36
    -  37export function itemName(mdl:any, sub:any) {
    -  38    return m('span.hs-item-name', !mdl.fullPath? sub.name : libLink('a', mdl.lib, mdl.fullPath, sub.name));
    -  39}
    -  40
    -  41
    -  42export function itemTooltip(mdl:any) {
    -  43    return m('span.hs-item-name', tooltip(mdl.name, 'class name and then some', 'bottom'));
    -  44}
    -  45
    -  46export function extensionOf(mdl:any) {
    -  47    return m('span.hs-item-extensions', !mdl.extendedTypes? undefined : [
    -  48        m('span.hs-item-extends', 'extends'),
    -  49        m('span', mdl.extendedTypes.map((t:any, i:number) =>
    -  50            m('span.hs-item-extension', [
    -  51                libLink('a', mdl.lib, DocSets.get(mdl.lib, t.id).fullPath, t.name),
    -  52                mdl.extendedTypes.map.length>(i+1)? ', ': ''
    -  53            ])
    -  54        )),
    -  55    ]);
    -  56}
    -  57
    -  58export function inheritedFrom(mdl:any) {
    -  59    if (mdl.inheritedFrom) {
    -  60        let parent = DocSets.get(mdl.lib, mdl.inheritedFrom.id);
    -  61        parent = DocSets.get(mdl.lib, parent.fullPath.substring(0, parent.fullPath.lastIndexOf('.')));
    -  62        return m('span.hs-item-inherited-from', [
    -  63            m('span', 'inherited from '),
    -  64            libLink('a', parent.lib, parent.fullPath, parent.name)
    -  65        ]);
    -  66    } else {
    -  67        return m('span.hs-item-inherited-from', undefined);
    -  68    }
    -  69}
    -  70
    -  71export function sourceLink(mdl:any) {
    -  72    const source = mdl.sources? mdl.sources[0] : undefined;
    -  73    if (source) {
    -  74        let file = (source.fileName || '').replace('.ts', '.html');
    -  75        const index = file.indexOf(mdl.lib);
    -  76        if (index>0) {
    -  77            file = file.substr(index); // only consider links within the docSet (everything after the lib name)
    -  78        }
    -  79        return m('span.hs-item-member-source',  
    -  80            m('a', { href:`${SourceBase}${mdl.lib}/${file}#${Math.max(0,source.line-5)}`, target:"_blank"}, '[source]')
    -  81        );
    -  82    } else {
    -  83        return m('span.hs-item-member-source', '');
    -  84    }
    -  85}
    -  86
    -  87/**
    -  88 * creates a library link on the specified `name`. 
    -  89 * The link points to `/api//`
    -  90 * @param css the css tag selector to use
    -  91 * @param cls the css class selector to use
    -  92 * @param lib the lib string to point to
    -  93 * @param id the id number to point to
    -  94 * @param name the name on which to formt he link
    -  95 */

    -  96export function libLink(css:string, lib:string, id:string, name:string) {
    -  97    return m(css, { href:`/api/${lib}/${id}`, oncreate: m.route.link, onupdate: m.route.link }, name);
    -  98};
    -  99
    - 100/**
    - 101 * creates a function or method signature
    - 102 */

    - 103export function signature(s:any, mdl:any): Vnode {
    - 104    const comma = (i:number) => (i>0)? ', ': '';
    - 105    function optional(flags: any) {
    - 106        return (flags && flags.isOptional)? '.hs-item-optional' : '';
    - 107    }
    - 108
    - 109    let sig = [];
    - 110    if (s) {
    - 111        if (s.parameters) {
    - 112            sig = s.parameters.map((p:any, i:number) => m('span', [
    - 113                comma(i),
    - 114                m('span.hs-item-sig-param', [
    - 115                    m(`span.hs-item-name${optional(p.flags)}`, p.name),
    - 116                    type(p, mdl.lib)
    - 117                ])
    - 118            ]));
    - 119        }
    - 120        switch (mdl.kindString) {
    - 121            case 'Method':
    - 122            case 'Function': 
    - 123            case 'Constructor': 
    - 124                sig.unshift(m('span.hs-item-name', '('));
    - 125                sig.push(m('span.hs-item-name', ')'));
    - 126                break;
    - 127            default:
    - 128        }
    - 129    }
    - 130    return m('span.hs-item-signature', sig);
    - 131}
    - 132
    - 133/**
    - 134 * adds a default value, if defined
    - 135 */

    - 136export function defaultVal(s:any, lib:string): Vnode {
    - 137    if (s && s.defaultValue) {
    - 138        let val = ` = ${s.defaultValue}`.replace(/{/gi, '{ ').replace(/}/gi, ' }');
    - 139        return m('span.hs-item-default', val);
    - 140    } else {
    - 141        return;
    - 142    }        
    - 143}
    - 144
    - 145export function type(t:any, lib:string) {
    - 146    function _type(tt:any):any {
    - 147        switch (tt.type) {
    - 148            case undefined:         return '';
    - 149            case 'array':           return m('span.hs-item-type-array', ['Array<', _type(tt.elementType), '>']);
    - 150                                    
    - 151            case 'tuple':           return m('span.hs-item-type-tuple', [
    - 152                                        '[ ',
    - 153                                        ...tt.elements.map((e:any, i:number) => [i>0?', ':undefined, _type(e)]),
    - 154                                        ' ]'
    - 155                                    ]);
    - 156            case 'intrinsic':
    - 157            case 'instrinct':       return m('span.hs-item-type-instrinct', tt.id? libLink('span', lib, tt.fullPath, tt.name) : tt.name); 
    - 158            case 'stringLiteral':   return m('span.hs-item-type-string-literal', tt.type); 
    - 159            case 'union':           return m('span.hs-item-type-union', [...tt.types.map((e:any, i:number) => [i>0?' | ':undefined, _type(e)])]);
    - 160            case 'reference':       let refRes = tt.name;
    - 161                                    if (tt.id) {
    - 162                                        const typeRef = DocSets.get(lib, tt.id);
    - 163                                        if (typeRef.typeArguments) { refRes = typeRef.name+'<'+ typeRef.typeArguments.map(_type).join(', ') + '>'; }
    - 164                                        else if (typeRef.id)       { refRes = libLink('a', lib, typeRef.fullPath, typeRef.name); }
    - 165                                        else                       { refRes = typeRef.name; }
    - 166                                    }
    - 167                                    return m('span.hs-item-type-reference', refRes);
    - 168            case 'reflection':      let rflRes;
    - 169                                    if (tt.declaration) {
    - 170                                        rflRes = !tt.declaration.children? tt.declaration.kindString :
    - 171                                            m('span.hs-item-reflection', [
    - 172                                                '{ ',
    - 173                                                ...tt.declaration.children.map((c:any, i:number) => 
    - 174                                                    [i>0?', ':undefined, c.name, ': ', _type(c.type)]
    - 175                                                ),
    - 176                                                ' }'
    - 177                                            ]);
    - 178                                    } else {
    - 179                                        rflRes = 'UNKNOWN';
    - 180                                    }
    - 181                                    return m('span.hs-item-type-reflection', rflRes);
    - 182            default: console.log('unknown type '+ tt.type);
    - 183                     console.log(t);
    - 184                     return t.type;
    - 185        }
    - 186    }
    - 187
    - 188    try {
    - 189       return m('span', !t.type? '': [
    - 190           m('span.hs-item-name',':'), 
    - 191           m('span.hs-item-sig-type', _type(t.type)),
    - 192           defaultVal(t, lib)
    - 193        ]);
    - 194    } catch(e) { console.log(e); console.log(e.trace); }
    - 195}
    - 196
    - 197export function makeID(section:string, mdl:any) {
    - 198    let result = section? section+'_' : '';
    - 199    result = (result + (mdl.name || '')).toLowerCase();
    - 200    return (result!=='')? result : undefined;
    - 201}
    - - \ No newline at end of file diff --git a/docs/src/hsDoc/view/Tooltip.html b/docs/src/hsDoc/view/Tooltip.html deleted file mode 100644 index 8617ad4..0000000 --- a/docs/src/hsDoc/view/Tooltip.html +++ /dev/null @@ -1,25 +0,0 @@ - - -

    view/Tooltip.ts

    -
       1import { m, Vnode} from 'hslayout';
    -   2
    -   3export function tooltip(text:string, tip:string, position:string):Vnode { 
    -   4    // position: top, left, botton, right
    -   5    return m('.hs-tooltip[href=#]', [text, m(`span.hs-tooltip-${position}`, tip)]);
    -   6}
    -   7
    -   8
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Axes.html b/docs/src/hsGraph/Axes.html deleted file mode 100644 index e1dc329..0000000 --- a/docs/src/hsGraph/Axes.html +++ /dev/null @@ -1,450 +0,0 @@ - - -

    Axes.ts

    -
       1/**
    -   2 * # Axes
    -   3 * renders the x- and y-axis with title, tick marks and labels.
    -   4 * 
    -   5 * ### Attributes
    -   6 * The `Axes` class is called by {@link Graph.Graph `Graph`} as 
    -   7 * `m(Axes, { cfg:cfg.axes, scales:scales })`
    -   8 * with the following attributes:
    -   9 * - cfg: a {@link Axes.AxesConfig AxesConfig} object
    -  10 * - scales: a {@link Axes.Scales Scales } object
    -  11 *
    -  12 * ### Configurations and Defaults
    -  13 * See {@link Axes.Axes.defaultConfig Axes.defaultConfig}
    -  14 * 
    -  15 * ### Example
    -  16 * 
    -  17 * 
    -  18 * let series = {
    -  19 *    colNames:['time', 'volume', 'price'],
    -  20 *    rows:[
    -  21 *      [0.2, 0.7, 0.87],
    -  22 *      [0.4, 0.015, 0.7],
    -  23 *      [0.6, 0.01, 0.7],
    -  24 *      [0.7, 5, 0.6],
    -  25 *      [0.8, 10, 0.75]
    -  26 * ]};
    -  27 * 
    -  28 * function myConfig(cfg) {
    -  29 *      cfg.series.data   = [series];
    -  30 *      cfg.series.series = [
    -  31 *          { x:'time', y:'volume'},
    -  32 *          { x:'time', y:'price'}
    -  33 *      ];
    -  34 *      cfg.series.series[0].style.marker.visible = true;
    -  35 *      cfg.series.series[1].style.marker.visible = true;
    -  36 *      cfg.series.series[1].style.marker.shape = hsgraph.Series.marker.square;
    -  37 *      cfg.chart.title.text          = 'Volume over Time';
    -  38 *      cfg.chart.title.xpos          = 'end';
    -  39 *      cfg.chart.title.ypos          = 'top';
    -  40 *      cfg.chart.title.vOffset       = -1.5;
    -  41 *      cfg.grid.minor.hor.visible    = true;
    -  42 * 
    -  43 *      const axes = cfg.axes.primary;
    -  44 *      axes.x.title.text = 'time';
    -  45 *      axes.y.title.text = 'volume';
    -  46 *      axes.y.scale.type = hsgraph.Axes.type.log;
    -  47 * }
    -  48 * 
    -  49 * m.mount(root, { 
    -  50 *      view:() => m(hsgraph.Graph, {cfgFn: myConfig })
    -  51 * });
    -  52 *
    -  53 * 
    -  54 * 
    -  55 * .hs-graph-chart { fill: #fff; }
    -  56 * .hs-graph-series { stroke-width: 5; }
    -  57 * 
    -  58 * 

    -  59 */

    -  60
    -  61 /** */
    -  62import { m, Vnode}  from 'hslayout';
    -  63import { XYScale,
    -  64         ScaleCfg, 
    -  65         Scales,
    -  66         MarkCfg,
    -  67         AxisCfg,
    -  68         AxesConfig,
    -  69         TickStruct,
    -  70         TickLabel,
    -  71         TickDefs } from './AxesTypes';
    -  72;
    -  73import { Config, 
    -  74         LabelCfg } from './Graph';
    -  75import { Scale }    from './Scale';
    -  76import { Domain }   from 'hsdata';
    -  77import { SVGElem, 
    -  78         TextHAlign,
    -  79         TextVAlign,
    -  80         Area }     from './SVGElem';
    -  81
    -  82
    -  83/** 
    -  84 * calculates the range value of axis crossing from a domain value.
    -  85 * @param cross the domain value where the axis crosses. Either 'min', 'max', or a numeric domain value
    -  86 * @param scale the Scale object for the perpendicular axis.
    -  87 */

    -  88function getCrossAt(cross:string|number, scale:Scale):number {
    -  89    let crossesAt:number;
    -  90    switch (cross) {
    -  91        case 'min': crossesAt = scale.domain()[0]; break;
    -  92        case 'max': crossesAt = scale.domain()[1]; break;
    -  93        default:    crossesAt = cross || 0;
    -  94    }
    -  95    return scale.convert(crossesAt);
    -  96}
    -  97
    -  98export class Axes extends SVGElem {
    -  99    /**
    - 100     * Defines available axis types:
    - 101     * - linear
    - 102     * - log
    - 103     * - date
    - 104     * - index
    - 105     * - percent
    - 106     * - ordinal
    - 107     * - nominal
    - 108     */

    - 109    static type = {
    - 110        linear:     'linear axis',
    - 111        log:        'log axis',
    - 112        date:       'date axis',
    - 113        index:      'index axis',
    - 114        percent:    'percent axis',
    - 115        ordinal:    'ordinal axis',
    - 116        nominal:    'nominal axis'
    - 117    };
    - 118
    - 119    /** 
    - 120    * Defines default values for display elements in `Axes`
    - 121    * sets the default configuration for the primary and secondary axes.
    - 122    * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations. 
    - 123    * 
    - 124    * ### Configurations and Defaults
    - 125    * ```
    - 126    * cfg.axes = {@link AxesTypes.AxesConfig } {
    - 127    *    primary: {                // Primary axis:
    - 128    *       x: axisCfg(true, true),
    - 129    *       y: axisCfg(true, false)
    - 130    *    },
    - 131    *    secondary: {               // Secondary axis:
    - 132    *       x: axisCfg(false, true),
    - 133    *       y: axisCfg(false, false)
    - 134    *    }
    - 135    *  }
    - 136    * ```
    - 137    * #### axisCfg(primary:boolean, x:boolean):
    - 138    * ```
    - 139    *  cfg.axes.[primary|secondary].[x|y] = {@link AxesTypes.AxisCfg }{
    - 140    *     visible:    primary? true : false,   // hide secondary axes
    - 141    *     crossesAt:  primary? 'min':'max',    // default axis crossing
    - 142    *     scale:     {@link AxesTypes.ScaleCfg }scaleCfg(),     // scale type and domain
    - 143    *     title:     {@link Graph.LabelCfg }titleCfg(primary, x),
    - 144    *     ticks:     {@link AxesTypes.TicksCfg }{                    
    - 145    *         major: {@link AxesTypes.TickStruct }{                
    - 146    *             marks:  {@link AxesTypes.MarkCfg }markCfg(primary, true),  
    - 147    *             labels: {@link Graph.LabelCfg }labelCfg(primary, x, true),     
    - 148    *             labelFmt: undefined 
    - 149    *         },
    - 150    *         minor: {@link AxesTypes.TickStruct }{ 
    - 151    *             marks:  markCfg(primary, false),
    - 152    *             labels: labelCfg(primary, x, false),     
    - 153    *             labelFmt: undefined 
    - 154    *         }
    - 155    *     } 
    - 156    *  }
    - 157    * ```
    - 158    * #### scaleCfg():
    - 159    * ```
    - 160    *  cfg.axes.[primary|secondary].[x|y].scale = {@link AxesTypes.ScaleCfg }{
    - 161    *      type:   {@link Axes.Axes.type } Axes.type.linear,  
    - 162    *      domain: {@link Data.Domain }['auto', 'auto']    // : min/max of domain; 'auto', 'tight', or a domain value
    - 163    *  }
    - 164    * ```
    - 165    * #### titleCfg(primary:boolean, x:boolean):
    - 166    * ```
    - 167    *  cfg.axes.[primary|secondary].[x|y].title = {@link SVGElem.TextElem }{
    - 168    *     visible: true,  
    - 169    *     text:    (x? 'x' : 'y') + (primary? '' : '2'),    // 'x' / 'y' or 'x2' / 'y2'
    - 170    *     xpos:    x? 'end' : (primary? 'middle' : 'start'),          
    - 171    *     ypos:    x? 'top' : (primary? 'bottom' : 'top'),           
    - 172    *     hOffset: x? -2 : (primary? 0 : 0.3),            
    - 173    *     vOffset: x? (primary? 0.4 : -1.2) : (primary? -0.5 : 0.7) 
    - 174    *  }      
    - 175    * ```
    - 176    * #### markCfg(primary:boolean, major:boolean):
    - 177    * ```
    - 178    *  cfg.axes.[primary|secondary].[x|y].ticks.[major|minor].marks = {@link AxesTypes.MarkCfg }{
    - 179    *     visible: major, 
    - 180    *     length: (primary? 1 : -1) * (major? 10 : 5) 
    - 181    *  }      
    - 182    * ```
    - 183    * #### labelCfg(primary:boolean, x:boolean, major:boolean):
    - 184    * ```
    - 185    *  cfg.axes.[primary|secondary].[x|y].ticks.[major|minor].labels = {@link SVGElem.TextElem }{
    - 186    *     visible: major, 
    - 187    *     xpos: x? 'middle' : (primary? 'end' : 'start')
    - 188    *     ypos: x? (primary? 'top' : 'bottom') : 'center', 
    - 189    *     hOffset: x? 0 (primary? -0.7 : 0.7), 
    - 190    *     vOffset: x? (primary? 0.7 : -0.7) : 0
    - 191    *  }      
    - 192    * ```
    - 193    * @param cfg the configuration object, containing default settings for all 
    - 194    * previously configured components.
    - 195    */

    - 196    static defaultConfig(cfg:Config) {
    - 197        function scaleCfg():ScaleCfg {
    - 198            return {                             // axis scaling information
    - 199                type: Axes.type.linear,         //    scale type
    - 200                domain:['auto', 'auto']  //    min/max of domain; 'auto', or a domain value
    - 201            };
    - 202        }
    - 203        function labelCfg(primary:boolean, x:boolean, major:boolean):LabelCfg {
    - 204            return { 
    - 205                visible: major, text: '',
    - 206                xpos: x? TextHAlign.middle : (primary? TextHAlign.end : TextHAlign.start),
    - 207                ypos: x? (primary? TextVAlign.top : TextVAlign.bottom) : TextVAlign.center, 
    - 208                hOffset: x? 0 : (primary? -0.7 : 0.7), 
    - 209                vOffset: x? (primary? 0.7 : -0.7) : 0
    - 210            }; 
    - 211        }
    - 212        function markCfg(primary: boolean, major:boolean):MarkCfg {
    - 213            return { 
    - 214                visible: major, 
    - 215                length: (primary? 1 : -1) * (major? 10 : 5) 
    - 216            };
    - 217        }
    - 218        function titleCfg(primary:boolean, x:boolean):LabelCfg {
    - 219            return {
    - 220                visible: true,  text: (x? 'x' : 'y') + (primary? '' : '2'),    
    - 221                xpos:  x? TextHAlign.end : (primary? TextHAlign.middle : TextHAlign.start),          
    - 222                ypos:  x? TextVAlign.top : (primary? TextVAlign.bottom : TextVAlign.top),           
    - 223                hOffset: x? -2 : (primary? 0 : 0.3),            
    - 224                vOffset: x? (primary? 0.4 : -1.2) : (primary? -0.5 : 0.7)       
    - 225            };
    - 226        }
    - 227        function axisCfg(primary:boolean, x:boolean):AxisCfg {
    - 228            return {
    - 229                visible:    primary? true : false, 
    - 230                crossesAt:  primary?'min':'max', 
    - 231                scale:      scaleCfg(),
    - 232                title: titleCfg(primary, x),
    - 233                ticks: {                    
    - 234                    major: {                
    - 235                        marks:  markCfg(primary, true),  
    - 236                        labels: labelCfg(primary, x, true),
    - 237                        labelFmt: undefined    
    - 238                    },
    - 239                    minor: { 
    - 240                        marks:  markCfg(primary, false),
    - 241                        labels: labelCfg(primary, x, false),    
    - 242                        labelFmt: undefined    
    - 243                    }
    - 244                } 
    - 245            };
    - 246        }
    - 247        cfg.axes = {
    - 248            primary: {
    - 249                x: axisCfg(true, true),
    - 250                y: axisCfg(true, false)
    - 251            },
    - 252            secondary: {
    - 253                x: axisCfg(false, true),
    - 254                y: axisCfg(false, false)
    - 255            }
    - 256        };
    - 257    }
    - 258
    - 259    /**
    - 260     * Makes adjustments to cfg based on current settings
    - 261     * @param cfg the configuration object, containing default settings for all components
    - 262     */

    - 263    static adjustConfig(cfg:Config) { 
    - 264    }
    - 265    
    - 266    /**
    - 267     * draws the axis line
    - 268     */

    - 269    drawAxisLine(x:boolean, range:Area, cross:number) {
    - 270        return x? this.horLine(range[0], range[1], cross, 'hs-graph-axis-line') :
    - 271                  this.verLine(cross, range[0], range[1], 'hs-graph-axis-line');
    - 272    }
    - 273
    - 274    /**
    - 275     * draws the axis title
    - 276     */

    - 277    drawTitle(x:boolean, ttlCfg:LabelCfg, type: string, range:Area, cross:number):Vnode {
    - 278        ttlCfg.cssClass = 'hs-graph-axis-title';
    - 279        const xy = { transform:`translate(${x?range[1]:cross}, ${x?cross:range[1]})` };
    - 280        return !ttlCfg.visible? undefined : 
    - 281            m('g', xy, this.text(ttlCfg, ttlCfg.text));
    - 282    }
    - 283
    - 284    /**
    - 285     * draws the tick marks. Labels are plotted for major tick marks only.
    - 286     */

    - 287    drawTickMarks(x:boolean, type:string, crossesAt:number, scale:Scale, ticks:TickDefs, cfg:TickStruct):Vnode {
    - 288        return m('svg', { class:`hs-graph-axis-${type}-tick-marks`}, 
    - 289            !cfg.marks.visible? '' : ticks.marks.map((t:number) => { 
    - 290                return x? this.verLine(scale.convert(t), crossesAt, crossesAt+cfg.marks.length) :
    - 291                          this.horLine(crossesAt, crossesAt-cfg.marks.length, scale.convert(t));
    - 292            })
    - 293        );
    - 294    }
    - 295
    - 296    /**
    - 297     * draws the tick labels. Labels are plotted for major tick marks only.
    - 298     */

    - 299    drawTickLabels(x:boolean, type:string, crossesAt:number, scale:Scale, ticks:TickDefs, cfg:TickStruct):Vnode {
    - 300        scale.setLabelFormat(cfg.labelFmt);
    - 301        return m('svg', {class:`hs-graph-axis-${type}-tick-label`}, 
    - 302            !cfg.labels.visible? '' : ticks.labels.map((t:TickLabel) => { 
    - 303                const v = scale.convert(t.pos);
    - 304                const xy = { transform:`translate(${x?v:crossesAt}, ${x?crossesAt:v})` };
    - 305                return m('g', xy, this.text(cfg.labels, t.text));
    - 306            })
    - 307        );
    - 308    }
    - 309
    - 310    /**
    - 311     * draws a single axis
    - 312     * @param dir axis to draw: 'x' or 'y'
    - 313     * @param attrs attributes required for rendering:
    - 314     * - type: 'primary' or 'secondary'
    - 315     * - scales:
    - 316     * - cfg: 
    - 317     */

    - 318    drawAxis(dir:string, scales: XYScale, type:string, axisCfg:AxesConfig):Vnode {
    - 319        const x = dir==='x';
    - 320        const range = scales[dir].range();
    - 321        const cfg   = axisCfg[type][dir];
    - 322        scales[dir].scaleType(cfg.scale.type);
    - 323        const crossesAt:number = getCrossAt(cfg.crossesAt, scales[x?'y':'x']);
    - 324        const ticks = scales[dir].ticks();
    - 325        return !cfg.visible? undefined : m('svg', { class:`hs-graph-axis-${dir} hs-graph-axis-${type}`}, [
    - 326            this.drawAxisLine(x, range, crossesAt),
    - 327            this.drawTitle(x, cfg.title, type, range, crossesAt),
    - 328            this.drawTickMarks(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor),
    - 329            this.drawTickMarks(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major),
    - 330            this.drawTickLabels(x, 'minor', crossesAt, scales[dir], ticks.minor, cfg.ticks.minor),
    - 331            this.drawTickLabels(x, 'major', crossesAt, scales[dir], ticks.major, cfg.ticks.major)
    - 332        ]);
    - 333    }
    - 334
    - 335    view(node?: Vnode): Vnode {
    - 336        const cfg:AxesConfig = node.attrs.cfg;
    - 337        const scales:Scales  = node.attrs.scales;
    - 338        return m('svg', {class:'hs-graph-axis'}, [
    - 339            this.drawAxis('x', scales.primary, 'primary', cfg),
    - 340            this.drawAxis('y', scales.primary, 'primary', cfg),
    - 341            this.drawAxis('x', scales.secondary, 'secondary', cfg),
    - 342            this.drawAxis('y', scales.secondary, 'secondary', cfg)
    - 343        ]);
    - 344    }
    - 345}
    - 346
    - 347/**
    - 348 * ### Simple Example
    - 349 * 
    - 350 * 
    - 351 * let series = {
    - 352 *    colNames:['time', 'volume'],
    - 353 *    rows:[
    - 354 *      [-1, 0.2],
    - 355 *      [0.2, 0.7],
    - 356 *      [0.4, -0.2],
    - 357 *      [0.6, 0],
    - 358 *      [0.8, 0.5],
    - 359 *      [1, 0.7]
    - 360 * ]};
    - 361 * 
    - 362 * m.mount(root, { 
    - 363 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    - 364 *          cfg.chart.title.text          = 'Simple Example';
    - 365 *          cfg.series.data   = [series];
    - 366 *          cfg.series.series = [{ x:'time', y:'volume' }];
    - 367 *      }})
    - 368 * });
    - 369 *
    - 370 * 
    - 371 * 
    - 372 * .hs-graph-chart { fill: #fff; }
    - 373 * .hs-graph-series { stroke-width: 5; }
    - 374 * 
    - 375 * 

    - 376 */

    - 377class ExampleLinearAxis {}
    - 378
    - 379/**
    - 380* ### Logarithmic Axis
    - 381
    - 382
    - 383* let series = {
    - 384*    colNames:['time', 'volume'],
    - 385*    rows:[[0.3, 0.2], [0.32, 0.7], [0.4, 8], [0.56, 10], [0.7, 0.5], [0.8, 15]]
    - 386* };
    - 387
    - 388* m.mount(root, { 
    - 389*      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    - 390*          cfg.chart.title.text = 'Log Y Axis';
    - 391*          cfg.series.data   = [series];
    - 392*          cfg.series.series = [{ x'time', y:'volume' }];
    - 393*          cfg.axes.primary.x.scale.type = hsgraph.Axes.type.log;
    - 394*          cfg.axes.primary.x.scale.domain = ['tight', 'tight'];
    - 395*          cfg.axes.primary.y.scale.type = hsgraph.Axes.type.log;
    - 396*          cfg.axes.primary.y.scale.domain = ['auto', 'auto'];
    - 397*          cfg.grid.minor.hor.visible = true;
    - 398*          cfg.grid.minor.ver.visible = true;
    - 399*      }})
    - 400* });
    - 401*
    - 402
    - 403

    - 404*/

    - 405class ExampleLogAxis {}
    - 406
    - 407/**
    - 408* ### Date Axis
    - 409
    - 410
    - 411* let series = {
    - 412*    colNames:['time', 'volume'],
    - 413*    rows:[['2/6/17', 0.2], ['3/18/17', 0.7], ['5/1/17', 8], ['11/20/17', 10], ['1/15/18', 0.5]]
    - 414* };
    - 415
    - 416* m.mount(root, { 
    - 417*      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    - 418*          cfg.chart.title.text = 'Date X Axis';
    - 419*          cfg.series.data   = [series];
    - 420*          cfg.series.series = [{ x:'time', y:'volume' }];
    - 421*          cfg.axes.primary.x.scale.type = hsgraph.Axes.type.date;
    - 422*          cfg.axes.primary.x.ticks.major.labelFmt = '%MMM %YY';
    - 423*      }})
    - 424* });
    - 425*
    - 426
    - 427
    - 428* .hs-graph-series { stroke-width: 5; }
    - 429
    - 430

    - 431*/

    - 432class ExampleDateAxis {}
    - 433
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/AxesCfg.html b/docs/src/hsGraph/AxesCfg.html deleted file mode 100644 index 10a4bac..0000000 --- a/docs/src/hsGraph/AxesCfg.html +++ /dev/null @@ -1,234 +0,0 @@ - - -

    AxesCfg.ts

    -
       1/**
    -   2 * # AxesCfg
    -   3 * sets the default configuration for the primary and secondary axes
    -   4 * 
    -   5 * ### Configurations and Defaults
    -   6 * ```
    -   7 *  {@link Axes.AxesSet AxesSet}:
    -   8 *  primary: {                          // Primary axis:
    -   9 *      x: {                            // {@link Axes.AxisCfg AxisCfg}
    -  10 *          visible: true,              // axis visibility
    -  11 *          crossesAt:'min',            // axis crossing in domain: 'min', 'max', or domain value
    -  12 *          scale: {                    // {@link Axes.ScaleCfg ScaleCfg}; axis scaling information
    -  13 *              type: 'linear',             
    -  14 *              domain:['auto', 'auto'] // min/max of domain; set to autodetect
    -  15 *          },
    -  16 *          title: {                    // {@link Axes.AxisTitleCfg AxisTitleCfg}; axis title configuration
    -  17 *              visible: true,  text: 'x'                   
    -  18 *              hAlign:  'end', vAlign:  'top',             
    -  19 *              hOffset: -2,    vOffset: 0.4                
    -  20 *          },
    -  21 *          ticks: {                    // tick mark configuration
    -  22 *              major: {                // {@link Axes.TickStruct TickStruct}; major ticks
    -  23 *                  marks: { visible: true, length: 10 },  
    -  24 *                  labels: { hAlign: 'middle', vAlign: 'top', hOffset: 0, vOffset: 0.7 }      
    -  25 *              },
    -  26 *              minor: {                // {@link Axes.TickStruct TickStruct}; minor ticks
    -  27 *                  marks: { visible: true,  length: 5 },
    -  28 *                  labels: { hAlign: 'middle', vAlign: 'top', hOffset: 0, vOffset: 0.7 }
    -  29 *              }   
    -  30 *          } 
    -  31 *      },
    -  32 *      y: {visible: true, 
    -  33 *          crossesAt:'min',
    -  34 *          scale: {       
    -  35 *              type: 'linear', 
    -  36 *              domain:['auto', 'auto']  
    -  37 *          },
    -  38 *          title: {text:'y', visible:true,
    -  39 *              hAlign:  'middle', hOffset: 0,
    -  40 *              vAlign:  'bottom', vOffset: -0.5
    -  41 *          },
    -  42 *          ticks: { 
    -  43 *              major: { marks: { visible:true, length:10 },
    -  44 *                      labels:{ hAlign: 'end', vAlign: 'center', hOffset: -0.7, vOffset: 0 }
    -  45 *              }, 
    -  46 *              minor: { marks: { visible:true, length:5 },
    -  47 *                       labels:{ hAlign: 'end', vAlign: 'center', hOffset: -0.7, vOffset: 0 }
    -  48 *              } 
    -  49 *          }
    -  50 *      }
    -  51 *  },
    -  52 *  secondary: {                        // Secondary axis:
    -  53 *      x: {visible: true, 
    -  54 *          crossesAt:'max',
    -  55 *          scale: {       
    -  56 *              type: 'linear', 
    -  57 *              domain:['auto', 'auto']  
    -  58 *          },
    -  59 *          title: {text:'x2', visible:true, 
    -  60 *                  hAlign:  'end', hOffset: -2,
    -  61 *                  vAlign:  'top', vOffset: -1.2
    -  62 *          },
    -  63 *          ticks: { 
    -  64 *              major: { marks: { visible:true, length:-10 },
    -  65 *                          labels:{ hAlign: 'middle', vAlign: 'bottom', hOffset: 0, vOffset: -0.7 }
    -  66 *              }, 
    -  67 *              minor: { marks: { visible:true, length:-5 },
    -  68 *                          labels:{ hAlign: 'middle', vAlign: 'bottom', hOffset: 0, vOffset: -0.7 }
    -  69 *              } 
    -  70 *          }
    -  71 *      },
    -  72 *      y: {visible: true, 
    -  73 *          crossesAt:'max',
    -  74 *          scale: {       
    -  75 *              type: 'linear', 
    -  76 *              domain:['auto', 'auto']  
    -  77 *          },
    -  78 *          title: {text:'y2', visible:true, 
    -  79 *                  hAlign:  'start', hOffset: 0.3,
    -  80 *                  vAlign:  'top', vOffset: 0.7
    -  81 *          },
    -  82 *          ticks: { 
    -  83 *              major: { marks: { visible:true, length:-10 },
    -  84 *                          labels:{ hAlign: 'start', vAlign: 'center', hOffset: 0.7, vOffset: 0 }
    -  85 *              }, 
    -  86 *              minor: { marks: { visible:true, length:-5 },
    -  87 *                          labels:{ hAlign: 'start', vAlign: 'center', hOffset: 0.7, vOffset: 0 }
    -  88 *              } 
    -  89 *          }
    -  90 *      }
    -  91 *  }
    -  92 * ```
    -  93 */

    -  94
    -  95/** */
    -  96import { Config }   from './Graph';
    -  97import { TitleCfg } from './SVGElem';
    -  98import { AxesSet, ScaleCfg, TickStruct }    
    -  99                    from './Axes';
    - 100
    - 101/** Defines coinfigurable settings per axis */
    - 102export interface AxisCfg {
    - 103    /** determines if the axis will be rendered */
    - 104    visible:    boolean;     
    - 105     
    - 106    /** configures the axis title; see {@link SVGElem.TitleCfg TitleCfg} */  
    - 107    title:      TitleCfg;
    - 108
    - 109    /** axis crossing in domain: 'min', 'max', or domain value */
    - 110    crossesAt:  number|string; 
    - 111
    - 112    /** scale type and domain; see {@link Axes.ScaleCfg ScaleCfg} */
    - 113    scale: ScaleCfg;
    - 114
    - 115    /** configures the major and minor ticks; see {@link Axes.TickStruct TickStruct} */
    - 116    ticks: {
    - 117        major:  TickStruct;
    - 118        minor:  TickStruct;
    - 119    };
    - 120}
    - 121
    - 122export function configAxes(config:Config):AxesSet { return {
    - 123    primary: {
    - 124        x: {visible: true,              // axis visibility
    - 125            crossesAt:'min',            // axis crossing in domain: 'min', 'max', or domain value
    - 126            scale: {                    // axis scaling information
    - 127                type: 'linear',         //    scale type: 'linear'|'log'|'date'|'index'|'percent'|'ordinal'|'nominal'
    - 128                domain:['auto', 'auto'] //    min/max of domain; set to autodetect
    - 129            },
    - 130            title: {          // axis title configuration
    - 131                visible: true,          //    title visibility
    - 132                text:    'x',           //    title text
    - 133                xpos:  'end',           // label text-align: 'start' | 'middle' | 'end'
    - 134                ypos:  'top',           // label  vertical align: 'top' | 'center' | 'bottom'
    - 135                hOffset: -2,            // horizontal label offset in 'em'
    - 136                vOffset: 0.4            // vertical label offset in 'em'
    - 137            },
    - 138            ticks: {                    // tick mark configuration
    - 139                major: {                // major ticks:
    - 140                    marks: {            // tick marks:
    - 141                        visible: true,  //    tick visibility
    - 142                        length: 10      //    tick length in viewBox coordinates
    - 143                    },  
    - 144                    labels: {           // tick labels:
    - 145                        xpos: 'middle', //    label text-align: 'start' | 'middle' | 'end'
    - 146                        ypos: 'top',    //    label vertical align: 'top' | 'center' | 'bottom'
    - 147                        hOffset: 0,     //    horizontal label offset in 'em'
    - 148                        vOffset: 0.7    //    vertical label offset in 'em'
    - 149                    }      
    - 150                },
    - 151                minor: { marks: { visible: true,  length: 5, },
    - 152                            labels:{ xpos: 'middle', ypos: 'top', hOffset: 0, vOffset: 0.7 }      
    - 153                }
    - 154            } // length of tick marks
    - 155        },
    - 156        y: {visible: true, 
    - 157            crossesAt:'min',
    - 158            scale: {       
    - 159                type: 'linear', 
    - 160                domain:['auto', 'auto']  
    - 161            },
    - 162            title: {text:'y', visible:true,
    - 163                    xpos:  'middle', hOffset: 0,
    - 164                    ypos:  'bottom', vOffset: -0.5
    - 165            },
    - 166            ticks: { 
    - 167                major: { marks: { visible:true, length:10 },
    - 168                            labels:{ xpos: 'end', ypos: 'center', hOffset: -0.7, vOffset: 0 }
    - 169                }, 
    - 170                minor: { marks: { visible:true, length:5 },
    - 171                            labels:{ xpos: 'end', ypos: 'center', hOffset: -0.7, vOffset: 0 }
    - 172                } 
    - 173            }
    - 174        }
    - 175    },
    - 176    secondary: {
    - 177        x: {visible: false, 
    - 178            crossesAt:'max',
    - 179            scale: {       
    - 180                type: 'linear', 
    - 181                domain:['auto', 'auto']  
    - 182            },
    - 183            title: {text:'x2', visible:true, 
    - 184                    xpos:  'end', hOffset: -2,
    - 185                    ypos:  'top', vOffset: -1.2
    - 186            },
    - 187            ticks: { 
    - 188                major: { marks: { visible:true, length:-10 },
    - 189                            labels:{ xpos: 'middle', ypos: 'bottom', hOffset: 0, vOffset: -0.7 }
    - 190                }, 
    - 191                minor: { marks: { visible:true, length:-5 },
    - 192                            labels:{ xpos: 'middle', ypos: 'bottom', hOffset: 0, vOffset: -0.7 }
    - 193                } 
    - 194            }
    - 195        },
    - 196        y: {visible: false, 
    - 197            crossesAt:'max',
    - 198            scale: {       
    - 199                type: 'linear', 
    - 200                domain:['auto', 'auto']  
    - 201            },
    - 202            title: {text:'y2', visible:true, 
    - 203                    xpos:  'start', hOffset: 0.3,
    - 204                    ypos:  'top', vOffset: 0.7
    - 205            },
    - 206            ticks: { 
    - 207                major: { marks: { visible:true, length:-10 },
    - 208                            labels:{ xpos: 'start', ypos: 'center', hOffset: 0.7, vOffset: 0 }
    - 209                }, 
    - 210                minor: { marks: { visible:true, length:-5 },
    - 211                            labels:{ xpos: 'start', ypos: 'center', hOffset: 0.7, vOffset: 0 }
    - 212                } 
    - 213            }
    - 214        }
    - 215    }
    - 216};}
    - 217
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/AxesDefaultCfg.html b/docs/src/hsGraph/AxesDefaultCfg.html deleted file mode 100644 index 96a1a1d..0000000 --- a/docs/src/hsGraph/AxesDefaultCfg.html +++ /dev/null @@ -1,181 +0,0 @@ - - -

    AxesDefaultCfg.ts

    -
       1/**
    -   2 * # AxesCfg
    -   3 * sets the default configuration for the primary and secondary axes
    -   4 * 
    -   5 * ### Configurations and Defaults
    -   6 * See {@link AxesDefaultCfg.configAxes configAxes}
    -   7 */

    -   8
    -   9/** */
    -  10import { Config }               from './Graph';
    -  11import { TitleCfg }             from './SVGElem';
    -  12import { Scale, ScaleCfg, DomainCfg }  from './Scale';
    -  13import { AxesSet, MarkCfg, TicksCfg }    from './Axes';
    -  14
    -  15/** Defines configurable settings per axis */
    -  16export interface AxisCfg {
    -  17    /** determines if the axis will be rendered */
    -  18    visible:    boolean;     
    -  19     
    -  20    /** configures the axis title */  
    -  21    title:      TitleCfg;
    -  22
    -  23    /** axis crossing in domain: 'min', 'max', or domain value */
    -  24    crossesAt:  number|string; 
    -  25
    -  26    /** scale type and domain */
    -  27    scale: ScaleCfg;
    -  28
    -  29    /** configures the major and minor ticks */
    -  30    ticks: TicksCfg;
    -  31}
    -  32
    -  33/**
    -  34 * # configAxes
    -  35 * sets the default configuration for the primary and secondary axes
    -  36 * 
    -  37 * ### Configurations and Defaults
    -  38 * #### defaultScale: {@link Scale.ScaleCfg Scale.ScaleCfg} =
    -  39 * ```
    -  40 *  {
    -  41 *      type: Scale.type.linear,   // {@link Scale.Scale.type Scale.type} 
    -  42 *      domain:['auto', 'auto']    // {@link Scale.DomainCfg Scale.DomainCfg}: min/max of domain; 'auto', or a domain value
    -  43 *  }
    -  44 * ```
    -  45 * #### cfg...title: {@link SVGElem.TitleCfg titleCfg} =
    -  46 * ```
    -  47 *  {
    -  48 *     visible: true,  
    -  49 *     text:    (x? 'x' : 'y') + (primary? '' : '2'),    // 'x'/'y' or 'x2'/'y2'
    -  50 *     xpos:    x? 'end' : (primary? 'middle' : 'start'),          
    -  51 *     ypos:    x? 'top' : (primary? 'bottom' : 'top'),           
    -  52 *     hOffset: x? -2 : (primary? 0 : 0.3),            
    -  53 *     vOffset: x? (primary? 0.4 : -1.2) : (primary? -0.5 : 0.7) 
    -  54 *  }      
    -  55 * ```
    -  56 * #### cfg..ticks..marks: {@link AxisDefaultCfg.MarkCfg markCfg} =
    -  57 * ```
    -  58 *  {
    -  59 *     visible: true, 
    -  60 *     length: (primary? 1 : -1) * (major? 10 : 5) 
    -  61 *  }      
    -  62 * ```
    -  63 * #### cfg..ticks..labels: {@link SVGElem.TitleCfg labelCfg} =
    -  64 * ```
    -  65 *  {
    -  66 *     visible: true, 
    -  67 *     xpos: x? 'middle' : (primary? 'end' : 'start')
    -  68 *     ypos: x? (primary? 'top' : 'bottom') : 'center', 
    -  69 *     hOffset: x? 0 (primary? -0.7 : 0.7), 
    -  70 *     vOffset: x? (primary? 0.7 : -0.7) : 0
    -  71 *  }      
    -  72 * ```
    -  73 * #### cfg..: {@link Axis.AxisCfg axisCfg} =
    -  74 * ```
    -  75 *  {
    -  76 *     visible:    primary? true : false,   // hide secondary axes
    -  77 *     crossesAt:  primary?'min':'max',     // default axis crossing
    -  78 *     scale:      defaultScale,            // see above
    -  79 *     title:      titleCfg(primary, x),
    -  80 *     ticks: {                    
    -  81 *         major: {                
    -  82 *             marks: markCfg(primary, true),  
    -  83 *             labels: tickLabelCfg(primary, x)      
    -  84 *         },
    -  85 *         minor: { 
    -  86 *             marks: markCfg(primary, false),
    -  87 *             labels: tickLabelCfg(primary, x)     
    -  88 *         }
    -  89 *     } 
    -  90 *  }
    -  91 * ```
    -  92 * #### cfg.axes: {@link Axes.AxesSet AxesSet} =
    -  93 * ```
    -  94 * {
    -  95 *    primary: {                // Primary axis:
    -  96 *       x: axisCfg(true, true),
    -  97 *       y: axisCfg(true, false)
    -  98 *    },
    -  99 *    secondary: {               // Secondary axis:
    - 100 *       x: axisCfg(false, true),
    - 101 *       y: axisCfg(false, false)
    - 102 *    }
    - 103 *  }
    - 104 * ```
    - 105 */

    - 106export function configAxes(cfg:Config):AxesSet { 
    - 107    const defaultScale:ScaleCfg = {                  // axis scaling information
    - 108        type: Scale.type.linear,            //    scale type
    - 109        domain:['auto', 'auto']  //    min/max of domain; 'auto', or a domain value
    - 110    };
    - 111    function labelCfg(primary:boolean, x:boolean):TitleCfg {
    - 112        return { 
    - 113            visible: true, text: '', 
    - 114            xpos: x? 'middle' : (primary? 'end' : 'start'),
    - 115            ypos: x? (primary? 'top' : 'bottom') : 'center', 
    - 116            hOffset: x? 0 : (primary? -0.7 : 0.7), 
    - 117            vOffset: x? (primary? 0.7 : -0.7) : 0
    - 118        }; 
    - 119    }
    - 120    function markCfg(primary: boolean, major:boolean):MarkCfg {
    - 121        return { 
    - 122            visible: true, 
    - 123            length: (primary? 1 : -1) * (major? 10 : 5) 
    - 124        };
    - 125    }
    - 126    function titleCfg(primary:boolean, x:boolean):TitleCfg {
    - 127        return {
    - 128            visible: true,  text: (x? 'x' : 'y') + (primary? '' : '2'),    
    - 129            xpos:  x? 'end' : (primary? 'middle' : 'start'),          
    - 130            ypos:  x? 'top' : (primary? 'bottom' : 'top'),           
    - 131            hOffset: x? -2 : (primary? 0 : 0.3),            
    - 132            vOffset: x? (primary? 0.4 : -1.2) : (primary? -0.5 : 0.7)       
    - 133        };
    - 134    }
    - 135    function axisCfg(primary:boolean, x:boolean):AxisCfg {
    - 136        return {
    - 137            visible:    primary? true : false, 
    - 138            crossesAt:  primary?'min':'max', 
    - 139            scale:      defaultScale,
    - 140            title: titleCfg(primary, x),
    - 141            ticks: {                    
    - 142                major: {                
    - 143                    marks:  markCfg(primary, true),  
    - 144                    labels: labelCfg(primary, x)      
    - 145                },
    - 146                minor: { 
    - 147                    marks:  markCfg(primary, false),
    - 148                    labels: labelCfg(primary, x)     
    - 149                }
    - 150            } 
    - 151        };
    - 152    }
    - 153    return {
    - 154        primary: {
    - 155            x: axisCfg(true, true),
    - 156            y: axisCfg(true, false)
    - 157        },
    - 158        secondary: {
    - 159            x: axisCfg(false, true),
    - 160            y: axisCfg(false, false)
    - 161        }
    - 162    };
    - 163}
    - 164
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/AxesTypes.html b/docs/src/hsGraph/AxesTypes.html deleted file mode 100644 index 5182d2b..0000000 --- a/docs/src/hsGraph/AxesTypes.html +++ /dev/null @@ -1,110 +0,0 @@ - - -

    AxesTypes.ts

    -
       1/**
    -   2 * @module Axes
    -   3 */

    -   4
    -   5 /** */
    -   6import { VisibleCfg, 
    -   7         LabelCfg } from './Graph';
    -   8import { Scale }    from './Scale';
    -   9import { Domain }   from 'hsdata';
    -  10
    -  11/** Set of `Scales` for x- and y-axis*/
    -  12export interface XYScale { x: Scale; y:Scale; }
    -  13
    -  14/** Set of `Scales` for primary and secondary x- and y-axes. */
    -  15export interface Scales {
    -  16    primary:   XYScale;
    -  17    secondary: XYScale;
    -  18}
    -  19
    -  20/**
    -  21 * Configures the scale type and domain boundaries `[min, max]` to be displayed.
    -  22 */

    -  23export interface ScaleCfg {
    -  24    /** scale type: {@link Axes.Axes.type Axes.type}.`linear` | `log` | `date` | `index` | `percent` | `ordinal` | `nominal` */
    -  25    type: string;
    -  26
    -  27    /**
    -  28     * Configures the domain boundaries `[min, max]` to be displayed.
    -  29     * For ordinal values these are the numeric min and max values of the domain,
    -  30     * or the special values 
    -  31     * - `auto`: determines the domain automatically from the data. Boundaries are set 'loosely' 
    -  32     *   so that the major tick mark below and above the data range are displayed as well.
    -  33     * - `tight`: same as `auto`, except the domain covers exactly the values contained in data. 
    -  34     * Both values can be set indepoendently for `min` and `max`
    -  35     */

    -  36    domain: Domain;
    -  37}
    -  38
    -  39export interface Ticks {
    -  40    major: TickDefs;
    -  41    minor: TickDefs;
    -  42}
    -  43
    -  44export interface TickLabel {
    -  45    pos:number;     // domain value, at which to print tick label
    -  46    text:string;    // string to print at labelPos
    -  47}
    -  48
    -  49export interface TickDefs {
    -  50    marks:  number[];   // domain values where to draw a mark
    -  51    labels: TickLabel[];// 
    -  52};
    -  53
    -  54/** Defines configurable settings for tick marks */
    -  55export interface MarkCfg extends VisibleCfg {
    -  56    /** length in viewBox coordinates */
    -  57    length:  number; 
    -  58}
    -  59
    -  60/** Defines configurable settings for tick marks and labels per axis */
    -  61export interface TickStruct {
    -  62    marks:  MarkCfg;
    -  63    labels: LabelCfg;
    -  64    labelFmt: string;
    -  65}
    -  66
    -  67/** Defines configurable settings for major and minor ticks (marks and labels) */
    -  68export interface TicksCfg {
    -  69    major:  TickStruct;
    -  70    minor:  TickStruct;
    -  71}
    -  72
    -  73/** Defines configurable settings. */
    -  74export interface AxesConfig  {
    -  75    primary:   { x: AxisCfg; y: AxisCfg; };
    -  76    secondary: { x: AxisCfg; y: AxisCfg; };
    -  77}
    -  78
    -  79/** Defines configurable settings per axis */
    -  80export interface AxisCfg extends VisibleCfg{
    -  81    /** configures the axis title */  
    -  82    title:      LabelCfg;
    -  83
    -  84    /** axis crossing in domain: 'min', 'max', or domain value */
    -  85    crossesAt:  number|string; 
    -  86
    -  87    /** axis type  */
    -  88    scale: ScaleCfg;
    -  89
    -  90    /** configures the major and minor ticks */
    -  91    ticks: TicksCfg;
    -  92}
    -  93
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Canvas.html b/docs/src/hsGraph/Canvas.html deleted file mode 100644 index 99c42d8..0000000 --- a/docs/src/hsGraph/Canvas.html +++ /dev/null @@ -1,89 +0,0 @@ - - -

    Canvas.ts

    -
       1/**
    -   2 * # Canvas
    -   3 * renders the graph's background.
    -   4 * 
    -   5 * ### Attributes
    -   6 * The `Canvas` class is called by {@link Graph.Graph `Graph`} as 
    -   7 * `m(Canvas, { cfg:cfg.canvas}))`
    -   8 * with the following attributes:
    -   9 * - cfg: a {@link Canvas.CanvasConfig `CanvasConfig`} configuration object
    -  10 * 
    -  11 * ### Configurations and Defaults
    -  12 * See {@link Canvas.Canvas.defaultConfig Canvas.defaultConfig}
    -  13 */

    -  14
    -  15/** */
    -  16import { m, Vnode}              from 'hslayout';
    -  17import { SVGElem, Area }        from './SVGElem';
    -  18import { Config, VisibleCfg }   from './Graph';
    -  19
    -  20
    -  21/** Defines configurable settings. */
    -  22export interface CanvasConfig extends VisibleCfg{
    -  23    range?:  Area;              // graph width and height
    -  24}
    -  25
    -  26export class Canvas extends SVGElem {
    -  27    /** 
    -  28     * Defines default values for all configurable parameters in `Graph`.
    -  29     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    -  30     * 
    -  31     * ### Configurations and Defaults
    -  32     * ```
    -  33     *  cfg.canvas = {@link Canvas.CanvasConfig }{
    -  34     *     range: {         // the graphs background rect:
    -  35     *        w: 100,       //    width
    -  36     *        h: 100,       //    height
    -  37     *        wunit:'%',    //    unit for width
    -  38     *        hunit:'%'     //    unit for height
    -  39     *     }   
    -  40     *  } 
    -  41     * ``` 
    -  42     * @param cfg the configuration object, containing default settings for all 
    -  43     * previously configured components. 
    -  44     */

    -  45    static defaultConfig(cfg:Config) {
    -  46        cfg.canvas = {
    -  47            range:  { // graph width and height
    -  48                w: 100, wunit:'%',
    -  49                h: 100, hunit:'%'
    -  50            }  
    -  51        };
    -  52    }
    -  53
    -  54    /**
    -  55     * Makes adjustments to cfg based on current settings
    -  56     * @param cfg the configuration object, containing default settings for all components
    -  57     */

    -  58    static adjustConfig(cfg:Config) {
    -  59    }
    -  60    
    -  61    view(node?: Vnode): Vnode {
    -  62        const cg = node.attrs.cfg;
    -  63        return m('svg', {class: 'hs-graph-canvas'}, [
    -  64            this.rect({x:0, y:0},
    -  65                { w:cg.range.w, h:cg.range.h, wunit:cg.range.wunit, hunit:cg.range.hunit},
    -  66                '' // style string
    -  67            )
    -  68        ]);
    -  69    }
    -  70}
    -  71
    -  72
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Chart.html b/docs/src/hsGraph/Chart.html deleted file mode 100644 index 969ee24..0000000 --- a/docs/src/hsGraph/Chart.html +++ /dev/null @@ -1,148 +0,0 @@ - - -

    Chart.ts

    -
       1/**
    -   2 * # Chart
    -   3 * renders the chart background and title.
    -   4 * 
    -   5 * ### Attributes
    -   6 * The `Chart` class is called by {@link Graph.Graph `Graph`} as 
    -   7 * `m(Chart, { cfg:cfg.chart, plotArea:plotArea })`
    -   8 * with the following attributes:
    -   9 * - cfg: a {@link Chart.ChartConfig ChartConfig} object
    -  10 * - plotArea: a {@link SVGElem.Rect Rect } object for plotting the chart background
    -  11 * 
    -  12 * ### Configurations and Defaults
    -  13 * See {@link Chart.Chart.defaultConfig Chart.defaultConfig}
    -  14 */

    -  15
    -  16 /** */
    -  17import { m, Vnode}          from 'hslayout';
    -  18import { Config, 
    -  19         LabelCfg,
    -  20         VisibleCfg }       from './Graph';
    -  21import { SVGElem,  Rect }   from './SVGElem';
    -  22
    -  23
    -  24/** Defines configurable settings. */
    -  25export interface ChartConfig extends VisibleCfg {
    -  26    /** the title text and positioning  */
    -  27    title:  LabelCfg;
    -  28};
    -  29
    -  30/**
    -  31 * Renders the chart background and title.
    -  32 */

    -  33export class Chart extends SVGElem { 
    -  34    /** 
    -  35     * Defines default values for display elements in `Chart`
    -  36     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    -  37     * 
    -  38     * ### Configurations and Defaults
    -  39     * ```
    -  40     *  cfg.chart = {@link Chart.ChartConfig }{
    -  41     *     visible: true,          // Chart area is visible
    -  42     *     title:  {               // the chart title
    -  43     *        visible: true,      // Chart title is visible
    -  44     *        text:'',            // the sting to display
    -  45     *        hOffset: 0,         // horizontal label offset in 'em'
    -  46     *        vOffset: -1.5,      // vertical label offset in 'em'
    -  47     *        xpos:'middle',      // hor. title position: 0-100%, rel. to Chart
    -  48     *        ypos:'top'          // ver. title position: 0-100%, rel. to Chart
    -  49     *     }   
    -  50     *  } 
    -  51     * ``` 
    -  52     * @param cfg the configuration object, containing default settings for all 
    -  53     * previously configured components.
    -  54     */

    -  55    static defaultConfig(cfg:Config) {
    -  56        cfg.chart = {
    -  57            visible: true,          // Chart area is visible
    -  58            title:  {     // the chart title
    -  59                visible: true,      // Chart title is visible
    -  60                text:'',            // the sting to display
    -  61                hOffset: 0,         // horizontal label offset in 'em'
    -  62                vOffset: -1.5,      // vertical label offset in 'em'
    -  63                xpos:'middle',      // hor. title position: 0-100%, rel. to Chart
    -  64                ypos:'top'          // ver. title position: 0-100%, rel. to Chart
    -  65            }
    -  66        };
    -  67    return cfg;
    -  68    }
    -  69
    -  70    /**
    -  71     * Makes adjustments to cfg based on current settings
    -  72     * @param cfg the configuration object, containing default settings for all components
    -  73     */

    -  74    static adjustConfig(cfg:Config) {        
    -  75    }
    -  76    
    -  77    static clientWidth:number;
    -  78    static clientHeight:number;
    -  79
    -  80    onupdate(node?: Vnode) { 
    -  81        this.updateTitleSize(node);
    -  82//                m.redraw();
    -  83    }
    -  84
    -  85    updateTitleSize(node: Vnode) {
    -  86        // get clientWidth /Height of title
    -  87        if (node.dom) {
    -  88            const c = node.dom.lastChild;
    -  89            if (c && c.clientWidth>0) {
    -  90                if (Chart.clientWidth !== c.clientWidth) {
    -  91                    Chart.clientWidth = c.clientWidth;
    -  92                    Chart.clientHeight = c.clientHeight;
    -  93                }
    -  94            }
    -  95        }
    -  96    }
    -  97
    -  98    drawBackground(plotArea:Rect) {
    -  99        const tl = plotArea.tl;
    - 100        const br = plotArea.br;
    - 101        return this.rect({x:tl.x, y:tl.y}, {w: br.x-tl.x, h: br.y-tl.y},'');
    - 102    }
    - 103
    - 104    drawTitle(plotArea:Rect, cfg:ChartConfig) {
    - 105        const tl = plotArea.tl;
    - 106        const br = plotArea.br;
    - 107        cfg.title.cssClass = 'hs-graph-chart-title';
    - 108        switch(cfg.title.xpos) {
    - 109            case 'start':   cfg.title.x = tl.x+'';   break;
    - 110            case 'middle':  cfg.title.x = (tl.x+br.x)/2+'';  break;
    - 111            case 'end':     cfg.title.x = br.x+''; break;
    - 112        }
    - 113        switch(cfg.title.ypos) {
    - 114            case 'top':     cfg.title.y = tl.y+'';   break;
    - 115            case 'center':  cfg.title.y = (tl.y+br.y)/2+'';  break;
    - 116            case 'bottom':  cfg.title.y = br.y+''; break;
    - 117        }
    - 118        return !cfg.title.visible? undefined : this.text(cfg.title, cfg.title.text);
    - 119    }
    - 120
    - 121    view(node?: Vnode): Vnode {
    - 122        const cfg:ChartConfig = node.attrs.cfg;
    - 123        const plotArea:Rect = node.attrs.plotArea;
    - 124        return m('svg', { class:'hs-graph-chart'}, [
    - 125            this.drawBackground(plotArea),
    - 126            this.drawTitle(plotArea, cfg)
    - 127        ]);
    - 128    }
    - 129}
    - 130
    - 131
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Config.html b/docs/src/hsGraph/Config.html deleted file mode 100644 index d8671e1..0000000 --- a/docs/src/hsGraph/Config.html +++ /dev/null @@ -1,40 +0,0 @@ - - -

    Config.ts

    -
       1import { ScaleSet }     from './Scale';
    -   2import { GraphSet }     from './Graph';
    -   3import { AxisSet }      from './Axes';
    -   4import { SeriesSet }    from './Series';
    -   5import { ChartSet }     from './Chart';
    -   6import { GridSet }      from './Grid';
    -   7
    -   8export interface Config {
    -   9    scale?:  ScaleSet;
    -  10    graph?:  GraphSet;
    -  11    axes?:   AxisSet;
    -  12    chart?:  ChartSet;
    -  13    grid?:   GridSet;
    -  14    series?: SeriesSet;
    -  15    title?:{
    -  16        text?: string;
    -  17        align?: {h:string; v:string}   // h: center | left | right; v: center | top  | bottom
    -  18    };
    -  19    legend?:{
    -  20
    -  21    };
    -  22}
    -  23
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Data.html b/docs/src/hsGraph/Data.html deleted file mode 100644 index 78f43d1..0000000 --- a/docs/src/hsGraph/Data.html +++ /dev/null @@ -1,351 +0,0 @@ - - -

    Data.ts

    -
       1/**
    -   2 * 
    -   3 */

    -   4
    -   5
    -   6import { Scales }       from './AxesTypes';
    -   7import { SeriesDef, 
    -   8         SeriesConfig } from './Series';
    -   9
    -  10/** defines a [min-max] range */
    -  11export type NumRange = [number, number];
    -  12
    -  13/** defines a numeric domain that includes all values of a column */
    -  14export type NumDomain = [number, number];
    -  15
    -  16/** defines a Date domain that includes all values of a column */
    -  17export type DateDomain = [Date, Date];
    -  18
    -  19/** defines a categorical domain that includes all values of a column */
    -  20export type NameDomain = string[];
    -  21
    -  22/** defines a generic domain that can be any of the typed domains. */
    -  23export type Domain = NumDomain | DateDomain | NameDomain;
    -  24
    -  25/** defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    -  26export type ColSpecifier = number|string;
    -  27
    -  28/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    -  29export type DataVal = number|string|Date;
    -  30
    -  31/** a single row of column values */
    -  32export type DataRow = DataVal[];
    -  33
    -  34/** a row-of-column array of data. Values are accessed as `data[row][column]` */
    -  35export type DataRows = DataRow[];
    -  36
    -  37/** 
    -  38 * Description of a data set:
    -  39 * ```
    -  40 * {
    -  41 *    names: string[],  // array of names for columns in `rows` 
    -  42 *    rows:  DataRows   // row array of columns, accessed as `` 
    -  43 * }
    -  44 * ```
    -  45 */

    -  46export type DataSet = {
    -  47    names: string[];
    -  48    rows:  DataRows;
    -  49};
    -  50
    -  51interface TypeStruct { type: string; count: number;};
    -  52
    -  53interface MetaStruct {
    -  54    name:       string;         // column name
    -  55    column:     number;         // column index
    -  56    accessed:   boolean;        // has column data been accessed?
    -  57    cast:       boolean;        // has column data been cast 
    -  58    types:      TypeStruct[];   // data types, sorted by likelihood
    -  59}
    -  60
    -  61export class Data {
    -  62    public static type = {
    -  63        number:     'number data',
    -  64        name:       'name data',
    -  65        date:       'date data',
    -  66        currency:   'currency data',
    -  67        percent:    'percent data',
    -  68        nominal:    'nominal data'
    -  69    };
    -  70    private data: DataRows;
    -  71    private meta: MetaStruct[] = [];
    -  72
    -  73    private getMeta(col:ColSpecifier):MetaStruct { 
    -  74        if (!this.meta) { this.meta = []; }
    -  75        if (!this.meta[col]) { return undefined; }
    -  76        this.meta[col].accessed = true;
    -  77        return this.meta[col]; 
    -  78    }
    -  79
    -  80    private addColumn(newCol:string):number {
    -  81        var m = this.getMeta(newCol);
    -  82        if (m === undefined) { 
    -  83            m = this.meta[newCol] = {};
    -  84            m.name   = newCol; 
    -  85            m.column = this.meta.length;
    -  86            this.meta.push(m);      // access name by both column name and index
    -  87        }
    -  88        m.cast     = false;         // has not been cast yet
    -  89        m.accessed = false;         // has not been accessed yet
    -  90        return this.meta.length-1;
    -  91    }
    -  92
    -  93     
    -  94    /**
    -  95     * returns the column index of the specified column. 
    -  96     * `col` can be either an index or a name.
    -  97     * @param column the data column, name or index, for which to return the index. 
    -  98     * @return the column number or `undefined`.
    -  99     */

    - 100    public colNumber(col:ColSpecifier) {
    - 101        var m = this.getMeta(col);
    - 102        if (!m) { return undefined; }
    - 103        else {
    - 104            m.accessed = true; 
    - 105            return m.column; 
    - 106        }
    - 107    }
    - 108    
    - 109    /**
    - 110     * returns the column name for the specified column. 
    - 111     * `col` can be either an index or a name.
    - 112     * @param column the data column, name or index. 
    - 113     * @return the column name or `undefined`.
    - 114     */

    - 115    public colName(col:ColSpecifier) {
    - 116        var m = this.getMeta(col);
    - 117        if (!m) { return undefined; }
    - 118        m.accessed = true; 
    - 119        return m.name; 
    - 120    }
    - 121
    - 122    /**
    - 123     * returns the column type for the specified column. 
    - 124     * `col` can be either an index or a name.
    - 125     * @param column the data column, name or index. 
    - 126     * @return the column type.
    - 127     */

    - 128    public colType(col:ColSpecifier) { 
    - 129        return this.getMeta(col).types[0].type;
    - 130    }
    - 131
    - 132
    - 133    /**
    - 134     * Determines the type of data in `col`. An array of counts is created for all
    - 135     * encountered types, sorted by descending frequency. THe most likely type in position 0
    - 136     * of the array is returned.
    - 137     * @param col the index of the column to be typed. 
    - 138     * @return the most likely type of data in `col`.
    - 139     */

    - 140    private findTypes(col:ColSpecifier):string {
    - 141        const m = this.getMeta(col);
    - 142        const types:TypeStruct[] = [];
    - 143        Object.keys(Data.type).forEach((t:string) => {
    - 144            const ts = { type: Data.type[t], count: 0 }; 
    - 145            types.push(ts);
    - 146            types[Data.type[t]] = ts;
    - 147        });
    - 148        for (let v of this.allRows(col)) {
    - 149            const t = this.findType(v);
    - 150            if (t !== null) { types[t].count++; }
    - 151        }
    - 152        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    - 153            if (a.type==='currency'&&a.count>0) { return -1; }
    - 154            if (b.type==='currency'&&b.count>0) { return 1; }
    - 155            return b.count - a.count;
    - 156        });
    - 157        m.types = types;
    - 158        return types[0].type;
    - 159    }
    - 160
    - 161    /**
    - 162     * @description determines the data type. Supported types are 
    - 163     * ```
    - 164     * 'date':    sample represents a Date, either as a Date object or a String 
    - 165     * 'number':  sample represents a number
    - 166     * 'percent': sample represents a percentage (special case of a real number)
    - 167     * 'nominal': sample represents a nominal (ordinal or categorical) value
    - 168     * ```
    - 169     * @param val the value to bve typed.
    - 170     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    - 171     */

    - 172    private findType(val:DataVal) {
    - 173        if (val && val!=='') {
    - 174            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    - 175            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    - 176
    - 177            // else: val is a string:
    - 178            const strVal = ''+val;
    - 179            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    - 180            if (!isNaN(this.toDate(val).getTime()))                            { return Data.type.date; }
    - 181            if (val.endsWith('%') && !isNaN(parseFloat(val)))                  { return Data.type.percent; }
    - 182
    - 183            // european large number currency representation: '$dd,ddd[,ddd]'
    - 184            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    - 185                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    - 186                    return Data.type.currency; 
    - 187                }
    - 188            }
    - 189            switch (strVal.toLowerCase()) {
    - 190                case "null": break;
    - 191                case "#ref!": break;
    - 192                default: if (val.length>0) { return Data.type.nominal; }
    - 193            }
    - 194        }
    - 195        return null;
    - 196    }    
    - 197
    - 198    /**
    - 199     * modifies `domain` to include all values in column `col`.
    - 200     * @param col the column name or index 
    - 201     * @param domain the 
    - 202     */

    - 203    private findDomain(col:ColSpecifier, domain:Domain) {
    - 204        if (col === undefined) { // use array index as domain
    - 205            domain[0] = 0;
    - 206            domain[1] = this.data.length-1;
    - 207        } else {
    - 208            const c = this.colNumber(col);
    - 209            const type = this.colType(col);
    - 210            this.data.forEach((r:DataRow) => {
    - 211                switch(type) {
    - 212                    case Data.type.nominal: 
    - 213                        const nomDom = domain;
    - 214                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    - 215                        break;
    - 216                    default: 
    - 217                        let v:number = r[c];
    - 218                        domain[0] = (v - 219                        domain[1] = (v>domain[1])? v : domain[1];
    - 220                }
    - 221            });
    - 222        }
    - 223    }
    - 224
    - 225    /** 
    - 226     * determines the max ranges each coordinate of each series and auto-sets the domains on the respective scales. 
    - 227     */

    - 228    public adjustDomains(cfg:SeriesConfig, scales:Scales) {
    - 229        let domainDims = 0;
    - 230        cfg.series.forEach((s:SeriesDef) => 
    - 231            domainDims = Math.max(domainDims,s.cols.length)
    - 232        );
    - 233
    - 234        const domains:Domain[] = Array(domainDims).fill(1).map(() => [1e20, -1e20]);
    - 235    
    - 236        cfg.series.map((s:SeriesDef) => { // for each series:
    - 237            s.cols.forEach((colIdx:ColSpecifier, i:number) => {
    - 238                this.findDomain(colIdx, domains[i]);
    - 239            });
    - 240        });
    - 241        scales.primary.x.setAutoDomain(domains[0]);
    - 242        scales.primary.y.setAutoDomain(domains[1]);
    - 243    }
    - 244
    - 245    /**
    - 246     * sets `data` to the existing data set. If data has previously been set, 
    - 247     * `data` will be added to the end of the list if all `names`  match those of the 
    - 248     * existing set. 
    - 249     * @param data the data to add
    - 250     * @param names an array of names that match the columns
    - 251     * @param autoType unless set to false, the method will attempt to determine the 
    - 252     * type of data and automatically cast data points to their correct value
    - 253     */

    - 254    public setData(data:DataRows, names:ColSpecifier[], autoType=true):void {
    - 255        this.meta = undefined;
    - 256        this.data = data;
    - 257        names.forEach((col:string) => this.addColumn(col));
    - 258        names.forEach((col:string) => this.findTypes(col));
    - 259        this.castData();
    - 260    }
    - 261
    - 262    public * allRows(column:ColSpecifier):Iterable {
    - 263        const c = this.colNumber(column);
    - 264        for (let r=0; r - 265            yield this.data[r][c];
    - 266        }
    - 267    }
    - 268
    - 269    public getData():DataRows {
    - 270        return this.data;
    - 271    }
    - 272
    - 273    public castData() {
    - 274        this.meta.forEach((c:MetaStruct) => {
    - 275            const col = c.column;
    - 276            if (!c.cast) {
    - 277                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    - 278            }
    - 279            c.cast = true;
    - 280        });
    - 281    }
    - 282
    - 283    /**
    - 284     * @param str the string to convert to a data
    - 285     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    - 286     * @returns a new Date object parsed from `str`.
    - 287     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    - 288     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    - 289     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    - 290     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    - 291     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    - 292     */

    - 293    private toDate(val:DataVal, limitYear=1970):Date {
    - 294        let d:Date;
    - 295        if (val instanceof Date) { d = val; }
    - 296                            else { d = new Date(val); }   
    - 297        let yr=d.getFullYear();
    - 298        if (yr < 100) { 
    - 299            yr += 1900; 
    - 300            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    - 301        }
    - 302        return d;
    - 303    }
    - 304
    - 305    /**
    - 306     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    - 307     * does not match any of the previous keywords, no casting occurs.
    - 308     * @param sample The value to cast.
    - 309     * @returns The result of the cast. 
    - 310     * @description Casts the sample to the specified data type.
    - 311     */

    - 312    private castVal(type:string, val:DataVal):DataVal {
    - 313        switch (type) {
    - 314            case Data.type.date:    if (val instanceof Date) { return val; }
    - 315                            val = this.toDate(val);
    - 316                            if (isNaN(val.getTime())) { val = null; }
    - 317                            break;
    - 318            case Data.type.percent: if (typeof val === 'string') {
    - 319                                const num = parseFloat(val);
    - 320                                val = (val).endsWith('%')? num/100 : num;
    - 321                            } 
    - 322                            if (isNaN(val)) { val = null; }
    - 323                            break;
    - 324            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    - 325             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    - 326             /* falls through */
    - 327            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    - 328                            if (isNaN(val)) { val = null; }
    - 329                            break;
    - 330            default:        val = ''+val;
    - 331        }
    - 332        return val;
    - 333     }     
    - 334}
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Graph.html b/docs/src/hsGraph/Graph.html deleted file mode 100644 index 23a76d2..0000000 --- a/docs/src/hsGraph/Graph.html +++ /dev/null @@ -1,404 +0,0 @@ - - -

    Graph.ts

    -
       1/**
    -   2 * # Graph
    -   3 * The main `Graph` object that contains all graph components and sets up the controlling logic.
    -   4 * `Graph` sets up a viewBox that is always 1000 units wide. the height automatically adjusts to fill available space while 
    -   5 * preserving a uniform scaling (i.e. preserveAspectRatio = default (xMidYMid)).
    -   6 * 
    -   7 * ### Attributes
    -   8 * The main entry point for applications using this library is the `Graph` class,
    -   9 * typically called as `m(Graph, {cfgFn: (cfg:any) => {...});` 
    -  10 * Accepted attributes are:
    -  11 * - cfgFn: a {@link Graph.CfgFn CfgFn} function that allows setting graph parameters.
    -  12 *
    -  13 * ### Example
    -  14 * 
    -  15 * 
    -  16 * let series = {
    -  17 *    names:['time', 'volume', 'price'],
    -  18 *    rows:[
    -  19 *          [-1,   0.2, 0.8],
    -  20 *          [0.2,  0.7, 0.87],
    -  21 *          [0.4, -0.2, 0.7],
    -  22 *          [0.6,    0, 0.7],
    -  23 *          [0.8,  0.5, 0.6],
    -  24 *          [1,    0.7, 0.75]
    -  25 *    ]
    -  26 * };
    -  27 * 
    -  28 * function myConfig(cfg) {
    -  29 *      cfg.series.data   = [series];
    -  30 *      cfg.series.series = [
    -  31 *          { x:'time', y:'volume']},
    -  32 *          { x:'time', y:'price']}
    -  33 *      ];
    -  34 *      cfg.series.series[0].style.marker.visible = true;
    -  35 *      cfg.series.series[1].style.marker.visible = true;
    -  36 *      cfg.series.series[1].style.marker.shape = hsgraph.Series.marker.diamond;
    -  37 *      const axes = cfg.axes.primary;
    -  38 *      cfg.chart.title.text          = 'Volume over Time';
    -  39 *      cfg.chart.title.xpos          = 'end';
    -  40 *      cfg.chart.title.ypos          = 'top';
    -  41 *      cfg.chart.title.vOffset       = -1.5;
    -  42 *      axes.x.title.text = 'time';
    -  43 *      axes.y.title.text = 'volume';
    -  44 *      axes.x.crossesAt = 0;
    -  45 *      axes.y.crossesAt = 0;
    -  46 *      cfg.axes.secondary.x.visible = false;
    -  47 *      cfg.axes.secondary.y.visible = false;
    -  48 * }
    -  49 * 
    -  50 * m.mount(root, { 
    -  51 *      view:() => m(hsgraph.Graph, {cfgFn: myConfig })
    -  52 * });
    -  53 *
    -  54 * 
    -  55 * 
    -  56 * .hs-graph-chart { fill: #fff; }
    -  57 * .hs-graph-series { stroke-width: 5; }
    -  58 * 
    -  59 * 

    -  60 * 
    -  61 * ### Configurations and Defaults
    -  62 * See {@link Graph.Graph.defaultConfig Graph.defaultConfig}
    -  63 */

    -  64
    -  65/** */
    -  66import { m, Vnode}      from 'hslayout';
    -  67import { Data, 
    -  68         DataSet,
    -  69         NumDomain }    from 'hsdata';
    -  70import { Axes }         from './Axes';
    -  71import { AxesConfig,
    -  72         Scales }       from './AxesTypes';
    -  73import { Scale }        from './Scale';
    -  74import { Canvas, 
    -  75         CanvasConfig } from './Canvas';
    -  76import { Series, 
    -  77         SeriesDef,
    -  78         SeriesConfig } from './Series';
    -  79import { Chart, 
    -  80         ChartConfig }  from './Chart';
    -  81import { Grid, 
    -  82         GridsConfig }  from './Grid';
    -  83import { Legend, 
    -  84         LegendConfig } from './Legend';
    -  85import { SVGElem, 
    -  86         TextElem,
    -  87         Rect, 
    -  88         round }        from './SVGElem';
    -  89import { delay }        from 'hsutil';
    -  90
    -  91const viewBoxWidth:number  = 1000;  // the viewBox size in px
    -  92let   viewBoxHeight:number = 700;   // the viewBox size in px
    -  93
    -  94
    -  95export interface VisibleCfg extends GraphBaseCfg{
    -  96    visible: boolean;
    -  97}
    -  98
    -  99/** 
    - 100 * Configurator for a title, such as Chart title, or Axis title. 
    - 101 * Titles have their own visible switch.
    - 102 */

    - 103export interface LabelCfg extends TextElem, VisibleCfg {
    - 104}
    - 105
    - 106export interface GraphBaseCfg {
    - 107}
    - 108
    - 109/**
    - 110 */

    - 111export interface Config {
    - 112    viewBox?: { w: number; h: number; };
    - 113    graph?:  GraphConfig;
    - 114    canvas?: CanvasConfig;
    - 115    axes?:   AxesConfig;
    - 116    chart?:  ChartConfig;
    - 117    grid?:   GridsConfig;
    - 118    series?: SeriesConfig;
    - 119    legend?: LegendConfig;
    - 120}
    - 121
    - 122/**
    - 123 * `Graph` related configuration options.
    - 124 * See {@link Graph.Graph.makeConfig Graph.makeConfig} for all configurations and
    - 125 * {@link Graph.Graph.config Graph.config} for default `Graph` configuration.
    - 126 */

    - 127export interface GraphConfig extends GraphBaseCfg {
    - 128    margin :{           // in viewBox units 
    - 129        top:    number;          
    - 130        left:   number;   
    - 131        bottom: number;   
    - 132        right:  number;   
    - 133    };
    - 134    timeCond: any;
    - 135}
    - 136
    - 137/**
    - 138 * Creates a deep copy of `def`, taking fields present in `update` to supercede the default value.
    - 139 * @param def contains the default setting for each parameter
    - 140 */

    - 141function copy(def:any):any {
    - 142    let result:any = {};
    - 143    Object.keys(def).map((k:string) => {
    - 144        if (typeof def[k] === 'object' && !Array.isArray(def[k]) && def[k]!==null) {
    - 145            result[k] = copy(def[k]);
    - 146        } else {
    - 147            result[k] = def[k];
    - 148        }
    - 149    });
    - 150    return result;
    - 151}
    - 152
    - 153/** 
    - 154 * signature of a user configuration function, used in {@link Graph.Graph.makeConfig `Graph.makeConfig`} 
    - 155 * @param cfg the fully initialized configuration object. `CfgFn` should overwrite selected values as needed.
    - 156 */

    - 157export interface CfgFn { (cfg:Config):void; }
    - 158
    - 159
    - 160
    - 161/** The main `Graph` object, responsible for setting up the grpahing components and logic. */
    - 162export class Graph extends SVGElem {
    - 163    /**
    - 164     * Creates and returns a `cfg` configuration object containing configuration entries
    - 165     * for  `Graph` and all of its subcomponents:
    - 166     * -   {@link Graph.Graph.config `cfg.graph`}: some general Graph setting, such as margins
    - 167     * -   {@link Canvas.Canvas.config `cfg.canvas`}:  the background canvas on which all components are rendered
    - 168     * -   {@link Chart.Chart.config `cfg.chart`}: the chart area and title
    - 169     * -   {@link Axes.Axes.config `cfg.axes`}: the x- and y-axes, tick marks and labels, and axis title
    - 170     * -   {@link Grid.Grid.config `cfg.grid`}: the major and minor gridlines
    - 171     * -   {@link Series.Series.config `cfg.series`}: the one or more data series to render
    - 172     * -   {@link Legend.Legend.config `cfg.legend`}: the legend for the shown series
    - 173     * if a `userCfg` function is provided, it gets called after all configurations are
    - 174     * initialized with default values. The `cfg` object is passed as parameter into the 
    - 175     * function, which then can selectively overwrite certain settings as needed.
    - 176     * @param userCfg a user defined configuration function with the signature 
    - 177     * `(cfg:{@link Config Config}):void.`
    - 178     */

    - 179    private static makeConfig(userCfg?:CfgFn):Config { 
    - 180        const cfg:Config = {};
    - 181        Graph.defaultConfig(cfg);
    - 182        Canvas.defaultConfig(cfg);
    - 183        Axes.defaultConfig(cfg);
    - 184        Series.defaultConfig(cfg);
    - 185        Grid.defaultConfig(cfg);
    - 186        Chart.defaultConfig(cfg);
    - 187        Legend.defaultConfig(cfg);
    - 188        if (userCfg) { 
    - 189            try { 
    - 190                userCfg(cfg); 
    - 191            } catch(e) {
    - 192                console.log('error in usercfg');
    - 193                console.log(e);
    - 194                console.log(e.stack);
    - 195            }
    - 196        }
    - 197        return cfg;
    - 198    }
    - 199
    - 200    /** 
    - 201     * Defines default values for all configurable parameters in `Graph`
    - 202     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    - 203     * 
    - 204     * #### Configurations and Defaults
    - 205     * ```
    - 206     *  cfg.graph = {@link Graph.GraphConfig } {
    - 207     *     margin: {      // the margin between viewBox edges and nearest plot component
    - 208     *        top: 10,    // viewBox units      
    - 209     *        left: 10,   // viewBox units    
    - 210     *        bottom: 10, // viewBox units    
    - 211     *        right: 10   // viewBox units 
    - 212     *     }   
    - 213     *  } 
    - 214     * ``` 
    - 215     * @param cfg the configuration object, containing default settings for all 
    - 216     * previously configured components.
    - 217     */

    - 218    protected static defaultConfig(cfg:Config) {      
    - 219        cfg.graph = {
    - 220            margin :{
    - 221                top: 10,    // viewBox units      
    - 222                left: 10,   // viewBox units    
    - 223                bottom: 10, // viewBox units    
    - 224                right: 10   // viewBox units    
    - 225            },
    - 226            timeCond: {}
    - 227        };
    - 228    }
    - 229
    - 230    /**
    - 231     * Makes adjustments to cfg based on current settings.
    - 232     * Called just prior to drawing.
    - 233     * @param cfg the configuration object, containing default settings for all components
    - 234     */

    - 235    protected static adjustConfig(cfg:Config) {
    - 236        Canvas.adjustConfig(cfg);
    - 237        Axes.adjustConfig(cfg);
    - 238        Series.adjustConfig(cfg);
    - 239        Grid.adjustConfig(cfg);
    - 240        Chart.adjustConfig(cfg);
    - 241        Legend.adjustConfig(cfg);
    - 242    }
    - 243
    - 244    private marginOffset = {
    - 245        left:   0,     // in px
    - 246        right:  0,     // in px
    - 247        top:    0,     // in px
    - 248        bottom: 0      // in px
    - 249    };
    - 250
    - 251
    - 252    private scales: Scales;
    - 253
    - 254    private createPlotArea(cfgm:{top:number, left:number, bottom:number, right:number}):Rect {
    - 255        const tl = {
    - 256            x: cfgm.left + this.marginOffset.left,
    - 257            y: cfgm.top + this.marginOffset.top
    - 258        };
    - 259        const br = {
    - 260            x: viewBoxWidth  - cfgm.right  - this.marginOffset.right,
    - 261            y: viewBoxHeight - cfgm.bottom - this.marginOffset.bottom
    - 262        };
    - 263        return { tl: tl, br: br };
    - 264    }
    - 265
    - 266    private createData(cfg:any):Data[] {
    - 267        if (!cfg.series.data) {
    - 268            console.log('cfg.series.data not set');
    - 269        }
    - 270        if (!(cfg.series.data.length > 0)) {
    - 271            console.log('cfg.series.data not initialised with array of DataSets');
    - 272        }
    - 273        const timeCond = cfg.graph.timeCond;
    - 274        return cfg.series.data.map((d:DataSet|Data) => 
    - 275            ((d instanceof Data)? d : new Data(d)).filter(timeCond));
    - 276    }
    - 277
    - 278    private createScales(axes:any):Scales {
    - 279        if (!this.scales) { this.scales = {
    - 280            primary:   { x: new Scale(axes.primary.x.scale),   y: new Scale(axes.primary.y.scale) },
    - 281            secondary: { x: new Scale(axes.secondary.x.scale), y: new Scale(axes.secondary.y.scale) }
    - 282        };}
    - 283        return this.scales;
    - 284    }
    - 285
    - 286    adjustRange(plotArea:Rect, scales:Scales) { 
    - 287        scales.primary.x.range([plotArea.tl.x, plotArea.br.x]);
    - 288        scales.primary.y.range([plotArea.br.y, plotArea.tl.y]);
    - 289        scales.secondary.x.range([plotArea.tl.x, plotArea.br.x]);
    - 290        scales.secondary.y.range([plotArea.br.y, plotArea.tl.y]);
    - 291    }
    - 292
    - 293    /**
    - 294     * adjust the height of the viewBox to match available height in containing window,
    - 295     * e.g. after a resize
    - 296     * @param node the Graph node
    - 297     */

    - 298    adjustHeight(node?: Vnode) {
    - 299        if (node.dom && node.dom.parentElement) {
    - 300            const p = node.dom.parentElement;
    - 301            const temp = viewBoxWidth * p.clientHeight / p.clientWidth;
    - 302            if (!isNaN(temp) && temp !== viewBoxHeight) {
    - 303                viewBoxHeight = temp; 
    - 304            }
    - 305        }
    - 306    }
    - 307
    - 308    /**
    - 309     * check on update of axes bounding box and notify Graph.boxNotify
    - 310     */

    - 311    adjustMargins(cfg:Config) {
    - 312        const cfgm = cfg.graph.margin;
    - 313        function getBBox(css: string) {
    - 314            const elems = document.getElementsByClassName(css);
    - 315            const box = Array.prototype.map.call(elems, (e:any)=>e.getBBox());
    - 316            if(box && box[0]) { 
    - 317                margin.t = Math.max(margin.t, cfgm.top-box[0].y);               
    - 318                margin.l = Math.max(margin.l, cfgm.left-box[0].x);               
    - 319                margin.b = Math.max(margin.b,  box[0].y+box[0].height+cfgm.bottom-viewBoxHeight);               
    - 320                margin.r = Math.max(margin.r, box[0].x+box[0].width +cfgm.right -viewBoxWidth);               
    - 321            }
    - 322            margin.t = Math.min(margin.t, 40);  // limit to max 20px
    - 323            margin.b = 30; //Math.min(margin.b, 40);  // limit to max 20px
    - 324            margin.l = 40;
    - 325        }
    - 326        const margin = {t:-1e6,l:-1e6,b:-1e6,r:-1e6};
    - 327        getBBox('hs-graph-axis');
    - 328        getBBox('hs-graph-chart');
    - 329        this.marginOffset.top    += Math.max(margin.t);
    - 330        this.marginOffset.left   += Math.max(margin.l);
    - 331        this.marginOffset.bottom += Math.max(margin.b);
    - 332        this.marginOffset.right  += Math.max(margin.r);
    - 333    }
    - 334
    - 335    onupdate(node?: Vnode) { 
    - 336        this.adjustHeight(node); 
    - 337    }
    - 338
    - 339    oncreate(node?: Vnode) {
    - 340        window.addEventListener("resize", function() { m.redraw(); });
    - 341        this.adjustHeight(node); 
    - 342        Promise.resolve(node.attrs.cfg)
    - 343            .then(delay(10))
    - 344            .then(this.adjustMargins.bind(this))
    - 345            .then(m.redraw);
    - 346    }
    - 347
    - 348    /** 
    - 349     * determines the max ranges each coordinate of each series and auto-sets the domains on the respective scales. 
    - 350     */

    - 351    adjustDomains(cfg:SeriesConfig, scales:Scales, data:Data[]) {
    - 352        const domains = [[1e20, -1e20], [1e20, -1e20]];
    - 353    
    - 354        cfg.series.map((s:SeriesDef) => { // for each series:
    - 355            if (s.x)     { data[s.dataIndex].findDomain(s.x, domains[0]); }
    - 356            else         { domains[0][0] = 0; domains[0][1] = data[s.dataIndex].export().rows.length-1; }
    - 357            if (s.y)     { data[s.dataIndex].findDomain(s.y, domains[1]); }
    - 358            if (s.yBase) { data[s.dataIndex].findDomain(s.yBase, domains[1]); }
    - 359        });
    - 360        scales.primary.x.setAutoDomain(domains[0]);
    - 361        scales.primary.y.setAutoDomain(domains[1]);
    - 362    }
    - 363
    - 364
    - 365    view(node?: Vnode): Vnode {
    - 366        const cfgFn:CfgFn = node.attrs.cfgFn;
    - 367        const cfg:Config = Graph.makeConfig(cfgFn);
    - 368        const plotArea:Rect = this.createPlotArea(cfg.graph.margin);
    - 369        const scales:Scales = this.createScales(cfg.axes);
    - 370        this.adjustRange(plotArea, scales);
    - 371        const data = this.createData(cfg);
    - 372        this.adjustDomains(cfg.series, scales, data);
    - 373
    - 374        Graph.adjustConfig(cfg);
    - 375        node.attrs.cfg = cfg;
    - 376        return m('svg', { class:'hs-graph', width:'100%', height:'100%', 
    - 377                viewBox:`0 0 ${round(viewBoxWidth)} ${round(viewBoxHeight)}` }, [
    - 378            m(Canvas, { cfg:cfg.canvas}),
    - 379            m(Chart, { cfg:cfg.chart, plotArea:plotArea }),
    - 380            m(Grid, { cfg:cfg.grid, scales:scales }),
    - 381            m(Axes, { cfg:cfg.axes, scales:scales }),
    - 382            m(Series, { cfg:cfg.series, scales:scales, data:data }),
    - 383            m(Legend, { cfg:cfg.legend })
    - 384        ]);
    - 385    }
    - 386}
    - 387
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Grid.html b/docs/src/hsGraph/Grid.html deleted file mode 100644 index 3052b0e..0000000 --- a/docs/src/hsGraph/Grid.html +++ /dev/null @@ -1,139 +0,0 @@ - - -

    Grid.ts

    -
       1/**
    -   2 * # Grid
    -   3 * renders the major and minor gridlines in each direction.
    -   4 * 
    -   5 * ### Attributes
    -   6 * The `Chart` class is called by {@link Graph.Graph `Graph`} as 
    -   7 * `m(Grid, { cfg:cfg.grid, scales:scales })`
    -   8 * with the following attributes:
    -   9 * - cfg: a {@link Grid.GridsConfig GridsConfig} object
    -  10 * - scales: a {@link Axes.Scales Scales } object
    -  11 * 
    -  12 * ### Configurations and Defaults
    -  13 * See {@link Grid.Grid.defaultConfig Grid.defaultConfig}
    -  14 * 
    -  15 */

    -  16
    -  17/** */
    -  18import { m, Vnode}      from 'hslayout';
    -  19import { Config, 
    -  20         VisibleCfg }   from './Graph';
    -  21import { SVGElem }      from './SVGElem';
    -  22import { NumRange }     from 'hsdata';
    -  23import { Scale }        from './Scale';
    -  24import { TickDefs,
    -  25         Scales }       from './AxesTypes';
    -  26
    -  27/** defines configurable parameters for a grid */
    -  28export interface GridCfg extends VisibleCfg{
    -  29}
    -  30
    -  31/** defines configurable parameters for horizontal and vertical grids */
    -  32export interface  GridsCfg {
    -  33    hor: GridCfg;
    -  34    ver: GridCfg;
    -  35}
    -  36
    -  37/** Defines configurable settings. */
    -  38export interface GridsConfig {
    -  39    /** major grid lines */
    -  40    major: GridsCfg;
    -  41
    -  42    /** minor grid lines */
    -  43    minor: GridsCfg;
    -  44}
    -  45
    -  46export class Grid extends SVGElem{ 
    -  47    /** 
    -  48     * Defines default values for all configurable parameters in `Graph`
    -  49     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    -  50     * 
    -  51     * ### Configurations and Defaults
    -  52     * ```
    -  53     *  cfg.grid = {@link Grid.GridsConfig }{
    -  54     *      major: {
    -  55     *          hor: { visible:true },
    -  56     *          ver: { visible:true }
    -  57     *      },
    -  58     *      minor: {
    -  59     *          hor: { visible:false },
    -  60     *          ver: { visible:false }
    -  61     *      }
    -  62     *  } 
    -  63     * ``` 
    -  64     * @param cfg the configuration object, containing default settings for all 
    -  65     * previously configured components.
    -  66     */

    -  67    static defaultConfig(cfg:Config) {
    -  68        cfg.grid = {
    -  69            major: {
    -  70                hor: { visible:true },
    -  71                ver: { visible:true }
    -  72            },
    -  73            minor: {
    -  74                hor: { visible:false },
    -  75                ver: { visible:false }
    -  76            }
    -  77        };
    -  78    }
    -  79
    -  80    /**
    -  81     * Makes adjustments to cfg based on current settings
    -  82     * @param cfg the configuration object, containing default settings for all components
    -  83     */

    -  84    static adjustConfig(cfg:Config) {     
    -  85    }
    -  86    
    -  87    /** 
    -  88     * Draws horizontal gridlines parallel to the x-axis
    -  89     */

    -  90    private drawHorGrid(cfg:{visible:boolean}, scale:Scale, range:NumRange, ticks:TickDefs) {
    -  91        return !cfg.visible? m('svg') : m('svg', { class:'hs-graph-grid-hor' }, ticks.marks.map((t) =>
    -  92            this.horLine(range[0], range[1], scale.convert(t))
    -  93        ));
    -  94    }
    -  95
    -  96    /** 
    -  97     * Draws vertical gridlines parallel to the y-axis
    -  98     */

    -  99    private drawVerGrid(cfg:{visible:boolean}, scale:Scale, range:NumRange, ticks:TickDefs) {
    - 100        return !cfg.visible? m('svg') : m('svg', { class:'hs-graph-grid-ver' }, ticks.marks.map((t) =>
    - 101            this.verLine(scale.convert(t), range[0], range[1])
    - 102        ));
    - 103    }
    - 104
    - 105
    - 106    view(node?: Vnode): Vnode {
    - 107        const cfg:GridsConfig = node.attrs.cfg;
    - 108        const scales:Scales = node.attrs.scales;
    - 109        const ps = scales.primary;
    - 110        return m('svg', { class:'hs-graph-grid'}, [
    - 111            m('svg', { class:'hs-graph-grid-minor' }, [
    - 112                this.drawHorGrid(cfg.minor.hor, ps.y, ps.x.range(), ps.y.ticks().minor),
    - 113                this.drawVerGrid(cfg.minor.ver, ps.x, ps.y.range(), ps.x.ticks().minor)
    - 114            ]),
    - 115            m('svg', { class:'hs-graph-grid-major' }, [
    - 116                this.drawHorGrid(cfg.major.hor, ps.y, ps.x.range(), ps.y.ticks().major),
    - 117                this.drawVerGrid(cfg.major.ver, ps.x, ps.y.range(), ps.x.ticks().major)
    - 118            ])
    - 119        ]);
    - 120    }
    - 121}
    - 122
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Legend.html b/docs/src/hsGraph/Legend.html deleted file mode 100644 index 5959d4f..0000000 --- a/docs/src/hsGraph/Legend.html +++ /dev/null @@ -1,73 +0,0 @@ - - -

    Legend.ts

    -
       1/**
    -   2 * # Legend
    -   3 * renders the series' legend .
    -   4 * 
    -   5 * ### Attributes
    -   6 * The `Legend` class is called by {@link Graph.Graph `Graph`} as 
    -   7 * `m(Legend, { cfg:cfg.legend })`
    -   8 * with the following attributes:
    -   9 * - cfg: a {@link Legend.LegendConfig LegendConfig} object
    -  10 * 
    -  11 * ### Configurations and Defaults
    -  12 * See {@link Legend.Legend.defaultConfig Legend.defaultConfig}
    -  13 * 
    -  14 */

    -  15
    -  16/** */
    -  17import { m, Vnode}  from 'hslayout';
    -  18import { Config }   from './Graph';
    -  19//import { SVGElem }  from './SVGElem';
    -  20
    -  21
    -  22/** Defines configurable settings. */ 
    -  23export interface LegendConfig {
    -  24};
    -  25
    -  26export class Legend {
    -  27    /** 
    -  28     * Defines default values for all configurable parameters in `Legend`
    -  29     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    -  30     * 
    -  31     * ### Configurations and Defaults
    -  32     * ```
    -  33     *  cfg.legend = {@link Legend.LegendConfig }{
    -  34     *  } 
    -  35     * ``` 
    -  36     * @param cfg the configuration object, containing default settings for all 
    -  37     * previously configured components.
    -  38     */

    -  39    static defaultConfig(cfg:Config) {
    -  40        cfg.legend = {
    -  41        };
    -  42    }
    -  43
    -  44    /**
    -  45     * Makes adjustments to cfg based on current settings
    -  46     * @param cfg the configuration object, containing default settings for all components
    -  47     */

    -  48    static adjustConfig(cfg:Config) {
    -  49        
    -  50    }
    -  51    
    -  52    view(node?: Vnode): Vnode {
    -  53        return m('svg', { class:'hs-graph-legend', width:'100%', height:'100%'});
    -  54    }
    -  55}
    -  56
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Plot.html b/docs/src/hsGraph/Plot.html deleted file mode 100644 index 5889426..0000000 --- a/docs/src/hsGraph/Plot.html +++ /dev/null @@ -1,106 +0,0 @@ - - -

    Plot.ts

    -
       1/**
    -   2 * Abstract base class for plots.
    -   3 */

    -   4
    -   5/** */
    -   6import { m, Vnode}      from 'hslayout';
    -   7import { SVGElem,
    -   8         TextElem,
    -   9         TextHAlign,
    -  10         TextVAlign }   from './SVGElem';
    -  11import { Data, 
    -  12         DataRow }      from 'hsdata';
    -  13import { XYScale }      from './AxesTypes';
    -  14import { Series, 
    -  15         SeriesStyle,
    -  16         SeriesDef }    from './Series';
    -  17import { round }        from 'hsutil';
    -  18
    -  19export abstract class Plot extends SVGElem {
    -  20    drawLine(clipID:string, data:DataRow[], x:number, y:number, scales:XYScale, sStyle:SeriesStyle, title?:string) {
    -  21        const style = `stroke: ${sStyle.line.color}; stroke-width:${sStyle.line.width};`;
    -  22        return !sStyle.line.visible? m('.invisible-line','') : this.polyline(data, x, y, scales, clipID, style, title);
    -  23    }
    -  24
    -  25    drawMarker(clipID:string, data:DataRow[], x:number, y:number, scales:XYScale, sStyle:SeriesStyle, title?:string) {
    -  26        const mrk = Series.marker;
    -  27        let style = `fill:${sStyle.marker.color}`;
    -  28        return !sStyle.marker.visible? m('.invisible-marker','') : m('svg', {class:'hs-graph-series-markers'},
    -  29            data.map((p:number[]) => {
    -  30                const cx = scales.x.convert(p[x]);
    -  31                const cy = scales.y.convert(p[y]);
    -  32                const r  = sStyle.marker.size;
    -  33                switch (sStyle.marker.shape) {
    -  34                    case mrk.circle: 
    -  35                        return this.circle({x:cx, y:cy}, r, style, title);
    -  36                    case mrk.square: 
    -  37                        return this.rect({x:cx-r, y:cy-r}, {w:2*r, h:2*r}, style, title);
    -  38                    case mrk.diamond: 
    -  39                        return this.shape([[cx-r, cy], [cx, cy+r], [cx+r, cy], [cx, cy-r]], undefined, style, title);
    -  40                    case mrk.upTriangle: 
    -  41                        return this.shape([[cx-r, cy+r], [cx+r, cy+r], [cx, cy-r]], undefined, style, title);
    -  42                    case mrk.downTriangle: 
    -  43                        return this.shape([[cx-r, cy-r], [cx+r, cy-r], [cx, cy+r]], undefined, style, title);
    -  44                }
    -  45                return m(`.unkown-marker-${sStyle.marker.shape}`,'');
    -  46            })
    -  47        );
    -  48    }
    -  49
    -  50    drawLabel(clipID:string, data:DataRow[], x:number, y:number, lbl:number, scales:XYScale, sDef:SeriesDef) {
    -  51        const sStyle = sDef.style;
    -  52        const cfg:TextElem = {
    -  53            text:       '', 
    -  54            cssClass:   ``,
    -  55            style:      `fill:${sStyle.label.color}`,
    -  56            xpos:       TextHAlign.middle,
    -  57            ypos:       TextVAlign.center,
    -  58            hOffset:    sDef.hOffset,
    -  59            vOffset:    sDef.vOffset
    -  60        };
    -  61        return !sStyle.marker.visible? m('.invisible-marker','') : m('svg', {class:'hs-graph-series-labels'},
    -  62            data.map((p:DataRow) => {
    -  63                cfg.x = ''+scales.x.convert(p[x]);
    -  64                cfg.y = ''+scales.y.convert(p[y]);
    -  65                return this.text(cfg, round(p[lbl], 3));
    -  66            })
    -  67        );
    -  68    }
    -  69
    -  70    drawArea(clipID:string, data:DataRow[], x:number, yFore:number, yBack:number, scales:XYScale, sStyle:SeriesStyle, title:string) {
    -  71        if (sStyle.fill.visible) {
    -  72            const style = `fill: ${sStyle.fill.color};`;
    -  73            const drawFore = data;
    -  74            const drawBack = data.slice().reverse();
    -  75            return this.polygon(drawFore, drawBack, x, yFore, yBack, scales, clipID, style, title);
    -  76        } else {
    -  77            m('.invisible-line','');
    -  78        }
    -  79    }
    -  80
    -  81    abstract plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[];
    -  82
    -  83    setDefaults(data:Data, series:SeriesDef, scales:XYScale) {
    -  84    }
    -  85
    -  86
    -  87
    -  88
    -  89
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/PlotArea.html b/docs/src/hsGraph/PlotArea.html deleted file mode 100644 index 854c832..0000000 --- a/docs/src/hsGraph/PlotArea.html +++ /dev/null @@ -1,105 +0,0 @@ - - -

    PlotArea.ts

    -
       1/**
    -   2 * ## PlotArea
    -   3 * Plots data as an area. `PlotArea` is called if the series' `type` is 'area'.
    -   4 * The area will be filled between a series as indexed by `y` and the x-axis, 
    -   5 * or a second series indexed by `yBase`.
    -   6 * If `yBase` equals `$stacked`, subsequent series will be stacked upon each other.
    -   7 * `PlotArea` recognizes the following attributes:
    -   8 * - `x`: name of the x series
    -   9 * - `y`: name of the y series, also used as higher series when filling against `yBase`
    -  10 * - `yBase`: optional lower series to fill against instead of the x-axis. 
    -  11 * - `map`: Use 'stacked' to stack series upon each other. Use 'shared' to show the share of
    -  12 *    each series, normalized to 1.
    -  13 * 
    -  14 * 
    -  15 * 
    -  16 * let series = {
    -  17 *    colNames:['time', 'volume', 'costs'],
    -  18 *    rows:[
    -  19 *      [-1,  0.2, 0.3],
    -  20 *      [0.2, 0.7, 0.2],
    -  21 *      [0.4, 0.1, 0.3],
    -  22 *      [0.6, 0,   0.1],
    -  23 *      [0.8, 0.3, 0.5],
    -  24 *      [1,   0.2, 0.4]
    -  25 * ]};
    -  26 * 
    -  27 * m.mount(root, { 
    -  28 *    view:() => m(hslayout.Layout, {
    -  29 *       rows: [],
    -  30 *       content: [
    -  31 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg)}),
    -  32 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg, 'stacked')}),
    -  33 *          m(hsgraph.Graph, {cfgFn: cfg => defCfg(cfg, 'shared')})
    -  34 *       ]
    -  35 *    })
    -  36 * });
    -  37 * function defCfg(cfg, map) {
    -  38 *     cfg.series.series = [
    -  39 *        { x:'time', y:'volume', map:map, type: 'area' },
    -  40 *        { x:'time', y:'costs',  map:map, type: 'area' }
    -  41 *     ];
    -  42 *     cfg.series.data      = [series];
    -  43 *     cfg.series.series[0].style.fill.color = 'rgba(128, 128, 255, 0.5)';
    -  44 *     cfg.series.series[1].style.fill.color = 'rgba(0, 128, 0, 0.5)';
    -  45 *     cfg.axes.primary.y.scale.domain = [0, 1];
    -  46 *     cfg.axes.primary.y.title.visible = false;
    -  47 *     cfg.chart.title.visible = false;
    -  48 * }
    -  49 * 
    -  50 * 
    -  51 * 

    -  52 */

    -  53
    -  54
    -  55/** */
    -  56import { m, Vnode}      from 'hslayout';
    -  57import { Data }         from 'hsdata';
    -  58import { XYScale }      from './AxesTypes';
    -  59import { Plot }         from './Plot';
    -  60import { SeriesDef }    from './Series';
    -  61
    -  62export class PlotArea extends Plot { 
    -  63    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {
    -  64        const x     = data.colNumber(series.x);
    -  65        const y     = data.colNumber(series.y);
    -  66        const yBase = data.colNumber(series.yBase);  // or undefined
    -  67        const yMax  = data.colNumber('$sum');
    -  68        const mapRow = (row:any[]) =>
    -  69            (yMax===undefined)? [
    -  70                row[x],
    -  71                row[y]+row[yBase],
    -  72                row[yBase]
    -  73            ] : [
    -  74                row[x],
    -  75                (row[y]+row[yBase]) / row[yMax],
    -  76                row[yBase] / row[yMax]
    -  77            ]; 
    -  78        if (y===undefined) { return m('.error',''); }
    -  79        if (series.map) {
    -  80            const d = data.getData().map(mapRow);
    -  81            return [this.drawArea(clipID, d, 0, 1, 2, scales, series.style, series.y)];
    -  82        } else {
    -  83            const d = data.getData();
    -  84            return [this.drawArea(clipID, d, x, y, yBase, scales, series.style, series.y)];
    -  85        }
    -  86    }
    -  87}
    -  88
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/PlotBar.html b/docs/src/hsGraph/PlotBar.html deleted file mode 100644 index 64061f6..0000000 --- a/docs/src/hsGraph/PlotBar.html +++ /dev/null @@ -1,115 +0,0 @@ - - -

    PlotBar.ts

    -
       1/**
    -   2 * ## PlotBar 
    -   3 * Plots data as vertical bars by configuring the series' `type` 
    -   4 * as {@link Series.Series.plot 'bar'}. The `cols` name array starts with 
    -   5 * the x-value column, or `undefined` to use the row index as x-values.
    -   6 * 
    -   7 * #### Mode 1 - Classic Bars
    -   8 * Specify a single name for y-values to generate bars that reach up from the
    -   9 * x-axis to the value in each data row. Negative heights are allowed.
    -  10 * Example: `y:'volume'`
    -  11 * 
    -  12 * #### Mode 2 - High-Low Bars
    -  13 * Specify names for y and yBase values to create high-low bars that reach from the 
    -  14 * y-value to the yBase-value for each data row. Negative heights are allowed.
    -  15 * Example: `y:'open', yBase:'close'`
    -  16 * 
    -  17 * #### Example
    -  18 * 
    -  19 * 
    -  20 * let series = {
    -  21 *    colNames:['time', 'volume', 'open', 'close'],
    -  22 *    rows:[
    -  23 *      [5, 0.2, 0.3, 0.5],
    -  24 *      [10, 0.7, 0.1, 0.2],
    -  25 *      [15, 0.4, 0.5, 0.6],
    -  26 *      [20, 0.1, 0.4, 0.6],
    -  27 *      [25,0.5, 0.3, 0.55],
    -  28 *      [30, 0.3, 0.4, 0.5]
    -  29 * ]};
    -  30 * 
    -  31 * m.mount(root, { 
    -  32 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    -  33 *          cfg.chart.title.text = 'Bar Chart';
    -  34 *          cfg.series.data   = [series];
    -  35 *          cfg.series.series = [
    -  36 *              { y:'volume', type: 'bar'},
    -  37 *              { y:'open', yBase:'close', type: 'bar'}
    -  38 *          ];
    -  39 *          cfg.series.series[0].style.bar.width = 80;
    -  40 *          cfg.series.series[1].style.bar.offset = 0;
    -  41 *          cfg.series.series[1].style.bar.width = 10;
    -  42 *      }})
    -  43 * });
    -  44 *
    -  45 * 
    -  46 * 

    -  47 */

    -  48
    -  49/** */
    -  50import { m, Vnode}      from 'hslayout';
    -  51import { Data }         from 'hsdata';
    -  52import { NumDomain }    from 'hsdata';
    -  53import { XYScale }      from './AxesTypes';
    -  54import { Plot }         from './Plot';
    -  55import { SeriesDef,
    -  56         SeriesStyle }  from './Series';
    -  57
    -  58export class PlotBar extends Plot {
    -  59    drawBar(clipID:string, data:Data, x:number, y:number, y0:number, scales:XYScale, sStyle:SeriesStyle, s:number) {
    -  60        const style = `fill: ${sStyle.bar.color};`;
    -  61        const index = (x === undefined);
    -  62        const domain = scales.x.domain();
    -  63        const offset = s*sStyle.bar.offset * (domain[1] - domain[0])/ (100 * data.getData().length);
    -  64        const width  = sStyle.bar.width    * (domain[1] - domain[0])/ (100 * data.getData().length);
    -  65        return m('svg', {class:'hs-graph-series-bars'}, data.getData().map(
    -  66            (p:number[], i:number) => {
    -  67                const rx0 = scales.x.convert((index? i : p[x]) + offset - width/2);
    -  68                const rx1 = scales.x.convert((index? i : p[x]) + offset + width/2);
    -  69                const ry0 = scales.y.convert(y0===undefined? 0 : p[y0]);
    -  70                const ry = scales.y.convert(p[y]);
    -  71                return this.rect({x:rx0, y:ry0}, {h:ry-ry0, w:rx1-rx0}, style);
    -  72            })
    -  73        );
    -  74    }
    -  75
    -  76    setDefaults(data:Data, series:SeriesDef, scales:XYScale) {
    -  77        super.setDefaults(data, series, scales);
    -  78        let  dom = scales.y.domain();
    -  79        if (dom[0] > 0) { 
    -  80            dom[0] = 0; 
    -  81            scales.y.domain(dom);
    -  82        }
    -  83        if (series.x === undefined) {
    -  84            scales.x.domain([-0.5, data.getData().length-0.5]);
    -  85        }
    -  86    }
    -  87
    -  88    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {
    -  89        const x = data.colNumber(series.x);
    -  90        const y = data.colNumber(series.y);
    -  91        const yBase = series.yBase? data.colNumber(series.yBase) : undefined;
    -  92        if (y===undefined) { return m('.error',''); }
    -  93        return [
    -  94            this.drawBar(clipID, data, x, y, yBase, scales, series.style, i),
    -  95        ];
    -  96    }
    -  97}
    -  98
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/PlotLine.html b/docs/src/hsGraph/PlotLine.html deleted file mode 100644 index db943ab..0000000 --- a/docs/src/hsGraph/PlotLine.html +++ /dev/null @@ -1,68 +0,0 @@ - - -

    PlotLine.ts

    -
       1/**
    -   2 * ## PlotLine
    -   3 * Plots data as a line by configuring the series' `type` 
    -   4 * as {@link Series.Series.plot 'line'}. The `cols` name array starts with 
    -   5 * the x-value column, followed by the y-column.
    -   6 * 
    -   7 * 
    -   8 * 
    -   9 * let series = {
    -  10 *    colNames:['time', 'volume'],
    -  11 *    rows:[
    -  12 *      [-1, 0.2],
    -  13 *      [0.2, 0.7],
    -  14 *      [0.4, -0.2],
    -  15 *      [0.6, 0],
    -  16 *      [0.8, 0.5],
    -  17 *      [1, 0.7]
    -  18 * ]};
    -  19 * 
    -  20 * m.mount(root, { 
    -  21 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    -  22 *          cfg.chart.title.text          = 'Simple Example';
    -  23 *          cfg.series.data   = [series];
    -  24 *          cfg.series.series = [{ x:'time', y:'volume' }];
    -  25 *      }})
    -  26 * });
    -  27 *
    -  28 * 
    -  29 * 

    -  30 */

    -  31
    -  32/** */
    -  33import { m, Vnode}  from 'hslayout';
    -  34import { Data }     from 'hsdata';
    -  35import { XYScale }  from './AxesTypes';
    -  36import { Plot }     from './Plot';
    -  37import { SeriesDef }from './Series';
    -  38
    -  39export class PlotLine extends Plot { 
    -  40    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {
    -  41        const x = data.colNumber(series.x);
    -  42        const y = data.colNumber(series.y);
    -  43        if (x===undefined) { return m('.error',''); }
    -  44        if (y===undefined) { return m('.error',''); }
    -  45        return [
    -  46            this.drawLine(clipID, data.getData(), x, y, scales, series.style, series.y),
    -  47            this.drawMarker(clipID, data.getData(), x, y, scales, series.style, series.y)
    -  48        ];
    -  49    }
    -  50}
    -  51
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/PlotMarkers.html b/docs/src/hsGraph/PlotMarkers.html deleted file mode 100644 index 1b23a9f..0000000 --- a/docs/src/hsGraph/PlotMarkers.html +++ /dev/null @@ -1,71 +0,0 @@ - - -

    PlotMarkers.ts

    -
       1/**
    -   2 * ## PlotMarkers
    -   3 * Plots data as markers by configuring the series' `type` 
    -   4 * as {@link Series.Series.plot 'markers'}. 
    -   5 * The `cols` name array starts with 
    -   6 * the x-value column, followed by the y-column.
    -   7 * 
    -   8 * 
    -   9 * 
    -  10 * let series = {
    -  11 *    colNames:['time', 'volume'],
    -  12 *    rows:[
    -  13 *      [-1, 0.2],
    -  14 *      [0.2, 0.7],
    -  15 *      [0.4, -0.2],
    -  16 *      [0.6, 0],
    -  17 *      [0.8, 0.5],
    -  18 *      [1, 0.7]
    -  19 * ]};
    -  20 * 
    -  21 * m.mount(root, { 
    -  22 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    -  23 *          cfg.chart.title.text = 'Simple Example';
    -  24 *          cfg.series.data      = [series];
    -  25 *          cfg.series.series    = [{ x:'time', y:'volume', type: 'marker' }];
    -  26 *      }})
    -  27 * });
    -  28 *
    -  29 * 
    -  30 * 

    -  31 */

    -  32
    -  33/** */
    -  34import { m, Vnode}  from 'hslayout';
    -  35import { Data }     from 'hsdata';
    -  36import { XYScale }  from './AxesTypes';
    -  37import { Plot }     from './Plot';
    -  38import { SeriesDef }from './Series';
    -  39
    -  40export class PlotMarkers extends Plot { 
    -  41    plot(data:Data, series:SeriesDef, scales:XYScale, i:number, clipID:string): Vnode[] {
    -  42        const x = data.colNumber(series.x);
    -  43        const y = data.colNumber(series.y);
    -  44        const l = series.l? data.colNumber(series.l) : undefined;
    -  45        if (x===undefined) { return m('.error',''); }
    -  46        if (y===undefined) { return m('.error',''); }
    -  47        return [
    -  48            this.drawMarker(clipID, data.getData(), x, y, scales, series.style, series.y),
    -  49            (l===undefined)? undefined :
    -  50                this.drawLabel(clipID, data.getData(), x, y, l, scales, series)
    -  51        ];
    -  52    }
    -  53}
    -  54
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/SVGElem.html b/docs/src/hsGraph/SVGElem.html deleted file mode 100644 index 8fc9302..0000000 --- a/docs/src/hsGraph/SVGElem.html +++ /dev/null @@ -1,312 +0,0 @@ - - -

    SVGElem.ts

    -
       1import { m, Vnode } from 'hslayout';
    -   2import { XYScale }  from './AxesTypes';
    -   3import { DataRow }  from 'hsdata';
    -   4
    -   5/** svg primitive Point, measured in viewbox coordinates.  */
    -   6export interface Point {
    -   7    /** x-viewbox value of the point */
    -   8    x:   number;
    -   9    /** y-viewbox value of the point */
    -  10    y:   number;
    -  11    /** viewbox unit to use for x coordinate. Allowed values are 'px' or '%'; defaults to 'px' */
    -  12    xunit?: string;
    -  13    /** viewbox unit to use for y coordinate. Allowed values are 'px' or '%'; defaults to 'px' */
    -  14    yunit?: string;
    -  15}
    -  16
    -  17/** svg primitive Rect, measured in viewbox coordinates.  */
    -  18export interface Rect {
    -  19    /** top left point */
    -  20    tl: Point;
    -  21    /** bottom right point */
    -  22    br: Point;
    -  23}
    -  24
    -  25/** 
    -  26 * svg extended Point, measured in viewbox coordinates. 
    -  27 * Extends `Point` with optional `dx` and 'dy' offsets and optional units.
    -  28 */

    -  29export interface ExtendedPoint extends Point{
    -  30    dx?: number;
    -  31    dy?: number;
    -  32    dxunit?: string;
    -  33    dyunit?: string;
    -  34}
    -  35
    -  36
    -  37export interface Area {
    -  38    w: number;
    -  39    h: number;
    -  40    wunit?: string;
    -  41    hunit?: string;
    -  42}
    -  43
    -  44export interface TextElem {
    -  45    /** the text to show */
    -  46    text: string; 
    -  47
    -  48    /** a css class to set */
    -  49    cssClass?:  string;   
    -  50
    -  51    /** a style to set */
    -  52    style?:  string;   
    -  53
    -  54    /** optional absolute x positioning on the canvas, e.g. '50%' */
    -  55    x?:         string;
    -  56
    -  57    /** optional absolute y positioning on the canvas, e.g. '50%' */
    -  58    y?:         string;
    -  59    
    -  60    /** horizontal align: 'start' | 'middle' | 'end'; uses `text-align` attribute */
    -  61    xpos:       TextHAlign;
    -  62
    -  63    /** vertical align: 'top' | 'center' | 'bottom'; uses `dy` attribute */
    -  64    ypos:       TextVAlign;
    -  65
    -  66    /** horizontal label offset in 'em'; uses `dx` attribute */
    -  67    hOffset:    number;
    -  68
    -  69    /** vertical label offset in 'em'; uses `dy` attribute */
    -  70    vOffset:    number;
    -  71}
    -  72
    -  73export function round (num:number):string { 
    -  74    const result = num.toFixed(1);
    -  75    if (result === 'Infinity') {
    -  76        return '1e20';
    -  77    } 
    -  78    return result;
    -  79}
    -  80
    -  81export enum TextHAlign {
    -  82    start   = 'start',
    -  83    middle  = 'middle',
    -  84    end     = 'end'
    -  85}
    -  86
    -  87export enum TextVAlign {
    -  88    top     = 'top',
    -  89    center  = 'center',
    -  90    bottom  = 'bottom'
    -  91}
    -  92
    -  93export abstract class SVGElem {
    -  94    /**
    -  95     * plot some text 
    -  96     * @param cfg configures the text alignment and positioning
    -  97     * @param text the text to plot
    -  98     */

    -  99    text(cfg:TextElem, text:string):Vnode {
    - 100        let yShift = 0;
    - 101        let hAlign:TextHAlign = cfg.xpos;
    - 102        switch(cfg.xpos) {
    - 103            case TextHAlign.start:  break;
    - 104            case TextHAlign.end:    break;
    - 105            case TextHAlign.middle: 
    - 106            default:       hAlign = TextHAlign.middle; break;
    - 107        }
    - 108        switch(cfg.ypos) { // additional y 'em' shift
    - 109            case TextVAlign.top:    yShift = 0.7; break;
    - 110            case TextVAlign.center: yShift = 0.35; break;
    - 111            case TextVAlign.bottom: 
    - 112            default:                yShift =  0; break;
    - 113        }
    - 114        const param = { 
    - 115            x: cfg.x || '', 
    - 116            y: cfg.y || '',
    - 117            dx:round(cfg.hOffset||0) + 'em',    
    - 118            dy:round((cfg.vOffset||0)+yShift) + 'em',
    - 119            style: `text-anchor:${hAlign}; ${cfg.style||''}`,
    - 120            class: cfg.cssClass,
    - 121        };
    - 122        return m('text', param, text);
    - 123    }
    - 124
    - 125    /**
    - 126     * plot a rectangle in domain coordinates
    - 127     * @param tl the top-left corner of the rect
    - 128     * @param area the width and height of the rect
    - 129     * @param style optional css style setting, such as stroke or stroke-width
    - 130     */

    - 131    rect(tl:Point, area:Area, style:string, title?:string):Vnode {
    - 132        if (area.w < 0) {
    - 133            tl.x += area.w;
    - 134            area.w = -area.w;
    - 135        }
    - 136        if (area.h < 0) {
    - 137            tl.y += area.h;
    - 138            area.h = -area.h;
    - 139        }
    - 140        const param = {
    - 141            x: round(tl.x),       y: round(tl.y),
    - 142            width: round(area.w)  + (area.wunit||''), 
    - 143            height: round(area.h) + (area.hunit||''),
    - 144            style: style
    - 145        };
    - 146        return m('rect', param), m('title', title);
    - 147    }
    - 148
    - 149    /**
    - 150     * plot a circle around the center domain point `c`, with radius `r`
    - 151     * @param c the circle's center point in domain coordinates
    - 152     * @param r the circle's radius, in domain coordinates
    - 153     * @param style optional css style setting, such as stroke or stroke-width
    - 154     */

    - 155    circle(c:Point, r:number, style:string, title?:string):Vnode {
    - 156        return m('circle', 
    - 157            { cx: round(c.x), cy: round(c.y), r: round(r), style: style },
    - 158            m('title', title)
    - 159        );
    - 160    }
    - 161
    - 162    /**
    - 163     * defines a clip rect to apply to other elelements via the `id`
    - 164     * @param tl top-left corner of the `clipRect` in domain coordinates
    - 165     * @param area width and height of the `clipRect` in domain coordinates
    - 166     * @param id a unique clip id to reference the `clipRect` by
    - 167     */

    - 168    clipRect(tl:Point, area:Area, id:string):Vnode {
    - 169        const param = {
    - 170            x: round(tl.x),       y: round(tl.y),
    - 171            width: round(area.w)  + (area.wunit||''), 
    - 172            height: round(area.h) + (area.hunit||'')
    - 173        };
    - 174        return m('defs', m('clipPath', {id: id}, m('rect', param)));
    - 175    }
    - 176
    - 177    /**
    - 178     * plots a straight line from `x0/y0` to `x1/y1`.
    - 179     * @param x0 starting point x domain coordinate 
    - 180     * @param x1 ending point x domain coordinate 
    - 181     * @param y0 starting point y domain coordinate 
    - 182     * @param y1 ending point y domain coordinate 
    - 183     * @param cssClass optional css class attribute
    - 184     */

    - 185    line(x0:number, x1:number, y0:number, y1:number, cssClass?:string):Vnode {
    - 186        const param = {
    - 187            x1: round(x0), y1: round(y0), 
    - 188            x2: round(x1),   y2: round(y1), 
    - 189            class: cssClass
    - 190        };
    - 191        return m('line', param);
    - 192    }
    - 193
    - 194    /**
    - 195     * plots a horizontal line from `x0/y` to `x1/y`.
    - 196     * @param x0 starting point x domain coordinate 
    - 197     * @param x1 ending point x domain coordinate 
    - 198     * @param y  starting and ending point y domain coordinate 
    - 199     * @param cssClass optional css class attribute
    - 200     */

    - 201    horLine(x0:number, x1:number, y:number, cssClass?:string):Vnode {
    - 202        const param = {
    - 203            x1: round(x0), y1: round(y), 
    - 204            x2: round(x1), y2: round(y), 
    - 205            class: cssClass
    - 206        };
    - 207        return m('line', param);
    - 208    }
    - 209
    - 210    /**
    - 211     * plots a vertical line from `x/y0` to `x/y1`.
    - 212     * @param x  starting and ending point x domain coordinate 
    - 213     * @param y0 starting point y domain coordinate 
    - 214     * @param y1 ending point y domain coordinate 
    - 215     * @param cssClass optional css class attribute
    - 216     */

    - 217    verLine(x:number, y0:number, y1:number, cssClass?:string):Vnode {
    - 218        const param = {
    - 219            x1: round(x), y1: round(y0), 
    - 220            x2: round(x), y2: round(y1), 
    - 221            class: cssClass
    - 222        };
    - 223        return m('line', param);
    - 224    }
    - 225
    - 226    /**
    - 227     * plots a polyline from points in `data`. `x` and `y` are the indices to reference 
    - 228     * the data for the x-axis, respectively the y-axis in each row in `data`. That is,
    - 229     * plot `data[row][x] / data[row][y]` for all rows. 
    - 230     * @param data an array of rows; each row is an array of data. The first row contains the 
    - 231     * series names and will be skipped.
    - 232     * @param x the index in each row to use as x coordinate
    - 233     * @param y the index in each row to use as y coordinate
    - 234     * @param scales the scales to use to convert coordinates into range values
    - 235     * @param id the unique clip-path id to use, or undefined
    - 236     * @param style an optional `style` attribute, e.g. to set the stroke and stroke-width.
    - 237     */

    - 238    polyline(data:DataRow[], x:number, y:number, scales:XYScale, id:string, style?:string, title?:string):Vnode {
    - 239        return m('polyline', { 
    - 240            'clip-path': id? `url(#${id})` : undefined,
    - 241            style: style,
    - 242            points: data.map((row:number[]) => 
    - 243                `${round(scales.x.convert(row[x]))},${round(scales.y.convert(row[y]))}`).join(' ')
    - 244        }, m('title', title)); 
    - 245    }
    - 246
    - 247    /**
    - 248     * plots a polygon from points in `data`. `x` and `y` are the indices to reference 
    - 249     * the data for the x-axis, respectively the y-axis in each row in `data`. That is,
    - 250     * plot `data[row][x] / data[row][y]` for all rows. 
    - 251     * @param data an array of rows; each row is an array of data. The first row contains the 
    - 252     * series names and will be skipped.
    - 253     * @param x the index in each row to use as x coordinate
    - 254     * @param y the index in each row to use as y coordinate
    - 255     * @param scales the scales to use to convert coordinates into range values
    - 256     * @param id the unique clip-path id to use, or undefined
    - 257     * @param style an optional `style` attribute, e.g. to set the stroke and stroke-width.
    - 258     */

    - 259    polygon(dataFore:DataRow[], dataBack:DataRow[], x:number, yFore:number, yBack:number, scales:XYScale, id:string, style?:string, title?:string):Vnode {
    - 260        const indexed = (x===undefined);
    - 261        const sx = (_x:number) => round(scales.x.convert(_x));
    - 262        const sy = (_y:number) => round(scales.y.convert(_y));
    - 263        const clip = id? `url(#${id})` : undefined;
    - 264        const points:string = 
    - 265                dataFore.map((row:number[], i:number) => 
    - 266                    `${sx(indexed?i:row[x])},${sy(row[yFore])}`)
    - 267        .concat(dataBack.map((row:number[], i:number) => 
    - 268                    `${sx(indexed?(dataBack.length-i-1):row[x])},${sy(yBack?row[yBack]:0)}`
    - 269        )).join(' ');
    - 270        return m('polygon', { 'clip-path': clip, style: style, points: points }, m('title', title));
    - 271    }
    - 272
    - 273    /**
    - 274     * plots a shape from points in `data`. `x` and `y` are the indices to reference 
    - 275     * the data for the x-axis, respectively the y-axis in each row in `data`. That is,
    - 276     * plot `data[row][x] / data[row][y]` for all rows. 
    - 277     * @param data an array of rows; each row is an array of data. The first row contains the 
    - 278     * series names and will be skipped.
    - 279     * @param x the index in each row to use as x coordinate
    - 280     * @param y the index in each row to use as y coordinate
    - 281     * @param scales the scales to use to convert coordinates into range values
    - 282     * @param id the unique clip-path id to use, or undefined
    - 283     * @param style an optional `style` attribute, e.g. to set the stroke and stroke-width.
    - 284     */

    - 285    shape(points:DataRow[], id:string, style:string, title?:string):Vnode {
    - 286        return m('polyline', { 
    - 287            'clip-path': id? `url(#${id})` : undefined,
    - 288            style: style,
    - 289            points: points.map((row:number[]) => 
    - 290                `${round(row[0])},${round(row[1])}`).join(' ')
    - 291            }, m('title', title)); 
    - 292    }
    - 293}
    - 294
    - 295
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Scale.html b/docs/src/hsGraph/Scale.html deleted file mode 100644 index 8822b66..0000000 --- a/docs/src/hsGraph/Scale.html +++ /dev/null @@ -1,299 +0,0 @@ - - -

    Scale.ts

    -
       1/**
    -   2 * @module Axes
    -   3 */

    -   4
    -   5/** */ 
    -   6import { Domain, 
    -   7         NumRange }     from 'hsdata';
    -   8import { Axes }         from './Axes';
    -   9import { date, ms }     from 'hsutil';
    -  10import { Ticks,
    -  11         TickDefs,
    -  12         TickLabel,
    -  13         ScaleCfg }     from './AxesTypes';
    -  14
    -  15
    -  16function addTickNumber(t:TickDefs, v:number) { 
    -  17    t.labels.push({ pos: v, text: ''+Math.round(v*1000000)/1000000 }); 
    -  18}
    -  19
    -  20function addTickDate(t:TickDefs, v:Date, fmt:string) { 
    -  21    t.labels.push({ pos: v.getTime(), text:date(fmt, v) }); 
    -  22}
    -  23
    -  24
    -  25/** calculate major and minor ticks on a lionear scale. The first and last tick will be smaller and larger than the provided domain. */
    -  26function linScaleTickMarks(dom:NumRange, ticks:Ticks, numTicks:number) {
    -  27    function addTicks(unit:number, ticks:TickDefs):number {
    -  28        let exp = Math.pow(10, Math.floor(Math.log10(unit)));
    -  29        unit = Math.floor(unit / exp)*exp;
    -  30        const min = Math.floor(dom[0]/unit)*unit;
    -  31        const max = Math.ceil(dom[1]/unit)*unit;
    -  32        for (let v=min; v<=max; v+=unit) { addTickNumber(ticks, v); }
    -  33        return unit;
    -  34    }
    -  35    const majorUnit = addTicks((dom[1] - dom[0]) / numTicks, ticks.major);
    -  36    addTicks(majorUnit / numTicks, ticks.minor);
    -  37}
    -  38
    -  39function percentScaleTickMarks(dom:NumRange, ticks:Ticks, numTicks:number) {
    -  40    const formatPercent = (m:TickLabel) => m.text = `${Math.round(m.pos)*100}%`;
    -  41    linScaleTickMarks(dom, ticks, numTicks);
    -  42    ticks.major.labels.forEach(formatPercent);
    -  43    ticks.minor.labels.forEach(formatPercent);
    -  44//    addMinMaxTicks(dom, ticks);
    -  45}
    -  46
    -  47function logScaleTickMarks(dom:NumRange, ticks:Ticks) {
    -  48    dom[0] = Math.max(dom[0], 1e-20);
    -  49    dom[1] = Math.max(dom[1], 1e-20);
    -  50    let dif = Math.pow(10, Math.floor(Math.log10(dom[1] - dom[0])));
    -  51    let min = Math.pow(10, Math.floor(Math.log10(dom[0])));
    -  52    let max = Math.pow(10, Math.ceil(Math.log10(dom[1])));
    -  53    if (dif > min) {
    -  54        for (let v = min; v<=max; v*=10) {
    -  55            for (let i=1; i<=20; i++) {
    -  56                if (i===1 && v*i -  57                else if (i%10===0) {}
    -  58                else if (i<10) {        addTickNumber(ticks.minor, v*i); }
    -  59                else if (i%2===0) {     addTickNumber(ticks.minor, v*i); }
    -  60            }
    -  61        }
    -  62    } else {
    -  63        min = Math.floor(dom[0]/dif)*dif;
    -  64        max = Math.ceil(dom[1]/dif)*dif;
    -  65        if ((max-min)/dif < 4) { 
    -  66            dif /= 2; 
    -  67        }
    -  68        for (let v = min; v<=max; v+=dif) {
    -  69            addTickNumber(ticks.major, v);
    -  70        }
    -  71        addTickNumber(ticks.major, min);
    -  72        addTickNumber(ticks.major, max);
    -  73    }
    -  74}
    -  75
    -  76const tickCategories = [
    -  77    [10,0,0,0], [5,0,0,0], [2,0,0,0], [1,0,0,0], [0,6,0,0], [0,3,0,0], [0,1,0,0], [0,0,7,0], [0,0,1,0], [0,0,0,4], [0,0,0,1]
    -  78];
    -  79
    -  80function dateScaleTickMarks(dom:Domain, ticks:Ticks, fmt='%MM/%DD/%YY') {
    -  81    function addDates(i:number, tickDefs:TickDefs) {
    -  82        const createDate = (idx:number) => new Date(
    -  83            Math.floor(
    -  84   /* yr*/  dateDom[idx].getFullYear()/modYr)*modYr + (idx?incYr:0),
    -  85   /* mo*/  (incYr > 0)? 0 : Math.floor(dateDom[idx].getMonth()/modMo)*modMo + (idx?incMo:0),
    -  86   /* d */  (incMo > 0)? 1 : (dateDom[idx].getDate()- ((incDay === 7)? dateDom[idx].getDay() : 0)) + (idx?incDay:0),
    -  87   /* h */  (incDay> 0)? 0 : (dateDom[idx].getHours()) + (idx?incHour:0)
    -  88        );
    -  89        const incYr   = tickCategories[i][0]; 
    -  90        const incMo   = tickCategories[i][1]; 
    -  91        const incDay  = tickCategories[i][2];
    -  92        const incHour = tickCategories[i][3];
    -  93        const modYr   = incYr || 1;
    -  94        const modMo   = incMo || 1;
    -  95        const date0   = createDate(0);
    -  96        const date1   = createDate(1);
    -  97        fmt = incHour? '%hh:%mm' : '%MM/%DD/%YY';
    -  98        for (let d = date0; d<=date1; d = new Date(d.getFullYear()+incYr, d.getMonth()+incMo, d.getDate()+incDay, d.getHours()+incHour)) { 
    -  99            addTickDate(tickDefs, d, fmt); 
    - 100        } 
    - 101
    - 102    }
    - 103    const dateDom:Date[] = [
    - 104        (typeof dom[0] === 'number')? new Date(dom[0]) : dom[0], 
    - 105        (typeof dom[1] === 'number')? new Date(dom[1]) : dom[1]
    - 106    ];
    - 107    if (isNaN(dateDom[0].getTime())) { dateDom[0] = new Date('1/1/1980'); } 
    - 108    if (isNaN(dateDom[1].getTime())) { dateDom[0] = new Date(); } 
    - 109    const d = dateDom[1].getTime() - dateDom[0].getTime();
    - 110    tickCategories.some((cat:number[], i:number) => {
    - 111        const dMin = ms.fromDays((cat[0]*365 + cat[1]*30 + cat[2])) + ms.fromHours(cat[3]);
    - 112        if (d>3*dMin) {
    - 113            addDates(i, ticks.major);
    - 114            addDates(Math.min(i+1, tickCategories.length-1), ticks.minor);
    - 115            return true;
    - 116        } else {
    - 117            return false;
    - 118        }
    - 119    });
    - 120}
    - 121
    - 122/** calculates major tick label domain values */
    - 123function createTickLabels(type:string, domain:Domain, numTicks:number, fmt:string):Ticks {
    - 124    const sort = (a:TickLabel,b:TickLabel) => a.pos-b.pos;
    - 125    function sortTicks() { 
    - 126        ticks.minor.labels.sort(sort); ticks.major.labels.sort(sort); 
    - 127    };
    - 128    const dom:NumRange = [domain[0], domain[1]];
    - 129    const ticks:Ticks = {
    - 130        major: {marks:[], labels: []},
    - 131        minor: {marks:[], labels: []}
    - 132    };
    - 133    switch(type) {
    - 134        case Axes.type.log:     logScaleTickMarks(dom, ticks); sortTicks(); break;
    - 135        case Axes.type.date:    dateScaleTickMarks(dom, ticks, fmt); sortTicks(); break;
    - 136        case Axes.type.percent: percentScaleTickMarks(dom, ticks, numTicks); sortTicks(); break;
    - 137        case Axes.type.ordinal: break; 
    - 138        case Axes.type.nominal: break;
    - 139        case Axes.type.index:   
    - 140        case Axes.type.linear:
    - 141        default:                linScaleTickMarks(dom, ticks, numTicks); sortTicks(); 
    - 142    }  
    - 143    return ticks;
    - 144}
    - 145
    - 146
    - 147/**
    - 148 * translates a domain into a range
    - 149 */

    - 150export class Scale {    
    - 151    /** Defines default values for all configurable parameters */
    - 152    private typeVal:string      = Axes.type.linear;
    - 153    private rangeVal:NumRange   = [0,1];
    - 154    private domVal:Domain       = [0,1];
    - 155    private domMinAuto          = 0; // 0: explicit domain; 1: auto domain loose, 2: auto tight
    - 156    private domMaxAuto          = 0; // 0: explicit domain; 1: auto domain loose, 2: auto tight
    - 157    private labelFmt:string;
    - 158
    - 159    constructor(private cfg:ScaleCfg) { 
    - 160        this.scaleType(cfg.type);
    - 161        this.domain(cfg.domain);
    - 162    }
    - 163
    - 164    public setLabelFormat(labelFmt:string) {
    - 165        this.labelFmt = labelFmt;
    - 166    }
    - 167
    - 168    public range(r?:NumRange):NumRange   { 
    - 169        if (r) { 
    - 170            this.rangeVal = r; 
    - 171        }
    - 172        return this.rangeVal;
    - 173    }
    - 174    public domain(dom?:Domain):Domain { 
    - 175        if (dom) {
    - 176            if (this.scaleType() === Axes.type.date) {
    - 177                if (typeof dom[0] === 'string'|| typeof dom[1] === 'string') {
    - 178                    this.domVal[0] = (dom[0] === 'auto')? 0 : Date.parse(dom[0]); 
    - 179                    this.domVal[1] = (dom[1] === 'auto')? 1 : Date.parse(dom[1]); 
    - 180                }
    - 181            } else {
    - 182                    this.domVal[0] = (dom[0] === 'auto')? 0 : dom[0]; 
    - 183                    this.domVal[1] = (dom[1] === 'auto')? 1 : dom[1]; 
    - 184            }
    - 185            switch(dom[0]) {
    - 186                case 'tight' : this.domMinAuto = 2; break;
    - 187                case 'auto' :  this.domMinAuto = 1; break;
    - 188                default:       this.domMinAuto = 0;
    - 189            }
    - 190            switch(dom[1]) {
    - 191                case 'tight' : this.domMaxAuto = 2; break;
    - 192                case 'auto' :  this.domMaxAuto = 1; break;
    - 193                default:       this.domMaxAuto = 0;
    - 194            }
    - 195        }
    - 196        if (this.typeVal === Axes.type.log) {
    - 197            if (this.domVal[1] <= 0) { this.domVal[1] = 10; }
    - 198            if (this.domVal[0] <= 0) { this.domVal[0] = (this.domVal[1])/10; }
    - 199        }
    - 200        return this.domVal;
    - 201    }
    - 202    public scaleType(s?:string):string {
    - 203        if (s) { 
    - 204            this.typeVal = s; 
    - 205        }
    - 206        return this.typeVal;
    - 207    }
    - 208
    - 209    /**
    - 210     * If a `domain` limit is set to `auto`, calling this function tells the `Scale`
    - 211     * what the values of the min or max of the data set in the `domain` range are. 
    - 212     * These will be rounded down (for min) and up (for max) to determine the auto-range.
    - 213     * @param dom the `[min,max]` range of the data
    - 214     */

    - 215    public setAutoDomain(dom:NumRange) {
    - 216        const ticks:Ticks = createTickLabels(this.scaleType(), dom, 4, this.labelFmt);
    - 217        switch (this.domMinAuto) {
    - 218            case 1: this.domVal[0] = ticks.major.labels[0]? ticks.major.labels[0].pos : dom[0]; break; // loose
    - 219            case 2: this.domVal[0] = dom[0]; break;             // tight
    - 220        }
    - 221        switch (this.domMaxAuto) {
    - 222            case 1: this.domVal[1] = ticks.major.labels[ticks.major.labels.length-1].pos; break;
    - 223            case 2: this.domVal[1] = dom[1]; break;
    - 224        }
    - 225    }
    - 226
    - 227    /**
    - 228     * Calculates major and minor tick marks in domain coordinates
    - 229     */

    - 230    public ticks(numTicks:number=4):Ticks   { 
    - 231        function marksFromLabels(ticks:Ticks, type:string) {
    - 232            switch(type) {
    - 233                case Axes.type.nominal: 
    - 234                case Axes.type.index:   
    - 235                    const numLabels = ticks.major.labels.length;
    - 236                    ticks.major.marks = Array(numLabels+1).fill(1).map((e:any, i:number) => i-0.5);
    - 237                    ticks.minor.marks = ticks.minor.labels? ticks.minor.labels.map((l:TickLabel) => l.pos) : [];
    - 238                    break;
    - 239                case Axes.type.log: 
    - 240                case Axes.type.date:    
    - 241                case Axes.type.percent: 
    - 242                case Axes.type.ordinal:  
    - 243                case Axes.type.linear:
    - 244                default:
    - 245                    ticks.major.marks = ticks.major.labels? ticks.major.labels.map((l:TickLabel) => l.pos) : [];
    - 246                    ticks.minor.marks = ticks.minor.labels? ticks.minor.labels.map((l:TickLabel) => l.pos) : [];
    - 247            }
    - 248        }
    - 249        const dom:NumRange = [this.domain()[0], this.domain()[1]];
    - 250        const inRange = (t:TickLabel) => t.pos>=dom[0] && t.pos<=dom[1];
    - 251        const ticks:Ticks =  createTickLabels(this.scaleType(), this.domain(), numTicks, this.labelFmt);
    - 252        ticks.minor.labels = ticks.minor.labels.filter(inRange);
    - 253        ticks.major.labels = ticks.major.labels.filter(inRange);
    - 254        if (ticks.major.labels.length === 0) { ticks.major.labels = ticks.minor.labels; ticks.minor.labels = []; }
    - 255        marksFromLabels(ticks, this.scaleType());
    - 256        return ticks;
    - 257    }
    - 258    
    - 259    /** converts a domain value to a range value */
    - 260    convert(domVal:number):number { 
    - 261        const dom = this.domain();
    - 262        const range = this.range();
    - 263        const domMin = dom[0];
    - 264        const domMax = dom[1];
    - 265        let result;
    - 266        switch(this.scaleType()) {
    - 267            case Axes.type.log: 
    - 268                result = Math.log(domVal/domMin) / Math.log(domMax/domMin) * (range[1] - range[0]) + range[0];
    - 269                break;
    - 270            case Axes.type.nominal: break;
    - 271            case Axes.type.date:    
    - 272            case Axes.type.percent: 
    - 273            case Axes.type.index:   
    - 274            case Axes.type.ordinal:  
    - 275            case Axes.type.linear:
    - 276            default:
    - 277                result = (domVal- domMin) / (domMax - domMin) * (range[1] - range[0]) + range[0];
    - 278        }
    - 279        return result;
    - 280    }
    - 281}
    - 282
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/Series.html b/docs/src/hsGraph/Series.html deleted file mode 100644 index 79e9e2e..0000000 --- a/docs/src/hsGraph/Series.html +++ /dev/null @@ -1,380 +0,0 @@ - - -

    Series.ts

    -
       1/**
    -   2 * # Series
    -   3 * renders the one or more series in a variety of styles.
    -   4 * 
    -   5 * ### Configurations and Defaults
    -   6 * See {@link Series.Series.defaultConfig Series.defaultConfig} for defaults
    -   7 * and {@link Series.SeriesDef SeriesDef} for defining configuration details.
    -   8 * 
    -   9 * ### Attributes
    -  10 * The `Series` class is called by {@link Graph.Graph `Graph`} as 
    -  11 * `m(Series, { cfg:cfg.series, scales:scales, data:this.data })`
    -  12 * with the following attributes:
    -  13 * - cfg: {@link Series.SeriesConfig `SeriesConfig`} configuration parameters for series
    -  14 * - scales: {@link Axes.XYScale `XYScale`} the scales to use
    -  15 * - data: {@link hsData:Data.Data `Data`} array of `Data` sets to use, indexed by cfg[].dataIndex
    -  16 * 
    -  17 * @module Series
    -  18 */

    -  19
    -  20/** */
    -  21import { m, Vnode}      from 'hslayout';
    -  22import { Config,
    -  23         VisibleCfg }   from './Graph';
    -  24import { Data, 
    -  25         DataSet }      from 'hsdata';
    -  26import { Condition }    from 'hsdata';
    -  27import { SVGElem }      from './SVGElem';
    -  28import { Axes }         from './Axes';
    -  29import { XYScale }      from './AxesTypes';
    -  30import { PlotLine }     from './PlotLine';
    -  31import { PlotMarkers }  from './PlotMarkers';
    -  32import { PlotBar }      from './PlotBar';
    -  33import { PlotArea }     from './PlotArea';
    -  34
    -  35
    -  36function copyDefault(target:any, source:any, defaults:any) {
    -  37    Object.keys(source).forEach((key:string) => {
    -  38        if (typeof source[key] === 'object') { 
    -  39            if (target[key] === undefined) { target[key] = {}; }
    -  40            copyDefault(target[key], source[key], defaults); 
    -  41        } else {
    -  42            if (target[key] === undefined) { target[key] = source[key]; }
    -  43            if (target[key] === 'default') { target[key] = defaults[key]; }
    -  44        }
    -  45    });
    -  46}
    -  47
    -  48/**
    -  49 * 
    -  50 */

    -  51export class Series extends SVGElem { 
    -  52    /**
    -  53     * Defines available styles for series marker:
    -  54     * - circle
    -  55     * - square
    -  56     * - diamond
    -  57     * - upTriangle
    -  58     * - downTriangle
    -  59     */

    -  60    static marker = {
    -  61        circle:         Symbol('circle marker'),
    -  62        square:         Symbol('square marker'),
    -  63        diamond:        Symbol('diamond marker'),
    -  64        upTriangle:     Symbol('upward triangle marker'),
    -  65        downTriangle:   Symbol('downward triangle marker')
    -  66    };
    -  67
    -  68    /**
    -  69     * Defines available plot types:
    -  70     * - line
    -  71     * - bar
    -  72     */

    -  73    static plot = {
    -  74        line:    new PlotLine(),
    -  75        marker:  new PlotMarkers(),
    -  76        bar:     new PlotBar(),
    -  77        area:    new PlotArea()
    -  78    };
    -  79
    -  80    static map = {
    -  81        stacked: 'stacked',
    -  82        shared:  'shared'
    -  83    };
    -  84
    -  85    /** 
    -  86     * Defines default values for all configurable parameters in `Series`
    -  87     * See {@link Graph.Graph.makeConfig Graph.makeConfig} for the sequence of initializations.
    -  88     * 
    -  89     * ### Configurations and Defaults
    -  90     * ```
    -  91     *  cfg.series = {@link Series.SeriesConfig }{
    -  92     *          // pool of `Data` sets to be plotted, initialized as `[]`
    -  93     *      data: {@link hsData:Data.DataSet },     
    -  94     *          // series an markers are clipped to the plot area
    -  95     *      clip: true,       
    -  96     *          // array of series descriptors, initialized to empty array (no series)
    -  97     *      series: {@link Series.SeriesDef }[],
    -  98     *          // sets the default colors that will be assigend to series by index
    -  99     *      defaultColors:
    - 100     *          ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f', '#000', '#444', '#888', '#ccc'],
    - 101     *          // sets the default style to be applied to series
    - 102     *      defaultStyle: {@link Series.SeriesStyle } {
    - 103     *          line:   { 
    - 104     *              color: , // the line color to use, preset from defaultColors
    - 105     *              width: 5,       // the line width in viewbox units
    - 106     *              visible: true   // whether line is draw or not
    - 107     *          },
    - 108     *          marker: { 
    - 109     *              color: , // the marker color to use, preset from defaultColors
    - 110     *              size: 10,       // the marker size in viewbox coordinates
    - 111     *              shape: Series.marker.circle, // the marker shaper, See {@link Series.Series.marker Series.marker}
    - 112     *              visible: true 
    - 113     *          },
    - 114     *          fill: { 
    - 115     *              color: , // the fill color to use, preset from defaultColors
    - 116     *              visible: true 
    - 117     *          },
    - 118     *          bar: { 
    - 119     *              color: , // the bar color to use, preset from defaultColors
    - 120     *              width: 10,
    - 121     *              visible: true 
    - 122     *          }
    - 123     *      }
    - 124     *  } 
    - 125     * ``` 
    - 126     * @param cfg the configuration object, containing default settings for all 
    - 127     * previously configured components.
    - 128     */

    - 129    static defaultConfig(cfg:Config) {
    - 130        cfg.series = new SeriesConfig();
    - 131    }
    - 132
    - 133    /**
    - 134     * Makes adjustments to cfg based on current settings
    - 135     * @param cfg the configuration object, containing default settings for all components
    - 136     */

    - 137    static adjustConfig(cfg:Config) { 
    - 138        cfg.series.series.forEach((s:SeriesDef) => {
    - 139            if (s.x === undefined) { // undefined x-value -> use index as x-value
    - 140                cfg.axes.primary.x.title.hOffset = 0;
    - 141                cfg.axes.primary.x.scale.type = Axes.type.index;
    - 142                cfg.grid.minor.ver.visible = false;
    - 143            }
    - 144        });
    - 145    }
    - 146    
    - 147    drawClipRect(clipID:string, scales:XYScale) {
    - 148        return !clipID? m('') : this.clipRect(
    - 149            {   x:scales.x.range()[0], y:scales.y.range()[1]}, 
    - 150            {
    - 151                w:scales.x.range()[1] - scales.x.range()[0], 
    - 152                h:scales.y.range()[0] - scales.y.range()[1]
    - 153            }, 
    - 154            clipID);
    - 155    }
    - 156
    - 157    view(node?: Vnode): Vnode {
    - 158        const cfg:SeriesConfig  = node.attrs.cfg;
    - 159        const scales:XYScale = node.attrs.scales.primary;
    - 160        const data:Data[]    = node.attrs.data;
    - 161        const clipID = cfg.clip? 'hs'+Math.floor(Math.random()*10000) : undefined;
    - 162        cfg.series.map((s:SeriesDef) => {
    - 163            if (s.map === Series.map.shared) {  // reset ySum if needed
    - 164                s.ySum = '$sum';
    - 165                data[s.dataIndex].colAdd(s.ySum);            // add $max if not present
    - 166                data[s.dataIndex].colInitialize(s.ySum, 0);  // and initialize to 0
    - 167            }
    - 168        });
    - 169        cfg.series.map((s:SeriesDef) => {
    - 170            const dt = data[s.dataIndex];
    - 171            if (s.map===Series.map.shared) {    // aggregate ySum over series
    - 172                const valCol = dt.colNumber(s.y);                       
    - 173                dt.colInitialize(s.ySum, (v:number, i:number, row:number[])=>{ return v+row[valCol]; });
    - 174            }
    - 175            if (s.map) {
    - 176                s.yBase = '$'+ s.map;
    - 177                dt.colAdd(s.yBase);             // add $stacked or $shared if not present
    - 178                dt.colInitialize(s.yBase, 0);   // and initialize to 0
    - 179            }
    - 180        });
    - 181        return m('svg', { class:'hs-graph-series'}, [
    - 182            this.drawClipRect(clipID, scales),
    - 183            m('svg', cfg.series.map((s:SeriesDef, i:number) => { 
    - 184                const dt = data[s.dataIndex];
    - 185                const type = Series.plot[s.type] || Series.plot.line;
    - 186                type.setDefaults(dt, s, scales);
    - 187                const d = s.cond? dt.filter(s.cond) : dt;
    - 188                const plot = type.plot(d, s, scales, i, clipID);  // plot y above yBase; 
    - 189                if (s.map) {                                      // if 'stacked' or 'shared' -> accumulate y
    - 190                    const valCol = d.colNumber(s.y);                       
    - 191                    d.colInitialize(s.yBase, (v:number, i:number, row:number[])=>{ return v+row[valCol]; });
    - 192                }
    - 193                return m('svg', {class:`hs-graph-series-${i}`}, plot);
    - 194            }))
    - 195        ]);
    - 196    }
    - 197}
    - 198
    - 199export interface ColoredCfg extends VisibleCfg {
    - 200    /** the color in hex */
    - 201    color: string;
    - 202}
    - 203export interface LineStyle extends ColoredCfg {
    - 204    /** the stroke width in px */
    - 205    width: number; 
    - 206}
    - 207
    - 208export interface MarkerStyle extends ColoredCfg {
    - 209    /** the stroke width in px */
    - 210    size:  number;      
    - 211
    - 212    /** the marker shape, selected from {@link Series.Series.marker Series.marker} */
    - 213    shape: Symbol;              
    - 214}
    - 215
    - 216export interface FillStyle extends ColoredCfg {
    - 217}
    - 218
    - 219export interface TextStyle extends ColoredCfg {
    - 220}
    - 221
    - 222export interface BarStyle extends ColoredCfg {
    - 223    /** width of bars in % of space between bars */
    - 224    width: number;  
    - 225    
    - 226    /** offset between column series in % between bars */
    - 227    offset:number; 
    - 228}
    - 229
    - 230export interface SeriesStyle {
    - 231    line:   LineStyle;
    - 232    marker: MarkerStyle;
    - 233    fill:   FillStyle;
    - 234    bar:    BarStyle;
    - 235    label:  TextStyle;
    - 236}
    - 237
    - 238/** 
    - 239 * Defines Series columns and values to use, as well as the plot type to apply.
    - 240 * The following settings are available for configuration:
    - 241 * ```
    - 242 * cfg.series.series = [{
    - 243 *    type: TYPE,        // the series type, e.g. 'line', etc. See below.
    - 244 *    dataIndex: number, // the `Data` set to use. The index refers to the position in `series.data`
    - 245 *    x: string,         // the column name or index of the x-coordinate to use for drawing
    - 246 *    y: string,         // the column name or index of the y-coordinate to use for drawing
    - 247 *    yBase: string,     // if specified, used as lower series for filling the area
    - 248 *    l: string,         // the column name or index to use for series labels
    - 249 *    hOffset: number;   // horizontal label offset in em o
    - 250 *    vOffset?: number;  // vertical label offset in em
    - 251 *    map?: 'stacked' | 'shared'; // stack series, or show the share (normalize to 100%)
    - 252 *    style: {@link SeriesStyle SeriesStyle},  // allows overriding a default style setting
    - 253 *    cond: {@link hsData:DataFilters.Condition Condition} // allows specifying a filter applied to data before rendering.
    - 254 * }]
    - 255 * ```
    - 256 * The following series s are available. For configuration details, see:
    - 257 * - 'line':  (or omitted): {@link PlotLine PlotLine}
    - 258 * - 'markers': {@link PlotMarkers PlotMarkers}
    - 259 * - 'area':    {@link PlotArea PlotArea}
    - 260 * - 'bar':     {@link PlotBar PlotBar}
    - 261 */

    - 262export interface SeriesDef {
    - 263    /** 
    - 264     * required column names or indices. 
    - 265     * [0] is reserved for the x direction. 
    - 266     * Further elements are dependent on the {@link Series.type plot} type. 
    - 267     */

    - 268    x:string;               // x values
    - 269    y?:string;              // y values
    - 270    yBase?:string;          // if specified, treats (y/yBase) as (high/low) series
    - 271    ySum?:string;           // internal support column for 'shared' mode;
    - 272    l?:string;              // labels
    - 273    hOffset?: number;       // offset in em
    - 274    vOffset?: number;       // offset in em
    - 275    map?: string;           // accepts 'stacked'and 'shared'
    - 276    /** An index into the `Data[]` pool, identifying the `Data` set to use. defaults to `0` */
    - 277    dataIndex?: number;
    - 278    /** optional plot type, selected from {@link Series.Series.plot Series.plot} as string; defaults to  'line' */
    - 279    type?:string;   
    - 280    /** style information to use for plotting; if ommitted, a `type`-dependent default is used */
    - 281    style?:SeriesStyle;
    - 282    /** optinal filter condition on the data prior to drawing */
    - 283    cond?: Condition;
    - 284}
    - 285
    - 286
    - 287/** 
    - 288 * Defines the default settings. 
    - 289 * Implemented as a class rather than interface to allow for a getter/setter implementation
    - 290 * of `series`. This allows for postprocessing user configurations while maintaining 
    - 291 * convenient notation, e.g.
    - 292 * ```
    - 293 *  cfg.series.series = [           // invoke the setter
    - 294 *      { x:'time', y:'volume'},    // behind the scenes, adds 
    - 295 *      { x:'time', y:'price']}     // missing fields such as .style
    - 296 *  ];
    - 297 *  fg.series.series[0].style.marker.visible = true;    // invoke the getter
    - 298 * ```
    - 299 */

    - 300export class SeriesConfig {
    - 301    private seriesDefs:SeriesDef[] = [];
    - 302
    - 303    /** 
    - 304     * the `DataSet`s to be used for plots.
    - 305     * Each set describes the column names and the rows-of-columns data.
    - 306     * The `SeriesDef.dataIndex` determines which set to use.
    - 307     */

    - 308    public data: DataSet[]; 
    - 309
    - 310    /** determines if seires plot will be clipped to the chart area */
    - 311    public clip = true;   
    - 312
    - 313    /** 
    - 314     * determines the default style applied to each series.
    - 315     * Colors will be chosen by series index from `defaultColors`.
    - 316     */

    - 317    public defaultStyle:SeriesStyle = {
    - 318        line:   { color:'default', visible: true, width: 2},
    - 319        marker: { color:'default', visible: false, size: 10, shape: Series.marker.circle},
    - 320        label:  { color:'default', visible: false },
    - 321        fill:   { color:'default', visible: false },
    - 322        bar:    { color:'default', visible: false, width: 50, offset: 30 }
    - 323    };       
    - 324           
    - 325    /** determines the default color for the first couple of series */
    - 326    public defaultColors = ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f', '#000', '#444', '#888', '#ccc'];
    - 327
    - 328    /** 
    - 329     * `series` accessor method: array of series definitions to define plots. 
    - 330     * 
    - 331     */

    - 332    public set series(cfg: SeriesDef[]) {    // array of series descriptions
    - 333        const defStyle = this.defaultStyle;
    - 334        const defColors = this.defaultColors;
    - 335        cfg.forEach((s:SeriesDef) => {
    - 336            s.type = s.type || 'line';
    - 337            s.style = s.style || {};
    - 338            s.dataIndex = s.dataIndex || 0;
    - 339            const defaults = {
    - 340                color:defColors[this.seriesDefs.length]
    - 341            };
    - 342            copyDefault(s.style, defStyle, defaults);
    - 343            this.seriesDefs.push(s);
    - 344            switch (s.type) {
    - 345                case 'line': 
    - 346                    s.style.line.visible = true; 
    - 347                    break;
    - 348                case 'marker': 
    - 349                    s.style.marker.visible = true; 
    - 350                    break;
    - 351                case 'area': 
    - 352                    s.style.fill.visible = true; 
    - 353                    break;
    - 354                case 'bar': 
    - 355                    s.style.fill.visible = true; 
    - 356                    break;
    - 357            }
    - 358        });
    - 359    }
    - 360    public get series():SeriesDef[] { return this.seriesDefs; }
    - 361}
    - 362
    - 363
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/SeriesLine.html b/docs/src/hsGraph/SeriesLine.html deleted file mode 100644 index 418536e..0000000 --- a/docs/src/hsGraph/SeriesLine.html +++ /dev/null @@ -1,18 +0,0 @@ - - -

    SeriesLine.ts

    -
       1
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/example/start.html b/docs/src/hsGraph/example/start.html deleted file mode 100644 index b2bc19b..0000000 --- a/docs/src/hsGraph/example/start.html +++ /dev/null @@ -1,19 +0,0 @@ - - -

    example/start.ts

    -
       1import { Graph } from '../';
    -   2if (Graph) {}
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/hsGraph.html b/docs/src/hsGraph/hsGraph.html deleted file mode 100644 index 68354ae..0000000 --- a/docs/src/hsGraph/hsGraph.html +++ /dev/null @@ -1,182 +0,0 @@ - - -

    HsGraph.ts

    -
       1/**
    -   2 * # HsGraph
    -   3 * 
    -   4 * 
    -   5 * let series = [
    -   6 *      ['time', 'volume'],
    -   7 *      [-1, 0.2],
    -   8 *      [0.2, 0.7],
    -   9 *      [0.4, -0.2],
    -  10 *      [0.6, 0],
    -  11 *      [0.8, 0.5],
    -  12 *      [1, 0.7]
    -  13 * ];
    -  14 * 
    -  15 * const cfg = {
    -  16 *      series: { 
    -  17 *          data: series, 
    -  18 *          series: [{ xHeader: 'time', yHeader:'volume'}],
    -  19 *          chart: { title: { text: 'Volume over Time' }}
    -  20 *      },
    -  21 *      axes: { primary: { x: { title:'time' }, y: { title:'volume' }}}
    -  22 * }
    -  23 * m.mount(root, { 
    -  24 *      view:() => m(hsgraph.Graph, {cfg: cfg})
    -  25 * });
    -  26 *
    -  27 * 
    -  28 * 
    -  29 * .hs-graph-chart { fill: #fff; }
    -  30 * .hs-graph-series { stroke-width: 5;
    -  31 * 
    -  32 * 

    -  33
    -  34 */

    -  35
    -  36/** */
    -  37import { m, Vnode}           from 'hslayout';
    -  38import { Axes, AxisSet }     from './Axes';
    -  39import { Scale, ScaleSet }   from './Scale';
    -  40import { Canvas, CanvasSet } from './Canvas';
    -  41import { Series, SeriesSet } from './Series';
    -  42import { Chart, ChartSet }   from './Chart';
    -  43import { Grid, GridSet }     from './Grid';
    -  44import { Legend }            from './Legend';
    -  45import { SVGElem }           from './SVGElem';
    -  46
    -  47const viewBoxWidth:number  = 1000;  // the viewBox size
    -  48let   viewBoxHeight:number = 700;   // the viewBox size
    -  49const marginLeft:number    = 50;
    -  50const marginRight:number   = 10;
    -  51const marginTop:number     = 60;
    -  52const marginBottom:number  = 80;
    -  53
    -  54export interface Point {
    -  55    x: number|string;
    -  56    y: number|string;
    -  57}
    -  58export interface Area {
    -  59    w: number|string;
    -  60    h: number|string;
    -  61}
    -  62export interface Config {
    -  63    viewBox:  { w: number; h: number; };
    -  64    plotArea: { t: number; l: number; w: number; h: number; };
    -  65    scale?:  ScaleSet;
    -  66    canvas?: CanvasSet;
    -  67    axes?:   AxisSet;
    -  68    chart?:  ChartSet;
    -  69    grid?:   GridSet;
    -  70    series?: SeriesSet;
    -  71    legend?:{
    -  72
    -  73    };
    -  74}
    -  75/**
    -  76 * Creates a deep copy of `def`, taking fields present in `update` to supercede the default value.
    -  77 * @param def contains the default setting for each parameter
    -  78 * @param update contains updates to some or all of the settings
    -  79 */

    -  80function copy(def:any, update:any):any {
    -  81    let result:any = {};
    -  82    Object.keys(def).map((k:string) => {
    -  83        if (typeof def[k] === 'object' && !Array.isArray(def[k]) && def[k]!==null) {
    -  84            result[k] = copy(def[k], update[k] || {});
    -  85        } else {
    -  86            result[k] = update[k] || def[k];
    -  87        }
    -  88    });
    -  89    return result;
    -  90}
    -  91
    -  92export class HsGraph extends SVGElem {
    -  93    static defConfig:Config = {
    -  94        viewBox:  { w: viewBoxWidth, h: viewBoxHeight },
    -  95        plotArea: { t: marginTop, l: marginLeft, 
    -  96                    w: viewBoxWidth - marginRight - marginLeft,
    -  97                    h: viewBoxHeight - marginTop - marginBottom
    -  98                  }
    -  99    };
    - 100
    - 101    static config(config=HsGraph.defConfig) {
    - 102        Canvas.config(config);
    - 103        Scale.config(config);
    - 104        Axes.config(config);
    - 105        Series.config(config);
    - 106        Grid.config(config);
    - 107        Chart.config(config);
    - 108        Legend.config(config);
    - 109        return config;
    - 110    }
    - 111    
    - 112    private scales = { 
    - 113        primary:  <{x:Scale, y:Scale}> { },
    - 114        secondary:<{x:Scale, y:Scale}> { }
    - 115    };
    - 116
    - 117    private createScales(cfg:any) {
    - 118        const cg = cfg.graph;
    - 119        const cs = cfg.scale;
    - 120        if (!this.scales.primary.x) { 
    - 121            this.scales.primary.x   = new Scale(cs.primary.x);
    - 122            this.scales.primary.y   = new Scale(cs.primary.y);
    - 123            this.scales.secondary.x = new Scale(cs.secondary.x);
    - 124            this.scales.secondary.y = new Scale(cs.secondary.y);
    - 125        }
    - 126        this.scales.primary.x.range   = [cg.left, cg.right];
    - 127        this.scales.primary.y.range   = [cg.bottom, cg.top];
    - 128        this.scales.secondary.x.range = [cg.left, cg.right];
    - 129        this.scales.secondary.y.range = [cg.bottom, cg.top];
    - 130    }
    - 131
    - 132    adjustHeight(node?: Vnode) {
    - 133        if (node.dom && node.dom.parentElement) {
    - 134            const p = node.dom.parentElement;
    - 135            const temp = viewBoxWidth * p.clientHeight / p.clientWidth;
    - 136            if (!isNaN(temp) && temp !== viewBoxHeight) {
    - 137                viewBoxHeight = temp; 
    - 138                console.log('new height = ' + temp);
    - 139            }
    - 140        }
    - 141    }
    - 142
    - 143    onupdate(node?: Vnode) { this.adjustHeight(node); }
    - 144    oncreate(node?: Vnode) {
    - 145        this.adjustHeight(node);
    - 146        window.addEventListener("resize", function() { m.redraw(); });
    - 147    }
    - 148
    - 149    view(node?: Vnode): Vnode {
    - 150        const cp = copy(HsGraph.config(), node.attrs.cfg || {});
    - 151        const cg = cp.graph;
    - 152        this.createScales(cp);
    - 153        return m('svg', { class:'hs-graph', width:'100%', height:'100%', viewBox:`0 0 ${cg.range.w} ${cg.range.h}`, preserveAspectRatio:'xMaxYMin'}, [
    - 154            m(Canvas, { cfg:cp.canvas}),
    - 155            m(Chart, { cfg:cp.chart, x:cg.left, y:cg.top, 
    - 156                       width: cg.right-cg.left, height:cg.bottom-cg.top }),
    - 157            m(Axes, { cfg:cp.axes, scales:this.scales }),
    - 158            m(Grid, { cfg:cp.grid, scales:this.scales }),
    - 159            m(Series, { cfg:cp.series, scales:this.scales }),
    - 160            m(Legend, { cfg:cp.legend })
    - 161        ]);
    - 162    }
    - 163}
    - 164
    - 165
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/index.html b/docs/src/hsGraph/index.html deleted file mode 100644 index b05fa4f..0000000 --- a/docs/src/hsGraph/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - -

    index.ts

    -
       1export { Graph }    from './Graph';
    -   2export { Series,
    -   3         SeriesDef
    -   4         }          from './Series';
    -   5export { Axes }     from './Axes';
    -   6export { Scale }    from './Scale';
    -   7export { Grid }     from './Grid';
    -   8export { Legend }   from './Legend';
    -   9
    - - \ No newline at end of file diff --git a/docs/src/hsGraph/overview.html b/docs/src/hsGraph/overview.html deleted file mode 100644 index d399b4d..0000000 --- a/docs/src/hsGraph/overview.html +++ /dev/null @@ -1,94 +0,0 @@ - - -

    overview.ts

    -
       1/**
    -   2# hsGraph
    -   3hsGraph is a simnple graphing utility written in JavaScript and based on the [Mithril](https://mithril.js.org) framework.
    -   4It supports various chart types and scales and provides a convenient programmatic configuration mechanism. 
    -   5
    -   6## Usage
    -   7In mithril, simply render or mount a {@link Graph Graph} Component object and provide a `cfg`
    -   8attribute with the graph's configuration.
    -   9
    -  10### Simple Example
    -  11 * 
    -  12 * 
    -  13 * let data = {
    -  14 *    colNames:['time', 'volume'],
    -  15 *    rows:[
    -  16 *      [-1, 0.2],
    -  17 *      [0.2, 0.7],
    -  18 *      [0.4, -0.2],
    -  19 *      [0.6, 0],
    -  20 *      [0.8, 0.5],
    -  21 *      [1, 0.7]
    -  22 * ]};
    -  23 * 
    -  24 * m.mount(root, { 
    -  25 *      view:() => m(hsgraph.Graph, {cfgFn: cfg => {
    -  26 *          cfg.chart.title.text          = 'Simple Example';
    -  27 *          cfg.series.data   = [data];
    -  28 *          cfg.series.series = [{ x:'time', y:'volume' }];
    -  29 *      }})
    -  30 * });
    -  31 *
    -  32 * 
    -  33 * 
    -  34 * .hs-graph-chart { fill: #fff; }
    -  35 * .hs-graph-series { stroke-width: 5; }
    -  36 * 
    -  37 * 

    -  38
    -  39 ## Setting the data to render
    -  40 Data is provided in a rows-of-columns style array: `data[row][column]`.
    -  41 The first row in the data array contains column names by which the series can be identified.
    -  42 There is no conceptual limit to the number of rows or columns provided to `hsGraph`.
    -  43 In the configuration, 
    -  44 - set the array containing the data: `series.data = data;`  
    -  45 - and specify the x- and y-columns to render, by name: `series.series = [{xHeader:, yHeader:}]`
    -  46
    -  47## Configuration
    -  48All graph components are highly configurable. `hsGraph` uses default values for all configurable fields 
    -  49that can easily be changed, either programmatically or via a custom stylesheet.
    -  50
    -  51To programmatically set rendering parameters, simply provide a configuration function `cfg => {}` 
    -  52to the `cfgFn` attribute when setting up the mithril mount call - see example above. 
    -  53The `cfgFn` receives a configuration object that is fully initialized with default values, 
    -  54and should overwrite parameters as needed. See the overview for each component for configurable 
    -  55parameters.
    -  56
    -  57Available configurations include:
    -  58-   {@link Graph.Graph.defaultConfig Graph.defaultConfig }
    -  59-   {@link Canvas.Canvas.defaultConfig Canvas.defaultConfig}
    -  60-   {@link Chart.Chart.defaultConfig Chart.defaultConfig}
    -  61-   {@link Axes.Axes.defaultConfig Axes.defaultConfig}
    -  62-   {@link Grid.Grid.defaultConfig Grid.defaultConfig}
    -  63-   {@link Series.Series.defaultConfig Series.defaultConfig}
    -  64-   {@link Legend.Legend.defaultConfig Legend.defaultConfig}
    -  65
    -  66## Graph Components
    -  67The rendered graph is organized in a layered structure of components:
    -  68-   {@link Canvas Canvas}:  the background canvas on which all components are rendered
    -  69-   {@link Chart Chart}: the chart area and title
    -  70-   {@link Axes Axes}: the x- and y-axes, tick marks and labels, and axis title
    -  71-   {@link Grid Grid}: the major and minor gridlines
    -  72-   {@link Series Series}: the one or more data series to render
    -  73-   {@link Legend Legend}: the legend for the shown series
    -  74
    -  75*/

    -  76
    -  77/** */
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/example/columns.x.html b/docs/src/hsLayout/example/columns.x.html deleted file mode 100644 index d99ca2e..0000000 --- a/docs/src/hsLayout/example/columns.x.html +++ /dev/null @@ -1,88 +0,0 @@ - - -

    example/columns.x.ts

    -
       1import { m, Vnode }             from '../mithril';
    -   2import { Container, HsConfig }  from '../';
    -   3
    -   4
    -   5const myConfig = {
    -   6    Rows: {
    -   7        columns:  [''],
    -   8        maxCount: 5,
    -   9        leafCSS: 'leaf',
    -  10        content: [
    -  11            { Rows: {
    -  12                rows: [''],
    -  13                content: [
    -  14                    { aLeaf: { css:'leaf', columns: ['']}},
    -  15                    { aLeaf: { css:'leaf', columns: ['100px'] }},
    -  16                    { aLeaf: { css:'leaf', columns: ['100px', '200px'] }},
    -  17                    { aLeaf: { css:'leaf', columns: ['20%'] }},
    -  18                    { aLeaf: { css:'leaf', columns: ['20%', 'fill'] }}
    -  19                ]
    -  20            }},
    -  21            { Rows: {
    -  22                columns: [''],
    -  23                content: [
    -  24                    { aLeaf: { css:'leaf', rows: ['']}},
    -  25                    { aLeaf: { css:'leaf', rows: ['100px'] }},
    -  26                    { aLeaf: { css:'leaf', rows: ['100px', '200px'] }},
    -  27                    { aLeaf: { css:'leaf', rows: ['20%'] }},
    -  28                    { aLeaf: { css:'leaf', rows: ['20%', 'fill'] }}
    -  29                ]
    -  30            }}
    -  31        ]
    -  32    }
    -  33};
    -  34
    -  35function next(fn:any) {
    -  36    return setTimeout(() => {
    -  37        fn();
    -  38        next(fn);
    -  39    }, 2000);
    -  40}
    -  41
    -  42const example = { 
    -  43    Rows: class extends Container {
    -  44        getComponents(node: Vnode): Vnode {
    -  45            node.attrs.content.forEach((c:any) => c.attrs.maxCount = node.attrs.maxCount);
    -  46            return super.getComponents(node);
    -  47        }
    -  48    },
    -  49    aLeaf: class extends Container {
    -  50        count = 1;
    -  51        maxCount = 0;
    -  52
    -  53        constructor() {
    -  54            super();
    -  55            next(() => {
    -  56                this.count = (this.count >= this.maxCount)? 0 : this.count+1;
    -  57                m.redraw();
    -  58            });
    -  59        }
    -  60
    -  61        getComponents(node: Vnode): Vnode {
    -  62            this.maxCount = this.maxCount = node.attrs.maxCount || 3;
    -  63            const dims = node.attrs.columns || node.attrs.rows;
    -  64            const content = [...Array(this.count).keys()].map((c:number) => `${node.attrs.columns?'Columns':'Rows'}
    ${c+1}
    [${dims.join()}]`);
    -  65            return content;
    -  66        }
    -  67    }
    -  68};
    -  69
    -  70export const cfg = new HsConfig([example]).attachNodeTree(myConfig, document.body);
    -  71
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/example/config.x.html b/docs/src/hsLayout/example/config.x.html deleted file mode 100644 index f1430de..0000000 --- a/docs/src/hsLayout/example/config.x.html +++ /dev/null @@ -1,82 +0,0 @@ - - -

    example/config.x.ts

    -
       1import { m, Vnode}  from '../mithril';
    -   2import * as hslayout from '../';
    -   3//import * as widgets from '../../hsWidgets/src/';
    -   4
    -   5const myConfig = {
    -   6    Layout: {
    -   7        rows:  ["30px", "fill", "10px"],
    -   8        css: '.my-example',
    -   9        content: [{
    -  10            Layout:{
    -  11                columns: ["200px", "fill"],
    -  12                content: [
    -  13                    { LeftHead:    { lib:"route.lib", field:"route.field"}},
    -  14                    { MainHead:    { lib:"route.lib", field:"route.field"}}
    -  15                ]
    -  16            }},{
    -  17            Layout:{
    -  18                columns: ["200px", "fill"], 
    -  19                content: [
    -  20                    { LeftNav:    { lib:"route.lib", field:"route.field"}},
    -  21                    { MainNav:    { lib:"route.lib", field:"route.field"}}
    -  22                ]
    -  23            }},
    -  24            { Layout: {
    -  25                css: '.hs-site-footer',
    -  26                content: ['(c) Helpful ; Scripts']
    -  27            }}
    -  28        ] 
    -  29    },
    -  30    route: {
    -  31        default: '/api',
    -  32        paths: [
    -  33            '/api',             // defines `http://localhost/#!/api/
    -  34            '/api/:lib',        // defines `http://localhost/#!/api/:hsLib
    -  35            '/api/:lib/:field'  // defines `http://localhost/#!/api/:hsLib/:id        
    -  36        ]
    -  37    }
    -  38}; 
    -  39
    -  40const example = {
    -  41    LeftHead: class extends hslayout.Layout{ 
    -  42        getComponents(node:Vnode) { 
    -  43            return 'The Left Head'; 
    -  44        } 
    -  45    },
    -  46    MainHead: class extends hslayout.Layout{ 
    -  47        getComponents(node:Vnode) { return m('', 'The Main Head'); } 
    -  48    },
    -  49    LeftNav: class extends hslayout.Layout{ 
    -  50        getComponents(node:Vnode) { return m('', 'The Left Nav'); } 
    -  51    },
    -  52    MainNav: class extends hslayout.Layout{ 
    -  53        getComponents(node:Vnode) { return m('', 'The Main Nav'); } 
    -  54    },
    -  55    Footer: class extends hslayout.Layout{ 
    -  56        getComponents(node:Vnode) { return m('.hs-site-footer', '(c) Helpful ; Scripts'); } 
    -  57    }
    -  58};
    -  59
    -  60
    -  61
    -  62new hslayout.HsConfig([hslayout, example])
    -  63    .attachNodeTree(myConfig, document.getElementById('exampleBase'));
    -  64
    -  65
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/example/layout.x.html b/docs/src/hsLayout/example/layout.x.html deleted file mode 100644 index 17c2ee0..0000000 --- a/docs/src/hsLayout/example/layout.x.html +++ /dev/null @@ -1,138 +0,0 @@ - - -

    example/layout.x.ts

    -
       1/**
    -   2 * # Layout Examples
    -   3 * See example page
    -   4 * 
    -   5 */

    -   6
    -   7 /** */
    -   8import { m, Vnode }             from '../mithril';
    -   9import { Layout, HsConfig }  from '../';
    -  10
    -  11
    -  12const myConfig = {
    -  13    Layout: {
    -  14        rows: ['40px', 'fill'],         // header and main body
    -  15        content: [
    -  16            { Header: { css:'.header', title: 'Layout Example'}},
    -  17            { Main: {
    -  18                tiles:  [''],           // main body wiull arrange in tiles
    -  19                maxCount: 6,
    -  20                leafCSS: 'leaf',
    -  21                content: [
    -  22                    { Layout: {
    -  23                        rows: [''],     // 1st tile: rows of varying columns
    -  24                        content: [
    -  25                            { aLeaf: { css:'leaf', columns: [' ']}},
    -  26                            { aLeaf: { css:'leaf', columns: ['100px'] }},
    -  27                            { aLeaf: { css:'leaf', columns: ['100px', '200px'] }},
    -  28                            { aLeaf: { css:'leaf', columns: ['100px', 'fill'] }},
    -  29                            { aLeaf: { css:'leaf', columns: ['100px', 'fill', '100px'] }},
    -  30                            { aLeaf: { css:'leaf', columns: ['20%'] }},
    -  31                            { aLeaf: { css:'leaf', columns: ['20%', 'fill'] }},
    -  32                            { aLeaf: { css:'leaf', columns: ['20%', 'fill', '20%'] }}
    -  33                        ]
    -  34                    }},
    -  35                    { Layout: {
    -  36                        columns: [''],  // 2nd tile: columns of varying rows
    -  37                        content: [
    -  38                            { aLeaf: { css:'leaf', rows: [' ']}},
    -  39                            { aLeaf: { css:'leaf', rows: ['100px'] }},
    -  40                            { aLeaf: { css:'leaf', rows: ['100px', '200px'] }},
    -  41                            { aLeaf: { css:'leaf', rows: ['100px', 'fill'] }},
    -  42                            { aLeaf: { css:'leaf', rows: ['100px', 'fill', '100px'] }},
    -  43                            { aLeaf: { css:'leaf', rows: ['20%'] }},
    -  44                            { aLeaf: { css:'leaf', rows: ['20%', 'fill'] }},
    -  45                            { aLeaf: { css:'leaf', rows: ['20%', 'fill', '20%'] }}
    -  46                        ]
    -  47                    }},
    -  48                    { Layout: {
    -  49                        tiles: [''],    // 3rd tile: varying tiles
    -  50                        css: 'tile_pct',
    -  51                        content: [
    -  52                            { aLeaf: { css:'leaf', tiles: [' ']}},
    -  53                            { aLeaf: { css:'leaf', tiles: ['40%', 'fill']}},
    -  54                            { aLeaf: { css:'leaf', tiles: ['40%']}},
    -  55                            { aLeaf: { css:'leaf', tiles: ['40%', '30%', 'fill']}},
    -  56                        ]
    -  57                    }},
    -  58                    { Layout: {
    -  59                        tiles: [''],    // 3rd tile: varying tiles
    -  60                        css: 'tile_px',
    -  61                        content: [
    -  62                            { aLeaf: { css:'leaf', tiles: [' ']}},
    -  63                            { aLeaf: { css:'leaf', tiles: [' ', 'fill']}},
    -  64                            { aLeaf: { css:'leaf', tiles: [' ']}},
    -  65                            { aLeaf: { css:'leaf', tiles: [' ']}},
    -  66                        ]
    -  67                    }}
    -  68                ]
    -  69            }}
    -  70        ]
    -  71    }
    -  72};
    -  73
    -  74function next(fn:any) {
    -  75    return setTimeout(() => {
    -  76        fn();
    -  77        next(fn);
    -  78    }, 2000);
    -  79}
    -  80
    -  81const example = { 
    -  82    maxCount: 0,
    -  83    Header: class extends Layout {
    -  84        getComponents(node: Vnode): Vnode {
    -  85            return m(node.attrs.css, node.attrs.title);
    -  86        }
    -  87    },
    -  88    Main: class extends Layout {
    -  89        getComponents(node: Vnode): Vnode {
    -  90            example.maxCount = node.attrs.maxCount || 3;
    -  91            return super.getComponents(node);
    -  92        }
    -  93    },
    -  94    aLeaf: class extends Layout {
    -  95        count = 1;
    -  96        inc = 1;
    -  97
    -  98        constructor() {
    -  99            super();
    - 100            next(() => {
    - 101                this.count += this.inc;
    - 102                if (this.count >= example.maxCount) { this.inc = -1; }
    - 103                if (this.count <= 1)             { this.inc = +1; }
    - 104                m.redraw();
    - 105            });
    - 106        }
    - 107
    - 108        getComponents(node: Vnode): Vnode {
    - 109            const dims = node.attrs.columns || node.attrs.rows || node.attrs.tiles;
    - 110            let text = '';
    - 111            if (node.attrs.columns) { text = 'Columns'; }
    - 112            if (node.attrs.rows) { text = 'Rows'; }
    - 113            if (node.attrs.tiles) { text = 'Tiles'; }
    - 114            const content = [...Array(this.count).keys()].map((c:number) => `${text}
    ${c+1}
    [${dims.join()}]`);
    - 115            return content;
    - 116        }
    - 117    }
    - 118};
    - 119
    - 120export const cfg = new HsConfig([example]).attachNodeTree(myConfig, document.body);
    - 121
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/example/start.html b/docs/src/hsLayout/example/start.html deleted file mode 100644 index a3c2d14..0000000 --- a/docs/src/hsLayout/example/start.html +++ /dev/null @@ -1,19 +0,0 @@ - - -

    example/start.ts

    -
       1import { cfg } from './layout.x';
    -   2if (cfg) {}
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/hsConfig.html b/docs/src/hsLayout/hsConfig.html deleted file mode 100644 index 0f81528..0000000 --- a/docs/src/hsLayout/hsConfig.html +++ /dev/null @@ -1,274 +0,0 @@ - - -

    hsConfig.ts

    -
       1/**
    -   2 * ##HsConfig 
    -   3 * Tool to configure a layout via a configuration object that is either defined
    -   4 * as an object literal or as a JSON file.
    -   5 * 
    -   6 * The structure of the configuration object follows the convention
    -   7 
    -   8 {
    -   9     
    -  10     [,route: {
    -  11        default: '/api',
    -  12        paths: [
    -  13            '/api',             
    -  14            '/api/:lib',       
    -  15            '/api/:lib/:field' 
    -  16        ]
    -  17    }]
    -  18 }
    -  19 

    -  20`` is either {@link hsLayout:Layout.Layout Layout} or a subclass thereof.
    -  21`` is an object literal `{ :[, ...] }`
    -  22
    -  23Arrays and Object Literals in `` define a layout tree that will be traversed,
    -  24After which the tree will be instantiated by calling `m()`.
    -  25Mithril will then recursively create the Classes in the tree and call their `view` methods,
    -  26where `Configuration`settings will be available via the `node.attrs` parameter.
    -  27
    -  28The default `Layout` implementation recognizes the following special `` keys:
    -  29
    -  30* - `content`: the subcomponents to render in `Layout`, allowing for following `` types:
    -  31*     - `[{}, ...]`
    -  32*     - `['string literal', ...]`
    -  33*     - `'string literal'`
    -  34* - `css`: the CSS class to set on `Layout`
    -  35* - `href`: a href attribute to set on `Layout`. This makes `Layout` clickable and sends the 
    -  36     respective attribute value to the Mithril router.
    -  37* - `onclick`: a function to call when `Layout` is clicked.
    -  38*/

    -  39
    -  40/** */
    -  41import { m, Vnode } from './mithril'; 
    -  42import * as layout from './';
    -  43
    -  44/**
    -  45 * creates a deep copy of the struct passed in.
    -  46 * @param struct the object to copy
    -  47 */

    -  48function copy(struct:any): any {
    -  49    let result:any;
    -  50    if (Array.isArray(struct)) { result = []; }
    -  51    else if (typeof struct === 'object') { result = {}; }
    -  52    else { return struct; }
    -  53    Object.keys(struct).map((k:string) => result[k] = copy(struct[k]));
    -  54    return result;
    -  55}
    -  56
    -  57
    -  58/**
    -  59 * resolves the symbol `sym` against the provided `context`.
    -  60 * If successful, returns the class definition for `sym`. 
    -  61 * @param sym the symbol to resolve
    -  62 * @param context the context to resolve against; `mithril` and `hsLayout` 
    -  63 * are implicitely part of the context and need not be specified.
    -  64 * @return the resolved Class, or `undefined`.
    -  65 */

    -  66function resolve(sym:string, context:any[]) {
    -  67    let cl:any;
    -  68    context.concat(layout).some((c:any) =>  cl = c[sym]);
    -  69    return cl;
    -  70}
    -  71
    -  72/**
    -  73 * recurses a configuration, trying to fetch the class definition for each element (key) in `config`. 
    -  74 * If successful, it creates an object literal containing the component class and its attributes.
    -  75 * If unsuccessful, the element's value is returned unaltered so that it can be consumed 
    -  76 * by an instance further up in the recursion tree.
    -  77 * @param config an object literal containing a configuration subtree
    -  78 * @param context an array of objects against which to instantiate elements of `config`.
    -  79 * @return an object literal representing the configuration, with Class names resolved 
    -  80 * against the provided `context`.
    -  81 */

    -  82function recurse(config:any, context:any[]) {
    -  83    if (['string', 'number', 'boolean', 'function'].indexOf(typeof config)>=0) { return config; }
    -  84    const keys = Object.keys(config);
    -  85    let result = config.length? [] : {};
    -  86    keys.map((k:string):Vnode => {
    -  87        const content = recurse(config[k], context); 
    -  88        const cl:any = resolve(k, context);
    -  89        if (cl) { 
    -  90            const r = {
    -  91                compClass:cl,   // Component class
    -  92                attrs:content   // attributes passed to the Component class
    -  93            };
    -  94            (!Array.isArray(config) && keys.length === 1)? 
    -  95                result = r : 
    -  96                result[k] = r;   
    -  97        }
    -  98        else { result[k] = content; }
    -  99    }); 
    - 100    return result; 
    - 101}
    - 102
    - 103
    - 104/**
    - 105 * Interprets a configuration and either mounts it or routs it in `mithril`. 
    - 106 * Example: 
    - 107
    - 108import * as mylib from './mylib';
    - 109
    - 110const myConfig = { 
    - 111    Layout: {
    - 112        rows:  ['50px', 'fill'],
    - 113        css: '.hs-site',
    - 114        content: [{MyClass: {}}, 'bottom row']
    - 115    },
    - 116    route: {
    - 117        default: '/api',
    - 118        paths: [
    - 119            '/api',             // defines `http://localhost/#!/api/
    - 120            '/api/:lib',        // defines `http://localhost/#!/api/foo
    - 121            '/api/:lib/:field'  // defines `http://localhost/#!/api/foo/bar        
    - 122        ]
    - 123    }
    - 124}
    - 125
    - 126const myExample = {
    - 127    MyClass: class extends Layout {
    - 128        view(node:Vnode) { return m('', 'myExample'); }
    - 129    }
    - 130}
    - 131
    - 132new HsConfig([mylib, myExample]).attachNodeTree(myConfig, document.body)
    - 133

    - 134 */

    - 135export class HsConfig {
    - 136    /**
    - 137     * Constructs an HsConfig object on a `context`. Any class names encountered
    - 138     * in the configuration tree when calling `attachNodeTree` will be resolved
    - 139     * against this context. The `mithril`and `hsLayout` namespaces are automatically 
    - 140     * added to the context.
    - 141     * @param context Array of namespaces againt which classes will be resolved.  
    - 142     */

    - 143    constructor(protected context:any[]) {}
    - 144
    - 145    /**
    - 146     * Interprets a configuration object and attaches it to a DOM element
    - 147     * @param config an object literal, or name of a JSON file, containing a configration tree
    - 148     * @param root a DOM element to which to attach the tree
    - 149     */

    - 150    attachNodeTree(config:any, root:any) {
    - 151        /**
    - 152         * decodes the parts of a `route` declaration in the `config` tree
    - 153         * that will be passed to the `mithril` `m.route()` command.
    - 154         * 
    - 155         * `route` defines a `default` path, as well as an array `paths` of 
    - 156         * path templates containing variables of the form `:varName`.
    - 157         * 
    - 158         * All `paths`resolve to the same root element defined in the config tree.
    - 159         * @param route an object literal structured as 
    - 160         * 

    - 161         * {
    - 162         *     default: '...'   // the default path
    - 163         *     paths: [
    - 164         *         '/:var1[/:var2...]'  // path template, 
    - 165         *         ...
    - 166         *     ]
    - 167         * }
    - 168         * 

    - 169         */

    - 170        function decodeRoute(route:any) {
    - 171            const rp:string[] = route.params = [];
    - 172            route.paths.map((p0:string) => {
    - 173                const params = p0.match(/:(.+?)\b/g);
    - 174                if (params) { 
    - 175                    params.map((p1:string) => p1.substr(1))
    - 176                            .map((p2:any) => rp.indexOf(p2)<0? rp.push(p2):''); 
    - 177                }
    - 178            });
    - 179            return route;
    - 180        }
    - 181        /**
    - 182         * Handles top-level interpretations of a config tree and returns 
    - 183         * a normalized object with the following rules:
    - 184         * - a `route` entry, if present, will have a resolved class constructors for each string class designator
    - 185         * - a `root` entry is the first encountered top-level Vnode in `config`
    - 186         * - all other top-level entries in `config` wikll be copied to returned object
    - 187         */

    - 188        function decode(config:any) {
    - 189            let result:any = { };
    - 190            if (config.compClass && !result.root) {   // only capture the first one
    - 191                result.root = config; 
    - 192            } else {
    - 193                Object.keys(config).map((k:any) => {
    - 194                    if (config[k].compClass && !result.root) {   // only capture the first one
    - 195                        result.root = config[k]; 
    - 196                    } else if (k==='route') { 
    - 197                        result.route = decodeRoute(config.route);
    - 198                    } else {
    - 199                        result[k] = config[k];
    - 200                    }
    - 201                });
    - 202            }
    - 203            return result;
    - 204        }
    - 205
    - 206        function prepareRoutes(content:any) {
    - 207            const cr = content.root;
    - 208            class Router {
    - 209                view(node:Vnode) { 
    - 210                    cr.attrs.route = {};
    - 211                    content.route.params.map((k:any) =>
    - 212                        cr.attrs.route[k] = node.attrs[k]
    - 213                    );
    - 214                    return m(cr.compClass, copy(cr.attrs));  
    - 215                }
    - 216            }
    - 217            content.route.routes = {};
    - 218            content.route.paths.map((path:string) => content.route.routes[path] = Router);
    - 219        }
    - 220
    - 221        function mountOrRoute(c:any) {
    - 222            const content = decode(c);
    - 223            const cr = content.root;
    - 224            if (!cr) { 
    - 225                console.log('*** no top level component defined in config:'); 
    - 226                console.log(config); 
    - 227            }
    - 228            if (content.route) {
    - 229                prepareRoutes(content);
    - 230                m.route(root, content.route.default, content.route.routes);
    - 231                console.log('starting router');
    - 232            } else {
    - 233                m.mount(root, {view: (node:Vnode)=> m(cr.compClass, copy(cr.attrs))});
    - 234                console.log('mounting component');
    - 235            }
    - 236        }
    - 237
    - 238        const context = this.context;
    - 239        this.getContent(config)           
    - 240            .then((r:any) => recurse(r, context))
    - 241            .then(mountOrRoute);
    - 242    }
    - 243
    - 244    private getContent(config:any) {
    - 245        return (typeof config === 'string')? this.load(config) : Promise.resolve(config);
    - 246    }
    - 247
    - 248    private load(file:string) {
    - 249        console.log('requesting ' + file);
    - 250        return m.request({ method: "GET", url: file })
    - 251            .catch((e:any) => {
    - 252                console.log('error:');
    - 253                console.log(e);
    - 254            });
    - 255    }
    - 256}
    - 257
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/index.html b/docs/src/hsLayout/index.html deleted file mode 100644 index 679f717..0000000 --- a/docs/src/hsLayout/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - -

    index.ts

    -
       1/**
    -   2 * @description hsLayout: Library for generating formatted screen layouts.
    -   3 */

    -   4
    -   5import * as pillars     from './view/PillaredLayouter';      if(pillars) {}
    -   6import * as tiles       from './view/TileLayouter';          if(tiles) {}
    -   7/** */
    -   8export { Layout }    from './view/Layout'; 
    -   9export { FILL, px, pc, 
    -  10         LayoutToken }  from './view/Tokens'; 
    -  11export { Layouter }     from './view/Layouter';
    -  12export { HsConfig }     from './hsConfig';
    -  13export { m, Vnode, o }  from './mithril'
    -  14
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/mithril.html b/docs/src/hsLayout/mithril.html deleted file mode 100644 index 7d1568a..0000000 --- a/docs/src/hsLayout/mithril.html +++ /dev/null @@ -1,43 +0,0 @@ - - -

    mithril.ts

    -
       1/**
    -   2 * translates mithril libraries to an ES6 module and provides some Typescript type shortcuts.
    -   3 */

    -   4
    -   5if (!global['window']) {
    -   6    console.log('creating non-browser polyfill');
    -   7    // Polyfill DOM env for mithril
    -   8    global['window'] = require("mithril/test-utils/browserMock.js")();
    -   9    global['document'] = window.document;
    -  10
    -  11}
    -  12
    -  13/**
    -  14 * import and re-export the mithril m objkect
    -  15 */

    -  16export const m = require("mithril");
    -  17
    -  18/**
    -  19 * provide and export a Typescript Vnode type
    -  20 */

    -  21export type Vnode = typeof m.Vnode;
    -  22
    -  23const o = require("mithril/ospec/ospec");
    -  24o.root = window.document.createElement("div");
    -  25
    -  26export { o };
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/overview.html b/docs/src/hsLayout/overview.html deleted file mode 100644 index c47a762..0000000 --- a/docs/src/hsLayout/overview.html +++ /dev/null @@ -1,95 +0,0 @@ - - -

    overview.ts

    -
       1/**
    -   2 * # hsLayout 
    -   3 * hsLayout provides means to layout the browser window in various ways.
    -   4 * See [Layout Examples](example/layout.html)
    -   5 * 
    -   6 * ## Concepts
    -   7 * 
    -   8 * ### Layouts
    -   9 * Layouts can be either defined generically:
    -  10 * ```
    -  11 * m(Layout, {
    -  12 *     css: '.myLayoutClass',  // optional
    -  13 *     columns: []
    -  14 *     content: ['left', 'right']
    -  15 * })
    -  16 * ```
    -  17 * Or, for more complex cases, by defining a class that extends {@link Layout.Layout `Layout`}:
    -  18 * ```
    -  19 * class Columns extends Layout {
    -  20 *     getComponents(node:Vnode) {
    -  21 *         return [m(LeftColumn), m(CenterColumn), m(RightColumn)]
    -  22 *     }
    -  23 * }
    -  24 * m(Columns);
    -  25 * ```
    -  26 * 
    -  27 * ### Layouters
    -  28 * To create new layout styles, define a class that extends the abstract {@link Layouter.Layouter `Layouter`} class.
    -  29 * This class should implement the `getStyles` method which calculates the styles attributes required for each `Component`
    -  30 * to be layed out in a `Layout`.
    -  31 * 
    -  32 * Currently defined Layouters:
    -  33 * -   {@link PillaredLayouter.Columns `Columns`}
    -  34 * -   {@link PillaredLayouter.Rows    `Rows`}
    -  35 * -   {@link TileLayouter.Tiles       `Tiles`}
    -  36 * 
    -  37 * ### Example
    -  38 * 
    -  39 * 
    -  40 * const theContent = ['Top row: 50px', 'Bottom row: remainder']
    -  41 * m.mount(root, {view: () => m(hslayout.Layout, {
    -  42 *     css: 'myColumn',
    -  43 *     rows: ["50px", "fill"], 
    -  44 *     content:theContent
    -  45 *     })
    -  46 * });
    -  47 * 
    -  48 * 
    -  49 * .myColumn .hs-layout {
    -  50 *     border: 1px solid white;
    -  51 * }
    -  52 * 
    -  53 * 

    -  54 * 
    -  55 * ### Nested Example
    -  56 * 
    -  57 * 
    -  58 * m.mount(root, {view: () => 
    -  59 *     m(hslayout.Layout, {
    -  60 *         css: 'myColumn',
    -  61 *         rows: ["150px", "fill"], 
    -  62 *         content:[
    -  63 *             m(hslayout.Layout, {columns:['20%'], content:['top left', 'top 2nd']}), 
    -  64 *             m(hslayout.Layout, {columns:['20%'], content:['bottom left', 'bottom 2nd']})
    -  65 *         ]
    -  66 *     })
    -  67 * });
    -  68 * 
    -  69 * 
    -  70 * .myColumn .hs-layout {
    -  71 *     border: 1px solid white;
    -  72 * }
    -  73 * 
    -  74 * 

    -  75 */

    -  76
    -  77/** */
    -  78
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/Container.html b/docs/src/hsLayout/view/Container.html deleted file mode 100644 index 8135269..0000000 --- a/docs/src/hsLayout/view/Container.html +++ /dev/null @@ -1,159 +0,0 @@ - - -

    view/Container.ts

    -
       1/**
    -   2 Definitions of the abstract base classes `Component` and `Container`.
    -   3 */

    -   4
    -   5/** */
    -   6import { m, Vnode}      from '../mithril';
    -   7
    -   8import { Layout }       from './Layout'; 
    -   9
    -  10/**
    -  11 * abstract base class of a viewable component. Subclasses can be passed into `mithril` 
    -  12 * to create render trees.
    -  13 * ### Example
    -  14 * `m('', [m(Component, {parameters})])`
    -  15 */

    -  16export abstract class Component {
    -  17    /** 
    -  18     * the standard `Mithril` component view function 
    -  19     * @param vnode the vnode passed by `Mithril`
    -  20     * @return A vnode that represents the view of this `Component` 
    -  21     */

    -  22    public abstract view(vnode?: Vnode): Vnode;
    -  23}
    -  24
    -  25/**
    -  26Abstract base class for applying layouts. Subclasses should implement a {@link Container.Container.getComponents `getComponents`} method that returns
    -  27the components to render. The default implementation returns the conponents passed in `node.attrs.content`.
    -  28Optionally, the subclass can also implement {@link Container.Container.getCSS `getCSS`} to provide the CSS class to 
    -  29assign to the component, and override the default implementation, which returns `node.attrs.css`. 
    -  30### Example:
    -  31
    -  32import { Container, px, FILL }  from 'hslayout';
    -  33const TitleHeight   = px(30); 
    -  34const FooterHeight  = px(10); 
    -  35class MyLayout extends Container {
    -  36    getComponents(node:Vnode):Vnode {
    -  37        return this.layout('.my-layout', { rows:[TitleHeight, FILL, FooterHeight] }, [
    -  38            m(), 
    -  39            m(),
    -  40            m()
    -  41        ]);
    -  42    }
    -  43    getCSS(node:Vnode):string {
    -  44    }
    -  45
    -  46

    -  47 */

    -  48export abstract class Container extends Component {
    -  49    /**
    -  50     * holds structural elements in style form: left, right, top, bottom, width, height
    -  51     */

    -  52    public style:string;
    -  53
    -  54//    oninit(node:Vnode)   { this.report('Container:init', node); }
    -  55//    oncreate(node:Vnode) { this.report('Container:create', node); } 
    -  56//    onupdate(node:Vnode) { this.report('Container:update', node); }
    -  57
    -  58    /**
    -  59     * Called during the lifecycle `view` call to retrieve the subcomponents to render in this container.
    -  60     * The default implementation returns components stored in `node.attrs.content`. This allows for 
    -  61     * creating containers directly via mithril: `m(Container, {content:[...]})`. 
    -  62     * In case `node.attrs.content` is an array of literals with a `compClass` field describing a Component class, 
    -  63     * the method will create a Mithril node on that class and pass the `node.attrs.route` argument down to it.
    -  64     * Override this method to create containers that return more sophisticated content.
    -  65     * @return a Vnode or an array or Vnodes
    -  66     */

    -  67    protected getComponents(node:Vnode):Vnode {
    -  68        return !Array.isArray(node.attrs.content)? node.attrs.content :
    -  69            node.attrs.content.map((c:any) => {
    -  70                if (c.compClass) { 
    -  71                    c.attrs.route = node.attrs.route;
    -  72                    return m(c.compClass, c.attrs);
    -  73                } else {
    -  74                    return c;
    -  75                }
    -  76            });
    -  77    }
    -  78
    -  79    /**
    -  80     * Called during the lifecycle `view` call to retrieve the css style class to apply to this container.
    -  81     * The default implementation returns components stored in `node.attrs.css`. This allows for 
    -  82     * creating containers directly via mithril: `m(Container, {content:[...], css:'.my-class'})`.
    -  83     * Override this method to create containers that return more sophisticated content.
    -  84     */

    -  85    protected getCSS(node:Vnode):string {
    -  86        return node.attrs.css || '';
    -  87    }
    -  88
    -  89
    -  90    private normalizeContent(components:Array|string): Vnode {
    -  91        if (typeof components === 'string') { 
    -  92            return [m('.hs-leaf', m.trust(components))]; 
    -  93        }
    -  94        if (components.length>0) { // an array:
    -  95            if (components.some((c:any) => (typeof c !== 'object'))) {
    -  96                return components.map((comp:string|typeof Container):Vnode => 
    -  97                    (comp instanceof Container)? comp : m(Container, {content:comp})
    -  98                );
    -  99            } else {
    - 100                return components;
    - 101            }
    - 102        }
    - 103        return [components];
    - 104    }
    - 105
    - 106    /**
    - 107    lays out the component in `components` according to the configuration in `attrs`.
    - 108    The method returns a vnode container that has an associated `cssClass` style.
    - 109    `layout` is called during the `render` phase of the `mithril` lifecycle, 
    - 110    which ensures an outside-in calling sequence on containers; 
    - 111    i.e. the outermost containers are called first, and `node` will already have the 
    - 112    `style` field set with required style attributes. 
    - 113    These are added to any `attrs` parameter provided.
    - 114
    - 115    The format for the layout configuration in `attrs` is 
    - 116    {}
    - 117    

    - 118     where `keyword` is the keyword with which the `Layout` was registered.
    - 119     * @param cssClass a css style designator; same as used in m(cssClass, ...) 
    - 120     * @param layout the attribute object literal that configures the layout
    - 121     * @param components the components to layout within the container. 
    - 122     * This is either a primitive `string`, or an array of `Container`s or `string`s.
    - 123     * @return a vnode that has an associated `cssClass` style.
    - 124     */

    - 125    view(node:Vnode): Vnode {
    - 126        const content = this.normalizeContent(this.getComponents(node)); // --> Vnode[]
    - 127        let css = Layout.createLayout(node.attrs, content);
    - 128        const attrs:any = {
    - 129            style: node.style,
    - 130            route: node.attrs.route,     
    - 131            onclick: node.attrs.onclick
    - 132        };
    - 133        node.attrs.route = undefined;
    - 134        if (node.attrs.href) { 
    - 135            attrs.href = node.attrs.href;
    - 136            attrs.oncreate = m.route.link;
    - 137            attrs.onupdate = m.route.link;
    - 138        }
    - 139        return m(`.hs-layout ${css} ${this.getCSS(node)}`, attrs, content.map((c:any) => c));
    - 140    }
    - 141}
    - 142
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/Layout.html b/docs/src/hsLayout/view/Layout.html deleted file mode 100644 index 9aede41..0000000 --- a/docs/src/hsLayout/view/Layout.html +++ /dev/null @@ -1,153 +0,0 @@ - - -

    view/Layout.ts

    -
       1/**
    -   2 * # Layout
    -   3 * A `mithril` component class that layouts available space in the window.
    -   4 * 
    -   5 * ### Invocation
    -   6 * invoked as `m(Layout, {name:, content:Array})`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - :Array, required.  matches a registered {@link Layouter Layouter}
    -  10 * - content: Array, required. The Vnode children to lay out. 
    -  11 * - css:String, optional. The css specifier to use for this `Layout` component.
    -  12 * - route: object literal holding parameters passed from `m.route`
    -  13 * - href: String, optional. If present, makes the component clickable
    -  14 * - onclick:(), optional. The function to call when clicked
    -  15 */

    -  16
    -  17/** */
    -  18import { m, Vnode}      from '../mithril';
    -  19import { Layouter }       from './Layouter'; 
    -  20
    -  21/**
    -  22Base class for applying layouts. Subclasses should implement a {@link Layout.Layout.getComponents `getComponents`} method that returns
    -  23the components to render. The default implementation returns the conponents passed in `node.attrs.content`.
    -  24Optionally, the subclass can also implement {@link Layout.Layout.getCSS `getCSS`} to provide the CSS class to 
    -  25assign to the component, and override the default implementation, which returns `node.attrs.css`. 
    -  26### Example:
    -  27
    -  28import { Layout, px, FILL }  from 'hslayout';
    -  29const TitleHeight   = px(30); 
    -  30const FooterHeight  = px(10); 
    -  31class MyLayout extends Layout {
    -  32    getComponents(node:Vnode):Vnode {
    -  33        return this.layout('.my-layout', { rows:[TitleHeight, FILL, FooterHeight] }, [
    -  34            m(), 
    -  35            m(),
    -  36            m()
    -  37        ]);
    -  38    }
    -  39    getCSS(node:Vnode):string {
    -  40    }
    -  41
    -  42

    -  43 */

    -  44export class Layout {
    -  45    /**
    -  46     * holds structural elements in style form: left, right, top, bottom, width, height
    -  47     */

    -  48    public style:string;
    -  49
    -  50//    oninit(node:Vnode)   { this.report('Layout:init', node); }
    -  51//    oncreate(node:Vnode) { this.report('Layout:create', node); } 
    -  52//    onupdate(node:Vnode) { this.report('Layout:update', node); }
    -  53
    -  54    /**
    -  55     * Called during the lifecycle `view` call to retrieve the subcomponents to render in this container.
    -  56     * The default implementation returns components stored in `node.attrs.content`. This allows for 
    -  57     * creating containers directly via mithril: `m(Layout, {content:[...]})`. 
    -  58     * In case `node.attrs.content` is an array of literals with a `compClass` field describing a Component class, 
    -  59     * the method will create a Mithril node on that class and pass the `node.attrs.route` argument down to it.
    -  60     * 
    -  61     * Override this method to create containers that return more sophisticated content.
    -  62     * @return a String, a Vnode, or an array of Strings or Vnodes
    -  63     */

    -  64    protected getComponents(node:Vnode):Vnode {
    -  65        return !Array.isArray(node.attrs.content)? node.attrs.content :
    -  66            node.attrs.content.map((c:any) => {
    -  67                if (c.compClass) { 
    -  68                    c.attrs.route = node.attrs.route;
    -  69                    return m(c.compClass, c.attrs);
    -  70                } else {
    -  71                    return c;
    -  72                }
    -  73            });
    -  74    }
    -  75
    -  76    /**
    -  77     * Called during the lifecycle `view` call to retrieve the css style class to apply to this container.
    -  78     * The default implementation returns components stored in `node.attrs.css`. This allows for 
    -  79     * creating containers directly via mithril: `m(Layout, {content:[...], css:'.my-class'})`.
    -  80     * Override this method to create containers that return more sophisticated content.
    -  81     */

    -  82    protected getCSS(node:Vnode):string {
    -  83        return node.attrs.css || '';
    -  84    }
    -  85
    -  86
    -  87    private normalizeContent(components:Array|string): Vnode {
    -  88        if (typeof components === 'string') { 
    -  89            return [m('.hs-leaf', m.trust(components))]; 
    -  90        }
    -  91        if (components.length>0) { // an array: ensure elements are Layout components
    -  92            return components.map((comp:string|typeof Layout):Vnode => 
    -  93                    (comp instanceof Layout)? comp : m(Layout, {content:comp})
    -  94            );
    -  95        }
    -  96        // else: assume components is a mithril node: return node as an array
    -  97        return [components];
    -  98    }
    -  99
    - 100    /**
    - 101    lays out the component in `components` according to the configuration in `attrs`.
    - 102    The method returns a vnode container that has an associated `cssClass` style.
    - 103    `layout` is called during the `render` phase of the `mithril` lifecycle, 
    - 104    which ensures an outside-in calling sequence on containers; 
    - 105    i.e. the outermost containers are called first, and `node` will already have the 
    - 106    `style` field set with required style attributes. 
    - 107    These are added to any `attrs` parameter provided.
    - 108
    - 109    The format for the layout configuration in `attrs` is 
    - 110    {}
    - 111    

    - 112     where `keyword` is the keyword with which the `Layouter` was registered.
    - 113     * @param cssClass a css style designator; same as used in m(cssClass, ...) 
    - 114     * @param layout the attribute object literal that configures the layout
    - 115     * @param components the components to layout within the container. 
    - 116     * This is either a primitive `string`, or an array of `Layout`s or `string`s.
    - 117     * @return a vnode that has an associated `cssClass` style.
    - 118     */

    - 119    view(node:Vnode): Vnode {
    - 120        const content = this.normalizeContent(this.getComponents(node)); // --> Vnode[]
    - 121        let css = Layouter.createLayout(node.attrs, content);
    - 122        const attrs:any = {
    - 123            style: node.style,
    - 124            route: node.attrs.route,     
    - 125            onclick: node.attrs.onclick
    - 126        };
    - 127        node.attrs.route = undefined;
    - 128        if (node.attrs.href) { 
    - 129            attrs.href = node.attrs.href;
    - 130            attrs.oncreate = m.route.link;
    - 131            attrs.onupdate = m.route.link;
    - 132        }
    - 133        return m(`.hs-layout ${css} ${this.getCSS(node)}`, attrs, content.map((c:any) => c));
    - 134    }
    - 135}
    - 136
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/Layouter.html b/docs/src/hsLayout/view/Layouter.html deleted file mode 100644 index e95a05b..0000000 --- a/docs/src/hsLayout/view/Layouter.html +++ /dev/null @@ -1,148 +0,0 @@ - - -

    view/Layouter.ts

    -
       1/**
    -   2Layouter.ts provides basic mechanisms for laying out a view container. 
    -   3Subclasses of `Layouter` should
    -   4- implement the {@link Layouter.Layouter.getStyles getStyles} method.
    -   5- register the subclass and configuration keyword with the static 
    -   6   {@link Layouter.Layouter.register register} method.
    -   7*/

    -   8
    -   9/** */
    -  10import { Vnode} from '../mithril';
    -  11
    -  12import { LayoutToken }  from './Tokens';
    -  13import { Layout }    from './Layout';
    -  14import { px, pc, FILL } from './Tokens';
    -  15
    -  16/**
    -  17Abstract base class for creating layout style implementations.
    -  18Subclasses should implement `getStyles`. In addition, subclasses need to be registered with the 
    -  19static `Layouter.register` method.
    -  20### Example
    -  21
    -  22class MyLayouter extends Layouter {
    -  23    cssClass = '.my-css-class';
    -  24    constructor(public areaDesc:LayoutToken[]) { 
    -  25        super(areaDesc); 
    -  26    }
    -  27    
    -  28    protected getStyles(components:Array):string {
    -  29        components.map((c:Layout|Vnode, i:number) => {
    -  30            c.style = `width:auto; height:auto;
    -  31        });   
    -  32        return this.cssClass;
    -  33   }
    -  34}
    -  35
    -  36Layouter.register('MyLayouter', MyLayouter);
    -  37

    -  38 */

    -  39export abstract class Layouter {
    -  40    /**
    -  41     * statis list of available styles. The key for each entry is the keyword that triggers the style,
    -  42     * and the value is a constructor for that style
    -  43     */

    -  44    static layoutStyles:{string?: Layouter} = {};
    -  45
    -  46        /**
    -  47     * Translates `string` params to {@link hsLayout:Tokens.LayoutToken LayoutTokens}.
    -  48     * The `params` are expected to either
    -  49     * - end in 'px'
    -  50     * - end in '%'
    -  51     * - be equal to 'fill' (case insensitive)
    -  52     * @param params an Array of strings that will be converted to an array of LayourTokens.
    -  53     * 
    -  54     */

    -  55    private static translate(params:Array):Array {
    -  56        if (params.length === 0) { params.push(''); }   //  [] --> ['']
    -  57        return params.map((param:string|any) => {
    -  58            if (typeof param === 'string') {
    -  59                if (param.endsWith('px')) { return px(parseInt(param)); }
    -  60                if (param.endsWith('%')) { return pc(parseInt(param)); }
    -  61                if (param.toLowerCase()==='fill') { return FILL;}
    -  62            } else {
    -  63                return param;
    -  64            }
    -  65        });
    -  66    }
    -  67
    -  68    /**
    -  69     * Register a new Layouter style with corresponding configuration keyword.
    -  70     * Example:```
    -  71     * class ColumnsLayout extends Layouter {...}
    -  72     * Layouter.register('Column', Columns);
    -  73     * ```
    -  74     * @param keyword the keyword used in the attributes to `this.layout`
    -  75     * @param style the `Layouter` implementation to instantiate when encountering `keyword` 
    -  76     */

    -  77    public static register(keyword:string, style:typeof Layouter) {
    -  78//        console.log(`registering ${keyword} layout`);
    -  79        Layouter.layoutStyles[keyword] = style;
    -  80    }
    -  81
    -  82    /**
    -  83     * Lays out the `components` according to the configuration in `attrs`.
    -  84     * The method will search for a registered layout key in `attrs`, then construct the `Layouter` associated with the key
    -  85     * with the parameters for the key, and call the `getStyles` method on the style with the provided `components`.
    -  86     * @param attrs an object literal, typically provided as middle attributes object in the m(css, {}, '') call.
    -  87     * @param components 
    -  88     * @return returns the css class that the `getStyles` function returns.
    -  89     */

    -  90    public static createLayout(attrs:any, components:Array):string {
    -  91        let css = '';
    -  92        Object.keys(Layouter.layoutStyles).some(key => { // executes the first match key in attrs.
    -  93            if (attrs[key]) { 
    -  94                css = new Layouter.layoutStyles[key](Layouter.translate(attrs[key])).getStyles(components); 
    -  95                attrs[key] = undefined;
    -  96                return true;
    -  97            }
    -  98            return false;
    -  99        });
    - 100        return css;
    - 101    }
    - 102
    - 103
    - 104    spacing = 0;   
    - 105    
    - 106    /**
    - 107     * Layouter Constructor, will be called by the static `createLayout` method when creating the layout on a {@link hsLayout:Layout.Layout `Layout`}.
    - 108     * The `areaDesc` parameter is expected to be of the form {: {@link hsLayout:Tokens.LayoutToken `LayoutToken`}[]}} 
    - 109     * and will be passed through form the `Layout` requesting the layout.
    - 110     * @param areaDesc 
    - 111     */

    - 112    constructor(public areaDesc:LayoutToken[]) {};
    - 113
    - 114    /**
    - 115     * Calculates the style attributes required for each component in `Components`.
    - 116     * These attributes are saved in a `style` field on the component itself. 
    - 117     * During rendering these `style` attributes are copied to the `node.attrs.styles` field.
    - 118     * ### Example
    - 119    protected getStyles(components:Array):string {
    - 120        components.map((c:Layout|Vnode, i:number) => {
    - 121            c.style = `width:auto; height:auto;
    - 122        });   
    - 123        return this.cssClass;
    - 124    }
    - 125    

    - 126     * @param components 
    - 127     */

    - 128    protected abstract getStyles(components:Array):string;
    - 129}
    - 130
    - 131
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/PillaredLayout.html b/docs/src/hsLayout/view/PillaredLayout.html deleted file mode 100644 index a328a4f..0000000 --- a/docs/src/hsLayout/view/PillaredLayout.html +++ /dev/null @@ -1,359 +0,0 @@ - - -

    view/PillaredLayout.ts

    -
       1/**
    -   2Lays out components in pillars, i.e. either {@link hsLayout:PillaredLayout.Columns columns}
    -   3or {@link hsLayout:PillaredLayout.Rows rows}
    -   4Use either of
    -   5- `{rows: [attributes]}`
    -   6- `{columns: [attributes]}` 
    -   7
    -   8to invoke this layout.
    -   9
    -  10### Example
    -  11
    -  12    {rows: [px(200), FILL]}   // --> top row has height 200px, all other rows evenly share remaining space 
    -  13    {rows: ["200px", "fill"]} // --> equivalent description
    -  14

    -  15
    -  16## Attributes
    -  17The following values **v** are valid entries in The Attributes array:
    -  18- **px(n)** or **"px"** -- a fixed number of pixels 
    -  19- **pc(n)** or **"%"**  -- a fixed percentage of available space
    -  20- **FILL** or **"fill"**   -- a special constant to indicate - may appear only once per array.
    -  21
    -  22The following options are supported for the Attributes array:
    -  23- **[ ]**: An empty array; all components will be evenly spaced across the available width. 
    -  24- **[v]**: All components have the specified width (in px or %) and will fill the available space from the left,
    -  25    leaving any remaining unused space on the right. 
    -  26- **[v1, v2]**: All components have the specified widths (in px or %) and will fill the available space from the left,
    -  27    leaving any remaining unused space on the right. If there are more components than widths, the right-most width
    -  28    will be used for the reminaing widgets.
    -  29- **[v, FILL]**: Sets the first (left) widget to a width of `v`.

    -  30    if `v` is specified in %, the remaining n-1 components will have equal relative widths of `(100-v)/(n-1)%`

    -  31    if `v` is specified in px, the remaining n-1 components will have their right borders at location `i*100/n%`, with i=1...n.
    -  32- **[FILL, v]**: Sets the last (right) widget to a width of `v`.

    -  33    if `v` is specified in %, the remaining n-1 components will have equal relative widths of `(100-v)/(n-1)%`

    -  34    if `v` is specified in px, the remaining n-1 components will have their left borders at location `i*100/n%`, with i=0...n-1.
    -  35- **[va, FILL, vb]**: Sets the first and last widget to a width of `va`/`vb`.

    -  36    Both have to be specified either in px or in %.

    -  37    if the unit is %, the remaining n-2 components will have equal relative widths of `(100-vb-va)/(n-2)%`

    -  38    if the unit is px, the remaining n-2 components will have their left/right borders at location `i*100/n%`.
    -  39- **[v1, v2, FILL, v3, v4]**: multiple widths can be specified in uninterrupted sequence both from the left and the right. 
    -  40 */

    -  41
    -  42/** */
    -  43import { Container }    from './Container';
    -  44import { Layout }       from './Layout';
    -  45import { LayoutToken, DefinedToken, PixelToken }    from './Tokens';
    -  46import { Vnode}         from '../mithril';
    -  47
    -  48
    -  49
    -  50/**
    -  51 * interface definition for entries in `cParams`
    -  52 */

    -  53interface PillarParams {
    -  54    cssClass: string;
    -  55    fields: string[];
    -  56}
    -  57
    -  58/**
    -  59 * array of trigger keywords for column and row layout styles
    -  60 */

    -  61export const PillarLayouts = [
    -  62    'columns', 'rows'
    -  63];
    -  64
    -  65/**
    -  66 * contains style settings for the row and column layout
    -  67 */

    -  68const cParams = {
    -  69    columns: {
    -  70        cssClass: '.hs-column-layout',
    -  71        fields: ['top', 'bottom', 'left', 'right', 'height', 'width']
    -  72    },
    -  73    rows: {
    -  74        cssClass: '.hs-row-layout',
    -  75        fields: ['left', 'right', 'top', 'bottom', 'width', 'height']
    -  76    }
    -  77};
    -  78
    -  79type descriptor = {size:number, code:string, fields:{}};
    -  80
    -  81/**
    -  82 * Abstract base Layout for creating Pillars (rows, colums)
    -  83 */

    -  84abstract class Pillars extends Layout{
    -  85    firstFixed: number; // number of DefinedToken entries at the beginning
    -  86    lastFixed:  number; // number of DefinedToken entries at the end
    -  87    unit:(num:number)=>descriptor[];
    -  88    fields: string[];
    -  89    cssClass:string;
    -  90
    -  91    /**
    -  92     * Constructs a Pillared layout (rows or columns).
    -  93     * Determines the `unit` (% or px) from the passed area descriptors
    -  94     * @param params Style params for either rows or columns layout
    -  95     * @param areaDesc Description of the requested layout 
    -  96     */

    -  97    constructor(params:PillarParams, public areaDesc:LayoutToken[]) { 
    -  98        super(areaDesc); 
    -  99        this.fields = params.fields;
    - 100        this.cssClass = params.cssClass;
    - 101
    - 102        let n = areaDesc.length-1;
    - 103        let first = 0;
    - 104        let last  = 0;        
    - 105        // if any of the dimensions are in px, use the pixel method; else use the percent method
    - 106        this.unit = areaDesc.some((area:LayoutToken) => (area instanceof PixelToken))? this.unitPixel : this.unitPercent;   
    - 107        
    - 108        // determine first = number of consecutive fixed fields at start
    - 109        areaDesc.some((area:LayoutToken, i:number) => ((areaDesc[i]   instanceof DefinedToken)? ++first<0 : true));         
    - 110
    - 111        // determine last  = number of consecutive fixed fields at end
    - 112        areaDesc.some((area:LayoutToken, i:number) => ((areaDesc[n-i] instanceof DefinedToken)? ++last<0  : true));         
    - 113
    - 114        this.firstFixed = first;
    - 115        this.lastFixed  = Math.min(last, areaDesc.length-first);
    - 116    };
    - 117
    - 118    // num: number of areas to layout
    - 119    /**
    - 120     * Creates an iterable list of size descriptors, one for each area to be layed out.
    - 121     * Each descriptor 
    - 122     * @param num the number of areas to be layed out
    - 123     * @return Iterable list of `num` size descriptors, one for each area to be layed out
    - 124     */

    - 125    private getSizes(num:number):descriptor[] {
    - 126        const first = this.firstFixed;
    - 127        const last  = this.lastFixed;
    - 128        const desc  = this.areaDesc;
    - 129        const len = desc.length;
    - 130
    - 131        return [...Array(num).keys()].map((i:number) => {
    - 132            let size:number = null;
    - 133            let t = null;
    - 134            if (i > num-1-last)  { size = desc[len - (num-i)].getSize(); t = 'end'; }       // end sequence
    - 135            else if (i < first)  { size = desc[i].getSize(); t = 'start'; }                 // start sequence
    - 136            else if (len>0 && len===first){ size = desc[len-1].getSize(); t = 'start'; }    // all items 
    - 137            return {size:size, code:t, fields:{}};
    - 138        });
    - 139    }
    - 140
    - 141    private unitPercent(num:number):descriptor[] {
    - 142        let f = this.fields;
    - 143        let max = 100.0;
    - 144        let styles:descriptor[] = this.getSizes(num);
    - 145
    - 146        styles.forEach(style => { if (style.size) { max = max - style.size; num--; } });
    - 147        let defDim = max / num;      // divvy up remaining space
    - 148
    - 149        function pass(styles:descriptor[], ix0:string, ix1:string, breakCond:(cond:string)=>boolean) {
    - 150            let sumDim = 0;
    - 151            styles.some(style => { // stop when breakCond is met
    - 152                let size = style.size || defDim;
    - 153                if (breakCond(style.code)) { return true; }
    - 154                style.fields[ix0] = sumDim+'%';
    - 155                sumDim += size;
    - 156                style.fields[ix1] = (100-sumDim)+'%'; 
    - 157                style.fields[f[5]] = 'auto';
    - 158                return false;
    - 159            });
    - 160        }
    - 161
    - 162        pass(styles, f[2], f[3], (e:string) => e==='end');              // forward pass
    - 163        pass(styles.reverse(), f[3], f[2], (e:string) => e!=='end');    // backward pass
    - 164        return styles.reverse();    // reverse a second time for original sequence.
    - 165    };
    - 166
    - 167    private unitPixel(num:number):descriptor[] { // pattern: [px, px, FILL , px, px]
    - 168        let styles:descriptor[] = this.getSizes(num);
    - 169        let f = this.fields;
    - 170       
    - 171        let defDim = 100.0/num;          // used for unspecified widths
    - 172
    - 173        // work forwards through the heights
    - 174        let sumDim = 0;
    - 175        styles.some((style, i) => {
    - 176            if (style.code==='start') {   // so far, all heights explicitly set as px
    - 177                style.fields[f[2]] = sumDim +'px';
    - 178                sumDim += style.size + (this.spacing || 0) + (this.spacing || 0);
    - 179                style.fields[f[3]] = 'auto';
    - 180                style.fields[f[5]] = style.size +'px';
    - 181            } else if (style.code === null) {
    - 182                style.fields[f[2]] = (sumDim>0)? (sumDim +'px') : (i*defDim + '%');
    - 183                sumDim = -1;
    - 184                style.fields[f[3]] = (100-(i+1)*defDim) + '%';
    - 185                style.fields[f[5]] = 'auto';
    - 186            } else if (style.code==='end') { return true; }
    - 187            return false;
    - 188        });
    - 189        
    - 190        // work backwards through the heights
    - 191        sumDim = 0;
    - 192        styles.slice().reverse().some((style, i) => {
    - 193            style.fields[f[3]] = sumDim + 'px';
    - 194            if (style.code === 'end') { 
    - 195                sumDim += style.size + (this.spacing || 0) + (this.spacing || 0);
    - 196                style.fields[f[2]] = 'auto';
    - 197                style.fields[f[5]] = style.size+'px';
    - 198            } else {
    - 199                if (sumDim>0 && style.code !== 'start') {
    - 200                    style.fields[f[5]] = 'auto';
    - 201                }
    - 202                return true; 
    - 203            } 
    - 204            return false;
    - 205        });  
    - 206        return styles;
    - 207    };
    - 208    
    - 209    /**
    - 210     * Calculates the style attributes required for each component in `Components`.
    - 211     * These attributes are saved in a `styles` field on the component itself. 
    - 212     * During rendering these `styles` attributes are copied to the `node.attrs.styles` field.
    - 213     * @param components 
    - 214     */

    - 215    protected getStyles(components:Array):string  { 
    - 216        let f = this.fields;
    - 217        let styles:descriptor[] = this.unit(components.length);
    - 218        components.map((c:Container|Vnode, i:number) => {
    - 219            c.style = `${f[0]}:0%; ${f[1]}:0%; `;
    - 220            Object.keys(styles[i].fields).forEach((st:string) => { c.style += `${st}: ${styles[i].fields[st]};`; });
    - 221        });   
    - 222        return this.cssClass;
    - 223    };
    - 224};
    - 225
    - 226/**
    - 227 * Constructs a columns pillar layout style.

    - 228 * Use `{columns: [attributes]}` to invoke this layout. See top of page for a description.
    - 229 * 
    - 230 * 
    - 231 * const styles = [ 
    - 232 *     [],                // equal spacing
    - 233 *     ["100px"],         // fixed spacing
    - 234 *     ["60px", "100px"], // fixed spacing, first one smaller
    - 235 *     ["100px", "fill"], // first one fixed, rest equal
    - 236 *     ["fill", "100px"], // last one fixed, rest equal
    - 237 *     ["20%"],           // relative spacing, all equal
    - 238 *     ["20%", "fill"],   // first relative, rest equal
    - 239 *     ["fill", "20%"]    // last relative, rest equal
    - 240 * ];
    - 241 * let c = [];
    - 242 * function next() {
    - 243 *     if (c.length >= 5) { c = []; }
    - 244 *     else { c.push(''); }
    - 245 *     setTimeout(next, 2000);
    - 246 *     m.redraw();
    - 247 * }
    - 248 * 
    - 249 * m.mount(root, { 
    - 250 *     view:() => m(hslayout.Container, {
    - 251 *         rows:[],  // each row a style
    - 252 *         content: styles.map(i => m(hslayout.Container, {
    - 253 *             css: '.myExample', 
    - 254 *             content: c.map(c=>(''+i)),
    - 255 *             columns: i    // a style from styles
    - 256 *         }))
    - 257 *     })
    - 258 * });
    - 259 * next();
    - 260 * 
    - 261 * 
    - 262 * .hs-row-layout>.myExample { 
    - 263 *     border-top:    1px solid white;
    - 264 *     border-bottom: 1px solid white;
    - 265 * }
    - 266 * .myExample>.hs-layout {
    - 267 *     border-left:  1px solid white;
    - 268 *     border-right: 1px solid white;
    - 269 *     background-color: #ccc;
    - 270 * }
    - 271 * .myExample { 
    - 272 *     color:       #a44; 
    - 273 *     font-weight: bold; 
    - 274 *     text-align:  center;
    - 275 * }
    - 276 * 
    - 277 * 

    - 278 */

    - 279class Columns extends Pillars {
    - 280    constructor(public areaDesc:LayoutToken[]) { super(cParams[PillarLayouts[0]], areaDesc);  };
    - 281};
    - 282
    - 283/**
    - 284 * Constructs a row pillar layout style.

    - 285 * Use `{row: [attributes]}` to invoke this layout. See top of page for a description.
    - 286 * 
    - 287 * 
    - 288 * const styles = [ 
    - 289 *     [],                // equal spacing
    - 290 *     ["100px"],         // fixed spacing
    - 291 *     ["60px", "100px"], // fixed spacing, first one smaller
    - 292 *     ["100px", "fill"], // first one fixed, rest equal
    - 293 *     ["fill", "100px"], // last one fixed, rest equal
    - 294 *     ["20%"],           // relative spacing, all equal
    - 295 *     ["20%", "fill"],   // first relative, rest equal
    - 296 *     ["fill", "20%"]    // last relative, rest equal
    - 297 * ];
    - 298 * let c = [];
    - 299 * function next() {
    - 300 *     if (c.length >= 5) { c = []; }
    - 301 *     else { c.push(''); }
    - 302 *     setTimeout(next, 2000);
    - 303 *     m.redraw();
    - 304 * }
    - 305 * 
    - 306 * m.mount(root, { 
    - 307 *     view:() => m(hslayout.Container, {
    - 308 *         columns:[],  // each column a style
    - 309 *         content: styles.map(i => m(hslayout.Container, {
    - 310 *             css: '.myExample', 
    - 311 *             content: c.map(c=>(''+i)),
    - 312 *             rows: i   // a style from styles
    - 313 *         }))
    - 314 *     })
    - 315 * });
    - 316 * next();
    - 317 * 
    - 318 * 
    - 319 * .hs-column-layout>.myExample {
    - 320 *     border-left:    1px solid white;
    - 321 *     border-right: 1px solid white;
    - 322 * }
    - 323 * .myExample>.hs-layout {
    - 324 *     border-top:  1px solid white;
    - 325 *     border-bottom: 1px solid white;
    - 326 *     background-color: #ccc;
    - 327 * }
    - 328 * .myExample { 
    - 329 *     color:       #a44; 
    - 330 *     font-weight: bold; 
    - 331 *     text-align:  center;
    - 332 * }
    - 333 * 
    - 334 * 

    - 335 */

    - 336class Rows extends Pillars {
    - 337    constructor(public areaDesc:LayoutToken[]) { super(cParams[PillarLayouts[1]], areaDesc);  };
    - 338};
    - 339
    - 340Layout.register(PillarLayouts[0], Columns);
    - 341Layout.register(PillarLayouts[1],    Rows);
    - 342
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/PillaredLayout.spec.html b/docs/src/hsLayout/view/PillaredLayout.spec.html deleted file mode 100644 index 99ab705..0000000 --- a/docs/src/hsLayout/view/PillaredLayout.spec.html +++ /dev/null @@ -1,101 +0,0 @@ - - -

    view/PillaredLayout.spec.ts

    -
       1
    -   2const hslayout = require('../src/');
    -   3const m = hslayout.m;
    -   4const o = hslayout.o;
    -   5
    -   6
    -   7const columns = ["150px", "fill"];
    -   8const titles  = ['Left Column: 150px', 'Right Column: remainder'];
    -   9
    -  10
    -  11o.spec('rows', () => {
    -  12    let rows:any;
    -  13    o.before(() => {
    -  14        m.mount(o.root, {view: () => m(hslayout.Container, {
    -  15            css: 'myRow',
    -  16            rows: columns,
    -  17            content: titles
    -  18            })
    -  19        }); 
    -  20        rows = o.root.childNodes[0];
    -  21    }); 
    -  22    o('first level', () => {
    -  23        o(rows===undefined).equals(false)('should be defined');
    -  24        o(rows.className.includes('myRow')).equals(true)(`class myRow in '${rows.className}'`);
    -  25        o(rows.className.includes('hs-row-layout')).equals(true)(`class hs-row-layout in '${rows.className}'`);
    -  26        o(rows.childNodes.length).equals(2)(`has ${rows.childNodes.length} children`);
    -  27    });
    -  28
    -  29    o('second level', () => {
    -  30        rows.childNodes.forEach((c:any, i:number) => {
    -  31            o(c.className.includes('hs-layout')).equals(true)(`class hs-layout in '${c.className}'`);
    -  32            o(c.style.left).equals('0%')(`style left`);
    -  33            o(c.style.right).equals('0%')(`style right`);
    -  34            o(c.style.top).equals((i===0)?'0px':columns[0])(`style top`);
    -  35            o(c.style.bottom).equals((i===0)?'auto':'0px')(`style bottom`);
    -  36            o(c.style.height).equals((i===0)?columns[0]:'auto')(`style height`);
    -  37            o(c.childNodes.length).equals(1)(`has ${c.childNodes.length} children`);
    -  38        });
    -  39    });
    -  40    o('third level', () => {
    -  41        rows.childNodes.forEach((c:any, i:number) => {
    -  42            o(c.childNodes[0].className.includes('hs-leaf')).equals(true)(`class hs-leaf in '${c.childNodes[0].className}'`);
    -  43            o(c.childNodes[0].childNodes[0].nodeValue).equals(titles[i])(`item ${i+1} child leaf text`);
    -  44        });
    -  45    });
    -  46});
    -  47
    -  48o.spec('columns', () => {
    -  49    let rows:any;
    -  50    o.before(() => {
    -  51        m.mount(o.root, {view: () => m(hslayout.Container, {
    -  52            css: 'myColumn',
    -  53            columns: columns,
    -  54            content: titles
    -  55            })
    -  56        }); 
    -  57        rows = o.root.childNodes[0];
    -  58    }); 
    -  59    o('first level', () => {
    -  60        o(rows===undefined).equals(false)('should be defined');
    -  61        o(rows.className.includes('myColumn')).equals(true)(`class myColumn in '${rows.className}'`);
    -  62        o(rows.className.includes('hs-column-layout')).equals(true)(`class hs-column-layout in '${rows.className}'`);
    -  63        o(rows.childNodes.length).equals(2)(`has ${rows.childNodes.length} children`);
    -  64    });
    -  65
    -  66    o('second level', () => {
    -  67        rows.childNodes.forEach((c:any, i:number) => {
    -  68            o(c.className.includes('hs-layout')).equals(true)(`class hs-layout in '${c.className}'`);
    -  69            o(c.style.top).equals('0%')(`style top`);
    -  70            o(c.style.bottom).equals('0%')(`style bottom`);
    -  71            o(c.style.left).equals((i===0)?'0px':columns[0])(`style left`);
    -  72            o(c.style.right).equals((i===0)?'auto':'0px')(`style right`);
    -  73            o(c.style.width).equals((i===0)?columns[0]:'auto')(`style width`);
    -  74            o(c.childNodes.length).equals(1)(`has ${c.childNodes.length} children`);
    -  75        });
    -  76    });
    -  77    o('third level', () => {
    -  78        rows.childNodes.forEach((c:any, i:number) => {
    -  79            o(c.childNodes[0].className.includes('hs-leaf')).equals(true)(`class hs-leaf in '${c.childNodes[0].className}'`);
    -  80            o(c.childNodes[0].childNodes[0].nodeValue).equals(titles[i])(`item ${i+1} child leaf text`);
    -  81        });
    -  82    });
    -  83});
    -  84
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/PillaredLayouter.html b/docs/src/hsLayout/view/PillaredLayouter.html deleted file mode 100644 index 23ca97a..0000000 --- a/docs/src/hsLayout/view/PillaredLayouter.html +++ /dev/null @@ -1,360 +0,0 @@ - - -

    view/PillaredLayouter.ts

    -
       1/**
    -   2Lays out components in pillars, i.e. either {@link hsLayout:PillaredLayout.Columns columns}
    -   3or {@link hsLayout:PillaredLayout.Rows rows}
    -   4Use either of
    -   5- `{rows: [attributes]}`
    -   6- `{columns: [attributes]}` 
    -   7
    -   8to invoke this layout.
    -   9
    -  10### Example
    -  11
    -  12    {rows: [px(200), FILL]}   // --> top row has height 200px, all other rows evenly share remaining space 
    -  13    {rows: ["200px", "fill"]} // --> equivalent description
    -  14

    -  15
    -  16## Attributes
    -  17The following values **v** are valid entries in The Attributes array:
    -  18- **px(n)** or **"px"** -- a fixed number of pixels 
    -  19- **pc(n)** or **"%"**  -- a fixed percentage of available space
    -  20- **FILL** or **"fill"**   -- a special constant to indicate - may appear only once per array.
    -  21
    -  22The following options are supported for the Attributes array:
    -  23- **[ ]**: An empty array; all components will be evenly spaced across the available width. 
    -  24- **[v]**: All components have the specified width (in px or %) and will fill the available space from the left,
    -  25    leaving any remaining unused space on the right. 
    -  26- **[v1, v2]**: All components have the specified widths (in px or %) and will fill the available space from the left,
    -  27    leaving any remaining unused space on the right. If there are more components than widths, the right-most width
    -  28    will be used for the reminaing widgets.
    -  29- **[v, FILL]**: Sets the first (left) widget to a width of `v`.

    -  30    if `v` is specified in %, the remaining n-1 components will have equal relative widths of `(100-v)/(n-1)%`

    -  31    if `v` is specified in px, the remaining n-1 components will have their right borders at location `i*100/n%`, with i=1...n.
    -  32- **[FILL, v]**: Sets the last (right) widget to a width of `v`.

    -  33    if `v` is specified in %, the remaining n-1 components will have equal relative widths of `(100-v)/(n-1)%`

    -  34    if `v` is specified in px, the remaining n-1 components will have their left borders at location `i*100/n%`, with i=0...n-1.
    -  35- **[va, FILL, vb]**: Sets the first and last widget to a width of `va`/`vb`.

    -  36    Both have to be specified either in px or in %.

    -  37    if the unit is %, the remaining n-2 components will have equal relative widths of `(100-vb-va)/(n-2)%`

    -  38    if the unit is px, the remaining n-2 components will have their left/right borders at location `i*100/n%`.
    -  39- **[v1, v2, FILL, v3, v4]**: multiple widths can be specified in uninterrupted sequence both from the left and the right. 
    -  40 */

    -  41
    -  42/** */
    -  43import { Layout }    from './Layout';
    -  44import { Layouter }       from './Layouter';
    -  45import { LayoutToken, DefinedToken, PixelToken }    from './Tokens';
    -  46import { Vnode}         from '../mithril';
    -  47
    -  48
    -  49
    -  50/**
    -  51 * interface definition for entries in `cParams`
    -  52 */

    -  53interface PillarParams {
    -  54    cssClass: string;
    -  55    fields: string[];
    -  56}
    -  57
    -  58/**
    -  59 * array of trigger keywords for column and row layout styles
    -  60 */

    -  61export const PillarLayouts = [
    -  62    'columns', 'rows'
    -  63];
    -  64
    -  65/**
    -  66 * contains style settings for the row and column layout
    -  67 */

    -  68const cParams = {
    -  69    columns: {
    -  70        cssClass: '.hs-column-layout',
    -  71        fields: ['top', 'bottom', 'left', 'right', 'height', 'width']
    -  72    },
    -  73    rows: {
    -  74        cssClass: '.hs-row-layout',
    -  75        fields: ['left', 'right', 'top', 'bottom', 'width', 'height']
    -  76    }
    -  77};
    -  78
    -  79type descriptor = {size:number, code:string, fields:{}};
    -  80
    -  81/**
    -  82 * Abstract base Layouter for creating PillarLayouter (rows, colums)
    -  83 */

    -  84abstract class PillarLayouter extends Layouter{
    -  85    firstFixed: number; // number of DefinedToken entries at the beginning
    -  86    lastFixed:  number; // number of DefinedToken entries at the end
    -  87    unit:(num:number)=>descriptor[];
    -  88    fields: string[];
    -  89    cssClass:string;
    -  90
    -  91    /**
    -  92     * Constructs a Pillared layout (rows or columns).
    -  93     * Determines the `unit` (% or px) from the passed area descriptors
    -  94     * @param params Style params for either rows or columns layout
    -  95     * @param areaDesc Description of the requested layout 
    -  96     */

    -  97    constructor(params:PillarParams, public areaDesc:LayoutToken[]) { 
    -  98        super(areaDesc); 
    -  99        this.fields = params.fields;
    - 100        this.cssClass = params.cssClass;
    - 101
    - 102        let n = areaDesc.length-1;
    - 103        let first = 0;
    - 104        let last  = 0;        
    - 105        // if any of the dimensions are in px, use the pixel method; else use the percent method
    - 106        this.unit = areaDesc.some((area:LayoutToken) => (area instanceof PixelToken))? 
    - 107            this.unitPixel : this.unitPercent;   
    - 108        
    - 109        // determine first = number of consecutive fixed fields at start
    - 110        areaDesc.some((area:LayoutToken, i:number) => 
    - 111            ((areaDesc[i]   instanceof DefinedToken)? ++first<0 : true));         
    - 112
    - 113        // determine last  = number of consecutive fixed fields at end
    - 114        areaDesc.some((area:LayoutToken, i:number) => 
    - 115            ((areaDesc[n-i] instanceof DefinedToken)? ++last<0  : true));         
    - 116
    - 117        this.firstFixed = first;
    - 118        this.lastFixed  = Math.min(last, areaDesc.length-first);
    - 119    };
    - 120
    - 121    // num: number of areas to layout
    - 122    /**
    - 123     * Creates an iterable list of size descriptors, one for each area to be layed out.
    - 124     * Each descriptor 
    - 125     * @param num the number of areas to be layed out
    - 126     * @return Iterable list of `num` size descriptors, one for each area to be layed out
    - 127     */

    - 128    private getSizes(num:number):descriptor[] {
    - 129        const first = this.firstFixed;
    - 130        const last  = this.lastFixed;
    - 131        const desc  = this.areaDesc;
    - 132        const len = desc.length;
    - 133
    - 134        return [...Array(num).keys()].map((i:number) => {
    - 135            let size:number = null;
    - 136            let t = null;
    - 137            if (i > num-1-last)  { size = desc[len - (num-i)].getSize(); t = 'end'; }       // end sequence
    - 138            else if (i < first)  { size = desc[i].getSize(); t = 'start'; }                 // start sequence
    - 139            else if (len>0 && len===first){ size = desc[len-1].getSize(); t = 'start'; }    // all items 
    - 140            return {size:size, code:t, fields:{}};
    - 141        });
    - 142    }
    - 143
    - 144    private unitPercent(num:number):descriptor[] {
    - 145        let f = this.fields;
    - 146        let max = 100.0;
    - 147        let styles:descriptor[] = this.getSizes(num);
    - 148
    - 149        styles.forEach(style => { if (style.size) { max = max - style.size; num--; } });
    - 150        let defDim = max / num;      // divvy up remaining space
    - 151
    - 152        function pass(styles:descriptor[], ix0:string, ix1:string, breakCond:(cond:string)=>boolean) {
    - 153            let sumDim = 0;
    - 154            styles.some(style => { // stop when breakCond is met
    - 155                let size = style.size || defDim;
    - 156                if (breakCond(style.code)) { return true; }
    - 157                style.fields[ix0] = sumDim+'%';
    - 158                sumDim += size;
    - 159                style.fields[ix1] = (100-sumDim)+'%'; 
    - 160                style.fields[f[5]] = 'auto';
    - 161                return false;
    - 162            });
    - 163        }
    - 164
    - 165        pass(styles, f[2], f[3], (e:string) => e==='end');              // forward pass
    - 166        pass(styles.reverse(), f[3], f[2], (e:string) => e!=='end');    // backward pass
    - 167        return styles.reverse();    // reverse a second time for original sequence.
    - 168    };
    - 169
    - 170    private unitPixel(num:number):descriptor[] { // pattern: [px, px, FILL , px, px]
    - 171        let styles:descriptor[] = this.getSizes(num);
    - 172        let f = this.fields;
    - 173       
    - 174        let defDim = 100.0/num;          // used for unspecified widths
    - 175
    - 176        // work forwards through the heights
    - 177        let sumDim = 0;
    - 178        styles.some((style, i) => {
    - 179            if (style.code==='start') {   // so far, all heights explicitly set as px
    - 180                style.fields[f[2]] = sumDim +'px';
    - 181                sumDim += style.size + (this.spacing || 0) + (this.spacing || 0);
    - 182                style.fields[f[3]] = 'auto';
    - 183                style.fields[f[5]] = style.size +'px';
    - 184            } else if (style.code === null) {
    - 185                style.fields[f[2]] = (sumDim>0)? (sumDim +'px') : (i*defDim + '%');
    - 186                sumDim = -1;
    - 187                style.fields[f[3]] = (100-(i+1)*defDim) + '%';
    - 188                style.fields[f[5]] = 'auto';
    - 189            } else if (style.code==='end') { return true; }
    - 190            return false;
    - 191        });
    - 192        
    - 193        // work backwards through the heights
    - 194        sumDim = 0;
    - 195        styles.slice().reverse().some((style, i) => {
    - 196            style.fields[f[3]] = sumDim + 'px';
    - 197            if (style.code === 'end') { 
    - 198                sumDim += style.size + (this.spacing || 0) + (this.spacing || 0);
    - 199                style.fields[f[2]] = 'auto';
    - 200                style.fields[f[5]] = style.size+'px';
    - 201            } else {
    - 202                if (sumDim>0 && style.code !== 'start') {
    - 203                    style.fields[f[5]] = 'auto';
    - 204                }
    - 205                return true; 
    - 206            } 
    - 207            return false;
    - 208        });  
    - 209        return styles;
    - 210    };
    - 211    
    - 212    /**
    - 213     * Calculates the style attributes required for each component in `Components`.
    - 214     * These attributes are saved in a `styles` field on the component itself. 
    - 215     * During rendering these `styles` attributes are copied to the `node.attrs.styles` field.
    - 216     * @param components 
    - 217     */

    - 218    protected getStyles(components:Array):string  { 
    - 219        let f = this.fields;
    - 220        let styles:descriptor[] = this.unit(components.length);
    - 221        components.map((c:Layout|Vnode, i:number) => {
    - 222            c.style = `${f[0]}:0%; ${f[1]}:0%; `;
    - 223            Object.keys(styles[i].fields).forEach((st:string) => { c.style += `${st}: ${styles[i].fields[st]};`; });
    - 224        });   
    - 225        return this.cssClass;
    - 226    };
    - 227};
    - 228
    - 229/**
    - 230 * Constructs a columns pillar layout style.

    - 231 * Use `{columns: [attributes]}` to invoke this layout. See top of page for a description.
    - 232 * 
    - 233 * 
    - 234 * const styles = [ 
    - 235 *     [],                // equal spacing
    - 236 *     ["100px"],         // fixed spacing
    - 237 *     ["60px", "100px"], // fixed spacing, first one smaller
    - 238 *     ["100px", "fill"], // first one fixed, rest equal
    - 239 *     ["fill", "100px"], // last one fixed, rest equal
    - 240 *     ["20%"],           // relative spacing, all equal
    - 241 *     ["20%", "fill"],   // first relative, rest equal
    - 242 *     ["fill", "20%"]    // last relative, rest equal
    - 243 * ];
    - 244 * let c = [];
    - 245 * m.mount(root, { 
    - 246 *     view:() => m(hslayout.Layout, {
    - 247 *         rows:[],  // each row a style
    - 248 *         content: styles.map(i => m(hslayout.Layout, {
    - 249 *             css: '.myExample', 
    - 250 *             content: c.map(c=>(''+i)), // the style descriptor
    - 251 *             columns: i                 // a style from styles
    - 252 *         }))
    - 253 *     })
    - 254 * });
    - 255 * function next() {
    - 256 *     if (c.length >= 5) { c = []; }
    - 257 *     else { c.push(''); }
    - 258 *     setTimeout(next, 2000);
    - 259 *     m.redraw();
    - 260 * }
    - 261 * 
    - 262 * next();
    - 263 * 
    - 264 * 
    - 265 * .hs-row-layout>.myExample { 
    - 266 *     border-top:    1px solid white;
    - 267 *     border-bottom: 1px solid white;
    - 268 * }
    - 269 * .myExample>.hs-layout {
    - 270 *     border:    1px solid white;
    - 271 *     background-color: #ccc;
    - 272 * }
    - 273 * .myExample { 
    - 274 *     color:       #a44; 
    - 275 *     font-weight: bold; 
    - 276 *     text-align:  center;
    - 277 * }
    - 278 * 
    - 279 * 

    - 280 */

    - 281class Columns extends PillarLayouter {
    - 282    constructor(public areaDesc:LayoutToken[]) { super(cParams[PillarLayouts[0]], areaDesc);  };
    - 283};
    - 284
    - 285/**
    - 286 * Constructs a row pillar layout style.

    - 287 * Use `{row: [attributes]}` to invoke this layout. See top of page for a description.
    - 288 * 
    - 289 * 
    - 290 * const styles = [ 
    - 291 *     [],                // equal spacing
    - 292 *     ["100px"],         // fixed spacing
    - 293 *     ["60px", "100px"], // fixed spacing, first one smaller
    - 294 *     ["100px", "fill"], // first one fixed, rest equal
    - 295 *     ["fill", "100px"], // last one fixed, rest equal
    - 296 *     ["20%"],           // relative spacing, all equal
    - 297 *     ["20%", "fill"],   // first relative, rest equal
    - 298 *     ["fill", "20%"]    // last relative, rest equal
    - 299 * ];
    - 300 * let c = [];
    - 301 * function next() {
    - 302 *     if (c.length >= 5) { c = []; }
    - 303 *     else { c.push(''); }
    - 304 *     setTimeout(next, 2000);
    - 305 *     m.redraw();
    - 306 * }
    - 307 * 
    - 308 * m.mount(root, { 
    - 309 *     view:() => m(hslayout.Layout, {
    - 310 *         columns:[],  // each column a style
    - 311 *         content: styles.map(i => m(hslayout.Layout, {
    - 312 *             css: '.myExample', 
    - 313 *             content: c.map(c=>(''+i)),
    - 314 *             rows: i   // a style from styles
    - 315 *         }))
    - 316 *     })
    - 317 * });
    - 318 * next();
    - 319 * 
    - 320 * 
    - 321 * .hs-column-layout>.myExample {
    - 322 *     border-left:  1px solid white;
    - 323 *     border-right: 1px solid white;
    - 324 * }
    - 325 * .myExample>.hs-layout {
    - 326 *     border:    1px solid white;
    - 327 *     background-color: #ccc;
    - 328 * }
    - 329 * .myExample { 
    - 330 *     color:       #a44; 
    - 331 *     font-weight: bold; 
    - 332 *     text-align:  center;
    - 333 * }
    - 334 * 
    - 335 * 

    - 336 */

    - 337class Rows extends PillarLayouter {
    - 338    constructor(public areaDesc:LayoutToken[]) { super(cParams[PillarLayouts[1]], areaDesc);  };
    - 339};
    - 340
    - 341Layouter.register(PillarLayouts[0], Columns);
    - 342Layouter.register(PillarLayouts[1],    Rows);
    - 343
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/PillaredLayouter.spec.html b/docs/src/hsLayout/view/PillaredLayouter.spec.html deleted file mode 100644 index 740ecf9..0000000 --- a/docs/src/hsLayout/view/PillaredLayouter.spec.html +++ /dev/null @@ -1,101 +0,0 @@ - - -

    view/PillaredLayouter.spec.ts

    -
       1
    -   2const hslayout = require('../src/');
    -   3const m = hslayout.m;
    -   4const o = hslayout.o;
    -   5
    -   6
    -   7const columns = ["150px", "fill"];
    -   8const titles  = ['Left Column: 150px', 'Right Column: remainder'];
    -   9
    -  10
    -  11o.spec('rows', () => {
    -  12    let rows:any;
    -  13    o.before(() => {
    -  14        m.mount(o.root, {view: () => m(hslayout.Layout, {
    -  15            css: 'myRow',
    -  16            rows: columns,
    -  17            content: titles
    -  18            })
    -  19        }); 
    -  20        rows = o.root.childNodes[0];
    -  21    }); 
    -  22    o('first level', () => {
    -  23        o(rows===undefined).equals(false)('should be defined');
    -  24        o(rows.className.includes('myRow')).equals(true)(`class myRow in '${rows.className}'`);
    -  25        o(rows.className.includes('hs-row-layout')).equals(true)(`class hs-row-layout in '${rows.className}'`);
    -  26        o(rows.childNodes.length).equals(2)(`has ${rows.childNodes.length} children`);
    -  27    });
    -  28
    -  29    o('second level', () => {
    -  30        rows.childNodes.forEach((c:any, i:number) => {
    -  31            o(c.className.includes('hs-layout')).equals(true)(`class hs-layout in '${c.className}'`);
    -  32            o(c.style.left).equals('0%')(`style left`);
    -  33            o(c.style.right).equals('0%')(`style right`);
    -  34            o(c.style.top).equals((i===0)?'0px':columns[0])(`style top`);
    -  35            o(c.style.bottom).equals((i===0)?'auto':'0px')(`style bottom`);
    -  36            o(c.style.height).equals((i===0)?columns[0]:'auto')(`style height`);
    -  37            o(c.childNodes.length).equals(1)(`has ${c.childNodes.length} children`);
    -  38        });
    -  39    });
    -  40    o('third level', () => {
    -  41        rows.childNodes.forEach((c:any, i:number) => {
    -  42            o(c.childNodes[0].className.includes('hs-leaf')).equals(true)(`class hs-leaf in '${c.childNodes[0].className}'`);
    -  43            o(c.childNodes[0].childNodes[0].nodeValue).equals(titles[i])(`item ${i+1} child leaf text`);
    -  44        });
    -  45    });
    -  46});
    -  47
    -  48o.spec('columns', () => {
    -  49    let rows:any;
    -  50    o.before(() => {
    -  51        m.mount(o.root, {view: () => m(hslayout.Layout, {
    -  52            css: 'myColumn',
    -  53            columns: columns,
    -  54            content: titles
    -  55            })
    -  56        }); 
    -  57        rows = o.root.childNodes[0];
    -  58    }); 
    -  59    o('first level', () => {
    -  60        o(rows===undefined).equals(false)('should be defined');
    -  61        o(rows.className.includes('myColumn')).equals(true)(`class myColumn in '${rows.className}'`);
    -  62        o(rows.className.includes('hs-column-layout')).equals(true)(`class hs-column-layout in '${rows.className}'`);
    -  63        o(rows.childNodes.length).equals(2)(`has ${rows.childNodes.length} children`);
    -  64    });
    -  65
    -  66    o('second level', () => {
    -  67        rows.childNodes.forEach((c:any, i:number) => {
    -  68            o(c.className.includes('hs-layout')).equals(true)(`class hs-layout in '${c.className}'`);
    -  69            o(c.style.top).equals('0%')(`style top`);
    -  70            o(c.style.bottom).equals('0%')(`style bottom`);
    -  71            o(c.style.left).equals((i===0)?'0px':columns[0])(`style left`);
    -  72            o(c.style.right).equals((i===0)?'auto':'0px')(`style right`);
    -  73            o(c.style.width).equals((i===0)?columns[0]:'auto')(`style width`);
    -  74            o(c.childNodes.length).equals(1)(`has ${c.childNodes.length} children`);
    -  75        });
    -  76    });
    -  77    o('third level', () => {
    -  78        rows.childNodes.forEach((c:any, i:number) => {
    -  79            o(c.childNodes[0].className.includes('hs-leaf')).equals(true)(`class hs-leaf in '${c.childNodes[0].className}'`);
    -  80            o(c.childNodes[0].childNodes[0].nodeValue).equals(titles[i])(`item ${i+1} child leaf text`);
    -  81        });
    -  82    });
    -  83});
    -  84
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/TileLayout.html b/docs/src/hsLayout/view/TileLayout.html deleted file mode 100644 index ae1a08d..0000000 --- a/docs/src/hsLayout/view/TileLayout.html +++ /dev/null @@ -1,156 +0,0 @@ - - -

    view/TileLayout.ts

    -
       1/**
    -   2Lays out components in tiles
    -   3Use 
    -   4- `{tiles: [attributes]}`
    -   5
    -   6to invoke this layout.
    -   7
    -   8### Example
    -   9
    -  10    {tiles: ["20%]}   // --> tiles will all have 20% of available height and width 
    -  11

    -  12 * 
    -  13 * 
    -  14 * let c = [1,2,3,4,5];
    -  15 * 
    -  16 * m.mount(root, { 
    -  17 *     view:() => m(hslayout.Container, {
    -  18 *         tiles:[], 
    -  19 *         content: c.map((c,i)=>(''+i)),
    -  20 *         css: '.myExample'
    -  21 *     })
    -  22 * });
    -  23 *
    -  24 * function next() {
    -  25 *     if (c.length >= 9) { c = []; }
    -  26 *     else { c.push(''); }
    -  27 *     setTimeout(next, 2000);
    -  28 *     m.redraw();
    -  29 * }
    -  30 * next();
    -  31 * 
    -  32 * 
    -  33 * .myExample .hs-layout { 
    -  34 *     border: 1px solid white;
    -  35 *     background-color: #ccc;
    -  36 *     color:       #a44; 
    -  37 *     text-align:  center;
    -  38 * }
    -  39 * 
    -  40 * 

    -  41
    -  42## Attributes
    -  43The following values **v** are valid entries in The Attributes array:
    -  44- **px(n)** or **"_n_ px"** -- a fixed number of pixels 
    -  45- **pc(n)** or **"_n_ %"**  -- a fixed percentage of available space
    -  46- **FILL** or **"fill"**   -- a special constant to indicate - may appear only once per array.
    -  47
    -  48The following options are supported for the Attributes array:
    -  49- **[ ]**: An empty array; The available tiles will cover the entire width and height. 
    -  50    Their size will adapt as tiles are added.
    -  51- **[FILL]**: like [ ], except the last tile fills the available space. 
    -  52- **[v]**: All components have the specified width and height (in px or %) and will fill the available space from the left,
    -  53    leaving any remaining unused space on the right. 
    -  54- **[w, h]**: All components have the specified width w and height h (in px or %) and will fill the available space from the left,
    -  55    leaving any remaining unused space on the right. 
    -  56- **[v, FILL]**: like [v], except that the last tile in each row will fill the remaining available width 
    -  57    and the tiles in the bottom row will fill the remaining height
    -  58- **[w, h, FILL]**: like [w, h], except that the last tile will fill the remaining available width. 
    -  59 */

    -  60/** */
    -  61import { Container }    from './Container';
    -  62import { Layout }       from './Layout';
    -  63import { LayoutToken, FillToken, DefinedToken, PixelToken }    from './Tokens';
    -  64import { Vnode}         from '../mithril';
    -  65
    -  66type descriptor = {top:string, left:string, right:string, bottom:string, width:string, height:string};
    -  67
    -  68/**
    -  69 */

    -  70class Tiles extends Layout {
    -  71    cssClass:string;
    -  72    unit: any;
    -  73
    -  74    /**
    -  75     * Constructs a Pillared layout (rows or columns)
    -  76     * @param params Style params for either rows or columns layout
    -  77     * @param areaDesc Description of the requested layout 
    -  78     */

    -  79    constructor(public areaDesc:LayoutToken[]) { 
    -  80        super(areaDesc); 
    -  81        // if any of the dimensions are in px, use the pixel method; else use the percent method
    -  82        // get unitPixel if any area is PixelToken           
    -  83        this.unit = areaDesc.some((area:LayoutToken) => (area instanceof PixelToken))? 
    -  84            this.unitPixel : this.unitPercent;           
    -  85    };
    -  86
    -  87    private unitPercent(num:number) {
    -  88        const desc = this.areaDesc;
    -  89        const fill = this.areaDesc.some(a => (a instanceof FillToken));
    -  90        const root = Math.sqrt(num);
    -  91        const rows = Math.round(root);
    -  92        let   cols = Math.floor(root);
    -  93        if (root > cols) { cols++; }
    -  94        let width  = (desc[0] instanceof DefinedToken)? desc[0].getSize() : undefined;
    -  95        let height = (desc[1] instanceof DefinedToken)? desc[1].getSize() : width;
    -  96
    -  97        width  = width  || 100/cols;
    -  98        height = height || 100/rows;
    -  99        let left = 0;
    - 100        let top  = 0;
    - 101
    - 102
    - 103        let styles = [...Array(num).keys()].map(i => { 
    - 104            let r = 'auto';    let w = width+'%'; 
    - 105            let b = 'auot';    let h = height+'%';
    - 106            if ((left + 2*width) > 100 && fill) { r = '0%'; w = 'auto'; }
    - 107            if ((top + 2*height) > 100 && fill) { b = '0%'; h = 'auto'; }
    - 108            const style = `
    - 109                top: ${Math.floor(top)}%; bottom:${b};
    - 110                left: ${left}%;           right:${r};
    - 111                width: ${w};              height: ${h};
    - 112            `;
    - 113            if (Math.round(left += width) > 100-Math.floor(width)) { left = 0; top += height; }
    - 114            return style;
    - 115         });
    - 116        return styles;    // reverse a second time for original sequence.
    - 117    };
    - 118
    - 119    private unitPixel(num:number) { // pattern: [px, px, FILL]
    - 120    };
    - 121    
    - 122    /**
    - 123     * Calculates the style attributes required for each component in `Components`.
    - 124     * These attributes are saved in a `styles` field on the component itself. 
    - 125     * During rendering these `styles` attributes are copied to the `node.attrs.styles` field.
    - 126     * @param components 
    - 127     */

    - 128    protected getStyles(components:Array):string  { 
    - 129        let styles = this.unit(components.length);
    - 130        components.map((c:Container|Vnode, i:number) => {
    - 131            c.style = styles[i];
    - 132        });   
    - 133        return '.hs-tile-layout';
    - 134    };
    - 135};
    - 136
    - 137
    - 138Layout.register('tiles', Tiles);
    - 139
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/TileLayouter.html b/docs/src/hsLayout/view/TileLayouter.html deleted file mode 100644 index e63e4bb..0000000 --- a/docs/src/hsLayout/view/TileLayouter.html +++ /dev/null @@ -1,180 +0,0 @@ - - -

    view/TileLayouter.ts

    -
       1/**
    -   2Lays out components in tiles
    -   3Use 
    -   4- `{tiles: [attributes]}`
    -   5
    -   6to invoke this layout.
    -   7
    -   8### Example
    -   9
    -  10    {tiles: ["20%"]}   // --> tiles will all have 20% of available height and width 
    -  11

    -  12 * 
    -  13 * 
    -  14 * let c = [1,2,3,4,5];
    -  15 * 
    -  16 * m.mount(root, { 
    -  17 *     view:() => m(hslayout.Layout, {
    -  18 *         tiles:[], 
    -  19 *         content: c.map((c,i)=>(''+i)),
    -  20 *         css: '.myExample'
    -  21 *     })
    -  22 * });
    -  23 *
    -  24 * function next() {
    -  25 *     if (c.length >= 9) { c = []; }
    -  26 *     else { c.push(''); }
    -  27 *     setTimeout(next, 2000);
    -  28 *     m.redraw();
    -  29 * }
    -  30 * next();
    -  31 * 
    -  32 * 
    -  33 * .myExample .hs-layout { 
    -  34 *     border: 1px solid white;
    -  35 *     background-color: #ccc;
    -  36 *     color:       #a44; 
    -  37 *     text-align:  center;
    -  38 * }
    -  39 * 
    -  40 * 

    -  41
    -  42## Attributes
    -  43The following values **v** are valid entries in The Attributes array:
    -  44- **px(n)** or **"_n_ px"** -- a fixed number of pixels 
    -  45- **pc(n)** or **"_n_ %"**  -- a fixed percentage of available space
    -  46- **FILL** or **"fill"**   -- a special constant indicate to fill remaining space - may appear only once per array.
    -  47
    -  48The following options are supported for the Attributes array:
    -  49- **[ ]**: An empty array; The available tiles will cover the entire width and height. 
    -  50    Their size will adapt as tiles are added.
    -  51- **[FILL]**: like [ ], except the last tile fills the available space. 
    -  52- **[v]**: All components have the specified width and height (in px or %) and will fill the available space from the left,
    -  53    leaving any remaining unused space on the right. 
    -  54- **[w, h]**: All components have the specified width w and height h (in px or %) and will fill the available space from the left,
    -  55    leaving any remaining unused space on the right. 
    -  56- **[v, FILL]**: like [v], except that the last tile in each row will fill the remaining available width 
    -  57    and the tiles in the bottom row will fill the remaining height
    -  58- **[w, h, FILL]**: like [w, h], except that the last tile will fill the remaining available width. 
    -  59 */

    -  60/** */
    -  61import { Layout }    from './Layout';
    -  62import { Layouter }       from './Layouter';
    -  63import { LayoutToken, FillToken, DefinedToken, PixelToken }    from './Tokens';
    -  64import { Vnode}         from '../mithril';
    -  65
    -  66type descriptor = {top:string, left:string, right:string, bottom:string, width:string, height:string};
    -  67
    -  68/**
    -  69 */

    -  70class Tiles extends Layouter {
    -  71    cssClass:string;
    -  72    unit: any;
    -  73
    -  74    /**
    -  75     * Constructs a Tileds layout
    -  76     * @param areaDesc Description of the requested layout 
    -  77     */

    -  78    constructor(public areaDesc:LayoutToken[]) { 
    -  79        super(areaDesc); 
    -  80        // if any of the dimensions are in px, use the pixel method; else use the percent method
    -  81        // get unitPixel if any area is PixelToken           
    -  82        this.unit = areaDesc.some((area:LayoutToken) => (area instanceof PixelToken))? 
    -  83            this.unitPixel : this.unitPercent;           
    -  84    };
    -  85
    -  86    private unitPercent(num:number) {
    -  87        const desc = this.areaDesc;
    -  88        const fill = this.areaDesc.some(a => (a instanceof FillToken));
    -  89        const root = Math.sqrt(num);
    -  90        const rows = Math.round(root);
    -  91        let   cols = Math.floor(root);
    -  92        if (root > cols) { cols++; }
    -  93        let width  = (desc[0] instanceof DefinedToken)? desc[0].getSize() : undefined;
    -  94        let height = (desc[1] instanceof DefinedToken)? desc[1].getSize() : width;
    -  95
    -  96        width  = width  || 100/cols;
    -  97        height = height || 100/rows;
    -  98        let left = 0;
    -  99        let top  = 0;
    - 100
    - 101        let styles = [...Array(num).keys()].map(i => { 
    - 102            let r = 'auto';    let w = width+'%'; 
    - 103            let b = 'auto';    let h = height+'%';
    - 104            if ((left + 2*width) > 100 && fill) { r = '0%'; w = 'auto'; }
    - 105            if ((top + 2*height) > 100 && fill) { b = '0%'; h = 'auto'; }
    - 106            const style = `
    - 107                top: ${Math.floor(top)}%; bottom:${b};
    - 108                left: ${left}%;           right:${r};
    - 109                width: ${w};              height: ${h};
    - 110            `;
    - 111            if (Math.round(left += width) > 100-Math.floor(width)) { left = 0; top += height; }
    - 112            return style;
    - 113         });
    - 114        return styles;    
    - 115    };
    - 116
    - 117    private unitPixel(num:number) { // pattern: [px, px, FILL]
    - 118        const desc = this.areaDesc;
    - 119//        const fill = this.areaDesc.some(a => (a instanceof FillToken));
    - 120        const root = Math.sqrt(num);
    - 121        const rows = Math.round(root);
    - 122        let   cols = Math.floor(root);
    - 123        if (root > cols) { cols++; }
    - 124        let width  = (desc[0] instanceof DefinedToken)? desc[0].getSize() : undefined;
    - 125        let height = (desc[1] instanceof DefinedToken)? desc[1].getSize() : width;
    - 126
    - 127        width  = width  || 100/cols;
    - 128        height = height || 100/rows;
    - 129        let left = 0;
    - 130        let top  = 0;
    - 131
    - 132        let styles = [...Array(num).keys()].map(i => { 
    - 133            let r = 'auto';    let w = width+'px'; 
    - 134            let b = 'auto';    let h = height+'px';
    - 135            const style = `
    - 136                top: ${Math.floor(top)}%; bottom:${b};
    - 137                left: ${left}%;           right:${r};
    - 138                width: ${w};              height: ${h};
    - 139            `;
    - 140            if (Math.round(left += width) > 100-Math.floor(width)) { left = 0; top += height; }
    - 141            return style;
    - 142         });
    - 143        return styles;    
    - 144    };
    - 145    
    - 146    /**
    - 147     * Calculates the style attributes required for each component in `Components`.
    - 148     * These attributes are saved in a `styles` field on the component itself. 
    - 149     * During rendering these `styles` attributes are copied to the `node.attrs.styles` field.
    - 150     * @param components 
    - 151     */

    - 152    protected getStyles(components:Array):string  { 
    - 153        let styles = this.unit(components.length);
    - 154        components.map((c:Layout|Vnode, i:number) => {
    - 155            c.style = styles[i];
    - 156        });   
    - 157        return '.hs-tile-layout';
    - 158    };
    - 159};
    - 160
    - 161
    - 162Layouter.register('tiles', Tiles);
    - 163
    - - \ No newline at end of file diff --git a/docs/src/hsLayout/view/Tokens.html b/docs/src/hsLayout/view/Tokens.html deleted file mode 100644 index 3fdda1d..0000000 --- a/docs/src/hsLayout/view/Tokens.html +++ /dev/null @@ -1,75 +0,0 @@ - - -

    view/Tokens.ts

    -
       1/**
    -   2 * ## Layout Tokens
    -   3 * Used to specify layout sizes
    -   4 */

    -   5
    -   6/**
    -   7 * Abstract token for a layout area. It is defined by a single number available via the constructor. 
    -   8 */

    -   9export abstract class LayoutToken {
    -  10    constructor(private size: number) {}
    -  11    public getSize() { return this.size; }
    -  12}
    -  13
    -  14/**
    -  15 * A layout token that is defined in size.
    -  16 */

    -  17export abstract class DefinedToken extends LayoutToken{
    -  18    constructor(size: number) { super(size); } 
    -  19}
    -  20
    -  21/**
    -  22 * A layout token that is undefined in size, and that fill will     the available space.
    -  23 */

    -  24export class FillToken extends LayoutToken {
    -  25    constructor() { super(-1); }
    -  26}
    -  27
    -  28/**
    -  29 * A defined token that sets a size in pixel.
    -  30 */

    -  31export class PixelToken extends DefinedToken {
    -  32    constructor(size:number) { super(size); }
    -  33}
    -  34
    -  35/**
    -  36 * A defined token that sets a size in percent of available space.
    -  37 */

    -  38export class PercentToken extends DefinedToken {
    -  39    constructor(size:number) { super(size); }
    -  40}
    -  41
    -  42/**
    -  43 * A convenience function that returns a defined pixel-sized token
    -  44 * @param px the number of pixels in the token
    -  45 */

    -  46export function px(px:number)   { return new PixelToken(px); }
    -  47
    -  48/**
    -  49 * A convenience function that returns a defined percent-sized token
    -  50 * @param pc the percentage in the token
    -  51 */

    -  52export function pc(pc:number)   { return new PercentToken(pc); }
    -  53
    -  54/**
    -  55 * Convenience constant, standing for an undefined fill token.
    -  56 */

    -  57export const FILL = new FillToken();
    -  58
    - - \ No newline at end of file diff --git a/docs/src/hsNode/cpUtil.html b/docs/src/hsNode/cpUtil.html deleted file mode 100644 index de4df02..0000000 --- a/docs/src/hsNode/cpUtil.html +++ /dev/null @@ -1,59 +0,0 @@ - - -

    cpUtil.ts

    -
       1const cp    = require('child_process');
    -   2import { log } from './';
    -   3
    -   4/**
    -   5 * @ngdoc object
    -   6 * @name hsNode.cpUtil
    -   7 * @description Convenience functions for child process access, wrapped in Promises.
    -   8 * - {@link hsNode.cpUtil#methods_exec exec}
    -   9 */

    -  10
    -  11//===============================================================================
    -  12//  Low level Promise wrappers
    -  13 
    -  14/**
    -  15 * @ngdoc object
    -  16 * @name exec
    -  17 * @methodOf hsNode.cpUtil
    -  18 * @description executes `command` in a child process and promises to return the stdout and stderr streams.
    -  19 

    -  20        let utils = require('./cpUtils');
    -  21        utils.exec(cmd)
    -  22            .then((stdout, stderr) => {...})
    -  23            .catch(err => {...});
    -  24

    -  25 * @param {string} command the shell command to execute
    -  26 * @param {object} options the options to pass along to the shell
    -  27 * @return {Promise} promise to provide the stdout and stderr streams form the child process.
    -  28 */

    -  29function exec(command:string, options?:any) {
    -  30    return new Promise((resolve:(result:{out:string, err:string})=>void, reject:(e:string)=>void) => {
    -  31        cp.exec(command, options, (error:string, stdout:string, stderr:string) => {
    -  32            if (error) {
    -  33     log.error('exec for ' + command + ': ' + error);
    -  34                reject(error);
    -  35            } else {
    -  36                resolve({out:stdout, err:stderr});
    -  37            }
    -  38        });
    -  39    });
    -  40}
    -  41
    -  42export { exec };
    - - \ No newline at end of file diff --git a/docs/src/hsNode/cpUtil.spec.html b/docs/src/hsNode/cpUtil.spec.html deleted file mode 100644 index 634870f..0000000 --- a/docs/src/hsNode/cpUtil.spec.html +++ /dev/null @@ -1,80 +0,0 @@ - - -

    cpUtil.spec.ts

    -
       1import { exec } from './';
    -   2
    -   3
    -   4describe("cpUtil", () => {
    -   5    let cpOut:string, cpErr:string, cpE:string;
    -   6    const helper = {
    -   7        out: (out:string, err:string) => { cpOut = out; cpErr = err; },
    -   8        err: (e:string) => { cpE = e; }
    -   9    };
    -  10
    -  11    function call(cmd:string, done:any) {
    -  12        exec(cmd)
    -  13            .then((result:{out:string, err:string}) => { helper.out(result.out, result.err); done(); })
    -  14            .catch((e:string) => { helper.err(e); done(); });
    -  15    }
    -  16
    -  17    beforeEach(() => {
    -  18        cpE = cpErr = cpOut = undefined;
    -  19        spyOn(helper, 'out').and.callThrough();
    -  20        spyOn(helper, 'err').and.callThrough();
    -  21    });
    -  22
    -  23    describe('valid command', () => {
    -  24        beforeEach(done => { call("pwd", done);
    -  25//            cp.exec("pwd")
    -  26//                .then((result:{out:string, err:string}) => { helper.out(result.out, result.err); done(); })
    -  27//                .catch((e:string) => { helper.err(e); done(); });
    -  28        });
    -  29
    -  30        it('should execute "pwd" in a shell without error', done => {
    -  31            expect(helper.out).toHaveBeenCalled();
    -  32            expect(helper.err).not.toHaveBeenCalled();
    -  33            done();
    -  34        });
    -  35
    -  36        it('should result in path', () => {
    -  37            expect(cpOut.trim().endsWith('/hsNode')).toEqual(true);
    -  38            expect(cpE).not.toBeDefined();
    -  39            expect(cpErr).toBe('');
    -  40        });  
    -  41    });
    -  42
    -  43    describe('invalid command', () => {
    -  44        beforeEach(done => { call("abcd", done);
    -  45//            cp.exec("abcd")
    -  46//                .then((result:{out:string, err:string}) => { helper.out(result.out, result.err); done(); })
    -  47//                .catch((e:string) => { helper.err(e); done(); });
    -  48        });
    -  49
    -  50        it('should fail executing "abcd" in a shell', done => {
    -  51            expect(helper.out).not.toHaveBeenCalled();
    -  52            expect(helper.err).toHaveBeenCalled();
    -  53            done();
    -  54        });
    -  55
    -  56        it('should result in error', () => {
    -  57            expect(cpOut).not.toBeDefined();
    -  58            expect(cpErr).not.toBeDefined();
    -  59            expect(cpE).toMatch('abcd: command not found');
    -  60        });  
    -  61    });
    -  62});
    -  63
    - - \ No newline at end of file diff --git a/docs/src/hsNode/date.html b/docs/src/hsNode/date.html deleted file mode 100644 index 0e147bc..0000000 --- a/docs/src/hsNode/date.html +++ /dev/null @@ -1,89 +0,0 @@ - - -

    date.ts

    -
       1/**
    -   2 * @ngdoc object
    -   3 * @name hsNode.date
    -   4 * @description .
    -   5 * ### Date formatting support. 
    -   6 * Formats are specified in a printf-style format string. 
    -   7 * ### Example:
    -   8 * 

    -   9 * import date  from './date';
    -  10 * date('%MM/%DD/%YY');           // -> 08/17/16 (using current date)
    -  11 * let d = new Date('7/4/2010');
    -  12 * date('%DDDD, %MM/%DD/%YY', d); // -> Sunday, 07/04/10
    -  13 * 

    -  14 * ### Supported Formats
    -  15- `%YY, %YYYY`           : two- or four-digit year, as '73', '1973'
    -  16- `%M, %MM, %MMM, %MMMM` : month of year as '2', '02', 'Feb', 'February'
    -  17- `%D, %DD`              : day of month as '5', '05' (1...31)
    -  18- `%DDD, %DDDD`          : day of week as 'Tue', 'Tuesday'
    -  19- `%h, %hh`              : hour of day as '7', '07 (0...23)
    -  20- `%m, %mm`              : minutes as '6', '06' (0..59)
    -  21- `%ss`                  : seconds as '09' (0...59)
    -  22- `%j, %jj, %jjj`        : milliseconds as '1', '15', '159'
    -  23 */

    -  24
    -  25/** translates short month names to full month names */
    -  26const monthStr = [
    -  27    ['Jan', 'January'], ['Feb', 'February'], ['Mar', 'March'], ['Apr', 'April'], ['May', 'May'], ['Jun', 'June'],
    -  28    ['Jul', 'July'], ['Aug', 'August'], ['Sep', 'September'], ['Oct', 'October'], ['Nov', 'November'], ['Dec', 'December']];
    -  29
    -  30/** translates short day names to full day names */
    -  31const dayStr = [
    -  32    ['Sun', 'Sunday'],['Mon', 'Monday'],['Tue', 'Tuesday'],['Wed', 'Wednesday'],['Thu', 'Thursday'],['Fri', 'Friday'],['Sat', 'Saturday']];
    -  33
    -  34/**
    -  35 * left-pads a `number` with zeros to match `minDigits` minimum digits
    -  36 */

    -  37function formatNumber(number:number, minDigits:number):string {
    -  38    let r = ""+number;
    -  39    while (r.length < minDigits) { r = "0" + r; }
    -  40    return r;
    -  41}
    -  42
    -  43
    -  44/**
    -  45 * @ngdoc method 
    -  46 * @name ()
    -  47 * @methodOf hsNode.date
    -  48 * @param {String} formatString the format string to use.
    -  49 * @param {Date=} [date=new Date()] the date to format.
    -  50 * @returns {String} a copy of `formatString` where all supported patterns are replaced by the respective values from `date`.
    -  51 */

    -  52export default (formatString:string, date=new Date()) => formatString
    -  53 .replace(/%YYYY/g, ''+date.getFullYear())
    -  54 .replace(/%YY/g,   ''+(date.getFullYear()%100))
    -  55 .replace(/%MMMM/g,  monthStr[date.getMonth()][1])
    -  56 .replace(/%MMM/g,   monthStr[date.getMonth()][0])
    -  57 .replace(/%MM/g,   formatNumber(date.getMonth()+1,2))
    -  58 .replace(/%M/g,   ''+(date.getMonth()+1))
    -  59 .replace(/%DDDD/g,  dayStr[date.getDay()][1])
    -  60 .replace(/%DDD/g,   dayStr[date.getDay()][0])
    -  61 .replace(/%DD/g,   formatNumber(date.getDate(),2))
    -  62 .replace(/%D/g,   ''+date.getDate())
    -  63 .replace(/%hh/g,   formatNumber(date.getHours(),2))
    -  64 .replace(/%h/g,  ''+date.getHours())
    -  65 .replace(/%mm/g,   formatNumber(date.getMinutes(),2))
    -  66 .replace(/%m/g,   ''+date.getMinutes())
    -  67 .replace(/%ss/g,   formatNumber(date.getSeconds(),2))
    -  68 .replace(/%jjj/g,   formatNumber(date.getMilliseconds(),3))
    -  69 .replace(/%jj/g,   formatNumber(date.getMilliseconds()/10,2))
    -  70 .replace(/%j/g, formatNumber(date.getMilliseconds()/100,1))
    -  71;
    -  72
    - - \ No newline at end of file diff --git a/docs/src/hsNode/date.spec.html b/docs/src/hsNode/date.spec.html deleted file mode 100644 index 0423a8f..0000000 --- a/docs/src/hsNode/date.spec.html +++ /dev/null @@ -1,59 +0,0 @@ - - -

    date.spec.ts

    -
       1import { date } from './';
    -   2
    -   3
    -   4describe("date", function() {
    -   5 it('should have date defined as a function', function() {
    -   6 expect(date).toBeDefined();
    -   7 expect(typeof date).toBe('function');
    -   8 });
    -   9  
    -  10 describe('formatting of date 7/4/2010', function() {
    -  11 let d = new Date('7/4/2010');
    -  12
    -  13 it('should convert "%YYYY-%MMMM-%DD"', function() {
    -  14 expect(date("%YYYY-%MMMM-%DD", d)).toBe("2010-July-04");
    -  15 });
    -  16
    -  17 it('should convert "%YY%MMM%D %YY"', function() {
    -  18 expect(date("%YY%MMM%D %YY", d)).toBe("10Jul4 10");
    -  19 });
    -  20
    -  21 it('should convert "%YY%MM%D %h:%m:%ss.%j"', function() {
    -  22 expect(date("%YY%MM%D %h:%m:%ss.%j", d)).toBe("10074 0:0:00.0");
    -  23 });
    -  24
    -  25 it('should convert "%DDD, %YY%MM%DD %hh:%mm:%ss.%jj"', function() {
    -  26 expect(date("%DDD, %YY%MM%DD %hh:%mm:%ss.%jj", d)).toBe("Sun, 100704 00:00:00.00");
    -  27 });
    -  28
    -  29 it('should convert "%DDDD, %YY%MM%DD %hh:%mm:%ss.%jjj"', function() {
    -  30 expect(date("%DDDD, %YY%MM%DD %hh:%mm:%ss.%jjj", d)).toBe("Sunday, 100704 00:00:00.000");
    -  31 });
    -  32 });
    -  33
    -  34 describe('formatting of current date', function() {
    -  35 let now = new Date();
    -  36
    -  37 it('should format ' + now.toDateString(), function() {
    -  38 expect(date("%YYYY-%MM-%DD")).toBe(date("%YYYY-%MM-%DD", now));
    -  39 });
    -  40 });
    -  41});
    -  42
    - - \ No newline at end of file diff --git a/docs/src/hsNode/excel.html b/docs/src/hsNode/excel.html deleted file mode 100644 index 957578f..0000000 --- a/docs/src/hsNode/excel.html +++ /dev/null @@ -1,282 +0,0 @@ - - -

    excel.ts

    -
       1/**
    -   2 * # Excel 
    -   3 * Convenience functions to access tables in Excel files.
    -   4 * Uses the {@link https://github.com/SheetJS/js-xlsx Sheet JS xlsx parser and writer}.
    -   5 * 
    -   6 * # Excel related functions
    -   7 * - {@link excel.readFile readFile} 
    -   8 *
    -   9 */

    -  10
    -  11 /** */
    -  12const XLSX = require('xlsx');
    -  13
    -  14import { log }      from './';
    -  15import { DataRow}   from 'hsdata';
    -  16import { WorkBook,
    -  17         WorkSheet,
    -  18         CellObject
    -  19       }            from 'xlsx/types';
    -  20
    -  21log.prefix('XL');
    -  22
    -  23
    -  24/**
    -  25 * reads and returns a promise for an {@link #/hsLog/hsNode.excelFile excel file}.
    -  26 * ```
    -  27 * {
    -  28 *     {@link excel.readFile.getSheetNames getSheetNames},
    -  29 *  {@link excel.readFile.getTableColumns getTableColumns},
    -  30 *  {@link excel.readFile.getRowsForTable getRowsForTable},
    -  31 *  {@link excel.readFile.getTable getTable},
    -  32 *  {@link excel.readFile.nextExcelColIndex nextExcelColIndex},
    -  33 *  {@link excel.readFile.getCellValue getCellValue}
    -  34 * }
    -  35 * ```
    -  36 * # Usage
    -  37 * ```
    -  38 * const excel = require('./hsNode.excel');
    -  39 * const excelFile = excel.excelFile('./aFile.xlsx');
    -  40 * ``` 
    -  41 * @param name the name of the Excel file to read
    -  42 * @returns an object of functions providing access to the contents of the excel file.
    -  43 */

    -  44export function readFile(name:string, options?:any):ExcelFile { 
    -  45    //----------- private methods ------------------
    -  46 let workbook:WorkBook;
    -  47
    -  48 /**
    -  49  * returns the value of a cell, or undefined
    -  50  * @param sheet the sheet object or sheet name to retrieve cells from;
    -  51  * @param col the column index ('A',...)
    -  52  * @param row index (1,...)
    -  53  * @returns the value of a cell, or undefined
    -  54  */

    -  55 function getCellValue(sheet:string|WorkSheet, col:string, row:number):string {
    -  56 if (typeof sheet === 'string') { sheet = workbook.Sheets[sheet]; } 
    -  57        let c:CellObject;
    -  58 if (sheet[col+row] && sheet[col+row].v!=='') { 
    -  59            c = sheet[col+row];
    -  60            let val = c.w!==undefined? c.w : c.v;
    -  61 if (c) { switch(c.t) {
    -  62 case 's': return (val).replace(/,/g,';').replace(/[\n\r]+/g,' ').trim();
    -  63 case 'n': /* falls through */ 
    -  64 default: return c.w.replace(/,/g,'');
    -  65 }}
    -  66 }
    -  67 return ''; 
    -  68 }
    -  69
    -  70 /**
    -  71  * **Generator**, yields consecutive cell values over a row
    -  72  * @param sheet the sheet object or sheet name to retrieve cells from;
    -  73  * @param row the row to iterate over
    -  74  * @param colIterator iterable over columns;
    -  75  * or an iterable that generates column indices.
    -  76  */

    -  77 function* getCellValues(sheet:WorkSheet, row:number, colIterator:string[]) {
    -  78 for (let col of colIterator) {
    -  79 yield getCellValue(sheet, col, row); 
    -  80 }
    -  81 }
    -  82
    -  83 /**
    -  84  * **Generator**, yields consecutive column names as an 
    -  85  * {col, name} object. 
    -  86  * The generator exits when the first empty column name is encountered.
    -  87  * @param sheet the sheet to scan
    -  88  * @param row the row to scan
    -  89  * @param startCol defaults to 'A'
    -  90  */

    -  91 function* getConsecutiveColumnNames(sheet:WorkSheet, row:number, startCol='A') {
    -  92 for (let col of nextExcelColIndex(startCol)) {
    -  93 if (!getCellValue(sheet, col, row)) { break; }
    -  94 yield {col:col, name:getCellValue(sheet, col, row)}; 
    -  95 }
    -  96 }
    -  97
    -  98 /**
    -  99  * returns an array[c] of values from columns that match indices provided `columns`.
    - 100  * @param sheet the sheet object or sheet name to retrieve cells from;
    - 101  * @param row the row to iterate over
    - 102  * @param columns a) an array of column names. b) an {from:'A', to:'Z'} object 
    - 103  * @return array of column values in the row
    - 104  */

    - 105 function getRow(sheet:WorkSheet, row:number, columns:string[]) {
    - 106 let result = [...getCellValues(sheet, row, columns)];
    - 107 return result;
    - 108 }
    - 109
    - 110 /**
    - 111  * returns the value of a cell, or undefined
    - 112  * @param sheetName the sheet object or sheet name to retrieve cells from;
    - 113  * @param row index (1,...)
    - 114     * @param it an iterator over columns
    - 115  * @returns the value of a cell, or undefined
    - 116  */

    - 117 function constructCol(sheetName:string, row:number, it:any):TableStruct {
    - 118 let result:TableStruct = {
    - 119 names:[],
    - 120 sheetName: sheetName,
    - 121 headerRow: row,
    - 122 colIndex:  []
    - 123 };
    - 124 for (let col of it) {
    - 125 result.names.push(col.name);
    - 126 result.colIndex.push(col.col);
    - 127 }
    - 128 return result;
    - 129 }
    - 130
    - 131 /**
    - 132  * gets a table of values, starting at the startCol and startRow.
    - 133  * The table includes all consecutive columns with valid names, and all consecutive
    - 134  * rows with at least one valid cell value.
    - 135  * @param sheetID the sheet name or index from which to get the table
    - 136  * @param startCol determines the left edge of the table; defaults to 'A'
    - 137  * @param startRow determines the top edge of the table; defaults to 1
    - 138  * @returns a tuple of {columns, table} 
    - 139  */

    - 140 function getTable(sheetID:string|number, startCol='A', startRow=1) {
    - 141        const sheetName = (typeof sheetID === 'string')? sheetID : getSheetNames()[sheetID];
    - 142 const columns:TableStruct = getTableColumns(sheetName, startCol, startRow);
    - 143 const table:DataRow[]     = getRowsForTable(columns);
    - 144 return {columns, table};
    - 145    }
    - 146    
    - 147
    - 148    //----------- public methods ------------------
    - 149 /**
    - 150  * retrieves sheet names from a file
    - 151  * @returns {[string]} an array of sheet names
    - 152  */

    - 153 function getSheetNames():string[] {
    - 154 let names:string[] = [];
    - 155 for (let s in workbook.Sheets) { 
    - 156 names.push(s);
    - 157 }
    - 158 return names;
    - 159 }
    - 160
    - 161 /**
    - 162  * getTableColumns retrieves an array of consecutive valid column names.
    - 163  * @param sheetName the sheet object to retrieve cells from
    - 164  * @param startCol the first column of the table; defaults to 'A'.
    - 165  * @param row the row to iterate over; defaults to 1.
    - 166  * @returns an excel tabkle description
    - 167  */

    - 168 function getTableColumns(sheetName:string, startCol='A', row=1):TableStruct {
    - 169        let sheet:WorkSheet = workbook.Sheets[sheetName];
    - 170 return constructCol(sheetName, row, getConsecutiveColumnNames(sheet, row, startCol));
    - 171 }
    - 172
    - 173 /**
    - 174  * getRowsForTable returns a 2D array[r][c] of row values, where the columns match the provided 
    - 175  * columns names. 
    - 176  * @param table an array of column descriptors. 
    - 177  * @param maxRows if specified, determines the maximum number of rows to scan for. 
    - 178  * If omitted, iteration stops when the first row of empty values is encountered.
    - 179  */

    - 180 function getRowsForTable(table:TableStruct, maxRows=0):DataRow[] {
    - 181 if (!table.sheetName) { throw new Error('illegal table parameter in getRowsForTable'); }
    - 182 let sheet:WorkSheet = workbook.Sheets[table.sheetName];
    - 183 let result:DataRow[] = [];
    - 184 let row=0; 
    - 185 while (true) {
    - 186 let newRow = getRow(sheet, row+table.headerRow+1, table.colIndex);
    - 187 let filledCells = 0;
    - 188 for (let c in newRow) { if (newRow[c]) { filledCells++; }}
    - 189            row++;
    - 190            // only return non-empty rows
    - 191            if (filledCells > 0) { result.push(newRow); }
    - 192            // if no maxRows specified: break upon first empty row
    - 193            else if (maxRows<=0) {  break; }
    - 194            // if rows exceed maxRows: break;
    - 195 if (maxRows>0 && row>=maxRows) { break; }
    - 196 }
    - 197 return result;
    - 198 }
    - 199
    - 200    /**
    - 201     * **generator** for Excel column indices starting at startCol. 
    - 202     * Following 'Z' the next column generated is 'AA' and so on. The generator 
    - 203     * starts with producing startCol as first index.
    - 204     * # Usage
    - 205     * ```
    - 206     * for (col of file.nextExcelColIndex(startCol='Y') { 
    - 207     *    printf("%s, ", col);      // -> Y, Z, AA, AB
    - 208     *    if (col === 'AB')  { break; }
    - 209     * }
    - 210     * ```
    - 211     * @param startCol the first column index ('A', ....) to yield; defaults to 'A'
    - 212     */

    - 213    function* nextExcelColIndex(startCol='A'):IterableIterator {
    - 214        function nextChar(c:string):string { return String.fromCharCode(c.charCodeAt(0) + 1); }
    - 215        
    - 216        let c = startCol;
    - 217        while (true) {
    - 218            yield c;
    - 219            if (c.length === 1) {
    - 220                c = (c < 'Z')? nextChar(c[0]) : 'AA';
    - 221            } else {
    - 222                var ch = nextChar(c[1]);
    - 223                c = (ch > 'Z')? nextChar(c[0])+'A' : c[0] + ch;
    - 224            }
    - 225        }
    - 226    }
    - 227 log.debug('reading file ' + name);
    - 228 workbook = XLSX.readFile(name, options);
    - 229 return {
    - 230 getSheetNames: getSheetNames,
    - 231 getTableColumns: getTableColumns,
    - 232 getRowsForTable: getRowsForTable,
    - 233 getTable: getTable,
    - 234 nextExcelColIndex: nextExcelColIndex,
    - 235 getCellValue: getCellValue
    - 236 };
    - 237}
    - 238
    - 239
    - 240/**
    - 241 * A structure describing an Excel table
    - 242 */

    - 243export interface TableStruct {
    - 244    names:string[];
    - 245    sheetName:string;
    - 246    headerRow:number;
    - 247    colIndex:string[]; 
    - 248}
    - 249
    - 250/**
    - 251 * 
    - 252 */

    - 253export interface Table {
    - 254    columns:TableStruct;
    - 255    table:DataRow[];
    - 256}
    - 257
    - 258export interface ExcelFile {
    - 259    getSheetNames: () =>string[];
    - 260    getTableColumns: (sheetName:string, startCol?:string, row?:number) => TableStruct;
    - 261    getRowsForTable: (table:TableStruct, maxRows?:number) => DataRow[];
    - 262    getTable: (sheetID:string|number, startCol?:string, startRow?:number) => Table;
    - 263    nextExcelColIndex: (startCol?:string) => IterableIterator;
    - 264    getCellValue: (sheet:string|WorkSheet, col:string, row:number) => string;
    - 265}
    - - \ No newline at end of file diff --git a/docs/src/hsNode/excel.spec.html b/docs/src/hsNode/excel.spec.html deleted file mode 100644 index b5f90fb..0000000 --- a/docs/src/hsNode/excel.spec.html +++ /dev/null @@ -1,152 +0,0 @@ - - -

    excel.spec.ts

    -
       1import { hsExcel } from './';
    -   2
    -   3const TEST_FILE = '../example/test.xlsx';
    -   4
    -   5describe("hsExcel", function() {
    -   6 it('should have hsExcel defined', function() {
    -   7 expect(hsExcel).toBeDefined();
    -   8 });
    -   9  
    -  10 describe("test file", function() {
    -  11 const NAME  = TEST_FILE;
    -  12 const SHEET = 'Closed';
    -  13 let file:any;
    -  14
    -  15 beforeEach(function() {
    -  16 file = hsExcel.readFile(__dirname+'/'+NAME);
    -  17 });
    -  18
    -  19 it('should have read '+NAME, function() {
    -  20 expect(file).toBeDefined();
    -  21 });
    -  22
    -  23 describe('sheets', function() {
    -  24 let sheets:any;
    -  25
    -  26 beforeEach(function() { 
    -  27 sheets = file.getSheetNames(); 
    -  28 });
    -  29
    -  30 it('should have 2 sheets', function() {
    -  31 expect(sheets.length).toBe(2);
    -  32 });
    -  33
    -  34 it(`should have sheet "${SHEET}"`, function() {
    -  35 expect(sheets.indexOf(SHEET)).toBe(1);
    -  36 });
    -  37 });
    -  38
    -  39 describe('getCellValue', function() {
    -  40 it(`should have cell value`, function() {
    -  41 expect(file.getCellValue(SHEET, 'B', 5)).toBe('Ringo');
    -  42 });
    -  43 });
    -  44
    -  45 describe('header row', function() {
    -  46 it('should have a column name "Topic" on 4th position', function() {
    -  47 let columns = file.getTableColumns(SHEET, 'A', 1);
    -  48 expect(columns.names[2]).toBe('Topic');
    -  49 });
    -  50
    -  51 it('should accept string as row number', function() {
    -  52 let columns = file.getTableColumns(SHEET, 'A', "1");
    -  53 expect(columns.names[2]).toBe('Topic'); 
    -  54 });
    -  55 }); 
    -  56
    -  57 describe('getRowsForTable', function() {
    -  58 it('should fail for illegal collumns', function() {
    -  59 function noSheet() {
    -  60 file.getRowsForTable({});
    -  61 }
    -  62 expect(noSheet).toThrowError('illegal table parameter in getRowsForTable');
    -  63 });
    -  64
    -  65 it('should return maxRows', function() {
    -  66 let columns = file.getTableColumns(SHEET, 'A', 1);
    -  67 let rows = file.getRowsForTable(columns, 1);
    -  68 expect(rows.length).toBe(1);
    -  69 });
    -  70
    -  71 it('should return less than maxRows=10', function() {
    -  72 let columns = file.getTableColumns(SHEET, 'A', 1);
    -  73 let rows = file.getRowsForTable(columns, 10);
    -  74 expect(rows.length).toBe(4);
    -  75 });
    -  76 });
    -  77
    -  78 describe('table rows', function() {
    -  79 let columns:any;
    -  80 let rows:any;
    -  81
    -  82 beforeEach(function() { 
    -  83 columns = file.getTableColumns(SHEET, 'A', 1);
    -  84 rows = file.getRowsForTable(columns);
    -  85 });
    -  86
    -  87 it('should have 4 rows', function() {
    -  88 expect(rows.length).toBe(4);
    -  89 });
    -  90
    -  91 it('should have "Start" value in 4th row', function() {
    -  92 let col = columns.names.indexOf('Start');
    -  93 expect(col).toBe(3);
    -  94 expect(rows[3][col]).toBe('03/01/14');
    -  95 });
    -  96 });
    -  97
    -  98 describe('entire table', function() {
    -  99 it('should have 5 columns', function() {
    - 100 let {columns} = file.getTable(SHEET, 'A', 1);
    - 101 expect(columns.names.length).toBe(5);
    - 102 });
    - 103
    - 104 it('should have 4 rows', function() {
    - 105 let {table} = file.getTable(SHEET, 'A', 1);
    - 106 expect(table.length).toBe(4);
    - 107 });
    - 108 });
    - 109
    - 110 describe('nextExcelColIndex', function() {
    - 111 function nextIndex(startCol:string) { 
    - 112 const gen = file.nextExcelColIndex(startCol);
    - 113 gen.next(); // reproduces startCol;
    - 114 return gen.next().value;
    - 115 }
    - 116
    - 117 it("should produce column 'N' after column 'M'", function() {
    - 118 expect(nextIndex('M')).toBe('N');
    - 119 });
    - 120
    - 121 it("should produce column 'AA' after column 'Z'", function() {
    - 122 expect(nextIndex('Z')).toBe('AA');
    - 123 });
    - 124
    - 125 it("should produce column 'BA' after column 'AZ'", function() {
    - 126 expect(nextIndex('AZ')).toBe('BA');
    - 127 });
    - 128
    - 129 it("should produce column 'BN' after column 'BM'", function() {
    - 130 expect(nextIndex('BM')).toBe('BN');
    - 131 });
    - 132 });
    - 133 });
    - 134});
    - 135
    - - \ No newline at end of file diff --git a/docs/src/hsNode/fsUtil.html b/docs/src/hsNode/fsUtil.html deleted file mode 100644 index 5baf573..0000000 --- a/docs/src/hsNode/fsUtil.html +++ /dev/null @@ -1,307 +0,0 @@ - - -

    fsUtil.ts

    -
       1const fs  = require('fs');
    -   2const path = require('path');
    -   3
    -   4import { log } from './';
    -   5
    -   6/**
    -   7 * Convenience functions for file system access, wrapped in Promises.
    -   8 * - {@link hsNode.fsUtil#methods_realPath realPath}
    -   9 * - {@link hsNode.fsUtil#methods_pathExists pathExists}
    -  10 * - {@link hsNode.fsUtil#methods_isfile isFile}
    -  11 * - {@link hsNode.fsUtil#methods_isdirectory isDirectory}
    -  12 * - {@link hsNode.fsUtil#methods_readDir readDir}
    -  13 * - {@link hsNode.fsUtil#methods_readFile readFile}
    -  14 * - {@link hsNode.fsUtil#methods_readTextFile readTextFile}
    -  15 * - {@link hsNode.fsUtil#methods_readJsonFile readJsonFile}
    -  16 * - {@link hsNode.fsUtil#methods_writeFile writeFile}
    -  17 * - {@link hsNode.fsUtil#methods_writeTextFile writeTextFile}
    -  18 * - {@link hsNode.fsUtil#methods_writeJsonFile writeJsonFile}
    -  19 * - {@link hsNode.fsUtil#methods_appendFile appendFile}
    -  20 * - {@link hsNode.fsUtil#methods_remove remove}
    -  21 */

    -  22
    -  23 export interface Stats {
    -  24    path:       string;     // path to the file
    -  25    device:     any;        // ID of device containing file
    -  26    iNode:      number;     // Inode number 
    -  27    type:       number;     // File type and mode 
    -  28    numLinks:   number;     // Number of hard links 
    -  29    userID:     string;     // User ID of owner 
    -  30    groupID:    string;     // Group ID of owner 
    -  31    deviceID:   string;     // Device ID (if special file) 
    -  32    totalSize:  number;     // Total size, in bytes 
    -  33    blockSize:  number;     // Block size for filesystem I/O 
    -  34    numBlocks:  number;     // Number of 512B blocks allocated 
    -  35    accessTime:       any;  // Time of last access
    -  36    modifyTime:       any;  // Time of last modification
    -  37    statusChangeTime: any;  // Time of last status change     
    -  38 }
    -  39
    -  40//===============================================================================
    -  41//  Low level Promise wrappers
    -  42
    -  43function stat(thePath:string):Promise {
    -  44 return Promise.resolve(thePath)
    -  45 .then(realPath)
    -  46 .then(thePath => new Promise((resolve:(value:Stats)=>void, reject) => {
    -  47 fs.stat(thePath, (err:any, stats:Stats) => {
    -  48 if(err) { reject(err); } // reject is hard to test: realpath throws an error before stat can.
    -  49 else    { 
    -  50 stats.path = thePath;
    -  51 resolve(stats); 
    -  52 }
    -  53 });
    -  54 }));
    -  55}
    -  56
    -  57function lstat(thePath:string) {
    -  58 return Promise.resolve(thePath)
    -  59 .then(path.normalize)
    -  60 .then(thePath => new Promise((resolve, reject) => {
    -  61 log.debug('lstat for ' + thePath);
    -  62 fs.lstat(thePath, (err:any, stats:any) => {
    -  63 if(err) { reject(err); }
    -  64 else    { 
    -  65 stats.path = thePath;
    -  66 resolve(stats); 
    -  67 }
    -  68 });
    -  69 }));
    -  70}
    -  71
    -  72function error(err:any):any {
    -  73    const msg = `*** error in fsUtil: ${err}`;
    -  74    console.log(msg);
    -  75    console.log(err.trace);
    -  76    throw new Error(msg);
    -  77}
    -  78
    -  79//===============================================================================
    -  80//   Exported functions
    -  81
    -  82/**
    -  83 * determines the canonical path for `thePath`, resolving all symbolic links and '../'in the path.
    -  84 * @param thePath the path to check
    -  85 * @return promise to provide the real canonical system path.
    -  86 */

    -  87function realPath(thePath:string):Promise {
    -  88 return new Promise((resolve:(path:string)=>void, reject:(err:any)=>void) => {
    -  89 fs.realpath(thePath, (err:any, resolvedPath:string) => err? reject(err) : resolve(resolvedPath) );
    -  90    })
    -  91    .catch(error);
    -  92}
    -  93
    -  94/**
    -  95 * determines if `thePath` exists and promises to provide `true` or `false`.
    -  96 * @param {string} thePath the path to check
    -  97 * @return {Promise} promise to provide `true` or `false`
    -  98 */

    -  99function pathExists(thePath:string):Promise {
    - 100 return stat(thePath).then((stats:any) => stats.path).catch(() => false)
    - 101    .catch(error);
    - 102};
    - 103
    - 104/**
    - 105 * determines if `thePath` is a file and promises to provide `true` or `false`.
    - 106 * @param {string} thePath the path to check
    - 107 * @return {Promise} promise to provide `true` or `false`
    - 108 */

    - 109function isFile(thePath:string):Promise {
    - 110 return stat(thePath).then((stats:any) => stats.isFile()? stats.path : false).catch(() => false)
    - 111    .catch(error);
    - 112};
    - 113
    - 114/**
    - 115 * determines if `thePath` is a directory and promises to provide `true` or `false`.
    - 116 * @param {string} thePath the path to check
    - 117 * @return {Promise} promise to provide `true` or `false`
    - 118 */

    - 119function isDirectory(thePath:string):Promise {
    - 120 return stat(thePath).then((stats:any) => stats.isDirectory()? stats.path : false).catch(() => false)
    - 121    .catch(error);
    - 122};
    - 123
    - 124/**
    - 125 * determines if `thePath` is a directory and promises to provide `true` or `false`.
    - 126 * @param {string} thePath the path to check
    - 127 * @return {Promise} promise to provide `true` or `false`
    - 128 */

    - 129function isLink(thePath:string):Promise {
    - 130 return lstat(thePath).then((stats:any) => stats.isSymbolicLink()? stats.path : false).catch(() => false)
    - 131    .catch(error);
    - 132};
    - 133
    - 134/**
    - 135 * lists all files in a directory and promises to provide the list.
    - 136 * @param {string} thePath the path to check
    - 137 * @return {Promise} promise to provide a list of directory entries.
    - 138 */

    - 139function readDir(thePath:string):Promise {
    - 140 return Promise.resolve(thePath)
    - 141 .then(realPath)
    - 142 .then(thePath => new Promise((resolve:(files:any)=>void, reject:(err:any)=>void) => {
    - 143 fs.readdir(thePath, (err:any, files:any) =>  {
    - 144 if(err) { reject(err); }
    - 145 else { 
    - 146 files.path = thePath;
    - 147 resolve(files); 
    - 148 }
    - 149 });
    - 150 }))
    - 151    .catch(error);
    - 152}
    - 153
    - 154
    - 155/**
    - 156 * reads a file either as binary or text and promises to provide the content.
    - 157 * @param {string} thePath the path to read
    - 158 * @param {boolean=} [isText=true] `true`|`false` if file should be read as `utf8`|binary 
    - 159 * @return {Promise} promise to provide file content.
    - 160 */

    - 161function readFile(thePath:string, isText=true):Promise {
    - 162 return new Promise((resolve:(data:any)=>void, reject:(err:any)=>void) => {
    - 163 let encoding = isText? 'utf8' : undefined;
    - 164 fs.readFile(thePath, encoding, (err:any, data:any) => {
    - 165 if (err) { reject(err); }
    - 166 resolve(data);
    - 167 });
    - 168 })
    - 169    .catch(error);
    - 170};
    - 171
    - 172/**
    - 173 * reads a text file and promises to provide the content.
    - 174 * @param {string} thePath the path to read
    - 175 * @return {Promise} promise to provide file content.
    - 176 */

    - 177function readTextFile(thePath:string):Promise { 
    - 178 return readFile(thePath, true)
    - 179    .catch(error);
    - 180};
    - 181
    - 182/**
    - 183 * reads a text file and promises to provide the content.
    - 184 * @param {string} thePath the path to read
    - 185 * @return {Promise} promise to provide file content.
    - 186 */

    - 187function readJsonFile(thePath:string):Promise {
    - 188    return readFile(thePath, true)
    - 189 .then((data:any) => (typeof data === 'string')? JSON.parse(data) : data)
    - 190    .catch(error);
    - 191}
    - 192
    - 193/**
    - 194 * writes a file either as binary or text and promises no return.
    - 195 * @param {string} thePath the path to write to
    - 196 * @param {object} content the content to write
    - 197 * @param {boolean} isText `true`|`false` if file should be read as `utf8`|binary 
    - 198 * @return {Promise} promise to provide nothing.
    - 199 */

    - 200function writeFile(thePath:string, content:string, isText:boolean=true):Promise {
    - 201 return new Promise((resolve, reject) => {
    - 202 var encoding = isText? 'utf8' : undefined;
    - 203     fs.writeFile(thePath, content, encoding, (err:any) => err? reject(err) : resolve());
    - 204 })
    - 205    .catch(error);
    - 206};
    - 207
    - 208/**
    - 209 * writes content to a file either as a stream and promises no return.
    - 210 * @param {string} thePath the path to write to
    - 211 * @param {object} content the content to write
    - 212 * @return {Promise} promise to provide nothing.
    - 213 */

    - 214function writeStream(thePath:string, content:string):Promise {
    - 215 return new Promise((resolve, reject) => {
    - 216        let s = fs.createWriteStream(thePath, {flags:'w', mode:0o666});
    - 217        s.on('error', (src:any) => reject(src));
    - 218        s.write(content, 'binary', () => resolve());
    - 219        s.end();
    - 220 })
    - 221    .catch(error);
    - 222}
    - 223
    - 224/**
    - 225 * writes a text file and promises no return.
    - 226 * @param {string} thePath the path to write
    - 227 * @return {Promise} promise to provide nothing.
    - 228 */

    - 229function writeTextFile(thePath:string, content:string):Promise { 
    - 230 return writeFile(thePath, content, true)
    - 231    .catch(error);
    - 232};
    - 233
    - 234/**
    - 235 * writes a text file and promises no return.
    - 236 * @param {string} thePath the path to write
    - 237 * @param {object} obj the object to write
    - 238 * @return {Promise} promise to provide nothing.
    - 239 */

    - 240function writeJsonFile(thePath:string, obj:any):Promise {
    - 241    return Promise.resolve(obj)
    - 242 .then(JSON.stringify)
    - 243 .then(data => writeTextFile(thePath, data))
    - 244    .catch(error);
    - 245}
    - 246
    - 247/**
    - 248 * appends to a file either as binary or text and promises no return.
    - 249 * @param {string} thePath the path to write to
    - 250 * @param {object} content the content to write
    - 251 * @param {boolean} isText `true`|`false` if file should be read as `utf8`|binary 
    - 252 * @return {Promise} promise to provide nothing.
    - 253 */

    - 254function appendFile(thePath:string, content:string, isText:boolean=true):Promise {
    - 255 return new Promise((resolve, reject) => {
    - 256 var encoding = isText? 'utf8' : undefined;
    - 257     fs.appendFile(thePath, content, encoding, (err:any) => err? reject(err) : resolve());
    - 258 })
    - 259    .catch(error);
    - 260};
    - 261
    - 262/**
    - 263 * promises to delete a file or folder.
    - 264 * @param {string} thePath the path to write
    - 265 * @return {Promise} promise to provide nothing.
    - 266 */

    - 267function remove(thePath:string):Promise {
    - 268 return new Promise((resolve:()=>void, reject:(err:any)=>void) => {
    - 269        fs.unlink(thePath, (e:any) => (e? reject(e) : resolve()));
    - 270 })
    - 271    .catch(error);
    - 272}
    - 273
    - 274export const fsUtil = { 
    - 275    realPath:       realPath, 
    - 276    pathExists:     pathExists, 
    - 277    isFile:         isFile, 
    - 278    isDirectory:    isDirectory, 
    - 279    isLink:         isLink, 
    - 280    readDir:        readDir, 
    - 281    readFile:       readFile, 
    - 282    readTextFile:   readTextFile, 
    - 283    readJsonFile:   readJsonFile, 
    - 284    writeFile:      writeFile, 
    - 285    writeStream:    writeStream, 
    - 286    writeTextFile:  writeTextFile, 
    - 287    writeJsonFile:  writeJsonFile,
    - 288    appendFile:     appendFile, 
    - 289    remove:         remove 
    - 290};
    - - \ No newline at end of file diff --git a/docs/src/hsNode/fsUtil.spec.html b/docs/src/hsNode/fsUtil.spec.html deleted file mode 100644 index cab0147..0000000 --- a/docs/src/hsNode/fsUtil.spec.html +++ /dev/null @@ -1,571 +0,0 @@ - - -

    fsUtil.spec.ts

    -
       1import { fsUtil } from './';
    -   2
    -   3
    -   4
    -   5describe("hsFSutil", function() {
    -   6 let called:any;
    -   7    const dir = __dirname; // + '/testTmp/';
    -   8    const TEST_DIR = dir+'/../example/';
    -   9
    -  10    function getCalled(done:()=>void) {
    -  11        let result:string, error:string;
    -  12        let called = { 
    -  13            resolved: (v:string) => { result=v; done(); },
    -  14            rejected: (v:string) => { error =v; done(); },
    -  15            getResult: () => result,
    -  16            getError:  () => error
    -  17        };
    -  18        spyOn(called, 'resolved').and.callThrough(); 
    -  19        spyOn(called, 'rejected').and.callThrough(); 
    -  20        return called;
    -  21    }
    -  22
    -  23 describe('pathExists' , () => {
    -  24 describe(process.cwd() , () => {
    -  25 beforeEach(done => {
    -  26 called = getCalled(done);
    -  27 fsUtil.pathExists(process.cwd()).then(called.resolved).catch(called.rejected);
    -  28 });
    -  29
    -  30 it('should exist', function(done) {
    -  31 expect(called.resolved).toHaveBeenCalledWith(process.cwd());
    -  32 expect(called.rejected).not.toHaveBeenCalled();
    -  33 done();
    -  34 });
    -  35 });
    -  36
    -  37 describe('./' , () => { 
    -  38 beforeEach(done => {
    -  39 called = getCalled(done);
    -  40 fsUtil.pathExists('./').then(called.resolved).catch(called.rejected);
    -  41 });
    -  42
    -  43 it('should exist', function(done) {
    -  44 expect(called.resolved).toHaveBeenCalledWith(process.cwd());
    -  45 expect(called.rejected).not.toHaveBeenCalled();
    -  46 done();
    -  47 });
    -  48 });
    -  49
    -  50 describe('/does-not-exists/', () => {
    -  51 beforeEach(done => {
    -  52 called = getCalled(done);
    -  53 fsUtil.pathExists('/does-not-exists/').then(called.resolved).catch(called.rejected);
    -  54 });
    -  55
    -  56 it('should not exist', function(done) {
    -  57 expect(called.resolved).toHaveBeenCalledWith(false);
    -  58 expect(called.rejected).not.toHaveBeenCalled();
    -  59 done();
    -  60 });
    -  61 });
    -  62 });
    -  63
    -  64 describe('isFile' , () => {
    -  65 describe(dir, () => {
    -  66 beforeEach(done => {
    -  67 called = getCalled(done);
    -  68 fsUtil.isFile(dir).then(called.resolved).catch(called.rejected);
    -  69 });
    -  70
    -  71 it('should not be a file', function(done) {
    -  72 expect(called.resolved).toHaveBeenCalledWith(false);
    -  73 expect(called.rejected).not.toHaveBeenCalled();
    -  74 done();
    -  75 });
    -  76 });
    -  77
    -  78 describe('Gruntfile.js' , () => {
    -  79            let rp:string;
    -  80 beforeEach(done => {
    -  81                fsUtil.realPath(dir+'/../../Gruntfile.js')
    -  82                .then((path:string) => {
    -  83     called = getCalled(done);
    -  84                    rp = path;
    -  85     fsUtil.isFile(rp).then(called.resolved).catch(called.rejected);
    -  86                });
    -  87 });
    -  88
    -  89 it('should be a file', function(done) {
    -  90 expect(called.resolved).toHaveBeenCalledWith(rp);
    -  91 expect(called.rejected).not.toHaveBeenCalled();
    -  92 done();
    -  93 });
    -  94 });
    -  95
    -  96 describe('./Gruntfile.js' , () => { 
    -  97 beforeEach(done => {
    -  98 called = getCalled(done);
    -  99 fsUtil.isFile('./Gruntfile.js').then(called.resolved).catch(called.rejected);
    - 100 });
    - 101
    - 102 it('should be a file', function(done) {
    - 103 expect(called.resolved).toHaveBeenCalledWith(process.cwd()+'/Gruntfile.js');
    - 104 expect(called.rejected).not.toHaveBeenCalled();
    - 105 done();
    - 106 });
    - 107 });
    - 108
    - 109 describe('./Gruntfile.js2', () => {
    - 110 beforeEach(done => {
    - 111 called = getCalled(done);
    - 112 fsUtil.isFile('./Gruntfile.js2').then(called.resolved).catch(called.rejected);
    - 113 });
    - 114  
    - 115 it('should not be a file an not be rejected', function(done) {
    - 116 expect(called.resolved).toHaveBeenCalledWith(false);
    - 117 expect(called.rejected).not.toHaveBeenCalled();
    - 118 done();
    - 119 });
    - 120 });
    - 121 });
    - 122
    - 123 describe('isDirectory' , () => {
    - 124 describe(process.cwd(), () => {
    - 125 beforeEach(done => {
    - 126 called = getCalled(done);
    - 127 fsUtil.isDirectory(process.cwd()).then(called.resolved).catch(called.rejected);
    - 128 });
    - 129
    - 130 it('should be a directory', function(done) {
    - 131 expect(called.resolved).toHaveBeenCalledWith(process.cwd());
    - 132 expect(called.rejected).not.toHaveBeenCalled();
    - 133 done();
    - 134 });
    - 135 });
    - 136
    - 137 describe('./' , () => { 
    - 138 beforeEach(done => {
    - 139 called = getCalled(done);
    - 140 fsUtil.isDirectory('./').then(called.resolved).catch(called.rejected);
    - 141 });
    - 142
    - 143 it('should be a directory', function(done) {
    - 144 expect(called.resolved).toHaveBeenCalledWith(process.cwd());
    - 145 expect(called.rejected).not.toHaveBeenCalled();
    - 146 done();
    - 147 });
    - 148 });
    - 149
    - 150 describe('./Gruntfile.js', () => {
    - 151 beforeEach(done => {
    - 152 called = getCalled(done);
    - 153 fsUtil.isDirectory('./Gruntfile.js').then(called.resolved).catch(called.rejected);
    - 154 });
    - 155  
    - 156 it('valid file should not be a directory an not be rejected', function(done) {
    - 157 expect(called.resolved).toHaveBeenCalledWith(false);
    - 158 expect(called.rejected).not.toHaveBeenCalled();
    - 159 done();
    - 160 });
    - 161 });
    - 162
    - 163 describe('./Gruntfile.js2', () => {
    - 164 beforeEach(done => {
    - 165 called = getCalled(done);
    - 166 fsUtil.isDirectory('./Gruntfile.js2').then(called.resolved).catch(called.rejected);
    - 167 });
    - 168  
    - 169 it('invalid file should not be a directory an not be rejected', function(done) {
    - 170 expect(called.resolved).toHaveBeenCalledWith(false);
    - 171 expect(called.rejected).not.toHaveBeenCalled();
    - 172 done();
    - 173 });
    - 174 });
    - 175 });
    - 176
    - 177 describe('isLink' , () => {
    - 178 describe(__dirname , () => {
    - 179 beforeEach(done => {
    - 180 called = getCalled(done);
    - 181 fsUtil.isLink(__dirname).then(called.resolved).catch(called.rejected);
    - 182 });
    - 183
    - 184 it('should not be a link', function(done) {
    - 185 expect(called.resolved).toHaveBeenCalledWith(false);
    - 186 expect(called.rejected).not.toHaveBeenCalled(); 
    - 187 done();
    - 188 });
    - 189 });
    - 190
    - 191 describe(dir+'/../../node_Modules' , () => {
    - 192 beforeEach(done => {
    - 193 called = getCalled(done);
    - 194 fsUtil.isLink(dir+'/../../node_Modules').then(called.resolved).catch(called.rejected);
    - 195 });
    - 196
    - 197 it('should be a link', function(done) {
    - 198 expect(called.resolved).toHaveBeenCalled();
    - 199 expect(called.resolved).not.toHaveBeenCalledWith(false); // instead: real path
    - 200 expect(called.rejected).not.toHaveBeenCalled();
    - 201 done();
    - 202 });
    - 203 });
    - 204
    - 205 describe(__dirname+'/abc' , () => {
    - 206 beforeEach(done => {
    - 207 called = getCalled(done);
    - 208 fsUtil.isLink(__dirname+'/abc').then(called.resolved).catch(called.rejected);
    - 209 });
    - 210
    - 211 it('should reject for invalid names', function(done) {
    - 212 expect(called.resolved).toHaveBeenCalledWith(false);
    - 213 expect(called.rejected).not.toHaveBeenCalled();
    - 214 done();
    - 215 });
    - 216 });
    - 217
    - 218 });
    - 219
    - 220 describe('readDir' , () => {
    - 221 describe(__dirname , () => {
    - 222 beforeEach(done => {
    - 223 called = getCalled(done);
    - 224 fsUtil.readDir(__dirname).then(called.resolved).catch(called.rejected);
    - 225 });
    - 226
    - 227 it('should return list of spec files', function(done) {
    - 228 expect(called.resolved).toHaveBeenCalled();
    - 229 expect(called.rejected).not.toHaveBeenCalled();
    - 230 expect(called.getResult()).toBeDefined();
    - 231 expect(called.getResult().length).toBeGreaterThan(6);
    - 232 done();
    - 233 });
    - 234 });
    - 235
    - 236 describe(__dirname+'/abcde' , () => {
    - 237 beforeEach(done => {
    - 238 called = getCalled(done);
    - 239 fsUtil.readDir(__dirname+'/abcde').then(called.resolved).catch(called.rejected);
    - 240 });
    - 241
    - 242 it('should reject', function(done) {
    - 243 expect(called.resolved).not.toHaveBeenCalled();
    - 244 expect(called.rejected).toHaveBeenCalled();
    - 245 done();
    - 246 });
    - 247 });
    - 248 });
    - 249
    - 250 describe('readFile' , () => {
    - 251        const file1 = TEST_DIR+'test.xlsx';
    - 252        const file2 = TEST_DIR+'test.xlsx2';
    - 253 describe(file1 , () => {
    - 254 beforeEach(done => {
    - 255 called = getCalled(done);
    - 256 fsUtil.readFile(file1, false).then(called.resolved).catch(called.rejected);
    - 257 });
    - 258
    - 259 it('should read binary file', function(done) {
    - 260 expect(called.resolved).toHaveBeenCalled();
    - 261 expect(typeof called.getResult()).toBe('object');
    - 262 expect(called.rejected).not.toHaveBeenCalled();
    - 263 done();
    - 264 });
    - 265 });
    - 266
    - 267 describe(file2 , () => {
    - 268 beforeEach(done => {
    - 269 called = getCalled(done);
    - 270 fsUtil.readFile(file2, false).then(called.resolved).catch(called.rejected);
    - 271 });
    - 272
    - 273 it('should reject', function(done) {
    - 274 expect(called.resolved).not.toHaveBeenCalled();
    - 275 expect(called.rejected).toHaveBeenCalled();
    - 276 expect(called.getError()+'').toMatch(/Error: ENOENT: no such file or directory/);
    - 277 done();
    - 278 });
    - 279 });
    - 280
    - 281 });
    - 282
    - 283 describe('readTextFile' , () => {
    - 284 describe(__dirname+'/fsUtil.spec.js' , () => {
    - 285 beforeEach(done => {
    - 286 called = getCalled(done);
    - 287 fsUtil.readTextFile(__dirname+'/fsUtil.spec.js').then(called.resolved).catch(called.rejected);
    - 288 });
    - 289
    - 290 it('should read text file', function(done) {
    - 291 expect(called.resolved).toHaveBeenCalled();
    - 292 expect(typeof called.getResult()).toBe('string');
    - 293 expect(called.rejected).not.toHaveBeenCalled();
    - 294 done();
    - 295 });
    - 296 });
    - 297 });
    - 298
    - 299 describe('readJsonFile' , () => {
    - 300        const file = __dirname+'/../../package.json';
    - 301 describe(file , () => {
    - 302 beforeEach(done => {
    - 303 called = getCalled(done);
    - 304 fsUtil.readJsonFile(file).then(called.resolved).catch(called.rejected);
    - 305 });
    - 306
    - 307 it('should read text file', function(done) {
    - 308 expect(called.resolved).toHaveBeenCalled();
    - 309 expect(called.rejected).not.toHaveBeenCalled();
    - 310 expect(typeof called.getResult()).toBe('object');
    - 311 expect(called.getResult().name).toBe('hsNode');
    - 312 done();
    - 313 });
    - 314 });
    - 315 });
    - 316
    - 317 describe('writeFile' , () => {
    - 318 describe(dir+'binFile' , () => {
    - 319 beforeEach(done => {
    - 320 called = getCalled(done);
    - 321 fsUtil.writeFile(dir+'binFile', 'test2', false).then(called.resolved).catch(called.rejected);
    - 322 });
    - 323
    - 324 it('should resolve', function(done) {
    - 325 expect(called.resolved).toHaveBeenCalled();
    - 326 expect(called.rejected).not.toHaveBeenCalled();
    - 327 done();
    - 328 });
    - 329
    - 330 describe('check for bin file', function() {
    - 331 beforeEach(done => {
    - 332 called = getCalled(done);
    - 333 fsUtil.readFile(dir+'binFile', false).then(called.resolved).catch(called.rejected);
    - 334 });
    - 335
    - 336 it('should exist', function(done) {
    - 337 expect(called.resolved).toHaveBeenCalled();
    - 338 expect(called.rejected).not.toHaveBeenCalled();
    - 339 done();
    - 340 });
    - 341
    - 342 it('should contain payload', function(done) {
    - 343 expect(typeof called.getResult()).toBe('object');
    - 344 expect(Buffer.from('test2').equals(called.getResult())).toBe(true);
    - 345 done();
    - 346 });
    - 347 });
    - 348 });
    - 349
    - 350 describe(dir+'binFile2' , () => {
    - 351 beforeEach(done => {
    - 352 called = getCalled(done);
    - 353 fsUtil.readFile(dir+'binFile2', false).then(called.resolved).catch(called.rejected);
    - 354 });
    - 355
    - 356 it('should reject', function(done) {
    - 357 expect(called.resolved).not.toHaveBeenCalled();
    - 358 expect(called.rejected).toHaveBeenCalled();
    - 359 done();
    - 360 });
    - 361 });
    - 362 });
    - 363
    - 364
    - 365 describe('appendFile' , () => {
    - 366 describe(dir+'binFile' , () => {
    - 367 beforeEach(done => {
    - 368 called = getCalled(done);
    - 369 fsUtil.appendFile(dir+'binFile', 'test2', false).then(called.resolved).catch(called.rejected);
    - 370 });
    - 371
    - 372            afterAll(done => {
    - 373                fsUtil.remove(dir+'binFile');
    - 374                done();
    - 375            });
    - 376
    - 377 it('should resolve', function(done) {
    - 378 expect(called.resolved).toHaveBeenCalled();
    - 379 expect(called.rejected).not.toHaveBeenCalled();
    - 380 done();
    - 381 });
    - 382
    - 383 describe('check for bin file', function() {
    - 384 beforeEach(done => {
    - 385 called = getCalled(done);
    - 386 fsUtil.readFile(dir+'binFile', false).then(called.resolved).catch(called.rejected);
    - 387 });
    - 388
    - 389 it('should exist', function(done) {
    - 390 expect(called.resolved).toHaveBeenCalled();
    - 391 expect(called.rejected).not.toHaveBeenCalled();
    - 392 done();
    - 393 });
    - 394
    - 395 it('should contain payload', function(done) {
    - 396 expect(typeof called.getResult()).toBe('object');
    - 397 expect(called.getResult().toString()).toMatch('test2test2test2test2');
    - 398 done();
    - 399 });
    - 400 });
    - 401 });
    - 402
    - 403 describe(dir+'binFile2' , () => {
    - 404 beforeEach(done => {
    - 405 called = getCalled(done);
    - 406 fsUtil.readFile(dir+'binFile2', false).then(called.resolved).catch(called.rejected);
    - 407 });
    - 408
    - 409 it('should reject', function(done) {
    - 410 expect(called.resolved).not.toHaveBeenCalled();
    - 411 expect(called.rejected).toHaveBeenCalled();
    - 412 done();
    - 413 });
    - 414 });
    - 415 });
    - 416
    - 417 describe('writeTextFile' , () => {
    - 418 describe(dir+'txtFile' , () => {
    - 419 beforeEach(done => {
    - 420 called = getCalled(done);
    - 421 fsUtil.writeTextFile(dir+'txtFile', 'test2').then(called.resolved).catch(called.rejected);
    - 422 });
    - 423
    - 424 it('should resolve', function(done) {
    - 425 expect(called.resolved).toHaveBeenCalled();
    - 426 expect(called.rejected).not.toHaveBeenCalled();
    - 427 done();
    - 428 });
    - 429
    - 430 describe('check for text file', function() {
    - 431 beforeEach(done => {
    - 432 called = getCalled(done);
    - 433 fsUtil.readTextFile(dir+'txtFile').then(called.resolved).catch(called.rejected);
    - 434 });
    - 435
    - 436 it('should exist', function(done) {
    - 437 expect(called.resolved).toHaveBeenCalled();
    - 438 expect(called.rejected).not.toHaveBeenCalled();
    - 439 done();
    - 440 });
    - 441
    - 442 it('should contain payload', function(done) {
    - 443 expect(typeof called.getResult()).toBe('string');
    - 444 expect(called.getResult()).toBe('test2');
    - 445 done();
    - 446 });
    - 447 });
    - 448 });
    - 449 });
    - 450
    - 451 describe('writeJsonFile' , () => {
    - 452 describe(dir+'jsnFile' , () => {
    - 453 beforeEach(done => {
    - 454 called = getCalled(done);
    - 455 fsUtil.writeJsonFile(dir+'jsnFile', {"name":"test2"}).then(called.resolved).catch(called.rejected);
    - 456 });
    - 457
    - 458 it('should resolve', function(done) {
    - 459 expect(called.resolved).toHaveBeenCalled();
    - 460 expect(called.rejected).not.toHaveBeenCalled();
    - 461 done();
    - 462 });
    - 463
    - 464 describe('check for json file', function() {
    - 465 beforeEach(done => {
    - 466 called = getCalled(done);
    - 467 fsUtil.readJsonFile(dir+'jsnFile').then(called.resolved).catch(called.rejected);
    - 468 });
    - 469
    - 470 it('should exist', function(done) {
    - 471 expect(called.resolved).toHaveBeenCalled();
    - 472 expect(called.rejected).not.toHaveBeenCalled();
    - 473 done();
    - 474 });
    - 475
    - 476 it('should contain payload', function(done) {
    - 477 expect(typeof called.getResult()).toBe('object');
    - 478 expect(called.getResult().name).toBe('test2');
    - 479 done();
    - 480 });
    - 481 });
    - 482 });
    - 483
    - 484 describe(dir+'jsn2File' , () => {
    - 485 beforeEach(done => {
    - 486 called = getCalled(done);
    - 487 fsUtil.writeJsonFile(dir+'jsn2File', 'test2').then(called.resolved).catch(called.rejected);
    - 488 });
    - 489
    - 490 it('should resolve', function(done) {
    - 491 expect(called.resolved).toHaveBeenCalled();
    - 492 expect(called.rejected).not.toHaveBeenCalled();
    - 493 done();
    - 494 });
    - 495
    - 496 describe('check for json file', function() {
    - 497 beforeEach(done => {
    - 498 called = getCalled(done);
    - 499 fsUtil.readJsonFile(dir+'jsn2File').then(called.resolved).catch(called.rejected);
    - 500 });
    - 501
    - 502 it('should exist', function(done) {
    - 503 expect(called.resolved).toHaveBeenCalled();
    - 504 expect(called.rejected).not.toHaveBeenCalled();
    - 505 done();
    - 506 });
    - 507
    - 508 it('should contain payload', function(done) {
    - 509 expect(typeof called.getResult()).toBe('string');
    - 510 expect(called.getResult()).toBe('test2');
    - 511 done();
    - 512 });
    - 513 });
    - 514 });
    - 515 });
    - 516
    - 517    describe('delete' , () => {
    - 518 describe(dir+'jsnFile' , () => {
    - 519 beforeEach(done => {
    - 520 called = getCalled(done);
    - 521 fsUtil.writeJsonFile(dir+'jsnFile', {"name":"test2"}).then(called.resolved).catch(called.rejected);
    - 522 });
    - 523
    - 524 it('should have created jsnFile', function(done) {
    - 525 expect(called.resolved).toHaveBeenCalled();
    - 526 expect(called.rejected).not.toHaveBeenCalled();
    - 527 done();
    - 528 });
    - 529
    - 530            describe('check for deletion', function() {
    - 531                beforeEach(done => {
    - 532                    called = getCalled(done);
    - 533                    fsUtil.remove(dir+'jsnFile')
    - 534                        .then(called.resolved)
    - 535                        .catch(called.rejected);
    - 536                });
    - 537                
    - 538                it('should have deleted file', function(done) {
    - 539                    expect(called.resolved).toHaveBeenCalled();
    - 540                    expect(called.rejected).not.toHaveBeenCalled();
    - 541                    fsUtil.isFile(dir+'jsnFile')
    - 542                    .then(exists => {
    - 543                        expect(exists).toBe(false);
    - 544                        done();
    - 545                    }).catch(() => {
    - 546                        fail('error deleting file');
    - 547                    });
    - 548                });
    - 549 });
    - 550 });
    - 551    });
    - 552
    - 553});
    - 554
    - - \ No newline at end of file diff --git a/docs/src/hsNode/httpUtil.html b/docs/src/hsNode/httpUtil.html deleted file mode 100644 index 9402335..0000000 --- a/docs/src/hsNode/httpUtil.html +++ /dev/null @@ -1,75 +0,0 @@ - - -

    httpUtil.ts

    -
       1const http    = require('http');
    -   2
    -   3/**
    -   4 * @ngdoc object
    -   5 * @name hsNode.httpUtil
    -   6 * @description Convenience functions for http access, wrapped in Promises.
    -   7 * - {@link hsNode.httpUtil#methods_request request}
    -   8 */

    -   9
    -  10//===============================================================================
    -  11//  Low level Promise wrappers
    -  12 
    -  13/**
    -  14 * @ngdoc object
    -  15 * @name request
    -  16 * @methodOf hsNode.httpUtil
    -  17 * @description sends a http request and promises to return the result.
    -  18 * @param {object} options the options to pass along to the request
    -  19 * @param {object} postData optional data to post
    -  20 * @return {Promise} promise to provide the result of the request.
    -  21 */

    -  22export function request(options:any, postData?:any) {
    -  23    return new Promise((resolve:(out:string)=>void, reject:(e:any)=>void) => {
    -  24        let data = ''; 
    -  25        const req = http.request(options, (res:any) => {
    -  26            res.setEncoding('utf8');
    -  27            res.on('data', (chunk:string) => { data += chunk; });
    -  28            res.on('end', () => resolve(data));
    -  29        });
    -  30        req.on('error', (e:any) => reject(e));
    -  31
    -  32        // write data to request body
    -  33        if (postData !== undefined) { req.write(postData); }
    -  34        req.end();
    -  35    });
    -  36}
    -  37
    -  38/**
    -  39 * @ngdoc object
    -  40 * @name get
    -  41 * @methodOf hsNode.httpUtil
    -  42 * @description sends a http get request and promises to return the result.
    -  43 * @param {object} options the options to pass along to the get request
    -  44 * @return {Promise} promise to provide the result of the request.
    -  45 */

    -  46export function get(options:any) {
    -  47    return new Promise((resolve:(out:string)=>void, reject:(e:string)=>void) => {
    -  48        let data = ''; 
    -  49        const req = http.get(options, (res:any) => {
    -  50            res.setEncoding('utf8');
    -  51            res.on('data', (chunk:string) => { data += chunk; });
    -  52            res.on('end', () => resolve(data));
    -  53        });
    -  54
    -  55        req.on('error', (e:string) => reject(e));
    -  56    });
    -  57}
    -  58
    - - \ No newline at end of file diff --git a/docs/src/hsNode/index.html b/docs/src/hsNode/index.html deleted file mode 100644 index 698b3ed..0000000 --- a/docs/src/hsNode/index.html +++ /dev/null @@ -1,30 +0,0 @@ - - -

    index.ts

    -
       1export { default as log }   from "./log";
    -   2export { default as date }  from "./date";
    -   3
    -   4import * as hsNode          from "./node";
    -   5import * as hsExcel         from "./excel";
    -   6export { hsExcel };
    -   7export { hsNode };
    -   8
    -   9
    -  10export *    from "./fsUtil";
    -  11export *    from "./cpUtil";
    -  12
    -  13
    - - \ No newline at end of file diff --git a/docs/src/hsNode/log.html b/docs/src/hsNode/log.html deleted file mode 100644 index f74003b..0000000 --- a/docs/src/hsNode/log.html +++ /dev/null @@ -1,308 +0,0 @@ - - -

    log.ts

    -
       1/**
    -   2 * @ngdoc object
    -   3 * @name hsNode.log
    -   4 * @description Logging convenience functions.
    -   5 * ## Usage
    -   6 * 

    -   7 * import log from './log';
    -   8 * log.info('by the way:'); // -> 20160817 09:59:08.032 info by the way:
    -   9 * log.error('oh dear!');   // -> 20160817 09:59:08.045 error *** oh dear!
    -  10 * 

    -  11 * 
    -  12 * ### Using the format template:
    -  13 * 

    -  14 * log.format('%MMM %DD %hh%mm%ss');
    -  15 * log.info('by the way:');  // -> Aug 17 095908 info by the way:
    -  16 * log.error('oh dear!');    // -> Aug 17 095908 error *** oh dear!
    -  17 * 

    -  18 * 
    -  19 * ### With module prefix:
    -  20 * 

    -  21 * import log from './log';
    -  22 * log.prefix('Main');
    -  23 * log.format('%hh%mm%ss');
    -  24 * log.info('by the way:');  // -> 09:59:08.032 Main info by the way:
    -  25 * log.error('oh dear!');    // -> 09:59:08.045 Main error *** oh dear!
    -  26 * 

    -  27 * 
    -  28 * ### Using a log file
    -  29 * 

    -  30 * log.format('%MM%DD');
    -  31 * log.info('by the way:'); // -> 0817 info by the way:
    -  32 * log.logFile('l%YY%MM');  // -> 0817 info now logging to file l1608.txt
    -  33 * log.error('oh dear!');   // -> 0817 error *** oh dear!
    -  34 * 

    -  35 * 
    -  36 * ## Reporting Levels:
    -  37 * - [DEBUG](#debug)
    -  38 * - [INFO](#info)
    -  39 * - [WARN](#warn)
    -  40 * - [ERROR](#error)
    -  41 * 
    -  42 * ## Reporting methods
    -  43 * - {@link hsNode.log#methods_debug debug()}
    -  44 * - {@link hsNode.log#methods_info info()}
    -  45 * - {@link hsNode.log#methods_warn warn()}
    -  46 * - {@link hsNode.log#methods_error error()}
    -  47 * 
    -  48 * ## Configurations:
    -  49 * - {@link hsNode.log#methods_level level()}
    -  50 * - {@link hsNode.log#methods_format format()}
    -  51 * - {@link hsNode.log#methods_prefix prefix()}
    -  52 * - {@link hsNode.log#methods_logFile logFile()}
    -  53 */

    -  54
    -  55/** importing nodejs file system function; needed to create logfiles */
    -  56import { date, hsNode, fsUtil } from "./";
    -  57
    -  58/**
    -  59 * @ngdoc property
    -  60 * @propertyOf hsNode.log 
    -  61 * @name DEBUG
    -  62 * @description Debug reporting level with importance 0
    -  63 */

    -  64const DEBUG         = Symbol('DEBUG');
    -  65/**
    -  66 * @ngdoc property
    -  67 * @name INFO
    -  68 * @propertyOf hsNode.log 
    -  69 * @description Info reporting level with importance 1
    -  70 */

    -  71const INFO          = Symbol('INFO');
    -  72/**
    -  73 * @ngdoc property
    -  74 * @name WARN
    -  75 * @propertyOf hsNode.log 
    -  76 * @description Info reporting level with importance 2
    -  77 */

    -  78const WARN          = Symbol('WARN');
    -  79/**
    -  80 * @ngdoc property
    -  81 * @propertyOf hsNode.log 
    -  82 * @name ERROR
    -  83 * @description Warning reporting level with importance 3
    -  84 */

    -  85const ERROR         = Symbol('ERROR');
    -  86
    -  87/**
    -  88 * Type definition for level descriptors
    -  89 */

    -  90interface LevelDesc { importance:number; sym:symbol; desc:string; };
    -  91
    -  92/** map of valid reporting levels */
    -  93const gLevels = {
    -  94    [DEBUG]:    {importance: 0, sym: DEBUG, desc: 'DEBUG'},
    -  95    [INFO]:     {importance: 1, sym: INFO,  desc: 'INFO'},
    -  96    [WARN]:     {importance: 2, sym: WARN,  desc: 'WARN'},
    -  97    [ERROR]:    {importance: 3, sym: ERROR, desc: 'ERROR'}
    -  98};
    -  99
    - 100/** current reporting level, same across all modules */
    - 101var gLevel:LevelDesc = (gLevel===undefined)? gLevels[INFO] : gLevel; 
    - 102console.log('set log level to ' + gLevel.sym.toString());
    - 103
    - 104/** current date format string. See [date module]('_date_.html') */
    - 105let gDateFormat   = '%YYYY%MM%DD %hh:%mm:%ss.%jjj';
    - 106
    - 107/** name of the current log file, or undefined */
    - 108let gLogFile: string; // initially disabled
    - 109
    - 110
    - 111function log() {
    - 112 let gPrefix = '';
    - 113    let gColors = true;
    - 114
    - 115 /**
    - 116  * @ngdoc object
    - 117  * @name level
    - 118  * @methodOf hsNode.log 
    - 119  * @param {String=} newLevel the new reporting level to set. 
    - 120  * If omitted, the method returns the currently set reporting level. 
    - 121  * @description sets the reporting level according to `newLevel`. 
    - 122  * Valid values are {@link hsNode.log.DEBUG DEBUG}, {@link hsNode.log.INFO INFO}, {@link hsNode.log.WARN WARN}, or {@link hsNode.log.ERROR ERROR}.
    - 123  * Subsequent reporting calls
    - 124  * will be filtered such that only calls with an importance at least the same as 
    - 125  * `newLevel` will be written to the log.
    - 126  * @return {Symbol} the new reporting level (DEBUG, INFO, ERROR)
    - 127  */

    - 128 function level(newLevel?:symbol):symbol {
    - 129     if (newLevel) { 
    - 130         if (gLevels[newLevel]) { 
    - 131          let oldLevel = gLevel;
    - 132             gLevel = gLevels[newLevel];
    - 133             let msg = 'new log level \'' + gLevel.desc.toUpperCase() + '\' (was ' + oldLevel.desc.toUpperCase() + ')';
    - 134             out((gLevel.sym === oldLevel.sym)?DEBUG : INFO, msg);
    - 135         }
    - 136         else { out(ERROR, "unkown level " + newLevel.toString() + '; log level remains ' + gLevel.sym.toString()); }
    - 137     }
    - 138     return gLevel.sym;
    - 139 }
    - 140
    - 141 /**
    - 142  * @ngdoc object
    - 143  * @name debug
    - 144  * @methodOf hsNode.log 
    - 145  * @param {string} msg the message to report.
    - 146  * @description reports an debug message to the log. 
    - 147  * The message will actually be reported to the log only if the current 
    - 148  * reporting level is DEBUG or lower.
    - 149  */

    - 150 function debug(msg:string) { out(DEBUG, msg); }
    - 151
    - 152 /**
    - 153  * @ngdoc object
    - 154  * @name info
    - 155  * @methodOf hsNode.log 
    - 156  * @param {string} msg the message to report.
    - 157  * @description reports an informational message to the log. 
    - 158  * The message will actually be reported to the log only if the current 
    - 159  * reporting level is INFO or lower.
    - 160  */

    - 161 function info(msg:string)  { out(INFO, msg); }
    - 162
    - 163 /**
    - 164  * @ngdoc object
    - 165  * @name warn
    - 166  * @methodOf hsNode.log 
    - 167  * @param {string} msg the message to report.
    - 168  * @description reports an warning message to the log. 
    - 169  * The message will actually be reported to the log only if the current 
    - 170  * reporting level is WARN or lower.
    - 171  */

    - 172 function warn(msg:string) { out(WARN, msg); }
    - 173
    - 174 /**
    - 175  * @ngdoc object
    - 176  * @name error
    - 177  * @methodOf hsNode.log 
    - 178  * @param {string} msg the message to report.
    - 179  * @description reports an error message to the log. 
    - 180  * The message will always be reported to the log.
    - 181  */

    - 182 function error(msg:string) { out(ERROR, msg); }
    - 183
    - 184 /**
    - 185  * @ngdoc function
    - 186  * @name dateFormat
    - 187  * @methodOf hsNode.log 
    - 188  * @param {String=} fmtStr the format string to use. 
    - 189  * @return {String} the currently set format string
    - 190  * @description sets the format string to use for logging. If no parameter is specified,
    - 191  * the function returns the currently set format string. The preset is '%YYYY%MM%DD %hh:%mm:%ss.%jjj'
    - 192     * For supported formats see {@link date date}.
    - 193  */

    - 194 function dateFormat(fmtStr?:string):string { 
    - 195     if (fmtStr) { gDateFormat = fmtStr; }
    - 196     return gDateFormat;
    - 197 }
    - 198
    - 199 /**
    - 200  * @ngdoc function
    - 201  * @name prefix
    - 202  * @methodOf hsNode.log 
    - 203  * @param {String=} prf the prefix to prepend. 
    - 204  * @description defines a prefix to be printed for each call to a log function. 
    - 205  * The return object contains all functions defined for export. 
    - 206  */

    - 207 function prefix(prf=''):void {
    - 208        gPrefix = prf? prf + ' ' : '';
    - 209 }
    - 210
    - 211 /**
    - 212  * @ngdoc function
    - 213  * @name logFile
    - 214  * @methodOf hsNode.log 
    - 215  * @param {String} [fileNameTemplate='log-%YYYY-%MM-%DD.txt'] a template to use for log file names. 
    - 216  * To disable logging, use file=''.
    - 217  * @description sets a new logfile name template. Logfiles are created using this template 
    - 218  * at the time of each log entry call. If the file exists, the log entry will be appended.
    - 219  * @return {Promise} promise to return the current logfile name template
    - 220  */

    - 221 function logFile(file='log-%YYYY-%MM-%DD.txt'):Promise {
    - 222        return Promise.resolve(file)
    - 223            .then(file => {
    - 224                if (file !== gLogFile) {
    - 225                    gLogFile = (file==='')? undefined : file;
    - 226                }
    - 227                if (!gLogFile) { info("disabling logfile"); return gLogFile; }
    - 228                if (gLogFile.indexOf('/')>=0) { 
    - 229                    const dir = gLogFile.substring(0, gLogFile.lastIndexOf('/'));
    - 230                    return fsUtil.pathExists(dir).then(exists => {
    - 231                        if (!exists) { 
    - 232                            gLogFile = undefined; 
    - 233                            warn(`path ${dir} doesn't exists; logfile disabled`); 
    - 234                        }
    - 235                        else { info(gLogFile? "now logging to file " + date(gLogFile) : "disabling logfile"); }
    - 236                        return gLogFile;
    - 237                    });
    - 238                }
    - 239                info("now logging to file " + date(gLogFile));
    - 240                return gLogFile;
    - 241            });
    - 242 }
    - 243
    - 244 function out(sym:symbol, msg:any) {
    - 245        const color = { ERROR: '\x1b[31m\x1b[1m', WARN: '\x1b[33m', DEBUG: '\x1b[36m', INFO: '\x1b[32m' };
    - 246 let desc = gLevels[sym];
    - 247     if (desc.importance >= gLevel.importance) {
    - 248         const dateStr = date(gDateFormat);
    - 249         let line = (typeof msg === 'string')? msg : hsNode.inspect(msg, null, gColors);
    - 250         line = gColors? ((color[sym]||"") + dateStr + ' ' + gPrefix + desc.desc + '\x1b[0m ' + line) :
    - 251                            (dateStr + ' ' + gPrefix + desc.desc + ' ' + line);
    - 252         console.log(line);
    - 253         if (msg.stack) { console.log(msg.stack); }
    - 254         if (gLogFile) {
    - 255          const filename = date(gLogFile);
    - 256          fsUtil.appendFile(filename, line+'\n').catch(e => { 
    - 257                    console.log(`error appending to file ${gLogFile}: ${e}`); 
    - 258                    throw new Error(e); });
    - 259         }
    - 260     }
    - 261 }
    - 262
    - 263    function defaultConfig(cfg:{colors?:boolean, logFile?:string, dateFormat?:string, level?:symbol }) {
    - 264        let colors = true;
    - 265        if (cfg.colors!==undefined)     { gColors = colors = cfg.colors; }     // true / false
    - 266        if (cfg.logFile!==undefined)    { logFile(cfg.logFile||undefined); }   // {logFile:null} => logFile(undefined)
    - 267        if (cfg.dateFormat!==undefined) { dateFormat(cfg.dateFormat); }        // e.g. '%YYYY%MM%DD %hh:%mm:%ss.%jjj'
    - 268        if (cfg.level!==undefined)      { level(cfg.level); }                  // e.g. INFO
    - 269     }
    - 270
    - 271 return {
    - 272 DEBUG:     DEBUG,
    - 273 INFO:     INFO,
    - 274 WARN:     WARN,
    - 275 ERROR:     ERROR,
    - 276 level:     level,
    - 277 debug:     debug,
    - 278 info:      info,
    - 279 warn:     warn,
    - 280 error:     error,
    - 281 dateFormat: dateFormat,
    - 282 prefix:     prefix,
    - 283 logFile:    logFile,
    - 284        config:     defaultConfig
    - 285 };
    - 286}
    - 287    
    - 288export default log();
    - 289
    - 290
    - 291
    - - \ No newline at end of file diff --git a/docs/src/hsNode/log.spec.html b/docs/src/hsNode/log.spec.html deleted file mode 100644 index 885d858..0000000 --- a/docs/src/hsNode/log.spec.html +++ /dev/null @@ -1,149 +0,0 @@ - - -

    log.spec.ts

    -
       1import { fsUtil, log, date }   from './';
    -   2
    -   3describe("log", () => {
    -   4    describe("message", () => {
    -   5        let gLog: any;
    -   6        let gMsg: string;
    -   7        
    -   8        function myLog(msg:string) {
    -   9            gMsg = msg;
    -  10    // gLog('received: '+ msg + '<<');
    -  11        }
    -  12        
    -  13        // avoid logging of level change
    -  14        function setLevel(level:symbol) {
    -  15            log.level(level);
    -  16            gMsg = undefined;
    -  17        }
    -  18
    -  19        beforeEach(function() {
    -  20            gLog = console.log;
    -  21            console.log = myLog;
    -  22            log.level(log.INFO);
    -  23            gMsg = undefined;
    -  24        });
    -  25        
    -  26        afterEach(function() {
    -  27            console.log = gLog;
    -  28        });
    -  29        
    -  30        describe('reporting functions', function() {
    -  31            it('should print info', function() {
    -  32                log.info("yes");
    -  33                expect(log.level()).toBe(log.INFO);
    -  34                expect(gMsg).toMatch(/INFO.*yes/);  
    -  35            });
    -  36            
    -  37            it('should print warning', function() {
    -  38                log.warn("alert");
    -  39                expect(log.level()).toBe(log.INFO);
    -  40                expect(gMsg).toMatch(/WARN.*alert/);  
    -  41            });
    -  42            
    -  43            it('should not print debug at INFO level', function() {
    -  44                setLevel(log.INFO);
    -  45                log.debug('yes');
    -  46                expect(gMsg).toBeUndefined();
    -  47            });
    -  48            
    -  49            it('should set DEBUG level', function() {
    -  50                expect(log.level()).toBe(log.INFO);
    -  51                log.level(log.DEBUG);
    -  52                expect(log.level()).toBe(log.DEBUG);
    -  53                expect(gMsg).toMatch(/new log level 'DEBUG' \(was INFO\)/);
    -  54            });
    -  55            
    -  56            it('should print info at DEBUG level', function() {
    -  57                setLevel(log.DEBUG);
    -  58                log.info('yes');
    -  59                expect(log.level()).toBe(log.DEBUG);
    -  60                expect(gMsg).toMatch(/INFO.*yes/);  
    -  61            });
    -  62            
    -  63            it('should print debug at DEBUG level', function() {
    -  64                log.level(log.DEBUG);
    -  65                expect(log.level()).toBe(log.DEBUG);
    -  66                expect(gMsg).toMatch(/new log level 'DEBUG' \(was INFO\)/);
    -  67                log.debug('yes');
    -  68                expect(gMsg).toMatch(/DEBUG.*yes/);  
    -  69            });
    -  70            
    -  71            it('should print error for invalid level', function() {
    -  72                log.level(Symbol('BOGUS'));
    -  73                expect(gMsg).toMatch(/ unkown level Symbol\(BOGUS\); log level remains Symbol\(INFO\)/);
    -  74                expect(log.level()).toBe(log.INFO);
    -  75            });
    -  76            
    -  77            it('should print error', function() {
    -  78                log.error('yes');
    -  79                expect(gMsg).toMatch(/ERROR.*yes/);
    -  80            });
    -  81        });
    -  82        
    -  83        describe('formatting', function() {
    -  84            it('should print prefix "test"', function() {
    -  85                log.prefix('test');
    -  86                log.info('yes');
    -  87                expect(gMsg).toMatch(/test INFO.*yes/);
    -  88            });
    -  89            
    -  90            it('should print date', function() {
    -  91                let date = new Date();
    -  92                log.config({dateFormat:'%M/%DD/%YY'});
    -  93                log.info('yes');
    -  94                expect(gMsg).toMatch((date.getFullYear()%100) + ' test INFO' );
    -  95                expect(gMsg).toMatch(/test INFO.*yes/);
    -  96            });
    -  97            
    -  98            it('should return dateFormat string', function() {
    -  99                expect(log.dateFormat()).toBe('%M/%DD/%YY');
    - 100            });
    - 101        });                    
    - 102
    - 103        describe('log file', function() {
    - 104            it('should be created next to Gruntfile for default path', done => {
    - 105                log.logFile().then(file => {
    - 106                    expect(file).toMatch(/log-%YYYY-%MM-%DD.txt/);
    - 107                    expect(gMsg).toMatch(/test INFO.*now logging to file/);
    - 108                    if (file) { fsUtil.remove(date(file)).catch(console.log); }
    - 109                    done();
    - 110                });
    - 111            });
    - 112            
    - 113            it('should be stopped for empty path', done => {
    - 114                log.logFile('').then(file => {
    - 115                    expect(file).not.toBeDefined();
    - 116                    expect(gMsg).toMatch(/test INFO.*disabling logfile/);
    - 117                    done();
    - 118                });
    - 119            });
    - 120            
    - 121            it('should be stopped for missing paths', done => {
    - 122                log.logFile('/missing/log.txt').then(file => {
    - 123                    expect(file).not.toBeDefined();
    - 124                    expect(gMsg).toMatch(/test WARN.*path .missing doesn't exists; logfile disabled/);
    - 125                    done();
    - 126                })
    - 127                .catch(() => {});
    - 128            });
    - 129        });
    - 130    });
    - 131});
    - 132
    - - \ No newline at end of file diff --git a/docs/src/hsNode/node.html b/docs/src/hsNode/node.html deleted file mode 100644 index 753340e..0000000 --- a/docs/src/hsNode/node.html +++ /dev/null @@ -1,72 +0,0 @@ - - -

    node.ts

    -
       1/**
    -   2 * @ngdoc overview
    -   3 * @name hsNode
    -   4 * @description 
    -   5 * Utility Modules for use with Node.js
    -   6 * ======================================
    -   7 * Provides
    -   8 * - {@link hsNode.log log}: logging support 
    -   9 * - {@link hsNode.date date}: sprintf-style date formatting 
    -  10 * - {@link hsNode.excel excel}: reading tables from Excel files 
    -  11 * - {@link hsNode.hsLibs hsLibs}: NodeJS module wrapper for hs and hsData libraries 
    -  12 * 
    -  13 * # Test Status: NodeJS
    -  14 *  -  15 *  style="border:none; "
    -  16 *  width="130%" height="500px">
    -  17 *  
    -  18 */

    -  19
    -  20const util  = require('util');
    -  21
    -  22/**
    -  23 * @ngdoc function
    -  24 * @name inspect
    -  25 * @methodOf hsNode.hsLibs
    -  26 * @description inspects the provided obj using the node utilities inspect function.
    -  27 * @param {obejct} obj the object to inspect
    -  28 * @param {number} depth the depth-level to report on, or inifinite depth if omitted
    -  29 * @param {boolean} color the depth-level to report on, or inifinite depth if omitted
    -  30 * @return {string} a color-formatted string representing `obj`
    -  31 */

    -  32export function inspect(obj:any, depth:number=null, colors=true) {
    -  33    return util.inspect(obj, {colors:colors, depth:depth});
    -  34}
    -  35
    -  36/**
    -  37 * @ngdoc function
    -  38 * @name timeout
    -  39 * @methodOf hsNode.hsLibs
    -  40 * @description timeout promise for use in Promise.race().
    -  41 * @param {number} ms the milliseconds to wait before rejecting
    -  42 * @return {Promise} a Promise that rejects after `ms` 
    -  43 */

    -  44export function timeout(ms:number) { return new Promise((resolve, reject) => { setTimeout(reject, ms); }); }
    -  45
    -  46/**
    -  47 * @ngdoc function
    -  48 * @name delay
    -  49 * @methodOf hsNode.hsLibs
    -  50 * @description delay promise for use in delay(ms).then(doSomething).
    -  51 * @param number ms the milliseconds to wait before resolving
    -  52 * @return a Promise that resolves after `ms` 
    -  53 */

    -  54export function delay(ms:number)   { return new Promise(resolve => { setTimeout(resolve, ms); }); }
    -  55
    - - \ No newline at end of file diff --git a/docs/src/hsNode/node.spec.html b/docs/src/hsNode/node.spec.html deleted file mode 100644 index faf57f3..0000000 --- a/docs/src/hsNode/node.spec.html +++ /dev/null @@ -1,75 +0,0 @@ - - -

    node.spec.ts

    -
       1import { hsNode } from './';
    -   2
    -   3describe("node", () => {
    -   4    describe("inspect", () => {
    -   5        it('should decompose {a:"yes", b:[1,2,3]}', () => {
    -   6            expect(hsNode.inspect({a:"yes", b:[1,2,3]}, null, false)).toEqual("{ a: 'yes', b: [ 1, 2, 3 ] }");
    -   7        });
    -   8        it('should report in color', () => {
    -   9            expect(hsNode.inspect({a:"yes", b:[1,2,3]})).not.toEqual(jasmine.stringMatching("{ a: 'yes', b: [ 1, 2, 3 ] }"));
    -  10            expect(hsNode.inspect({a:"yes", b:[1,2,3]})).toEqual(jasmine.stringMatching("'yes'"));
    -  11            expect(hsNode.inspect({a:"yes", b:[1,2,3]})).toEqual(jasmine.stringMatching("[ 1, 2, 3 ]"));
    -  12        });
    -  13        it('should report first level only', () => {
    -  14            expect(hsNode.inspect({a:"yes", b:[1,2,3]}, null, false)).toEqual("{ a: 'yes', b: [ 1, 2, 3 ] }");
    -  15            expect(hsNode.inspect({a:"yes", b:[1,2,3]}, 0, false)).toEqual("{ a: 'yes', b: [Array] }");
    -  16            expect(hsNode.inspect({a:"yes", b:[1,2,3]}, 1, false)).toEqual("{ a: 'yes', b: [ 1, 2, 3 ] }");
    -  17        });
    -  18    });
    -  19
    -  20    describe("timeout", () => {
    -  21        let reject: () => void; 
    -  22        let resolve:() => void;
    -  23        beforeEach(done => { 
    -  24            resolve = jasmine.createSpy("resolve");
    -  25            reject = jasmine.createSpy("reject");
    -  26            hsNode.timeout(100)
    -  27                .then(resolve)
    -  28                .catch(reject);
    -  29            setTimeout(done, 101);
    -  30        });
    -  31        
    -  32        it('should fail after 100ms', done => {
    -  33            expect(resolve).not.toHaveBeenCalled();
    -  34            expect(reject).toHaveBeenCalled();
    -  35            done();
    -  36        });
    -  37    });
    -  38
    -  39    describe("delay", () => {
    -  40        let reject: () => void; 
    -  41        let resolve:() => void;
    -  42        beforeEach(done => { 
    -  43            resolve = jasmine.createSpy("resolve");
    -  44            reject = jasmine.createSpy("reject");
    -  45            hsNode.delay(100)
    -  46                .then(resolve)
    -  47                .catch(reject);
    -  48            setTimeout(done, 101);
    -  49        });
    -  50        
    -  51        it('should resolve after 100ms', done => {
    -  52            expect(resolve).toHaveBeenCalled();
    -  53            expect(reject).not.toHaveBeenCalled();
    -  54            done();
    -  55        });
    -  56    });
    -  57});
    -  58
    - - \ No newline at end of file diff --git a/docs/src/hsStock/Home.html b/docs/src/hsStock/Home.html deleted file mode 100644 index a8b8563..0000000 --- a/docs/src/hsStock/Home.html +++ /dev/null @@ -1,65 +0,0 @@ - - -

    Home.ts

    -
       1import { m }            from 'hslayout';
    -   2import { Layout }       from 'hslayout';
    -   3import { Menu }         from 'hswidget';
    -   4import { SelectorDesc } from 'hswidget';
    -   5import { Vnode}         from 'hslayout';
    -   6import { ViewPane }      from './view/ViewPane';
    -   7import { TradePane }     from './view/TradePane';
    -   8import { ImportPane }    from './view/ImportPane';
    -   9
    -  10const TitleHeight        = '30px'; 
    -  11
    -  12const modes = [
    -  13    {name: 'View',   css: '.hs-selectable-view'},
    -  14    {name: 'Trade',  css: '.hs-selectable-trade'},
    -  15    {name: 'Import', css: '.hs-selectable-import'}
    -  16];
    -  17
    -  18export const Home = {
    -  19    view: () =>  m('', [Site(), SiteFooter()])
    -  20};
    -  21
    -  22const Site = () => {
    -  23    let siteContent;
    -  24    switch(m.route.param('mode')) {
    -  25        case modes[2].name:  siteContent = ImportPane; break;
    -  26        case modes[1].name:   siteContent = TradePane; break;
    -  27        case modes[0].name:
    -  28        default:        siteContent = ViewPane; break;
    -  29    }
    -  30    return m(Layout, {rows: [TitleHeight, "fill"], css: '.hs-site', content: [
    -  31        m(SiteMenu, {css: 'hs-site-menu'}),
    -  32        m(siteContent),
    -  33    ]});
    -  34};
    -  35
    -  36const SiteMenu = { 
    -  37    view: (node: Vnode):Vnode => {
    -  38        return m(Menu, {desc: 
    -  39            items: modes.map((c:any) => c.name),
    -  40            itemCss: modes.map((c:any) => c.css),
    -  41            selectedItem: modes.find((md:any) => md.name === m.route.param('mode')).name,
    -  42            changed: (item:string) => m.route.set('/site/:mode/:symbol', {mode:item, symbol:0}) 
    -  43        }});
    -  44    }
    -  45};
    -  46
    -  47const SiteFooter = () => m('.hs-site-footer', '(c) Helpful Scripts');
    -  48
    - - \ No newline at end of file diff --git a/docs/src/hsStock/Router.html b/docs/src/hsStock/Router.html deleted file mode 100644 index 988112b..0000000 --- a/docs/src/hsStock/Router.html +++ /dev/null @@ -1,82 +0,0 @@ - - -

    Router.ts

    -
       1
    -   2import { m }        from 'hslayout';
    -   3import { Home }     from './Home';
    -   4import { Button }   from 'hswidget';
    -   5
    -   6//const SAVE_URL      = '/cgi/save.js';
    -   7//const REGISTER_URL      = '/cgi/register.js';
    -   8
    -   9m.route.prefix("?");
    -  10
    -  11let authMode   = 'View';
    -  12let authSymbol = 'GOOG';
    -  13
    -  14const Auth = {
    -  15    username: "",
    -  16    password: "",
    -  17    
    -  18    setUsername: (value:string) => Auth.username = value,
    -  19    setPassword: (value:string) => Auth.password = value,
    -  20    login: function() {
    -  21        return m.request({
    -  22            url: `/stocks/private/test.json`,  
    -  23            user: Auth.username,
    -  24            password: Auth.password
    -  25        }).then(() => {
    -  26            console.log(`logged in as ${Auth.username}`);
    -  27            localStorage.setItem("auth-token", Auth.username);
    -  28            m.route.set(`/site/${authMode}/${authSymbol}`);
    -  29        }).catch((err:any) => {
    -  30            if (err.status === 401) {
    -  31                console.log('Authorization Error (401)');
    -  32            } else {
    -  33                console.log(err);
    -  34            }
    -  35        });
    -  36    }
    -  37};
    -  38
    -  39const Login = {
    -  40    view: function() {
    -  41        return m(".hs-form", [
    -  42            m("input[type=text][placeholder='Name']",         {oninput: m.withAttr("value", Auth.setUsername), value: Auth.username}),
    -  43            m("input[type=password][placeholder='Password']", {oninput: m.withAttr("value", Auth.setPassword), value: Auth.password}),
    -  44            m(Button, {name:'Login', onclick:Auth.login})
    -  45        ]);
    -  46    }
    -  47};
    -  48
    -  49
    -  50m.route(document.body, "/site/View", {
    -  51    "/site/:mode":           Home,
    -  52    "/site/:mode/:symbol":   Home,
    -  53    "/login": Login
    -  54});
    -  55
    -  56export function authenticated():boolean {
    -  57    if (!localStorage.getItem("auth-token")) { 
    -  58        authMode   = m.route.param('mode');
    -  59        authSymbol = m.route.param('symbol');
    -  60        m.route.set("/login"); 
    -  61        return false;
    -  62    } else {
    -  63        return true;
    -  64    }
    -  65}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/Site.html b/docs/src/hsStock/Site.html deleted file mode 100644 index 641aece..0000000 --- a/docs/src/hsStock/Site.html +++ /dev/null @@ -1,70 +0,0 @@ - - -

    Site.ts

    -
       1/**
    -   2 * Site documentation
    -   3 */

    -   4
    -   5/** */
    -   6import * as hslayout  from 'hslayout';
    -   7
    -   8const TitleHeight   = '30px'; 
    -   9const FooterHeight  = '10px';  
    -  10
    -  11const myConfig = {
    -  12    Container: { // whole page
    -  13        rows:  [TitleHeight, "fill", FooterHeight],
    -  14        css: '.hs-site',
    -  15/*        
    -  16        content: [{
    -  17            Container: {
    -  18                columns: ['50%'],
    -  19                css: '.hs-site',
    -  20                content: 'Header2'
    -  21        }},{
    -  22            Container: {
    -  23                columns: ['50%'],
    -  24                css: '.hs-site',
    -  25                content: 'Main'
    -  26        }},{
    -  27            Container: {
    -  28                columns: ['50%'],
    -  29                css: '.hs-site',
    -  30                content: 'Footer'
    -  31        }}
    -  32        ] 
    -  33*/
                
    -  34        content: ['Header', 'Main Part', 'Footer']
    -  35    },
    -  36    route: {
    -  37        default: '/api',
    -  38        paths: [
    -  39            '/api',             // defines `http://localhost/#!/api/
    -  40            '/api/:lib',        // defines `http://localhost/#!/api/:hsLib
    -  41            '/api/:lib/:field'  // defines `http://localhost/#!/api/:hsLib/:id        
    -  42        ]
    -  43    }
    -  44}; 
    -  45
    -  46
    -  47export function init() {
    -  48    new hslayout.HsConfig([hslayout]).attachNodeTree(myConfig, document.body);
    -  49}
    -  50
    -  51
    -  52
    -  53
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/Assets.html b/docs/src/hsStock/controller/Assets.html deleted file mode 100644 index a8ad037..0000000 --- a/docs/src/hsStock/controller/Assets.html +++ /dev/null @@ -1,78 +0,0 @@ - - -

    controller/Assets.ts

    -
       1import { m } from 'hslayout';
    -   2
    -   3const assetFile = 'private/transactions.json';
    -   4
    -   5const recode = {
    -   6    CASH: '_cash'
    -   7};
    -   8
    -   9export interface Transaction {
    -  10    /** the date of trade */
    -  11    Date: Date;
    -  12    /** the equity symbol being traded */
    -  13    symbol: string;
    -  14    /** the number of shares being bought (positive) or sold (negative) */
    -  15    change: number;
    -  16    /** the total number of shares after the transaction */
    -  17    total: number;
    -  18    price?: number;
    -  19    appliedSplits?: {[splitDateMS:number]: number};
    -  20}
    -  21
    -  22export interface TransactionList {
    -  23    [sym:string]: {
    -  24        /** most recent trade date */
    -  25        latestDate: Date;
    -  26        /** total shares after most recent trade */
    -  27        latestShares: number;
    -  28        trades: Transaction[];
    -  29    };
    -  30}
    -  31
    -  32function fileToList(data:any):TransactionList {
    -  33    const list: TransactionList = {};
    -  34    Object.keys(data).forEach((sym:string) => {
    -  35        sym = recode[sym] || sym;
    -  36        data[sym]
    -  37        .map((entry:any) => { 
    -  38            entry.Date = new Date(entry.date); 
    -  39            delete entry.date;
    -  40            return entry; 
    -  41        })
    -  42        .sort((a:any, b:any)=> a.Date < b.Date);
    -  43        const latestTrade = data[sym][data[sym].length-1];
    -  44        list[sym] = {
    -  45            latestDate:latestTrade.Date,
    -  46            latestShares: latestTrade.total,
    -  47            trades:[]
    -  48        };
    -  49        data[sym].forEach((trade:any) => {
    -  50            list[sym].trades.push(trade);
    -  51            if (typeof trade.Date === 'string') { trade.Date = new Date(trade.Date); }
    -  52        });
    -  53    });
    -  54    return list;
    -  55}
    -  56
    -  57export function readAssets(): Promise {
    -  58    return m.request({url: assetFile})
    -  59    .then(fileToList)
    -  60    .catch(console.log);
    -  61}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/Equities.html b/docs/src/hsStock/controller/Equities.html deleted file mode 100644 index 429c32f..0000000 --- a/docs/src/hsStock/controller/Equities.html +++ /dev/null @@ -1,195 +0,0 @@ - - -

    controller/Equities.ts

    -
       1import { EquityList }       from './EquityList'; 
    -   2import { EquityLoader }     from './EquityLoader'; 
    -   3import { Transaction }      from './Assets';
    -   4import { DataSet }          from 'hsdata';
    -   5import { VenueIDs, 
    -   6         VenueSummary }     from './Venue';
    -   7
    -   8export interface Category {
    -   9    cat:      string;         // the category name
    -  10    equities: EquityItem[];   // array of equities in this category
    -  11}
    -  12
    -  13export interface ItemStats {
    -  14    /** most recent trade date */
    -  15    latestDate?:        Date;
    -  16    /** most recent trade price */
    -  17    latestPrice? :      number;
    -  18
    -  19    /* last close price */
    -  20    closePrice?:        number;
    -  21    /** last close date */
    -  22    closeDate?:         Date;
    -  23    /** last close volume */
    -  24    closeVolume?:       number;
    -  25
    -  26    /** since previous close */
    -  27    change?:            number;
    -  28    /** price-to-earnings ratio */
    -  29    peRatio?:           number;
    -  30    /** 52 week high */
    -  31    week52high?:        number;
    -  32    /** 52 week low */
    -  33    week52low?:         number;
    -  34    /** market capitalziation */
    -  35    marketCap?:         number;
    -  36    /** total cash (Trailing twelve months) */
    -  37    cash?:              number;
    -  38    /** total revenue (Trailing twelve months) */
    -  39    revenue?:           number;
    -  40    /** total earnings (Trailing twelve months) */
    -  41    EBITDA?:            number;
    -  42    /** latest Earnings per Share */
    -  43    latestEPS?:         number;
    -  44    /** date of latest Earnings per Share */
    -  45    latestEPSDate?:     Date;
    -  46    /** dividend rate */
    -  47    dividendRate?:      number;
    -  48    /** dividend rate */
    -  49    dividendYield?:     number; 
    -  50    /** date of dividend */
    -  51    exDividendDate?:    Date;
    -  52}
    -  53
    -  54export interface EquitySplit {
    -  55    date:           Date;
    -  56    ratio:          number; // refers to the split ratio. The split ratio is an inverse of the number of shares that a holder of the stock would have after the split divided by the number of shares that the holder had before. 
    -  57                            // For example: Split ratio of .5 = 2 for 1 split.
    -  58}
    -  59
    -  60export interface EquityItem {
    -  61    /** equity symbol, e.g. 'GOOG' */
    -  62    symbol: string; 
    -  63    /** equity name, e.g. 'Alphabet' */
    -  64    name:   string;
    -  65    /** investment category, e.g. 'Stocks' */
    -  66    cat:    string;
    -  67
    -  68    /** set of traders that do not know this symbol */
    -  69    invalid?: {};
    -  70    venues?:  VenueIDs[];
    -  71
    -  72    /** number of shares owned */
    -  73    shares?: number;
    -  74    /** transaction history */
    -  75    trades?:Transaction[];
    -  76
    -  77    company?: {
    -  78        /** industry sector */
    -  79        sector?:    string;
    -  80        /** primary trading exchange */
    -  81        primaryExchange?: string;
    -  82    };
    -  83
    -  84    stats?: ItemStats;
    -  85    quotes?: DataSet;
    -  86    intraday?: DataSet;
    -  87    otherStats?:  any;
    -  88    splits?: EquitySplit[];
    -  89    changed?: boolean;
    -  90}
    -  91
    -  92
    -  93export class Equities {
    -  94    private static assembleCategories(items:EquityItem[]):Category[] {
    -  95        const categories:Category[] = [];
    -  96        items.forEach((item:EquityItem) => {
    -  97            let cat:Category = categories[item.cat];
    -  98            if (!cat) {
    -  99                cat = categories[item.cat] = {
    - 100                    cat: item.cat,
    - 101                    equities: []
    - 102                };
    - 103                categories.push(cat);
    - 104            };
    - 105            cat.equities.push(item);
    - 106        });
    - 107        categories.forEach((c:Category) => {
    - 108            c.equities.sort((a:EquityItem, b:EquityItem) => {
    - 109                if (a.shares > 0 || b.shares > 0) {
    - 110                    const diff = (b.shares || 0) - (a.shares || 0);
    - 111                    if (diff !== 0) { return diff; }
    - 112                }
    - 113                return (a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0);
    - 114            });
    - 115        });
    - 116        return categories; 
    - 117    }
    - 118
    - 119    //------  private parts -----
    - 120    private static equityList: EquityList;
    - 121    private static equityLoader: EquityLoader;
    - 122
    - 123
    - 124    //------  public parts -----
    - 125    constructor() { 
    - 126        if (!Equities.equityList)    { Equities.equityList     = new EquityList(); }
    - 127        if (!Equities.equityLoader)  { 
    - 128            Equities.equityLoader  = new EquityLoader(Equities.equityList); 
    - 129            Equities.equityLoader.loadEquityList();
    - 130        }
    - 131    }
    - 132
    - 133    public addItem(item:EquityItem):EquityItem {
    - 134        item = Equities.equityList.addItem(item);
    - 135        Equities.equityLoader.loadLocal(item);
    - 136        EquityLoader.saveEquityList(Equities.equityList.getAllSymbols());
    - 137        return item;
    - 138    }
    - 139
    - 140    public removeItem(itemOrSymbol:EquityItem|string) {
    - 141        Equities.equityList.removeItem(itemOrSymbol);
    - 142        EquityLoader.saveEquityList(Equities.equityList.getAllSymbols());
    - 143    }
    - 144
    - 145    public getItem(sym:string) { return Equities.equityList.getItem(sym); }
    - 146
    - 147    public getCategories():Category[] { 
    - 148        return Equities.assembleCategories(
    - 149            Equities.equityList.getAllSymbols().map(Equities.equityList.getItem.bind(Equities.equityList))
    - 150        );
    - 151    }
    - 152
    - 153    public getFirstByCat(cat:string):EquityItem {
    - 154        const c = this.getCategories()[cat];
    - 155        if (c && c.equities.length>0) { return c.equities[0]; }
    - 156        else { return Equities.equityList.unkownEquity(); }
    - 157    }
    - 158
    - 159    public getMarketUpdate():Promise { 
    - 160        return Equities.equityLoader.marketUpdate()
    - 161        .catch((err:any) => {
    - 162            console.log(err);
    - 163            return false;
    - 164        })
    - 165        .then(() => true); 
    - 166    }
    - 167    public getVenueSymbols():Promise { 
    - 168        return EquityLoader.getTrader().requestSymbols(); 
    - 169    }
    - 170    public readSplits()      { return Equities.equityLoader.requestSplitsIfMissing(); }
    - 171
    - 172    public applySplitsToTrades(item:EquityItem) {
    - 173        return EquityLoader.applySplitsToTrades(item);
    - 174    }
    - 175}
    - 176
    - 177export const gEquities = new Equities();
    - 178
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/Equity.html b/docs/src/hsStock/controller/Equity.html deleted file mode 100644 index 9d6d766..0000000 --- a/docs/src/hsStock/controller/Equity.html +++ /dev/null @@ -1,493 +0,0 @@ - - -

    controller/Equity.ts

    -
       1import { DataSet, DataRow }      from 'hsdata';
    -   2import { Trader,
    -   3         TraderSplit }  from './Trader';
    -   4import { ms }           from 'hsutil'; 
    -   5import { load, save }   from '../fileIO';
    -   6import { Transaction }  from './Assets';
    -   7
    -   8const DEF_EQUITY_LIST   = 'defEquityList.json';
    -   9const EQUITY_LIST       = 'equityList.json';
    -  10const SAVE_PATH         = 'hsStock/data';   // relative to 'apps/', defines in save.js cgi
    -  11const LOAD_PATH         = 'data';           // relative to 'hsStock/', root of webapp location
    -  12
    -  13export interface Category {
    -  14    cat:      string;         // the category name
    -  15    equities: EquityItem[];   // array of equities in this category
    -  16}
    -  17
    -  18export interface ItemStats {
    -  19    /** most recent trade date */
    -  20    latestDate?:        Date;
    -  21    /** most recent trade price */
    -  22    latestPrice? :      number;
    -  23
    -  24    /* last close price */
    -  25    closePrice?:        number;
    -  26    /** last close date */
    -  27    closeDate?:         Date;
    -  28    /** last close volume */
    -  29    closeVolume?:       number;
    -  30
    -  31    /** since previous close */
    -  32    change?:            number;
    -  33    /** price-to-earnings ratio */
    -  34    peRatio?:           number;
    -  35    /** 52 week high */
    -  36    week52high?:        number;
    -  37    /** 52 week low */
    -  38    week52low?:         number;
    -  39    /** market capitalziation */
    -  40    marketCap?:         number;
    -  41    /** total cash (Trailing twelve months) */
    -  42    cash?:              number;
    -  43    /** total revenue (Trailing twelve months) */
    -  44    revenue?:           number;
    -  45    /** total earnings (Trailing twelve months) */
    -  46    EBITDA?:            number;
    -  47    /** latest Earnings per Share */
    -  48    latestEPS?:         number;
    -  49    /** date of latest Earnings per Share */
    -  50    latestEPSDate?:     Date;
    -  51    /** dividend rate */
    -  52    dividendRate?:      number;
    -  53    /** dividend rate */
    -  54    dividendYield?:     number; 
    -  55    /** date of dividend */
    -  56    exDividendDate?:    Date;
    -  57}
    -  58
    -  59export interface EquityItem {
    -  60    /** equity symbol, e.g. 'GOOG' */
    -  61    symbol: string; 
    -  62    /** equity name, e.g. 'Alphabet' */
    -  63    name:   string;
    -  64    /** investment category, e.g. 'Stocks' */
    -  65    cat:    string;
    -  66
    -  67    /** set of traders that do not know this symbol */
    -  68    invalid?: {};
    -  69
    -  70    /** number of shares owned */
    -  71    shares?: number;
    -  72    /** transaction history */
    -  73    trades?:Transaction[];
    -  74
    -  75    company?: {
    -  76        /** industry sector */
    -  77        sector?:    string;
    -  78        /** primary trading exchange */
    -  79        primaryExchange?: string;
    -  80    };
    -  81
    -  82    stats?: ItemStats;
    -  83    quotes?: DataSet;
    -  84    intraday?: DataSet;
    -  85    otherStats?:  any;
    -  86    splits?: TraderSplit[];
    -  87    changed?: boolean;
    -  88}
    -  89
    -  90function saveQuotes(item:EquityItem):Promise {
    -  91    return save(item.quotes, `${SAVE_PATH}/stock/quotes${item.symbol}.json`)
    -  92    .then(() => item);
    -  93}
    -  94
    -  95/** saves equity inof to symXXX.json file, skipping the quotes */
    -  96function saveMeta(item:EquityItem):EquityItem {
    -  97    const copyPropertiesToItem = (item:EquityItem, data:EquityItem):EquityItem => {
    -  98        Object.keys(item).forEach((k:string) => data[k] = item[k]); 
    -  99        return data;             // continue working with original item
    - 100    };
    - 101
    - 102    if (item.changed) {
    - 103        item.changed = undefined;
    - 104        console.log(`saving stock/sym${item.symbol}.json`);
    - 105        const copy = copyPropertiesToItem(item, {});
    - 106//        delete copy.intraday;
    - 107        delete copy.quotes;
    - 108        delete copy.trades;
    - 109        save(copy, `${SAVE_PATH}/stock/sym${item.symbol}.json`);
    - 110    }
    - 111    return item;
    - 112}
    - 113
    - 114function updateMetaFromTrader(item:EquityItem) {
    - 115//    console.log(`${item.symbol} id out of date`);
    - 116    item.changed = true;
    - 117    return EquityList.getTrader().getMeta(item);
    - 118};
    - 119
    - 120function checkProperties(item:EquityItem):EquityItem {
    - 121    if (item.company && item.company.sector) { 
    - 122        if (item.cat !== item.company.sector) {
    - 123            item.cat = item.company.sector;
    - 124            item.changed = true;
    - 125        }
    - 126    }
    - 127    item.stats.closePrice = item.stats.closePrice || (item.otherStats? item.otherStats.close : -1);
    - 128    if (!item.stats.closeDate) {
    - 129        if (item.otherStats) {
    - 130            item.stats.closeDate = new Date(item.otherStats.closeTime);
    - 131        } else {
    - 132            console.log(`not item.otherStats for ${item.symbol}`);
    - 133        }
    - 134    }
    - 135    if (item.stats['latestVolume']) { delete item.stats['latestVolume']; }
    - 136    return item;
    - 137}
    - 138
    - 139
    - 140function loadMeta(item:EquityItem):Promise {
    - 141    const copyPropertiesToItem = (data:EquityItem):EquityItem => {
    - 142        Object.keys(data).forEach((k:string) => item[k] = data[k]); 
    - 143        return item;             // continue working with original item
    - 144    };
    - 145
    - 146    function loadSplitsIfMissing (item:EquityItem):Promise {
    - 147        return (!item.splits || item.splits.length === 0)? 
    - 148            this.readSymSplit(item) : 
    - 149            Promise.resolve(item);
    - 150    }
    - 151
    - 152    return load(`${LOAD_PATH}/stock/sym${item.symbol}.json`)
    - 153        // if nothing on local server: ignore
    - 154        .catch(() => item)
    - 155        .then(updateMetaFromTrader)
    - 156        .then(copyPropertiesToItem)
    - 157        .then(checkProperties)
    - 158        .then(loadQuotesIfOutdated)
    - 159        .then(loadSplitsIfMissing.bind(gEquityList))
    - 160        .then(applySplitsToTrades)  // new splits are only loaded upon specific request
    - 161        .then(saveMeta);
    - 162}
    - 163
    - 164/** impute trades with share price */
    - 165function imputeTradesWithSharePrice(item:EquityItem):EquityItem {
    - 166    if (item.trades) {
    - 167        item.trades.forEach((trade:Transaction) => { 
    - 168            if (!(trade.Date instanceof Date)) { trade.Date = new Date(trade.Date); }        
    - 169            if (trade.price) {
    - 170                if (typeof trade.price === 'string') {
    - 171                    trade.price = parseFloat(trade.price);
    - 172                    item.changed = true;
    - 173                }
    - 174            } else {
    - 175                item.changed = true;
    - 176                const row:any = item.quotes.rows.find((t:any) => {
    - 177                    if (!(t[0] instanceof Date)) { t[0] = new Date(t[0]); }
    - 178                    return t[0]>trade.Date;
    - 179                });
    - 180                trade.price = row? row[2] : 20;
    - 181            }
    - 182        });
    - 183    }    
    - 184    return item;            
    - 185};
    - 186
    - 187function updateStats(item: EquityItem):EquityItem {
    - 188    if (item.quotes.rows.length > 0) {
    - 189        const date = item.stats.closeDate;
    - 190        const dCol = item.quotes.names.indexOf('Date');
    - 191        const vCol = item.quotes.names.indexOf('Volume');
    - 192        const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    - 193        if (new Date(latestRow[dCol]) === date) {
    - 194            item.stats.closeVolume = latestRow[vCol];
    - 195        }
    - 196    }
    - 197    return item;
    - 198}
    - 199
    - 200/** read quotes from trader */
    - 201function get5yrQuotesFromTrader(item:EquityItem):Promise {
    - 202    return EquityList.getTrader().getQuotes(item, '5y')
    - 203    .then((data:DataSet):EquityItem => { item.quotes = data; return item; })
    - 204    .then(saveQuotes);
    - 205}
    - 206
    - 207
    - 208function updateQuotesFromDataSet(data:DataSet, item:EquityItem):EquityItem {
    - 209    if (item.quotes.rows.length > 0) {
    - 210        const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    - 211        const dCol = item.quotes.names.indexOf('Date');
    - 212        const lastItemDate = new Date(latestRow[dCol]);
    - 213        data.rows.forEach((row:any[]) => {
    - 214            const rowDate = (typeof row[dCol] === 'string')? new Date(row[dCol]) : row[dCol];
    - 215            if (rowDate > lastItemDate) { item.quotes.rows.push(row); }
    - 216        });
    - 217    }
    - 218    return item;
    - 219}
    - 220
    - 221/** read quotes from trader */
    - 222function getMissingRecentQuotesAndSave(item:EquityItem):Promise {
    - 223    let timeCode;
    - 224    if (item.quotes.rows.length === 0) {
    - 225        timeCode = '5yr';
    - 226    } else {
    - 227        const dCol      = item.quotes.names.indexOf('Date');
    - 228        const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    - 229        const missingDays = ms.toDays(new Date().getTime() - new Date(latestRow[dCol]).getTime());
    - 230        if (missingDays > 720)  { timeCode = '5yr'; }
    - 231        if (missingDays > 360)  { timeCode = '2yr'; }
    - 232        if (missingDays > 170)  { timeCode = '1yr'; }
    - 233        if (missingDays > 80)   { timeCode = '6m'; }
    - 234        if (missingDays > 28)   { timeCode = '3m'; }
    - 235        if (missingDays > 1)    { timeCode = '1m'; }
    - 236    } 
    - 237    
    - 238    if (timeCode) {
    - 239        return EquityList.getTrader().getQuotes(item, timeCode)
    - 240        .then((data:DataSet):EquityItem => updateQuotesFromDataSet(data, item))
    - 241        .then(saveQuotes);
    - 242    } else {
    - 243        return Promise.resolve(item);
    - 244    }
    - 245}
    - 246
    - 247function getIntradayQuotes(item:EquityItem):Promise {
    - 248    return EquityList.getTrader().getQuotes(item, '1d')
    - 249    .then((data:DataSet):EquityItem => { 
    - 250        const dCol = data.names.indexOf('Data');
    - 251        item.intraday.names = data.names;
    - 252        item.intraday.rows  = data.rows.filter((row:DataRow) => row[dCol]);
    - 253        return item;
    - 254    });
    - 255}
    - 256
    - 257
    - 258function loadQuotesIfOutdated(item:EquityItem):Promise {
    - 259    /** adds a quotes DataSet to an item  */
    - 260    const addQuotesToItem = (quotes:DataSet):EquityItem=> { 
    - 261        item.quotes = quotes;
    - 262        return item;
    - 263    };
    - 264    return load(`${LOAD_PATH}/stock/quotes${item.symbol}.json`)
    - 265        .then(addQuotesToItem)
    - 266        .catch(() => get5yrQuotesFromTrader(item))
    - 267        .then(getMissingRecentQuotesAndSave)
    - 268        .then(getIntradayQuotes)
    - 269        .then(updateStats)
    - 270        .then(imputeTradesWithSharePrice)
    - 271        ;
    - 272}
    - 273
    - 274function applySplitsToTrades(item:EquityItem):EquityItem {    
    - 275    if (item.splits && item.trades) {
    - 276        item.splits.forEach((split:TraderSplit) => {
    - 277            if (typeof split.date === 'string') { split.date = new Date(split.date); }
    - 278            item.trades.forEach((trade:Transaction) => {
    - 279                if (trade.Date < split.date) {
    - 280                    trade.price *= split.ratio;
    - 281                }
    - 282            });
    - 283        });
    - 284    }
    - 285    return item;
    - 286}
    - 287
    - 288function loadSplits(item:EquityItem):Promise {
    - 289    const addSplitsToItem = (splits:TraderSplit[]):EquityItem => { item.splits = splits; return item; };
    - 290    if (item.splits && item.splits.length===0) { item.splits = undefined; }
    - 291    return (item.splits)? Promise.resolve(item) :
    - 292        EquityList.getTrader().getSplits(item)
    - 293        .then(addSplitsToItem);
    - 294}
    - 295
    - 296function EquityList2JSON(list:EquityList):any {
    - 297    const data:any = {};
    - 298    list.getCategories().forEach((c:Category) => {
    - 299        data[c.cat] = {};
    - 300        c.equities.forEach((e:EquityItem) => {
    - 301            data[c.cat][e.symbol] = e.name;
    - 302        });
    - 303    });
    - 304    return data;
    - 305
    - 306
    - 307
    - 308
    - 309export class EquityList {
    - 310    //------  Static  parts -----
    - 311    private static trader = new Trader();
    - 312    private static lastUpdate:Date;
    - 313    private static marketUpdated(since:Date): Promise {
    - 314        const closingHour = 16;     // venue closes at 4pm PT;
    - 315        return EquityList.trader.lastMarketUpdate()
    - 316        .then((lastUpdated:Date) => {
    - 317            const today = new Date();
    - 318            EquityList.lastUpdate = today;
    - 319            if (!since) { return true; }                // no recent update
    - 320            if (lastUpdated < since) { return false; }   // no updates since
    - 321            if ((today.getDay()+6)%7 < 5)  {            // Mo-Fri: during trading days
    - 322                if (today.getTime() - lastUpdated.getTime() > ms.fromHours(24))
    - 323                    { return true; }                    //    --> more than a day old
    - 324                if (lastUpdated.getHours() < closingHour-1) {       // during trading hours
    - 325                    if (today.getTime() - lastUpdated.getTime() > ms.fromHours(1))
    - 326                        { return true; }                //    --> more than 1h
    - 327                }
    - 328            } else {                                    // during Weekend:
    - 329                return true;                            //    --> update once
    - 330            }
    - 331            return false;
    - 332        })
    - 333        .catch((err) => {
    - 334            console.log(`no response from trader: ${err}`);
    - 335            return false;
    - 336        });
    - 337    }
    - 338
    - 339
    - 340    //------  private  parts -----
    - 341    private bySymbol   = <{string: EquityItem}>{};
    - 342
    - 343    private unkownEquity() { 
    - 344        return {cat:'unknown Cat', symbol:'????', name:'unknown'}; 
    - 345    }
    - 346
    - 347    private JsonToEquityList(data:any):EquityList {
    - 348        if (!data) { console.log('no data in JsonToEquityList'); }
    - 349        else {
    - 350            Object.keys(data).forEach((k:string) => {
    - 351                Object.keys(data[k]).forEach((e:string) => {
    - 352                    this.add({ symbol: e, name: data[k][e], cat: k, stats:{}, company:{}});
    - 353                });
    - 354            });   
    - 355        }
    - 356        return this;
    - 357    }
    - 358
    - 359    private add(item:EquityItem):EquityItem {
    - 360        item.invalid = item.invalid || {};
    - 361        const sym = item.symbol.toUpperCase();
    - 362        if (!this.bySymbol[sym]) {
    - 363            this.bySymbol[sym] = item;
    - 364        }
    - 365        return this.bySymbol[sym];
    - 366    };
    - 367
    - 368    private remove(itemOrSymbol:EquityItem|string) {
    - 369        const item = (typeof itemOrSymbol === 'string')? 
    - 370            this.bySymbol[itemOrSymbol.toUpperCase()] : this.bySymbol[(itemOrSymbol).symbol];
    - 371        delete this.bySymbol[item.symbol.toUpperCase()];
    - 372    }
    - 373
    - 374    private  saveEquityList():Promise {
    - 375        return save(EquityList2JSON(this), `${SAVE_PATH}/${EQUITY_LIST}`);
    - 376    }
    - 377
    - 378    private readSymSplit(item:EquityItem):Promise {
    - 379        return loadSplits(item)
    - 380        .then(saveMeta)
    - 381        .then(applySplitsToTrades)  // new splits are only loaded upon specific request
    - 382        .catch((err) => {
    - 383            console.log(`error in readSymSplit: ${err}`);
    - 384            return item;
    - 385        });
    - 386    }
    - 387
    - 388    //------  public parts -----
    - 389
    - 390    public static getTrader() { return EquityList.trader; }
    - 391
    - 392    public readSplits() {
    - 393        Object.keys(this.bySymbol).forEach((sym:string) => {
    - 394            this.readSymSplit(this.getItem(sym));
    - 395        });
    - 396    }
    - 397
    - 398    public clearInvalids() {
    - 399        Object.keys(this.bySymbol).forEach((sym:string) => {
    - 400            const item = this.getItem(sym);
    - 401            delete item.invalid;
    - 402            item.changed = true;
    - 403            saveMeta(item);
    - 404        });
    - 405    }
    - 406
    - 407    public getItem(symbol:string):EquityItem { 
    - 408        if (this.bySymbol[symbol]) { 
    - 409            return this.bySymbol[symbol]; 
    - 410        }
    - 411        return this.unkownEquity();
    - 412    }
    - 413
    - 414    public addItem(item:EquityItem):EquityItem {
    - 415        item = this.add(item);
    - 416        loadMeta(item);
    - 417        this.saveEquityList();
    - 418        return item;
    - 419    }
    - 420
    - 421    public removeItem(itemOrSymbol:EquityItem|string) {
    - 422        this.remove(itemOrSymbol);
    - 423        this.saveEquityList();
    - 424    }
    - 425
    - 426    public getCategories():Category[] { 
    - 427        const categories:Category[] = [];
    - 428        Object.keys(this.bySymbol).forEach((sym:string) => {
    - 429            const item = this.bySymbol[sym];
    - 430            let cat:Category = categories[item.cat];
    - 431            if (!cat) {
    - 432                cat = categories[item.cat] = {
    - 433                    cat: item.cat,
    - 434                    equities: []
    - 435                };
    - 436                categories.push(cat);
    - 437            };
    - 438            cat.equities.push(item);
    - 439        });
    - 440        categories.forEach((c:Category) => {
    - 441            c.equities.sort((a:EquityItem, b:EquityItem) => {
    - 442                if (a.shares > 0 || b.shares > 0) {
    - 443                    const diff = (b.shares || 0) - (a.shares || 0);
    - 444                    if (diff !== 0) { return diff; }
    - 445                }
    - 446                return (a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0);
    - 447            });
    - 448        });
    - 449        return categories; 
    - 450    }
    - 451
    - 452    public getFirstByCat(cat:string):EquityItem {
    - 453        const c = this.getCategories()[cat];
    - 454        if (c && c.equities.length>0) { return c.equities[0]; }
    - 455        else { return this.unkownEquity(); }
    - 456    }
    - 457
    - 458    public marketUpdate() {
    - 459        Object.keys(this.bySymbol).forEach((sym:string) => {
    - 460            const item = this.bySymbol[sym];
    - 461            load(item);
    - 462        });
    - 463    }
    - 464
    - 465    public loadEquityList():Promise {
    - 466        return load(`${LOAD_PATH}/${EQUITY_LIST}`)
    - 467        .catch(() => load(`${LOAD_PATH}/${DEF_EQUITY_LIST}`))
    - 468        .then((data:any) => this.JsonToEquityList.call(this, data))
    - 469        .then(() => EquityList.marketUpdated(EquityList.lastUpdate))
    - 470        .then((b:boolean) => b? this.marketUpdate() : '');
    - 471    }
    - 472}
    - 473
    - 474export const gEquityList = new EquityList();
    - 475gEquityList.loadEquityList();
    - 476
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/EquityList.html b/docs/src/hsStock/controller/EquityList.html deleted file mode 100644 index faa972f..0000000 --- a/docs/src/hsStock/controller/EquityList.html +++ /dev/null @@ -1,120 +0,0 @@ - - -

    controller/EquityList.ts

    -
       1import { Transaction }  from './Assets';
    -   2import { EquityItem }   from './Equities';
    -   3
    -   4
    -   5
    -   6export class EquityList {
    -   7    //------  Static  parts -----
    -   8   
    -   9    /** impute trades with share price */
    -  10    public static imputeTradesWithSharePrice(item:EquityItem):EquityItem {
    -  11        if (item.trades) {
    -  12            item.trades.forEach((trade:Transaction) => { 
    -  13                if (!(trade.Date instanceof Date)) { trade.Date = new Date(trade.Date); }        
    -  14                if (trade.price) {
    -  15                    if (typeof trade.price === 'string') {
    -  16                        trade.price = parseFloat(trade.price);
    -  17                        item.changed = true;
    -  18                    }
    -  19                } else if (item.quotes && item.quotes.rows) {
    -  20                    item.changed = true;
    -  21                    const row:any = item.quotes.rows.find((t:any) => {
    -  22                        if (!(t[0] instanceof Date)) { t[0] = new Date(t[0]); }
    -  23                        return t[0]>trade.Date;
    -  24                    });
    -  25                    trade.price = row? row[2] : 20;
    -  26                }
    -  27            });
    -  28        }    
    -  29        return item;            
    -  30    };
    -  31
    -  32    //------  private  parts -----
    -  33    private bySymbol   = <{string: EquityItem}>{};
    -  34
    -  35    //------  public parts -----
    -  36
    -  37    public clearInvalids() {
    -  38        Object.keys(this.bySymbol).forEach((sym:string) => {
    -  39            const item = this.getItem(sym);
    -  40            delete item.invalid;
    -  41            item.changed = true;
    -  42        });
    -  43    }
    -  44
    -  45    public unkownEquity() { 
    -  46        return {cat:'unknown Cat', symbol:'????', name:'unknown'}; 
    -  47    }
    -  48
    -  49    public newItem(sym:string):EquityItem { 
    -  50        const item = {
    -  51            symbol:sym, 
    -  52            cat:'unknown Cat', 
    -  53            name:'unknown',
    -  54            changed: true
    -  55        }; 
    -  56        return this.addItem(item);
    -  57    }
    -  58
    -  59
    -  60    public getAllSymbols():string[] {
    -  61        return Object.keys(this.bySymbol);
    -  62    }
    -  63
    -  64    public getItem(symbol:string):EquityItem { 
    -  65        if (!this || !this.bySymbol) {
    -  66            console.log('missing this');
    -  67        }
    -  68        return this.bySymbol[symbol] || this.unkownEquity();
    -  69    }
    -  70
    -  71    public addItem(item:EquityItem):EquityItem {
    -  72        const sym = item.symbol.toUpperCase();
    -  73        delete item.invalid;        // no longer used
    -  74        return this.bySymbol[sym] || (this.bySymbol[sym] = item);
    -  75    }
    -  76
    -  77    public removeItem(itemOrSymbol:EquityItem|string) {
    -  78        const item = (typeof itemOrSymbol === 'string')? 
    -  79            this.bySymbol[itemOrSymbol.toUpperCase()] : this.bySymbol[(itemOrSymbol).symbol];
    -  80        delete this.bySymbol[item.symbol.toUpperCase()];
    -  81    }
    -  82
    -  83    public checkProperties(item:EquityItem):EquityItem {
    -  84        if (item.company && item.company.sector) { 
    -  85            if (item.cat !== item.company.sector) {
    -  86                item.cat = item.company.sector;
    -  87                item.changed = true;
    -  88            }
    -  89        }
    -  90        item.stats.closePrice = item.stats.closePrice || (item.otherStats? item.otherStats.close : -1);
    -  91        if (!item.stats.closeDate) {
    -  92            if (item.otherStats) {
    -  93                item.stats.closeDate = new Date(item.otherStats.closeTime);
    -  94            } else {
    -  95                console.log(`not item.otherStats for ${item.symbol}`);
    -  96            }
    -  97        }
    -  98        if (item.stats['latestVolume']) { delete item.stats['latestVolume']; }
    -  99        return item;
    - 100    }
    - 101}
    - 102
    - 103
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/EquityLoader.html b/docs/src/hsStock/controller/EquityLoader.html deleted file mode 100644 index 923d05e..0000000 --- a/docs/src/hsStock/controller/EquityLoader.html +++ /dev/null @@ -1,345 +0,0 @@ - - -

    controller/EquityLoader.ts

    -
       1import { DataSet }      from 'hsdata';
    -   2import { Trader }       from './Trader';
    -   3import { Transaction }  from './Assets';
    -   4import { EquityList }   from './EquityList';
    -   5import { EquitySplit }  from './Equities';
    -   6import { EquityItem }   from './Equities';
    -   7import { ms }           from 'hsutil'; 
    -   8import { load, save }   from '../fileIO';
    -   9
    -  10const DEF_EQUITY_LIST   = 'defEquityList.json';
    -  11const EQUITY_LIST       = 'equityList.json';
    -  12const SAVE_PATH         = 'hsStock/data';   // relative to 'apps/', defines in save.js cgi
    -  13const LOAD_PATH         = 'data';           // relative to 'hsStock/', root of webapp location
    -  14
    -  15
    -  16
    -  17function copyProperties(from:EquityItem, to:EquityItem):EquityItem {
    -  18    Object.keys(from).forEach((k:string) => to[k] = from[k]); 
    -  19    return to;             // continue working with original item
    -  20};
    -  21
    -  22/** saves equity inof to symXXX.json file, skipping the quotes */
    -  23function saveMeta(item:EquityItem):Promise {
    -  24    if (item.changed) {
    -  25        const copy = {
    -  26            symbol:     item.symbol, 
    -  27            name:       item.name,
    -  28            cat:        item.cat,
    -  29            venues:     item.venues,
    -  30            shares:     item.shares,
    -  31            trades:     item.trades,
    -  32            company:    item.company,
    -  33            stats:      item.stats,
    -  34            otherStats: item.otherStats,
    -  35            splits:     item.splits
    -  36        };
    -  37        return save(copy, `${SAVE_PATH}/stock/sym${item.symbol}.json`)
    -  38            .then(() => {
    -  39                console.log(`${new Date().getTime() %10000}: saved sym${item.symbol}.json to local`);
    -  40                item.changed = undefined;
    -  41                return item;
    -  42            });
    -  43    }
    -  44    return Promise.resolve(item); 
    -  45}
    -  46
    -  47
    -  48
    -  49function updateStats(item: EquityItem):EquityItem {
    -  50    if (item && item.quotes && item.quotes.rows && item.quotes.rows.length > 0) {
    -  51        const date = item.stats.closeDate;
    -  52        const dCol = item.quotes.colNames.indexOf('Date');
    -  53        const vCol = item.quotes.colNames.indexOf('Volume');
    -  54        const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    -  55        if (latestRow[dCol] === date) {
    -  56            item.stats.closeVolume = latestRow[vCol];
    -  57        }
    -  58    }
    -  59    return item;
    -  60}
    -  61
    -  62
    -  63function JsonToSymArray(data:any):string[] {
    -  64    if (!data) { 
    -  65        console.log('no data in JsonToSymArray'); 
    -  66    } else if(data.length > 0) {    // new format
    -  67        return data;
    -  68    } else {                        // old format
    -  69        const syms:string[] = [];
    -  70        Object.keys(data).forEach((k:string) => 
    -  71            Object.keys(data[k]).forEach((e:string) => syms.push(e))
    -  72        );   
    -  73        return syms;
    -  74    }
    -  75}
    -  76
    -  77
    -  78let trader:Trader;
    -  79
    -  80export class EquityLoader {
    -  81    //------  Static  parts -----
    -  82    private static lastUpdate:Date;
    -  83    public static getTrader() { return trader; }
    -  84    
    -  85    public static shouldUpdate(since:Date): Promise {
    -  86        const closingHour = 16;     // venue closes at 4pm PT;
    -  87        return trader.lastMarketUpdate()
    -  88        .then((lastUpdated:Date) => {
    -  89            const today = new Date();
    -  90            EquityLoader.lastUpdate = today;
    -  91            if (!since) { return true; }                // no recent update
    -  92            if (lastUpdated < since) { return false; }   // no updates since
    -  93            if ((today.getDay()+6)%7 < 5)  {            // Mo-Fri: during trading days
    -  94                if (today.getTime() - lastUpdated.getTime() > ms.fromHours(24))
    -  95                    { return true; }                    //    --> more than a day old
    -  96                if (lastUpdated.getHours() < closingHour-1) {       // during trading hours
    -  97                    if (today.getTime() - lastUpdated.getTime() > ms.fromHours(1))
    -  98                        { return true; }                //    --> more than 1h
    -  99                }
    - 100            } else {                                    // during Weekend:
    - 101                return true;                            //    --> update once
    - 102            }
    - 103            return false;
    - 104        })
    - 105        .catch((err) => {
    - 106            console.log(`no response from trader: ${err}`);
    - 107            return false;
    - 108        });
    - 109    }
    - 110
    - 111    public static applySplitsToTrades(item:EquityItem):EquityItem {   
    - 112        if (item.splits && item.trades) {
    - 113            item.splits.forEach((split:EquitySplit) => {
    - 114                if (typeof split.date === 'string') { split.date = new Date(split.date); }
    - 115                item.trades.forEach((trade:Transaction) => {
    - 116                    if (!trade.appliedSplits) { trade.appliedSplits = {}; }
    - 117                    if (!trade.appliedSplits[split.date.getTime()] && trade.Date < split.date) {
    - 118                        trade.price *= split.ratio;
    - 119                        trade.change /= split.ratio;
    - 120                        trade.total /= split.ratio;
    - 121                        trade.appliedSplits[split.date.getTime()] = split.ratio;
    - 122                        item.changed = true;
    - 123                    }
    - 124                });
    - 125            });
    - 126        }
    - 127        return item;
    - 128    }
    - 129
    - 130    public static filterQuotes(data:DataSet, dateColName:string, valColName:string) {
    - 131        let dateCol  = data.colNames.indexOf(dateColName);
    - 132        let closeCol = data.colNames.indexOf(valColName);
    - 133        const noNull = (r:any[]) => r[dateCol] !==undefined && r[dateCol] !==null &&
    - 134                                    r[closeCol]!==undefined && r[closeCol]!==null;
    - 135        data.rows = data.rows.filter(noNull);
    - 136        data.rows.map((r:any[]) => r[dateCol] = new Date(r[dateCol]));
    - 137    }
    - 138
    - 139    public static saveQuotes(item:EquityItem):Promise {
    - 140        console.log(`${new Date().getTime() %10000}: save ${item.quotes.rows.length} Quotes ${item.symbol} to local`);
    - 141        const result = {
    - 142            quotes:     item.quotes,
    - 143            intraday:   item.intraday
    - 144        };
    - 145        return save(result, `${SAVE_PATH}/stock/quotes${item.symbol}.json`)
    - 146        .catch((err:any) => {
    - 147            console.log(`error for in saveQuotes: ${err}`);
    - 148            console.log(item);
    - 149            return item;
    - 150        })
    - 151        .then(() => item);
    - 152    }
    - 153
    - 154    private static requestIntradayQuotes(item:EquityItem):Promise {
    - 155        return trader.requestQuotes(item, 1)
    - 156        .catch((err:any) => {
    - 157            console.error(`error in getIntradayQuotes: ${err}`);
    - 158            return item;
    - 159        });
    - 160    }
    - 161
    - 162
    - 163    private static requestSymSplitIfMissing(item:EquityItem):Promise {
    - 164        function addSplitsToItem(splits:EquitySplit[]):EquityItem { 
    - 165            if (!item.splits) { 
    - 166                item.splits = splits; 
    - 167            } else {
    - 168                splits.forEach((split:EquitySplit) => {
    - 169                    if (!item.splits.find((s:EquitySplit) => s.date === split.date)) { 
    - 170                        item.splits.push(split); 
    - 171                    }
    - 172                });
    - 173            }
    - 174            item.splits.sort((a:EquitySplit, b:EquitySplit) => a.date.getTime() - b.date.getTime()); 
    - 175            EquityLoader.applySplitsToTrades(item); // new splits are only loaded upon specific request
    - 176            return item; 
    - 177        };
    - 178
    - 179//        if (item.splits && item.splits.length===0) { item.splits = undefined; }
    - 180        
    - 181        return (item.splits)? Promise.resolve(item) :
    - 182            trader.requestSplits(item)
    - 183            .then(addSplitsToItem)
    - 184            .catch((err) => {
    - 185                console.log(`error in readSymSplit: ${err}`);
    - 186                return item;
    - 187            });
    - 188    }
    - 189
    - 190    public static saveEquityList(symbols:string[]):Promise {
    - 191        console.log(`${new Date().getTime() %10000}: saveEquityList to local`);
    - 192        return save(symbols, `${SAVE_PATH}/${EQUITY_LIST}`);
    - 193    }
    - 194
    - 195    //------  private  parts -----
    - 196    private list:EquityList;
    - 197
    - 198    private loadAllItemsLocal(items: EquityItem[]):Promise {
    - 199        return Promise.all(items
    - 200//            .filter(item => item.symbol==='AAPL')
    - 201            .map(item =>
    - 202                this.loadLocal(item)
    - 203                .then((item:EquityItem) => this.list.addItem(item))
    - 204                .catch(console.log)
    - 205            ))
    - 206        .then(()=>{});
    - 207    }
    - 208
    - 209
    - 210    //------  public parts -----
    - 211
    - 212    constructor(list:EquityList) {
    - 213        this.list = list;
    - 214        if (!trader) { 
    - 215            trader = new Trader(); 
    - 216            Trader.loadLocalVenues(LOAD_PATH, SAVE_PATH, '/venues.json');
    - 217        }
    - 218    }
    - 219
    - 220    /**
    - 221     * load the equity list, then load all equities 
    - 222     */

    - 223    public loadEquityList():Promise {
    - 224        console.log(`${new Date().getTime() %10000}: loadEquityList from local`);
    - 225        return load(`${LOAD_PATH}/${EQUITY_LIST}`)
    - 226        .catch(() => load(`${LOAD_PATH}/${DEF_EQUITY_LIST}`))
    - 227        .then(JsonToSymArray)
    - 228        .then((syms:string[]) => syms.map((sym) => this.list.newItem(sym)))
    - 229        .then(this.loadAllItemsLocal.bind(this));
    - 230    }
    - 231
    - 232    public requestSplitsIfMissing():Promise {
    - 233        return Promise.all(
    - 234            this.list.getAllSymbols().map((sym:string) => 
    - 235                EquityLoader.requestSymSplitIfMissing(this.list.getItem(sym))
    - 236                .then(saveMeta)
    - 237            )
    - 238        )
    - 239        .catch(console.log)
    - 240        .then(()=>{});
    - 241    }
    - 242
    - 243    public marketUpdate():Promise {
    - 244        return Promise.all(
    - 245            this.list.getAllSymbols()
    - 246//            .filter((s:string) => s==='AAPL')
    - 247            .map((sym:string) => this.loadRemote(this.list.getItem(sym))
    - 248            )
    - 249        )
    - 250        .then(()=>true)
    - 251        .catch((err:any) => {
    - 252            console.log(`error in marketUpdate: ${err}`);
    - 253            return false;
    - 254        });
    - 255    }
    - 256
    - 257    public loadLocal(item:EquityItem):Promise {
    - 258        /** adds a quotes DataSet to an item  */
    - 259        function addQuotesToItem(quotes:{quotes:DataSet, intraday:DataSet}):EquityItem { 
    - 260            if (quotes) {
    - 261                const q = quotes.quotes || quotes;
    - 262                item.quotes = {
    - 263                    colNames: q['colNames'] || q['names'],
    - 264                    rows:     q['rows']
    - 265                };
    - 266                item.intraday = quotes.intraday? quotes.intraday : 
    - 267                    { colNames: [], rows:[] }; 
    - 268            }
    - 269            return item;
    - 270        }
    - 271        function copyParts(data:EquityItem) {
    - 272            if (item.trades) { data.trades = item.trades; }
    - 273            copyProperties(data, item); 
    - 274            return item;         
    - 275        }
    - 276        function normalizeItem(item:EquityItem):Promise {
    - 277            if (item.quotes) {
    - 278                EquityLoader.filterQuotes(item.quotes, 'Date', 'Close');
    - 279            }
    - 280            if (item.intraday) {
    - 281                if (item.intraday['names']) {
    - 282                    item.intraday.colNames = item.intraday['names'];
    - 283                    delete item.intraday['names'];
    - 284                }
    - 285                EquityLoader.filterQuotes(item.intraday, 'Date', 'Low');
    - 286            }
    - 287            Trader.getVenue(item); // to initialize the venues in item
    - 288            EquityLoader.applySplitsToTrades(item);
    - 289            return saveMeta(item);
    - 290        }
    - 291        if (item.symbol === '????') {
    - 292            return Promise.resolve(item);
    - 293        } else {
    - 294            return load(`${LOAD_PATH}/stock/sym${item.symbol}.json`)
    - 295                .then(copyParts)
    - 296                .then(() => load(`${LOAD_PATH}/stock/quotes${item.symbol}.json`))
    - 297                .then(addQuotesToItem) 
    - 298                .then(normalizeItem)       
    - 299                .catch(() => item); // if nothing on local server: ignore
    - 300        }
    - 301    }
    - 302
    - 303    public loadRemote(item:EquityItem):Promise {
    - 304        const list = this.list;
    - 305        const copyPropertiesToItem = (data:EquityItem):EquityItem => {
    - 306            Object.keys(data).forEach((k:string) => item[k] = data[k]); 
    - 307            return item;             // continue working with original item
    - 308        };
    - 309
    - 310        return Promise.resolve(item)
    - 311            .then(trader.requestMeta)
    - 312            .then(copyPropertiesToItem)
    - 313            .then(list.checkProperties)
    - 314            .then(EquityLoader.getTrader().requestQuotes)
    - 315            .then(EquityLoader.saveQuotes)
    - 316            .then(EquityLoader.requestIntradayQuotes)
    - 317            .then(updateStats)
    - 318            .then(EquityList.imputeTradesWithSharePrice)
    - 319            .then(EquityLoader.requestSymSplitIfMissing)
    - 320            .then(saveMeta)
    - 321            .catch((err:any) => {
    - 322                console.error(`error in loadRemote: ${err}`);
    - 323                return item;
    - 324            });
    - 325    }
    - 326
    - 327}
    - 328
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/Loader.html b/docs/src/hsStock/controller/Loader.html deleted file mode 100644 index d510321..0000000 --- a/docs/src/hsStock/controller/Loader.html +++ /dev/null @@ -1,18 +0,0 @@ - - -

    controller/Loader.ts

    -
       1
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/Trader.html b/docs/src/hsStock/controller/Trader.html deleted file mode 100644 index a1d22ce..0000000 --- a/docs/src/hsStock/controller/Trader.html +++ /dev/null @@ -1,325 +0,0 @@ - - -

    controller/Trader.ts

    -
       1import { EquityItem,
    -   2         EquitySplit }      from './Equities';
    -   3import { EquityLoader } from './EquityLoader';
    -   4import { VenueIDs,
    -   5         Venue,
    -   6         VenueSummary }     from './Venue';
    -   7import { IexVenue }         from './VenueIex';
    -   8import { ms }               from 'hsutil';
    -   9import { DataSet }          from 'hsdata';
    -  10import { load, save }       from '../fileIO';
    -  11
    -  12export interface TraderQuote {
    -  13    Date:           Date;
    -  14    close:          number;
    -  15    high:           number;
    -  16    low:            number;
    -  17    open:           number;
    -  18    volume:         number;
    -  19}
    -  20
    -  21export interface TraderIntraday {
    -  22    Date:           Date;
    -  23    high:           number;
    -  24    low:            number;
    -  25}
    -  26
    -  27export interface TraderSymbol {
    -  28    symbol: string;
    -  29    name:   string;  
    -  30}
    -  31
    -  32function createVenues():Venue[] {
    -  33    const vns:Venue[] = [];
    -  34    vns.push(vns[VenueIDs.IEX] = new IexVenue());
    -  35    return vns;
    -  36}
    -  37
    -  38    /** accessible by index, or by Venues.***  */
    -  39const venues:Venue[] = createVenues();
    -  40    
    -  41export const getVenue = (name: VenueIDs|number):Venue => venues[name];
    -  42
    -  43export const allVenueIDs = ():VenueIDs[] => venues.map(
    -  44    (venue:Venue) => venue.summary.venueID
    -  45);
    -  46
    -  47
    -  48/** converts and imputates trader quotes to a DataSet */
    -  49export function traderQuote2Dataset(dataIn:any[]):DataSet  {
    -  50    const names = ['Date', 'Open', 'Close', 'High', 'Low', 'Volume'];
    -  51    if (dataIn.length === 0) {
    -  52        console.log(`received no quotes ${(dataIn).url}`);
    -  53        return { colNames:names, rows:[]};
    -  54    } else {
    -  55        const rows  = dataIn
    -  56        .filter((e:any) => e.date)
    -  57        .map((e: any) => {
    -  58            if (e.minute) {
    -  59                const date = e.date? new Date(e.date + ' ' + e.minute) : undefined;
    -  60                return [
    -  61                    date, 
    -  62                    e.marketHigh,
    -  63                    e.marketLow
    -  64                ];
    -  65            } else {
    -  66                return [
    -  67                    e.date? new Date(e.date) : undefined,
    -  68                    e.close,
    -  69                    e.high || e.close,
    -  70                    e.low  || e.close,
    -  71                    e.open || e.close,
    -  72                    e.volume
    -  73                ];
    -  74            }
    -  75        });
    -  76        return { colNames:names, rows:rows};
    -  77    }
    -  78};
    -  79
    -  80
    -  81export class Trader { 
    -  82    //------  static  parts -----
    -  83
    -  84    /**
    -  85     * load local venue desciptor and update venue fields
    -  86     * data: { venueName:[TraderSymbol] }
    -  87     */

    -  88    private static updateLocalVenues(data:{[venueName:string]:TraderSymbol[]}) {
    -  89        Object.keys(data).map((ven:VenueIDs) => {
    -  90            if (getVenue(ven)) {
    -  91                const v:VenueSummary = getVenue(ven).summary;
    -  92                data[ven].map((e:TraderSymbol) => {
    -  93                    v.symbols.push(e.symbol);
    -  94                    v.names.push(e.name);
    -  95                    v.equities[e.symbol] = e;
    -  96                });
    -  97            } else {
    -  98                console.log(`unknown venue ${ven}`);
    -  99            }
    - 100        });
    - 101    }
    - 102
    - 103    public static loadLocalVenues(loadPath:string, savePath:string, file:string) {
    - 104        load(loadPath+file)
    - 105        .then(Trader.updateLocalVenues)
    - 106        .catch(() => {
    - 107            Promise.all(allVenueIDs().map((n:VenueIDs) => getVenue(n).requestSymbolsForVenue()))
    - 108            .catch(console.log)
    - 109            .then(()=> savePath+file)
    - 110            .then(Trader.saveLocalVenues);
    - 111        });                      
    - 112    }
    - 113
    - 114    private static saveLocalVenues(savePath:string) {
    - 115        const venues = {};
    - 116        allVenueIDs().map((n:VenueIDs) => {
    - 117            const summary:VenueSummary = getVenue(n).summary;
    - 118            venues[n] = Object.keys(summary.equities);
    - 119        });
    - 120        return save(venues, savePath)
    - 121        .catch(console.log);
    - 122    }
    - 123    
    - 124
    - 125    /**
    - 126     * adds quotes to item.intraday; overwriting item.intraday. 
    - 127     * @param quotes 
    - 128     * @param item 
    - 129     */

    - 130    private static addIntraday(quotes:TraderIntraday[], item:EquityItem):EquityItem {
    - 131        const names = ['Date', 'High', 'Low'];
    - 132        const rows  = quotes.map((t:TraderIntraday) => [t.Date, t.high, t.low]);
    - 133        item.intraday = {colNames:names, rows:rows};
    - 134        EquityLoader.filterQuotes(item.intraday, 'Date', 'Low');
    - 135        return item;
    - 136    }
    - 137
    - 138    /**
    - 139     * adds quotes to item.quotes; creating item.quotes if undefined. 
    - 140     * @param quotes 
    - 141     * @param item 
    - 142     */

    - 143    private static addQuotes(quotes:TraderQuote[], item:EquityItem):EquityItem {
    - 144        const  sortDate = ((r0:Date[], r1:Date[]) => r0[0].getTime() - r1[0].getTime());
    - 145        let lastItemDate = new Date('1/1/1980');
    - 146        if (!item.quotes) {
    - 147            item.quotes = {
    - 148                colNames: ['Date','Open','Close','High','Low','Volume'],
    - 149                rows: []
    - 150            };
    - 151        }
    - 152        const dCol = item.quotes.colNames.indexOf('Date');
    - 153        if (item.quotes.rows.length > 0) {
    - 154            item.quotes.rows.sort(sortDate);
    - 155//item.quotes.rows.map((r:any[]) => console.log(r[0]));            
    - 156            const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    - 157            lastItemDate = (typeof latestRow[dCol] === 'string')? new Date(latestRow[dCol]) : latestRow[dCol];
    - 158//console.log(`${item.name}: ${latestRow[0]} ${dCol} ${lastItemDate}`);            
    - 159        }
    - 160        quotes
    - 161            .sort((a:TraderQuote, b:TraderQuote) => a.Date.getTime() - b.Date.getTime())
    - 162            .map((q:TraderQuote) => {               // copy rows to item.quotes
    - 163                if (q.Date > lastItemDate) { 
    - 164                    item.quotes.rows.push([q.Date, q.open, q.close, q.high, q.low, q.volume]);
    - 165                }
    - 166            });
    - 167        if (item.quotes.rows.length > 0) {  // update item.stats
    - 168            const vCol = item.quotes.colNames.indexOf('Volume');
    - 169            const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    - 170            item.stats.closeVolume = latestRow[vCol];
    - 171            item.stats.closeDate   = latestRow[dCol];
    - 172        }
    - 173        return item;
    - 174    }
    - 175
    - 176    private static adjustMissingDays(item:EquityItem):number {
    - 177        if (!item.quotes || item.quotes.rows.length === 0) {
    - 178            return 10000;
    - 179        } else {
    - 180            const dCol      = item.quotes.colNames.indexOf('Date');
    - 181            const latestRow = item.quotes.rows[item.quotes.rows.length-1];
    - 182            return ms.toDays(new Date().getTime() - new Date(latestRow[dCol]).getTime());
    - 183        }
    - 184    }
    - 185
    - 186
    - 187    //------  private  parts -----
    - 188
    - 189
    - 190    //------  public  parts -----
    - 191
    - 192    private static getVenueID(item:EquityItem):VenueIDs {
    - 193        if (!item.venues || item.venues.length===0) { 
    - 194            item.venues = [VenueIDs.IEX]; 
    - 195            item.changed = true;
    - 196        }
    - 197        return item.venues[0];
    - 198    }
    - 199
    - 200    public static getVenue(item:EquityItem):Venue {
    - 201        const venueID = Trader.getVenueID(item);
    - 202        return venueID? venues[venueID] : undefined;
    - 203    }
    - 204
    - 205    public static invalidateVenueID(item:EquityItem, venue:VenueIDs) {
    - 206        if (item.venues[venue]) { 
    - 207            console.log(`invalidating ${venue} for ${item.symbol}`);
    - 208            delete item.venues[venue]; 
    - 209            item.changed = true;
    - 210        }
    - 211    }
    - 212
    - 213    /**
    - 214     * constructs a Trader and loads the local 
    - 215     * @param loadPath 
    - 216     * @param savePath 
    - 217     * @param file 
    - 218     */

    - 219    constructor() {        
    - 220    }
    - 221
    - 222
    - 223
    - 224    public lastMarketUpdate(): Promise {
    - 225        return getVenue(0).requestMarketUpdate()
    - 226        .catch((err:any) => {
    - 227            console.log(err);
    - 228            return new Date();
    - 229        });
    - 230    }
    - 231
    - 232    /** 
    - 233     * initiates remote requests to the venues and updates `item` accordingly.
    - 234     * If `missingDays` is 1, intraday quotes will be requested.
    - 235     * Otherwise, appropriate daily quotes are requested to fill `item.quotes` as needed,
    - 236     * with a maximum of `missingDays`, if specified,
    - 237     * and intraday quoates will not be requested.
    - 238     * 
    - 239     * @return fully updated `item` as requested.
    - 240     */

    - 241    public requestQuotes(item:EquityItem, missingDays?:number):Promise {
    - 242
    - 243        const venue = Trader.getVenue(item);
    - 244        if (venue) {
    - 245            if (missingDays <= 1) { 
    - 246                return Promise.resolve(item)
    - 247                    .then(venue.requestIntradayVenue)
    - 248                    .then((q:TraderIntraday[]) => Trader.addIntraday(q, item))
    - 249                    .catch((err:any) => {
    - 250                        Trader.invalidateVenueID(item, venue.summary.venueID);
    - 251                        console.log(`error in requestIntraday ${item.symbol} for venue ${venue}: ${err}`);
    - 252                        return item;
    - 253                    });
    - 254            } else {
    - 255                missingDays = Trader.adjustMissingDays(item);
    - 256                return Promise.resolve()
    - 257                    .then(() => venue.requestQuotesVenue(item, missingDays))
    - 258                    .then((q:TraderQuote[]) => Trader.addQuotes(q, item))
    - 259                    .catch((err:any) => {
    - 260                        Trader.invalidateVenueID(item, venue.summary.venueID);
    - 261                        console.log(`error in requestQuotes ${item.symbol} for venue ${venue}: ${err}`);
    - 262                        return item;
    - 263                    });
    - 264            }
    - 265        } else {
    - 266            return Promise.resolve(item);
    - 267        }
    - 268    }
    - 269
    - 270    public requestSplits(item:EquityItem):Promise {
    - 271        const venue = Trader.getVenue(item);
    - 272        if (venue) { return venue.requestSplitsVenue(item)
    - 273            .catch((err:any) => {
    - 274                Trader.invalidateVenueID(item, venue.summary.venueID);
    - 275                console.log(`error in requestSplits ${item.symbol} for venue ${venue}: ${err}`);
    - 276                return [];
    - 277            });
    - 278        }
    - 279    }
    - 280
    - 281    public requestMeta(item:EquityItem):Promise {
    - 282        const venue = Trader.getVenue(item);
    - 283        if (venue) { return venue.requestMetaVenue(item)
    - 284            .catch((err:any) => {
    - 285                Trader.invalidateVenueID(item, venue.summary.venueID);
    - 286                console.log(`error in requestMeta ${item.symbol} for venue ${venue}: ${err}`);
    - 287                throw `error getting meta info for ${item.symbol}`;    
    - 288            });
    - 289        } else {
    - 290            throw `no venue defined for ${item.symbol}`;
    - 291        }
    - 292    }
    - 293
    - 294    public requestSymbols():Promise {
    - 295        return getVenue(0).requestSymbolsForVenue()
    - 296            .catch((err:any) => {
    - 297                console.log(`error in requestSymbols for venue ${getVenue(0)}: ${err}`);
    - 298                return getVenue(0).summary;
    - 299            });
    - 300    }
    - 301
    - 302    /*
    - 303
    - 304
    - 305
    - 306*/

    - 307}
    - 308
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/TraderIEX.html b/docs/src/hsStock/controller/TraderIEX.html deleted file mode 100644 index 450af28..0000000 --- a/docs/src/hsStock/controller/TraderIEX.html +++ /dev/null @@ -1,311 +0,0 @@ - - -

    controller/TraderIEX.ts

    -
       1import { TraderQuote,
    -   2         TraderReferences,
    -   3         TraderSymbol,
    -   4         TraderSplit,
    -   5         TraderProfile } from './Trader';
    -   6import { EquityItem }    from './Equity';
    -   7import { m }             from 'hslayout';
    -   8import { round }         from 'hsutil';
    -   9
    -  10interface IEXSymbols extends TraderSymbol {
    -  11    date:       string;
    -  12    isEnabled:  boolean;
    -  13    type:       string;     // refers to the common issue type of the stock. 
    -  14                            //  ad â€“ American Depository Receipt (ADR’s) 
    -  15                            //  re â€“ Real Estate Investment Trust (REIT’s) 
    -  16                            //  ce â€“ Closed end fund (Stock and Bond Fund) 
    -  17                            //  si â€“ Secondary Issue 
    -  18                            //  lp â€“ Limited Partnerships 
    -  19                            //  cs â€“ Common Stock 
    -  20                            //  et â€“ Exchange Traded Fund (ETF) 
    -  21                            //  (blank) = Not Available, i.e., Warrant, Note, or (non-filing) Closed Ended Funds
    -  22    iexId:      string;
    -  23}
    -  24
    -  25interface IEXMeta extends EquityItem {
    -  26    beta:               number; // 
    -  27    week52change:       number; // 
    -  28    shortInterest:      number; // 
    -  29    shortDate:          string; // 
    -  30    dividendRate:       number; // 
    -  31    dividendYield:      number; // 
    -  32    exDividendDate:     string; // 
    -  33    latestEPS:          number; // (Most recent quarter)
    -  34    latestEPSDate:      string; // 
    -  35    sharesOutstanding:  number; // 
    -  36    float:              number; // 
    -  37    returnOnEquity:     number; // (Trailing twelve months)
    -  38    consensusEPS:       number; // (Most recent quarter)
    -  39    numberOfEstimates:  number; // (Most recent quarter)
    -  40    EBITDA:             number; // (Trailing twelve months)
    -  41    revenue:            number; // (Trailing twelve months)
    -  42    grossProfit:        number; // (Trailing twelve months)
    -  43    cash:               number; // reers to total cash. (Trailing twelve months)
    -  44    debt:               number; // refers to total debt. (Trailing twelve months)
    -  45    ttmEPS:             number; // (Trailing twelve months)
    -  46    revenuePerShare:    number; // (Trailing twelve months)
    -  47    revenuePerEmployee: number; // (Trailing twelve months)
    -  48    peRatioHigh:        number; // 
    -  49    peRatioLow:         number; // 
    -  50    EPSSurpriseDollar:  number; // refers to the difference between actual EPS and consensus EPS in dollars.
    -  51    EPSSurprisePercent: number; // refers to the percent difference between actual EPS and consensus EPS.
    -  52    returnOnAssets:     number; // (Trailing twelve months)
    -  53    returnOnCapital:    number; // (Trailing twelve months)
    -  54    profitMargin:       number; // 
    -  55    priceToSales:       number; // 
    -  56    priceToBook:        number; // 
    -  57    day200MovingAvg:    number; // 
    -  58    day50MovingAvg:     number; // 
    -  59    institutionPercent: number; // represents top 15 institutions
    -  60    insiderPercent:     number; // 
    -  61    shortRatio:         number; // 
    -  62    year5ChangePercent: number; // 
    -  63    year2ChangePercent: number; // 
    -  64    year1ChangePercent: number; // 
    -  65    ytdChangePercent:   number; // 
    -  66    month6ChangePercent: number; // 
    -  67    month3ChangePercent: number; // 
    -  68    month1ChangePercent: number; // 
    -  69    day5ChangePercent:  number; // 
    -  70}
    -  71
    -  72
    -  73interface IEXQuote extends TraderQuote {
    -  74    change:         number;
    -  75    changeOverTime: number;
    -  76    changePercent:  number;
    -  77    label:          string; // "Oct 16"
    -  78    unadjustedVolume: number;
    -  79    vwap:           number;
    -  80}
    -  81
    -  82function processMarketsForLatestsUpdate(markets:any[]):Date {
    -  83    let maxDate:Date;
    -  84    markets.forEach((venue:any) => {
    -  85        const lastDate = new Date(venue.lastUpdated);
    -  86console.log(`venue '${venue.venueName}', ${round(venue.marketPercent*100, 2)}% of market, last traded at ${lastDate.toTimeString()}`);
    -  87        if (!maxDate || maxDate < lastDate) { maxDate =  lastDate; }
    -  88    });
    -  89    return maxDate;
    -  90}
    -  91
    -  92/**
    -  93 * https://iextrading.com/developer/docs/
    -  94 */

    -  95export class IexTrading implements TraderProfile {
    -  96    id = 'IEXTrading';
    -  97    base = 'https://api.iextrading.com/1.0';
    -  98    marketUpdateUrl = ()           => `${this.base}/market`;
    -  99    symbolsUrl      = ()           => `${this.base}/ref-data/symbols`;
    - 100    statsUrl        = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/stats`;
    - 101    metaUrl         = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/quote`;
    - 102    quoteUrl        = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/chart`;
    - 103    financialsUrl   = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/financials`;
    - 104    earningsUrl     = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/earnings`;
    - 105    dividendsUrl    = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/dividends/5y`;
    - 106    splitsUrl       = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/splits/5y`;
    - 107    logoUrl         = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/logo`;
    - 108    
    - 109    lastMarketUpdate(): Promise {
    - 110        return m.request({url:this.marketUpdateUrl()})
    - 111        .then(processMarketsForLatestsUpdate);
    - 112    }
    - 113
    - 114    normalizeStats = (data:any, item:EquityItem):EquityItem => {
    - 115//console.log(`receiving stock '${data.symbol}' stats`);   
    - 116        item.name                 = data.companyName;
    - 117        item.symbol               = data.symbol;
    - 118        item.cat                  = item.cat || 'Stocks';
    - 119        item.company              = item.company || {};
    - 120        item.stats                = item.stats || {};
    - 121        item.stats.week52high     = data.week52high;
    - 122        item.stats.week52low      = data.week52low;
    - 123        item.stats.latestEPS      = data.latestEPS;
    - 124        item.stats.latestEPSDate  = new Date(data.latestEPSDate);
    - 125        item.stats.marketCap      = data.marketcap;
    - 126        item.stats.cash           = data.cash;
    - 127        item.stats.revenue        = data.revenue;
    - 128        item.stats.EBITDA         = data.EBITDA;
    - 129        item.stats.exDividendDate = new Date(data.exDividendDate);
    - 130        item.stats.dividendRate   = data.dividendRate;
    - 131        item.stats.dividendYield  = data.dividendYield;
    - 132        item.otherStats = item.otherStats || {};
    - 133        delete data.otherStats;
    - 134        Object.keys(data).forEach((k:string) => ((item.stats[k]===undefined)? item.otherStats[k] = data[k] : ''));
    - 135        return item;
    - 136    }
    - 137
    - 138    normalizeMeta = (data:any, item:EquityItem):EquityItem => {
    - 139//console.log(`receiving stock '${data.symbol}' meta`);   
    - 140        item.name                    = data.companyName;
    - 141        item.symbol                  = data.symbol;
    - 142        item.cat                     = item.cat || 'Stocks';
    - 143        item.stats.latestDate        = data.latestTime? new Date(data.latestUpdate) : new Date();
    - 144        item.stats.latestPrice       = data.latestPrice;
    - 145        item.stats.closeDate         = new Date(data.closeTime);
    - 146        item.stats.closePrice        = data.close;
    - 147        item.stats.change            = data.change;
    - 148        item.company                 = item.company || {};
    - 149        item.company.sector          = data.sector;
    - 150        item.company.primaryExchange = data.primaryExchange;
    - 151        item.stats = item.stats || {};
    - 152        item.otherStats = item.otherStats || {};
    - 153        delete data.otherStats;
    - 154        Object.keys(data).forEach((k:string) => ((item.stats[k]===undefined)? item.otherStats[k] = data[k] : ''));
    - 155        return item;
    - 156    }
    - 157
    - 158    normalizeQuotes = (data:any[]):TraderQuote[] => {
    - 159        if (data) {
    - 160            data.sort((a:TraderQuote, b:TraderQuote) => Date.parse(a.Date) - Date.parse(b.Date));
    - 161        }
    - 162//console.log(`receiving stock quote for`);   
    - 163        return data;
    - 164    }
    - 165
    - 166    normalizeSymbols = (data:any[]):TraderReferences => {
    - 167        const result:TraderReferences = {symbols:[], names:[], equities:<{string:TraderSymbol}>{}};
    - 168        data.forEach((entry:any) => { 
    - 169            result.equities[`sym${entry.symbol}`] = entry; 
    - 170            result.symbols.push(entry.symbol);
    - 171            result.names.push(entry.name);
    - 172        });
    - 173        return result;
    - 174    }
    - 175
    - 176    normalizeSplits = (data:IEXSplit[]): TraderSplit[] => {
    - 177        if (data.length>0) {
    - 178            data.map((t:IEXSplit) => t.date = new Date(t.exDate));
    - 179            return data;
    - 180        }
    - 181        return undefined;
    - 182    }
    - 183};
    - 184
    - 185
    - 186interface IEXStat {
    - 187    companyName:            string;
    - 188    marketcap:              number; // is not calculated in real time.
    - 189    beta:                   number;
    - 190    week52high:             number;
    - 191    week52low:              number;
    - 192    week52change:           number;
    - 193    shortInterest:          number;
    - 194    shortDate:              string;
    - 195    dividendRate:           number;
    - 196    dividendYield:          number;
    - 197    exDividendDate:         string;
    - 198    latestEPS:              number; // (Most recent quarter)
    - 199    latestEPSDate:          string;
    - 200    sharesOutstanding:      number;
    - 201    float:                  number;
    - 202    returnOnEquity:         number; // (Trailing twelve months)
    - 203    consensusEPS:           number; // (Most recent quarter)
    - 204    numberOfEstimates:      number; // (Most recent quarter)
    - 205    symbol:                 string;
    - 206    EBITDA:                 number; // (Trailing twelve months)
    - 207    revenue:                number; // (Trailing twelve months)
    - 208    grossProfit:            number; // (Trailing twelve months)
    - 209    cash:                   number; // refers to total cash. (Trailing twelve months)
    - 210    debt:                   number; // refers to total debt. (Trailing twelve months)
    - 211    ttmEPS:                 number; // (Trailing twelve months)
    - 212    revenuePerShare:        number; // (Trailing twelve months)
    - 213    revenuePerEmployee:     number; // (Trailing twelve months)
    - 214    peRatioHigh:            number;
    - 215    peRatioLow:             number;
    - 216    EPSSurpriseDollar:      number; // refers to the difference between actual EPS and consensus EPS in dollars.
    - 217    EPSSurprisePercent:     number; // refers to the percent difference between actual EPS and consensus EPS.
    - 218    returnOnAssets:         number; // (Trailing twelve months)
    - 219    returnOnCapital:        number; // (Trailing twelve months)
    - 220    profitMargin:           number;
    - 221    priceToSales:           number;
    - 222    priceToBook:            number;
    - 223    day200MovingAvg:        number;
    - 224    day50MovingAvg:         number;
    - 225    institutionPercent:     number; // represents top 15 institutions
    - 226    insiderPercent:         number;
    - 227    shortRatio:             number;
    - 228    year5ChangePercent:     number;
    - 229    year2ChangePercent:     number;
    - 230    year1ChangePercent:     number;
    - 231    ytdChangePercent:       number;
    - 232    month6ChangePercent:    number;
    - 233    month3ChangePercent:    number;
    - 234    month1ChangePercent:    number;
    - 235    day5ChangePercent:      number;    
    - 236}
    - 237
    - 238interface IEXFinancials {
    - 239    reportDate:             string;
    - 240    grossProfit:            number;
    - 241    costOfRevenue:          number;
    - 242    operatingRevenue:       number;
    - 243    totalRevenue:           number;
    - 244    operatingIncome:        number;
    - 245    netIncome:              number;
    - 246    researchAndDevelopment: number;
    - 247    operatingExpense:       number;
    - 248    currentAssets:          number;
    - 249    totalAssets:            number;
    - 250    totalLiabilities:       number;
    - 251    currentCash:            number;
    - 252    currentDebt:            number;
    - 253    totalCash:              number;
    - 254    totalDebt:              number;
    - 255    shareholderEquity:      number;
    - 256    cashChange:             number;
    - 257    cashFlow:               number;
    - 258    operatingGainsLosses:   string;
    - 259}
    - 260
    - 261interface IEXEarnings {
    - 262    actualEPS:          number;
    - 263    consensusEPS:       number;
    - 264    estimatedEPS:       number;
    - 265    announceTime:       string;
    - 266    numberOfEstimates:  number;
    - 267    EPSSurpriseDollar:  number;
    - 268    EPSReportDate:      string;
    - 269    fiscalPeriod:       string;
    - 270    fiscalEndDate:      string;
    - 271}
    - 272
    - 273interface IEXDividends {
    - 274    exDate:         string; // refers to the dividend ex-date
    - 275    paymentDate:    string; // refers to the payment date
    - 276    recordDate:     string; // refers to the dividend record date
    - 277    declaredDate:   string; // refers to the dividend declaration date
    - 278    amount:         number; // refers to the payment amount
    - 279    type:           string; // refers to the dividend payment type (Dividend income, Interest income, Stock dividend, Short term capital gain, Medium term capital gain, Long term capital gain, Unspecified term capital gain)
    - 280    qualified:      string; // refers to the dividend income type 
    - 281                            // P = Partially qualified income 
    - 282                            // Q = Qualified income 
    - 283                            // N = Unqualified income 
    - 284                            // null = N/A or unknown
    - 285}
    - 286
    - 287export interface IEXSplit extends TraderSplit {
    - 288    exDate:         string; // refers to the split ex-date
    - 289    declaredDate:   string; // refers to the split declaration date
    - 290    recordDate:     string; // refers to the split record date
    - 291    paymentDate:    string; // refers to the split payment date
    - 292    toFactor:       string; // To factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    - 293    forFactor:      string; // For factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    - 294}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/Venue.html b/docs/src/hsStock/controller/Venue.html deleted file mode 100644 index 122e1b1..0000000 --- a/docs/src/hsStock/controller/Venue.html +++ /dev/null @@ -1,68 +0,0 @@ - - -

    controller/Venue.ts

    -
       1import { m }            from 'hslayout';
    -   2import { PacingQueue }  from 'hsutil';
    -   3import { TraderQuote,
    -   4         TraderIntraday,
    -   5         TraderSymbol } from './Trader';
    -   6import { EquityItem }   from './Equities';
    -   7import { EquitySplit }  from './Equities';
    -   8
    -   9
    -  10export enum VenueIDs {
    -  11    IEX = 'IEX'
    -  12}
    -  13
    -  14/** provides details on available equities for a venue */
    -  15export interface VenueSummary {
    -  16    venueID:    VenueIDs; 
    -  17    venueName:  string;
    -  18    symbols:    string[];
    -  19    names:      string[];
    -  20    equities:   {string:TraderSymbol};  // sym -> TraderSymbol
    -  21}
    -  22
    -  23
    -  24export abstract class Venue {
    -  25    protected static queue = new PacingQueue(10);
    -  26    protected static addPacedGet(url:string): Promise {
    -  27//console.log(`${new Date().getTime()%10000}: addPacedGet requesting ${url}`);
    -  28        return Venue.queue.add((ms:number) => {
    -  29//            console.log(`${new Date().getTime()%10000}: pacedGet(after ${ms} ms) requesting ${url}`);
    -  30            return m.request({url:url})
    -  31                .then((data:any) => {
    -  32                    console.log(`     ${new Date().getTime()%10000}: pacedGet received data from ${url}`);
    -  33                    return data;
    -  34                })
    -  35                .catch((err:any) => {
    -  36                    console.log(`*** ${new Date().getTime()%10000}: pacedGet error ${err} from ${url}`);
    -  37                });
    -  38        });
    -  39    }
    -  40
    -  41    constructor() {}
    -  42
    -  43    summary:        VenueSummary;
    -  44
    -  45    abstract requestMarketUpdate(): Promise;
    -  46    abstract requestMetaVenue(item:EquityItem):Promise;
    -  47    abstract requestQuotesVenue(item:EquityItem, missingDays:number):Promise;
    -  48    abstract requestIntradayVenue(item:EquityItem):Promise;
    -  49    abstract requestSplitsVenue(item:EquityItem):Promise;
    -  50    abstract requestSymbolsForVenue():Promise;
    -  51}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/controller/VenueIEX.html b/docs/src/hsStock/controller/VenueIEX.html deleted file mode 100644 index 41b6adc..0000000 --- a/docs/src/hsStock/controller/VenueIEX.html +++ /dev/null @@ -1,416 +0,0 @@ - - -

    controller/VenueIEX.ts

    -
       1import { TraderQuote,
    -   2         TraderIntraday,
    -   3         TraderSymbol}      from './Trader';
    -   4import { VenueIDs,
    -   5         VenueSummary,
    -   6         Venue }   from './Venue';
    -   7import { EquityItem }       from './Equities';
    -   8import { EquitySplit }      from './Equities';
    -   9import { round }            from 'hsutil';
    -  10
    -  11
    -  12/**
    -  13 * # IEX Trading Venue.
    -  14 * https://iextrading.com/developer/docs/
    -  15 * 
    -  16 * Behaves passively, i.e. does not initiate any server calls without explicit requests.
    -  17 * All methods initating requests are named `request***`
    -  18 */

    -  19export class IexVenue extends Venue {
    -  20    private static base        = 'https://api.iextrading.com/1.0';
    -  21    private static symbolsUrl  =                 `${IexVenue.base}/ref-data/symbols`;
    -  22    private static marketUpdateUrl = ()       => `${IexVenue.base}/market`;
    -  23    private static quoteUrl    = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/chart`;
    -  24    private static splitsUrl   = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/splits/5y`;
    -  25    private static statsUrl    = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/stats`;
    -  26    private static metaUrl     = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/quote`;
    -  27//    private financialsUrl   = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/financials`;
    -  28//    private earningsUrl     = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/earnings`;
    -  29//    private dividendsUrl    = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/dividends/5y`;
    -  30//    private logoUrl         = (sym:string) => `${IexVenue.base}/stock/${encodeURIComponent(sym)}/logo`;
    -  31
    -  32    private static newSummary():VenueSummary {
    -  33       return {
    -  34            venueID:    VenueIDs.IEX, 
    -  35            venueName: 'IEXTrading',
    -  36            symbols:    [],
    -  37            names:      [],
    -  38            equities:   <{string:TraderSymbol}>{}
    -  39        };
    -  40    }
    -  41
    -  42    private static normalizeMeta (data:any, item:EquityItem):EquityItem {
    -  43        if (data) {
    -  44            item.name                    = data.companyName;
    -  45            item.symbol                  = data.symbol;
    -  46            item.cat                     = item.cat || 'Stocks';
    -  47            item.stats.latestDate        = data.latestTime? new Date(data.latestUpdate) : new Date();
    -  48            item.stats.latestPrice       = data.latestPrice;
    -  49            item.stats.closeDate         = new Date(data.closeTime);
    -  50            item.stats.closePrice        = data.close;
    -  51            item.stats.change            = data.change;
    -  52            item.company                 = item.company || {};
    -  53            item.company.sector          = data.sector;
    -  54            item.company.primaryExchange = data.primaryExchange;
    -  55            item.stats = item.stats || {};
    -  56            item.otherStats = item.otherStats || {};
    -  57            delete data.otherStats;
    -  58            Object.keys(data).forEach((k:string) => ((item.stats[k]===undefined)? item.otherStats[k] = data[k] : ''));
    -  59        }
    -  60        return item;
    -  61    }
    -  62
    -  63    private static normalizeStats = (data:any, item:EquityItem):EquityItem => {
    -  64        item.name                 = data.companyName || 'unkown company';
    -  65        item.symbol               = data.symbol;
    -  66        item.cat                  = item.cat || 'Stocks';
    -  67        item.company              = item.company || {};
    -  68        item.stats                = item.stats || {};
    -  69        item.stats.week52high     = data.week52high;
    -  70        item.stats.week52low      = data.week52low;
    -  71        item.stats.latestEPS      = data.latestEPS;
    -  72        item.stats.latestEPSDate  = new Date(data.latestEPSDate);
    -  73        item.stats.marketCap      = data.marketcap;
    -  74        item.stats.cash           = data.cash;
    -  75        item.stats.revenue        = data.revenue;
    -  76        item.stats.EBITDA         = data.EBITDA;
    -  77        item.stats.exDividendDate = new Date(data.exDividendDate);
    -  78        item.stats.dividendRate   = data.dividendRate;
    -  79        item.stats.dividendYield  = data.dividendYield;
    -  80        item.otherStats = item.otherStats || {};
    -  81        delete data.otherStats;
    -  82        Object.keys(data).forEach((k:string) => ((item.stats[k]===undefined)? item.otherStats[k] = data[k] : ''));
    -  83        return item;
    -  84    }
    -  85
    -  86    private static normalizeQuotes(data:any[]):TraderQuote[] {
    -  87        return data
    -  88            .filter((d:any) => d.date)   // remove nulls
    -  89            .map((d:any) => {
    -  90                return {
    -  91                    Date:   new Date(d.date),
    -  92                    high:   parseFloat(d.high),
    -  93                    low:    parseFloat(d.low),
    -  94                    open:   parseFloat(d.open),  
    -  95                    close:  parseFloat(d.close),
    -  96                    volume: parseFloat(d.volume)
    -  97                };
    -  98            }); // sorting willbe done in Trader
    -  99    }
    - 100
    - 101    private static normalizeIntraday(data:any[]):TraderIntraday[] {
    - 102        return !data? [] : 
    - 103            data.filter((d:any) => d.date && d.minute)   // remove nulls
    - 104                .filter((d:any) => d.marketVolume>0)
    - 105                .map((d:any) => {
    - 106                    return {
    - 107                        Date: new Date(d.date.slice(0,4), d.date.slice(4,6)-1, d.date.slice(-2), d.minute.slice(0,2), d.minute.slice(-2)),
    - 108                        high: parseFloat(d.marketHigh),
    - 109                        low:  parseFloat(d.marketLow)
    - 110                    };
    - 111                }); // sorting willbe done in Trader
    - 112    }
    - 113
    - 114    private static normalizeSplits(data:IEXSplit[]): EquitySplit[] {
    - 115        if (data && data.length>0) {
    - 116            data.map((t:IEXSplit) => t.date = new Date(t.exDate));
    - 117            return data;
    - 118        }
    - 119        return undefined;
    - 120    }
    - 121
    - 122    private static processMarketsForLatestUpdate(markets:any[]):Date {
    - 123        let maxDate:Date;
    - 124        let maxMarket = '??';
    - 125        markets.forEach((venue:any) => {
    - 126            const lastDate = new Date(venue.lastUpdated);
    - 127console.log(`venue '${venue.venueName}', ${round(venue.marketPercent*100, 2)}% of market, last traded at ${lastDate.toTimeString()}`);
    - 128            if (!maxDate || maxDate < lastDate) { 
    - 129                maxDate =  lastDate; 
    - 130                maxMarket = venue.venueName;
    - 131            }
    - 132        });
    - 133console.log('latest update: ${maxDate} on ${maxMarket}');
    - 134        return maxDate;
    - 135    }
    - 136
    - 137    private normalizeSymbols = (data:string[]):VenueSummary => {
    - 138console.log(`found ${data.length} symbols for ${this.summary.venueName}`);        
    - 139        data.forEach((entry:any) => { 
    - 140            this.summary.equities[`sym${entry.symbol}`] = entry; 
    - 141            this.summary.symbols.push(entry.symbol);
    - 142            this.summary.names.push(entry.name);
    - 143        });
    - 144        return this.summary;
    - 145    }
    - 146
    - 147
    - 148    constructor() {
    - 149        super();
    - 150        this.summary = IexVenue.newSummary();
    - 151    }
    - 152
    - 153    /** retrieves the date and time of the most recent transaction on 
    - 154     * any of the markets supported by the venue */

    - 155    requestMarketUpdate(): Promise {
    - 156        return Venue.addPacedGet(IexVenue.marketUpdateUrl())
    - 157        .then(IexVenue.processMarketsForLatestUpdate);
    - 158    }
    - 159
    - 160    requestMetaVenue(item:EquityItem):Promise {
    - 161        function request(url:string, type:string, normalize:(data:any, item:EquityItem)=>EquityItem): Promise {
    - 162            return Venue.addPacedGet(url)
    - 163                .then((data:any) => {
    - 164                    if(!data) { throw `no data for request ${url}`; }
    - 165                    return normalize(data, item);
    - 166                });
    - 167        }
    - 168
    - 169        const stats = IexVenue.statsUrl(item.symbol);
    - 170        const meta  = IexVenue.metaUrl(item.symbol);
    - 171        return Promise.resolve()
    - 172        .then(() => request(stats, 'stats', IexVenue.normalizeStats))
    - 173        .catch((err:any) => {
    - 174            console.log(`*** error in request stats for ${stats}: ${err}`);
    - 175        })
    - 176        .then(() => request(meta, 'meta', IexVenue.normalizeMeta));
    - 177    }
    - 178
    - 179    requestQuotesVenue(item:EquityItem, missingDays:number):Promise {
    - 180        let timeCode;
    - 181//        if (!item.quotes || item.quotes.rows.length === 0) {
    - 182//            timeCode = '5yr';
    - 183//        } else {
    - 184            if (missingDays > 1)    { timeCode = '1m'; }
    - 185            if (missingDays > 28)   { timeCode = '3m'; }
    - 186            if (missingDays > 80)   { timeCode = '6m'; }
    - 187//            if (missingDays > 170)  { timeCode = '1yr'; }
    - 188//            if (missingDays > 360)  { timeCode = '2yr'; }
    - 189//            if (missingDays > 720)  { timeCode = '5yr'; }
    - 190//        }
    - 191    
    - 192        const url = IexVenue.quoteUrl(item.symbol)+'/'+ timeCode;
    - 193        return (!timeCode)? 
    - 194            Promise.resolve([]) :
    - 195            Venue.addPacedGet(url).then(IexVenue.normalizeQuotes);
    - 196    }
    - 197
    - 198    requestIntradayVenue(item:EquityItem):Promise {
    - 199        const url = IexVenue.quoteUrl(item.symbol)+'/1d';
    - 200        return Venue.addPacedGet(url)
    - 201            .then(IexVenue.normalizeIntraday);
    - 202    }
    - 203
    - 204    requestSplitsVenue(item:EquityItem):Promise {
    - 205        const url = IexVenue.splitsUrl(item.symbol);
    - 206        return Venue.addPacedGet(url)
    - 207            .then(IexVenue.normalizeSplits);
    - 208    }
    - 209
    - 210    requestSymbolsForVenue():Promise {
    - 211        const url = IexVenue.symbolsUrl;
    - 212console.log(`getting Trader symbols ${url}`);        
    - 213        return Venue.addPacedGet(url)
    - 214            .then(this.normalizeSymbols);
    - 215    }
    - 216};
    - 217
    - 218
    - 219interface IEXSymbols extends TraderSymbol {
    - 220    date:       string;
    - 221    isEnabled:  boolean;
    - 222    type:       string;     // refers to the common issue type of the stock. 
    - 223                            //  ad â€“ American Depository Receipt (ADR’s) 
    - 224                            //  re â€“ Real Estate Investment Trust (REIT’s) 
    - 225                            //  ce â€“ Closed end fund (Stock and Bond Fund) 
    - 226                            //  si â€“ Secondary Issue 
    - 227                            //  lp â€“ Limited Partnerships 
    - 228                            //  cs â€“ Common Stock 
    - 229                            //  et â€“ Exchange Traded Fund (ETF) 
    - 230                            //  (blank) = Not Available, i.e., Warrant, Note, or (non-filing) Closed Ended Funds
    - 231    iexId:      string;
    - 232}
    - 233
    - 234interface IEXMeta extends EquityItem {
    - 235    beta:               number; // 
    - 236    week52change:       number; // 
    - 237    shortInterest:      number; // 
    - 238    shortDate:          string; // 
    - 239    dividendRate:       number; // 
    - 240    dividendYield:      number; // 
    - 241    exDividendDate:     string; // 
    - 242    latestEPS:          number; // (Most recent quarter)
    - 243    latestEPSDate:      string; // 
    - 244    sharesOutstanding:  number; // 
    - 245    float:              number; // 
    - 246    returnOnEquity:     number; // (Trailing twelve months)
    - 247    consensusEPS:       number; // (Most recent quarter)
    - 248    numberOfEstimates:  number; // (Most recent quarter)
    - 249    EBITDA:             number; // (Trailing twelve months)
    - 250    revenue:            number; // (Trailing twelve months)
    - 251    grossProfit:        number; // (Trailing twelve months)
    - 252    cash:               number; // reers to total cash. (Trailing twelve months)
    - 253    debt:               number; // refers to total debt. (Trailing twelve months)
    - 254    ttmEPS:             number; // (Trailing twelve months)
    - 255    revenuePerShare:    number; // (Trailing twelve months)
    - 256    revenuePerEmployee: number; // (Trailing twelve months)
    - 257    peRatioHigh:        number; // 
    - 258    peRatioLow:         number; // 
    - 259    EPSSurpriseDollar:  number; // refers to the difference between actual EPS and consensus EPS in dollars.
    - 260    EPSSurprisePercent: number; // refers to the percent difference between actual EPS and consensus EPS.
    - 261    returnOnAssets:     number; // (Trailing twelve months)
    - 262    returnOnCapital:    number; // (Trailing twelve months)
    - 263    profitMargin:       number; // 
    - 264    priceToSales:       number; // 
    - 265    priceToBook:        number; // 
    - 266    day200MovingAvg:    number; // 
    - 267    day50MovingAvg:     number; // 
    - 268    institutionPercent: number; // represents top 15 institutions
    - 269    insiderPercent:     number; // 
    - 270    shortRatio:         number; // 
    - 271    year5ChangePercent: number; // 
    - 272    year2ChangePercent: number; // 
    - 273    year1ChangePercent: number; // 
    - 274    ytdChangePercent:   number; // 
    - 275    month6ChangePercent: number; // 
    - 276    month3ChangePercent: number; // 
    - 277    month1ChangePercent: number; // 
    - 278    day5ChangePercent:  number; // 
    - 279}
    - 280
    - 281
    - 282interface IEXQuote extends TraderQuote {
    - 283    change:         number;
    - 284    changeOverTime: number;
    - 285    changePercent:  number;
    - 286    label:          string; // "Oct 16"
    - 287    unadjustedVolume: number;
    - 288    vwap:           number;
    - 289}
    - 290
    - 291interface IEXStat {
    - 292    companyName:            string;
    - 293    marketcap:              number; // is not calculated in real time.
    - 294    beta:                   number;
    - 295    week52high:             number;
    - 296    week52low:              number;
    - 297    week52change:           number;
    - 298    shortInterest:          number;
    - 299    shortDate:              string;
    - 300    dividendRate:           number;
    - 301    dividendYield:          number;
    - 302    exDividendDate:         string;
    - 303    latestEPS:              number; // (Most recent quarter)
    - 304    latestEPSDate:          string;
    - 305    sharesOutstanding:      number;
    - 306    float:                  number;
    - 307    returnOnEquity:         number; // (Trailing twelve months)
    - 308    consensusEPS:           number; // (Most recent quarter)
    - 309    numberOfEstimates:      number; // (Most recent quarter)
    - 310    symbol:                 string;
    - 311    EBITDA:                 number; // (Trailing twelve months)
    - 312    revenue:                number; // (Trailing twelve months)
    - 313    grossProfit:            number; // (Trailing twelve months)
    - 314    cash:                   number; // refers to total cash. (Trailing twelve months)
    - 315    debt:                   number; // refers to total debt. (Trailing twelve months)
    - 316    ttmEPS:                 number; // (Trailing twelve months)
    - 317    revenuePerShare:        number; // (Trailing twelve months)
    - 318    revenuePerEmployee:     number; // (Trailing twelve months)
    - 319    peRatioHigh:            number;
    - 320    peRatioLow:             number;
    - 321    EPSSurpriseDollar:      number; // refers to the difference between actual EPS and consensus EPS in dollars.
    - 322    EPSSurprisePercent:     number; // refers to the percent difference between actual EPS and consensus EPS.
    - 323    returnOnAssets:         number; // (Trailing twelve months)
    - 324    returnOnCapital:        number; // (Trailing twelve months)
    - 325    profitMargin:           number;
    - 326    priceToSales:           number;
    - 327    priceToBook:            number;
    - 328    day200MovingAvg:        number;
    - 329    day50MovingAvg:         number;
    - 330    institutionPercent:     number; // represents top 15 institutions
    - 331    insiderPercent:         number;
    - 332    shortRatio:             number;
    - 333    year5ChangePercent:     number;
    - 334    year2ChangePercent:     number;
    - 335    year1ChangePercent:     number;
    - 336    ytdChangePercent:       number;
    - 337    month6ChangePercent:    number;
    - 338    month3ChangePercent:    number;
    - 339    month1ChangePercent:    number;
    - 340    day5ChangePercent:      number;    
    - 341}
    - 342
    - 343interface IEXFinancials {
    - 344    reportDate:             string;
    - 345    grossProfit:            number;
    - 346    costOfRevenue:          number;
    - 347    operatingRevenue:       number;
    - 348    totalRevenue:           number;
    - 349    operatingIncome:        number;
    - 350    netIncome:              number;
    - 351    researchAndDevelopment: number;
    - 352    operatingExpense:       number;
    - 353    currentAssets:          number;
    - 354    totalAssets:            number;
    - 355    totalLiabilities:       number;
    - 356    currentCash:            number;
    - 357    currentDebt:            number;
    - 358    totalCash:              number;
    - 359    totalDebt:              number;
    - 360    shareholderEquity:      number;
    - 361    cashChange:             number;
    - 362    cashFlow:               number;
    - 363    operatingGainsLosses:   string;
    - 364}
    - 365
    - 366interface IEXEarnings {
    - 367    actualEPS:          number;
    - 368    consensusEPS:       number;
    - 369    estimatedEPS:       number;
    - 370    announceTime:       string;
    - 371    numberOfEstimates:  number;
    - 372    EPSSurpriseDollar:  number;
    - 373    EPSReportDate:      string;
    - 374    fiscalPeriod:       string;
    - 375    fiscalEndDate:      string;
    - 376}
    - 377
    - 378interface IEXDividends {
    - 379    exDate:         string; // refers to the dividend ex-date
    - 380    paymentDate:    string; // refers to the payment date
    - 381    recordDate:     string; // refers to the dividend record date
    - 382    declaredDate:   string; // refers to the dividend declaration date
    - 383    amount:         number; // refers to the payment amount
    - 384    type:           string; // refers to the dividend payment type (Dividend income, Interest income, Stock dividend, Short term capital gain, Medium term capital gain, Long term capital gain, Unspecified term capital gain)
    - 385    qualified:      string; // refers to the dividend income type 
    - 386                            // P = Partially qualified income 
    - 387                            // Q = Qualified income 
    - 388                            // N = Unqualified income 
    - 389                            // null = N/A or unknown
    - 390}
    - 391
    - 392export interface IEXSplit extends EquitySplit {
    - 393    exDate:         string; // refers to the split ex-date
    - 394    declaredDate:   string; // refers to the split declaration date
    - 395    recordDate:     string; // refers to the split record date
    - 396    paymentDate:    string; // refers to the split payment date
    - 397    toFactor:       string; // To factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    - 398    forFactor:      string; // For factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    - 399}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/fileIO.html b/docs/src/hsStock/fileIO.html deleted file mode 100644 index ab2c084..0000000 --- a/docs/src/hsStock/fileIO.html +++ /dev/null @@ -1,49 +0,0 @@ - - -

    fileIO.ts

    -
       1
    -   2import { m }            from 'hslayout';
    -   3
    -   4const SAVE_URL          = '/cgi/save.js';
    -   5
    -   6export function save(data:any, fname:string):Promise {
    -   7    return m.request({
    -   8        method: 'PUT',
    -   9        url: `${SAVE_URL}?name=${fname}`,   // fname relative to 'apps/
    -  10        data: data
    -  11    })
    -  12    .then(() => data)                       // send `data` into next `then`
    -  13    .catch((err:any) => {
    -  14        console.log(`error saving to ${fname}`);
    -  15        console.log(err);
    -  16        console.log(err.stack);
    -  17        return data;
    -  18    });
    -  19}
    -  20
    -  21export function load(fname:string):Promise {
    -  22    return m.request({
    -  23        method: 'GET',
    -  24        url: fname                          // relative to 'apps//
    -  25    })
    -  26    .catch((err:any):null => {
    -  27        console.log(`error loading ${fname}`);
    -  28        return null;
    -  29    });
    -  30}
    -  31
    -  32
    - - \ No newline at end of file diff --git a/docs/src/hsStock/index.html b/docs/src/hsStock/index.html deleted file mode 100644 index 01b4587..0000000 --- a/docs/src/hsStock/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - -

    index.ts

    -
       1/**
    -   2 * Progam entry point. Initiates loading the docsets and setting up a router structure
    -   3 */

    -   4
    -   5/** */
    -   6
    -   7import * as Router from './Router';
    -   8if (Router) {}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/overview.html b/docs/src/hsStock/overview.html deleted file mode 100644 index 533da82..0000000 --- a/docs/src/hsStock/overview.html +++ /dev/null @@ -1,23 +0,0 @@ - - -

    overview.ts

    -
       1/**
    -   2# hsStock
    -   3
    -   4*/

    -   5
    -   6/** */
    - - \ No newline at end of file diff --git a/docs/src/hsStock/saveToFile.html b/docs/src/hsStock/saveToFile.html deleted file mode 100644 index e5a386c..0000000 --- a/docs/src/hsStock/saveToFile.html +++ /dev/null @@ -1,36 +0,0 @@ - - -

    saveToFile.ts

    -
       1
    -   2import { m }            from 'hslayout';
    -   3
    -   4const SAVE_URL          = '/cgi/save.js';
    -   5
    -   6export function save(data:any, fname:string):Promise {
    -   7    return m.request({
    -   8        method: 'PUT',
    -   9        url: `${SAVE_URL}?name=${fname}`,   // fname relative to 'apps/
    -  10        data: data
    -  11    })
    -  12    .then(() => data)                       // send `data` into next `then`
    -  13    .catch((err:any) => {
    -  14        console.log(`error saving to ${fname}`);
    -  15        console.log(err);
    -  16        console.log(err.stack);
    -  17        return data;
    -  18    });
    -  19}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/server/convertInvestments.html b/docs/src/hsStock/server/convertInvestments.html deleted file mode 100644 index 8be6bd7..0000000 --- a/docs/src/hsStock/server/convertInvestments.html +++ /dev/null @@ -1,20 +0,0 @@ - - -

    server/convertInvestments.ts

    -
       1import { hsNode } from 'hsnode';
    -   2
    -   3console.log(hsNode);
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/Equity.html b/docs/src/hsStock/view/Equity.html deleted file mode 100644 index 965e2a3..0000000 --- a/docs/src/hsStock/view/Equity.html +++ /dev/null @@ -1,242 +0,0 @@ - - -

    view/Equity.ts

    -
       1import { m }            from 'hslayout';
    -   2import { Data,
    -   3         DataSet }      from 'hsgraph';
    -   4import { Trader,
    -   5         TraderQuote }  from './Trader';
    -   6
    -   7const DEF_EQUITY_LIST   = 'defEquityList.json';
    -   8const EQUITY_LIST       = 'equityList.json';
    -   9const SAVE_URL          = '../../cgi-bin/save.js';
    -  10
    -  11export interface Category {
    -  12    cat:      string;         // the category name
    -  13    equities: EquityItem[];   // array of equities in this category
    -  14}
    -  15
    -  16export interface EquityItem {
    -  17    /** equity symbol, e.g. 'GOOG' */
    -  18    symbol: string; 
    -  19    /** equity name, e.g. 'Alphabet' */
    -  20    name:   string;
    -  21    /** investment category, e.g. 'Stocks' */
    -  22    cat:    string;
    -  23
    -  24    company?: {
    -  25        /** industry sector */
    -  26        sector?:    string;
    -  27        /** primary trading exchange */
    -  28        primaryExchange?: string;
    -  29    };
    -  30
    -  31    stats?: {
    -  32        /** price-to-earnings ratio */
    -  33        peRatio?:           number;
    -  34        /** 52 week high */
    -  35        week52high?:        number;
    -  36        /** 52 week low */
    -  37        week52low?:         number;
    -  38        /** market capitalziation */
    -  39        marketCap?:         number;
    -  40        /** latest Earnings per Share */
    -  41        latestEPS?:         number;
    -  42        /** date of latest Earnings per Share */
    -  43        latestEPSDate?:     string;
    -  44        /** dividend rate */
    -  45        dividendRate?:      number;
    -  46        /** dividend rate */
    -  47        dividendYield?:     number; 
    -  48        /** date of dividend */
    -  49        exDividendDate?:    string;
    -  50    };
    -  51    quotes?: Data;
    -  52    otherStats?:  {};
    -  53}
    -  54
    -  55export class EquityList {
    -  56    //------  private  parts -----
    -  57    private bySymbol   = <{string: EquityItem}>{};
    -  58    private categories = [];
    -  59    private trader: Trader;
    -  60
    -  61    private addCategory(cat:string) {
    -  62        if (!this.categories[cat]) {
    -  63            const category:Category = { cat: cat, equities: [] };
    -  64            this.categories.push(category);
    -  65            this.categories[cat] = category;
    -  66        }
    -  67    }
    -  68
    -  69    private unkownEquity() { return {cat:'unknown Cat', symbol:'????', name:'unknown'}; }
    -  70
    -  71    private JSON2EquityList(data:any):EquityList {
    -  72        if (!data) { console.log('no data in JSON2EquityList'); }
    -  73        else {
    -  74            Object.keys(data).forEach((k:string) => {
    -  75                this.addCategory(k);
    -  76                Object.keys(data[k]).forEach((e:string) => {
    -  77                    this.add({ symbol: e, name: data[k][e], cat: k, stats:{}, company:{}});
    -  78                });
    -  79            });   
    -  80        }
    -  81        return this;
    -  82    }
    -  83
    -  84    private EquityList2JSON():any {
    -  85        const data:any = {};
    -  86        this.categories.forEach((c:Category) => {
    -  87            data[c.cat] = {};
    -  88            c.equities.forEach((e:EquityItem) => {
    -  89                data[c.cat][e.symbol] = e.name;
    -  90            });
    -  91        });
    -  92        return data;
    -  93    }
    -  94
    -  95    private add(item:EquityItem) {
    -  96        const sym = item.symbol.toUpperCase();
    -  97        if (!this.bySymbol[sym]) {
    -  98            this.bySymbol[sym] = item;
    -  99            if (!this.categories[item.cat]) { this.addCategory(item.cat); }
    - 100            this.categories[item.cat].equities.push(item);
    - 101        }
    - 102        this.loadMeta(item);
    - 103    };
    - 104
    - 105    private remove(itemOrSymbol:EquityItem|string) {
    - 106        const item = (typeof itemOrSymbol === 'string')? 
    - 107            this.bySymbol[itemOrSymbol.toUpperCase()] : this.bySymbol[(itemOrSymbol).symbol];
    - 108        this.bySymbol[item.symbol.toUpperCase()] = undefined;
    - 109        const i = this.categories[item.cat].equities.indexOf(item);
    - 110        if (i>=0) { this.categories[item.cat].equities.splice(i,1); }
    - 111    }
    - 112
    - 113    //------  public parts -----
    - 114
    - 115    constructor() {
    - 116        this.trader = new Trader();
    - 117    }
    - 118
    - 119    getItem(symbol:string):EquityItem { 
    - 120        if (this.bySymbol[symbol]) { 
    - 121            return this.bySymbol[symbol]; 
    - 122        }
    - 123        if (this.categories.length > 0) { 
    - 124            if (this.categories[0].equities.length > 0) { 
    - 125                return this.categories[0].equities[0]; 
    - 126            }
    - 127        }
    - 128        return this.unkownEquity();
    - 129    }
    - 130    getCategories():Category[] { return this.categories; }
    - 131    getFirstByCat(cat:string):EquityItem {
    - 132        const c = this.categories[cat];
    - 133        if (c && c.equities.length>0) { return c.equities[0]; }
    - 134        else { return this.unkownEquity(); }
    - 135    }
    - 136
    - 137    addItem(item:EquityItem) {
    - 138        this.add(item);
    - 139        this.saveEquityList();
    - 140    }
    - 141    removeItem(itemOrSymbol:EquityItem|string) {
    - 142        this.remove(itemOrSymbol);
    - 143        this.saveEquityList();
    - 144    }
    - 145    load(fname:string):Promise {
    - 146        return m.request({
    - 147            method: 'GET',
    - 148            url: 'data/'+fname                  // relative to 'apps//
    - 149        });
    - 150    }
    - 151    save(data:any, fname:string):Promise {
    - 152        return m.request({
    - 153            method: 'POST',
    - 154            url: `${SAVE_URL}?name=${fname}`,   // relative to 'apps//data/
    - 155            data: data
    - 156        })
    - 157        .then(() => data)                       // send `data` into next `then`
    - 158        .catch((err:any) => {
    - 159            console.log(`error saving to ${fname}`);
    - 160            console.log(err);
    - 161            console.log(err.stack);
    - 162            return data;
    - 163        });
    - 164    }
    - 165    loadEquityList():Promise {
    - 166        return this.load(EQUITY_LIST)
    - 167        .catch(() => this.load(DEF_EQUITY_LIST))
    - 168        .then((data:any) => this.JSON2EquityList.call(this, data));
    - 169    }
    - 170    saveEquityList():Promise {
    - 171        return this.save(this.EquityList2JSON.call(this), EQUITY_LIST);
    - 172    }
    - 173    loadMeta(item:EquityItem):Promise {
    - 174        return this.load(`stock/sym${item.symbol}.json`)
    - 175        .catch(() => 
    - 176            this.trader.getMeta(item.symbol)
    - 177            .then((data:EquityItem) => { 
    - 178                this.saveMeta(data, item.symbol);
    - 179                return data;
    - 180            }))
    - 181        .then((data:EquityItem) => {
    - 182            if (!data) { console.log('no data in JSON2EquityList'); }
    - 183            else {
    - 184                Object.keys(data).forEach((k:string) => item[k] = data[k]);
    - 185            }
    - 186            return item;
    - 187        });
    - 188    }
    - 189    saveMeta(data:any, sym:string):Promise {
    - 190        console.log(`saving stock/sym${sym}.json`);
    - 191        return this.save(data, `stock/sym${sym}.json`);
    - 192    }
    - 193    loadQuotes(item:EquityItem):Promise {
    - 194        const traderQuote2Dataset = (dataIn:TraderQuote[]) => {
    - 195            const dataOut:Data = new Data();
    - 196            dataOut.setData(
    - 197                dataIn.map((e: TraderQuote) => [e.date, e.open, e.close, e.high, e.low, e.volume]), 
    - 198                ['Date', 'Open', 'Close', 'High', 'Low', 'Volume']);
    - 199            return dataOut;
    - 200        };
    - 201        if (item.quotes && item.quotes.getData().length>0) {
    - 202            return Promise.resolve(item);
    - 203        } else {
    - 204            return this.load(`stock/quotes${item.symbol}.json`)
    - 205            .then((data:DataSet) => { 
    - 206                item.quotes = new Data(data);
    - 207                return item;
    - 208            })
    - 209            .catch(() => 
    - 210                this.trader.getQuotes(item, '5y')
    - 211                .then(traderQuote2Dataset)
    - 212                .then((data:Data) => {
    - 213                    item.quotes = data;
    - 214                    this.saveQuotes(item);
    - 215                    return item;
    - 216                })
    - 217            );
    - 218        }
    - 219    }
    - 220    saveQuotes(item:EquityItem):Promise {
    - 221        return this.save(item.quotes.export(), `stock/quotes${item.symbol}.json`);
    - 222    }
    - 223}
    - 224
    - 225
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/Header.html b/docs/src/hsStock/view/Header.html deleted file mode 100644 index c3fd6db..0000000 --- a/docs/src/hsStock/view/Header.html +++ /dev/null @@ -1,31 +0,0 @@ - - -

    view/Header.ts

    -
       1import { m, Vnode}  from 'hslayout';
    -   2import { Layout }   from 'hslayout';
    -   3import { Menu }     from 'hswidget';
    -   4
    -   5export class Header extends Layout {
    -   6    getComponents(node: Vnode): Vnode {
    -   7        const r = node.attrs.route;
    -   8        return m(Menu, {desc: { 
    -   9            items: ['View', 'Trade', 'Import'].map((c:any) => c),
    -  10            selectedItem: (r && r.mode)? r.mode : 0,
    -  11            select: (item:string) => m.route.set('/api/:mode/0', {mode:item}) 
    -  12        }});
    -  13    }     
    -  14}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/Import.html b/docs/src/hsStock/view/Import.html deleted file mode 100644 index cd9564e..0000000 --- a/docs/src/hsStock/view/Import.html +++ /dev/null @@ -1,71 +0,0 @@ - - -

    view/Import.ts

    -
       1import { m }            from 'hslayout';
    -   2import { EquityList }   from './Equity';
    -   3import { Trader }       from './Trader';
    -   4import { Button }       from 'hswidget';
    -   5
    -   6
    -   7let Symbols:string[] = []; 
    -   8
    -   9const trader = new Trader();
    -  10
    -  11export function tabImport(list:EquityList, symbol:string) {
    -  12    return m('.hs-left-nav', buttons(list));
    -  13}
    -  14
    -  15function buttons(list:EquityList) {
    -  16    function stockImport() {
    -  17        list.load('symbolList.json')
    -  18        .then((sList:string[]) => {
    -  19            function next(i:number) {
    -  20                trader.getMeta(sList[i])
    -  21                .then((data:any) => {
    -  22                    list.save(data, `stocks/sym${sList[i]}.json`);
    -  23                    return i;
    -  24                })
    -  25                .then((i:number) => {
    -  26                    if (i -  27                })
    -  28                .catch((err:any) => console.log(`i=${i}, sym=${sList[i]}, err=${err}`));
    -  29            }
    -  30            next(0);
    -  31        });   
    -  32    } 
    -  33
    -  34    function loadSymbols() {
    -  35        trader.getSymbols()
    -  36        .then((data:any) => {
    -  37            list.save(data.list, 'symbolList.json');
    -  38            Symbols = data.list;
    -  39            return data;
    -  40        })
    -  41        .then((data:any) => {
    -  42            list.save(data.set, 'symbolSet.json');
    -  43            return data;
    -  44        });
    -  45    }
    -  46
    -  47    return [
    -  48        m(Button, {name:'IEX Import', onclick:loadSymbols}),
    -  49        m(Button, {name:'Stock Import', onclick:stockImport}),
    -  50        m('', `${Symbols.length} records loaded`)
    -  51    ];
    -  52}
    -  53
    -  54
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/ImportPane.html b/docs/src/hsStock/view/ImportPane.html deleted file mode 100644 index 755c024..0000000 --- a/docs/src/hsStock/view/ImportPane.html +++ /dev/null @@ -1,65 +0,0 @@ - - -

    view/ImportPane.ts

    -
       1import { m, Vnode }         from 'hslayout';
    -   2import { Layout }           from 'hslayout';
    -   3import { gEquities,
    -   4         Equities }         from '../controller/Equities';
    -   5import { Button }           from 'hswidget';
    -   6import { VenueSummary }     from '../controller/Venue';
    -   7import { save }             from '../fileIO';
    -   8
    -   9
    -  10let Symbols:string[] = []; 
    -  11
    -  12export const ImportPane = {
    -  13    view: (node: Vnode): Vnode => {
    -  14        return m(Layout, {
    -  15            rows: ['50px'],
    -  16            css: '.hs-import-pane',
    -  17            content: buttons(gEquities)
    -  18        });
    -  19    }    
    -  20};
    -  21
    -  22
    -  23function buttons(list:Equities) {
    -  24    return [
    -  25        m(Button, {name:'get IEX Symbols', onclick:readSymbols}),
    -  26        m(Button, {name:'get Stock Splits', onclick:readSplits}),
    -  27//        m(Button, {name:'clear invalid venues', onclick:gEquities.clearInvalids.bind(gEquities)}),
    -  28        m(Button, {name:'Stock Import'}),
    -  29        m(Button, { 
    -  30//            style: 'left:150px; width:70px;',
    -  31            name: 'Update',
    -  32            onclick: () => gEquities.getMarketUpdate()            
    -  33        }),
    -  34        m('', `${Symbols.length} records loaded`)
    -  35    ];
    -  36}
    -  37
    -  38function readSplits() {
    -  39    gEquities.readSplits(); 
    -  40}
    -  41
    -  42function readSymbols() {
    -  43    gEquities.getVenueSymbols()
    -  44    .then((ref:VenueSummary) => {
    -  45        save(ref.equities, `hsStock/data/traderSymbols.json`);
    -  46    });
    -  47}
    -  48
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/LeftNav.html b/docs/src/hsStock/view/LeftNav.html deleted file mode 100644 index 686f6b1..0000000 --- a/docs/src/hsStock/view/LeftNav.html +++ /dev/null @@ -1,45 +0,0 @@ - - -

    view/LeftNav.ts

    -
       1import { Vnode}      from 'hslayout';
    -   2import { Layout }    from 'hslayout';
    -   3import { tabView }      from './ViewPane';
    -   4import { tabTrade }     from './TradePane';
    -   5import { tabImport }    from './ImportPane';
    -   6import { gEquityList }  from '../Site';
    -   7
    -   8export class LeftNav extends Layout { 
    -   9    getComponents(node: Vnode): Vnode {
    -  10        let mode:string = 'View';
    -  11        let symbol:string;
    -  12        let list = gEquityList;
    -  13        if (node.attrs && node.attrs.route) {
    -  14            mode = node.attrs.route.mode;
    -  15            symbol = node.attrs.route.symbol;
    -  16        }
    -  17        let content = '???';
    -  18        switch(mode) {
    -  19            case 'Import':  content = tabImport(list, symbol); break;
    -  20            case 'Trade':   content = tabTrade(list, symbol); break;
    -  21            case 'View':
    -  22            default:        content = tabView(list, symbol);
    -  23        }
    -  24        return content;
    -  25    }     
    -  26
    -  27
    -  28
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/Main.html b/docs/src/hsStock/view/Main.html deleted file mode 100644 index 6707903..0000000 --- a/docs/src/hsStock/view/Main.html +++ /dev/null @@ -1,85 +0,0 @@ - - -

    view/Main.ts

    -
       1import { m, Vnode}      from 'hslayout';
    -   2import { Layout }       from 'hslayout';
    -   3import { Graph,
    -   4         DataSet, 
    -   5         Series,
    -   6         Axes }         from 'hsgraph';
    -   7import { Collapsible,
    -   8         Button }       from 'hswidget';
    -   9import { EquityItem }   from './Equity';
    -  10import { gEquityList }  from '../Site';
    -  11
    -  12export class MainDetails extends Layout {
    -  13    getComponents(node: Vnode): Vnode {
    -  14        let symbol:string;
    -  15        let list = gEquityList;
    -  16        if (node.attrs && node.attrs.route) {
    -  17            symbol = node.attrs.route.symbol;
    -  18        }
    -  19        const item:EquityItem = list.getItem(symbol);
    -  20        return m('.hs-equity-detail', [
    -  21            m('.hs-equity-name', item.name),
    -  22            m('.hs-equity-symbol', item.symbol),
    -  23            m('.hs-equity-cat', item.cat),
    -  24            m('.hs-equity-cat', item.stats.peRatio),
    -  25            m('.hs-equity-cat', item.stats.week52high),
    -  26            m('.hs-equity-cat', item.stats.week52low),
    -  27            m('.hs-equity-cat', item.stats.marketCap),
    -  28            m('.hs-equity-cat', item.company.sector),
    -  29            m('.hs-equity-cat', item.company.primaryExchange),
    -  30            m('.hs-equity-cat', `${item.quotes?item.quotes.getData().length:0} quotes`)
    -  31        ]);
    -  32    }     
    -  33
    -  34
    -  35export class MainGraph extends Layout {
    -  36    getComponents(node: Vnode): Vnode {
    -  37        let symbol:string;
    -  38        let list = gEquityList;
    -  39        if (node.attrs && node.attrs.route) {
    -  40            symbol = node.attrs.route.symbol;
    -  41        }
    -  42        const item = list.getItem(symbol);
    -  43        const data:DataSet = item.quotes? item.quotes.export() : {names:['Date', 'Close'], rows:[['1/1/17',0], ['12/31/17', 1]]};
    -  44        return [m(Graph, {cfgFn: (cfg:any) => {
    -  45                cfg.chart.title.visible = false;
    -  46                cfg.axes.primary.x.scale.type = Axes.type.date;
    -  47                cfg.axes.primary.x.title.visible = false;
    -  48                cfg.axes.primary.x.scale.domain = ['auto', new Date()]; // always up to today
    -  49                cfg.axes.primary.y.scale.type = Axes.type.log;
    -  50                cfg.axes.primary.y.scale.domain = ['tight', 'tight']; // always up to today
    -  51                cfg.axes.primary.y.title.visible = false;
    -  52                cfg.axes.primary.y.ticks.minor.labels.visible = true;
    -  53                cfg.grid.minor.hor.visible = true;
    -  54                cfg.series.data   = data;
    -  55                cfg.series.defaultStyle.line.width = 1;
    -  56                cfg.series.series = [
    -  57                    { cols: ['Date', 'Close'], type: Series.plot.line },
    -  58                    { cols: ['Date', 'High'], type: Series.plot.line }
    -  59                ];
    -  60            }}),
    -  61            m(Collapsible, {css:'hs-stock-setting-overlay', components: [
    -  62                m('', 'Options:'),
    -  63                [m(Button, { name: 'option 1'}), m('', 'option 2')]
    -  64            ]})
    -  65        ];
    -  66    }     
    -  67
    -  68
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/MainDetails.html b/docs/src/hsStock/view/MainDetails.html deleted file mode 100644 index 390138d..0000000 --- a/docs/src/hsStock/view/MainDetails.html +++ /dev/null @@ -1,145 +0,0 @@ - - -

    view/MainDetails.ts

    -
       1import { m, Vnode}      from 'hslayout';
    -   2import { Layout }       from 'hslayout';
    -   3import { gEquities,
    -   4         EquityItem }   from '../controller/Equities';
    -   5import { date, round }  from 'hsutil'; 
    -   6
    -   7const format = (n:number):string => {
    -   8    let result = ''+n;
    -   9    const limits =  [1000000000, 1000000, 1000, 1, 0.001, 0.000001, 0.000000001];
    -  10    const postfix = [' B',       ' M',    ' k', '', ' m',     ' Âµ',        ' n'];
    -  11
    -  12    limits.some((v:number, i:number) => {
    -  13        if (n>v) { 
    -  14            result = Math.round(n/v*10)/10+postfix[i];
    -  15            return true;
    -  16        }
    -  17        return false;
    -  18    });
    -  19    return result;
    -  20};
    -  21
    -  22/**
    -  23 * ## 
    -  24 */

    -  25export class CycleThrough {
    -  26    static state = {};
    -  27    static create(key:string, ...args:string[]) {
    -  28        return new CycleThrough(key, args);
    -  29    }
    -  30    key:string;
    -  31    args: string[];
    -  32    private constructor(key:string, args:string[]) {
    -  33        this.active = args[1]!==undefined;
    -  34        this.key    = key;
    -  35        this.args   = args;
    -  36    }
    -  37
    -  38    public active:boolean;
    -  39    public next = () => !this.active? '' : (CycleThrough.state[this.key] = ((CycleThrough.state[this.key] || 0)+1) % this.args.length);
    -  40    public get val() { return this.args[CycleThrough.state[this.key] || 0]; }
    -  41}
    -  42
    -  43function ellipses(str:string, limit:number):string { 
    -  44    return !str? str :
    -  45        str.length -  46}
    -  47
    -  48export class MainDetails extends Layout { 
    -  49    getComponents(node: Vnode): Vnode {
    -  50        const symbol  = m.route.param('symbol');
    -  51        const item:EquityItem = gEquities.getItem(symbol);
    -  52        const s = item.stats || {};
    -  53        const c = item.company || {};
    -  54        const divDate = (s.dividendRate && s.exDividendDate)? date('%MM/%D/%YY', new Date(s.exDividendDate)) : '';
    -  55        const pe = s.peRatio || round((s.latestPrice || 0) / s.latestEPS, 3);
    -  56        const latestDate = date('%MM/%DD/%YY: ', new Date(s.latestDate));
    -  57        const latestEPSDate = s.latestEPSDate? date('%MM/%D/%YY', new Date(s.latestEPSDate)) : '1/1/1970';
    -  58        const latestEPS     = s.latestEPS? `$${s.latestEPS}`: '--';
    -  59        const latestEPSRate = s.latestEPS? `${round(100*s.latestEPS/s.latestPrice,3)}%`: '--';
    -  60        const week52high    = s.week52high? `$${s.week52high}` : '--';
    -  61        const week52hgRatio = s.week52high? `${round(100*s.week52high/s.latestPrice,3)}%`: '--';
    -  62        const week52low     = s.week52low? `$${s.week52low}` : '--';
    -  63        const week52lwRatio = s.week52low? `${round(100*s.week52low/s.latestPrice,3)}%`: '--';
    -  64        const cols = [{ 
    -  65            css:'', 
    -  66            fields: [
    -  67                [`${item.cat}:`,                        ellipses(c.sector, 18)],
    -  68                ['Exchange:',                           ellipses(c.primaryExchange, 18)],
    -  69                ['Invested:',                           `${item.shares} shares`, `$${format(item.shares*(s.latestPrice || 0))}`]
    -  70        ]},{ 
    -  71            css:'', 
    -  72            fields: [
    -  73                ['Market Cap',                          `$${format(s.marketCap)}`],
    -  74                ['Revenue:',                            `$${format(s.revenue)}`],
    -  75                ['Profits:',                            `$${format(s.EBITDA)}`],
    -  76                ['Cash:',                               `$${format(s.cash)}`]
    -  77        ]},{ 
    -  78            css:'', 
    -  79            fields: [
    -  80                ['PE:',                                 `${pe || '--'}`],
    -  81                ['52 wk high:',                         week52high, week52hgRatio],
    -  82                ['52 wk low:',                          week52low,  week52lwRatio],
    -  83                ['Volume (shares):',                    `${format(s.closeVolume) || '--'}`]
    -  84        ]},{ 
    -  85            css:'.hs-equity-right-column', 
    -  86            fields: [
    -  87                [`Dividend ${divDate}:`,    `$${s.dividendRate}`,  `${round(s.dividendYield,3)}%`],
    -  88                [`EPS ${latestEPSDate}:`,   latestEPS, latestEPSRate]
    -  89        ]}];
    -  90        const change = CycleThrough.create('change', `$${s.change}`, `${round(100*s.change/s.latestPrice,3)}%`, 'hehe');
    -  91        return m(Layout, {
    -  92            css: '.hs-equity-detail',
    -  93            rows: ['30px', '80px'],
    -  94            content: [
    -  95                m(Layout, {
    -  96                    columns:['fill', '250px'],
    -  97                    content: [
    -  98                        m('span.hs-equity', [
    -  99                            m('span.hs-equity-name', item.name),
    - 100                            m('span.hs-equity-symbol', item.symbol)
    - 101                        ]),
    - 102                        m('span.hs-equity .hs-align-right', [
    - 103                            m('span', `${latestDate}`),
    - 104                            m('span.hs-equity-close', `$${s.latestPrice || 0}`),
    - 105                            m(`span.hs-equity-change ${s.change<0? '.hs-negative': '.hs-positive'} ${change.active?'.hs-link':''}`, {onclick: change.next}, `${change.val}`)
    - 106                        ])
    - 107                    ]
    - 108                }),
    - 109                m(Layout, {
    - 110                    css: '.hs-equity-detail-column',
    - 111                    columns:[],
    - 112                    content: cols.map((c:any, col:number) => m(Layout, {
    - 113                        columns:[],
    - 114                        content: [
    - 115                            m('', c.fields.map((e:[string, string]) => m('.hs-equity-cat', e[0]))),
    - 116                            m('', c.fields.map((e:[string, string], idx:number) => {
    - 117                                const t = CycleThrough.create(`${col}${idx}`, e[1], e[2]);
    - 118                                return m(`.hs-equity-cat .hs-align-right ${t.active?'.hs-link':''} ${c.css}`, {onclick: t.next}, t.val);
    - 119                            })) 
    - 120                        ]
    - 121                    }))
    - 122                })
    - 123            ]
    - 124        });
    - 125    }     
    - 126
    - 127
    - 128
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/MainGraph.html b/docs/src/hsStock/view/MainGraph.html deleted file mode 100644 index d5d86b1..0000000 --- a/docs/src/hsStock/view/MainGraph.html +++ /dev/null @@ -1,121 +0,0 @@ - - -

    view/MainGraph.ts

    -
       1import { m, Vnode}      from 'hslayout';
    -   2import { Layout }       from 'hslayout';
    -   3import { Data,
    -   4         DataSet }      from 'hsdata';
    -   5import { Condition }    from 'hsdata';
    -   6import { 
    -   7//         Button,
    -   8         ToggleButton } from 'hswidget';
    -   9import { Graph,
    -  10         Series,
    -  11         Axes }         from 'hsgraph';
    -  12import { gEquities,
    -  13         EquityItem }   from '../controller/Equities';
    -  14
    -  15let limitDateIndex = 0;
    -  16
    -  17function getLimitDate(time:string):Date {
    -  18    const result = new Date();
    -  19    switch (time) {
    -  20        case 'max':  result.setFullYear(result.getFullYear()-30); break;
    -  21        case '40yr': result.setFullYear(result.getFullYear()-40); break;
    -  22        case '20yr': result.setFullYear(result.getFullYear()-20); break;
    -  23        case '10yr': result.setFullYear(result.getFullYear()-10); break;
    -  24        case '5yr':  result.setFullYear(result.getFullYear()-5); break;
    -  25        case '1yr':  result.setFullYear(result.getFullYear()-1); break;
    -  26        case '3mo':  result.setMonth(result.getMonth()-(3+result.getMonth()%3)); break;
    -  27        case '1mo':  result.setMonth(result.getMonth()-1); break;
    -  28        case '10d':  result.setDate(result.getDate()-10); break;
    -  29        case '1d':   result.setDate(result.getDate()-1); break;
    -  30    }
    -  31    result.setHours(0);
    -  32    return result;
    -  33}
    -  34
    -  35export class MainGraph extends Layout { 
    -  36    getComponents(node: Vnode): Vnode { 
    -  37        const timeWindows = ['1yr', '3mo', '1mo', '10d', '1d', '40yr', '20yr', '10yr', '5yr'];
    -  38        const limitDates = timeWindows.map(getLimitDate);
    -  39        let limitDate = limitDates[limitDateIndex];
    -  40console.log(`time ${limitDateIndex}: ${timeWindows[limitDateIndex]} ${limitDate.toDateString()}`);        
    -  41        let maxDate = new Date();
    -  42        const symbol = m.route.param('symbol');
    -  43        const item:EquityItem = gEquities.getItem(symbol);
    -  44        if (timeWindows[limitDateIndex]==='1d' && item.intraday) {
    -  45            limitDate = item.intraday.rows[0][0]; // the date
    -  46            maxDate = item.intraday.rows[item.intraday.rows.length-1][0];
    -  47        }
    -  48        const dataQuotes:DataSet = item.quotes? item.quotes : 
    -  49            {name:'Quotes', colNames:['Date', 'Close'], rows:[]};
    -  50        const dataIntra:DataSet = item.intraday? item.intraday : 
    -  51            {name:'Intraday', colNames:['Date', 'Close'], rows:[[]]};
    -  52        const shares:DataSet = Data.toDataSet(item.trades, 'Shares');
    -  53        const buyCond:Condition = { change: (c:number) => c>0};
    -  54        const sellCond:Condition = { change: (c:number) => c<0};
    -  55        const timeCond:Condition = { Date: (d:Date) => d>limitDate};
    -  56        return [m('.hs-layout-fill', { onmousemove:console.log}, m(Graph, { cfgFn: (cfg:any) => {
    -  57            cfg.graph.timeCond = timeCond;
    -  58            cfg.chart.title.visible = false;
    -  59            cfg.axes.primary.x.scale.type = Axes.type.date;
    -  60            cfg.axes.primary.x.title.visible = false;
    -  61            cfg.axes.primary.x.scale.domain = ['auto', 'tight']; // always up to today
    -  62            cfg.axes.primary.y.scale.type = Axes.type.log;
    -  63            cfg.axes.primary.y.scale.domain = ['tight', 'tight']; // always up to today
    -  64            cfg.axes.primary.y.title.visible = false;
    -  65            cfg.axes.primary.y.ticks.minor.labels.visible = true;
    -  66            cfg.grid.minor.hor.visible = true;
    -  67            cfg.series.data   = [dataQuotes, shares, dataIntra];
    -  68            cfg.series.defaultStyle.line.width = 1;
    -  69            cfg.series.series = [
    -  70                { x:'Date', y:'High', yBase:'Low', type: 'area', dataIndex:timeWindows[limitDateIndex]==='1d'?2:0},
    -  71                { x:'Date', y:'Close', type: 'line' },
    -  72                { x:'Date', y:'price', l:'change', type: 'marker', dataIndex:1, cond:buyCond },
    -  73                { x:'Date', y:'price', l:'change', type: 'marker', dataIndex:1, cond:sellCond }
    -  74            ];
    -  75            cfg.series.series[0].style.fill.color = '#ccf';
    -  76            cfg.series.series[1].style.line.color = '#008';
    -  77            cfg.series.series[2].style.line.visible = false;
    -  78            cfg.series.series[2].style.marker.shape = Series.marker.upTriangle;
    -  79            cfg.series.series[2].style.marker.color = '#0c0';
    -  80            cfg.series.series[2].style.label.color = '#0c0';
    -  81            cfg.series.series[2].style.marker.size = 8;
    -  82            cfg.series.series[2].vOffset = 5;   // em
    -  83            cfg.series.series[3].style.line.visible = false;
    -  84            cfg.series.series[3].style.marker.shape = Series.marker.downTriangle;
    -  85            cfg.series.series[3].style.marker.color = '#a00';
    -  86            cfg.series.series[3].style.label.color = '#a00';
    -  87            cfg.series.series[3].style.marker.size = 8;
    -  88            cfg.series.series[3].vOffset = 5;   // em 
    -  89        }})),
    -  90        m(ToggleButton, { 
    -  91            style: 'left:100px; width:35px;',
    -  92            desc: {
    -  93                items:timeWindows, 
    -  94                selectedItem: timeWindows[limitDateIndex],
    -  95                changed: (item:string) => {
    -  96                    const i = (timeWindows.indexOf(item) + 1) % timeWindows.length;
    -  97                    limitDateIndex = i;
    -  98                }
    -  99            }
    - 100        })
    - 101        ];
    - 102    }     
    - 103
    - 104
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/MainMenu.html b/docs/src/hsStock/view/MainMenu.html deleted file mode 100644 index b2eff78..0000000 --- a/docs/src/hsStock/view/MainMenu.html +++ /dev/null @@ -1,31 +0,0 @@ - - -

    view/MainMenu.ts

    -
       1import { m, Vnode}  from 'hslayout';
    -   2import { Layout }   from 'hslayout';
    -   3import { Menu }     from 'hswidget';
    -   4
    -   5export class MainMenu extends Layout {
    -   6    getComponents(node: Vnode): Vnode {
    -   7        const r = node.attrs.route;
    -   8        return m(Menu, {desc: { 
    -   9            items: ['View', 'Trade', 'Import'].map((c:any) => c),
    -  10            selectedItem: (r && r.mode)? r.mode : 0,
    -  11            select: (item:string) => m.route.set('/api/:mode/0', {mode:item}) 
    -  12        }});
    -  13    }     
    -  14}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/Modal.html b/docs/src/hsStock/view/Modal.html deleted file mode 100644 index 9d6395a..0000000 --- a/docs/src/hsStock/view/Modal.html +++ /dev/null @@ -1,31 +0,0 @@ - - -

    view/Modal.ts

    -
       1import { m, Vnode}      from 'hslayout';
    -   2
    -   3
    -   4export class Modal {
    -   5    private static modal:Vnode; 
    -   6    public static show() { Modal.modal = m(Modal); }
    -   7    view(node:Vnode) {
    -   8        return m('.hs-modal-frame', !Modal.modal? '': [
    -   9            m('.hs-modal-background', { onclick: () => { Modal.modal=undefined; }}, ''),
    -  10            m('.hs-modal-foreground', 'the form')
    -  11        ]);
    -  12    }
    -  13}
    -  14
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/SiteMenu.html b/docs/src/hsStock/view/SiteMenu.html deleted file mode 100644 index 6027c2b..0000000 --- a/docs/src/hsStock/view/SiteMenu.html +++ /dev/null @@ -1,31 +0,0 @@ - - -

    view/SiteMenu.ts

    -
       1import { m, Vnode}  from 'hslayout';
    -   2import { Layout }   from 'hslayout';
    -   3import { Menu }     from 'hswidget';
    -   4
    -   5export class SiteMenu extends Layout {
    -   6    getComponents(node: Vnode): Vnode {
    -   7        const r = node.attrs.route;
    -   8        return m(Menu, {desc: { 
    -   9            items: ['View', 'Trade', 'Import'].map((c:any) => c),
    -  10            selectedItem: (r && r.mode)? r.mode : 0,
    -  11            select: (item:string) => m.route.set('/api/:mode/0', {mode:item}) 
    -  12        }});
    -  13    }     
    -  14}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/StockQuotes.html b/docs/src/hsStock/view/StockQuotes.html deleted file mode 100644 index 3ddb85f..0000000 --- a/docs/src/hsStock/view/StockQuotes.html +++ /dev/null @@ -1,103 +0,0 @@ - - -

    view/StockQuotes.ts

    -
       1import { m }  from 'hslayout';
    -   2
    -   3/**
    -   4 * https://iextrading.com/developer/docs/
    -   5 */

    -   6const iexTrading = {
    -   7    base: 'https://api.iextrading.com/1.0',
    -   8    symbolsUrl: () => `${iexTrading.base}/ref-data/symbols`,
    -   9    metaUrl:   (sym:string) => `${iexTrading.base}/stock/${encodeURIComponent(sym)}/quote`,
    -  10    quoteUrl:   (sym:string) => `${iexTrading.base}/stock/${encodeURIComponent(sym)}/chart`,
    -  11    
    -  12    normalizeMeta: (data:any) => {
    -  13console.log('receiving stock meta');   
    -  14        const meta = {
    -  15            name:       data.companyName,
    -  16            symbol:     data.symbol,
    -  17            pe:         data.peRatio,
    -  18            week52High: data.week52High,
    -  19            week52Low:  data.week52Low,
    -  20            open:       data.open,
    -  21            close:      data.close,
    -  22            marketCap:  data.marketCap,
    -  23            sector:     data.sector,
    -  24            primaryExchange:  data.primaryExchange,
    -  25            change:     data.change
    -  26        };
    -  27        return meta;
    -  28    },
    -  29
    -  30    normalizeQuotes: (data:any) => {
    -  31console.log('receiving stock quote');   
    -  32        return data;
    -  33    },
    -  34
    -  35    normalizeSymbols: (data:any) => {
    -  36        const result = {list:[], set:{}};
    -  37        data.forEach((entry:any) => { 
    -  38            result.set[`sym${entry.symbol}`] = entry; 
    -  39            result.list.push(entry.symbol);
    -  40        });
    -  41        return result;
    -  42    }
    -  43};
    -  44
    -  45
    -  46export function getQuotes(sym:string):Promise {
    -  47    return m.request({
    -  48        method: 'GET',
    -  49        url: iexTrading.quoteUrl(sym)
    -  50    })
    -  51    .then(iexTrading.normalizeQuotes)
    -  52    .then((r:string) => {
    -  53        console.log(`load result: ${r}`);
    -  54    })
    -  55    .catch((err:any) => {
    -  56        console.log(`error requesting ${this.url}`);
    -  57        console.log(err);
    -  58        console.log(err.stack);
    -  59    });
    -  60}
    -  61
    -  62export function getMeta(sym:string):Promise {
    -  63    return m.request({
    -  64        method: 'GET',
    -  65        url: iexTrading.metaUrl(sym)
    -  66    })
    -  67    .then(iexTrading.normalizeMeta)
    -  68    .catch((err:any) => {
    -  69        console.log(`error requesting ${this.url}`);
    -  70        console.log(err);
    -  71        console.log(err.stack);
    -  72    });
    -  73}
    -  74
    -  75export function getSymbols():Promise {
    -  76    return m.request({
    -  77        method: 'GET',
    -  78        url: iexTrading.symbolsUrl()
    -  79    })
    -  80    .then(iexTrading.normalizeSymbols)
    -  81    .catch((err:any) => {
    -  82        console.log(`error requesting ${this.url}`);
    -  83        console.log(err);
    -  84        console.log(err.stack);
    -  85    });
    -  86}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/Trade.html b/docs/src/hsStock/view/Trade.html deleted file mode 100644 index 488856c..0000000 --- a/docs/src/hsStock/view/Trade.html +++ /dev/null @@ -1,24 +0,0 @@ - - -

    view/Trade.ts

    -
       1import { m }            from 'hslayout';
    -   2import { EquityList }   from './Equity';
    -   3
    -   4export function tabTrade(list:EquityList, symbol:string) {
    -   5    return m('.hs-left-nav', 'Trade...');
    -   6}
    -   7
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/TradePane.html b/docs/src/hsStock/view/TradePane.html deleted file mode 100644 index c1f9584..0000000 --- a/docs/src/hsStock/view/TradePane.html +++ /dev/null @@ -1,128 +0,0 @@ - - -

    view/TradePane.ts

    -
       1import { m, Vnode }     from 'hslayout';
    -   2import { Layout }       from 'hslayout';
    -   3import { Data }         from 'hsdata';
    -   4import { Graph,
    -   5         SeriesDef,
    -   6         Axes }         from 'hsgraph';
    -   7import { gEquities,
    -   8         Category,
    -   9         EquityItem }   from '../controller/Equities';
    -  10import { Transaction }  from '../controller/Assets';
    -  11
    -  12
    -  13export const TradePane = {
    -  14    view: (node: Vnode): Vnode => {
    -  15        return m(Layout, {
    -  16            columns: [],
    -  17            css: '.hs-trade-pane',
    -  18            content: [m(EquityShare)]
    -  19        });
    -  20    }    
    -  21};
    -  22/*
    -  23function getInvestments2():[Data, Data] {
    -  24    let investment = new Data({ colNames: ['Date', 'Total'], rows: [], name:'Investments'});
    -  25    let categories = new Data({ colNames: ['Date', 'Total'], rows: [], name:'Categories' });
    -  26
    -  27    // create columns
    -  28    gEquities.getCategories().map((cat:Category)=>{
    -  29        categories.colAdd(cat.cat);
    -  30        cat.equities.map((item:EquityItem) => investment.colAdd(item.symbol) );
    -  31    });
    -  32
    -  33    
    -  34    investment.sort('ascending', 'Date');
    -  35    categories.sort('ascending', 'Date');
    -  36    return [investment, categories];
    -  37}
    -  38*/

    -  39function getInvestments():[Data, Data] {
    -  40    let investment = new Data({ colNames: ['Date', 'Total'], rows: [], name:'Investments'});
    -  41    let categories = new Data({ colNames: ['Date', 'Total'], rows: [], name:'Categories' });
    -  42
    -  43    // create columns
    -  44    gEquities.getCategories().map((cat:Category)=>{
    -  45        categories.colAdd(cat.cat);
    -  46        cat.equities.map((item:EquityItem) => investment.colAdd(item.symbol) );
    -  47    });
    -  48
    -  49    // fill columns
    -  50    const dateCol = investment.colNumber('Date');
    -  51    const totalCol = investment.colNumber('Total');
    -  52    const investRows = investment.export().rows;
    -  53    const categRows  = categories.export().rows;
    -  54    gEquities.getCategories().map((cat:Category)=>{
    -  55        const catCol = categories.colNumber(cat.cat);
    -  56        cat.equities.map((item:EquityItem) => {
    -  57            const symCol = investment.colNumber(item.symbol);
    -  58            if (item.trades) {
    -  59                item.trades.map((trade:Transaction) => {
    -  60                    const invRow:any[] = investment.export().colNames.map(()=>undefined);
    -  61                    const catRow:any[] = categories.export().colNames.map(()=>undefined);
    -  62                    const value = trade.total * trade.price;
    -  63                    invRow[dateCol]  = trade.Date;
    -  64                    catRow[dateCol]  = trade.Date;
    -  65                    invRow[symCol]   = value;
    -  66                    catRow[catCol]   = value;
    -  67                    invRow[totalCol] = value;
    -  68                    catRow[totalCol] = value;
    -  69                    investRows.push(invRow);
    -  70                    categRows.push(catRow);
    -  71                });
    -  72            }
    -  73        });
    -  74    });
    -  75    investment.sort('ascending', 'Date');
    -  76    categories.sort('ascending', 'Date');
    -  77    return [investment, categories];
    -  78}
    -  79
    -  80
    -  81class EquityShare extends Layout {
    -  82    getComponents(node: Vnode): Vnode { 
    -  83        const impute = (val:number, c:number, i:number, rows:any[][]) =>
    -  84            (val !== null && val !== undefined)? val : ((i>0)? rows[i-1][c] : 0);
    -  85
    -  86        let [investment, categories] = getInvestments();
    -  87        const show = ['cats', 'stocks'][0];
    -  88        let dataSet = show==='cats'? categories : investment;
    -  89
    -  90        const names = dataSet.colNames();
    -  91        names.shift(); // remove Date
    -  92        dataSet = dataSet.map(names, impute); // all cols except Date
    -  93        names.shift(); // remove Total
    -  94
    -  95        return [m('.hs-layout-fill', { onmousemove:console.log}, m(Graph, { cfgFn: (cfg:any) => {
    -  96            cfg.series.data   = [dataSet];
    -  97            cfg.series.series = names.map((n:string, i:number):SeriesDef => {
    -  98                return { x:'Date', y:n, map:'shared', type: 'area'};
    -  99            });
    - 100            cfg.axes.primary.x.scale.type = Axes.type.date;
    - 101//            cfg.axes.primary.y.scale.type = Axes.type.percent;
    - 102            cfg.axes.primary.x.title.visible = false;
    - 103            cfg.axes.primary.x.scale.domain = ['tight', 'tight']; // always up to today
    - 104            cfg.axes.primary.y.scale.domain = [0, 1]; // always up to today
    - 105//            .concat([
    - 106//                { x:'Date', y:'Total', type: 'line' }
    - 107//            ]);
    - 108        }}))];
    - 109    }
    - 110}
    - 111
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/Trader.html b/docs/src/hsStock/view/Trader.html deleted file mode 100644 index e9e5e51..0000000 --- a/docs/src/hsStock/view/Trader.html +++ /dev/null @@ -1,110 +0,0 @@ - - -

    view/Trader.ts

    -
       1import { m }                from 'hslayout';
    -   2import { TraderReferences }    from './Trader';
    -   3import { IexTrading }       from './TraderIEX';
    -   4import { EquityItem }       from './Equity';
    -   5
    -   6
    -   7
    -   8export interface TraderQuote {
    -   9    close:          number;
    -  10    date:           string;
    -  11    high:           number;
    -  12    low:            number;
    -  13    open:           number;
    -  14    volume:         number;
    -  15}
    -  16
    -  17export interface TraderProfile {
    -  18    base: string;
    -  19    symbolsUrl:                 () => string;
    -  20    statsUrl:         (sym:string) => string;
    -  21    metaUrl:          (sym:string) => string;
    -  22    quoteUrl:         (sym:string) => string;
    -  23    normalizeStats:     (data:any) => EquityItem;
    -  24    normalizeMeta:      (data:any) => EquityItem;
    -  25    normalizeQuotes:  (data:any[]) => TraderQuote[];
    -  26    normalizeSymbols: (data:any[]) => TraderReferences;
    -  27}
    -  28
    -  29export interface TraderSymbol {
    -  30    symbol: string;
    -  31    name:   string;
    -  32    
    -  33}
    -  34
    -  35export interface TraderReferences {
    -  36    symbols:    string[];
    -  37    names:      string[];
    -  38    equities:   {string:TraderSymbol};
    -  39}
    -  40
    -  41export class Trader {
    -  42    private trader: TraderProfile;
    -  43    constructor(trader='iexTrading') { 
    -  44        switch (trader) {
    -  45            case 'iexTrading':
    -  46            default: this.trader = new IexTrading(); 
    -  47        }
    -  48    }
    -  49
    -  50    getQuotes(item:EquityItem, date:string):Promise {
    -  51        const url = this.trader.quoteUrl(item.symbol)+'/'+ date;
    -  52        return m.request({ method: 'GET', url: url })
    -  53        .then(this.trader.normalizeQuotes)
    -  54        .catch((err:any) => {
    -  55            console.log(`error requesting ${url}`);
    -  56            console.log(err);
    -  57            console.log(err.stack);
    -  58        });
    -  59    }
    -  60
    -  61    getMeta(sym:string):Promise {
    -  62        let item:EquityItem;
    -  63        return m.request({ method: 'GET', url: this.trader.statsUrl(sym) })
    -  64        .then(this.trader.normalizeStats)
    -  65        .then((meta:EquityItem) => item = meta)
    -  66        .catch((err:any) => {
    -  67            console.log(`error requesting ${this.trader.metaUrl(sym)}`);
    -  68            console.log(err);
    -  69            console.log(err.stack);
    -  70        })
    -  71        .then(() => m.request({ method: 'GET', url: this.trader.metaUrl(sym) }))
    -  72        .then(this.trader.normalizeMeta)
    -  73        .then((meta:EquityItem) => item.company = meta.company)
    -  74        .catch((err:any) => {
    -  75            console.log(`error requesting ${this.trader.metaUrl(sym)}`);
    -  76            console.log(err);
    -  77            console.log(err.stack);
    -  78        })
    -  79        .then(() => item);
    -  80    }
    -  81
    -  82    getSymbols():Promise {
    -  83        const url = this.trader.symbolsUrl();
    -  84        return m.request({ method: 'GET', url: url })
    -  85        .then(this.trader.normalizeSymbols)
    -  86        .catch((err:any) => {
    -  87            console.log(`error requesting ${url}`);
    -  88            console.log(err);
    -  89            console.log(err.stack);
    -  90        });
    -  91    }
    -  92}
    -  93
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/TraderIEX.html b/docs/src/hsStock/view/TraderIEX.html deleted file mode 100644 index 4ca17e2..0000000 --- a/docs/src/hsStock/view/TraderIEX.html +++ /dev/null @@ -1,281 +0,0 @@ - - -

    view/TraderIEX.ts

    -
       1import { TraderQuote,
    -   2         TraderReferences,
    -   3         TraderSymbol,
    -   4         TraderProfile } from './Trader';
    -   5import { EquityItem }    from './Equity';
    -   6
    -   7interface IEXSymbols extends TraderSymbol {
    -   8    date:       string;
    -   9    isEnabled:  boolean;
    -  10    type:       string;     // refers to the common issue type of the stock. 
    -  11                            //  ad â€“ American Depository Receipt (ADR’s) 
    -  12                            //  re â€“ Real Estate Investment Trust (REIT’s) 
    -  13                            //  ce â€“ Closed end fund (Stock and Bond Fund) 
    -  14                            //  si â€“ Secondary Issue 
    -  15                            //  lp â€“ Limited Partnerships 
    -  16                            //  cs â€“ Common Stock 
    -  17                            //  et â€“ Exchange Traded Fund (ETF) 
    -  18                            //  (blank) = Not Available, i.e., Warrant, Note, or (non-filing) Closed Ended Funds
    -  19    iexId:      string;
    -  20}
    -  21
    -  22interface IEXMeta extends EquityItem {
    -  23    beta:               number; // 
    -  24    week52change:       number; // 
    -  25    shortInterest:      number; // 
    -  26    shortDate:          string; // 
    -  27    dividendRate:       number; // 
    -  28    dividendYield:      number; // 
    -  29    exDividendDate:     string; // 
    -  30    latestEPS:          number; // (Most recent quarter)
    -  31    latestEPSDate:      string; // 
    -  32    sharesOutstanding:  number; // 
    -  33    float:              number; // 
    -  34    returnOnEquity:     number; // (Trailing twelve months)
    -  35    consensusEPS:       number; // (Most recent quarter)
    -  36    numberOfEstimates:  number; // (Most recent quarter)
    -  37    EBITDA:             number; // (Trailing twelve months)
    -  38    revenue:            number; // (Trailing twelve months)
    -  39    grossProfit:        number; // (Trailing twelve months)
    -  40    cash:               number; // reers to total cash. (Trailing twelve months)
    -  41    debt:               number; // refers to total debt. (Trailing twelve months)
    -  42    ttmEPS:             number; // (Trailing twelve months)
    -  43    revenuePerShare:    number; // (Trailing twelve months)
    -  44    revenuePerEmployee: number; // (Trailing twelve months)
    -  45    peRatioHigh:        number; // 
    -  46    peRatioLow:         number; // 
    -  47    EPSSurpriseDollar:  number; // refers to the difference between actual EPS and consensus EPS in dollars.
    -  48    EPSSurprisePercent: number; // refers to the percent difference between actual EPS and consensus EPS.
    -  49    returnOnAssets:     number; // (Trailing twelve months)
    -  50    returnOnCapital:    number; // (Trailing twelve months)
    -  51    profitMargin:       number; // 
    -  52    priceToSales:       number; // 
    -  53    priceToBook:        number; // 
    -  54    day200MovingAvg:    number; // 
    -  55    day50MovingAvg:     number; // 
    -  56    institutionPercent: number; // represents top 15 institutions
    -  57    insiderPercent:     number; // 
    -  58    shortRatio:         number; // 
    -  59    year5ChangePercent: number; // 
    -  60    year2ChangePercent: number; // 
    -  61    year1ChangePercent: number; // 
    -  62    ytdChangePercent:   number; // 
    -  63    month6ChangePercent: number; // 
    -  64    month3ChangePercent: number; // 
    -  65    month1ChangePercent: number; // 
    -  66    day5ChangePercent:  number; // 
    -  67}
    -  68
    -  69
    -  70interface IEXQuote extends TraderQuote {
    -  71    change:         number;
    -  72    changeOverTime: number;
    -  73    changePercent:  number;
    -  74    label:          string; // "Oct 16"
    -  75    unadjustedVolume: number;
    -  76    vwap:           number;
    -  77}
    -  78
    -  79
    -  80/**
    -  81 * https://iextrading.com/developer/docs/
    -  82 */

    -  83export class IexTrading implements TraderProfile {
    -  84    base = 'https://api.iextrading.com/1.0';
    -  85    symbolsUrl    = ()           => `${this.base}/ref-data/symbols`;
    -  86    statsUrl      = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/stats`;
    -  87    metaUrl       = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/quote`;
    -  88    quoteUrl      = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/chart`;
    -  89    financialsUrl = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/financials`;
    -  90    earningsUrl   = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/earnings`;
    -  91    dividendsUrl  = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/dividends/5y`;
    -  92    splitsUrl     = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/splits/5y`;
    -  93    logoUrl       = (sym:string) => `${this.base}/stock/${encodeURIComponent(sym)}/logo`;
    -  94    
    -  95    normalizeStats:(data:any) => EquityItem = (data:any) => {
    -  96console.log(`receiving stock '${data.symbol}' stats`);   
    -  97        const meta:EquityItem = {
    -  98            name:           data.companyName,
    -  99            symbol:         data.symbol,
    - 100            cat:            'Stocks',
    - 101            company: {
    - 102            },
    - 103            stats: {
    - 104                week52high:     data.week52high,
    - 105                week52low:      data.week52low,
    - 106                latestEPS:      data.latestEPS,
    - 107                latestEPSDate:  data.latestEPSDate,
    - 108                marketCap:      data.marketcap,
    - 109                exDividendDate: data.exDividendDate,
    - 110                dividendRate:   data.dividendRate,
    - 111                dividendYield:  data.dividendYield
    - 112            },
    - 113            otherStats:     {}
    - 114        };
    - 115        Object.keys(data).forEach((k:string) => meta.otherStats[k] = data[k]);
    - 116        return meta;
    - 117    }
    - 118
    - 119    normalizeMeta:(data:any) => EquityItem = (data:any) => {
    - 120console.log(`receiving stock '${data.symbol}' meta`);   
    - 121        const meta = {
    - 122            name:       data.companyName,
    - 123            symbol:     data.symbol,
    - 124            cat:        'Stocks',
    - 125            company: {
    - 126                sector:             data.sector,
    - 127                primaryExchange:    data.primaryExchange
    - 128            },
    - 129            stats: {},
    - 130            otherStats:     {}
    - 131        };
    - 132        Object.keys(data).forEach((k:string) => meta.otherStats[k] = data[k]);
    - 133        return meta;
    - 134    }
    - 135
    - 136    normalizeQuotes:(data:any[]) => TraderQuote[] = (data:any[]) => {
    - 137        data.sort((a:TraderQuote, b:TraderQuote) => Date.parse(a.date) - Date.parse(b.date));
    - 138console.log(`receiving stock quote for`);   
    - 139        return data;
    - 140    }
    - 141
    - 142    normalizeSymbols:(data:any[]) => TraderReferences = (data:any[]) => {
    - 143        const result:TraderReferences = {symbols:[], names:[], equities:<{string:TraderSymbol}>{}};
    - 144        data.forEach((entry:any) => { 
    - 145            result.equities[`sym${entry.symbol}`] = entry; 
    - 146            result.symbols.push(entry.symbol);
    - 147            result.names.push(entry.name);
    - 148        });
    - 149        return result;
    - 150    }
    - 151};
    - 152
    - 153
    - 154interface IEXStat {
    - 155    companyName:            string;
    - 156    marketcap:              number; // is not calculated in real time.
    - 157    beta:                   number;
    - 158    week52high:             number;
    - 159    week52low:              number;
    - 160    week52change:           number;
    - 161    shortInterest:          number;
    - 162    shortDate:              string;
    - 163    dividendRate:           number;
    - 164    dividendYield:          number;
    - 165    exDividendDate:         string;
    - 166    latestEPS:              number; // (Most recent quarter)
    - 167    latestEPSDate:          string;
    - 168    sharesOutstanding:      number;
    - 169    float:                  number;
    - 170    returnOnEquity:         number; // (Trailing twelve months)
    - 171    consensusEPS:           number; // (Most recent quarter)
    - 172    numberOfEstimates:      number; // (Most recent quarter)
    - 173    symbol:                 string;
    - 174    EBITDA:                 number; // (Trailing twelve months)
    - 175    revenue:                number; // (Trailing twelve months)
    - 176    grossProfit:            number; // (Trailing twelve months)
    - 177    cash:                   number; // refers to total cash. (Trailing twelve months)
    - 178    debt:                   number; // refers to total debt. (Trailing twelve months)
    - 179    ttmEPS:                 number; // (Trailing twelve months)
    - 180    revenuePerShare:        number; // (Trailing twelve months)
    - 181    revenuePerEmployee:     number; // (Trailing twelve months)
    - 182    peRatioHigh:            number;
    - 183    peRatioLow:             number;
    - 184    EPSSurpriseDollar:      number; // refers to the difference between actual EPS and consensus EPS in dollars.
    - 185    EPSSurprisePercent:     number; // refers to the percent difference between actual EPS and consensus EPS.
    - 186    returnOnAssets:         number; // (Trailing twelve months)
    - 187    returnOnCapital:        number; // (Trailing twelve months)
    - 188    profitMargin:           number;
    - 189    priceToSales:           number;
    - 190    priceToBook:            number;
    - 191    day200MovingAvg:        number;
    - 192    day50MovingAvg:         number;
    - 193    institutionPercent:     number; // represents top 15 institutions
    - 194    insiderPercent:         number;
    - 195    shortRatio:             number;
    - 196    year5ChangePercent:     number;
    - 197    year2ChangePercent:     number;
    - 198    year1ChangePercent:     number;
    - 199    ytdChangePercent:       number;
    - 200    month6ChangePercent:    number;
    - 201    month3ChangePercent:    number;
    - 202    month1ChangePercent:    number;
    - 203    day5ChangePercent:      number;    
    - 204}
    - 205
    - 206interface IEXFinancials {
    - 207    reportDate:             string;
    - 208    grossProfit:            number;
    - 209    costOfRevenue:          number;
    - 210    operatingRevenue:       number;
    - 211    totalRevenue:           number;
    - 212    operatingIncome:        number;
    - 213    netIncome:              number;
    - 214    researchAndDevelopment: number;
    - 215    operatingExpense:       number;
    - 216    currentAssets:          number;
    - 217    totalAssets:            number;
    - 218    totalLiabilities:       number;
    - 219    currentCash:            number;
    - 220    currentDebt:            number;
    - 221    totalCash:              number;
    - 222    totalDebt:              number;
    - 223    shareholderEquity:      number;
    - 224    cashChange:             number;
    - 225    cashFlow:               number;
    - 226    operatingGainsLosses:   string;
    - 227}
    - 228
    - 229interface IEXEarnings {
    - 230    actualEPS:          number;
    - 231    consensusEPS:       number;
    - 232    estimatedEPS:       number;
    - 233    announceTime:       string;
    - 234    numberOfEstimates:  number;
    - 235    EPSSurpriseDollar:  number;
    - 236    EPSReportDate:      string;
    - 237    fiscalPeriod:       string;
    - 238    fiscalEndDate:      string;
    - 239}
    - 240
    - 241interface IEXDividends {
    - 242    exDate:         string; // refers to the dividend ex-date
    - 243    paymentDate:    string; // refers to the payment date
    - 244    recordDate:     string; // refers to the dividend record date
    - 245    declaredDate:   string; // refers to the dividend declaration date
    - 246    amount:         number; // refers to the payment amount
    - 247    type:           string; // refers to the dividend payment type (Dividend income, Interest income, Stock dividend, Short term capital gain, Medium term capital gain, Long term capital gain, Unspecified term capital gain)
    - 248    qualified:      string; // refers to the dividend income type 
    - 249                            // P = Partially qualified income 
    - 250                            // Q = Qualified income 
    - 251                            // N = Unqualified income 
    - 252                            // null = N/A or unknown
    - 253}
    - 254
    - 255interface IEXSplits {
    - 256    exDate:         string; // refers to the split ex-date
    - 257    declaredDate:   string; // refers to the split declaration date
    - 258    recordDate:     string; // refers to the split record date
    - 259    paymentDate:    string; // refers to the split payment date
    - 260    ratio:          number; // refers to the split ratio. The split ratio is an inverse of the number of shares that a holder of the stock would have after the split divided by the number of shares that the holder had before. 
    - 261                            // For example: Split ratio of .5 = 2 for 1 split.
    - 262    toFactor:       string; // To factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    - 263    forFactor:      string; // For factor of the split. Used to calculate the split ratio forfactor/tofactor = ratio (eg Â½ = 0.5)
    - 264}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/View.html b/docs/src/hsStock/view/View.html deleted file mode 100644 index ddfea23..0000000 --- a/docs/src/hsStock/view/View.html +++ /dev/null @@ -1,87 +0,0 @@ - - -

    view/View.ts

    -
       1
    -   2import { m, Vnode}      from 'hslayout';
    -   3import { collapsible,
    -   4         AddButton, 
    -   5         RemoveButton }  from 'hswidget';
    -   6import { EquityList,
    -   7         Category,
    -   8         EquityItem }   from './Equity';
    -   9import { Trader }       from './Trader';
    -  10
    -  11export function tabView(list:EquityList, symbol:string) {
    -  12    return m('.hs-left-nav', list? navList(list, symbol) : 'left');
    -  13}
    -  14
    -  15const gRequests = {};
    -  16const trader = new Trader();
    -  17
    -  18/** creates the list if modules (`*.ts` files) */
    -  19function navList(list:EquityList, symbol:string):Vnode[] {    
    -  20    /** process a category, e.g. `Stocks`. */
    -  21
    -  22    const cats = list.getCategories().map((c:Category) => categoryEntry(c,list,symbol));
    -  23    return [m('.hs-left-nav-content', cats)];
    -  24}
    -  25
    -  26/** returns a Vnoide structure representing an investment category. */
    -  27function categoryEntry(c:Category, list:EquityList, symbol:string) {
    -  28    function addItem() {            
    -  29        const num = Math.floor(Math.random()*1000);
    -  30        list.addItem({
    -  31            symbol: 's'+num,
    -  32            cat: c.cat,
    -  33            name: c.cat+num
    -  34        });           
    -  35        m.route.set('/api/:mode/:symbol', {mode:'View', symbol:list.getFirstByCat(c.cat).symbol});
    -  36    }
    -  37
    -  38    /** returns a Vnode for an ivestment item, e.g. "Google" */
    -  39    function equityEntry(item:EquityItem) {
    -  40        function removeItem() { list.removeItem(item); }
    -  41
    -  42        if (!gRequests[item.symbol]) { // once only !
    -  43            gRequests[item.symbol] = true;
    -  44            list.loadMeta(item.symbol)
    -  45            .catch(() => 
    -  46                trader.getMeta(item.symbol)
    -  47                .then((data:any) => { 
    -  48                    list.saveMeta(data, item.symbol);
    -  49                    return data;
    -  50                }))
    -  51            .then((data:EquityItem) => 
    -  52                Object.keys(data).forEach((k:string) => item[k] = data[k]));
    -  53        }
    -  54        const selected = (item.symbol === symbol)? '.hs-left-nav-selected' : '';
    -  55        return m(`.hs-left-nav-entry ${selected}`, [
    -  56            m('a', { href:`/api/View/${item.symbol}`, oncreate: m.route.link, onupdate: m.route.link }, item.name),
    -  57            m(RemoveButton, { remove:removeItem })
    -  58        ]);
    -  59    }
    -  60
    -  61    const selected = (c.cat === list.getItem(symbol).cat)? '.hs-left-nav-selected' : '';
    -  62    return collapsible(`.hs-left-nav-module`, { isExpanded:selected }, [
    -  63        m('.hs-left-nav-module-name ${selected}', [
    -  64            m('a', { href:`/api/View/${list.getFirstByCat(c.cat).symbol}`, oncreate: m.route.link, onupdate: m.route.link }, c.cat),
    -  65            m(AddButton, { add:addItem })
    -  66        ]),
    -  67        c.equities.map(equityEntry)
    -  68    ]);
    -  69}
    -  70
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/ViewLeft.html b/docs/src/hsStock/view/ViewLeft.html deleted file mode 100644 index 443339a..0000000 --- a/docs/src/hsStock/view/ViewLeft.html +++ /dev/null @@ -1,149 +0,0 @@ - - -

    view/ViewLeft.ts

    -
       1import { m, Vnode}      from 'hslayout';
    -   2import { Collapsible,
    -   3         AddButton, 
    -   4         Modal,
    -   5         TypeAhead,
    -   6         RemoveButton }  from 'hswidget';
    -   7import { gEquities,
    -   8         Equities,
    -   9         Category,
    -  10         EquityItem }   from '../controller/Equities';
    -  11import { authenticated } from '../Router';
    -  12import { readAssets,TransactionList }   from '../controller/Assets';
    -  13
    -  14let gAssets:TransactionList;
    -  15let ModalShow = false;
    -  16
    -  17export const ViewLeft = {
    -  18    view: (node: Vnode):Vnode => {
    -  19        const symbol  = m.route.param('symbol');
    -  20        return m('.hs-left-nav', [
    -  21            gEquities? navList(gEquities, symbol) : 'left',
    -  22            ModalShow? m(Modal, { 
    -  23                content: m(AddItemForm, {list:gEquities}),
    -  24                dismiss: () => ModalShow=false
    -  25            }) : undefined
    -  26        ]);
    -  27    }
    -  28};
    -  29
    -  30/** creates the list if modules (`*.ts` files) */
    -  31function navList(list:Equities, symbol:string):Vnode[] {    
    -  32    /** process a category, e.g. `Stocks`. */
    -  33
    -  34    if (authenticated()) { getAssets(list); }
    -  35    
    -  36    const cats = list.getCategories().map((c:Category) => categoryEntry(c,list,symbol));
    -  37    return m('.hs-left-nav-content', cats);
    -  38}
    -  39
    -  40/** returns a Vnoide structure representing an investment category. */
    -  41function categoryEntry(c:Category, list:Equities, symbol:string) {
    -  42    /** returns a Vnode for the category header */
    -  43    function catHeader():Vnode {
    -  44        return m('.hs-left-nav-module-name ${selected}', [
    -  45            m('a', { href:`/site/View/${symbol}`, oncreate:m.route.link, onupdate:m.route.link }, [
    -  46                c.equities.length + ' ',
    -  47                c.cat
    -  48            ]),
    -  49            m(AddButton, { onclick:()=> ModalShow=true })
    -  50        ]);
    -  51    }
    -  52
    -  53    /** returns a Vnode for an ivestment item, e.g. "Google" */
    -  54    function equityEntry(item:EquityItem):Vnode {
    -  55        function removeItem() { 
    -  56            list.removeItem(item); }
    -  57
    -  58        const selected = (item.symbol === symbol)? '.hs-left-nav-selected' : '';
    -  59        const unknown = (item.name !== item.symbol)? '' : '.hs-unkown-equity';
    -  60        return m(`.hs-left-nav-entry ${selected} ${unknown} ${item.shares>0?'.hs-owns-shares':''}`, [
    -  61            m('a', { href:`/site/View/${item.symbol}`, oncreate:m.route.link, onupdate:m.route.link }, [
    -  62                item.shares?item.shares+' ':'', item.name
    -  63            ]),
    -  64            m(RemoveButton, { onclick:removeItem })
    -  65        ]);
    -  66    }
    -  67
    -  68    // open the collapsible if it contains `symbol`. Otherwise leave it unchanged (undefined)
    -  69    const selected = (c.cat === list.getItem(symbol).cat)? '.hs-left-nav-selected' : undefined;
    -  70    return m(Collapsible, {css:`.hs-left-nav-module`, isExpanded:selected, components: [
    -  71        catHeader(),
    -  72        c.equities.map(equityEntry)
    -  73    ]});
    -  74}
    -  75
    -  76function getAssets(list:Equities) {
    -  77    if (!gAssets) {
    -  78        gAssets = {};
    -  79        readAssets()
    -  80        .then((tlist:TransactionList) => {
    -  81            gAssets = tlist;
    -  82            let numSyms = 0;
    -  83            let numTrades = 0;
    -  84            Object.keys(tlist).forEach((sym:string) => {
    -  85                numSyms++;
    -  86                numTrades += tlist[sym].trades.length;
    -  87                let item:EquityItem = list.getItem(sym);
    -  88                if (item.symbol === '????') {
    -  89                    item = list.addItem({ symbol: sym, cat: 'new', name: sym });
    -  90                }
    -  91                item.shares = tlist[sym].latestShares;
    -  92                item.trades = tlist[sym].trades;
    -  93                list.applySplitsToTrades(item);
    -  94            });
    -  95            console.log(`received assets list: ${numTrades} trades for ${numSyms} symbols`);
    -  96        });
    -  97    }
    -  98}
    -  99
    - 100class AddItemForm {
    - 101    list:Equities;
    - 102    symbol = '';
    - 103
    - 104    submit() {
    - 105        this.list.addItem({
    - 106            symbol: this.symbol,
    - 107            cat: 'Stocks',
    - 108            name: this.symbol
    - 109        });           
    - 110//        Modal.dismiss();
    - 111    };
    - 112        
    - 113    view(node:Vnode) {
    - 114//        const form = this;
    - 115        this.list = node.attrs.list;
    - 116        return m(TypeAhead, {list: '', onsubmit:(e:any) => {
    - 117            this.symbol = e.currentTarget.value;
    - 118            this.submit.apply(this);
    - 119        }});
    - 120/*            
    - 121        return m('.hs-form',  m('form', { onsubmit: () => form.submit.apply(this) }, [
    - 122            m('input[type="text"][placeholder="Symbol"][name="symbol"]', {
    - 123                value: form.symbol,
    - 124                onchange: function(e:any) {
    - 125                    form.symbol = e.currentTarget.value;
    - 126                }
    - 127            }),
    - 128            m(Button, {name:'add', onclick:() => form.submit.apply(this)})
    - 129        ]));
    - 130*/
            
    - 131    }
    - 132}
    - - \ No newline at end of file diff --git a/docs/src/hsStock/view/ViewPane.html b/docs/src/hsStock/view/ViewPane.html deleted file mode 100644 index 90de297..0000000 --- a/docs/src/hsStock/view/ViewPane.html +++ /dev/null @@ -1,45 +0,0 @@ - - -

    view/ViewPane.ts

    -
       1
    -   2import { m, Vnode}      from 'hslayout';
    -   3import { Layout }       from 'hslayout';
    -   4import { MainDetails }  from './MainDetails';
    -   5import { MainGraph }    from './MainGraph';
    -   6import { ViewLeft }     from './ViewLeft';
    -   7
    -   8const LeftNavWidth       = '200px'; 
    -   9const StocksDetailHeight = '110px'; 
    -  10
    -  11export const ViewPane = {
    -  12    view: (node: Vnode): Vnode => {
    -  13        return m(Layout, {
    -  14            columns: [LeftNavWidth, 'fill'],
    -  15            css: '.hs-view-pane',
    -  16            content: [
    -  17                m(ViewLeft), 
    -  18                m(Layout, {
    -  19                    css: '.hs-view-center', 
    -  20                    rows:[StocksDetailHeight,'fill'], 
    -  21                    content:[m(MainDetails), m(MainGraph)]
    -  22                })
    -  23            ]
    -  24        });
    -  25    }    
    -  26};
    -  27
    -  28
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/Checksum.html b/docs/src/hsUtil/Checksum.html deleted file mode 100644 index c9f67c2..0000000 --- a/docs/src/hsUtil/Checksum.html +++ /dev/null @@ -1,33 +0,0 @@ - - -

    Checksum.ts

    -
       1/**
    -   2 * Creates a checksum on a string.
    -   3 * Adapted from https://stackoverflow.com/questions/811195/fast-open-source-checksum-for-small-strings
    -   4 */

    -   5
    -   6 /** 
    -   7  * fast implementation for short strings (20-500 chars)
    -   8  */

    -   9 export function shortCheckSum(s:string):string {
    -  10    var chk = 0x12345678;
    -  11    var len = s.length;
    -  12    for (var i = 0; i < len; i++) {
    -  13        chk += (s.charCodeAt(i) * (i + 1));
    -  14    }
    -  15    return (chk & 0xffffffff).toString(16);
    -  16 }
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/Date.html b/docs/src/hsUtil/Date.html deleted file mode 100644 index de7f0c0..0000000 --- a/docs/src/hsUtil/Date.html +++ /dev/null @@ -1,95 +0,0 @@ - - -

    Date.ts

    -
       1/**
    -   2# Date formatting support. 
    -   3Formats are specified in a printf-style format string. 
    -   4## Supported Formats
    -   5- `%YY, %YYYY`           : two- or four-digit year, as '73', '1973'
    -   6- `%M, %MM, %MMM, %MMMM` : month of year as '2', '02', 'Feb', 'February'
    -   7- `%D, %DD`              : day of month as '5', '05' (1...31)
    -   8- `%DDD, %DDDD`          : day of week as 'Tue', 'Tuesday'
    -   9- `%h, %hh`              : hour of day as '7', '07 (0...23)
    -  10- `%m, %mm`              : minutes as '6', '06' (0..59)
    -  11- `%ss`                  : seconds as '09' (0...59)
    -  12- `%j, %jj, %jjj`        : milliseconds as '1', '15', '159'
    -  13 */

    -  14
    -  15 /** short and long month names */
    -  16const monthStr = [
    -  17    ['Jan', 'January'], ['Feb', 'February'], ['Mar', 'March'], ['Apr', 'April'], ['May', 'May'], ['Jun', 'June'],
    -  18    ['Jul', 'July'], ['Aug', 'August'], ['Sep', 'September'], ['Oct', 'October'], ['Nov', 'November'], ['Dec', 'December']];
    -  19
    -  20 /** short and long weekday names */
    -  21const dayStr = [
    -  22    ['Sun', 'Sunday'],['Mon', 'Monday'],['Tue', 'Tuesday'],['Wed', 'Wednesday'],['Thu', 'Thursday'],['Fri', 'Friday'],['Sat', 'Saturday']];
    -  23
    -  24/** add leading zeros to an integer until `digits` are reached */
    -  25function formatNumber(number:number, digits:number):string {
    -  26    var r = ''+number;
    -  27    while (r.length < digits) { r = "0" + r; }
    -  28    return r;
    -  29}
    -  30
    -  31
    -  32/**
    -  33 * ## Example:
    -  34 * 

    -  35 * date('%MM/%DD/%YY');           // -> 08/17/16 (using current date)
    -  36 * let d = new Date('7/4/2010');
    -  37 * date('%DDDD, %MM/%DD/%YY', d); // -> Sunday, 07/04/10
    -  38 * 

    -  39 * @param formatString the format string to use.
    -  40 * @param [date=new Date()] the date to format.
    -  41 * @returns a copy of `formatString` where all supported patterns are replaced by the respective values from `date`.
    -  42 */

    -  43export function date(formatString:string, date=new Date()):string {
    -  44    return isNaN( date.getTime() )?
    -  45        'invalid':
    -  46        formatString
    -  47            .replace(/%YYYY/g, ''+date.getFullYear())
    -  48            .replace(/%YY/g,   ''+(date.getFullYear()%100))
    -  49            .replace(/%MMMM/g,  monthStr[date.getMonth()][1])
    -  50            .replace(/%MMM/g,   monthStr[date.getMonth()][0])
    -  51            .replace(/%MM/g,   formatNumber(date.getMonth()+1,2))
    -  52            .replace(/%M/g,   ''+(date.getMonth()+1))
    -  53            .replace(/%DDDD/g,  dayStr[date.getDay()][1])
    -  54            .replace(/%DDD/g,   dayStr[date.getDay()][0])
    -  55            .replace(/%DD/g,   formatNumber(date.getDate(),2))
    -  56            .replace(/%D/g,   ''+date.getDate())
    -  57            .replace(/%hh/g,   formatNumber(date.getHours(),2))
    -  58            .replace(/%h/g,  ''+date.getHours())
    -  59            .replace(/%mm/g,   formatNumber(date.getMinutes(),2))
    -  60            .replace(/%m/g,   ''+date.getMinutes())
    -  61            .replace(/%ss/g,   formatNumber(date.getSeconds(),2))
    -  62            .replace(/%jjj/g,   formatNumber(date.getMilliseconds(),3))
    -  63            .replace(/%jj/g,   formatNumber(date.getMilliseconds()/10,2))
    -  64            .replace(/%j/g, formatNumber(date.getMilliseconds()/100,1));
    -  65}
    -  66
    -  67/** converts minutes, hours, days, weeks ... into milliseconds and back */ 
    -  68export const ms = {
    -  69    fromMinutes:    (min:number) => 1000*60*min,
    -  70    fromHours:      (h:number)   => 1000*60*60*h,
    -  71    fromDays:       (d:number)   => 1000*60*60*24*d,
    -  72    fromWeeks:      (w:number)   => 1000*60*60*24*7*w,
    -  73    toMinutes:      (ms:number)  => ms/(1000*60),
    -  74    toHours:        (ms:number)  => ms/(1000*60*60),
    -  75    toDays:         (ms:number)  => ms/(1000*60*60*24),
    -  76    toWeeks:        (ms:number)  => ms/(1000*60*60*24*7)
    -  77};
    -  78
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/Number.html b/docs/src/hsUtil/Number.html deleted file mode 100644 index 090281d..0000000 --- a/docs/src/hsUtil/Number.html +++ /dev/null @@ -1,34 +0,0 @@ - - -

    Number.ts

    -
       1/**
    -   2 * # Number Formatting Support.
    -   3 * 
    -   4 * 
    -   5 */

    -   6
    -   7/**
    -   8 * rounds a number `n` to the specified `d` decimals and returns a string
    -   9 */

    -  10 export function round(n:number, d:number):string {
    -  11     if (isNaN(n)) { return ''; }
    -  12     if (n === 0) { return '0'; }
    -  13     const exp = Math.round(Math.log10(Math.abs(n)));
    -  14     if (exp > d) { return ''+n; }
    -  15     const base = Math.pow(10, d-exp);
    -  16     return ''+Math.round(n*base)/base;
    -  17 }
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/PacingQueue.html b/docs/src/hsUtil/PacingQueue.html deleted file mode 100644 index 3edc7f7..0000000 --- a/docs/src/hsUtil/PacingQueue.html +++ /dev/null @@ -1,63 +0,0 @@ - - -

    PacingQueue.ts

    -
       1/**
    -   2 * # PacingQueue
    -   3 * ensures that a functions in a sequence are not executed faster than a preset minimum delay
    -   4 */

    -   5
    -   6 /** */
    -   7export class PacingQueue {
    -   8    delayMS:number;
    -   9    queue = [];
    -  10    baseMS = Date.now();
    -  11    /**
    -  12     * @param delay the minimum number of milliseconds between executions of 
    -  13     * two registered functions; defaults to 100;
    -  14     */

    -  15    constructor(delayMS=100) {
    -  16        this.delayMS = delayMS; 
    -  17        this.next(this.queue); 
    -  18    }
    -  19
    -  20    private nextTimeout() {
    -  21        setTimeout(() => this.next(this.queue), this.delayMS);
    -  22    }
    -  23
    -  24    add(fn: (msSinceAdding:number) => any):Promise {
    -  25        return new Promise((resolve, reject) => {
    -  26            if (this.queue.length === 0) { this.nextTimeout(); }
    -  27            this.queue.push({fn:fn, resolve:resolve, reject:reject, time:Date.now()});
    -  28 });
    -  29    }
    -  30
    -  31    next(q:any[]) {
    -  32        if (q.length > 0) {
    -  33            const entry = q.shift();
    -  34            entry.resolve(
    -  35                entry.fn(Date.now() - entry.time)   // call the registered function with the actual delay 
    -  36                .catch((err:any) => {
    -  37                    console.log(`error calling paced function: ${err}`);
    -  38                    console.log(err.stack);
    -  39                    throw err;
    -  40                })
    -  41            );
    -  42            this.nextTimeout();
    -  43        }
    -  44    }
    -  45}
    -  46
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/TimedPromise.html b/docs/src/hsUtil/TimedPromise.html deleted file mode 100644 index 3c7c518..0000000 --- a/docs/src/hsUtil/TimedPromise.html +++ /dev/null @@ -1,46 +0,0 @@ - - -

    TimedPromise.ts

    -
       1/**
    -   2 * ## Helpful Script Utility Module
    -   3 * Provides convenience functions that don't depend on specific frameworks or libraries 
    -   4 */

    -   5
    -   6
    -   7/**
    -   8 * @description timeout promise for use in `Promise.race()`.
    -   9 * @param {number} ms the milliseconds to wait before rejecting
    -  10 * @return {Promise} a Promise that rejects after `ms` 
    -  11 */

    -  12export function timeout(ms:number):Promise { 
    -  13    return new Promise((resolve, reject) => { setTimeout(reject, ms); }); 
    -  14}
    -  15
    -  16/**
    -  17 * @description delay promise for use in `Promise.all(param).then(delay(ms)).then(doSomething)`.
    -  18 * `delay` passes the parameter received from the calling promise down to the resolving promise.
    -  19 * @param number ms the milliseconds to wait before resolving
    -  20 * @return a `Promise` that resolves after `ms` 
    -  21 */

    -  22export function delay(ms:number)   { 
    -  23    return (args:T):Promise => {
    -  24        return new Promise((resolve:(args:T)=>void) => { 
    -  25            setTimeout(() => { resolve(args); }, ms); 
    -  26        }); 
    -  27    };
    -  28}
    -  29
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/hsChecksum.html b/docs/src/hsUtil/hsChecksum.html deleted file mode 100644 index ea7adbd..0000000 --- a/docs/src/hsUtil/hsChecksum.html +++ /dev/null @@ -1,33 +0,0 @@ - - -

    hsChecksum.ts

    -
       1/**
    -   2 * Creates a checksum on a string.
    -   3 * Adapted from https://stackoverflow.com/questions/811195/fast-open-source-checksum-for-small-strings
    -   4 */

    -   5
    -   6 /** 
    -   7  * fast implementation for short strings (20-500 chars)
    -   8  */

    -   9 export function shortCheckSum(s:string):string {
    -  10    var chk = 0x12345678;
    -  11    var len = s.length;
    -  12    for (var i = 0; i < len; i++) {
    -  13        chk += (s.charCodeAt(i) * (i + 1));
    -  14    }
    -  15    return (chk & 0xffffffff).toString(16);
    -  16 }
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/hsTimedPromise.html b/docs/src/hsUtil/hsTimedPromise.html deleted file mode 100644 index 5c6f3b0..0000000 --- a/docs/src/hsUtil/hsTimedPromise.html +++ /dev/null @@ -1,46 +0,0 @@ - - -

    hsTimedPromise.ts

    -
       1/**
    -   2 * ## Helpful Script Utility Module
    -   3 * Provides convenience functions that don't depend on specific frameworks or libraries 
    -   4 */

    -   5
    -   6
    -   7/**
    -   8 * @description timeout promise for use in `Promise.race()`.
    -   9 * @param {number} ms the milliseconds to wait before rejecting
    -  10 * @return {Promise} a Promise that rejects after `ms` 
    -  11 */

    -  12export function timeout(ms:number):Promise { 
    -  13    return new Promise((resolve, reject) => { setTimeout(reject, ms); }); 
    -  14}
    -  15
    -  16/**
    -  17 * @description delay promise for use in `Promise.all(param).then(delay(ms)).then(doSomething)`.
    -  18 * `delay` passes the parameter received from the calling promise down to the resolving promise.
    -  19 * @param number ms the milliseconds to wait before resolving
    -  20 * @return a `Promise` that resolves after `ms` 
    -  21 */

    -  22export function delay(ms:number)   { 
    -  23    return (args:Promise):Promise => {
    -  24        return new Promise((resolve:any) => { 
    -  25            setTimeout(() => { resolve(args); }, ms); 
    -  26        }); 
    -  27    };
    -  28}
    -  29
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/hsUtil.html b/docs/src/hsUtil/hsUtil.html deleted file mode 100644 index cfe3679..0000000 --- a/docs/src/hsUtil/hsUtil.html +++ /dev/null @@ -1,52 +0,0 @@ - - -

    hsUtil.ts

    -
       1/**
    -   2 * ## Helpful Script Utility Module
    -   3 * Provides convenience functions that don't depend on specific frameworks or libraries 
    -   4 */

    -   5
    -   6
    -   7/**
    -   8 * @ngdoc function
    -   9 * @name timeout
    -  10 * @methodOf hsNode.hsLibs
    -  11 * @description timeout promise for use in Promise.race().
    -  12 * @param {number} ms the milliseconds to wait before rejecting
    -  13 * @return {Promise} a Promise that rejects after `ms` 
    -  14 */

    -  15export function timeout(ms:number) { 
    -  16    return new Promise((resolve, reject) => { setTimeout(reject, ms); }); 
    -  17}
    -  18
    -  19/**
    -  20 * @ngdoc function
    -  21 * @name delay
    -  22 * @methodOf hsNode.hsLibs
    -  23 * @description delay promise for use in Promise.all(param).then(delay(ms)).then(doSomething).
    -  24 * `delay` passes the paremeter received from the calling promise down to the following promise.
    -  25 * @param number ms the milliseconds to wait before resolving
    -  26 * @return a Promise that resolves after `ms` 
    -  27 */

    -  28export function delay(ms:number)   { 
    -  29    return (args:any) => {
    -  30        return new Promise((resolve:any) => { 
    -  31            setTimeout(() => { resolve(args); }, ms); 
    -  32        }); 
    -  33    };
    -  34}
    -  35
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/index.html b/docs/src/hsUtil/index.html deleted file mode 100644 index 1a76aeb..0000000 --- a/docs/src/hsUtil/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - -

    index.ts

    -
       1export { timeout, delay } from './TimedPromise';
    -   2export { markDown }       from './showdown';
    -   3export { shortCheckSum }  from './Checksum';
    -   4export { date, ms }       from './Date';
    -   5export { round }          from './Number';
    -   6export { PacingQueue }    from './PacingQueue';
    -   7
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/overview.html b/docs/src/hsUtil/overview.html deleted file mode 100644 index 804e55f..0000000 --- a/docs/src/hsUtil/overview.html +++ /dev/null @@ -1,30 +0,0 @@ - - -

    overview.ts

    -
       1/**
    -   2 * # hsUtil
    -   3 * 
    -   4 * Helpful Scripts utility functions that are framework independent. 
    -   5 * 
    -   6 * ## Index
    -   7 * -   {@link TimedPromise TimedPromise} functions that provide delays and timeouts for promises.
    -   8 * -   {@link CheckSum CheckSum} a quick checksum implementation for small strings
    -   9 * -   {@link Date Date} printf-style date formatting function
    -  10 * -   {@link showdown showdown} an ES6 wrapper for the showdown library
    -  11 */

    -  12
    -  13 /** */
    - - \ No newline at end of file diff --git a/docs/src/hsUtil/showdown.html b/docs/src/hsUtil/showdown.html deleted file mode 100644 index 41ae29d..0000000 --- a/docs/src/hsUtil/showdown.html +++ /dev/null @@ -1,24 +0,0 @@ - - -

    showdown.ts

    -
       1const showdown  = require('showdown');
    -   2
    -   3const converter = new showdown.Converter();
    -   4
    -   5export function markDown(text:string) { 
    -   6    return converter.makeHtml(text);
    -   7}
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/AddRemove.html b/docs/src/hsWidget/AddRemove.html deleted file mode 100644 index bed15e5..0000000 --- a/docs/src/hsWidget/AddRemove.html +++ /dev/null @@ -1,48 +0,0 @@ - - -

    AddRemove.ts

    -
       1/**
    -   2 * # AddRemove Buttons
    -   3 * Adds `+` and `-` buttons to add or remove items from a list.
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as 
    -   7 * ```
    -   8 *  m('div', [
    -   9 *      m('div', 'main content row'),
    -  10 *      m(AddButton, { onclick: })
    -  11 *  ]),
    -  12 * ```
    -  13 * 
    -  14 * ### Attributes (node.attrs):
    -  15 * - `onclick`: function to call when button is pressed 
    -  16 */

    -  17
    -  18 /** */
    -  19import { m, Vnode}      from 'hslayout';
    -  20
    -  21export class AddButton {
    -  22    view(node:Vnode):Vnode {
    -  23        return m('.hs-add-button', { onclick:node.attrs.onclick }, '');
    -  24    }
    -  25}
    -  26
    -  27export class RemoveButton {
    -  28    view(node:Vnode):Vnode {
    -  29        return m('.hs-remove-button', { onclick:node.attrs.onclick }, '');
    -  30    }
    -  31}
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/Button.html b/docs/src/hsWidget/Button.html deleted file mode 100644 index 06b0059..0000000 --- a/docs/src/hsWidget/Button.html +++ /dev/null @@ -1,74 +0,0 @@ - - -

    Button.ts

    -
       1/**
    -   2 * # Button Widget
    -   3 * A simple button widget
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as `m(Button, {name:, onclick:});`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - `onclick:() => void` function to execute when button is clicked
    -  10 * - `name: string` name to show as button text
    -  11 * - `css: string` css class to assign to button tag
    -  12 * - `style: string` style string to apply to button tag
    -  13 * 
    -  14 * ### Example
    -  15 * 
    -  16 * 
    -  17 * let clicked = 0;
    -  18 * 
    -  19 * m.mount(root, {view: () => m('.hs-white', [
    -  20 *    m('h4', 'Please click:'),
    -  21 *    m(hswidget.Button, { desc: {
    -  22 *        name: 'click me',
    -  23 *        clicked: () => clicked++
    -  24 *    }}),
    -  25 * ])});
    -  26 * 
    -  27 * 

    -  28 * 
    -  29 */

    -  30
    -  31/** */
    -  32import { Vnode }     from 'hslayout';
    -  33import { ToggleButton } from './ToggleButton';
    -  34
    -  35/**
    -  36 * # Button Widget
    -  37 * A simple button widget
    -  38 * 
    -  39 * ### Profile
    -  40 * invoked as `m(Button, {name:, onclick:});`
    -  41 * 
    -  42 * ### Attributes (node.attrs):
    -  43 * attribtues as defined in {@link ToggleButton.ToggleButton `ToggleButton`}, 
    -  44 * except for `items` and `changed`, which are replaced by 
    -  45 * - `name: string` name to show as button text (in lieu of `items`)
    -  46 * - `clicked:() => void` function to execute when button is clicked
    -  47 */

    -  48export class Button extends ToggleButton {
    -  49    view(node: Vnode) {
    -  50        const desc = node.attrs.desc;
    -  51        desc.items = [desc.name || 'button'];
    -  52        desc.changed = desc.clicked;
    -  53        return super.view(node);
    -  54    }
    -  55}
    -  56
    -  57
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/Collapsible.html b/docs/src/hsWidget/Collapsible.html deleted file mode 100644 index 054d912..0000000 --- a/docs/src/hsWidget/Collapsible.html +++ /dev/null @@ -1,93 +0,0 @@ - - -

    Collapsible.ts

    -
       1/**
    -   2 * # Collapsible Widget
    -   3 * returns a Vnode that can be toggled to expand and contract by clicking on the first `component`.
    -   4 * 
    -   5 * ### Invocation
    -   6 * invoked as 
    -   7 * ```
    -   8 * m(Collapsible, { css:, isExpanded:true, components:[
    -   9 *     m('div', 'the title'),
    -  10 *     ['body item1', 'body item2', 'body item3']
    -  11 * ]})
    -  12 * ```
    -  13 * 
    -  14 * ### Attributes (node.attrs):
    -  15 * - `css`: optional; the css class to assign to the entire Collapsible div
    -  16 * - `isExpanded`: optional; boolean indicating if the Collapsible is initially expanded
    -  17 * - `components`: array of two components: 
    -  18 *     - `component[0]` is the title of the Collapsible. This will remain visible and can be clicked 
    -  19 *       on to expand or contract the remaining components
    -  20 *     - `component[1]` an array of Vnodes that will be collapsed or expanded.
    -  21 * 
    -  22 * ### Example
    -  23 * 
    -  24 * 
    -  25 * m.mount(root, {view: () => m('.hs-white', [
    -  26 *    m(hswidget.Collapsible, { css:'.myExample', components: [
    -  27 *       m('.myTitle', 'click me to toggle'), [
    -  28 *          m('.myItem', 'body item1'), 
    -  29 *          m('.myItem', 'body item2'), 
    -  30 *          m('.myItem', 'body item3')
    -  31 *       ]
    -  32 *    ]}),
    -  33 *    m('', 'This is a background text that will be pushed down by the Collapsible')
    -  34 * ])});
    -  35 * 
    -  36 * 
    -  37 * div { margin-top: 5px; }
    -  38 * .myTitle {
    -  39 *    display: inline-block;
    -  40 *    border-radius: 0px 4px;
    -  41 *    padding: 1px;
    -  42 *    border-bottom: 1px solid blue;
    -  43 *    width: auto;
    -  44 * }
    -  45 * 
    -  46 * 

    -  47 */

    -  48
    -  49 /** */
    -  50import { m, Vnode } from 'hslayout';
    -  51
    -  52export class Collapsible {
    -  53    expanded = false;
    -  54    toggle() {
    -  55        this.expanded = !this.expanded;
    -  56    }
    -  57    view(node:Vnode) {
    -  58        const css        = node.attrs.css;
    -  59        const components = node.attrs.components;
    -  60        const preArrow   = node.attrs.preArrow;
    -  61        const postArrow  = node.attrs.postArrow;
    -  62        if (node.attrs.isExpanded!==undefined) {
    -  63            this.expanded = node.attrs.isExpanded;
    -  64        }
    -  65        const expCSS = this.expanded?'hs-collapsible-expanded':'';
    -  66        return m(`.hs-collapsible ${css} ${expCSS}`, { onclick:this.toggle.bind(this)}, [
    -  67            m('.hs-collapsible-title',[
    -  68                !preArrow? m('') : m(`.hs-collapsible-pre .hs-collapsible-arrow-${this.expanded?'down' : 'right'}`),
    -  69                components[0],
    -  70                !postArrow? m('') : m(`.hs-collapsible-post .hs-collapsible-arrow-${this.expanded?'down' : 'left'}`),
    -  71            ]),
    -  72            components[1]? m('.hs-collapsible-content', components[1].map((c:any) =>m('',c))) : undefined
    -  73        ]);
    -  74    }
    -  75}
    -  76
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/CornerButton.html b/docs/src/hsWidget/CornerButton.html deleted file mode 100644 index 7aac5aa..0000000 --- a/docs/src/hsWidget/CornerButton.html +++ /dev/null @@ -1,120 +0,0 @@ - - -

    CornerButton.ts

    -
       1/**
    -   2 * # Corner Button
    -   3 * creates a button at the corner of a positioned panel.
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as `m(CornerButton, {  })`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - `onclick: ()=>void` a function that is called when the modal box is dismissed
    -  10 * 
    -  11 * ### Example
    -  12 * 
    -  13 * 
    -  14 * const buttons = {}
    -  15 * m.mount(root, {view: () => m('', Object.keys(hswidget.ButtonSymbols).map(
    -  16 *      (b) => m('.myPositioned', [
    -  17 *          buttons[b]? m('.myClicked', 'Yayy!!') : m('', b),
    -  18 *          m(hswidget.CornerButton, { symbol:hswidget.CornerButton.getSymbol(b), onclick:click(b) })
    -  19 *      ])
    -  20 * ))});
    -  21 * 
    -  22 * function click(button) {
    -  23 *      return () => {
    -  24 *          buttons[button] = true;
    -  25 *          setTimeout(reset(button), 800);
    -  26 *      }
    -  27 * }
    -  28 * 
    -  29 * function reset(button) {
    -  30 *      return () => {
    -  31 *          buttons[button] = false;
    -  32 *          m.redraw();
    -  33 *      }
    -  34 * }
    -  35 * 
    -  36 * 
    -  37 * .myClicked { background-color: #efe; }
    -  38 * .myPositioned { 
    -  39 *      position: relative; 
    -  40 *      display: inline-block;
    -  41 *      box-sizing: border-box;
    -  42 *      background-color: #fff; 
    -  43 *      text-align: center;
    -  44 *      font-size: 70%;
    -  45 *      margin:  2px;
    -  46 *      padding-top: 20px;
    -  47 *      height: 50px;
    -  48 *      width:  50px;
    -  49 * }
    -  50 * .hs-corner-button { color: #008; }
    -  51 * 
    -  52 * 

    -  53 */

    -  54
    -  55 /** */
    -  56import { m, Vnode}  from 'hslayout'; 
    -  57
    -  58export const ButtonSymbols = {
    -  59    cross:      { sym: '×' },
    -  60    minus:      { sym: '−'},
    -  61    plus:       { sym: '+'},
    -  62    dLeft:      { sym: '«'},
    -  63    dRight:     { sym: '»'},
    -  64    left:       { sym: '‹'},
    -  65    right:      { sym: '›'},
    -  66    leftTri:    { sym: '◂'},
    -  67    rightTri:   { sym: '▸'},
    -  68    upTri:      { sym: '▴'},
    -  69    downTri:    { sym: '▾'},
    -  70    up:         { sym: '∧'},
    -  71    down:       { sym: '∨'},
    -  72    lArrow:     { sym: '←'},
    -  73    rArrow:     { sym: '→'},
    -  74    uArrow:     { sym: '↑'},
    -  75    dArrow:     { sym: '↓'},
    -  76    empty:      { sym: '○'},
    -  77    emptySlash: { sym: '∅'},
    -  78    oSlash:     { sym: 'ø'},
    -  79    o:          { sym: 'ο'},
    -  80    lines3:     { sym: '≡'},
    -  81    sum:        { sym: 'Σ'},
    -  82    ellipsis:   { sym: '…'},
    -  83    vertEllips: { sym: '⁝'},
    -  84    bullet:     { sym: '•'},
    -  85    enter:      { sym: '↵'},
    -  86    again:      { sym: '↻'},
    -  87    start:      { sym: '⇱'},
    -  88    end:        { sym: '⇲'}
    -  89};
    -  90
    -  91export class CornerButton {
    -  92    constructor(protected symbol='-') {}
    -  93    static getSymbol(name:string) {
    -  94        return ButtonSymbols[name]? ButtonSymbols[name].sym : '';
    -  95    }
    -  96    view(node:Vnode) {
    -  97        return m('.hs-corner-button', 
    -  98            { onclick: node.attrs.onclick }, 
    -  99            m.trust(node.attrs.symbol));
    - 100    }
    - 101}
    - 102
    - 103
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/DropOver.html b/docs/src/hsWidget/DropOver.html deleted file mode 100644 index 8297f6b..0000000 --- a/docs/src/hsWidget/DropOver.html +++ /dev/null @@ -1,87 +0,0 @@ - - -

    DropOver.ts

    -
       1/**
    -   2 * # DropOver Widget
    -   3 * returns a Vnode that can be toggled to expand on top of existing content.
    -   4 * 
    -   5 * ### Invocation
    -   6 * invoked as 
    -   7 * ```
    -   8 * m(DropOver, { css:, dir:DropOver.right, components:[
    -   9 *     m('div', 'the title'),
    -  10 *     ['body item1', 'body item2', 'body item3']
    -  11 * ]})
    -  12 * ```
    -  13 * 
    -  14 * ### Attributes (node.attrs):
    -  15 * - `css`: the css class to assign to the entire Collapsible div
    -  16 * - `dir`: the direction in which the `DropOver` expands; defaults to DropOver.down
    -  17 * - `components`: array of two components: 
    -  18 *     - `component[0]` is the title of the DropOver. This will remain visible and can be clicked 
    -  19 *       on to expand the remaining components
    -  20 *     - `component[1]` an *array of Vnodes* that will be expanded.
    -  21 * 
    -  22 * ### Example
    -  23 * 
    -  24 * 
    -  25 * const clicked = e => console.log(e);
    -  26 * m.mount(root, {view: () => m(hslayout.Layout, {
    -  27 *     rows:["100%"],
    -  28 *     content:[
    -  29 *         m(hswidget.DropOver, { css:'.myExample', components: [
    -  30 *              m('.myTitle', 'click me to open'),
    -  31 *              [
    -  32 *                  m('.myItem', {onclick: clicked}, 'body item1'), 
    -  33 *                  m('.myItem', {onclick: clicked}, 'body item2'), 
    -  34 *                  m('.myItem', {onclick: clicked}, 'body item3')
    -  35 *              ]
    -  36 *         ]}),
    -  37 *     ]
    -  38 * })});
    -  39 * 
    -  40 * 

    -  41 */

    -  42
    -  43 /** */
    -  44import { m, Vnode } from 'hslayout';
    -  45
    -  46export class DropOver {
    -  47    static left  = 'left';
    -  48    static right = 'right';
    -  49    static up    = 'up';
    -  50    static down  = 'down';
    -  51
    -  52    expanded = false;
    -  53    toggle() {
    -  54        this.expanded = !this.expanded;
    -  55    }
    -  56    view(node:Vnode) {
    -  57        const css        = node.attrs.css;
    -  58        const components = node.attrs.components;
    -  59        if (node.attrs.isExpanded!==undefined) {
    -  60            this.expanded = node.attrs.isExpanded;
    -  61        }
    -  62        return m(`.hs-dropover ${css}`, { onclick:()=>this.expanded = !this.expanded}, [
    -  63            components[0],
    -  64            components[1]? m('.hs-dropover-content', 
    -  65                { class: this.expanded?'hs-dropover-expanded':'' }, 
    -  66                components[1].map((c:any) =>c)) : undefined
    -  67        ]);
    -  68    }
    -  69}
    -  70
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/Menu.html b/docs/src/hsWidget/Menu.html deleted file mode 100644 index 83e1db6..0000000 --- a/docs/src/hsWidget/Menu.html +++ /dev/null @@ -1,83 +0,0 @@ - - -

    Menu.ts

    -
       1/**
    -   2 * # Menu Widget
    -   3 * Creates a simple menu with several items.
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as `m(Menu, { desc: })`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - `desc:` {@link Menu.MenuDesc MenuDesc}
    -  10 *     - `items: string[]`                  the items on the menu
    -  11 *     - `changed: (item:string) => void`   called when item clicked
    -  12 *     - `defaultItem?: number|string`      the currently selected item, by index or name
    -  13 *     - `itemCSS?: string[]`               css to apply to items;
    -  14 * - `css?: string`                         css class to assign to button group
    -  15 * - `style?: string`                       style string to apply to button tag
    -  16 * - `size?: string | string[]`             sizes to layout menu items; 
    -  17 * 
    -  18 * ### Example
    -  19 * 
    -  20 * 
    -  21 * const items = ['One', 'Two', 'Three'];
    -  22 * const content   = ['1st', '2nd', '3rd'];
    -  23 * let  theContent = content[1];
    -  24 * 
    -  25 * m.mount(root, {view: () => m(hslayout.Layout, {
    -  26 *     rows:["30px", "fill"],
    -  27 *     content:[
    -  28 *         m(hswidget.Menu, {desc: {
    -  29 *             items: items,
    -  30 *             defaultItem: 'Two',
    -  31 *             changed: item => 
    -  32 *                theContent = content[items.indexOf(item)]
    -  33 *         }}),
    -  34 *         m(hslayout.Layout, { css:'myMain', content: theContent })
    -  35 *     ]
    -  36 * })});
    -  37 *
    -  38 * 
    -  39 * 
    -  40 * .myMain { 
    -  41 *    border:1px solid #ddd;
    -  42 *    border-top: 0px solid #ddd;
    -  43 * } 
    -  44 * .hs-selectable { 
    -  45 *     background-color: #f4f4e8; 
    -  46 * }
    -  47 * .hs-selected { 
    -  48 *     background-color: #eed; 
    -  49 *     border-width:0px;
    -  50 * }
    -  51 * 
    -  52 * 

    -  53 */

    -  54
    -  55 /** */
    -  56import { Vnode }        from 'hslayout';
    -  57import { RadioButton }  from './RadioButton';
    -  58
    -  59
    -  60/**
    -  61 * Creates a simple menu with several items, as configured by the desc:SelectorDesc object passed as a parameter. 
    -  62 */

    -  63export class Menu extends RadioButton {
    -  64    view(node: Vnode): Vnode { return this.viewGroup('.hs-menu', node); }
    -  65};
    -  66
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/Menu.spec.html b/docs/src/hsWidget/Menu.spec.html deleted file mode 100644 index 0fd7df1..0000000 --- a/docs/src/hsWidget/Menu.spec.html +++ /dev/null @@ -1,66 +0,0 @@ - - -

    Menu.spec.ts

    -
       1
    -   2const hslayout = require('hslayout');
    -   3const m = hslayout.m;
    -   4const o = hslayout.o;
    -   5
    -   6const hsMenu = require("../src/Menu");
    -   7const Menu = hsMenu.Menu;
    -   8
    -   9const left  = ['0%', '25%', '50%', '75%'];
    -  10const right = ['75%', '50%', '25%', '0%'];
    -  11const title = ['1a', '2a', '3a', '4a']; 
    -  12
    -  13o.spec('hsMenu', () => {
    -  14    let menu:any;
    -  15    o.before(() => {
    -  16        const md = { 
    -  17            items: title,
    -  18            changed: (item:string) => { console.log('selected'); }
    -  19        };
    -  20        m.mount(o.root, {view: () => m(Menu, { desc: md }) }); 
    -  21        menu = o.root.childNodes[0];
    -  22    });
    -  23
    -  24    o('Menu', () => {
    -  25        o(menu).notEquals(undefined)('creation');
    -  26        o(menu.className.indexOf('hs-menu')).notEquals(-1)("is menu");
    -  27        o(menu.className.indexOf('hs-layout')).notEquals(-1)("is layout");
    -  28    });
    -  29
    -  30    o('Menu Items', () => {
    -  31        const cn = menu.childNodes;
    -  32        o(cn.length).equals(4)("has 4 menu items");
    -  33        cn.forEach((c:any, i:any) => {
    -  34            o(c.className.indexOf('hs-selectable')).notEquals(-1)(`item ${i+1} menu-item class`);
    -  35            o(c.className.indexOf('hs-layout')).notEquals(-1)(`item ${i+1} layout class`);
    -  36            o(c.className.includes('hs-selected')).equals((i===0)?true:false)(`item ${i+1} selected class`);
    -  37            o(c.style.left).equals(left[i])(`item ${i+1} left`);
    -  38            o(c.style.right).equals(right[i])(`item ${i+1} right`);
    -  39            o(c.style.top).equals('0%')(`item ${i+1} top`);
    -  40            o(c.style.bottom).equals('0%')(`item ${i+1} bottom`);
    -  41            o(c.childNodes.length).equals(1)(`item ${i+1} num children`);
    -  42            o(c.childNodes[0].className).equals('hs-leaf')(`item ${i+1} child leaf`);
    -  43            o(c.childNodes[0].childNodes[0].nodeValue).equals(title[i])(`item ${i+1} child leaf text`);
    -  44        });
    -  45    });
    -  46
    -  47});
    -  48
    -  49
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/Modal.html b/docs/src/hsWidget/Modal.html deleted file mode 100644 index 6914a81..0000000 --- a/docs/src/hsWidget/Modal.html +++ /dev/null @@ -1,68 +0,0 @@ - - -

    Modal.ts

    -
       1/**
    -   2 * # Modal Widget
    -   3 * returns a Vnode that covers the entire window. 
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as `m(Modal, {  })`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - `width?:  string` the `px` or `%` of the window width to use, or 'auto' if omitted.
    -  10 * - `height?: string` the `px` or `%` of the window height to use, or 'auto' if omitted.
    -  11 * - `content: Vnode` the mithril node to show as content of the modal
    -  12 * - `dismiss: ()=>void` a function that is called when the modal box is dismissed
    -  13 * 
    -  14 * ### Example
    -  15 * 
    -  16 * 
    -  17 * let showModal = false;
    -  18 * m.mount(root, {view: () => m('.hs-white', [
    -  19 *      m('h4', {onclick:() => showModal = true }, 'click me'),
    -  20 *      showModal? m(hswidget.Modal, { 
    -  21 *          width:  '300px',
    -  22 *          height: '200px',
    -  23 *          dismiss: () => showModal = false,
    -  24 *          content: m('', 'click border to release') 
    -  25 *      }) : undefined
    -  26 *    ])
    -  27 * });
    -  28 * 
    -  29 * 

    -  30 */

    -  31
    -  32 /** */
    -  33import { m, Vnode}  from 'hslayout'; 
    -  34import { ToolbarButton } from './ToolbarButton';
    -  35
    -  36export class Modal {
    -  37    view(node:Vnode) {
    -  38        const w = node.attrs.width  || 'auto';
    -  39        const h = node.attrs.height || 'auto';
    -  40        const attrs = { style: `width:${w}; height:${h};`};
    -  41        return m('.hs-modal-frame', [
    -  42            m('.hs-modal-background', { onclick: node.attrs.dismiss}, ''),
    -  43            m('.hs-modal-foreground', attrs, !node.attrs.content? 'modal pane' : [
    -  44                node.attrs.content,
    -  45//                m('.hs-modal-close', { onclick: node.attrs.dismiss }, m.trust('×')) 
    -  46                m(ToolbarButton, { onclick: node.attrs.dismiss, symbol:ToolbarButton.getSymbol('cross') }) 
    -  47            ])
    -  48        ]);
    -  49    }
    -  50}
    -  51
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/OneOfButtons.html b/docs/src/hsWidget/OneOfButtons.html deleted file mode 100644 index faf07a2..0000000 --- a/docs/src/hsWidget/OneOfButtons.html +++ /dev/null @@ -1,39 +0,0 @@ - - -

    OneOfButtons.ts

    -
       1/**
    -   2 * # OneOfButtons Widget
    -   3 * A set of adjoint buttons, one of which can be active at a time
    -   4 * 
    -   5 * ### Invocation
    -   6 * invoked as `m(OneOfButtons, {names:[], initial:, onclick:})`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - onclick: function to execute when button is clicked
    -  10 * - name: name to show as button text
    -  11 */

    -  12
    -  13/** */
    -  14import { m, Vnode }     from 'hslayout';
    -  15
    -  16
    -  17export class Button {
    -  18    view(node: Vnode) {
    -  19        return m('.hs-button-group', {onclick:node.attrs.onclick},  node.attrs.name || 'button');
    -  20    }
    -  21}
    -  22
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/RadioButton.html b/docs/src/hsWidget/RadioButton.html deleted file mode 100644 index b23b3cd..0000000 --- a/docs/src/hsWidget/RadioButton.html +++ /dev/null @@ -1,89 +0,0 @@ - - -

    RadioButton.ts

    -
       1/**
    -   2 * # Button Widget
    -   3 * A simple button widget
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as `m(Button, {name:, onclick:});`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - `onclick:() => void` function to execute when button is clicked
    -  10 * - `name: string` name to show as button text
    -  11 * - `css: string` css class to assign to button tag
    -  12 * - `style: string` style string to apply to button tag
    -  13 * 
    -  14 * ### Example
    -  15 * 
    -  16 * 
    -  17 * let clicked = 0;
    -  18 * let radio = '';
    -  19 * let toggle = '';
    -  20 * 
    -  21 * m.mount(root, {view: () => m('.hs-white', [
    -  22 *    m('h4', `Select Radio Station: ${radio}`),
    -  23 *    m(hswidget.RadioButtons, { desc: {
    -  24 *        items: ['1st', '2nd','3rd'],
    -  25 *        changed: (item) => radio = item
    -  26 *    }})
    -  27 * ])});
    -  28 * 
    -  29 * 

    -  30 * 
    -  31 */

    -  32
    -  33/** */
    -  34import { m, Vnode }     from 'hslayout';
    -  35import { Layout }       from 'hslayout';
    -  36import { Selector }     from './Selector';
    -  37import { oneOfItems }   from './Selector';
    -  38import { SelectorDesc } from './Selector';
    -  39
    -  40/**
    -  41 * # Radio Button Widget
    -  42 * A group of buttons with one or none selected
    -  43 * 
    -  44 * ### Profile
    -  45 * invoked as `m(RadioButton, {desc: { items:[], changed:}});`
    -  46 * 
    -  47 * ### Attributes (node.attrs):
    -  48 * - `desc:` see {@link Selector.SelectorDesc SelectorDesc}
    -  49 *     - `changed:(item:string) => void`    function to execute when button is selected
    -  50 *     - `selectedItem?: number|string`     the currently selected item, by index or name
    -  51 *     - `items: string[]`                  names to individual buttons to show
    -  52 *     - `itemCss?:string[]`                css to apply to each item;
    -  53 * - `css?: string`                         css class to assign to button group
    -  54 * - `style?: string`                       style string to apply to button tag
    -  55 * - `size?: string | string[]`             sizes to layout menu items; 
    -  56 */

    -  57export class RadioButton extends Selector {
    -  58    viewGroup(css:string, node: Vnode) {
    -  59        const desc:SelectorDesc = this.init(node.attrs.desc, oneOfItems);
    -  60        node.attrs.desc = undefined;
    -  61        css = `${css} ${node.attrs.css || ''}`;
    -  62        const style = node.attrs.style || '';
    -  63
    -  64        return m(css, {style:style}, m(Layout, {
    -  65            columns: [],
    -  66            content: desc.items.map((l:string, i:number) => this.renderItem(desc, i))
    -  67        }));
    -  68    }
    -  69    view(node: Vnode): Vnode { return this.viewGroup('.hs-radio-buttons', node); }
    -  70}
    -  71
    -  72
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/Selector.html b/docs/src/hsWidget/Selector.html deleted file mode 100644 index e0dd91d..0000000 --- a/docs/src/hsWidget/Selector.html +++ /dev/null @@ -1,177 +0,0 @@ - - -

    Selector.ts

    -
       1/**
    -   2 * # Abstract Selector
    -   3 * Creates a Selector with several Selectables.
    -   4 * The `updateSelected` property determines how selecting an item affects 
    -   5 * the `isSelected` status of all other items. Preconfigured options are
    -   6 * -  {@link Selector.oneOfItems oneOfItems}
    -   7 * -  {@link Selector.anyItems   anyItems}
    -   8 * 
    -   9 * 
    -  10 * ### Invocation
    -  11 * implementation dependant
    -  12 * 
    -  13 * ### Attributes (node.attrs):
    -  14 * - desc: {@link Selector.SelectorDesc SelectorDesc}
    -  15 *     - items: string[];                // the items on the selector
    -  16 *     - defaultItem?: number|string;    // the initial selected item, by index or name
    -  17 *     - changed: (item:string) => void; // called when selection changed
    -  18 *     - itemCss?:string[];              // css to apply to items;
    -  19 */

    -  20
    -  21 /** */
    -  22import { m } from 'hslayout';
    -  23
    -  24/** passed into Menu from the calling application */
    -  25export interface SelectorDesc {
    -  26    /** the items on the menu */
    -  27    items: string[];
    -  28    /** optional array of css styles; each will be applied to the respective item  */
    -  29    itemCss?: string[];
    -  30    /** the initial selected item */
    -  31    defaultItem?: string|number;
    -  32    /** the function to call when the selection changes */
    -  33    changed: (item:string) => void;
    -  34    /** the function to call if this item receives a mouseDown event */
    -  35    mouseDown?: (item:string) => void;
    -  36    /** the function to call if this item receives a mouseUp event */
    -  37    mouseUp?: (item:string) => void;
    -  38}
    -  39
    -  40/** interface of the parameter passed to a `Selectable` */
    -  41export interface SelectableDesc {
    -  42    /** the item's title */
    -  43    title: string;
    -  44    /** the item's select status */
    -  45    isSelected: boolean;
    -  46    /** optional css class to use */
    -  47    css?: string;
    -  48    /** optional style string to apply */
    -  49    style?: string;
    -  50    /** the function to call if this item is clicked */
    -  51    clicked?: (item:string) => void;
    -  52    /** the function to call if this item receives a mouseDown event */
    -  53    mouseDown?: (item:string) => void;
    -  54    /** the function to call if this item receives a mouseUp event */
    -  55    mouseUp?: (item:string) => void;
    -  56}
    -  57
    -  58export type selectFn = (items:{string:SelectableDesc}, title:string) => void;
    -  59
    -  60/** 
    -  61 * called to update selection after the item with title `title` was selected.
    -  62 * `oneOfItems` ensures that `title` will be selected and all others deselected
    -  63 */

    -  64export function oneOfItems(items:{string:SelectableDesc}, title:string) {
    -  65    Object.keys(this.items).forEach((key:string) => { 
    -  66        this.items[key].isSelected = (key===title); 
    -  67    });
    -  68}
    -  69
    -  70/** 
    -  71 * called to update selection after the item with title `title` was selected.
    -  72 * `anyItems` ensures that `title` will be selected independant of all others
    -  73 */

    -  74export function anyItems(items:{string:SelectableDesc}, title:string) {
    -  75    this.items[title].isSelected = !this.items[title].isSelected; 
    -  76}
    -  77
    -  78
    -  79/**
    -  80 * Creates a simple menu with several items, as configured by the desc:SelectorDesc object passed as a parameter. 
    -  81 */

    -  82export abstract class Selector {
    -  83    /** 
    -  84     * determines which function to use to updatye selections after events.
    -  85     * Pre-configured function include:
    -  86     * - oneOfItems: default; only one item of the set can be selected at a time
    -  87     * - anyItem: each item can individually be selected. Pressing an item again will deselect it.
    -  88     */

    -  89    private updateSelected:selectFn = [oneOfItems, anyItems][0];
    -  90
    -  91    protected selectedItem: string; 
    -  92
    -  93    /** instance variable, keeping a list of menu items and a `select` function for tracking which item is selected. */
    -  94    private items = <{string:SelectableDesc}>{};
    -  95
    -  96    init(desc:SelectorDesc, updateSelected:selectFn = oneOfItems):SelectorDesc {
    -  97        this.updateSelected = updateSelected.bind(this);
    -  98        desc.items = desc.items || [];
    -  99        desc.changed = desc.changed || ((item:string) => console.log(`missing changed() function for menu item ${item}`));
    - 100        this.checkSelectedItem(desc);
    - 101        return desc;
    - 102    };
    - 103
    - 104    /** ensures that `selectedItem` is defined and is a string */
    - 105    checkSelectedItem(desc:SelectorDesc) {
    - 106        if (this.selectedItem === undefined) {
    - 107            if (typeof desc.defaultItem === 'number') { 
    - 108                this.selectedItem = desc.items[desc.defaultItem % desc.items.length];
    - 109            } else {
    - 110                this.selectedItem = desc.defaultItem || desc.items[0];
    - 111            }
    - 112        }
    - 113    }
    - 114
    - 115    internalStateUpdate(desc:SelectorDesc, item:string) {
    - 116        this.selectedItem = item;
    - 117        this.checkSelectedItem(desc);
    - 118        this.updateSelected(this.items, this.selectedItem); // local housekeeping: make sure the item's style shows correct selection
    - 119    }
    - 120
    - 121    renderItem(desc:SelectorDesc, i:number) {
    - 122        const reactor = (callback:(itm:string)=>void) => (item:string) => {
    - 123            this.internalStateUpdate(desc, item);
    - 124            if (typeof callback === 'function') { 
    - 125                callback(item);  // trigger any actions from the selection
    - 126            }     
    - 127        }; 
    - 128        const l:string = desc.items[i] || '';
    - 129        const itemCss = desc.itemCss || [];
    - 130
    - 131        this.checkSelectedItem(desc);
    - 132        return selectable({ 
    - 133            title: l, 
    - 134            css: itemCss[i],        // possibly undefined
    - 135            isSelected: this.selectedItem? (l.toLowerCase() === this.selectedItem.toLowerCase()) : false, 
    - 136            mouseDown: reactor(desc.mouseDown),
    - 137            mouseUp: reactor(desc.mouseUp),
    - 138            clicked: reactor(desc.changed)
    - 139        });
    - 140    }
    - 141};
    - 142
    - 143/**
    - 144 * Creates a Selectable as part of the `Selector`, 
    - 145 * as configured by the desc:SelectableDesc object passed as a parameter.
    - 146 * Selectables can be in one of two states, selected or not selected. 
    - 147 * @return an `.hs-selectable` node
    - 148 */

    - 149export function selectable(childDesc:SelectableDesc) {
    - 150    const css           = childDesc.css || '';
    - 151    const cssSelected   = `${childDesc.isSelected?'hs-selected': ''}`;
    - 152    const onclick       = childDesc.clicked?   () => { childDesc.clicked(childDesc.title); }   : undefined;
    - 153    const onmousedown   = childDesc.mouseDown? () => { childDesc.mouseDown(childDesc.title); } : undefined;
    - 154    const onmouseup     = childDesc.mouseUp?   () => { childDesc.mouseUp(childDesc.title); }   : undefined;
    - 155    return m(`.hs-selectable ${css} ${cssSelected}`, 
    - 156        { style: childDesc.style, onclick:onclick, onmousedown:onmousedown, onmouseup:onmouseup },
    - 157        childDesc.title
    - 158    );
    - 159}
    - 160
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/ToggleButton.html b/docs/src/hsWidget/ToggleButton.html deleted file mode 100644 index fd460e8..0000000 --- a/docs/src/hsWidget/ToggleButton.html +++ /dev/null @@ -1,99 +0,0 @@ - - -

    ToggleButton.ts

    -
       1/**
    -   2 * # Button Widget
    -   3 * A simple button widget
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as `m(Button, {name:, onclick:});`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - `onclick:() => void` function to execute when button is clicked
    -  10 * - `name: string` name to show as button text
    -  11 * - `css: string` css class to assign to button tag
    -  12 * - `style: string` style string to apply to button tag
    -  13 * 
    -  14 * ### Example
    -  15 * 
    -  16 * 
    -  17 * let clicked = 0;
    -  18 * let radio = '';
    -  19 * let toggle = '';
    -  20 * 
    -  21 * m.mount(root, {view: () => m('.hs-white', [
    -  22 *    m('h4', `Please Toggle: (currently ${toggle})`),
    -  23 *    m(hswidget.ToggleButton, { desc: {
    -  24 *        items: ['1st', '2nd','3rd'],
    -  25 *        changed: (item) => toggle = item
    -  26 *    }})
    -  27 * ])});
    -  28 * 
    -  29 * 

    -  30 * 
    -  31 */

    -  32
    -  33/** */
    -  34import { m, Vnode }     from 'hslayout';
    -  35import { Selector }     from './Selector';
    -  36import { oneOfItems }   from './Selector';
    -  37
    -  38/**
    -  39 * # ToggleButton Widget
    -  40 * A button widget that toggle through a set of items, or states and 
    -  41 * shows the current state as button title
    -  42 * 
    -  43 * ### Profile
    -  44 * invoked as `m(ToggleButton, {desc: { items:[], changed:}});`
    -  45 * 
    -  46 * ### Attributes (node.attrs):
    -  47 * - `desc:` see {@link Selector.SelectorDesc SelectorDesc}
    -  48 *     - `changed:(item:string) => void` function to execute when button is selected
    -  49 *     - `selectedItem?: number|string` the currently selected item, by index or name
    -  50 *     - `items: string[]` names of individual states to toggle through
    -  51 *     - `itemCss?:string[]` css to apply to each item;
    -  52 * - `css?: string` css class to assign to button group
    -  53 * - `style?: string` style string to apply to button tag
    -  54 */

    -  55export class ToggleButton extends Selector {
    -  56    private toggleIndex = -1;
    -  57    private mouseDown = '';
    -  58    view(node: Vnode): Vnode {
    -  59        const desc = this.init(node.attrs.desc, oneOfItems);
    -  60        node.attrs.desc = undefined;
    -  61        const css = node.attrs.css || '';
    -  62        const style = node.attrs.style || '';
    -  63
    -  64        // insert click update into passed click function
    -  65        const parentChanged = desc.changed;
    -  66        desc.changed = ((item:string) => {
    -  67            this.toggleIndex = (this.toggleIndex+1) % desc.items.length;
    -  68            item = desc.items[this.toggleIndex];
    -  69            this.internalStateUpdate(desc, item);
    -  70            if (parentChanged) { parentChanged(item); }
    -  71        });
    -  72
    -  73        if (this.toggleIndex<0) { this.toggleIndex = 0; }
    -  74
    -  75        desc.mouseDown = () => this.mouseDown = '.hs-button-pressed';
    -  76        desc.mouseUp   = () => this.mouseDown = '';
    -  77
    -  78        return m(`.hs-toggle-button${css}${this.mouseDown}`, { style:style}, m('span', 
    -  79            this.renderItem(desc, this.toggleIndex)
    -  80        ));
    -  81    }
    -  82}
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/ToolbarButton.html b/docs/src/hsWidget/ToolbarButton.html deleted file mode 100644 index 19ad9ac..0000000 --- a/docs/src/hsWidget/ToolbarButton.html +++ /dev/null @@ -1,147 +0,0 @@ - - -

    ToolbarButton.ts

    -
       1/**
    -   2 * # Toolbar Button
    -   3 * creates a set of buttons at the corner of a positioned panel.
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as `m(ToolbarButtons, {  })`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - `symbols: string | string[]` a symbol, or array of symbols 
    -  10 * - `onclick: ()=>void` a function that is called when the modal box is dismissed
    -  11 * 
    -  12 * ### Example
    -  13 * 
    -  14 * 
    -  15 * const buttons = {}
    -  16 * const keys = Object.keys(hswidget.ButtonSymbols);
    -  17 * const symbols = [];
    -  18 * let batch = [];
    -  19 * for (let i=0; i -  20 *    if (i % 4 === 0) {
    -  21 *       batch = []
    -  22 *       symbol.push(batch);
    -  23 *    }
    -  24 *    batch.push(keys[i]);
    -  25 * }
    -  26 * 
    -  27 * m.mount(root, {view: () => m('', [
    -  28 *    m('', keys.map(
    -  29 *       (b) => m('.myPositioned', [
    -  30 *          buttons[b]? m('.myClicked', 'Yayy!!') : m('', b),
    -  31 *          m(hswidget.ToolbarButtons, { symbol:hswidget.ToolbarButtons.getSymbol(b), onclick:click(b) })
    -  32 *       ])
    -  33 *    )), 
    -  34 *    m('', symbols.map(
    -  35 *       (batch) => m('.myPositioned', [
    -  36 *          m(hswidget.ToolbarButtons, { symbol:batch.map(b => hswidget.ToolbarButtons.getSymbol(b)), onclick:click(b) })
    -  37 *       ])
    -  38 *    ))
    -  39 * ])});
    -  40 * 
    -  41 * function click(button) {
    -  42 *      return () => {
    -  43 *          buttons[button] = true;
    -  44 *          setTimeout(reset(button), 800);
    -  45 *      }
    -  46 * }
    -  47 * 
    -  48 * function reset(button) {
    -  49 *      return () => {
    -  50 *          buttons[button] = false;
    -  51 *          m.redraw();
    -  52 *      }
    -  53 * }
    -  54 * 
    -  55 * 
    -  56 * .myClicked { background-color: #efe; }
    -  57 * .myPositioned { 
    -  58 *      position: relative; 
    -  59 *      display: inline-block;
    -  60 *      box-sizing: border-box;
    -  61 *      background-color: #fff; 
    -  62 *      text-align: center;
    -  63 *      font-size: 70%;
    -  64 *      margin:  2px;
    -  65 *      padding-top: 20px;
    -  66 *      height: 50px;
    -  67 *      width:  50px;
    -  68 * }
    -  69 * .hs-corner-button { color: #008; }
    -  70 * 
    -  71 * 

    -  72 */

    -  73
    -  74 /** */
    -  75import { m, Vnode}  from 'hslayout'; 
    -  76
    -  77export const ButtonSymbols = {
    -  78    cross:      { sym: '×' },
    -  79    minus:      { sym: '−'},
    -  80    plus:       { sym: '+'},
    -  81    dLeft:      { sym: '«'},
    -  82    dRight:     { sym: '»'},
    -  83    left:       { sym: '‹'},
    -  84    right:      { sym: '›'},
    -  85    leftTri:    { sym: '◂'},
    -  86    rightTri:   { sym: '▸'},
    -  87    upTri:      { sym: '▴'},
    -  88    downTri:    { sym: '▾'},
    -  89    up:         { sym: '∧'},
    -  90    down:       { sym: '∨'},
    -  91    lArrow:     { sym: '←'},
    -  92    rArrow:     { sym: '→'},
    -  93    uArrow:     { sym: '↑'},
    -  94    dArrow:     { sym: '↓'},
    -  95    empty:      { sym: '○'},
    -  96    emptySlash: { sym: '∅'},
    -  97    oSlash:     { sym: 'ø'},
    -  98    o:          { sym: 'ο'},
    -  99    lines3:     { sym: '≡'},
    - 100    sum:        { sym: 'Σ'},
    - 101    ellipsis:   { sym: '…'},
    - 102    vertEllips: { sym: '⁝'},
    - 103    bullet:     { sym: '•'},
    - 104    enter:      { sym: '↵'},
    - 105    again:      { sym: '↻'},
    - 106    start:      { sym: '⇱'},
    - 107    end:        { sym: '⇲'}
    - 108};
    - 109
    - 110export class ToolbarButton {
    - 111    constructor(protected symbol='-') {}
    - 112    static getSymbol(name:string) {
    - 113        return ButtonSymbols[name]? ButtonSymbols[name].sym : '';
    - 114    }
    - 115    view(node:Vnode) {
    - 116        if (node.attrs.symbol.length) {
    - 117            return node.attrs.symbol.map((sym:string) => 
    - 118                m('.hs-corner-button', 
    - 119                    { onclick: node.attrs.onclick }, 
    - 120                    m.trust(sym))
    - 121            );
    - 122        } else {
    - 123            return m('.hs-corner-button', 
    - 124                { onclick: node.attrs.onclick }, 
    - 125                m.trust(node.attrs.symbol));
    - 126        }
    - 127    }
    - 128}
    - 129
    - 130
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/TypeAhead.html b/docs/src/hsWidget/TypeAhead.html deleted file mode 100644 index 90837a1..0000000 --- a/docs/src/hsWidget/TypeAhead.html +++ /dev/null @@ -1,150 +0,0 @@ - - -

    TypeAhead.ts

    -
       1/**
    -   2 * # TypeAhead
    -   3 * Provides a search box with a type-ahead dropdown to show valid options that match the current search input.
    -   4 * 
    -   5 * ### Profile
    -   6 * invoked as `m(hswidget.TypeAhead, {  });`
    -   7 * 
    -   8 * ### Attributes (node.attrs):
    -   9 * - `list: string | string[]` the list to search in. If `list` is a string, it serves
    -  10 *    as a URL to a `json` file containing an array of search terms. Else, if it is a 
    -  11 *    string[] it serves directly as an array of search terms
    -  12 * - `placeholder: string` an indicator what to enter in the search box
    -  13 * - `onsubmit: (term:string) => void`  a function to call when a term is submitted
    -  14 * - `autofocus: boolean` whether the search box automatically gets the focus
    -  15 * 
    -  16 * ### Example
    -  17 * 
    -  18 * 
    -  19 * let hero = '';
    -  20 * let friend = '';
    -  21 * m.mount(root, {view: () => m('.hs-white', [
    -  22 *      m('h4', hero.length? `Selected: ${hero}` : 'Local List: Search for a Superhero'),
    -  23 *      m(hswidget.TypeAhead, { 
    -  24 *         placeholder: 'favorite hero',
    -  25 *         onsubmit: item => hero = item,
    -  26 *         list: ['Batman', 'Superman', 'Spiderman', 'Hulk']
    -  27 *      }),
    -  28 *      m('h4', friend.length? `Selected: ${friend}` : 'Remote List: Search for a Friend'),
    -  29 *      m(hswidget.TypeAhead, { 
    -  30 *         placeholder: 'best friend',
    -  31 *         onsubmit: item => friend = item,
    -  32 *         autofocus: true,
    -  33 *         list: 'example/search.json'
    -  34 *      })
    -  35 *   ])
    -  36 * });
    -  37 * 
    -  38 * 

    -  39 * 
    -  40 */

    -  41
    -  42 /** */
    -  43import { m, Vnode } from 'hslayout';
    -  44
    -  45// emphasize literal matches as *bold* in the drop down list
    -  46function emphasize(item:string, match:string) {
    -  47    const re = new RegExp(match, 'gi');
    -  48    const decorations = item
    -  49        .replace(re, (m:string) => `${m}`)
    -  50        .split('<')
    -  51        .map((s:string) => {
    -  52            if (s.startsWith('/b>')) { 
    -  53                return m('span', {name:item}, s.slice(3)); 
    -  54            } else if (s.startsWith('b>')) {
    -  55                return m('b', {name:item}, s.slice(2));
    -  56            } else {
    -  57                return m('span', {name:item}, s);
    -  58            }
    -  59        });
    -  60    return m('span', decorations); 
    -  61}
    -  62
    -  63class GetList {
    -  64    public list:string[] = [];
    -  65    private captureList(list:any[], map:(l:any[])=>string[]) {
    -  66        this.list = map? map(list) : list;
    -  67    }
    -  68    constructor(list:string|string[], map?:(item:any[])=>string[]) {
    -  69        if (typeof list === 'string') {
    -  70            m.request({ method: "GET", url: list })
    -  71            .then((data:any[]) => this.captureList(data, map));
    -  72        } else {
    -  73            this.captureList(list, map);
    -  74        }
    -  75    }
    -  76}
    -  77
    -  78export class TypeAhead {
    -  79    typeAheadList:string[] = [];
    -  80    hidden = true;
    -  81    value = '';
    -  82    inputNode:any;
    -  83    view(node:Vnode) {
    -  84        const gl = new GetList(node.attrs.list);
    -  85        const nosubmit = () => console.log('no submit function defined');
    -  86        const submit = (v:string) => node.attrs.onsubmit? node.attrs.onsubmit(v) : nosubmit();
    -  87        const select = (e:any) => { if (e) { 
    -  88            submit(e.target.attributes.name.value);
    -  89            this.inputNode.value = '';
    -  90            this.hidden = true;
    -  91        }};
    -  92        const input = (e:any) => {
    -  93            const n = this.inputNode = e.target;
    -  94            const input = this.value = n.value;
    -  95            const withinInput = new RegExp(`${input}`, 'gi');
    -  96            const beginningOfInput = new RegExp(`^${input}`, 'gi');
    -  97            this.typeAheadList = gl.list.filter((l:string) => l.match(withinInput));
    -  98            n.value = this.typeAheadList.filter((l:string) => l.match(beginningOfInput))[0] || input; 
    -  99            this.hidden = n.value.length===0; 
    - 100            let pos = input.length;
    - 101            n.setSelectionRange(pos, n.value.length);
    - 102        };
    - 103        const keyPressed = (e:any) => {
    - 104            const n = this.inputNode = e.target;
    - 105            if (e.code === 'Enter') {
    - 106                submit(n.value);
    - 107                n.value = '';
    - 108                 this.hidden = true;
    - 109            } else if (e.code === 'Backspace') {
    - 110                const input = n.firstChild.data;
    - 111                if (input.length > 0) {
    - 112                    n.value = input.slice(0);
    - 113                }
    - 114            }
    - 115        };
    - 116        const inputNode = m(`input.hs-typeahead-input${this.value?'.hs-typeahead-value' : '.hs-typeahead-placeholder'}`, 
    - 117            {
    - 118                contenteditable:true,
    - 119                placeholder:    node.attrs.placeholder,
    - 120                autofocus:      node.attrs.autofocus || true,
    - 121                onkeydown:      keyPressed.bind(this),
    - 122                oninput:        input.bind(this)
    - 123            }, 
    - 124            m.trust(this.value?this.value : node.attrs.placeholder));
    - 125
    - 126        return m('.hs-form', [
    - 127            inputNode, 
    - 128            this.hidden? undefined : 
    - 129                m('.hs-typeahead-list', this.typeAheadList.map((l:string) => 
    - 130                    m('', { onclick: select.bind(this) }, emphasize(l, this.value))))
    - 131        ]);
    - 132    }
    - 133}
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/example/start.html b/docs/src/hsWidget/example/start.html deleted file mode 100644 index b1f60b6..0000000 --- a/docs/src/hsWidget/example/start.html +++ /dev/null @@ -1,19 +0,0 @@ - - -

    example/start.ts

    -
       1import { Menu } from '../';
    -   2if (Menu) {}
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/index.html b/docs/src/hsWidget/index.html deleted file mode 100644 index d33bc16..0000000 --- a/docs/src/hsWidget/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - -

    index.ts

    -
       1/**
    -   2 * @description hsWidgets: Library of UI screen elements.
    -   3 */

    -   4
    -   5/**
    -   6 * 
    -   7 */

    -   8export { Menu }         from './Menu'; 
    -   9export { SelectorDesc } from './Selector'; 
    -  10export { Button }       from './Button'; 
    -  11export { RadioButton }  from './RadioButton'; 
    -  12export { ToggleButton } from './ToggleButton'; 
    -  13export { ToolbarButton,
    -  14         ButtonSymbols
    -  15        }               from './ToolbarButton';
    -  16export { AddButton, 
    -  17         RemoveButton } from './AddRemove'; 
    -  18export { Collapsible }  from './Collapsible'; 
    -  19export { Modal }        from './Modal'; 
    -  20export { TypeAhead }    from './TypeAhead'; 
    -  21
    - - \ No newline at end of file diff --git a/docs/src/hsWidget/overview.html b/docs/src/hsWidget/overview.html deleted file mode 100644 index f54243b..0000000 --- a/docs/src/hsWidget/overview.html +++ /dev/null @@ -1,192 +0,0 @@ - - -

    overview.ts

    -
       1/**
    -   2# hsWidgets 
    -   3Provides various UI widgets:
    -   4
    -   5| Widget | Description |
    -   6|========|=============|
    -   7|   {@link Menu.Menu Menu} | A group of horizontal menu items that can trigger actions |
    -   8|   {@link Button.Button Button} | A simple button widget |
    -   9|   {@link Collapsible Collapsible} | A panel that will expand znd collapse when the title is clicked |
    -  10|   {@link Modal Modal} | A modal panel that will cover the entire window until released. |
    -  11|   {@link AddRemove AddButton} | An inline `+` button that will open a form for adding new elements. |
    -  12|   {@link AddRemove RemoveButton} | An inline `-` button that will remove an item. |
    -  13|   {@link TypeAhead TypeAhead} | A TypeAhead search input form. |
    -  14
    -  15 * 
    -  16 * 
    -  17 * const render = () => m.mount(root, {view: () => m('.hs-white', [
    -  18 * 
    -  19 *    m('h2.myGapButtons', 'Buttons'),
    -  20 *    m('h4', `Please click: (${clicked}-times clicked)`),
    -  21 *    m(hswidget.Button, { desc: {
    -  22 *        name: 'click me',
    -  23 *        clicked: () => clicked++
    -  24 *    }}),
    -  25 *    m('h4', `Select Radio Station: ${radio}`),
    -  26 *    m(hswidget.RadioButton, { desc: {
    -  27 *        items: ['1st', '2nd','3rd'],
    -  28 *        changed: (item) => radio = item
    -  29 *    }}),
    -  30 *    m('h4', `Please Toggle between 1st, 2nd, and 3rd`),
    -  31 *    m(hswidget.ToggleButton, { desc: {
    -  32 *        items: ['1st', '2nd','3rd'],
    -  33 *        changed: (item) => toggle = item
    -  34 *    }}),
    -  35 * 
    -  36 *    m('h2.myGapMenus', 'Menus'),
    -  37 *    m('h4', 'Please select:'),
    -  38 *    m(hswidget.Menu, { css: '.myMenu', desc: {
    -  39 *       items: menuItems,
    -  40 *       defaultItem: 'Two',
    -  41 *       changed: (item) => theContent = content[menuItems.indexOf(item)]
    -  42 *    }}),
    -  43 *    m('myMenuMain', theContent),
    -  44 * 
    -  45 *    m('h2.myGapModal', 'Modal Dialog Box'),
    -  46 *    m('h4', {onclick:() => showModal = true }, 'Click me to open a modal box'),
    -  47 *    showModal? m(hswidget.Modal, {
    -  48 *       width:  '300px',
    -  49 *       height: '200px',
    -  50 *       dismiss: () => showModal = false,
    -  51 *       content: m('', 'click on border or on the x to release')
    -  52 *    }) : undefined,
    -  53 * 
    -  54 *    m('h2.myGapCollapsibless', 'Collapsibles'),
    -  55 *    m(hswidget.Collapsible, { css:'.myCollapsible', components: [
    -  56 *       m('.myTitle', 'click me to toggle - no arrows'), content 
    -  57 *    ]}),
    -  58 *    m(hswidget.Collapsible, { css:'.myCollapsible', preArrow:true, components: [
    -  59 *       m('.myTitle', 'click me to toggle - left arrow'), content 
    -  60 *    ]}),
    -  61 *    m(hswidget.Collapsible, { css:'.myCollapsible', postArrow:true, components: [
    -  62 *       m('.myTitle', 'click me to toggle - right arrow'), content 
    -  63 *    ]}),
    -  64 *    m(hswidget.Collapsible, { css:'.myCollapsible', preArrow:true, postArrow:true, components: [
    -  65 *       m('.myTitle', 'click me to toggle - both arrows'), content
    -  66 *    ]}),
    -  67 *    m('', 'Background text, will be pushed down by the Collapsible'),
    -  68 * 
    -  69 *    m('h2.myGapTypeAhead', 'Typeahead Search'),
    -  70 *    m('h4', 'In-Memory List: ' + hero.length? `Selected: ${hero}` : 'Search for a Superhero'),
    -  71 *    m(hswidget.TypeAhead, { 
    -  72 *       placeholder: 'favorite hero',
    -  73 *       onsubmit: item => hero = item,
    -  74 *       list: ['Batman', 'Superman', 'Spiderman', 'Hulk']
    -  75 *    }),
    -  76 *    m('h4', `Remote List: ${friend.length? 'Selected: '+ friend : 'Search for a Friend'}`),
    -  77 *    m(hswidget.TypeAhead, { 
    -  78 *       placeholder: 'best friend',
    -  79 *       onsubmit: item => friend = item,
    -  80 *       autofocus: true,
    -  81 *       list: 'example/search.json'
    -  82 *    }),
    -  83 *
    -  84 *    m('h2.myGapCornerButtons', 'Corner Buttons'),
    -  85 *    m('h4', lastCornerButton),
    -  86 *    m('', Object.keys(hswidget.ButtonSymbols).map(
    -  87 *       (b) => m('.myCornerPositioned', [
    -  88 *          buttons[b]? m('.myCornerClicked', 'Yayy!!') : m('', b),
    -  89 *          m(hswidget.ToolbarButtons, { symbol:hswidget.ToolbarButtons.getSymbol(b), onclick:click(b) })
    -  90 *       ])
    -  91 *    )),
    -  92 * ])});
    -  93 * 
    -  94 * 
    -  95 * //--------------------------------------
    -  96 * // supporting variables:
    -  97 * const menuItems = ['One', 'Two', 'Three'];
    -  98 * const content   = ['1st', '2nd', '3rd'];
    -  99 * let  theContent = content[1];
    - 100 * let clicked = 0;
    - 101 * let radio = '';
    - 102 * let toggle = '';
    - 103 * const buttons = {};
    - 104 * let lastCornerButton = '';
    - 105 * let showModal = false;
    - 106 * let hero = '';
    - 107 * let friend = '';
    - 108 * 
    - 109 * const click = (button) => () => {
    - 110 *    lastCornerButton = '';
    - 111 *    if (hswidget.ButtonSymbols[button]) {
    - 112 *       lastCornerButton = m.trust(`last button pressed: ${hswidget.ButtonSymbols[button].sym}`);
    - 113 *       buttons[button] = true;
    - 114 *       setTimeout(reset(button), 800);
    - 115 *    }
    - 116 * };
    - 117 * 
    - 118 * const reset = (button) => () => {
    - 119 *    buttons[button] = false;
    - 120 *    m.redraw();
    - 121 * }
    - 122 *
    - 123 * render();
    - 124 * 
    - 125 *
    - 126 * 
    - 127 * .myMenuMain { 
    - 128 *    border:1px solid #ddd;
    - 129 *    border-top: 0px solid #ddd;
    - 130 * } 
    - 131 * .myMenu .hs-selectable { 
    - 132 *     background-color: #eef; 
    - 133 * }
    - 134 * .myMenu .hs-selected { 
    - 135 *     background-color: #ddf; 
    - 136 *     border-width:0px;
    - 137 * }
    - 138 * .myCollapsible {
    - 139 *     margin-bottom: 5px;
    - 140 * }
    - 141 * .myCollapsible .hs-collapsible-title {
    - 142 *     font-weight:bold;
    - 143 *     padding-left: 3px;
    - 144 *     background-color: #eee;
    - 145 * }
    - 146 * .myCollapsible .hs-collapsible-expanded {
    - 147 *     margin-left: 10px;
    - 148 * }
    - 149 * .myCornerClicked { background-color: #efe; }
    - 150 * .myCornerPositioned { 
    - 151 *      position: relative; 
    - 152 *      display: inline-block;
    - 153 *      box-sizing: border-box;
    - 154 *      background-color: #eee; 
    - 155 *      text-align: center;
    - 156 *      font-size: 70%;
    - 157 *      margin:  2px;
    - 158 *      padding-top: 20px;
    - 159 *      height: 50px;
    - 160 *      width:  50px;
    - 161 * }
    - 162 * .hs-corner-button { color: #008; }
    - 163 * 
    - 164 * .myGapButtons        { margin-top: 90px; }
    - 165 * .myGapMenus          { margin-top: 80px; }
    - 166 * .myGapModal          { margin-top: 50px; }
    - 167 * .myGapCollapsibless  { margin-top: 115px; }
    - 168 * .myGapTypeAhead      { margin-top: 130px; }
    - 169 * .myGapCornerButtons  { margin-top: 105px; }
    - 170 * 
    - 171 * 
    - 172*/

    - 173
    - 174/** */
    - 175
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/AddRemove.html b/docs/src/hsWidgets/AddRemove.html deleted file mode 100644 index 6abc12c..0000000 --- a/docs/src/hsWidgets/AddRemove.html +++ /dev/null @@ -1,36 +0,0 @@ - - -

    AddRemove.ts

    -
       1/**
    -   2 * # AddRemove Buttons
    -   3 * Adds '+' and '-' buttons to add or remove items from a list.
    -   4 */

    -   5
    -   6 /** */
    -   7import { m, Vnode}      from 'hslayout';
    -   8
    -   9export class AddButton {
    -  10    view(node:Vnode):Vnode {
    -  11        return m('.hs-add-button', { onclick:node.attrs.add }, '');
    -  12    }
    -  13}
    -  14
    -  15export class RemoveButton {
    -  16    view(node:Vnode):Vnode {
    -  17        return m('.hs-remove-button', { onclick:node.attrs.remove }, '');
    -  18    }
    -  19}
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/Button.html b/docs/src/hsWidgets/Button.html deleted file mode 100644 index 7c64052..0000000 --- a/docs/src/hsWidgets/Button.html +++ /dev/null @@ -1,32 +0,0 @@ - - -

    Button.ts

    -
       1/**
    -   2 * # Button Widget
    -   3 * invoked as `m(Button, {name:, onclick:})`
    -   4 */

    -   5
    -   6/** */
    -   7import { m, Vnode }     from 'hslayout';
    -   8
    -   9
    -  10export class Button {
    -  11    view(node: Vnode) {
    -  12        return m('.hs-button', {onclick:node.attrs.onclick},  node.attrs.name || 'button');
    -  13    }
    -  14}
    -  15
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/Collapsible.html b/docs/src/hsWidgets/Collapsible.html deleted file mode 100644 index cf64495..0000000 --- a/docs/src/hsWidgets/Collapsible.html +++ /dev/null @@ -1,54 +0,0 @@ - - -

    Collapsible.ts

    -
       1/**
    -   2 * # Collapsible
    -   3 * 
    -   4 */

    -   5
    -   6 /** */
    -   7import { m, Vnode } from 'hslayout';
    -   8
    -   9const expanded: {string?:boolean} = {};
    -  10
    -  11const getKey = () => 'hs'+Math.floor(Math.random()*2000000);
    -  12
    -  13/**
    -  14 * returns a Vnode that can be toggled to expand and contract by clicking on the first `component`.
    -  15 * @param css the css class to assign to the entire collapsible div
    -  16 * @param attrs optional attributes list:
    -  17 * - isExpanded: boolean indicates if the collapsible is initially expanded
    -  18 * @param components array of two components: 
    -  19 * - component[0] is the title of the collapsible. This will remain visible and cabn be clicked 
    -  20 *   on to expand or contract the remaining components
    -  21 * - component[1] a Vnode or an array of Vnodes that will be collapsed or expanded.
    -  22 */

    -  23export function collapsible(css:string, attrs:any, components:Vnode[]) {
    -  24    function toggle() {
    -  25        expanded[key] = !expanded[key];
    -  26//        m.redraw();
    -  27    }
    -  28    if (!components) { components = attrs; attrs = undefined; }
    -  29    const key = getKey();
    -  30    if (attrs.isExpanded) { expanded[key] = true; }
    -  31    return m(`.hs-collapsible ${css}`, { onclick:toggle}, [
    -  32            components[0],
    -  33            !components[1]? undefined : m('.hs-collapsible-content', { 
    -  34                class: expanded[key]?'':'hs-collapsed'
    -  35            }, components[1].map((c:any) =>c))
    -  36        ]);
    -  37}
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/Menu.html b/docs/src/hsWidgets/Menu.html deleted file mode 100644 index f51a002..0000000 --- a/docs/src/hsWidgets/Menu.html +++ /dev/null @@ -1,142 +0,0 @@ - - -

    Menu.ts

    -
       1/**
    -   2 * # hsMenu
    -   3 * Creates a simple menu with several items.
    -   4 * The `Menu` object is passed into `Mithril`'s m function with a `MenuDesc` object:
    -   5 * ```
    -   6 * interface MenuDesc {
    -   7 *    items: string[];                // the items on the menu
    -   8 *    select: (item:string) => void;  // called when item clicked
    -   9 *    selectedItem?: string;          // the currently selected item
    -  10 *    size?:string[];                 // size to layout menu items
    -  11 * }
    -  12 * ```
    -  13 * 
    -  14 * ## Example
    -  15 * 
    -  16 * 
    -  17 * const items = ['One', 'Two', 'Three'];
    -  18 * const content   = ['1st', '2nd', '3rd'];
    -  19 * let  theContent = content[1];
    -  20 * 
    -  21 * m.mount(root, {view: () => m(hslayout.Container, {
    -  22 *     rows:["30px", "fill"],
    -  23 *     content:[
    -  24 *         m(widget.Menu, {desc: {
    -  25 *             items: items,
    -  26 *             selectedItem: 'Two',
    -  27 *             select: item => 
    -  28 *                theContent = content[items.indexOf(item)]
    -  29 *         }}),
    -  30 *         m(hslayout.Container, { css:'myMain', content: theContent })
    -  31 *     ]
    -  32 * })});
    -  33 *
    -  34 * 
    -  35 * 
    -  36 * .myMain { 
    -  37 *    border:1px solid #ddd;
    -  38 *    border-top: 0px solid #ddd;
    -  39 * } 
    -  40 * .hs-menu-item-selected { 
    -  41 *     background-color: #eed; 
    -  42 *     border-width:0px;
    -  43 * }
    -  44 * 
    -  45 * 

    -  46 */

    -  47
    -  48 /** */
    -  49import { Container, m, Vnode } from 'hslayout';
    -  50
    -  51/** passed into Menu from the calling application */
    -  52export interface MenuDesc {
    -  53    /** the items on the menu */
    -  54    items: string[];
    -  55    /** the currently selected item */
    -  56    selectedItem?: string;
    -  57    /** the function to call when the selection changes */
    -  58    select: (item:string) => void;
    -  59    /** optional array of size strings used to layout the menu items; defaults to `[ ]` */
    -  60    size?:string[];
    -  61}
    -  62
    -  63/** interface of the parameter passed to a `MenuItem` */
    -  64export interface MenuItemDesc {
    -  65    /** the item's title */
    -  66    title: string;
    -  67    /** the item's select status */
    -  68    isSelected: boolean;
    -  69    /** the function to call if this item is selected */
    -  70    clicked: (item:string) => void;
    -  71}
    -  72
    -  73/**
    -  74 * Creates a simple menu with several items, as configured by the desc:MenuDesc object passed as a parameter. 
    -  75 */

    -  76export class Menu extends Container {
    -  77    /** instance variable, keeping a list of menu items and a `select` function for tracking which item is selected. */
    -  78    menu = { 
    -  79        items:<{string:MenuItemDesc}> {},
    -  80        select: (title:string) => {
    -  81            Object.keys(this.menu.items).forEach((key:string) => { 
    -  82                this.menu.items[key].isSelected = (key===title); 
    -  83            });
    -  84        }
    -  85    };
    -  86
    -  87    getComponents(node: Vnode): Vnode {
    -  88        const _menu = this.menu;
    -  89        const desc = node.attrs.desc;
    -  90        node.attrs.desc = undefined;
    -  91
    -  92        desc.selectedItem = desc.selectedItem || desc.items[0];
    -  93        node.attrs.columns = desc.size || [];
    -  94        node.attrs.css = '.hs-menu';
    -  95        return desc.items.map((l:string) => {
    -  96            _menu.items[l] = _menu.items[l] || { 
    -  97                title: l, 
    -  98                isSelected: l === desc.selectedItem, 
    -  99                clicked:(item:string) => {
    - 100                    desc.selectedItem = item;
    - 101                    _menu.select(item); // local housekeeping: make sure the item's style shows correct selection
    - 102                    if (typeof desc.select === 'function') { 
    - 103                        desc.select(item);  // trigger any actions form the selection
    - 104                    }     
    - 105                }
    - 106            }; 
    - 107            return m(MenuItem, { desc:_menu.items[l] });
    - 108        });
    - 109    }
    - 110};
    - 111
    - 112/**
    - 113 * Creates a menu item as part of the menu, as configured by the desc:MenuItemDesc object passed as a parameter.
    - 114 */

    - 115class MenuItem extends Container {
    - 116    getComponents(node: Vnode): Vnode {
    - 117        const desc:MenuItemDesc = node.attrs.desc;
    - 118        node.attrs.desc = undefined;
    - 119        node.attrs.css = `.hs-menu-item ${desc.isSelected?'hs-menu-item-selected': ''}`;
    - 120        node.attrs.onclick = () => { desc.clicked(desc.title); };
    - 121        return desc.title;
    - 122    }
    - 123};
    - 124
    - 125
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/Menu.spec.html b/docs/src/hsWidgets/Menu.spec.html deleted file mode 100644 index 441ea29..0000000 --- a/docs/src/hsWidgets/Menu.spec.html +++ /dev/null @@ -1,66 +0,0 @@ - - -

    Menu.spec.ts

    -
       1
    -   2const hslayout = require('hslayout');
    -   3const m = hslayout.m;
    -   4const o = hslayout.o;
    -   5
    -   6const hsMenu = require("../src/Menu");
    -   7const Menu = hsMenu.Menu;
    -   8
    -   9const left  = ['0%', '25%', '50%', '75%'];
    -  10const right = ['75%', '50%', '25%', '0%'];
    -  11const title = ['1a', '2a', '3a', '4a']; 
    -  12
    -  13o.spec('hsMenu', () => {
    -  14    let menu:any;
    -  15    o.before(() => {
    -  16        const md = { 
    -  17            items: title,
    -  18            select: (item:string) => { console.log('selected'); }
    -  19        };
    -  20        m.mount(o.root, {view: () => m(Menu, { desc: md }) }); 
    -  21        menu = o.root.childNodes[0];
    -  22    });
    -  23
    -  24    o('Menu', () => {
    -  25        o(menu).notEquals(undefined)('creation');
    -  26        o(menu.className.indexOf('hs-menu')).notEquals(-1)("is menu");
    -  27        o(menu.className.indexOf('hs-layout')).notEquals(-1)("is layout");
    -  28    });
    -  29
    -  30    o('Menu Items', () => {
    -  31        const cn = menu.childNodes;
    -  32        o(cn.length).equals(4)("has 4 menu items");
    -  33        cn.forEach((c:any, i:any) => {
    -  34            o(c.className.indexOf('hs-menu-item')).notEquals(-1)(`item ${i+1} menu-item class`);
    -  35            o(c.className.indexOf('hs-layout')).notEquals(-1)(`item ${i+1} layout class`);
    -  36            o(c.className.includes('hs-menu-item-selected')).equals((i===0)?true:false)(`item ${i+1} selected class`);
    -  37            o(c.style.left).equals(left[i])(`item ${i+1} left`);
    -  38            o(c.style.right).equals(right[i])(`item ${i+1} right`);
    -  39            o(c.style.top).equals('0%')(`item ${i+1} top`);
    -  40            o(c.style.bottom).equals('0%')(`item ${i+1} bottom`);
    -  41            o(c.childNodes.length).equals(1)(`item ${i+1} num children`);
    -  42            o(c.childNodes[0].className).equals('hs-leaf')(`item ${i+1} child leaf`);
    -  43            o(c.childNodes[0].childNodes[0].nodeValue).equals(title[i])(`item ${i+1} child leaf text`);
    -  44        });
    -  45    });
    -  46
    -  47});
    -  48
    -  49
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/Modal.html b/docs/src/hsWidgets/Modal.html deleted file mode 100644 index 5aa93f9..0000000 --- a/docs/src/hsWidgets/Modal.html +++ /dev/null @@ -1,32 +0,0 @@ - - -

    Modal.ts

    -
       1import { m, Vnode}      from 'hslayout';
    -   2
    -   3
    -   4export class Modal {
    -   5    private static modal:Vnode; 
    -   6    public static show()    { Modal.modal = m(Modal); }
    -   7    public static dismiss() { Modal.modal = undefined; }
    -   8    view(node:Vnode) {
    -   9        return m('.hs-modal-frame', !Modal.modal? '': [
    -  10            m('.hs-modal-background', { onclick: () => { Modal.modal=undefined; }}, ''),
    -  11            m('.hs-modal-foreground', node.attrs.content || 'modal pane')
    -  12        ]);
    -  13    }
    -  14}
    -  15
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/css/Button.html b/docs/src/hsWidgets/css/Button.html deleted file mode 100644 index 5fd4e34..0000000 --- a/docs/src/hsWidgets/css/Button.html +++ /dev/null @@ -1,32 +0,0 @@ - - -

    css/Button.ts

    -
       1/**
    -   2 * # Button Widget
    -   3 * invoked as `m(Button, {name:, onclick:})`
    -   4 */

    -   5
    -   6/** */
    -   7import { m, Vnode }     from 'hslayout';
    -   8
    -   9
    -  10export class Button {
    -  11    view(node: Vnode) {
    -  12        return m('.hs-button', {onclick:node.attrs.onclick},  node.attrs.name || 'button');
    -  13    }
    -  14}
    -  15
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/example/start.html b/docs/src/hsWidgets/example/start.html deleted file mode 100644 index b1f60b6..0000000 --- a/docs/src/hsWidgets/example/start.html +++ /dev/null @@ -1,19 +0,0 @@ - - -

    example/start.ts

    -
       1import { Menu } from '../';
    -   2if (Menu) {}
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/index.html b/docs/src/hsWidgets/index.html deleted file mode 100644 index 52b933e..0000000 --- a/docs/src/hsWidgets/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - -

    index.ts

    -
       1/**
    -   2 * @description hsWidgets: Library of UI screen elements.
    -   3 */

    -   4
    -   5/**
    -   6 * 
    -   7 */

    -   8export { Menu, MenuDesc }  from './Menu'; 
    -   9export { collapsible }     from './Collapsible'; 
    -  10
    - - \ No newline at end of file diff --git a/docs/src/hsWidgets/overview.html b/docs/src/hsWidgets/overview.html deleted file mode 100644 index 5f47fd6..0000000 --- a/docs/src/hsWidgets/overview.html +++ /dev/null @@ -1,28 +0,0 @@ - - -

    overview.ts

    -
       1/**
    -   2# hsWidgets 
    -   3Provides various UI widgets:
    -   4| Widget | Description |
    -   5|========|=============|
    -   6| .{@link hsGraph:hsMenu Menus} | A group of horizontal menu items that can trigger actions |
    -   7
    -   8*/

    -   9
    -  10/** */
    -  11
    - - \ No newline at end of file From 4bc44cfccc512b2846ca11b2f6b47fb863c7efa4 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 2 Jun 2018 22:14:13 -0700 Subject: [PATCH 03/17] added sources to docs --- docs/src/Data.html | 557 ++++++++++++++++++++++++++++++++++++++ docs/src/DataFilters.html | 267 ++++++++++++++++++ docs/src/index.html | 32 +++ docs/src/overview.html | 73 +++++ 4 files changed, 929 insertions(+) create mode 100644 docs/src/Data.html create mode 100644 docs/src/DataFilters.html create mode 100644 docs/src/index.html create mode 100644 docs/src/overview.html diff --git a/docs/src/Data.html b/docs/src/Data.html new file mode 100644 index 0000000..490c8c7 --- /dev/null +++ b/docs/src/Data.html @@ -0,0 +1,557 @@ + + +

    Data.ts

    +
       1/**
    +   2 */

    +   3
    +   4 /** */
    +   5import { Condition, filter } from './DataFilters';
    +   6
    +   7/** defines a [min-max] range */
    +   8export type NumRange = [number, number];
    +   9
    +  10/** defines a numeric domain that includes all values of a column */
    +  11export type NumDomain = [number, number];
    +  12
    +  13/** defines a Date domain that includes all values of a column */
    +  14export type DateDomain = [Date, Date];
    +  15
    +  16/** defines a categorical domain that includes all values of a column */
    +  17export type NameDomain = string[];
    +  18
    +  19/** defines a generic domain that can be any of the typed domains. */
    +  20export type Domain = NumDomain | DateDomain | NameDomain;
    +  21
    +  22/** defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    +  23export type ColumnReference = number|string;
    +  24
    +  25/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    +  26export type DataVal = number|string|Date;
    +  27
    +  28/** a single row of column values */
    +  29export type DataRow = DataVal[];
    +  30
    +  31/** a JSON format data set, using arrays of names and rows */
    +  32export interface DataSet {
    +  33    /** an optional name for the data set */
    +  34    name?:  string;
    +  35    /** an array of column names. Each name matches the column with the same index in DataRow */
    +  36    colNames:  string[];   
    +  37    /** rows of data */
    +  38    rows:   DataRow[];
    +  39}
    +  40
    +  41/** a JSON format data set, using an array of {name:value, ...} literals*/
    +  42export type DataLiteralSet = Array;
    +  43
    +  44interface TypeStruct { type: string; count: number;};
    +  45
    +  46interface MetaStruct {
    +  47    name:       string;         // column name
    +  48    column:     number;         // column index
    +  49    accessed:   boolean;        // has column data been accessed?
    +  50    cast:       boolean;        // has column data been cast 
    +  51    types:      TypeStruct[];   // data types, sorted by likelihood
    +  52}
    +  53
    +  54export type sortFn = (x:any, y:any) => number;
    +  55export type mapFn  = (colVal:any, colIndex?:number, rowIndex?:number, rows?:any[][]) => any;
    +  56
    +  57/**
    +  58 * # Data
    +  59 * A simple in-memory database that holds data in rows of columns.
    +  60 * 
    +  61 */

    +  62export class Data {
    +  63    //----------------------------
    +  64    // public part
    +  65    //----------------------------
    +  66    public static type = {
    +  67        number:     'number data',
    +  68        name:       'name data',
    +  69        date:       'date data',
    +  70        currency:   'currency data',
    +  71        percent:    'percent data',
    +  72        nominal:    'nominal data'
    +  73    };
    +  74
    +  75    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    +  76        data = data || [{}];
    +  77        const names = Object.keys(data[0]);
    +  78        const rows = data.map((r:any) => 
    +  79            names.map((n:string) => r[n]));
    +  80        return { rows:rows, colNames:names, name:name||undefined };
    +  81    }
    +  82
    +  83    constructor(data?:DataSet) {
    +  84        this.import(data);
    +  85    }
    +  86
    +  87    /**
    +  88     * @return the `name` field for this data base, if any
    +  89     */

    +  90    public getName():string {
    +  91        return this.name;
    +  92    }
    +  93
    +  94    /**
    +  95     * Imports data from an object literal `data`
    +  96     * @param data the data set to import
    +  97     */

    +  98    public import(data:DataSet) {
    +  99        this.name = data.name;
    + 100        this.setData(data.rows, data.colNames);
    + 101    }
    + 102
    + 103    /**
    + 104     * Exports to an object literal
    + 105     */

    + 106    public export():DataSet {
    + 107        return {
    + 108            rows: this.getData(),
    + 109            colNames:this.colNames()
    + 110        };
    + 111    }
    + 112
    + 113    /**
    + 114     * returns the 2D array underlying the data base.
    + 115     */

    + 116    public getData():DataRow[] {
    + 117        return this.data;
    + 118    }
    + 119
    + 120    /**
    + 121     * Returns the values in the specified column as a new array.
    + 122     * @param col the column to return.
    + 123     */

    + 124    public getColumn(col:ColumnReference): DataVal[] {
    + 125        const cn = this.colNumber(col);
    + 126        return this.data.map((row:DataRow) => row[cn]);
    + 127    }
    + 128
    + 129    /**
    + 130     * adds a new column to the data set. if `newCol` already exists, 
    + 131     * the column index is returned withoput change.
    + 132     * @param col the name of the new column
    + 133     * @return the index for the new column
    + 134     */

    + 135    public colAdd(col:string):number {
    + 136        let m = this.getMeta(col);
    + 137        if (m === undefined) { 
    + 138            m = this.meta[col] = {};
    + 139            m.name   = col; 
    + 140            m.column = this.meta.length;
    + 141            this.meta.push(m);      // access name by both column name and index
    + 142            m.cast     = false;         // has not been cast yet
    + 143            m.accessed = false;         // has not been accessed yet
    + 144        }
    + 145        return m.column;
    + 146    }
    + 147
    + 148    /**
    + 149     * initializes the specifed column with values, adding a new column if needed. 
    + 150     * If `val`is a function, it is called as ```
    + 151     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    + 152     * ```
    + 153     * @param col the column to initialize
    + 154     * @param initializer the value to initialize with, or a function whose return
    + 155     * value is used to initialize the column
    + 156     */

    + 157    public colInitialize(col:ColumnReference, initializer:any) {
    + 158        const cn = this.colNumber(col);
    + 159        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    + 160        const fn = typeof initializer === 'function';
    + 161        if (cn!==undefined) {
    + 162            this.data.map((r:DataRow, i:number) =>
    + 163                r[cn] = fn? initializer(r[cn], i, r) : initializer
    + 164            );
    + 165        }
    + 166    }
    + 167
    + 168    /**
    + 169     * returns the column index of the specified column. 
    + 170     * `col` can be either an index or a name.
    + 171     * @param column the data column, name or index, for which to return the index. 
    + 172     * @return the column number or `undefined`.
    + 173     */

    + 174    public colNumber(col:ColumnReference) {
    + 175        const m = this.getMeta(col);
    + 176        if (!m) { return undefined; }
    + 177        else {
    + 178            m.accessed = true; 
    + 179            return m.column; 
    + 180        }
    + 181    }
    + 182    
    + 183    /**
    + 184     * returns the column name for the specified column. 
    + 185     * `col` can be either an index or a name.
    + 186     * @param column the data column, name or index. 
    + 187     * @return the column name or `undefined`.
    + 188     */

    + 189    public colName(col:ColumnReference) {
    + 190        var m = this.getMeta(col);
    + 191        if (!m) { return undefined; }
    + 192        m.accessed = true; 
    + 193        return m.name; 
    + 194    }
    + 195
    + 196    /**
    + 197     * returns the names for all columns. 
    + 198     * @return an array of strings with the names.
    + 199     */

    + 200    public colNames():string[] {
    + 201        return this.meta.map((m:MetaStruct) => m.name); 
    + 202    }
    + 203
    + 204    /**
    + 205     * returns the column type for the specified column. 
    + 206     * `col` can be either an index or a name.
    + 207     * @param column the data column, name or index. 
    + 208     * @return the column type.
    + 209     */

    + 210    public colType(col:ColumnReference) { 
    + 211        const meta = this.getMeta(col);
    + 212        return meta? meta.types[0].type : Data.type.name;
    + 213    }
    + 214
    + 215    /**
    + 216     * modifies `domain` to include all values in column `col`.
    + 217     * @param col the column name or index 
    + 218     * @param domain the 
    + 219     */

    + 220    public findDomain(col:ColumnReference, domain:Domain) {
    + 221        if (col === undefined) { // use array index as domain
    + 222            domain[0] = 0;
    + 223            domain[1] = this.data.length-1;
    + 224        } else {
    + 225            const c = this.colNumber(col);
    + 226            const type = this.colType(col);
    + 227            if (this.data === undefined) {
    + 228                console.log('no data'); 
    + 229            }
    + 230            switch(type) {
    + 231                case Data.type.nominal: 
    + 232                    this.data.forEach((r:DataRow) => {
    + 233                        const nomDom = domain;
    + 234                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    + 235                    });
    + 236                    break;
    + 237                default: 
    + 238                    this.data.forEach((r:DataRow) => {
    + 239                        let v:number = r[c];
    + 240                        if (v!==undefined && v!==null) {
    + 241                            domain[0] = (v + 242                            domain[1] = (v>domain[1])? v : domain[1];
    + 243                        }
    + 244                    });
    + 245            }
    + 246        }
    + 247    }
    + 248
    + 249    public castData() {
    + 250        this.meta.forEach((c:MetaStruct) => {
    + 251            const col = c.column;
    + 252            if (!c.cast) {
    + 253                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    + 254            }
    + 255            c.cast = true;
    + 256        });
    + 257    }
    + 258
    + 259    /**
    + 260     * filters this data set and returns a new data set with a 
    + 261     * shallow copy of rows that pass the `condition`.
    + 262     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    + 263     * @param condition filters 
    + 264     * @return a new Data object with rows that pass the filter
    + 265     */

    + 266    public filter(condition:Condition):Data {
    + 267        return filter(this, condition);
    + 268    }
    + 269
    + 270    /**
    + 271     * @description Sorts the rows of values based on the result of the `sortFn`, 
    + 272     * which behaves similarly to the Array.sort method.  
    + 273     * Two modes are supported:
    + 274     * # Array Mode
    + 275     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    + 276     * This allows for complex sorts, combining conditions across multiple columns.
    + 277     * ```
    + 278     * data.sort((row1, row2) => row1[5] - row2[5] );
    + 279     * ```
    + 280     * # Column mode
    + 281     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 282     * into `sortFn`. This allows filtering for simple conditions.

    + 283     * **The specified column will be automatically cast prior to sorting**

    + 284     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    + 285     * @param col optional; the data column to use for sorting. 
    + 286     * @param sortFn a function to implement the conditions, 
    + 287     * follows the same specifications as the function passed to Array.sort(). 
    + 288     * Some predefined sort function can be invoked by providing a 
    + 289     * respective string instead of a function. The following functions are defined:
    + 290        
    + 291        
    + 292        
    + 293        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    + 294     * @return the Data object in order to allow for chaining.
    + 295     */

    + 296    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    + 297        let fn = sortFn;
    + 298        if (!col) {
    + 299            this.data.sort(fn);
    + 300        } else {
    + 301            col = this.colNumber(col);
    + 302            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b + 303            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    + 304            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    + 305        }
    + 306        return this;
    + 307    }
    + 308
    + 309    /** 
    + 310    *  Maps one or more columns in each rows of values based 
    + 311     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    + 312     * Two modes are supported:
    + 313     * # Array Mode
    + 314     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    + 315     * This allows for complex mapping combining conditions across multiple columns.
    + 316     * ```
    + 317     * data.map(function(values){ 
    + 318     *    values[1] = values[3] * values[5]; 
    + 319     *    return values; 
    + 320     * });
    + 321     * ```
    + 322     * Be sure to return the `values` array as a result.
    + 323     * # Column mode
    + 324     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 325     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    + 326     * ```
    + 327     * data.map('Price', function(value, i, values) { 
    + 328     *    return value * 2; 
    + 329     * });
    + 330     * ```
    + 331     * @param col the data column, or columns, to apply the mapping to. 
    + 332     * @param mapFn a function to implement the mapping,
    + 333     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    + 334     * - `val`: the column value in the current row
    + 335     * - `c`: the column index in the current row
    + 336     * - `i`: the row index 
    + 337     * - `rows`: the rows being iterated over
    + 338`    * 
    + 339     * follows the same specifications as the function passed to Array.map().

    + 340     * For column mode, some predefined map functions can be invoked by providing a 
    + 341     * respective string instead of a function. The following functions are defined:
    + 342        
    + 343        
    + 344        
    + 345        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    + 346     * @return a new Data object containing the mapping.
    + 347     */

    + 348    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    + 349        const noop = (val:any) => val;
    + 350        const cumulate = () => { 
    + 351            let sum=0; 
    + 352            return (val:number, i:number) => { sum += +val; return sum; };
    + 353        };
    + 354        function getFn() {
    + 355            let fn; // define fn inside each col loop to ensure initialization
    + 356            switch (mapFn) {
    + 357                case 'cumulate': fn = cumulate(); break;
    + 358                case 'noop':     fn = noop; break;
    + 359                default:         fn = mapFn;
    + 360            }
    + 361            return fn;
    + 362        }
    + 363
    + 364        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    + 365
    + 366        const names = col['length']? col : [col];            
    + 367        names.map((cn:ColumnReference) => {
    + 368            const c = this.colNumber(cn);
    + 369            let fn = getFn(); // define fn inside each col loop to ensure initialization
    + 370            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    + 371                row[c] = fn(row[c], c, i, rows); 
    + 372                return row;
    + 373            });
    + 374        });
    + 375        return result;
    + 376    }
    + 377
    + 378    //----------------------------
    + 379    // private part
    + 380    //----------------------------
    + 381    private data: DataRow[]    = [];
    + 382    private meta: MetaStruct[] = [];
    + 383    private name: string;
    + 384
    + 385    private getMeta(col:ColumnReference):MetaStruct { 
    + 386        if (!this.meta) { this.meta = []; }
    + 387        if (!this.meta[col]) { return undefined; }
    + 388        this.meta[col].accessed = true;
    + 389        return this.meta[col]; 
    + 390    }
    + 391
    + 392    /**
    + 393     * sets `data` to the existing data set. If data has previously been set, 
    + 394     * `data` will be added to the end of the list if all `names`  match those of the 
    + 395     * existing set. 
    + 396     * @param data the data to add
    + 397     * @param names an array of names that match the columns
    + 398     * @param autoType unless set to false, the method will attempt to determine the 
    + 399     * type of data and automatically cast data points to their correct value
    + 400     */

    + 401    private setData(data:DataRow[], names:string[], autoType=true):void {
    + 402        this.meta = [];
    + 403        this.data = data;
    + 404        if (!names) {
    + 405            console.log();
    + 406        }
    + 407        names.forEach((col:string) => this.colAdd(col));
    + 408        names.forEach((col:string) => this.findTypes(col));
    + 409        this.castData();
    + 410    }
    + 411
    + 412    /**
    + 413     * Determines the type of data in `col`. An array of counts is created for all
    + 414     * encountered types, sorted by descending frequency. THe most likely type in position 0
    + 415     * of the array is returned.
    + 416     * @param col the index of the column to be typed. 
    + 417     * @return the most likely type of data in `col`.
    + 418     */

    + 419    private findTypes(col:ColumnReference):string {
    + 420        const m = this.getMeta(col);
    + 421        const types:TypeStruct[] = [];
    + 422        Object.keys(Data.type).forEach((t:string) => {
    + 423            const ts = { type: Data.type[t], count: 0 }; 
    + 424            types.push(ts);
    + 425            types[Data.type[t]] = ts;
    + 426        });
    + 427        for (let v of this.allRows(col)) {
    + 428            const t = this.findType(v);
    + 429            if (t !== null) { types[t].count++; }
    + 430        }
    + 431        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    + 432            if (a.type==='currency'&&a.count>0) { return -1; }
    + 433            if (b.type==='currency'&&b.count>0) { return 1; }
    + 434            return b.count - a.count;
    + 435        });
    + 436        m.types = types;
    + 437        return types[0].type;
    + 438    }
    + 439
    + 440    /**
    + 441     * @description determines the data type. Supported types are 
    + 442     * ```
    + 443     * 'date':    sample represents a Date, either as a Date object or a String 
    + 444     * 'number':  sample represents a number
    + 445     * 'percent': sample represents a percentage (special case of a real number)
    + 446     * 'nominal': sample represents a nominal (ordinal or categorical) value
    + 447     * ```
    + 448     * @param val the value to bve typed.
    + 449     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    + 450     */

    + 451    private findType(val:DataVal) {
    + 452        if (val && val!=='') {
    + 453            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    + 454            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    + 455
    + 456            // else: val is a string:
    + 457            const strVal = ''+val;
    + 458            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    + 459            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    + 460            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    + 461            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    + 462
    + 463            // european large number currency representation: '$dd,ddd[,ddd]'
    + 464            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    + 465                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    + 466                    return Data.type.currency; 
    + 467                }
    + 468            }
    + 469            switch (strVal.toLowerCase()) {
    + 470                case "null": break;
    + 471                case "#ref!": break;
    + 472                default: if (val.length>0) { return Data.type.nominal; }
    + 473            }
    + 474        }
    + 475        return null;
    + 476    }    
    + 477
    + 478    /**
    + 479     * A generator that provides the specified column value for each row in `Data` in sequence. 
    + 480     * @param column 
    + 481     */

    + 482    private * allRows(column:ColumnReference):Iterable {
    + 483        const c = this.colNumber(column);
    + 484        for (let r=0; r + 485            yield this.data[r][c];
    + 486        }
    + 487    }
    + 488
    + 489    /**
    + 490     * @param val the string to convert to a date
    + 491     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    + 492     * @returns a new Date object parsed from `str`.
    + 493     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    + 494     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    + 495     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    + 496     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    + 497     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    + 498     */

    + 499    private toDate(val:DataVal, limitYear=1970):Date {
    + 500        let d:Date;
    + 501        if (val instanceof Date) { d = val; }
    + 502                            else { d = new Date(val); }   
    + 503        let yr=d.getFullYear();
    + 504        if (yr < 100) { 
    + 505            yr += 1900; 
    + 506            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    + 507        }
    + 508        return d;
    + 509    }
    + 510
    + 511    /**
    + 512     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    + 513     * does not match any of the previous keywords, no casting occurs.
    + 514     * @param sample The value to cast.
    + 515     * @returns The result of the cast. 
    + 516     * @description Casts the sample to the specified data type.
    + 517     */

    + 518    private castVal(type:string, val:DataVal):DataVal {
    + 519        switch (type) {
    + 520            case Data.type.date:    if (val instanceof Date) { return val; }
    + 521                            val = this.toDate(val);
    + 522                            if (isNaN(val.getTime())) { val = null; }
    + 523                            break;
    + 524            case Data.type.percent: if (typeof val === 'string') {
    + 525                                const num = parseFloat(val);
    + 526                                val = (val).endsWith('%')? num/100 : num;
    + 527                            } 
    + 528                            if (isNaN(val)) { val = null; }
    + 529                            break;
    + 530            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    + 531             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    + 532             /* falls through */
    + 533            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    + 534                            if (isNaN(val)) { val = null; }
    + 535                            break;
    + 536            default:        val = ''+val;
    + 537        }
    + 538        return val;
    + 539     }     
    + 540}
    + + \ No newline at end of file diff --git a/docs/src/DataFilters.html b/docs/src/DataFilters.html new file mode 100644 index 0000000..7e60815 --- /dev/null +++ b/docs/src/DataFilters.html @@ -0,0 +1,267 @@ + + +

    DataFilters.ts

    +
       1
    +   2/**
    +   3* Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object. 
    +   4* Each row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object. 
    +   5
    +   6* # Condition construction
    +   7*  
    +   8* ### General Condition
    +   9* ```
    +  10* Condition = 
    +  11*    IndexCondition            -> conditions on the row index
    +  12* || RecursiveCondition        -> (set of) conditions on column values
    +  13* ```
    +  14
    +  15* ### IndexCondition
    +  16* ```
    +  17* IndexCondition =
    +  18*    rowIndex:number           -> true if row index matches
    +  19* ```
    +  20
    +  21* ### RecursiveCondition
    +  22* ```
    +  23* RecursiveCondition =
    +  24*    OrCondition               -> OR: true if any compound condition is true
    +  25* || AndCondition              -> AND: true if all compound conditions are true
    +  26
    +  27* OrCondition =                -> OR: true if
    +  28*    AndCondition[]               -> any of the AndConditions are true
    +  29* || IndexCondition[]             -> any of thr IndexConditions are true
    +  30
    +  31* AndCondition =               -> AND: true if
    +  32*    SetAndCondition              -> all SetAndConditions are true
    +  33* || TermAndCondition             -> or if all TermAndConditions are true
    +  34*
    +  35* SetAndCondition = {          -> AND: true if all sub-conditions are true
    +  36*    'or':  RecursiveCondition    -> true if any RecursiveCondition is true
    +  37* || 'and': RecursiveCondition    -> true if all RecursiveCondition are true
    +  38* || 'not': RecursiveCondition    -> true if the condition is false
    +  39*
    +  40* TermAndCondition = {         -> Terminal AND: true if all terminal sub-conditions are true
    +  41*    colDesc:colValue             -> true if colValue matches 
    +  42* || colDesc:[colValue, ...]      -> true if any of the colValues match
    +  43* || colDesc:function(value,row)  -> true if function returns true 
    +  44* }
    +  45
    +  46* colDesc = either column name or index
    +  47* ```
    +  48
    +  49* ### Practical Tips
    +  50* ```
    +  51*    {'or': [recurCond, ...]}    -> OR, same as [recurCond, ...]
    +  52* || {'or': {SetCond, ...}}      -> OR, same as [SetCond, ...]
    +  53* || {'and': [recurCond, ...]}   -> AND, true if all recurCond are true
    +  54* || {'and': {SetCond, ...}}     -> AND, same as {SetCond, ...}
    +  55* || {'not': {SetCond, ...}}     -> NAND: true if the SetCond are true
    +  56* || {'not': [recurCond, ...]}   -> NOR: true if any of the recurCond are true
    +  57* ```
    +  58*      
    +  59* # Example
    +  60
    +  61
    +  62* const colNames = ['Name', 'Value', 'Start', 'End'];
    +  63* const rows = [
    +  64*   ['Harry', '100', '3/1/14', '11/20/14'], 
    +  65*   ['Mary', '1500', '7/1/14',  '9/30/14'],
    +  66*   ['Peter', '400', '5/20/14', '4/30/15'],  
    +  67*   ['Jane', '700', '11/13/14', '8/15/15']
    +  68* ]
    +  69* const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  70
    +  71* queries = [
    +  72*   ['0', undefined,                           'undefined query => pass all'],
    +  73*   ['1', [],                                  'empty OR:  []   => fail all'],
    +  74*   ['2', {},                                  'empty AND: {}   => pass all'],
    +  75*   ['3', 1,                                   '2nd row: pass row 1'],
    +  76*   ['4', [1,3],                               '2nd+4th: pass rows: 1 and 3'],
    +  77*   ['5', {Name:"Jane"},                       'Name is Jane'],
    +  78*   ['6', {1:1500},                            'Column 2 is 1500'],
    +  79*   ['7', {Name:["Peter", "Jane"]},            'Name is Peter or Jane'],
    +  80*   ['8', [{Name:"Peter"}, {Value:1500}],      'Name is Peter or Value is 1500'],
    +  81*   ['9', {or:{Name:"Peter", Value:1500}},     'OR:  same as 8:'],
    +  82*   ['A', {or:[{Name:"Peter"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],
    +  83*   ['B', {Name:"Peter", Value:400},           'Name is Peter and Value is 400'],
    +  84*   ['C', {and:{Name:"Peter", Value:400}},     'AND: {Name is Peter, Value is 400}'],
    +  85*   ['D', {and:{Name:"Peter", Value:1500}},    'AND: {Name is Peter, Value is 1500}'],
    +  86*   ['E', {and:[{Name:"Peter"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],
    +  87*   ['F', {and:[{Name:"Peter"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],
    +  88*   ['G', {not:{Name:"Peter", Value:400}},     'NAND: not {Name is Peter and Value is 400}'],
    +  89*   ['H', {not:{Name:"Peter", Value:1500}},    'NAND: not {Name is Peter and Value is 1500}'],
    +  90*   ['I', {not:[{Name:"Peter"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],
    +  91*   ['J', {Name:(v) => v.length===4},          'Name has 4 letters']
    +  92* ];
    +  93*
    +  94* m.mount(root, { 
    +  95*   view:() => m('', [
    +  96*       m('h3', 'Given the data set:'),
    +  97*       m('table#data', [
    +  98*           m('tr', colNames.map(n => m('th', n))),
    +  99*           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    + 100*       ]),
    + 101*       m('h3', 'The following queries yield:'),
    + 102*       m('table', [
    + 103*           m('tr', [m('th','#'), m('th','Query'), m('th',"Live Result, by 'Name' field")]),
    + 104*           ...queries.map(q => {
    + 105*               const result = data.filter(q[1]).getColumn('Name').join(', ');
    + 106*               return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);
    + 107*           })
    + 108*       ])
    + 109*   ])
    + 110* });
    + 111
    + 112
    + 113*   $exampleID { height: 600px; }
    + 114*   #data th { width:15%; }
    + 115*   table { 
    + 116*       font-size: 10pt;
    + 117*       margin-left: 10px;
    + 118*   }
    + 119
    + 120*      
    + 121*/

    + 122
    + 123/** */
    + 124import { Data,
    + 125         DataVal,
    + 126         DataRow
    + 127} from './Data'; 
    + 128
    + 129export type Condition = IndexCondition | RecursiveCondition;
    + 130
    + 131/** true if row index matches the number(s) */
    + 132export type IndexCondition = number;
    + 133
    + 134export type RecursiveCondition = AndCondition | OrCondition;
    + 135export type OrCondition = AndCondition[] | IndexCondition[];
    + 136export type AndCondition = SetAndCondition | TermAndCondition;
    + 137
    + 138export interface SetAndCondition {
    + 139    or?: RecursiveCondition;
    + 140    and?:RecursiveCondition;
    + 141    not?:RecursiveCondition;
    + 142};
    + 143
    + 144export interface TermAndCondition { 
    + 145    [colDesc:string]: 
    + 146        DataVal 
    + 147      | DataVal[]
    + 148      | TermConditionFunction
    + 149    ;
    + 150};
    + 151
    + 152export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean;
    + 153
    + 154
    + 155function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { 
    + 156    const col = colNumber(name);
    + 157    const valIsFunction = (typeof val === 'function');
    + 158    const valIsArray = ((typeof val === 'object') && (val.length!==undefined));
    + 159    if (isNaN(col)) { 
    + 160        console.log(`column name '${name}' cannot be resolved in terminal condition ${name}=${val}`);
    + 161        console.log(row);
    + 162        return false; // -> this condition is not met;
    + 163    } else if (valIsFunction) { 
    + 164        // query true if function evaluates to true
    + 165        return val(row[col], row);
    + 166    } else if (valIsArray) {
    + 167        // query true if empty array, or at least one c true
    + 168        return (val.length === 0) || val.some((v:any) => row[col] === v); 
    + 169    } else { // object: all conditions have to be met, unless specified as or
    + 170        return (row[col] === val); 
    + 171    }
    + 172}
    + 173
    + 174/**
    + 175 * applies `condition` to a row of data and returns `true` if the row passes.
    + 176 * @param condition the complex condition to test against
    + 177 * @param r the row index in the data set
    + 178 * @param row the row values 
    + 179 * @param and 
    + 180 */

    + 181function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and=true):boolean { 
    + 182    let orResult = false;
    + 183    let andResult= true;          
    + 184    // undefined condition is TRUE
    + 185    if (condition===undefined) { return true; }
    + 186    
    + 187    // Simple Index Condition on row index:
    + 188    else if (typeof condition === 'number') { return (condition === r); }
    + 189
    + 190    // Recursive Condition - OR: [...], AND {...}: 
    + 191    else if (typeof condition === 'object') {
    + 192        // array -> or condition on a list of row indices or compound conditions
    + 193        const mc = condition;
    + 194
    + 195        // OR condition: [...] 
    + 196        if (mc.length !== undefined) {            
    + 197            return (mc.length === 0)? 
    + 198                // empty OR is false:
    + 199                false : 
    + 200                // else: OR is true if any sub-condition is met
    + 201                mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, false));
    + 202        } 
    + 203        // AND condition: {...}
    + 204        else { 
    + 205            for (const name in condition) {
    + 206                let conditionMet = and; // initialize with false for OR, and true for AND conjunction
    + 207                const setCond = condition;
    + 208                
    + 209                // resolve SetConditions:
    + 210                switch (name) {
    + 211                    case 'or':  conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break;
    + 212                    case 'and': conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break;
    + 213                    case 'not': conditionMet = !resolveCondition(setCond.not, row, r, colNumber, true); break;
    + 214                    default:    conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); 
    + 215                }
    + 216                if (conditionMet) { orResult  = true;  if(!and) { break; }} // OR conjunction: exit for name loop if condition met
    + 217                             else { andResult = false; if(and)  { break; }} // AND conjunction: exit for name loop if condition not met
    + 218            }
    + 219        }    
    + 220    } else {
    + 221        console.error(`unrecognized condition: ${JSON.stringify(condition)}`);
    + 222        return false;
    + 223    }
    + 224    return and? andResult : orResult;
    + 225}
    + 226
    + 227/**
    + 228 * filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which
    + 229 * `cond` holds true.
    + 230 * @param data the `Data` object to filter
    + 231 * @param cond the complex condition to test against
    + 232 * @return a new `Data` object with the filtered rows 
    + 233 */

    + 234export function filter(data:Data, cond:Condition):Data {
    + 235    const colNumber = (name:string):number => data.colNumber(name);
    + 236    try {
    + 237        return new Data({
    + 238            name:     data.getName(),
    + 239            colNames: data.colNames(), 
    + 240            rows:data.getData().filter((row:DataRow, i:number) => {
    + 241                const keep = resolveCondition(cond, row, i, colNumber);
    + 242                return keep;
    + 243            })
    + 244        });
    + 245    } catch(err) {
    + 246        console.log(err);
    + 247        console.log(err.stack);
    + 248    }
    + 249}
    + 250
    + + \ No newline at end of file diff --git a/docs/src/index.html b/docs/src/index.html new file mode 100644 index 0000000..f59d1fa --- /dev/null +++ b/docs/src/index.html @@ -0,0 +1,32 @@ + + +

    index.ts

    +
       1export { NumRange,
    +   2         NumDomain,
    +   3         DateDomain,
    +   4         NameDomain,
    +   5         Domain,
    +   6         ColumnReference,
    +   7         DataVal,
    +   8         DataRow,
    +   9         DataSet
    +  10        }       from './Data';
    +  11
    +  12export { Data } from './Data';
    +  13export { Condition} from './DataFilters';
    +  14
    +  15
    + + \ No newline at end of file diff --git a/docs/src/overview.html b/docs/src/overview.html new file mode 100644 index 0000000..fd2fe14 --- /dev/null +++ b/docs/src/overview.html @@ -0,0 +1,73 @@ + + +

    overview.ts

    +
       1/**
    +   2 * # hsdatab
    +   3 * 
    +   4 * Helpful Scripts data management functions that are framework independent. 
    +   5 * 
    +   6 * ## Data Types
    +   7 * -   {@link Data.NumRange NumRange} defines a single [min, max] numeric range.
    +   8 * -   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column
    +   9 * -   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column
    +  10 * -   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column
    +  11 * -   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains.
    +  12 * -   {@link Data.ColumnReference ColumnReference} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array 
    +  13 * -   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array
    +  14 * -   {@link Data.DataRow DataRow} a single row of column values
    +  15 * 
    +  16 * ## Data Class
    +  17 * -   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions
    +  18 *
    +  19 * ## Example
    +  20 * 
    +  21 * 
    +  22 * const colNames = ['Name', 'Value', 'Start', 'End'];
    +  23 * const rows = [
    +  24 *   ['Harry', '100', '3/1/14', '11/20/14'], 
    +  25 *   ['Mary', '1500', '7/1/14',  '9/30/14'],
    +  26 *   ['Peter', '400', '5/20/14', '4/30/15'],  
    +  27 *   ['Jane', '700', '11/13/14', '8/15/15']
    +  28 * ]
    +  29 * const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  30 * 
    +  31 * query = {Name:["Peter", "Jane"]};
    +  32 * const result = data.filter(query).getColumn('Name').join(', ');
    +  33 *
    +  34 * m.mount(root, { 
    +  35 *   view:() => m('', [
    +  36 *       m('h3', 'Given the data set:'),
    +  37 *       m('table#data', [
    +  38 *           m('tr', colNames.map(n => m('th', n))),
    +  39 *           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    +  40 *       ]),
    +  41 *       m('h3', 'The query "{Name:["Peter", "Jane"]}" yields:'),
    +  42 *       m('', result)
    +  43 *   ])
    +  44 * });
    +  45 * 
    +  46 * 
    +  47 *   $exampleID { height: 600px; }
    +  48 *   #data th { width:15%; }
    +  49 * 
    +  50 *      
    +  51 */

    +  52
    +  53 /** */
    +  54
    +  55 
    +  56
    + + \ No newline at end of file From 09d3fcf90e6ff37dba70dfe26699922e219eab11 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 2 Jun 2018 22:19:51 -0700 Subject: [PATCH 04/17] fixed indexGH.html --- docs/indexGH.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/indexGH.html b/docs/indexGH.html index ae78047..47b2b57 100644 --- a/docs/indexGH.html +++ b/docs/indexGH.html @@ -3,9 +3,9 @@ HS Docs - + - + \ No newline at end of file From f0dbaf0b8e4aa197a5a1fd6bb847b95bdf02d7a1 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 9 Jun 2018 18:20:29 -0700 Subject: [PATCH 05/17] added docs --- docs/data/hsdatab.json | 639 +++++++++++++++++------------------------ 1 file changed, 269 insertions(+), 370 deletions(-) diff --git a/docs/data/hsdatab.json b/docs/data/hsdatab.json index 8cc4011..c45169f 100644 --- a/docs/data/hsdatab.json +++ b/docs/data/hsdatab.json @@ -1,11 +1,11 @@ { "id": 0, - "name": "hsdatab", + "name": "hsDatab", "kind": 0, "flags": {}, "children": [ { - "id": 49, + "id": 42, "name": "\"Data\"", "kind": 1, "kindString": "External module", @@ -16,7 +16,7 @@ "comment": {}, "children": [ { - "id": 63, + "id": 56, "name": "Data", "kind": 128, "kindString": "Class", @@ -28,7 +28,7 @@ }, "children": [ { - "id": 75, + "id": 68, "name": "constructor", "kind": 512, "kindString": "Constructor", @@ -37,14 +37,14 @@ }, "signatures": [ { - "id": 76, + "id": 69, "name": "new Data", "kind": 16384, "kindString": "Constructor signature", "flags": {}, "parameters": [ { - "id": 77, + "id": 70, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -54,14 +54,14 @@ "type": { "type": "reference", "name": "DataSet", - "id": 50 + "id": 43 } } ], "type": { "type": "reference", "name": "Data", - "id": 63 + "id": 56 } } ], @@ -74,7 +74,7 @@ ] }, { - "id": 125, + "id": 118, "name": "data", "kind": 1024, "kindString": "Property", @@ -94,13 +94,13 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 160 + "id": 153 } }, "defaultValue": " []" }, { - "id": 126, + "id": 119, "name": "meta", "kind": 1024, "kindString": "Property", @@ -120,13 +120,13 @@ "elementType": { "type": "reference", "name": "MetaStruct", - "id": 57 + "id": 50 } }, "defaultValue": " []" }, { - "id": 127, + "id": 120, "name": "name", "kind": 1024, "kindString": "Property", @@ -147,7 +147,7 @@ } }, { - "id": 142, + "id": 135, "name": "allRows", "kind": 2048, "kindString": "Method", @@ -157,7 +157,7 @@ }, "signatures": [ { - "id": 143, + "id": 136, "name": "allRows", "kind": 4096, "kindString": "Call signature", @@ -167,7 +167,7 @@ }, "parameters": [ { - "id": 144, + "id": 137, "name": "column", "kind": 32768, "kindString": "Parameter", @@ -178,7 +178,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ], @@ -189,7 +189,7 @@ { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } ] } @@ -204,7 +204,7 @@ ] }, { - "id": 112, + "id": 105, "name": "castData", "kind": 2048, "kindString": "Method", @@ -214,7 +214,7 @@ }, "signatures": [ { - "id": 113, + "id": 106, "name": "castData", "kind": 4096, "kindString": "Call signature", @@ -234,7 +234,7 @@ ] }, { - "id": 149, + "id": 142, "name": "castVal", "kind": 2048, "kindString": "Method", @@ -244,7 +244,7 @@ }, "signatures": [ { - "id": 150, + "id": 143, "name": "castVal", "kind": 4096, "kindString": "Call signature", @@ -260,7 +260,7 @@ }, "parameters": [ { - "id": 151, + "id": 144, "name": "type", "kind": 32768, "kindString": "Parameter", @@ -274,7 +274,7 @@ } }, { - "id": 152, + "id": 145, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -282,14 +282,14 @@ "type": { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } } ], "type": { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } } ], @@ -302,7 +302,7 @@ ] }, { - "id": 90, + "id": 83, "name": "colAdd", "kind": 2048, "kindString": "Method", @@ -312,7 +312,7 @@ }, "signatures": [ { - "id": 91, + "id": 84, "name": "colAdd", "kind": 4096, "kindString": "Call signature", @@ -323,7 +323,7 @@ }, "parameters": [ { - "id": 92, + "id": 85, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -352,7 +352,7 @@ ] }, { - "id": 93, + "id": 86, "name": "colInitialize", "kind": 2048, "kindString": "Method", @@ -362,7 +362,7 @@ }, "signatures": [ { - "id": 94, + "id": 87, "name": "colInitialize", "kind": 4096, "kindString": "Call signature", @@ -372,7 +372,7 @@ }, "parameters": [ { - "id": 95, + "id": 88, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -383,11 +383,11 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } }, { - "id": 96, + "id": 89, "name": "initializer", "kind": 32768, "kindString": "Parameter", @@ -416,7 +416,7 @@ ] }, { - "id": 100, + "id": 93, "name": "colName", "kind": 2048, "kindString": "Method", @@ -426,7 +426,7 @@ }, "signatures": [ { - "id": 101, + "id": 94, "name": "colName", "kind": 4096, "kindString": "Call signature", @@ -437,7 +437,7 @@ }, "parameters": [ { - "id": 102, + "id": 95, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -445,7 +445,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ], @@ -464,7 +464,7 @@ ] }, { - "id": 103, + "id": 96, "name": "colNames", "kind": 2048, "kindString": "Method", @@ -474,7 +474,7 @@ }, "signatures": [ { - "id": 104, + "id": 97, "name": "colNames", "kind": 4096, "kindString": "Call signature", @@ -501,7 +501,7 @@ ] }, { - "id": 97, + "id": 90, "name": "colNumber", "kind": 2048, "kindString": "Method", @@ -511,7 +511,7 @@ }, "signatures": [ { - "id": 98, + "id": 91, "name": "colNumber", "kind": 4096, "kindString": "Call signature", @@ -522,7 +522,7 @@ }, "parameters": [ { - "id": 99, + "id": 92, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -530,7 +530,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ], @@ -549,7 +549,7 @@ ] }, { - "id": 105, + "id": 98, "name": "colType", "kind": 2048, "kindString": "Method", @@ -559,7 +559,7 @@ }, "signatures": [ { - "id": 106, + "id": 99, "name": "colType", "kind": 4096, "kindString": "Call signature", @@ -570,7 +570,7 @@ }, "parameters": [ { - "id": 107, + "id": 100, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -578,7 +578,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ], @@ -597,7 +597,7 @@ ] }, { - "id": 83, + "id": 76, "name": "export", "kind": 2048, "kindString": "Method", @@ -607,7 +607,7 @@ }, "signatures": [ { - "id": 84, + "id": 77, "name": "export", "kind": 4096, "kindString": "Call signature", @@ -618,7 +618,7 @@ "type": { "type": "reference", "name": "DataSet", - "id": 50 + "id": 43 } } ], @@ -631,7 +631,7 @@ ] }, { - "id": 114, + "id": 107, "name": "filter", "kind": 2048, "kindString": "Method", @@ -641,7 +641,7 @@ }, "signatures": [ { - "id": 115, + "id": 108, "name": "filter", "kind": 4096, "kindString": "Call signature", @@ -652,7 +652,7 @@ }, "parameters": [ { - "id": 116, + "id": 109, "name": "condition", "kind": 32768, "kindString": "Parameter", @@ -670,7 +670,7 @@ "type": { "type": "reference", "name": "Data", - "id": 63 + "id": 56 } } ], @@ -683,7 +683,7 @@ ] }, { - "id": 108, + "id": 101, "name": "findDomain", "kind": 2048, "kindString": "Method", @@ -693,7 +693,7 @@ }, "signatures": [ { - "id": 109, + "id": 102, "name": "findDomain", "kind": 4096, "kindString": "Call signature", @@ -703,7 +703,7 @@ }, "parameters": [ { - "id": 110, + "id": 103, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -714,11 +714,11 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } }, { - "id": 111, + "id": 104, "name": "domain", "kind": 32768, "kindString": "Parameter", @@ -729,7 +729,7 @@ "type": { "type": "reference", "name": "Domain", - "id": 157 + "id": 150 } } ], @@ -748,7 +748,7 @@ ] }, { - "id": 139, + "id": 132, "name": "findType", "kind": 2048, "kindString": "Method", @@ -758,7 +758,7 @@ }, "signatures": [ { - "id": 140, + "id": 133, "name": "findType", "kind": 4096, "kindString": "Call signature", @@ -774,7 +774,7 @@ }, "parameters": [ { - "id": 141, + "id": 134, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -785,7 +785,7 @@ "type": { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } } ], @@ -804,7 +804,7 @@ ] }, { - "id": 136, + "id": 129, "name": "findTypes", "kind": 2048, "kindString": "Method", @@ -814,7 +814,7 @@ }, "signatures": [ { - "id": 137, + "id": 130, "name": "findTypes", "kind": 4096, "kindString": "Call signature", @@ -825,7 +825,7 @@ }, "parameters": [ { - "id": 138, + "id": 131, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -836,7 +836,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ], @@ -855,7 +855,7 @@ ] }, { - "id": 87, + "id": 80, "name": "getColumn", "kind": 2048, "kindString": "Method", @@ -865,7 +865,7 @@ }, "signatures": [ { - "id": 88, + "id": 81, "name": "getColumn", "kind": 4096, "kindString": "Call signature", @@ -875,7 +875,7 @@ }, "parameters": [ { - "id": 89, + "id": 82, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -886,7 +886,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ], @@ -895,7 +895,7 @@ "elementType": { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } } } @@ -909,7 +909,7 @@ ] }, { - "id": 85, + "id": 78, "name": "getData", "kind": 2048, "kindString": "Method", @@ -919,7 +919,7 @@ }, "signatures": [ { - "id": 86, + "id": 79, "name": "getData", "kind": 4096, "kindString": "Call signature", @@ -932,7 +932,7 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 160 + "id": 153 } } } @@ -946,7 +946,7 @@ ] }, { - "id": 128, + "id": 121, "name": "getMeta", "kind": 2048, "kindString": "Method", @@ -956,14 +956,14 @@ }, "signatures": [ { - "id": 129, + "id": 122, "name": "getMeta", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 130, + "id": 123, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -971,14 +971,14 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ], "type": { "type": "reference", "name": "MetaStruct", - "id": 57 + "id": 50 } } ], @@ -991,7 +991,7 @@ ] }, { - "id": 78, + "id": 71, "name": "getName", "kind": 2048, "kindString": "Method", @@ -1001,7 +1001,7 @@ }, "signatures": [ { - "id": 79, + "id": 72, "name": "getName", "kind": 4096, "kindString": "Call signature", @@ -1024,7 +1024,7 @@ ] }, { - "id": 80, + "id": 73, "name": "import", "kind": 2048, "kindString": "Method", @@ -1034,7 +1034,7 @@ }, "signatures": [ { - "id": 81, + "id": 74, "name": "import", "kind": 4096, "kindString": "Call signature", @@ -1044,7 +1044,7 @@ }, "parameters": [ { - "id": 82, + "id": 75, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1055,7 +1055,7 @@ "type": { "type": "reference", "name": "DataSet", - "id": 50 + "id": 43 } } ], @@ -1074,7 +1074,7 @@ ] }, { - "id": 121, + "id": 114, "name": "map", "kind": 2048, "kindString": "Method", @@ -1084,7 +1084,7 @@ }, "signatures": [ { - "id": 122, + "id": 115, "name": "map", "kind": 4096, "kindString": "Call signature", @@ -1095,7 +1095,7 @@ }, "parameters": [ { - "id": 123, + "id": 116, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -1109,21 +1109,21 @@ { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 }, { "type": "array", "elementType": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ] } }, { - "id": 124, + "id": 117, "name": "mapFn", "kind": 32768, "kindString": "Parameter", @@ -1141,7 +1141,7 @@ { "type": "reference", "name": "mapFn", - "id": 124 + "id": 117 } ] } @@ -1150,7 +1150,7 @@ "type": { "type": "reference", "name": "Data", - "id": 63 + "id": 56 } } ], @@ -1163,7 +1163,7 @@ ] }, { - "id": 131, + "id": 124, "name": "setData", "kind": 2048, "kindString": "Method", @@ -1173,7 +1173,7 @@ }, "signatures": [ { - "id": 132, + "id": 125, "name": "setData", "kind": 4096, "kindString": "Call signature", @@ -1183,7 +1183,7 @@ }, "parameters": [ { - "id": 133, + "id": 126, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1196,12 +1196,12 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 160 + "id": 153 } } }, { - "id": 134, + "id": 127, "name": "names", "kind": 32768, "kindString": "Parameter", @@ -1218,7 +1218,7 @@ } }, { - "id": 135, + "id": 128, "name": "autoType", "kind": 32768, "kindString": "Parameter", @@ -1248,7 +1248,7 @@ ] }, { - "id": 117, + "id": 110, "name": "sort", "kind": 2048, "kindString": "Method", @@ -1258,7 +1258,7 @@ }, "signatures": [ { - "id": 118, + "id": 111, "name": "sort", "kind": 4096, "kindString": "Call signature", @@ -1274,7 +1274,7 @@ }, "parameters": [ { - "id": 119, + "id": 112, "name": "sortFn", "kind": 32768, "kindString": "Parameter", @@ -1292,13 +1292,13 @@ { "type": "reference", "name": "sortFn", - "id": 119 + "id": 112 } ] } }, { - "id": 120, + "id": 113, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -1311,14 +1311,14 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 158 + "id": 151 } } ], "type": { "type": "reference", "name": "Data", - "id": 63 + "id": 56 } } ], @@ -1331,7 +1331,7 @@ ] }, { - "id": 145, + "id": 138, "name": "toDate", "kind": 2048, "kindString": "Method", @@ -1341,7 +1341,7 @@ }, "signatures": [ { - "id": 146, + "id": 139, "name": "toDate", "kind": 4096, "kindString": "Call signature", @@ -1357,7 +1357,7 @@ }, "parameters": [ { - "id": 147, + "id": 140, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -1368,11 +1368,11 @@ "type": { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } }, { - "id": 148, + "id": 141, "name": "limitYear", "kind": 32768, "kindString": "Parameter", @@ -1402,7 +1402,7 @@ ] }, { - "id": 71, + "id": 64, "name": "toDataSet", "kind": 2048, "kindString": "Method", @@ -1413,14 +1413,14 @@ }, "signatures": [ { - "id": 72, + "id": 65, "name": "toDataSet", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 73, + "id": 66, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1428,11 +1428,11 @@ "type": { "type": "reference", "name": "DataLiteralSet", - "id": 161 + "id": 154 } }, { - "id": 74, + "id": 67, "name": "name", "kind": 32768, "kindString": "Parameter", @@ -1448,7 +1448,7 @@ "type": { "type": "reference", "name": "DataSet", - "id": 50 + "id": 43 } } ], @@ -1461,7 +1461,7 @@ ] }, { - "id": 64, + "id": 57, "name": "type", "kind": 2097152, "kindString": "Object literal", @@ -1472,7 +1472,7 @@ }, "children": [ { - "id": 68, + "id": 61, "name": "currency", "kind": 32, "kindString": "Variable", @@ -1493,7 +1493,7 @@ "defaultValue": "\"currency data\"" }, { - "id": 67, + "id": 60, "name": "date", "kind": 32, "kindString": "Variable", @@ -1514,7 +1514,7 @@ "defaultValue": "\"date data\"" }, { - "id": 66, + "id": 59, "name": "name", "kind": 32, "kindString": "Variable", @@ -1535,7 +1535,7 @@ "defaultValue": "\"name data\"" }, { - "id": 70, + "id": 63, "name": "nominal", "kind": 32, "kindString": "Variable", @@ -1556,7 +1556,7 @@ "defaultValue": "\"nominal data\"" }, { - "id": 65, + "id": 58, "name": "number", "kind": 32, "kindString": "Variable", @@ -1577,7 +1577,7 @@ "defaultValue": "\"number data\"" }, { - "id": 69, + "id": 62, "name": "percent", "kind": 32, "kindString": "Variable", @@ -1603,12 +1603,12 @@ "title": "Variables", "kind": 32, "children": [ - 68, - 67, - 66, - 70, - 65, - 69 + 61, + 60, + 59, + 63, + 58, + 62 ] } ], @@ -1630,53 +1630,53 @@ "title": "Constructors", "kind": 512, "children": [ - 75 + 68 ] }, { "title": "Properties", "kind": 1024, "children": [ - 125, - 126, - 127 + 118, + 119, + 120 ] }, { "title": "Methods", "kind": 2048, "children": [ - 142, - 112, - 149, - 90, - 93, - 100, - 103, - 97, + 135, 105, + 142, 83, - 114, - 108, - 139, - 136, - 87, - 85, - 128, - 78, + 86, + 93, + 96, + 90, + 98, + 76, + 107, + 101, + 132, + 129, 80, + 78, 121, - 131, - 117, - 145, - 71 + 71, + 73, + 114, + 124, + 110, + 138, + 64 ] }, { "title": "Object literals", "kind": 2097152, "children": [ - 64 + 57 ] } ], @@ -1689,7 +1689,7 @@ ] }, { - "id": 50, + "id": 43, "name": "DataSet", "kind": 256, "kindString": "Interface", @@ -1701,7 +1701,7 @@ }, "children": [ { - "id": 52, + "id": 45, "name": "colNames", "kind": 1024, "kindString": "Property", @@ -1727,7 +1727,7 @@ } }, { - "id": 51, + "id": 44, "name": "name", "kind": 1024, "kindString": "Property", @@ -1751,7 +1751,7 @@ } }, { - "id": 53, + "id": 46, "name": "rows", "kind": 1024, "kindString": "Property", @@ -1773,7 +1773,7 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 160 + "id": 153 } } } @@ -1783,9 +1783,9 @@ "title": "Properties", "kind": 1024, "children": [ - 52, - 51, - 53 + 45, + 44, + 46 ] } ], @@ -1798,14 +1798,14 @@ ] }, { - "id": 57, + "id": 50, "name": "MetaStruct", "kind": 256, "kindString": "Interface", "flags": {}, "children": [ { - "id": 60, + "id": 53, "name": "accessed", "kind": 1024, "kindString": "Property", @@ -1823,7 +1823,7 @@ } }, { - "id": 61, + "id": 54, "name": "cast", "kind": 1024, "kindString": "Property", @@ -1841,7 +1841,7 @@ } }, { - "id": 59, + "id": 52, "name": "column", "kind": 1024, "kindString": "Property", @@ -1859,7 +1859,7 @@ } }, { - "id": 58, + "id": 51, "name": "name", "kind": 1024, "kindString": "Property", @@ -1877,7 +1877,7 @@ } }, { - "id": 62, + "id": 55, "name": "types", "kind": 1024, "kindString": "Property", @@ -1894,7 +1894,7 @@ "elementType": { "type": "reference", "name": "TypeStruct", - "id": 54 + "id": 47 } } } @@ -1904,11 +1904,11 @@ "title": "Properties", "kind": 1024, "children": [ - 60, - 61, - 59, - 58, - 62 + 53, + 54, + 52, + 51, + 55 ] } ], @@ -1921,14 +1921,14 @@ ] }, { - "id": 54, + "id": 47, "name": "TypeStruct", "kind": 256, "kindString": "Interface", "flags": {}, "children": [ { - "id": 56, + "id": 49, "name": "count", "kind": 1024, "kindString": "Property", @@ -1946,7 +1946,7 @@ } }, { - "id": 55, + "id": 48, "name": "type", "kind": 1024, "kindString": "Property", @@ -1969,8 +1969,8 @@ "title": "Properties", "kind": 1024, "children": [ - 56, - 55 + 49, + 48 ] } ], @@ -1983,7 +1983,7 @@ ] }, { - "id": 158, + "id": 151, "name": "ColumnReference", "kind": 4194304, "kindString": "Type alias", @@ -2015,7 +2015,7 @@ } }, { - "id": 161, + "id": 154, "name": "DataLiteralSet", "kind": 4194304, "kindString": "Type alias", @@ -2044,7 +2044,7 @@ } }, { - "id": 160, + "id": 153, "name": "DataRow", "kind": 4194304, "kindString": "Type alias", @@ -2066,12 +2066,12 @@ "elementType": { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } } }, { - "id": 159, + "id": 152, "name": "DataVal", "kind": 4194304, "kindString": "Type alias", @@ -2107,7 +2107,7 @@ } }, { - "id": 155, + "id": 148, "name": "DateDomain", "kind": 4194304, "kindString": "Type alias", @@ -2139,7 +2139,7 @@ } }, { - "id": 157, + "id": 150, "name": "Domain", "kind": 4194304, "kindString": "Type alias", @@ -2162,23 +2162,23 @@ { "type": "reference", "name": "NumDomain", - "id": 154 + "id": 147 }, { "type": "reference", "name": "DateDomain", - "id": 155 + "id": 148 }, { "type": "reference", "name": "NameDomain", - "id": 156 + "id": 149 } ] } }, { - "id": 156, + "id": 149, "name": "NameDomain", "kind": 4194304, "kindString": "Type alias", @@ -2204,7 +2204,7 @@ } }, { - "id": 154, + "id": 147, "name": "NumDomain", "kind": 4194304, "kindString": "Type alias", @@ -2236,7 +2236,7 @@ } }, { - "id": 153, + "id": 146, "name": "NumRange", "kind": 4194304, "kindString": "Type alias", @@ -2268,7 +2268,7 @@ } }, { - "id": 167, + "id": 160, "name": "mapFn", "kind": 4194304, "kindString": "Type alias", @@ -2285,21 +2285,21 @@ "type": { "type": "reflection", "declaration": { - "id": 168, + "id": 161, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 169, + "id": 162, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 170, + "id": 163, "name": "colVal", "kind": 32768, "kindString": "Parameter", @@ -2310,7 +2310,7 @@ } }, { - "id": 171, + "id": 164, "name": "colIndex", "kind": 32768, "kindString": "Parameter", @@ -2323,7 +2323,7 @@ } }, { - "id": 172, + "id": 165, "name": "rowIndex", "kind": 32768, "kindString": "Parameter", @@ -2336,7 +2336,7 @@ } }, { - "id": 173, + "id": 166, "name": "rows", "kind": 32768, "kindString": "Parameter", @@ -2372,7 +2372,7 @@ } }, { - "id": 162, + "id": 155, "name": "sortFn", "kind": 4194304, "kindString": "Type alias", @@ -2389,21 +2389,21 @@ "type": { "type": "reflection", "declaration": { - "id": 163, + "id": 156, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 164, + "id": 157, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 165, + "id": 158, "name": "x", "kind": 32768, "kindString": "Parameter", @@ -2414,7 +2414,7 @@ } }, { - "id": 166, + "id": 159, "name": "y", "kind": 32768, "kindString": "Parameter", @@ -2447,33 +2447,33 @@ "title": "Classes", "kind": 128, "children": [ - 63 + 56 ] }, { "title": "Interfaces", "kind": 256, "children": [ + 43, 50, - 57, - 54 + 47 ] }, { "title": "Type aliases", "kind": 4194304, "children": [ - 158, - 161, - 160, - 159, - 155, - 157, - 156, + 151, 154, 153, - 167, - 162 + 152, + 148, + 150, + 149, + 147, + 146, + 160, + 155 ] } ], @@ -2495,13 +2495,8 @@ }, "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/DataFilters.ts", "comment": { - "shortText": "The HsData object will feature its own column meta information, as well as\na copy of the rows array which allows for `filter` and `sort` operations.\nHowever, the column arrays will be shared with the original HsData object in order to be memory efficient.\nThis means that `map` and `newColumn` operations on the new object will affect the original object or any\nobject derived via `query`.", - "tags": [ - { - "tag": "description", - "text": "executes a query on the data. Each row in the data is checked and those for which\n`conditions` is true are returned as a new HsData object.\n\n## General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n## IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n## RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n## Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdata.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" - } - ] + "shortText": "Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object.\nEach row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object.", + "text": "# Condition construction\n\n### General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n### IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n### RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n### Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" }, "children": [ { @@ -2525,7 +2520,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 144, + "line": 140, "character": 7 } ], @@ -2547,7 +2542,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 145, + "line": 141, "character": 7 } ], @@ -2569,7 +2564,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 143, + "line": 139, "character": 6 } ], @@ -2594,7 +2589,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 142, + "line": 138, "character": 32 } ] @@ -2633,14 +2628,14 @@ { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 }, { "type": "array", "elementType": { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } }, { @@ -2655,7 +2650,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 148, + "line": 144, "character": 33 } ] @@ -2671,7 +2666,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 140, + "line": 136, "character": 24 } ], @@ -2702,7 +2697,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 133, + "line": 129, "character": 21 } ], @@ -2736,7 +2731,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 136, + "line": 132, "character": 26 } ], @@ -2756,7 +2751,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 139, + "line": 135, "character": 23 } ], @@ -2793,7 +2788,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 138, + "line": 134, "character": 30 } ], @@ -2813,88 +2808,6 @@ ] } }, - { - "id": 38, - "name": "ReduceFn", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 231, - "character": 20 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 39, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 40, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 41, - "name": "keep", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "boolean" - } - }, - { - "id": 42, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataRow", - "id": 160 - } - }, - { - "id": 43, - "name": "i", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 231, - "character": 22 - } - ] - } - } - }, { "id": 14, "name": "TermConditionFunction", @@ -2906,7 +2819,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 156, + "line": 152, "character": 33 } ], @@ -2935,7 +2848,7 @@ "type": { "type": "reference", "name": "DataVal", - "id": 159 + "id": 152 } }, { @@ -2947,7 +2860,7 @@ "type": { "type": "reference", "name": "DataRow", - "id": 160 + "id": 153 } } ], @@ -2960,7 +2873,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 156, + "line": 152, "character": 35 } ] @@ -2968,7 +2881,7 @@ } }, { - "id": 44, + "id": 38, "name": "filter", "kind": 64, "kindString": "Function", @@ -2977,71 +2890,58 @@ }, "signatures": [ { - "id": 45, + "id": 39, "name": "filter", "kind": 4096, "kindString": "Call signature", "flags": {}, + "comment": { + "shortText": "filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which\n`cond` holds true.", + "returns": "a new `Data` object with the filtered rows\n" + }, "parameters": [ { - "id": 46, + "id": 40, "name": "data", "kind": 32768, "kindString": "Parameter", "flags": {}, + "comment": { + "text": "the `Data` object to filter" + }, "type": { "type": "reference", "name": "Data", - "id": 63 + "id": 56 } }, { - "id": 47, + "id": 41, "name": "cond", "kind": 32768, "kindString": "Parameter", "flags": {}, + "comment": { + "text": "the complex condition to test against" + }, "type": { "type": "reference", "name": "Condition", "id": 9 } - }, - { - "id": 48, - "name": "reduceFn", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "ReduceFn", - "id": 38 - } - ] - } } ], "type": { "type": "reference", "name": "Data", - "id": 63 + "id": 56 } } ], "sources": [ { "fileName": "DataFilters.ts", - "line": 233, + "line": 234, "character": 22 } ] @@ -3090,7 +2990,7 @@ "type": { "type": "reference", "name": "DataRow", - "id": 160 + "id": 153 } }, { @@ -3150,7 +3050,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 185, + "line": 181, "character": 80 } ] @@ -3182,7 +3082,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 185, + "line": 181, "character": 25 } ] @@ -3232,7 +3132,7 @@ "type": { "type": "reference", "name": "DataRow", - "id": 160 + "id": 153 } }, { @@ -3278,7 +3178,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 159, + "line": 155, "character": 79 } ] @@ -3295,7 +3195,7 @@ "sources": [ { "fileName": "DataFilters.ts", - "line": 159, + "line": 155, "character": 33 } ] @@ -3319,7 +3219,6 @@ 10, 12, 11, - 38, 14 ] }, @@ -3327,7 +3226,7 @@ "title": "Functions", "kind": 64, "children": [ - 44, + 38, 28, 19 ] @@ -3342,7 +3241,7 @@ ] }, { - "id": 174, + "id": 167, "name": "\"index\"", "kind": 1, "kindString": "External module", @@ -3359,7 +3258,7 @@ ] }, { - "id": 175, + "id": 168, "name": "\"overview\"", "kind": 1, "kindString": "External module", @@ -3368,8 +3267,8 @@ }, "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", "comment": { - "shortText": "# hsData", - "text": "Helpful Scripts data management functions that are framework independent.\n\n## Data Types\n-   {@link Data.NumRange NumRange} defines a single [min, max] numeric range.\n-   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column\n-   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column\n-   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column\n-   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains.\n-   {@link Data.ColSpecifier ColSpecifier} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array\n-   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array\n-   {@link Data.DataRow DataRow} a single row of column values\n\n## Data Class\n-   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions\n" + "shortText": "# hsdatab", + "text": "Helpful Scripts data management functions that are framework independent.\n\n## Data Types\n-   {@link Data.NumRange NumRange} defines a single [min, max] numeric range.\n-   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column\n-   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column\n-   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column\n-   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains.\n-   {@link Data.ColumnReference ColumnReference} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array\n-   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array\n-   {@link Data.DataRow DataRow} a single row of column values\n\n## Data Class\n-   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query).getColumn('Name').join(', ');\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The query \"{Name:[\"Peter\", \"Jane\"]}\" yields:'),\n m('', result)\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n\n\n" }, "sources": [ { @@ -3385,10 +3284,10 @@ "title": "External modules", "kind": 1, "children": [ - 49, + 42, 1, - 174, - 175 + 167, + 168 ] } ] From 026dff37977b00e765fcf7020bf509a10e416e83 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 9 Jun 2018 18:25:45 -0700 Subject: [PATCH 06/17] moved to https --- docs/indexGH.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/indexGH.html b/docs/indexGH.html index 47b2b57..2854c97 100644 --- a/docs/indexGH.html +++ b/docs/indexGH.html @@ -3,9 +3,9 @@ HS Docs - + - + \ No newline at end of file From 478ee6b61bd5e88530849112e7eb61fc255f032b Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 16 Jun 2018 12:31:11 +0200 Subject: [PATCH 07/17] docs update --- docs/data/hsdatab.json | 491 ++++++++++--------- docs/data/index.json | 7 +- docs/src/Data.html | 957 +++++++++++++++++++------------------- docs/src/DataFilters.html | 8 +- docs/src/index.html | 8 +- docs/src/overview.html | 137 +++--- 6 files changed, 818 insertions(+), 790 deletions(-) diff --git a/docs/data/hsdatab.json b/docs/data/hsdatab.json index c45169f..a535f27 100644 --- a/docs/data/hsdatab.json +++ b/docs/data/hsdatab.json @@ -28,7 +28,7 @@ }, "children": [ { - "id": 68, + "id": 67, "name": "constructor", "kind": 512, "kindString": "Constructor", @@ -37,14 +37,14 @@ }, "signatures": [ { - "id": 69, + "id": 68, "name": "new Data", "kind": 16384, "kindString": "Constructor signature", "flags": {}, "parameters": [ { - "id": 70, + "id": 69, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -68,13 +68,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 81, + "line": 86, "character": 5 } ] }, { - "id": 118, + "id": 117, "name": "data", "kind": 1024, "kindString": "Property", @@ -85,7 +85,7 @@ "sources": [ { "fileName": "Data.ts", - "line": 381, + "line": 392, "character": 16 } ], @@ -94,13 +94,13 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 153 + "id": 152 } }, "defaultValue": " []" }, { - "id": 119, + "id": 118, "name": "meta", "kind": 1024, "kindString": "Property", @@ -111,7 +111,7 @@ "sources": [ { "fileName": "Data.ts", - "line": 382, + "line": 393, "character": 16 } ], @@ -126,7 +126,7 @@ "defaultValue": " []" }, { - "id": 120, + "id": 119, "name": "name", "kind": 1024, "kindString": "Property", @@ -137,7 +137,7 @@ "sources": [ { "fileName": "Data.ts", - "line": 383, + "line": 394, "character": 16 } ], @@ -147,7 +147,7 @@ } }, { - "id": 135, + "id": 134, "name": "allRows", "kind": 2048, "kindString": "Method", @@ -157,7 +157,7 @@ }, "signatures": [ { - "id": 136, + "id": 135, "name": "allRows", "kind": 4096, "kindString": "Call signature", @@ -167,7 +167,7 @@ }, "parameters": [ { - "id": 137, + "id": 136, "name": "column", "kind": 32768, "kindString": "Parameter", @@ -178,7 +178,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ], @@ -189,7 +189,7 @@ { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } ] } @@ -198,13 +198,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 482, + "line": 493, "character": 21 } ] }, { - "id": 105, + "id": 104, "name": "castData", "kind": 2048, "kindString": "Method", @@ -214,7 +214,7 @@ }, "signatures": [ { - "id": 106, + "id": 105, "name": "castData", "kind": 4096, "kindString": "Call signature", @@ -228,13 +228,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 249, + "line": 260, "character": 19 } ] }, { - "id": 142, + "id": 141, "name": "castVal", "kind": 2048, "kindString": "Method", @@ -244,7 +244,7 @@ }, "signatures": [ { - "id": 143, + "id": 142, "name": "castVal", "kind": 4096, "kindString": "Call signature", @@ -260,7 +260,7 @@ }, "parameters": [ { - "id": 144, + "id": 143, "name": "type", "kind": 32768, "kindString": "Parameter", @@ -274,7 +274,7 @@ } }, { - "id": 145, + "id": 144, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -282,27 +282,27 @@ "type": { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } } ], "type": { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } } ], "sources": [ { "fileName": "Data.ts", - "line": 518, + "line": 529, "character": 19 } ] }, { - "id": 83, + "id": 82, "name": "colAdd", "kind": 2048, "kindString": "Method", @@ -312,7 +312,7 @@ }, "signatures": [ { - "id": 84, + "id": 83, "name": "colAdd", "kind": 4096, "kindString": "Call signature", @@ -323,7 +323,7 @@ }, "parameters": [ { - "id": 85, + "id": 84, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -346,13 +346,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 135, + "line": 140, "character": 17 } ] }, { - "id": 86, + "id": 85, "name": "colInitialize", "kind": 2048, "kindString": "Method", @@ -362,7 +362,7 @@ }, "signatures": [ { - "id": 87, + "id": 86, "name": "colInitialize", "kind": 4096, "kindString": "Call signature", @@ -372,7 +372,7 @@ }, "parameters": [ { - "id": 88, + "id": 87, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -383,11 +383,11 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } }, { - "id": 89, + "id": 88, "name": "initializer", "kind": 32768, "kindString": "Parameter", @@ -410,13 +410,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 157, + "line": 162, "character": 24 } ] }, { - "id": 93, + "id": 92, "name": "colName", "kind": 2048, "kindString": "Method", @@ -426,7 +426,7 @@ }, "signatures": [ { - "id": 94, + "id": 93, "name": "colName", "kind": 4096, "kindString": "Call signature", @@ -437,7 +437,7 @@ }, "parameters": [ { - "id": 95, + "id": 94, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -445,7 +445,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ], @@ -458,13 +458,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 189, + "line": 194, "character": 18 } ] }, { - "id": 96, + "id": 95, "name": "colNames", "kind": 2048, "kindString": "Method", @@ -474,7 +474,7 @@ }, "signatures": [ { - "id": 97, + "id": 96, "name": "colNames", "kind": 4096, "kindString": "Call signature", @@ -495,13 +495,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 200, + "line": 205, "character": 19 } ] }, { - "id": 90, + "id": 89, "name": "colNumber", "kind": 2048, "kindString": "Method", @@ -511,7 +511,7 @@ }, "signatures": [ { - "id": 91, + "id": 90, "name": "colNumber", "kind": 4096, "kindString": "Call signature", @@ -522,7 +522,7 @@ }, "parameters": [ { - "id": 92, + "id": 91, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -530,7 +530,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ], @@ -543,13 +543,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 174, + "line": 179, "character": 20 } ] }, { - "id": 98, + "id": 97, "name": "colType", "kind": 2048, "kindString": "Method", @@ -559,7 +559,7 @@ }, "signatures": [ { - "id": 99, + "id": 98, "name": "colType", "kind": 4096, "kindString": "Call signature", @@ -570,7 +570,7 @@ }, "parameters": [ { - "id": 100, + "id": 99, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -578,7 +578,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ], @@ -591,13 +591,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 210, + "line": 215, "character": 18 } ] }, { - "id": 76, + "id": 75, "name": "export", "kind": 2048, "kindString": "Method", @@ -607,7 +607,7 @@ }, "signatures": [ { - "id": 77, + "id": 76, "name": "export", "kind": 4096, "kindString": "Call signature", @@ -625,13 +625,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 106, + "line": 111, "character": 17 } ] }, { - "id": 107, + "id": 106, "name": "filter", "kind": 2048, "kindString": "Method", @@ -641,7 +641,7 @@ }, "signatures": [ { - "id": 108, + "id": 107, "name": "filter", "kind": 4096, "kindString": "Call signature", @@ -652,7 +652,7 @@ }, "parameters": [ { - "id": 109, + "id": 108, "name": "condition", "kind": 32768, "kindString": "Parameter", @@ -677,13 +677,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 266, + "line": 277, "character": 17 } ] }, { - "id": 101, + "id": 100, "name": "findDomain", "kind": 2048, "kindString": "Method", @@ -693,62 +693,68 @@ }, "signatures": [ { - "id": 102, + "id": 101, "name": "findDomain", "kind": 4096, "kindString": "Call signature", "flags": {}, "comment": { - "shortText": "modifies `domain` to include all values in column `col`." + "shortText": "modifies `domain` to include all values in column `col`.\nIf no `col` is specified, the range of data indexes is returned.", + "returns": "the updated domain\n" }, "parameters": [ { - "id": 103, + "id": 102, "name": "col", "kind": 32768, "kindString": "Parameter", - "flags": {}, + "flags": { + "isOptional": true + }, "comment": { - "text": "the column name or index" + "text": "optional; the column name or index" }, "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } }, { - "id": 104, + "id": 103, "name": "domain", "kind": 32768, "kindString": "Parameter", - "flags": {}, + "flags": { + "isOptional": true + }, "comment": { - "text": "the\n" + "text": "optional; the Domain range to update" }, "type": { "type": "reference", "name": "Domain", - "id": 150 + "id": 149 } } ], "type": { - "type": "intrinsic", - "name": "void" + "type": "reference", + "name": "Domain", + "id": 149 } } ], "sources": [ { "fileName": "Data.ts", - "line": 220, + "line": 227, "character": 21 } ] }, { - "id": 132, + "id": 131, "name": "findType", "kind": 2048, "kindString": "Method", @@ -758,7 +764,7 @@ }, "signatures": [ { - "id": 133, + "id": 132, "name": "findType", "kind": 4096, "kindString": "Call signature", @@ -774,7 +780,7 @@ }, "parameters": [ { - "id": 134, + "id": 133, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -785,7 +791,7 @@ "type": { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } } ], @@ -798,13 +804,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 451, + "line": 462, "character": 20 } ] }, { - "id": 129, + "id": 128, "name": "findTypes", "kind": 2048, "kindString": "Method", @@ -814,7 +820,7 @@ }, "signatures": [ { - "id": 130, + "id": 129, "name": "findTypes", "kind": 4096, "kindString": "Call signature", @@ -825,7 +831,7 @@ }, "parameters": [ { - "id": 131, + "id": 130, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -836,7 +842,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ], @@ -849,13 +855,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 419, + "line": 430, "character": 21 } ] }, { - "id": 80, + "id": 79, "name": "getColumn", "kind": 2048, "kindString": "Method", @@ -865,7 +871,7 @@ }, "signatures": [ { - "id": 81, + "id": 80, "name": "getColumn", "kind": 4096, "kindString": "Call signature", @@ -875,7 +881,7 @@ }, "parameters": [ { - "id": 82, + "id": 81, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -886,7 +892,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ], @@ -895,7 +901,7 @@ "elementType": { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } } } @@ -903,13 +909,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 124, + "line": 129, "character": 20 } ] }, { - "id": 78, + "id": 77, "name": "getData", "kind": 2048, "kindString": "Method", @@ -919,7 +925,7 @@ }, "signatures": [ { - "id": 79, + "id": 78, "name": "getData", "kind": 4096, "kindString": "Call signature", @@ -932,7 +938,7 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 153 + "id": 152 } } } @@ -940,13 +946,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 116, + "line": 121, "character": 18 } ] }, { - "id": 121, + "id": 120, "name": "getMeta", "kind": 2048, "kindString": "Method", @@ -956,14 +962,14 @@ }, "signatures": [ { - "id": 122, + "id": 121, "name": "getMeta", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 123, + "id": 122, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -971,7 +977,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ], @@ -985,13 +991,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 385, + "line": 396, "character": 19 } ] }, { - "id": 71, + "id": 70, "name": "getName", "kind": 2048, "kindString": "Method", @@ -1001,7 +1007,7 @@ }, "signatures": [ { - "id": 72, + "id": 71, "name": "getName", "kind": 4096, "kindString": "Call signature", @@ -1018,13 +1024,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 90, + "line": 95, "character": 18 } ] }, { - "id": 73, + "id": 72, "name": "import", "kind": 2048, "kindString": "Method", @@ -1034,7 +1040,7 @@ }, "signatures": [ { - "id": 74, + "id": 73, "name": "import", "kind": 4096, "kindString": "Call signature", @@ -1044,7 +1050,7 @@ }, "parameters": [ { - "id": 75, + "id": 74, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1068,13 +1074,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 98, + "line": 103, "character": 17 } ] }, { - "id": 114, + "id": 113, "name": "map", "kind": 2048, "kindString": "Method", @@ -1084,7 +1090,7 @@ }, "signatures": [ { - "id": 115, + "id": 114, "name": "map", "kind": 4096, "kindString": "Call signature", @@ -1095,7 +1101,7 @@ }, "parameters": [ { - "id": 116, + "id": 115, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -1109,21 +1115,21 @@ { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 }, { "type": "array", "elementType": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ] } }, { - "id": 117, + "id": 116, "name": "mapFn", "kind": 32768, "kindString": "Parameter", @@ -1141,7 +1147,7 @@ { "type": "reference", "name": "mapFn", - "id": 117 + "id": 116 } ] } @@ -1157,13 +1163,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 348, + "line": 359, "character": 14 } ] }, { - "id": 124, + "id": 123, "name": "setData", "kind": 2048, "kindString": "Method", @@ -1173,7 +1179,7 @@ }, "signatures": [ { - "id": 125, + "id": 124, "name": "setData", "kind": 4096, "kindString": "Call signature", @@ -1183,7 +1189,7 @@ }, "parameters": [ { - "id": 126, + "id": 125, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1196,12 +1202,12 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 153 + "id": 152 } } }, { - "id": 127, + "id": 126, "name": "names", "kind": 32768, "kindString": "Parameter", @@ -1218,7 +1224,7 @@ } }, { - "id": 128, + "id": 127, "name": "autoType", "kind": 32768, "kindString": "Parameter", @@ -1242,13 +1248,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 401, + "line": 412, "character": 19 } ] }, { - "id": 110, + "id": 109, "name": "sort", "kind": 2048, "kindString": "Method", @@ -1258,7 +1264,7 @@ }, "signatures": [ { - "id": 111, + "id": 110, "name": "sort", "kind": 4096, "kindString": "Call signature", @@ -1274,7 +1280,7 @@ }, "parameters": [ { - "id": 112, + "id": 111, "name": "sortFn", "kind": 32768, "kindString": "Parameter", @@ -1292,13 +1298,13 @@ { "type": "reference", "name": "sortFn", - "id": 112 + "id": 111 } ] } }, { - "id": 113, + "id": 112, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -1311,7 +1317,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 151 + "id": 150 } } ], @@ -1325,13 +1331,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 296, + "line": 307, "character": 15 } ] }, { - "id": 138, + "id": 137, "name": "toDate", "kind": 2048, "kindString": "Method", @@ -1341,7 +1347,7 @@ }, "signatures": [ { - "id": 139, + "id": 138, "name": "toDate", "kind": 4096, "kindString": "Call signature", @@ -1357,7 +1363,7 @@ }, "parameters": [ { - "id": 140, + "id": 139, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -1368,11 +1374,11 @@ "type": { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } }, { - "id": 141, + "id": 140, "name": "limitYear", "kind": 32768, "kindString": "Parameter", @@ -1396,13 +1402,13 @@ "sources": [ { "fileName": "Data.ts", - "line": 499, + "line": 510, "character": 18 } ] }, { - "id": 64, + "id": 63, "name": "toDataSet", "kind": 2048, "kindString": "Method", @@ -1413,14 +1419,14 @@ }, "signatures": [ { - "id": 65, + "id": 64, "name": "toDataSet", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 66, + "id": 65, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1428,11 +1434,11 @@ "type": { "type": "reference", "name": "DataLiteralSet", - "id": 154 + "id": 153 } }, { - "id": 67, + "id": 66, "name": "name", "kind": 32768, "kindString": "Parameter", @@ -1455,7 +1461,7 @@ "sources": [ { "fileName": "Data.ts", - "line": 75, + "line": 80, "character": 27 } ] @@ -1479,10 +1485,13 @@ "flags": { "isExported": true }, + "comment": { + "shortText": "currency values. Currently support6ed are values ofg the format '$dd[,ddd]'" + }, "sources": [ { "fileName": "Data.ts", - "line": 70, + "line": 74, "character": 16 } ], @@ -1490,7 +1499,7 @@ "type": "intrinsic", "name": "string" }, - "defaultValue": "\"currency data\"" + "defaultValue": "\"currency\"" }, { "id": 60, @@ -1500,10 +1509,13 @@ "flags": { "isExported": true }, + "comment": { + "shortText": "date values" + }, "sources": [ { "fileName": "Data.ts", - "line": 69, + "line": 72, "character": 12 } ], @@ -1511,7 +1523,7 @@ "type": "intrinsic", "name": "string" }, - "defaultValue": "\"date data\"" + "defaultValue": "\"date\"" }, { "id": 59, @@ -1521,39 +1533,21 @@ "flags": { "isExported": true }, - "sources": [ - { - "fileName": "Data.ts", - "line": 68, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"name data\"" - }, - { - "id": 63, - "name": "nominal", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true + "comment": { + "shortText": "nominal values, represented by arbitrary words" }, "sources": [ { "fileName": "Data.ts", - "line": 72, - "character": 15 + "line": 70, + "character": 12 } ], "type": { "type": "intrinsic", "name": "string" }, - "defaultValue": "\"nominal data\"" + "defaultValue": "\"name\"" }, { "id": 58, @@ -1563,10 +1557,13 @@ "flags": { "isExported": true }, + "comment": { + "shortText": "numeric values" + }, "sources": [ { "fileName": "Data.ts", - "line": 67, + "line": 68, "character": 14 } ], @@ -1574,7 +1571,7 @@ "type": "intrinsic", "name": "string" }, - "defaultValue": "\"number data\"" + "defaultValue": "\"number\"" }, { "id": 62, @@ -1584,10 +1581,13 @@ "flags": { "isExported": true }, + "comment": { + "shortText": "percent values: 'd%'" + }, "sources": [ { "fileName": "Data.ts", - "line": 71, + "line": 76, "character": 15 } ], @@ -1595,7 +1595,7 @@ "type": "intrinsic", "name": "string" }, - "defaultValue": "\"percent data\"" + "defaultValue": "\"percent\"" } ], "groups": [ @@ -1606,7 +1606,6 @@ 61, 60, 59, - 63, 58, 62 ] @@ -1630,46 +1629,46 @@ "title": "Constructors", "kind": 512, "children": [ - 68 + 67 ] }, { "title": "Properties", "kind": 1024, "children": [ + 117, 118, - 119, - 120 + 119 ] }, { "title": "Methods", "kind": 2048, "children": [ - 135, - 105, - 142, - 83, - 86, - 93, - 96, - 90, - 98, - 76, - 107, - 101, - 132, - 129, - 80, - 78, - 121, - 71, - 73, - 114, - 124, - 110, - 138, - 64 + 134, + 104, + 141, + 82, + 85, + 92, + 95, + 89, + 97, + 75, + 106, + 100, + 131, + 128, + 79, + 77, + 120, + 70, + 72, + 113, + 123, + 109, + 137, + 63 ] }, { @@ -1773,7 +1772,7 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 153 + "id": 152 } } } @@ -1983,7 +1982,7 @@ ] }, { - "id": 151, + "id": 150, "name": "ColumnReference", "kind": 4194304, "kindString": "Type alias", @@ -2015,7 +2014,7 @@ } }, { - "id": 154, + "id": 153, "name": "DataLiteralSet", "kind": 4194304, "kindString": "Type alias", @@ -2044,7 +2043,7 @@ } }, { - "id": 153, + "id": 152, "name": "DataRow", "kind": 4194304, "kindString": "Type alias", @@ -2066,12 +2065,12 @@ "elementType": { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } } }, { - "id": 152, + "id": 151, "name": "DataVal", "kind": 4194304, "kindString": "Type alias", @@ -2107,7 +2106,7 @@ } }, { - "id": 148, + "id": 147, "name": "DateDomain", "kind": 4194304, "kindString": "Type alias", @@ -2139,7 +2138,7 @@ } }, { - "id": 150, + "id": 149, "name": "Domain", "kind": 4194304, "kindString": "Type alias", @@ -2162,23 +2161,23 @@ { "type": "reference", "name": "NumDomain", - "id": 147 + "id": 146 }, { "type": "reference", "name": "DateDomain", - "id": 148 + "id": 147 }, { "type": "reference", "name": "NameDomain", - "id": 149 + "id": 148 } ] } }, { - "id": 149, + "id": 148, "name": "NameDomain", "kind": 4194304, "kindString": "Type alias", @@ -2204,7 +2203,7 @@ } }, { - "id": 147, + "id": 146, "name": "NumDomain", "kind": 4194304, "kindString": "Type alias", @@ -2236,7 +2235,7 @@ } }, { - "id": 146, + "id": 145, "name": "NumRange", "kind": 4194304, "kindString": "Type alias", @@ -2268,7 +2267,7 @@ } }, { - "id": 160, + "id": 159, "name": "mapFn", "kind": 4194304, "kindString": "Type alias", @@ -2285,21 +2284,21 @@ "type": { "type": "reflection", "declaration": { - "id": 161, + "id": 160, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 162, + "id": 161, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 163, + "id": 162, "name": "colVal", "kind": 32768, "kindString": "Parameter", @@ -2310,7 +2309,7 @@ } }, { - "id": 164, + "id": 163, "name": "colIndex", "kind": 32768, "kindString": "Parameter", @@ -2323,7 +2322,7 @@ } }, { - "id": 165, + "id": 164, "name": "rowIndex", "kind": 32768, "kindString": "Parameter", @@ -2336,7 +2335,7 @@ } }, { - "id": 166, + "id": 165, "name": "rows", "kind": 32768, "kindString": "Parameter", @@ -2372,7 +2371,7 @@ } }, { - "id": 155, + "id": 154, "name": "sortFn", "kind": 4194304, "kindString": "Type alias", @@ -2389,21 +2388,21 @@ "type": { "type": "reflection", "declaration": { - "id": 156, + "id": 155, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 157, + "id": 156, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 158, + "id": 157, "name": "x", "kind": 32768, "kindString": "Parameter", @@ -2414,7 +2413,7 @@ } }, { - "id": 159, + "id": 158, "name": "y", "kind": 32768, "kindString": "Parameter", @@ -2463,17 +2462,17 @@ "title": "Type aliases", "kind": 4194304, "children": [ - 151, - 154, + 150, 153, 152, - 148, - 150, - 149, + 151, 147, + 149, + 148, 146, - 160, - 155 + 145, + 159, + 154 ] } ], @@ -2628,14 +2627,14 @@ { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 }, { "type": "array", "elementType": { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } }, { @@ -2848,7 +2847,7 @@ "type": { "type": "reference", "name": "DataVal", - "id": 152 + "id": 151 } }, { @@ -2860,7 +2859,7 @@ "type": { "type": "reference", "name": "DataRow", - "id": 153 + "id": 152 } } ], @@ -2990,7 +2989,7 @@ "type": { "type": "reference", "name": "DataRow", - "id": 153 + "id": 152 } }, { @@ -3132,7 +3131,7 @@ "type": { "type": "reference", "name": "DataRow", - "id": 153 + "id": 152 } }, { @@ -3241,7 +3240,7 @@ ] }, { - "id": 167, + "id": 166, "name": "\"index\"", "kind": 1, "kindString": "External module", @@ -3258,7 +3257,7 @@ ] }, { - "id": 168, + "id": 167, "name": "\"overview\"", "kind": 1, "kindString": "External module", @@ -3267,8 +3266,8 @@ }, "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", "comment": { - "shortText": "# hsdatab", - "text": "Helpful Scripts data management functions that are framework independent.\n\n## Data Types\n-   {@link Data.NumRange NumRange} defines a single [min, max] numeric range.\n-   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column\n-   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column\n-   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column\n-   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains.\n-   {@link Data.ColumnReference ColumnReference} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array\n-   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array\n-   {@link Data.DataRow DataRow} a single row of column values\n\n## Data Class\n-   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query).getColumn('Name').join(', ');\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The query \"{Name:[\"Peter\", \"Jane\"]}\" yields:'),\n m('', result)\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n\n\n" + "shortText": "# hsDatab", + "text": "Helpful Scripts framework-independent data management functions.\n\n*hsdatab* provides a JavaScript-based data management and query mechanism.\nData is managed in a simple in-memory database that holds data in rows of columns.\nIt autodetermines the types of data held in each column, along with the\ndomain range for each column of data.\nComplex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure.\n\n## Data Types\nsupported {@link Data.Data.type data types} include\n- **number**: numeric values\n- **name**: nominal values, represented by arbitrary words\n- **date**: date values\n- **currency**: Currently supported: '$dd[,ddd]'\n- **percent**: 'd%'\n\n## Data Class\nThe fundamental object in this library is {@link Data.Data `Data`},\na simple row-column based database object,\nfeaturing named columns, sorting, mapping and filtering functions.\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query);\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('pre',\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [\n m('td', row[0]),\n m('td', row[1]),\n m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),\n m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)\n ]))\n ])),\n m('h3', 'The column types and domains are'),\n m('pre', m('table',\n m('tr', m('th', 'Column'), m('th', 'Type'), m('th', 'Domain')),\n m('tr', m('td', '\"Name\":'), m('td', data.colType(\"Name\")), m('td', data.findDomain(\"Name\").join(', '))),\n m('tr', m('td', '\"Value\":'), m('td', data.colType(\"Value\")), m('td', data.findDomain(\"Value\").join(' - '))),\n m('tr', m('td', '\"Start\":'), m('td', data.colType(\"Start\")), m('td', data.findDomain(\"Start\").map(d => d.toDateString()).join(' - '))),\n m('tr', m('td', '\"Stop\":'), m('td', data.colType(\"End\")), m('td', data.findDomain(\"End\").map(d => d.toDateString()).join(' - ')))\n )),\n m('h3', 'The query:'),\n m('code', '{Name:[\"Peter\", \"Jane\"]}'),\n m('h3', 'yields results with \"Name\"'),\n m('code', result.getColumn('Name').join(', '))\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n #data { font-size: 11pt; }\n\n\n" }, "sources": [ { @@ -3286,8 +3285,8 @@ "children": [ 42, 1, - 167, - 168 + 166, + 167 ] } ] diff --git a/docs/data/index.json b/docs/data/index.json index ce75152..c9f319f 100644 --- a/docs/data/index.json +++ b/docs/data/index.json @@ -1,6 +1 @@ -{ - "docs": [ - "hsdatab.json" - ], - "title": "HS Libraries" -} \ No newline at end of file +{"docs": ["hsDatab.json"], "title": "HS Libraries"} \ No newline at end of file diff --git a/docs/src/Data.html b/docs/src/Data.html index 490c8c7..d2b7bfa 100644 --- a/docs/src/Data.html +++ b/docs/src/Data.html @@ -6,10 +6,10 @@ .line { margin: 0 5px 0 0; padding-right: 5px; color:#999; background-color:#eef; } comment { color: #080;} module { color: #804;} .listing { margin: 10px; border: 1px solid #ccc; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 14px; line-height: 1.2em; - overflow:scroll; - height:90%; + font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 14px; line-height: 1.2em; + overflow:scroll; + height:90%; } code { padding: 5px 0;}

    Data.ts

    @@ -79,479 +79,490 @@

    Data.ts

      64    // public part
      65    //----------------------------
      66    public static type = {
    -  67        number:     'number data',
    -  68        name:       'name data',
    -  69        date:       'date data',
    -  70        currency:   'currency data',
    -  71        percent:    'percent data',
    -  72        nominal:    'nominal data'
    -  73    };
    -  74
    -  75    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    -  76        data = data || [{}];
    -  77        const names = Object.keys(data[0]);
    -  78        const rows = data.map((r:any) => 
    -  79            names.map((n:string) => r[n]));
    -  80        return { rows:rows, colNames:names, name:name||undefined };
    -  81    }
    -  82
    -  83    constructor(data?:DataSet) {
    -  84        this.import(data);
    -  85    }
    -  86
    -  87    /**
    -  88     * @return the `name` field for this data base, if any
    -  89     */

    -  90    public getName():string {
    -  91        return this.name;
    -  92    }
    -  93
    -  94    /**
    -  95     * Imports data from an object literal `data`
    -  96     * @param data the data set to import
    -  97     */

    -  98    public import(data:DataSet) {
    -  99        this.name = data.name;
    - 100        this.setData(data.rows, data.colNames);
    - 101    }
    - 102
    - 103    /**
    - 104     * Exports to an object literal
    - 105     */

    - 106    public export():DataSet {
    - 107        return {
    - 108            rows: this.getData(),
    - 109            colNames:this.colNames()
    - 110        };
    - 111    }
    - 112
    - 113    /**
    - 114     * returns the 2D array underlying the data base.
    - 115     */

    - 116    public getData():DataRow[] {
    - 117        return this.data;
    - 118    }
    - 119
    - 120    /**
    - 121     * Returns the values in the specified column as a new array.
    - 122     * @param col the column to return.
    - 123     */

    - 124    public getColumn(col:ColumnReference): DataVal[] {
    - 125        const cn = this.colNumber(col);
    - 126        return this.data.map((row:DataRow) => row[cn]);
    - 127    }
    - 128
    - 129    /**
    - 130     * adds a new column to the data set. if `newCol` already exists, 
    - 131     * the column index is returned withoput change.
    - 132     * @param col the name of the new column
    - 133     * @return the index for the new column
    - 134     */

    - 135    public colAdd(col:string):number {
    - 136        let m = this.getMeta(col);
    - 137        if (m === undefined) { 
    - 138            m = this.meta[col] = {};
    - 139            m.name   = col; 
    - 140            m.column = this.meta.length;
    - 141            this.meta.push(m);      // access name by both column name and index
    - 142            m.cast     = false;         // has not been cast yet
    - 143            m.accessed = false;         // has not been accessed yet
    - 144        }
    - 145        return m.column;
    - 146    }
    - 147
    - 148    /**
    - 149     * initializes the specifed column with values, adding a new column if needed. 
    - 150     * If `val`is a function, it is called as ```
    - 151     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    - 152     * ```
    - 153     * @param col the column to initialize
    - 154     * @param initializer the value to initialize with, or a function whose return
    - 155     * value is used to initialize the column
    - 156     */

    - 157    public colInitialize(col:ColumnReference, initializer:any) {
    - 158        const cn = this.colNumber(col);
    - 159        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    - 160        const fn = typeof initializer === 'function';
    - 161        if (cn!==undefined) {
    - 162            this.data.map((r:DataRow, i:number) =>
    - 163                r[cn] = fn? initializer(r[cn], i, r) : initializer
    - 164            );
    - 165        }
    - 166    }
    - 167
    - 168    /**
    - 169     * returns the column index of the specified column. 
    - 170     * `col` can be either an index or a name.
    - 171     * @param column the data column, name or index, for which to return the index. 
    - 172     * @return the column number or `undefined`.
    - 173     */

    - 174    public colNumber(col:ColumnReference) {
    - 175        const m = this.getMeta(col);
    - 176        if (!m) { return undefined; }
    - 177        else {
    - 178            m.accessed = true; 
    - 179            return m.column; 
    - 180        }
    - 181    }
    - 182    
    - 183    /**
    - 184     * returns the column name for the specified column. 
    - 185     * `col` can be either an index or a name.
    - 186     * @param column the data column, name or index. 
    - 187     * @return the column name or `undefined`.
    - 188     */

    - 189    public colName(col:ColumnReference) {
    - 190        var m = this.getMeta(col);
    - 191        if (!m) { return undefined; }
    - 192        m.accessed = true; 
    - 193        return m.name; 
    - 194    }
    - 195
    - 196    /**
    - 197     * returns the names for all columns. 
    - 198     * @return an array of strings with the names.
    - 199     */

    - 200    public colNames():string[] {
    - 201        return this.meta.map((m:MetaStruct) => m.name); 
    - 202    }
    - 203
    - 204    /**
    - 205     * returns the column type for the specified column. 
    - 206     * `col` can be either an index or a name.
    - 207     * @param column the data column, name or index. 
    - 208     * @return the column type.
    - 209     */

    - 210    public colType(col:ColumnReference) { 
    - 211        const meta = this.getMeta(col);
    - 212        return meta? meta.types[0].type : Data.type.name;
    - 213    }
    - 214
    - 215    /**
    - 216     * modifies `domain` to include all values in column `col`.
    - 217     * @param col the column name or index 
    - 218     * @param domain the 
    - 219     */

    - 220    public findDomain(col:ColumnReference, domain:Domain) {
    - 221        if (col === undefined) { // use array index as domain
    - 222            domain[0] = 0;
    - 223            domain[1] = this.data.length-1;
    - 224        } else {
    - 225            const c = this.colNumber(col);
    - 226            const type = this.colType(col);
    - 227            if (this.data === undefined) {
    - 228                console.log('no data'); 
    - 229            }
    - 230            switch(type) {
    - 231                case Data.type.nominal: 
    - 232                    this.data.forEach((r:DataRow) => {
    - 233                        const nomDom = domain;
    - 234                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    - 235                    });
    - 236                    break;
    - 237                default: 
    - 238                    this.data.forEach((r:DataRow) => {
    - 239                        let v:number = r[c];
    - 240                        if (v!==undefined && v!==null) {
    - 241                            domain[0] = (v - 242                            domain[1] = (v>domain[1])? v : domain[1];
    - 243                        }
    - 244                    });
    - 245            }
    - 246        }
    - 247    }
    - 248
    - 249    public castData() {
    - 250        this.meta.forEach((c:MetaStruct) => {
    - 251            const col = c.column;
    - 252            if (!c.cast) {
    - 253                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    - 254            }
    - 255            c.cast = true;
    - 256        });
    - 257    }
    - 258
    - 259    /**
    - 260     * filters this data set and returns a new data set with a 
    - 261     * shallow copy of rows that pass the `condition`.
    - 262     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    - 263     * @param condition filters 
    - 264     * @return a new Data object with rows that pass the filter
    - 265     */

    - 266    public filter(condition:Condition):Data {
    - 267        return filter(this, condition);
    +  67        /** numeric values */
    +  68        number:     'number',
    +  69        /** nominal values, represented by arbitrary words */
    +  70        name:       'name',
    +  71        /** date values */
    +  72        date:       'date',
    +  73        /** currency values. Currently support6ed are values ofg the format '$dd[,ddd]' */
    +  74        currency:   'currency',
    +  75        /** percent values: 'd%' */
    +  76        percent:    'percent',
    +  77//        nominal:    'nominal'
    +  78    };
    +  79
    +  80    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    +  81        data = data || [{}];
    +  82        const names = Object.keys(data[0]);
    +  83        const rows = data.map((r:any) => 
    +  84            names.map((n:string) => r[n]));
    +  85        return { rows:rows, colNames:names, name:name||undefined };
    +  86    }
    +  87
    +  88    constructor(data?:DataSet) {
    +  89        this.import(data);
    +  90    }
    +  91
    +  92    /**
    +  93     * @return the `name` field for this data base, if any
    +  94     */

    +  95    public getName():string {
    +  96        return this.name;
    +  97    }
    +  98
    +  99    /**
    + 100     * Imports data from an object literal `data`
    + 101     * @param data the data set to import
    + 102     */

    + 103    public import(data:DataSet) {
    + 104        this.name = data.name;
    + 105        this.setData(data.rows, data.colNames);
    + 106    }
    + 107
    + 108    /**
    + 109     * Exports to an object literal
    + 110     */

    + 111    public export():DataSet {
    + 112        return {
    + 113            rows: this.getData(),
    + 114            colNames:this.colNames()
    + 115        };
    + 116    }
    + 117
    + 118    /**
    + 119     * returns the 2D array underlying the data base.
    + 120     */

    + 121    public getData():DataRow[] {
    + 122        return this.data;
    + 123    }
    + 124
    + 125    /**
    + 126     * Returns the values in the specified column as a new array.
    + 127     * @param col the column to return.
    + 128     */

    + 129    public getColumn(col:ColumnReference): DataVal[] {
    + 130        const cn = this.colNumber(col);
    + 131        return this.data.map((row:DataRow) => row[cn]);
    + 132    }
    + 133
    + 134    /**
    + 135     * adds a new column to the data set. if `newCol` already exists, 
    + 136     * the column index is returned withoput change.
    + 137     * @param col the name of the new column
    + 138     * @return the index for the new column
    + 139     */

    + 140    public colAdd(col:string):number {
    + 141        let m = this.getMeta(col);
    + 142        if (m === undefined) { 
    + 143            m = this.meta[col] = {};
    + 144            m.name   = col; 
    + 145            m.column = this.meta.length;
    + 146            this.meta.push(m);      // access name by both column name and index
    + 147            m.cast     = false;         // has not been cast yet
    + 148            m.accessed = false;         // has not been accessed yet
    + 149        }
    + 150        return m.column;
    + 151    }
    + 152
    + 153    /**
    + 154     * initializes the specifed column with values, adding a new column if needed. 
    + 155     * If `val`is a function, it is called as ```
    + 156     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    + 157     * ```
    + 158     * @param col the column to initialize
    + 159     * @param initializer the value to initialize with, or a function whose return
    + 160     * value is used to initialize the column
    + 161     */

    + 162    public colInitialize(col:ColumnReference, initializer:any) {
    + 163        const cn = this.colNumber(col);
    + 164        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    + 165        const fn = typeof initializer === 'function';
    + 166        if (cn!==undefined) {
    + 167            this.data.map((r:DataRow, i:number) =>
    + 168                r[cn] = fn? initializer(r[cn], i, r) : initializer
    + 169            );
    + 170        }
    + 171    }
    + 172
    + 173    /**
    + 174     * returns the column index of the specified column. 
    + 175     * `col` can be either an index or a name.
    + 176     * @param column the data column, name or index, for which to return the index. 
    + 177     * @return the column number or `undefined`.
    + 178     */

    + 179    public colNumber(col:ColumnReference) {
    + 180        const m = this.getMeta(col);
    + 181        if (!m) { return undefined; }
    + 182        else {
    + 183            m.accessed = true; 
    + 184            return m.column; 
    + 185        }
    + 186    }
    + 187    
    + 188    /**
    + 189     * returns the column name for the specified column. 
    + 190     * `col` can be either an index or a name.
    + 191     * @param column the data column, name or index. 
    + 192     * @return the column name or `undefined`.
    + 193     */

    + 194    public colName(col:ColumnReference) {
    + 195        var m = this.getMeta(col);
    + 196        if (!m) { return undefined; }
    + 197        m.accessed = true; 
    + 198        return m.name; 
    + 199    }
    + 200
    + 201    /**
    + 202     * returns the names for all columns. 
    + 203     * @return an array of strings with the names.
    + 204     */

    + 205    public colNames():string[] {
    + 206        return this.meta.map((m:MetaStruct) => m.name); 
    + 207    }
    + 208
    + 209    /**
    + 210     * returns the column type for the specified column. 
    + 211     * `col` can be either an index or a name.
    + 212     * @param column the data column, name or index. 
    + 213     * @return the column type.
    + 214     */

    + 215    public colType(col:ColumnReference) { 
    + 216        const meta = this.getMeta(col);
    + 217        return meta? meta.types[0].type : Data.type.name;
    + 218    }
    + 219
    + 220    /**
    + 221     * modifies `domain` to include all values in column `col`.
    + 222     * If no `col` is specified, the range of data indexes is returned.
    + 223     * @param col optional; the column name or index 
    + 224     * @param domain optional; the Domain range to update
    + 225     * @return the updated domain
    + 226     */

    + 227    public findDomain(col?:ColumnReference, domain?:Domain):Domain {
    + 228        if (domain===undefined) { domain = []; }
    + 229        if (col === undefined) { // use array index as domain
    + 230            domain[0] = 0;
    + 231            domain[1] = this.data.length-1;
    + 232        } else {
    + 233            const c = this.colNumber(col);
    + 234            const type = this.colType(col);
    + 235            if (this.data === undefined) {
    + 236                console.log('no data'); 
    + 237            }
    + 238            switch(type) {
    + 239                case Data.type.name: 
    + 240                    this.data.forEach((r:DataRow) => {
    + 241                        const nomDom = domain;
    + 242                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    + 243                    });
    + 244                    break;
    + 245                default: 
    + 246                    this.data.forEach((r:DataRow) => {
    + 247                        let v:number = r[c];
    + 248                        if (domain[0]===undefined) { domain[0] = v; }
    + 249                        if (domain[1]===undefined) { domain[1] = v; }
    + 250                        if (v!==undefined && v!==null) {
    + 251                            if (v + 252                            else if (v>domain[1]) { domain[1] = v; }
    + 253                        }
    + 254                    });
    + 255            }
    + 256        }
    + 257        return domain;
    + 258    }
    + 259
    + 260    public castData() {
    + 261        this.meta.forEach((c:MetaStruct) => {
    + 262            const col = c.column;
    + 263            if (!c.cast) {
    + 264                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    + 265            }
    + 266            c.cast = true;
    + 267        });
     268    }
     269
     270    /**
    - 271     * @description Sorts the rows of values based on the result of the `sortFn`, 
    - 272     * which behaves similarly to the Array.sort method.  
    - 273     * Two modes are supported:
    - 274     * # Array Mode
    - 275     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    - 276     * This allows for complex sorts, combining conditions across multiple columns.
    - 277     * ```
    - 278     * data.sort((row1, row2) => row1[5] - row2[5] );
    - 279     * ```
    - 280     * # Column mode
    - 281     * If `col` is specified, either as index or by column name, the respective column value is passed
    - 282     * into `sortFn`. This allows filtering for simple conditions.

    - 283     * **The specified column will be automatically cast prior to sorting**

    - 284     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    - 285     * @param col optional; the data column to use for sorting. 
    - 286     * @param sortFn a function to implement the conditions, 
    - 287     * follows the same specifications as the function passed to Array.sort(). 
    - 288     * Some predefined sort function can be invoked by providing a 
    - 289     * respective string instead of a function. The following functions are defined:
    - 290        
    - 291        
    - 292        
    - 293        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    - 294     * @return the Data object in order to allow for chaining.
    - 295     */

    - 296    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    - 297        let fn = sortFn;
    - 298        if (!col) {
    - 299            this.data.sort(fn);
    - 300        } else {
    - 301            col = this.colNumber(col);
    - 302            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b - 303            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    - 304            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    - 305        }
    - 306        return this;
    - 307    }
    - 308
    - 309    /** 
    - 310    *  Maps one or more columns in each rows of values based 
    - 311     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    - 312     * Two modes are supported:
    - 313     * # Array Mode
    - 314     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    - 315     * This allows for complex mapping combining conditions across multiple columns.
    - 316     * ```
    - 317     * data.map(function(values){ 
    - 318     *    values[1] = values[3] * values[5]; 
    - 319     *    return values; 
    - 320     * });
    - 321     * ```
    - 322     * Be sure to return the `values` array as a result.
    - 323     * # Column mode
    - 324     * If `col` is specified, either as index or by column name, the respective column value is passed
    - 325     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    - 326     * ```
    - 327     * data.map('Price', function(value, i, values) { 
    - 328     *    return value * 2; 
    - 329     * });
    - 330     * ```
    - 331     * @param col the data column, or columns, to apply the mapping to. 
    - 332     * @param mapFn a function to implement the mapping,
    - 333     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    - 334     * - `val`: the column value in the current row
    - 335     * - `c`: the column index in the current row
    - 336     * - `i`: the row index 
    - 337     * - `rows`: the rows being iterated over
    - 338`    * 
    - 339     * follows the same specifications as the function passed to Array.map().

    - 340     * For column mode, some predefined map functions can be invoked by providing a 
    - 341     * respective string instead of a function. The following functions are defined:
    - 342        
    - 343        
    - 344        
    - 345        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    - 346     * @return a new Data object containing the mapping.
    - 347     */

    - 348    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    - 349        const noop = (val:any) => val;
    - 350        const cumulate = () => { 
    - 351            let sum=0; 
    - 352            return (val:number, i:number) => { sum += +val; return sum; };
    - 353        };
    - 354        function getFn() {
    - 355            let fn; // define fn inside each col loop to ensure initialization
    - 356            switch (mapFn) {
    - 357                case 'cumulate': fn = cumulate(); break;
    - 358                case 'noop':     fn = noop; break;
    - 359                default:         fn = mapFn;
    - 360            }
    - 361            return fn;
    - 362        }
    - 363
    - 364        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    - 365
    - 366        const names = col['length']? col : [col];            
    - 367        names.map((cn:ColumnReference) => {
    - 368            const c = this.colNumber(cn);
    - 369            let fn = getFn(); // define fn inside each col loop to ensure initialization
    - 370            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    - 371                row[c] = fn(row[c], c, i, rows); 
    - 372                return row;
    - 373            });
    - 374        });
    - 375        return result;
    - 376    }
    - 377
    - 378    //----------------------------
    - 379    // private part
    - 380    //----------------------------
    - 381    private data: DataRow[]    = [];
    - 382    private meta: MetaStruct[] = [];
    - 383    private name: string;
    - 384
    - 385    private getMeta(col:ColumnReference):MetaStruct { 
    - 386        if (!this.meta) { this.meta = []; }
    - 387        if (!this.meta[col]) { return undefined; }
    - 388        this.meta[col].accessed = true;
    - 389        return this.meta[col]; 
    - 390    }
    - 391
    - 392    /**
    - 393     * sets `data` to the existing data set. If data has previously been set, 
    - 394     * `data` will be added to the end of the list if all `names`  match those of the 
    - 395     * existing set. 
    - 396     * @param data the data to add
    - 397     * @param names an array of names that match the columns
    - 398     * @param autoType unless set to false, the method will attempt to determine the 
    - 399     * type of data and automatically cast data points to their correct value
    - 400     */

    - 401    private setData(data:DataRow[], names:string[], autoType=true):void {
    - 402        this.meta = [];
    - 403        this.data = data;
    - 404        if (!names) {
    - 405            console.log();
    - 406        }
    - 407        names.forEach((col:string) => this.colAdd(col));
    - 408        names.forEach((col:string) => this.findTypes(col));
    - 409        this.castData();
    - 410    }
    - 411
    - 412    /**
    - 413     * Determines the type of data in `col`. An array of counts is created for all
    - 414     * encountered types, sorted by descending frequency. THe most likely type in position 0
    - 415     * of the array is returned.
    - 416     * @param col the index of the column to be typed. 
    - 417     * @return the most likely type of data in `col`.
    - 418     */

    - 419    private findTypes(col:ColumnReference):string {
    - 420        const m = this.getMeta(col);
    - 421        const types:TypeStruct[] = [];
    - 422        Object.keys(Data.type).forEach((t:string) => {
    - 423            const ts = { type: Data.type[t], count: 0 }; 
    - 424            types.push(ts);
    - 425            types[Data.type[t]] = ts;
    - 426        });
    - 427        for (let v of this.allRows(col)) {
    - 428            const t = this.findType(v);
    - 429            if (t !== null) { types[t].count++; }
    - 430        }
    - 431        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    - 432            if (a.type==='currency'&&a.count>0) { return -1; }
    - 433            if (b.type==='currency'&&b.count>0) { return 1; }
    - 434            return b.count - a.count;
    - 435        });
    - 436        m.types = types;
    - 437        return types[0].type;
    - 438    }
    - 439
    - 440    /**
    - 441     * @description determines the data type. Supported types are 
    - 442     * ```
    - 443     * 'date':    sample represents a Date, either as a Date object or a String 
    - 444     * 'number':  sample represents a number
    - 445     * 'percent': sample represents a percentage (special case of a real number)
    - 446     * 'nominal': sample represents a nominal (ordinal or categorical) value
    - 447     * ```
    - 448     * @param val the value to bve typed.
    - 449     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    - 450     */

    - 451    private findType(val:DataVal) {
    - 452        if (val && val!=='') {
    - 453            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    - 454            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    - 455
    - 456            // else: val is a string:
    - 457            const strVal = ''+val;
    - 458            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    - 459            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    - 460            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    - 461            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    - 462
    - 463            // european large number currency representation: '$dd,ddd[,ddd]'
    - 464            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    - 465                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    - 466                    return Data.type.currency; 
    - 467                }
    - 468            }
    - 469            switch (strVal.toLowerCase()) {
    - 470                case "null": break;
    - 471                case "#ref!": break;
    - 472                default: if (val.length>0) { return Data.type.nominal; }
    - 473            }
    - 474        }
    - 475        return null;
    - 476    }    
    - 477
    - 478    /**
    - 479     * A generator that provides the specified column value for each row in `Data` in sequence. 
    - 480     * @param column 
    - 481     */

    - 482    private * allRows(column:ColumnReference):Iterable {
    - 483        const c = this.colNumber(column);
    - 484        for (let r=0; r - 485            yield this.data[r][c];
    - 486        }
    - 487    }
    + 271     * filters this data set and returns a new data set with a 
    + 272     * shallow copy of rows that pass the `condition`.
    + 273     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    + 274     * @param condition filters 
    + 275     * @return a new Data object with rows that pass the filter
    + 276     */
    + 277    public filter(condition:Condition):Data {
    + 278        return filter(this, condition);
    + 279    }
    + 280
    + 281    /**
    + 282     * @description Sorts the rows of values based on the result of the `sortFn`, 
    + 283     * which behaves similarly to the Array.sort method.  
    + 284     * Two modes are supported:
    + 285     * # Array Mode
    + 286     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    + 287     * This allows for complex sorts, combining conditions across multiple columns.
    + 288     * ```
    + 289     * data.sort((row1, row2) => row1[5] - row2[5] );
    + 290     * ```
    + 291     * # Column mode
    + 292     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 293     * into `sortFn`. This allows filtering for simple conditions.

    + 294     * **The specified column will be automatically cast prior to sorting**

    + 295     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    + 296     * @param col optional; the data column to use for sorting. 
    + 297     * @param sortFn a function to implement the conditions, 
    + 298     * follows the same specifications as the function passed to Array.sort(). 
    + 299     * Some predefined sort function can be invoked by providing a 
    + 300     * respective string instead of a function. The following functions are defined:
    + 301        
    + 302        
    + 303        
    + 304        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    + 305     * @return the Data object in order to allow for chaining.
    + 306     */

    + 307    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    + 308        let fn = sortFn;
    + 309        if (!col) {
    + 310            this.data.sort(fn);
    + 311        } else {
    + 312            col = this.colNumber(col);
    + 313            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b + 314            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    + 315            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    + 316        }
    + 317        return this;
    + 318    }
    + 319
    + 320    /** 
    + 321    *  Maps one or more columns in each rows of values based 
    + 322     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    + 323     * Two modes are supported:
    + 324     * # Array Mode
    + 325     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    + 326     * This allows for complex mapping combining conditions across multiple columns.
    + 327     * ```
    + 328     * data.map(function(values){ 
    + 329     *    values[1] = values[3] * values[5]; 
    + 330     *    return values; 
    + 331     * });
    + 332     * ```
    + 333     * Be sure to return the `values` array as a result.
    + 334     * # Column mode
    + 335     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 336     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    + 337     * ```
    + 338     * data.map('Price', function(value, i, values) { 
    + 339     *    return value * 2; 
    + 340     * });
    + 341     * ```
    + 342     * @param col the data column, or columns, to apply the mapping to. 
    + 343     * @param mapFn a function to implement the mapping,
    + 344     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    + 345     * - `val`: the column value in the current row
    + 346     * - `c`: the column index in the current row
    + 347     * - `i`: the row index 
    + 348     * - `rows`: the rows being iterated over
    + 349`    * 
    + 350     * follows the same specifications as the function passed to Array.map().

    + 351     * For column mode, some predefined map functions can be invoked by providing a 
    + 352     * respective string instead of a function. The following functions are defined:
    + 353        
    + 354        
    + 355        
    + 356        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    + 357     * @return a new Data object containing the mapping.
    + 358     */

    + 359    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    + 360        const noop = (val:any) => val;
    + 361        const cumulate = () => { 
    + 362            let sum=0; 
    + 363            return (val:number, i:number) => { sum += +val; return sum; };
    + 364        };
    + 365        function getFn() {
    + 366            let fn; // define fn inside each col loop to ensure initialization
    + 367            switch (mapFn) {
    + 368                case 'cumulate': fn = cumulate(); break;
    + 369                case 'noop':     fn = noop; break;
    + 370                default:         fn = mapFn;
    + 371            }
    + 372            return fn;
    + 373        }
    + 374
    + 375        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    + 376
    + 377        const names = col['length']? col : [col];            
    + 378        names.map((cn:ColumnReference) => {
    + 379            const c = this.colNumber(cn);
    + 380            let fn = getFn(); // define fn inside each col loop to ensure initialization
    + 381            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    + 382                row[c] = fn(row[c], c, i, rows); 
    + 383                return row;
    + 384            });
    + 385        });
    + 386        return result;
    + 387    }
    + 388
    + 389    //----------------------------
    + 390    // private part
    + 391    //----------------------------
    + 392    private data: DataRow[]    = [];
    + 393    private meta: MetaStruct[] = [];
    + 394    private name: string;
    + 395
    + 396    private getMeta(col:ColumnReference):MetaStruct { 
    + 397        if (!this.meta) { this.meta = []; }
    + 398        if (!this.meta[col]) { return undefined; }
    + 399        this.meta[col].accessed = true;
    + 400        return this.meta[col]; 
    + 401    }
    + 402
    + 403    /**
    + 404     * sets `data` to the existing data set. If data has previously been set, 
    + 405     * `data` will be added to the end of the list if all `names`  match those of the 
    + 406     * existing set. 
    + 407     * @param data the data to add
    + 408     * @param names an array of names that match the columns
    + 409     * @param autoType unless set to false, the method will attempt to determine the 
    + 410     * type of data and automatically cast data points to their correct value
    + 411     */

    + 412    private setData(data:DataRow[], names:string[], autoType=true):void {
    + 413        this.meta = [];
    + 414        this.data = data;
    + 415        if (!names) {
    + 416            console.log();
    + 417        }
    + 418        names.forEach((col:string) => this.colAdd(col));
    + 419        names.forEach((col:string) => this.findTypes(col));
    + 420        this.castData();
    + 421    }
    + 422
    + 423    /**
    + 424     * Determines the type of data in `col`. An array of counts is created for all
    + 425     * encountered types, sorted by descending frequency. THe most likely type in position 0
    + 426     * of the array is returned.
    + 427     * @param col the index of the column to be typed. 
    + 428     * @return the most likely type of data in `col`.
    + 429     */

    + 430    private findTypes(col:ColumnReference):string {
    + 431        const m = this.getMeta(col);
    + 432        const types:TypeStruct[] = [];
    + 433        Object.keys(Data.type).forEach((t:string) => {
    + 434            const ts = { type: Data.type[t], count: 0 }; 
    + 435            types.push(ts);
    + 436            types[Data.type[t]] = ts;
    + 437        });
    + 438        for (let v of this.allRows(col)) {
    + 439            const t = this.findType(v);
    + 440            if (t !== null) { types[t].count++; }
    + 441        }
    + 442        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    + 443            if (a.type==='currency'&&a.count>0) { return -1; }
    + 444            if (b.type==='currency'&&b.count>0) { return 1; }
    + 445            return b.count - a.count;
    + 446        });
    + 447        m.types = types;
    + 448        return types[0].type;
    + 449    }
    + 450
    + 451    /**
    + 452     * @description determines the data type. Supported types are 
    + 453     * ```
    + 454     * 'date':    sample represents a Date, either as a Date object or a String 
    + 455     * 'number':  sample represents a number
    + 456     * 'percent': sample represents a percentage (special case of a real number)
    + 457     * 'nominal': sample represents a nominal (ordinal or categorical) value
    + 458     * ```
    + 459     * @param val the value to bve typed.
    + 460     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    + 461     */

    + 462    private findType(val:DataVal) {
    + 463        if (val && val!=='') {
    + 464            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    + 465            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    + 466
    + 467            // else: val is a string:
    + 468            const strVal = ''+val;
    + 469            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    + 470            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    + 471            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    + 472            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    + 473
    + 474            // european large number currency representation: '$dd[,ddd]'
    + 475            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    + 476                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    + 477                    return Data.type.currency; 
    + 478                }
    + 479            }
    + 480            switch (strVal.toLowerCase()) {
    + 481                case "null": break;
    + 482                case "#ref!": break;
    + 483                default: if (val.length>0) { return Data.type.name; }
    + 484            }
    + 485        }
    + 486        return null;
    + 487    }    
     488
     489    /**
    - 490     * @param val the string to convert to a date
    - 491     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    - 492     * @returns a new Date object parsed from `str`.
    - 493     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    - 494     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    - 495     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    - 496     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    - 497     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    - 498     */

    - 499    private toDate(val:DataVal, limitYear=1970):Date {
    - 500        let d:Date;
    - 501        if (val instanceof Date) { d = val; }
    - 502                            else { d = new Date(val); }   
    - 503        let yr=d.getFullYear();
    - 504        if (yr < 100) { 
    - 505            yr += 1900; 
    - 506            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    - 507        }
    - 508        return d;
    - 509    }
    - 510
    - 511    /**
    - 512     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    - 513     * does not match any of the previous keywords, no casting occurs.
    - 514     * @param sample The value to cast.
    - 515     * @returns The result of the cast. 
    - 516     * @description Casts the sample to the specified data type.
    - 517     */

    - 518    private castVal(type:string, val:DataVal):DataVal {
    - 519        switch (type) {
    - 520            case Data.type.date:    if (val instanceof Date) { return val; }
    - 521                            val = this.toDate(val);
    - 522                            if (isNaN(val.getTime())) { val = null; }
    - 523                            break;
    - 524            case Data.type.percent: if (typeof val === 'string') {
    - 525                                const num = parseFloat(val);
    - 526                                val = (val).endsWith('%')? num/100 : num;
    - 527                            } 
    - 528                            if (isNaN(val)) { val = null; }
    - 529                            break;
    - 530            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    - 531             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    - 532             /* falls through */
    - 533            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    - 534                            if (isNaN(val)) { val = null; }
    - 535                            break;
    - 536            default:        val = ''+val;
    - 537        }
    - 538        return val;
    - 539     }     
    - 540}
    + 490     * A generator that provides the specified column value for each row in `Data` in sequence. 
    + 491     * @param column 
    + 492     */
    + 493    private * allRows(column:ColumnReference):Iterable {
    + 494        const c = this.colNumber(column);
    + 495        for (let r=0; r + 496            yield this.data[r][c];
    + 497        }
    + 498    }
    + 499
    + 500    /**
    + 501     * @param val the string to convert to a date
    + 502     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    + 503     * @returns a new Date object parsed from `str`.
    + 504     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    + 505     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    + 506     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    + 507     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    + 508     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    + 509     */

    + 510    private toDate(val:DataVal, limitYear=1970):Date {
    + 511        let d:Date;
    + 512        if (val instanceof Date) { d = val; }
    + 513                            else { d = new Date(val); }   
    + 514        let yr=d.getFullYear();
    + 515        if (yr < 100) { 
    + 516            yr += 1900; 
    + 517            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    + 518        }
    + 519        return d;
    + 520    }
    + 521
    + 522    /**
    + 523     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    + 524     * does not match any of the previous keywords, no casting occurs.
    + 525     * @param sample The value to cast.
    + 526     * @returns The result of the cast. 
    + 527     * @description Casts the sample to the specified data type.
    + 528     */

    + 529    private castVal(type:string, val:DataVal):DataVal {
    + 530        switch (type) {
    + 531            case Data.type.date:    if (val instanceof Date) { return val; }
    + 532                            val = this.toDate(val);
    + 533                            if (isNaN(val.getTime())) { val = null; }
    + 534                            break;
    + 535            case Data.type.percent: if (typeof val === 'string') {
    + 536                                const num = parseFloat(val);
    + 537                                val = (val).endsWith('%')? num/100 : num;
    + 538                            } 
    + 539                            if (isNaN(val)) { val = null; }
    + 540                            break;
    + 541            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    + 542             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    + 543             /* falls through */
    + 544            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    + 545                            if (isNaN(val)) { val = null; }
    + 546                            break;
    + 547            default:        val = ''+val;
    + 548        }
    + 549        return val;
    + 550     }     
    + 551}
    \ No newline at end of file diff --git a/docs/src/DataFilters.html b/docs/src/DataFilters.html index 7e60815..cd063c1 100644 --- a/docs/src/DataFilters.html +++ b/docs/src/DataFilters.html @@ -6,10 +6,10 @@ .line { margin: 0 5px 0 0; padding-right: 5px; color:#999; background-color:#eef; } comment { color: #080;} module { color: #804;} .listing { margin: 10px; border: 1px solid #ccc; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 14px; line-height: 1.2em; - overflow:scroll; - height:90%; + font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 14px; line-height: 1.2em; + overflow:scroll; + height:90%; } code { padding: 5px 0;}

    DataFilters.ts

    diff --git a/docs/src/index.html b/docs/src/index.html index f59d1fa..6172591 100644 --- a/docs/src/index.html +++ b/docs/src/index.html @@ -6,10 +6,10 @@ .line { margin: 0 5px 0 0; padding-right: 5px; color:#999; background-color:#eef; } comment { color: #080;} module { color: #804;} .listing { margin: 10px; border: 1px solid #ccc; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 14px; line-height: 1.2em; - overflow:scroll; - height:90%; + font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 14px; line-height: 1.2em; + overflow:scroll; + height:90%; } code { padding: 5px 0;}

    index.ts

    diff --git a/docs/src/overview.html b/docs/src/overview.html index fd2fe14..5a4ae06 100644 --- a/docs/src/overview.html +++ b/docs/src/overview.html @@ -6,68 +6,91 @@ .line { margin: 0 5px 0 0; padding-right: 5px; color:#999; background-color:#eef; } comment { color: #080;} module { color: #804;} .listing { margin: 10px; border: 1px solid #ccc; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 14px; line-height: 1.2em; - overflow:scroll; - height:90%; + font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 14px; line-height: 1.2em; + overflow:scroll; + height:90%; } code { padding: 5px 0;}

    overview.ts

       1/**
    -   2 * # hsdatab
    +   2 * # hsDatab
       3 * 
    -   4 * Helpful Scripts data management functions that are framework independent. 
    +   4 * Helpful Scripts framework-independent data management functions. 
       5 * 
    -   6 * ## Data Types
    -   7 * -   {@link Data.NumRange NumRange} defines a single [min, max] numeric range.
    -   8 * -   {@link Data.NumDomain NumDomain} defines a numeric domain that includes all values of a column
    -   9 * -   {@link Data.DateDomain DateDomain} defines a Date domain that includes all values of a column
    -  10 * -   {@link Data.NameDomain NameDomain} defines a categorical domain that includes all values of a column
    -  11 * -   {@link Data.Domain Domain} defines a generic domain that can be any of the typed domains.
    -  12 * -   {@link Data.ColumnReference ColumnReference} defines a Column Specifier, either as column name or index in the {@link Data.DataRow `DataRow`} array 
    -  13 * -   {@link Data.DataVal DataVal} a generic data value type, used in the {@link Data.DataRow `DataRow`} array
    -  14 * -   {@link Data.DataRow DataRow} a single row of column values
    -  15 * 
    -  16 * ## Data Class
    -  17 * -   {@link Data.Data Data} A simple row-column based database object, featuring named columns, sorting, mapping and filtering functions
    -  18 *
    -  19 * ## Example
    -  20 * 
    -  21 * 
    -  22 * const colNames = ['Name', 'Value', 'Start', 'End'];
    -  23 * const rows = [
    -  24 *   ['Harry', '100', '3/1/14', '11/20/14'], 
    -  25 *   ['Mary', '1500', '7/1/14',  '9/30/14'],
    -  26 *   ['Peter', '400', '5/20/14', '4/30/15'],  
    -  27 *   ['Jane', '700', '11/13/14', '8/15/15']
    -  28 * ]
    -  29 * const data = new hsdatab.Data({colNames:colNames, rows:rows});
    -  30 * 
    -  31 * query = {Name:["Peter", "Jane"]};
    -  32 * const result = data.filter(query).getColumn('Name').join(', ');
    -  33 *
    -  34 * m.mount(root, { 
    -  35 *   view:() => m('', [
    -  36 *       m('h3', 'Given the data set:'),
    -  37 *       m('table#data', [
    -  38 *           m('tr', colNames.map(n => m('th', n))),
    -  39 *           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    -  40 *       ]),
    -  41 *       m('h3', 'The query "{Name:["Peter", "Jane"]}" yields:'),
    -  42 *       m('', result)
    -  43 *   ])
    -  44 * });
    -  45 * 
    -  46 * 
    -  47 *   $exampleID { height: 600px; }
    -  48 *   #data th { width:15%; }
    -  49 * 
    -  50 *      
    -  51 */

    -  52
    -  53 /** */
    -  54
    -  55 
    -  56
    +   6 * *hsdatab* provides a JavaScript-based data management and query mechanism.
    +   7 * Data is managed in a simple in-memory database that holds data in rows of columns. 
    +   8 * It autodetermines the types of data held in each column, along with the 
    +   9 * domain range for each column of data. 
    +  10 * Complex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure. 
    +  11 * 
    +  12 * ## Data Types
    +  13 * supported {@link Data.Data.type data types} include
    +  14 * - **number**: numeric values
    +  15 * - **name**: nominal values, represented by arbitrary words
    +  16 * - **date**: date values
    +  17 * - **currency**: Currently supported: '$dd[,ddd]'
    +  18 * - **percent**: 'd%'
    +  19 * 
    +  20 * ## Data Class
    +  21 * The fundamental object in this library is {@link Data.Data `Data`}, 
    +  22 * a simple row-column based database object, 
    +  23 * featuring named columns, sorting, mapping and filtering functions.
    +  24 *
    +  25 * ## Example
    +  26 * 
    +  27 * 
    +  28 * const colNames = ['Name', 'Value', 'Start', 'End'];
    +  29 * const rows = [
    +  30 *   ['Harry', '100', '3/1/14', '11/20/14'], 
    +  31 *   ['Mary', '1500', '7/1/14',  '9/30/14'],
    +  32 *   ['Peter', '400', '5/20/14', '4/30/15'],  
    +  33 *   ['Jane', '700', '11/13/14', '8/15/15']
    +  34 * ]
    +  35 * const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  36 * 
    +  37 * query = {Name:["Peter", "Jane"]};
    +  38 * const result = data.filter(query);
    +  39 *
    +  40 * m.mount(root, {
    +  41 *   view:() => m('', [
    +  42 *       m('h3', 'Given the data set:'),
    +  43 *       m('pre',
    +  44 *       m('table#data', [
    +  45 *           m('tr', colNames.map(n => m('th', n))),
    +  46 *           ...rows.map(row => m('tr', [
    +  47 *              m('td', row[0]),
    +  48 *              m('td', row[1]),
    +  49 *              m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),
    +  50 *              m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)
    +  51 *          ]))
    +  52 *       ])),
    +  53 *       m('h3', 'The column types and domains are'),
    +  54 *       m('pre', m('table', 
    +  55 *                  m('tr', m('th', 'Column'),   m('th', 'Type'),   m('th', 'Domain')),
    +  56 *                  m('tr', m('td', '"Name":'),  m('td', data.colType("Name")),   m('td', data.findDomain("Name").join(', '))),
    +  57 *                  m('tr', m('td', '"Value":'), m('td', data.colType("Value")),  m('td', data.findDomain("Value").join(' - '))),
    +  58 *                  m('tr', m('td', '"Start":'), m('td', data.colType("Start")),  m('td', data.findDomain("Start").map(d => d.toDateString()).join(' - '))),
    +  59 *                  m('tr', m('td', '"Stop":'),  m('td', data.colType("End")),    m('td', data.findDomain("End").map(d => d.toDateString()).join(' - ')))
    +  60 *       )),
    +  61 *       m('h3', 'The query:'),
    +  62 *       m('code', '{Name:["Peter", "Jane"]}'),
    +  63 *       m('h3', 'yields results with "Name"'),
    +  64 *       m('code', result.getColumn('Name').join(', '))
    +  65 *   ])
    +  66 * });
    +  67 * 
    +  68 * 
    +  69 *   $exampleID { height: 600px; }
    +  70 *   #data th { width:15%; }
    +  71 *   #data  { font-size: 11pt; }
    +  72 * 
    +  73 *      
    +  74 */
    +  75
    +  76 /** */
    +  77
    +  78 
    +  79
    \ No newline at end of file From 466248ef90bc70b3bc6d4d70a1620a39780c12d1 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 16 Jun 2018 12:36:44 +0200 Subject: [PATCH 08/17] update --- docs/data/hsdatab.json | 3293 ---------------------------------------- src/Data.html | 568 +++++++ src/DataFilters.html | 267 ++++ src/index.html | 32 + src/overview.html | 96 ++ 5 files changed, 963 insertions(+), 3293 deletions(-) delete mode 100644 docs/data/hsdatab.json create mode 100644 src/Data.html create mode 100644 src/DataFilters.html create mode 100644 src/index.html create mode 100644 src/overview.html diff --git a/docs/data/hsdatab.json b/docs/data/hsdatab.json deleted file mode 100644 index a535f27..0000000 --- a/docs/data/hsdatab.json +++ /dev/null @@ -1,3293 +0,0 @@ -{ - "id": 0, - "name": "hsDatab", - "kind": 0, - "flags": {}, - "children": [ - { - "id": 42, - "name": "\"Data\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.ts", - "comment": {}, - "children": [ - { - "id": 56, - "name": "Data", - "kind": 128, - "kindString": "Class", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "# Data\nA simple in-memory database that holds data in rows of columns." - }, - "children": [ - { - "id": 67, - "name": "constructor", - "kind": 512, - "kindString": "Constructor", - "flags": { - "isExported": true - }, - "signatures": [ - { - "id": 68, - "name": "new Data", - "kind": 16384, - "kindString": "Constructor signature", - "flags": {}, - "parameters": [ - { - "id": 69, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 43 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 86, - "character": 5 - } - ] - }, - { - "id": 117, - "name": "data", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 392, - "character": 16 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - }, - "defaultValue": " []" - }, - { - "id": 118, - "name": "meta", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 393, - "character": 16 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "MetaStruct", - "id": 50 - } - }, - "defaultValue": " []" - }, - { - "id": 119, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 394, - "character": 16 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 134, - "name": "allRows", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 135, - "name": "allRows", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "A generator that provides the specified column value for each row in `Data` in sequence." - }, - "parameters": [ - { - "id": 136, - "name": "column", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "\n" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "reference", - "name": "Iterable", - "typeArguments": [ - { - "type": "reference", - "name": "DataVal", - "id": 151 - } - ] - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 493, - "character": 21 - } - ] - }, - { - "id": 104, - "name": "castData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 105, - "name": "castData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 260, - "character": 19 - } - ] - }, - { - "id": 141, - "name": "castVal", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 142, - "name": "castVal", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "The result of the cast.", - "tags": [ - { - "tag": "description", - "text": "Casts the sample to the specified data type.\n" - } - ] - }, - "parameters": [ - { - "id": 143, - "name": "type", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "The type to cast into. In case of _any_ - i.e. `type`\ndoes not match any of the previous keywords, no casting occurs." - }, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 144, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - ], - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 529, - "character": 19 - } - ] - }, - { - "id": 82, - "name": "colAdd", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 83, - "name": "colAdd", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "adds a new column to the data set. if `newCol` already exists,\nthe column index is returned withoput change.", - "returns": "the index for the new column\n" - }, - "parameters": [ - { - "id": 84, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the name of the new column" - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 140, - "character": 17 - } - ] - }, - { - "id": 85, - "name": "colInitialize", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 86, - "name": "colInitialize", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "initializes the specifed column with values, adding a new column if needed.\nIf `val`is a function, it is called as ```\nval(colValue:DataVal, rowIndex:number, row:DataRow)\n```" - }, - "parameters": [ - { - "id": 87, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the column to initialize" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - }, - { - "id": 88, - "name": "initializer", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the value to initialize with, or a function whose return\nvalue is used to initialize the column\n" - }, - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 162, - "character": 24 - } - ] - }, - { - "id": 92, - "name": "colName", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 93, - "name": "colName", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column name for the specified column.\n`col` can be either an index or a name.", - "returns": "the column name or `undefined`.\n" - }, - "parameters": [ - { - "id": 94, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 194, - "character": 18 - } - ] - }, - { - "id": 95, - "name": "colNames", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 96, - "name": "colNames", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the names for all columns.", - "returns": "an array of strings with the names.\n" - }, - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 205, - "character": 19 - } - ] - }, - { - "id": 89, - "name": "colNumber", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 90, - "name": "colNumber", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column index of the specified column.\n`col` can be either an index or a name.", - "returns": "the column number or `undefined`.\n" - }, - "parameters": [ - { - "id": 91, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 179, - "character": 20 - } - ] - }, - { - "id": 97, - "name": "colType", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 98, - "name": "colType", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column type for the specified column.\n`col` can be either an index or a name.", - "returns": "the column type.\n" - }, - "parameters": [ - { - "id": 99, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 215, - "character": 18 - } - ] - }, - { - "id": 75, - "name": "export", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 76, - "name": "export", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Exports to an object literal" - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 43 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 111, - "character": 17 - } - ] - }, - { - "id": 106, - "name": "filter", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 107, - "name": "filter", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "filters this data set and returns a new data set with a\nshallow copy of rows that pass the `condition`.\nSee {@link DataFilters DataFilters} for rules and examples on how to construct conditions.", - "returns": "a new Data object with rows that pass the filter\n" - }, - "parameters": [ - { - "id": 108, - "name": "condition", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "filters" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 9 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 277, - "character": 17 - } - ] - }, - { - "id": 100, - "name": "findDomain", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 101, - "name": "findDomain", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "modifies `domain` to include all values in column `col`.\nIf no `col` is specified, the range of data indexes is returned.", - "returns": "the updated domain\n" - }, - "parameters": [ - { - "id": 102, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the column name or index" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - }, - { - "id": 103, - "name": "domain", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the Domain range to update" - }, - "type": { - "type": "reference", - "name": "Domain", - "id": 149 - } - } - ], - "type": { - "type": "reference", - "name": "Domain", - "id": 149 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 227, - "character": 21 - } - ] - }, - { - "id": 131, - "name": "findType", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 132, - "name": "findType", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample\n", - "tags": [ - { - "tag": "description", - "text": "determines the data type. Supported types are\n```\n'date': sample represents a Date, either as a Date object or a String\n'number': sample represents a number\n'percent': sample represents a percentage (special case of a real number)\n'nominal': sample represents a nominal (ordinal or categorical) value\n```" - } - ] - }, - "parameters": [ - { - "id": 133, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the value to bve typed." - }, - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 462, - "character": 20 - } - ] - }, - { - "id": 128, - "name": "findTypes", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 129, - "name": "findTypes", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Determines the type of data in `col`. An array of counts is created for all\nencountered types, sorted by descending frequency. THe most likely type in position 0\nof the array is returned.", - "returns": "the most likely type of data in `col`.\n" - }, - "parameters": [ - { - "id": 130, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the index of the column to be typed." - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 430, - "character": 21 - } - ] - }, - { - "id": 79, - "name": "getColumn", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 80, - "name": "getColumn", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Returns the values in the specified column as a new array." - }, - "parameters": [ - { - "id": 81, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the column to return.\n" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 129, - "character": 20 - } - ] - }, - { - "id": 77, - "name": "getData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 78, - "name": "getData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the 2D array underlying the data base." - }, - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 121, - "character": 18 - } - ] - }, - { - "id": 120, - "name": "getMeta", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 121, - "name": "getMeta", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 122, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "reference", - "name": "MetaStruct", - "id": 50 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 396, - "character": 19 - } - ] - }, - { - "id": 70, - "name": "getName", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 71, - "name": "getName", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the `name` field for this data base, if any\n" - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 95, - "character": 18 - } - ] - }, - { - "id": 72, - "name": "import", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 73, - "name": "import", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Imports data from an object literal `data`" - }, - "parameters": [ - { - "id": 74, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data set to import\n" - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 43 - } - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 103, - "character": 17 - } - ] - }, - { - "id": 113, - "name": "map", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 114, - "name": "map", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": " Maps one or more columns in each rows of values based\non the result of the `mapFn`, which behaves similarly to the Array.map() method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the `mapFn` is passed the column arrays per row as parameter.\nThis allows for complex mapping combining conditions across multiple columns.\n```\ndata.map(function(values){\n values[1] = values[3] * values[5];\n return values;\n});\n```\nBe sure to return the `values` array as a result.\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `mapFn`, along with the row index and the entire row array. This allows for simple mapping.\n```\ndata.map('Price', function(value, i, values) {\n return value * 2;\n});\n```", - "returns": "a new Data object containing the mapping.\n" - }, - "parameters": [ - { - "id": 115, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data column, or columns, to apply the mapping to." - }, - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "ColumnReference", - "id": 150 - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ] - } - }, - { - "id": 116, - "name": "mapFn", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "a function to implement the mapping,\ncalled on each row of the data set in turn as `mapFn(val, i, c, rows)`, where\n- `val`: the column value in the current row\n- `c`: the column index in the current row\n- `i`: the row index\n- `rows`: the rows being iterated over\n` *\nfollows the same specifications as the function passed to Array.map().
    \nFor column mode, some predefined map functions can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.
    " - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "mapFn", - "id": 116 - } - ] - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 359, - "character": 14 - } - ] - }, - { - "id": 123, - "name": "setData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 124, - "name": "setData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "sets `data` to the existing data set. If data has previously been set,\n`data` will be added to the end of the list if all `names` match those of the\nexisting set." - }, - "parameters": [ - { - "id": 125, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data to add" - }, - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - } - }, - { - "id": 126, - "name": "names", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "an array of names that match the columns" - }, - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 127, - "name": "autoType", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "unless set to false, the method will attempt to determine the\ntype of data and automatically cast data points to their correct value\n" - }, - "type": { - "type": "intrinsic", - "name": "boolean" - }, - "defaultValue": "true" - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 412, - "character": 19 - } - ] - }, - { - "id": 109, - "name": "sort", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 110, - "name": "sort", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the Data object in order to allow for chaining.\n", - "tags": [ - { - "tag": "description", - "text": "Sorts the rows of values based on the result of the `sortFn`,\nwhich behaves similarly to the Array.sort method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the column arrays are passed as samples into the `sortFn`.\nThis allows for complex sorts, combining conditions across multiple columns.\n```\ndata.sort((row1, row2) => row1[5] - row2[5] );\n```\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `sortFn`. This allows filtering for simple conditions.
    \n**The specified column will be automatically cast prior to sorting**
    \n`data.sort('Date', function(val1, val2) { return val1 - val2; });`" - } - ] - }, - "parameters": [ - { - "id": 111, - "name": "sortFn", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "a function to implement the conditions,\nfollows the same specifications as the function passed to Array.sort().\nSome predefined sort function can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.
    " - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "sortFn", - "id": 111 - } - ] - } - }, - { - "id": 112, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the data column to use for sorting." - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 307, - "character": 15 - } - ] - }, - { - "id": 137, - "name": "toDate", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 138, - "name": "toDate", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "a new Date object parsed from `str`.", - "tags": [ - { - "tag": "description", - "text": "returns a new Date object parsed from `str` and corrects for a difference in\ninterpreting centuries between webkit and mozilla in converting strings to Dates:\nThe string \"15/7/03\" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.\nIf `limitYear` is not specified this method uses 1970 as the decision date:\nyears 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.\n" - } - ] - }, - "parameters": [ - { - "id": 139, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the string to convert to a date" - }, - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - }, - { - "id": 140, - "name": "limitYear", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the year below which the century is corrected. Defaults to 1970." - }, - "type": { - "type": "intrinsic", - "name": "number" - }, - "defaultValue": "1970" - } - ], - "type": { - "type": "reference", - "name": "Date" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 510, - "character": 18 - } - ] - }, - { - "id": 63, - "name": "toDataSet", - "kind": 2048, - "kindString": "Method", - "flags": { - "isStatic": true, - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 64, - "name": "toDataSet", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 65, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataLiteralSet", - "id": 153 - } - }, - { - "id": 66, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "reference", - "name": "DataSet", - "id": 43 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 80, - "character": 27 - } - ] - }, - { - "id": 57, - "name": "type", - "kind": 2097152, - "kindString": "Object literal", - "flags": { - "isStatic": true, - "isExported": true, - "isPublic": true - }, - "children": [ - { - "id": 61, - "name": "currency", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "currency values. Currently support6ed are values ofg the format '$dd[,ddd]'" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 74, - "character": 16 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"currency\"" - }, - { - "id": 60, - "name": "date", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "date values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 72, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"date\"" - }, - { - "id": 59, - "name": "name", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "nominal values, represented by arbitrary words" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 70, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"name\"" - }, - { - "id": 58, - "name": "number", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "numeric values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 68, - "character": 14 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"number\"" - }, - { - "id": 62, - "name": "percent", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "percent values: 'd%'" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 76, - "character": 15 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"percent\"" - } - ], - "groups": [ - { - "title": "Variables", - "kind": 32, - "children": [ - 61, - 60, - 59, - 58, - 62 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 66, - "character": 22 - } - ], - "type": { - "type": "intrinsic", - "name": "object" - } - } - ], - "groups": [ - { - "title": "Constructors", - "kind": 512, - "children": [ - 67 - ] - }, - { - "title": "Properties", - "kind": 1024, - "children": [ - 117, - 118, - 119 - ] - }, - { - "title": "Methods", - "kind": 2048, - "children": [ - 134, - 104, - 141, - 82, - 85, - 92, - 95, - 89, - 97, - 75, - 106, - 100, - 131, - 128, - 79, - 77, - 120, - 70, - 72, - 113, - 123, - 109, - 137, - 63 - ] - }, - { - "title": "Object literals", - "kind": 2097152, - "children": [ - 57 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 62, - "character": 17 - } - ] - }, - { - "id": 43, - "name": "DataSet", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a JSON format data set, using arrays of names and rows" - }, - "children": [ - { - "id": 45, - "name": "colNames", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "an array of column names. Each name matches the column with the same index in DataRow" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 36, - "character": 12 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 44, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "comment": { - "shortText": "an optional name for the data set" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 34, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 46, - "name": "rows", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "rows of data" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 38, - "character": 8 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 45, - 44, - 46 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 32, - "character": 24 - } - ] - }, - { - "id": 50, - "name": "MetaStruct", - "kind": 256, - "kindString": "Interface", - "flags": {}, - "children": [ - { - "id": 53, - "name": "accessed", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 49, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - }, - { - "id": 54, - "name": "cast", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 50, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - }, - { - "id": 52, - "name": "column", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 48, - "character": 10 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 51, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 47, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 55, - "name": "types", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 51, - "character": 9 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "TypeStruct", - "id": 47 - } - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 53, - 54, - 52, - 51, - 55 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 46, - "character": 20 - } - ] - }, - { - "id": 47, - "name": "TypeStruct", - "kind": 256, - "kindString": "Interface", - "flags": {}, - "children": [ - { - "id": 49, - "name": "count", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 42 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 48, - "name": "type", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 27 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 49, - 48 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 20 - } - ] - }, - { - "id": 150, - "name": "ColumnReference", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 23, - "character": 27 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "string" - } - ] - } - }, - { - "id": 153, - "name": "DataLiteralSet", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a JSON format data set, using an array of {name:value, ...} literals" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 42, - "character": 26 - } - ], - "type": { - "type": "reference", - "name": "Array", - "typeArguments": [ - { - "type": "intrinsic", - "name": "any" - } - ] - } - }, - { - "id": 152, - "name": "DataRow", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a single row of column values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 29, - "character": 19 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - }, - { - "id": 151, - "name": "DataVal", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a generic data value type, used in the {@link Data.DataRow `DataRow`} array" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 26, - "character": 19 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "Date" - } - ] - } - }, - { - "id": 147, - "name": "DateDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a Date domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 14, - "character": 22 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "reference", - "name": "Date" - }, - { - "type": "reference", - "name": "Date" - } - ] - } - }, - { - "id": 149, - "name": "Domain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a generic domain that can be any of the typed domains." - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 20, - "character": 18 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "NumDomain", - "id": 146 - }, - { - "type": "reference", - "name": "DateDomain", - "id": 147 - }, - { - "type": "reference", - "name": "NameDomain", - "id": 148 - } - ] - } - }, - { - "id": 148, - "name": "NameDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a categorical domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 17, - "character": 22 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 146, - "name": "NumDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a numeric domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 11, - "character": 21 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "number" - } - ] - } - }, - { - "id": 145, - "name": "NumRange", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a [min-max] range" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 8, - "character": 20 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "number" - } - ] - } - }, - { - "id": 159, - "name": "mapFn", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 55, - "character": 17 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 160, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 161, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 162, - "name": "colVal", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 163, - "name": "colIndex", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 164, - "name": "rowIndex", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 165, - "name": "rows", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "array", - "elementType": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "any" - } - } - } - } - ], - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 55, - "character": 20 - } - ] - } - } - }, - { - "id": 154, - "name": "sortFn", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 54, - "character": 18 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 155, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 156, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 157, - "name": "x", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 158, - "name": "y", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 54, - "character": 20 - } - ] - } - } - } - ], - "groups": [ - { - "title": "Classes", - "kind": 128, - "children": [ - 56 - ] - }, - { - "title": "Interfaces", - "kind": 256, - "children": [ - 43, - 50, - 47 - ] - }, - { - "title": "Type aliases", - "kind": 4194304, - "children": [ - 150, - 153, - 152, - 151, - 147, - 149, - 148, - 146, - 145, - 159, - 154 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 1, - "name": "\"DataFilters\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/DataFilters.ts", - "comment": { - "shortText": "Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object.\nEach row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object.", - "text": "# Condition construction\n\n### General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n### IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n### RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n### Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" - }, - "children": [ - { - "id": 2, - "name": "SetAndCondition", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "children": [ - { - "id": 4, - "name": "and", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 140, - "character": 7 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 11 - } - }, - { - "id": 5, - "name": "not", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 141, - "character": 7 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 11 - } - }, - { - "id": 3, - "name": "or", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 139, - "character": 6 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 11 - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 4, - 5, - 3 - ] - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 138, - "character": 32 - } - ] - }, - { - "id": 6, - "name": "TermAndCondition", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "indexSignature": [ - { - "id": 7, - "name": "__index", - "kind": 8192, - "kindString": "Index signature", - "flags": {}, - "parameters": [ - { - "id": 8, - "name": "colDesc", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "DataVal", - "id": 151 - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - }, - { - "type": "reference", - "name": "TermConditionFunction", - "id": 14 - } - ] - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 144, - "character": 33 - } - ] - }, - { - "id": 13, - "name": "AndCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 136, - "character": 24 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "SetAndCondition", - "id": 2 - }, - { - "type": "reference", - "name": "TermAndCondition", - "id": 6 - } - ] - } - }, - { - "id": 9, - "name": "Condition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 129, - "character": 21 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "IndexCondition", - "id": 10 - }, - { - "type": "reference", - "name": "RecursiveCondition", - "id": 11 - } - ] - } - }, - { - "id": 10, - "name": "IndexCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "true if row index matches the number(s)" - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 132, - "character": 26 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 12, - "name": "OrCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 135, - "character": 23 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "array", - "elementType": { - "type": "reference", - "name": "AndCondition", - "id": 13 - } - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "IndexCondition", - "id": 10 - } - } - ] - } - }, - { - "id": 11, - "name": "RecursiveCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 134, - "character": 30 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "AndCondition", - "id": 13 - }, - { - "type": "reference", - "name": "OrCondition", - "id": 12 - } - ] - } - }, - { - "id": 14, - "name": "TermConditionFunction", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 152, - "character": 33 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 15, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 16, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 17, - "name": "value", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - }, - { - "id": 18, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 152, - "character": 35 - } - ] - } - } - }, - { - "id": 38, - "name": "filter", - "kind": 64, - "kindString": "Function", - "flags": { - "isExported": true - }, - "signatures": [ - { - "id": 39, - "name": "filter", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which\n`cond` holds true.", - "returns": "a new `Data` object with the filtered rows\n" - }, - "parameters": [ - { - "id": 40, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the `Data` object to filter" - }, - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - }, - { - "id": 41, - "name": "cond", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the complex condition to test against" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 9 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 234, - "character": 22 - } - ] - }, - { - "id": 28, - "name": "resolveCondition", - "kind": 64, - "kindString": "Function", - "flags": {}, - "signatures": [ - { - "id": 29, - "name": "resolveCondition", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "applies `condition` to a row of data and returns `true` if the row passes." - }, - "parameters": [ - { - "id": 30, - "name": "condition", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the complex condition to test against" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 9 - } - }, - { - "id": 31, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the row values" - }, - "type": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - }, - { - "id": 32, - "name": "r", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the row index in the data set" - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 33, - "name": "colNumber", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reflection", - "declaration": { - "id": 34, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 35, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 36, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 181, - "character": 80 - } - ] - } - } - }, - { - "id": 37, - "name": "and", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "\n" - }, - "type": { - "type": "intrinsic", - "name": "boolean" - }, - "defaultValue": "true" - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 181, - "character": 25 - } - ] - }, - { - "id": 19, - "name": "resolveTerminalCondition", - "kind": 64, - "kindString": "Function", - "flags": {}, - "signatures": [ - { - "id": 20, - "name": "resolveTerminalCondition", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 21, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 22, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 23, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - }, - { - "id": 24, - "name": "colNumber", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reflection", - "declaration": { - "id": 25, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 26, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 27, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 155, - "character": 79 - } - ] - } - } - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 155, - "character": 33 - } - ] - } - ], - "groups": [ - { - "title": "Interfaces", - "kind": 256, - "children": [ - 2, - 6 - ] - }, - { - "title": "Type aliases", - "kind": 4194304, - "children": [ - 13, - 9, - 10, - 12, - 11, - 14 - ] - }, - { - "title": "Functions", - "kind": 64, - "children": [ - 38, - 28, - 19 - ] - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 166, - "name": "\"index\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/index.ts", - "sources": [ - { - "fileName": "index.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 167, - "name": "\"overview\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", - "comment": { - "shortText": "# hsDatab", - "text": "Helpful Scripts framework-independent data management functions.\n\n*hsdatab* provides a JavaScript-based data management and query mechanism.\nData is managed in a simple in-memory database that holds data in rows of columns.\nIt autodetermines the types of data held in each column, along with the\ndomain range for each column of data.\nComplex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure.\n\n## Data Types\nsupported {@link Data.Data.type data types} include\n- **number**: numeric values\n- **name**: nominal values, represented by arbitrary words\n- **date**: date values\n- **currency**: Currently supported: '$dd[,ddd]'\n- **percent**: 'd%'\n\n## Data Class\nThe fundamental object in this library is {@link Data.Data `Data`},\na simple row-column based database object,\nfeaturing named columns, sorting, mapping and filtering functions.\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query);\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('pre',\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [\n m('td', row[0]),\n m('td', row[1]),\n m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),\n m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)\n ]))\n ])),\n m('h3', 'The column types and domains are'),\n m('pre', m('table',\n m('tr', m('th', 'Column'), m('th', 'Type'), m('th', 'Domain')),\n m('tr', m('td', '\"Name\":'), m('td', data.colType(\"Name\")), m('td', data.findDomain(\"Name\").join(', '))),\n m('tr', m('td', '\"Value\":'), m('td', data.colType(\"Value\")), m('td', data.findDomain(\"Value\").join(' - '))),\n m('tr', m('td', '\"Start\":'), m('td', data.colType(\"Start\")), m('td', data.findDomain(\"Start\").map(d => d.toDateString()).join(' - '))),\n m('tr', m('td', '\"Stop\":'), m('td', data.colType(\"End\")), m('td', data.findDomain(\"End\").map(d => d.toDateString()).join(' - ')))\n )),\n m('h3', 'The query:'),\n m('code', '{Name:[\"Peter\", \"Jane\"]}'),\n m('h3', 'yields results with \"Name\"'),\n m('code', result.getColumn('Name').join(', '))\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n #data { font-size: 11pt; }\n\n\n" - }, - "sources": [ - { - "fileName": "overview.ts", - "line": 1, - "character": 0 - } - ] - } - ], - "groups": [ - { - "title": "External modules", - "kind": 1, - "children": [ - 42, - 1, - 166, - 167 - ] - } - ] -} \ No newline at end of file diff --git a/src/Data.html b/src/Data.html new file mode 100644 index 0000000..d2b7bfa --- /dev/null +++ b/src/Data.html @@ -0,0 +1,568 @@ + + +

    Data.ts

    +
       1/**
    +   2 */

    +   3
    +   4 /** */
    +   5import { Condition, filter } from './DataFilters';
    +   6
    +   7/** defines a [min-max] range */
    +   8export type NumRange = [number, number];
    +   9
    +  10/** defines a numeric domain that includes all values of a column */
    +  11export type NumDomain = [number, number];
    +  12
    +  13/** defines a Date domain that includes all values of a column */
    +  14export type DateDomain = [Date, Date];
    +  15
    +  16/** defines a categorical domain that includes all values of a column */
    +  17export type NameDomain = string[];
    +  18
    +  19/** defines a generic domain that can be any of the typed domains. */
    +  20export type Domain = NumDomain | DateDomain | NameDomain;
    +  21
    +  22/** defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    +  23export type ColumnReference = number|string;
    +  24
    +  25/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    +  26export type DataVal = number|string|Date;
    +  27
    +  28/** a single row of column values */
    +  29export type DataRow = DataVal[];
    +  30
    +  31/** a JSON format data set, using arrays of names and rows */
    +  32export interface DataSet {
    +  33    /** an optional name for the data set */
    +  34    name?:  string;
    +  35    /** an array of column names. Each name matches the column with the same index in DataRow */
    +  36    colNames:  string[];   
    +  37    /** rows of data */
    +  38    rows:   DataRow[];
    +  39}
    +  40
    +  41/** a JSON format data set, using an array of {name:value, ...} literals*/
    +  42export type DataLiteralSet = Array;
    +  43
    +  44interface TypeStruct { type: string; count: number;};
    +  45
    +  46interface MetaStruct {
    +  47    name:       string;         // column name
    +  48    column:     number;         // column index
    +  49    accessed:   boolean;        // has column data been accessed?
    +  50    cast:       boolean;        // has column data been cast 
    +  51    types:      TypeStruct[];   // data types, sorted by likelihood
    +  52}
    +  53
    +  54export type sortFn = (x:any, y:any) => number;
    +  55export type mapFn  = (colVal:any, colIndex?:number, rowIndex?:number, rows?:any[][]) => any;
    +  56
    +  57/**
    +  58 * # Data
    +  59 * A simple in-memory database that holds data in rows of columns.
    +  60 * 
    +  61 */

    +  62export class Data {
    +  63    //----------------------------
    +  64    // public part
    +  65    //----------------------------
    +  66    public static type = {
    +  67        /** numeric values */
    +  68        number:     'number',
    +  69        /** nominal values, represented by arbitrary words */
    +  70        name:       'name',
    +  71        /** date values */
    +  72        date:       'date',
    +  73        /** currency values. Currently support6ed are values ofg the format '$dd[,ddd]' */
    +  74        currency:   'currency',
    +  75        /** percent values: 'd%' */
    +  76        percent:    'percent',
    +  77//        nominal:    'nominal'
    +  78    };
    +  79
    +  80    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    +  81        data = data || [{}];
    +  82        const names = Object.keys(data[0]);
    +  83        const rows = data.map((r:any) => 
    +  84            names.map((n:string) => r[n]));
    +  85        return { rows:rows, colNames:names, name:name||undefined };
    +  86    }
    +  87
    +  88    constructor(data?:DataSet) {
    +  89        this.import(data);
    +  90    }
    +  91
    +  92    /**
    +  93     * @return the `name` field for this data base, if any
    +  94     */

    +  95    public getName():string {
    +  96        return this.name;
    +  97    }
    +  98
    +  99    /**
    + 100     * Imports data from an object literal `data`
    + 101     * @param data the data set to import
    + 102     */

    + 103    public import(data:DataSet) {
    + 104        this.name = data.name;
    + 105        this.setData(data.rows, data.colNames);
    + 106    }
    + 107
    + 108    /**
    + 109     * Exports to an object literal
    + 110     */

    + 111    public export():DataSet {
    + 112        return {
    + 113            rows: this.getData(),
    + 114            colNames:this.colNames()
    + 115        };
    + 116    }
    + 117
    + 118    /**
    + 119     * returns the 2D array underlying the data base.
    + 120     */

    + 121    public getData():DataRow[] {
    + 122        return this.data;
    + 123    }
    + 124
    + 125    /**
    + 126     * Returns the values in the specified column as a new array.
    + 127     * @param col the column to return.
    + 128     */

    + 129    public getColumn(col:ColumnReference): DataVal[] {
    + 130        const cn = this.colNumber(col);
    + 131        return this.data.map((row:DataRow) => row[cn]);
    + 132    }
    + 133
    + 134    /**
    + 135     * adds a new column to the data set. if `newCol` already exists, 
    + 136     * the column index is returned withoput change.
    + 137     * @param col the name of the new column
    + 138     * @return the index for the new column
    + 139     */

    + 140    public colAdd(col:string):number {
    + 141        let m = this.getMeta(col);
    + 142        if (m === undefined) { 
    + 143            m = this.meta[col] = {};
    + 144            m.name   = col; 
    + 145            m.column = this.meta.length;
    + 146            this.meta.push(m);      // access name by both column name and index
    + 147            m.cast     = false;         // has not been cast yet
    + 148            m.accessed = false;         // has not been accessed yet
    + 149        }
    + 150        return m.column;
    + 151    }
    + 152
    + 153    /**
    + 154     * initializes the specifed column with values, adding a new column if needed. 
    + 155     * If `val`is a function, it is called as ```
    + 156     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    + 157     * ```
    + 158     * @param col the column to initialize
    + 159     * @param initializer the value to initialize with, or a function whose return
    + 160     * value is used to initialize the column
    + 161     */

    + 162    public colInitialize(col:ColumnReference, initializer:any) {
    + 163        const cn = this.colNumber(col);
    + 164        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    + 165        const fn = typeof initializer === 'function';
    + 166        if (cn!==undefined) {
    + 167            this.data.map((r:DataRow, i:number) =>
    + 168                r[cn] = fn? initializer(r[cn], i, r) : initializer
    + 169            );
    + 170        }
    + 171    }
    + 172
    + 173    /**
    + 174     * returns the column index of the specified column. 
    + 175     * `col` can be either an index or a name.
    + 176     * @param column the data column, name or index, for which to return the index. 
    + 177     * @return the column number or `undefined`.
    + 178     */

    + 179    public colNumber(col:ColumnReference) {
    + 180        const m = this.getMeta(col);
    + 181        if (!m) { return undefined; }
    + 182        else {
    + 183            m.accessed = true; 
    + 184            return m.column; 
    + 185        }
    + 186    }
    + 187    
    + 188    /**
    + 189     * returns the column name for the specified column. 
    + 190     * `col` can be either an index or a name.
    + 191     * @param column the data column, name or index. 
    + 192     * @return the column name or `undefined`.
    + 193     */

    + 194    public colName(col:ColumnReference) {
    + 195        var m = this.getMeta(col);
    + 196        if (!m) { return undefined; }
    + 197        m.accessed = true; 
    + 198        return m.name; 
    + 199    }
    + 200
    + 201    /**
    + 202     * returns the names for all columns. 
    + 203     * @return an array of strings with the names.
    + 204     */

    + 205    public colNames():string[] {
    + 206        return this.meta.map((m:MetaStruct) => m.name); 
    + 207    }
    + 208
    + 209    /**
    + 210     * returns the column type for the specified column. 
    + 211     * `col` can be either an index or a name.
    + 212     * @param column the data column, name or index. 
    + 213     * @return the column type.
    + 214     */

    + 215    public colType(col:ColumnReference) { 
    + 216        const meta = this.getMeta(col);
    + 217        return meta? meta.types[0].type : Data.type.name;
    + 218    }
    + 219
    + 220    /**
    + 221     * modifies `domain` to include all values in column `col`.
    + 222     * If no `col` is specified, the range of data indexes is returned.
    + 223     * @param col optional; the column name or index 
    + 224     * @param domain optional; the Domain range to update
    + 225     * @return the updated domain
    + 226     */

    + 227    public findDomain(col?:ColumnReference, domain?:Domain):Domain {
    + 228        if (domain===undefined) { domain = []; }
    + 229        if (col === undefined) { // use array index as domain
    + 230            domain[0] = 0;
    + 231            domain[1] = this.data.length-1;
    + 232        } else {
    + 233            const c = this.colNumber(col);
    + 234            const type = this.colType(col);
    + 235            if (this.data === undefined) {
    + 236                console.log('no data'); 
    + 237            }
    + 238            switch(type) {
    + 239                case Data.type.name: 
    + 240                    this.data.forEach((r:DataRow) => {
    + 241                        const nomDom = domain;
    + 242                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    + 243                    });
    + 244                    break;
    + 245                default: 
    + 246                    this.data.forEach((r:DataRow) => {
    + 247                        let v:number = r[c];
    + 248                        if (domain[0]===undefined) { domain[0] = v; }
    + 249                        if (domain[1]===undefined) { domain[1] = v; }
    + 250                        if (v!==undefined && v!==null) {
    + 251                            if (v + 252                            else if (v>domain[1]) { domain[1] = v; }
    + 253                        }
    + 254                    });
    + 255            }
    + 256        }
    + 257        return domain;
    + 258    }
    + 259
    + 260    public castData() {
    + 261        this.meta.forEach((c:MetaStruct) => {
    + 262            const col = c.column;
    + 263            if (!c.cast) {
    + 264                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    + 265            }
    + 266            c.cast = true;
    + 267        });
    + 268    }
    + 269
    + 270    /**
    + 271     * filters this data set and returns a new data set with a 
    + 272     * shallow copy of rows that pass the `condition`.
    + 273     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    + 274     * @param condition filters 
    + 275     * @return a new Data object with rows that pass the filter
    + 276     */

    + 277    public filter(condition:Condition):Data {
    + 278        return filter(this, condition);
    + 279    }
    + 280
    + 281    /**
    + 282     * @description Sorts the rows of values based on the result of the `sortFn`, 
    + 283     * which behaves similarly to the Array.sort method.  
    + 284     * Two modes are supported:
    + 285     * # Array Mode
    + 286     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    + 287     * This allows for complex sorts, combining conditions across multiple columns.
    + 288     * ```
    + 289     * data.sort((row1, row2) => row1[5] - row2[5] );
    + 290     * ```
    + 291     * # Column mode
    + 292     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 293     * into `sortFn`. This allows filtering for simple conditions.

    + 294     * **The specified column will be automatically cast prior to sorting**

    + 295     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    + 296     * @param col optional; the data column to use for sorting. 
    + 297     * @param sortFn a function to implement the conditions, 
    + 298     * follows the same specifications as the function passed to Array.sort(). 
    + 299     * Some predefined sort function can be invoked by providing a 
    + 300     * respective string instead of a function. The following functions are defined:
    + 301        
    + 302        
    + 303        
    + 304        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    + 305     * @return the Data object in order to allow for chaining.
    + 306     */

    + 307    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    + 308        let fn = sortFn;
    + 309        if (!col) {
    + 310            this.data.sort(fn);
    + 311        } else {
    + 312            col = this.colNumber(col);
    + 313            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b + 314            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    + 315            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    + 316        }
    + 317        return this;
    + 318    }
    + 319
    + 320    /** 
    + 321    *  Maps one or more columns in each rows of values based 
    + 322     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    + 323     * Two modes are supported:
    + 324     * # Array Mode
    + 325     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    + 326     * This allows for complex mapping combining conditions across multiple columns.
    + 327     * ```
    + 328     * data.map(function(values){ 
    + 329     *    values[1] = values[3] * values[5]; 
    + 330     *    return values; 
    + 331     * });
    + 332     * ```
    + 333     * Be sure to return the `values` array as a result.
    + 334     * # Column mode
    + 335     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 336     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    + 337     * ```
    + 338     * data.map('Price', function(value, i, values) { 
    + 339     *    return value * 2; 
    + 340     * });
    + 341     * ```
    + 342     * @param col the data column, or columns, to apply the mapping to. 
    + 343     * @param mapFn a function to implement the mapping,
    + 344     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    + 345     * - `val`: the column value in the current row
    + 346     * - `c`: the column index in the current row
    + 347     * - `i`: the row index 
    + 348     * - `rows`: the rows being iterated over
    + 349`    * 
    + 350     * follows the same specifications as the function passed to Array.map().

    + 351     * For column mode, some predefined map functions can be invoked by providing a 
    + 352     * respective string instead of a function. The following functions are defined:
    + 353        
    + 354        
    + 355        
    + 356        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    + 357     * @return a new Data object containing the mapping.
    + 358     */

    + 359    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    + 360        const noop = (val:any) => val;
    + 361        const cumulate = () => { 
    + 362            let sum=0; 
    + 363            return (val:number, i:number) => { sum += +val; return sum; };
    + 364        };
    + 365        function getFn() {
    + 366            let fn; // define fn inside each col loop to ensure initialization
    + 367            switch (mapFn) {
    + 368                case 'cumulate': fn = cumulate(); break;
    + 369                case 'noop':     fn = noop; break;
    + 370                default:         fn = mapFn;
    + 371            }
    + 372            return fn;
    + 373        }
    + 374
    + 375        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    + 376
    + 377        const names = col['length']? col : [col];            
    + 378        names.map((cn:ColumnReference) => {
    + 379            const c = this.colNumber(cn);
    + 380            let fn = getFn(); // define fn inside each col loop to ensure initialization
    + 381            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    + 382                row[c] = fn(row[c], c, i, rows); 
    + 383                return row;
    + 384            });
    + 385        });
    + 386        return result;
    + 387    }
    + 388
    + 389    //----------------------------
    + 390    // private part
    + 391    //----------------------------
    + 392    private data: DataRow[]    = [];
    + 393    private meta: MetaStruct[] = [];
    + 394    private name: string;
    + 395
    + 396    private getMeta(col:ColumnReference):MetaStruct { 
    + 397        if (!this.meta) { this.meta = []; }
    + 398        if (!this.meta[col]) { return undefined; }
    + 399        this.meta[col].accessed = true;
    + 400        return this.meta[col]; 
    + 401    }
    + 402
    + 403    /**
    + 404     * sets `data` to the existing data set. If data has previously been set, 
    + 405     * `data` will be added to the end of the list if all `names`  match those of the 
    + 406     * existing set. 
    + 407     * @param data the data to add
    + 408     * @param names an array of names that match the columns
    + 409     * @param autoType unless set to false, the method will attempt to determine the 
    + 410     * type of data and automatically cast data points to their correct value
    + 411     */

    + 412    private setData(data:DataRow[], names:string[], autoType=true):void {
    + 413        this.meta = [];
    + 414        this.data = data;
    + 415        if (!names) {
    + 416            console.log();
    + 417        }
    + 418        names.forEach((col:string) => this.colAdd(col));
    + 419        names.forEach((col:string) => this.findTypes(col));
    + 420        this.castData();
    + 421    }
    + 422
    + 423    /**
    + 424     * Determines the type of data in `col`. An array of counts is created for all
    + 425     * encountered types, sorted by descending frequency. THe most likely type in position 0
    + 426     * of the array is returned.
    + 427     * @param col the index of the column to be typed. 
    + 428     * @return the most likely type of data in `col`.
    + 429     */

    + 430    private findTypes(col:ColumnReference):string {
    + 431        const m = this.getMeta(col);
    + 432        const types:TypeStruct[] = [];
    + 433        Object.keys(Data.type).forEach((t:string) => {
    + 434            const ts = { type: Data.type[t], count: 0 }; 
    + 435            types.push(ts);
    + 436            types[Data.type[t]] = ts;
    + 437        });
    + 438        for (let v of this.allRows(col)) {
    + 439            const t = this.findType(v);
    + 440            if (t !== null) { types[t].count++; }
    + 441        }
    + 442        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    + 443            if (a.type==='currency'&&a.count>0) { return -1; }
    + 444            if (b.type==='currency'&&b.count>0) { return 1; }
    + 445            return b.count - a.count;
    + 446        });
    + 447        m.types = types;
    + 448        return types[0].type;
    + 449    }
    + 450
    + 451    /**
    + 452     * @description determines the data type. Supported types are 
    + 453     * ```
    + 454     * 'date':    sample represents a Date, either as a Date object or a String 
    + 455     * 'number':  sample represents a number
    + 456     * 'percent': sample represents a percentage (special case of a real number)
    + 457     * 'nominal': sample represents a nominal (ordinal or categorical) value
    + 458     * ```
    + 459     * @param val the value to bve typed.
    + 460     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    + 461     */

    + 462    private findType(val:DataVal) {
    + 463        if (val && val!=='') {
    + 464            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    + 465            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    + 466
    + 467            // else: val is a string:
    + 468            const strVal = ''+val;
    + 469            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    + 470            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    + 471            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    + 472            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    + 473
    + 474            // european large number currency representation: '$dd[,ddd]'
    + 475            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    + 476                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    + 477                    return Data.type.currency; 
    + 478                }
    + 479            }
    + 480            switch (strVal.toLowerCase()) {
    + 481                case "null": break;
    + 482                case "#ref!": break;
    + 483                default: if (val.length>0) { return Data.type.name; }
    + 484            }
    + 485        }
    + 486        return null;
    + 487    }    
    + 488
    + 489    /**
    + 490     * A generator that provides the specified column value for each row in `Data` in sequence. 
    + 491     * @param column 
    + 492     */

    + 493    private * allRows(column:ColumnReference):Iterable {
    + 494        const c = this.colNumber(column);
    + 495        for (let r=0; r + 496            yield this.data[r][c];
    + 497        }
    + 498    }
    + 499
    + 500    /**
    + 501     * @param val the string to convert to a date
    + 502     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    + 503     * @returns a new Date object parsed from `str`.
    + 504     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    + 505     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    + 506     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    + 507     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    + 508     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    + 509     */

    + 510    private toDate(val:DataVal, limitYear=1970):Date {
    + 511        let d:Date;
    + 512        if (val instanceof Date) { d = val; }
    + 513                            else { d = new Date(val); }   
    + 514        let yr=d.getFullYear();
    + 515        if (yr < 100) { 
    + 516            yr += 1900; 
    + 517            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    + 518        }
    + 519        return d;
    + 520    }
    + 521
    + 522    /**
    + 523     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    + 524     * does not match any of the previous keywords, no casting occurs.
    + 525     * @param sample The value to cast.
    + 526     * @returns The result of the cast. 
    + 527     * @description Casts the sample to the specified data type.
    + 528     */

    + 529    private castVal(type:string, val:DataVal):DataVal {
    + 530        switch (type) {
    + 531            case Data.type.date:    if (val instanceof Date) { return val; }
    + 532                            val = this.toDate(val);
    + 533                            if (isNaN(val.getTime())) { val = null; }
    + 534                            break;
    + 535            case Data.type.percent: if (typeof val === 'string') {
    + 536                                const num = parseFloat(val);
    + 537                                val = (val).endsWith('%')? num/100 : num;
    + 538                            } 
    + 539                            if (isNaN(val)) { val = null; }
    + 540                            break;
    + 541            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    + 542             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    + 543             /* falls through */
    + 544            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    + 545                            if (isNaN(val)) { val = null; }
    + 546                            break;
    + 547            default:        val = ''+val;
    + 548        }
    + 549        return val;
    + 550     }     
    + 551}
    + + \ No newline at end of file diff --git a/src/DataFilters.html b/src/DataFilters.html new file mode 100644 index 0000000..cd063c1 --- /dev/null +++ b/src/DataFilters.html @@ -0,0 +1,267 @@ + + +

    DataFilters.ts

    +
       1
    +   2/**
    +   3* Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object. 
    +   4* Each row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object. 
    +   5
    +   6* # Condition construction
    +   7*  
    +   8* ### General Condition
    +   9* ```
    +  10* Condition = 
    +  11*    IndexCondition            -> conditions on the row index
    +  12* || RecursiveCondition        -> (set of) conditions on column values
    +  13* ```
    +  14
    +  15* ### IndexCondition
    +  16* ```
    +  17* IndexCondition =
    +  18*    rowIndex:number           -> true if row index matches
    +  19* ```
    +  20
    +  21* ### RecursiveCondition
    +  22* ```
    +  23* RecursiveCondition =
    +  24*    OrCondition               -> OR: true if any compound condition is true
    +  25* || AndCondition              -> AND: true if all compound conditions are true
    +  26
    +  27* OrCondition =                -> OR: true if
    +  28*    AndCondition[]               -> any of the AndConditions are true
    +  29* || IndexCondition[]             -> any of thr IndexConditions are true
    +  30
    +  31* AndCondition =               -> AND: true if
    +  32*    SetAndCondition              -> all SetAndConditions are true
    +  33* || TermAndCondition             -> or if all TermAndConditions are true
    +  34*
    +  35* SetAndCondition = {          -> AND: true if all sub-conditions are true
    +  36*    'or':  RecursiveCondition    -> true if any RecursiveCondition is true
    +  37* || 'and': RecursiveCondition    -> true if all RecursiveCondition are true
    +  38* || 'not': RecursiveCondition    -> true if the condition is false
    +  39*
    +  40* TermAndCondition = {         -> Terminal AND: true if all terminal sub-conditions are true
    +  41*    colDesc:colValue             -> true if colValue matches 
    +  42* || colDesc:[colValue, ...]      -> true if any of the colValues match
    +  43* || colDesc:function(value,row)  -> true if function returns true 
    +  44* }
    +  45
    +  46* colDesc = either column name or index
    +  47* ```
    +  48
    +  49* ### Practical Tips
    +  50* ```
    +  51*    {'or': [recurCond, ...]}    -> OR, same as [recurCond, ...]
    +  52* || {'or': {SetCond, ...}}      -> OR, same as [SetCond, ...]
    +  53* || {'and': [recurCond, ...]}   -> AND, true if all recurCond are true
    +  54* || {'and': {SetCond, ...}}     -> AND, same as {SetCond, ...}
    +  55* || {'not': {SetCond, ...}}     -> NAND: true if the SetCond are true
    +  56* || {'not': [recurCond, ...]}   -> NOR: true if any of the recurCond are true
    +  57* ```
    +  58*      
    +  59* # Example
    +  60
    +  61
    +  62* const colNames = ['Name', 'Value', 'Start', 'End'];
    +  63* const rows = [
    +  64*   ['Harry', '100', '3/1/14', '11/20/14'], 
    +  65*   ['Mary', '1500', '7/1/14',  '9/30/14'],
    +  66*   ['Peter', '400', '5/20/14', '4/30/15'],  
    +  67*   ['Jane', '700', '11/13/14', '8/15/15']
    +  68* ]
    +  69* const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  70
    +  71* queries = [
    +  72*   ['0', undefined,                           'undefined query => pass all'],
    +  73*   ['1', [],                                  'empty OR:  []   => fail all'],
    +  74*   ['2', {},                                  'empty AND: {}   => pass all'],
    +  75*   ['3', 1,                                   '2nd row: pass row 1'],
    +  76*   ['4', [1,3],                               '2nd+4th: pass rows: 1 and 3'],
    +  77*   ['5', {Name:"Jane"},                       'Name is Jane'],
    +  78*   ['6', {1:1500},                            'Column 2 is 1500'],
    +  79*   ['7', {Name:["Peter", "Jane"]},            'Name is Peter or Jane'],
    +  80*   ['8', [{Name:"Peter"}, {Value:1500}],      'Name is Peter or Value is 1500'],
    +  81*   ['9', {or:{Name:"Peter", Value:1500}},     'OR:  same as 8:'],
    +  82*   ['A', {or:[{Name:"Peter"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],
    +  83*   ['B', {Name:"Peter", Value:400},           'Name is Peter and Value is 400'],
    +  84*   ['C', {and:{Name:"Peter", Value:400}},     'AND: {Name is Peter, Value is 400}'],
    +  85*   ['D', {and:{Name:"Peter", Value:1500}},    'AND: {Name is Peter, Value is 1500}'],
    +  86*   ['E', {and:[{Name:"Peter"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],
    +  87*   ['F', {and:[{Name:"Peter"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],
    +  88*   ['G', {not:{Name:"Peter", Value:400}},     'NAND: not {Name is Peter and Value is 400}'],
    +  89*   ['H', {not:{Name:"Peter", Value:1500}},    'NAND: not {Name is Peter and Value is 1500}'],
    +  90*   ['I', {not:[{Name:"Peter"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],
    +  91*   ['J', {Name:(v) => v.length===4},          'Name has 4 letters']
    +  92* ];
    +  93*
    +  94* m.mount(root, { 
    +  95*   view:() => m('', [
    +  96*       m('h3', 'Given the data set:'),
    +  97*       m('table#data', [
    +  98*           m('tr', colNames.map(n => m('th', n))),
    +  99*           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    + 100*       ]),
    + 101*       m('h3', 'The following queries yield:'),
    + 102*       m('table', [
    + 103*           m('tr', [m('th','#'), m('th','Query'), m('th',"Live Result, by 'Name' field")]),
    + 104*           ...queries.map(q => {
    + 105*               const result = data.filter(q[1]).getColumn('Name').join(', ');
    + 106*               return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);
    + 107*           })
    + 108*       ])
    + 109*   ])
    + 110* });
    + 111
    + 112
    + 113*   $exampleID { height: 600px; }
    + 114*   #data th { width:15%; }
    + 115*   table { 
    + 116*       font-size: 10pt;
    + 117*       margin-left: 10px;
    + 118*   }
    + 119
    + 120*      
    + 121*/

    + 122
    + 123/** */
    + 124import { Data,
    + 125         DataVal,
    + 126         DataRow
    + 127} from './Data'; 
    + 128
    + 129export type Condition = IndexCondition | RecursiveCondition;
    + 130
    + 131/** true if row index matches the number(s) */
    + 132export type IndexCondition = number;
    + 133
    + 134export type RecursiveCondition = AndCondition | OrCondition;
    + 135export type OrCondition = AndCondition[] | IndexCondition[];
    + 136export type AndCondition = SetAndCondition | TermAndCondition;
    + 137
    + 138export interface SetAndCondition {
    + 139    or?: RecursiveCondition;
    + 140    and?:RecursiveCondition;
    + 141    not?:RecursiveCondition;
    + 142};
    + 143
    + 144export interface TermAndCondition { 
    + 145    [colDesc:string]: 
    + 146        DataVal 
    + 147      | DataVal[]
    + 148      | TermConditionFunction
    + 149    ;
    + 150};
    + 151
    + 152export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean;
    + 153
    + 154
    + 155function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { 
    + 156    const col = colNumber(name);
    + 157    const valIsFunction = (typeof val === 'function');
    + 158    const valIsArray = ((typeof val === 'object') && (val.length!==undefined));
    + 159    if (isNaN(col)) { 
    + 160        console.log(`column name '${name}' cannot be resolved in terminal condition ${name}=${val}`);
    + 161        console.log(row);
    + 162        return false; // -> this condition is not met;
    + 163    } else if (valIsFunction) { 
    + 164        // query true if function evaluates to true
    + 165        return val(row[col], row);
    + 166    } else if (valIsArray) {
    + 167        // query true if empty array, or at least one c true
    + 168        return (val.length === 0) || val.some((v:any) => row[col] === v); 
    + 169    } else { // object: all conditions have to be met, unless specified as or
    + 170        return (row[col] === val); 
    + 171    }
    + 172}
    + 173
    + 174/**
    + 175 * applies `condition` to a row of data and returns `true` if the row passes.
    + 176 * @param condition the complex condition to test against
    + 177 * @param r the row index in the data set
    + 178 * @param row the row values 
    + 179 * @param and 
    + 180 */

    + 181function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and=true):boolean { 
    + 182    let orResult = false;
    + 183    let andResult= true;          
    + 184    // undefined condition is TRUE
    + 185    if (condition===undefined) { return true; }
    + 186    
    + 187    // Simple Index Condition on row index:
    + 188    else if (typeof condition === 'number') { return (condition === r); }
    + 189
    + 190    // Recursive Condition - OR: [...], AND {...}: 
    + 191    else if (typeof condition === 'object') {
    + 192        // array -> or condition on a list of row indices or compound conditions
    + 193        const mc = condition;
    + 194
    + 195        // OR condition: [...] 
    + 196        if (mc.length !== undefined) {            
    + 197            return (mc.length === 0)? 
    + 198                // empty OR is false:
    + 199                false : 
    + 200                // else: OR is true if any sub-condition is met
    + 201                mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, false));
    + 202        } 
    + 203        // AND condition: {...}
    + 204        else { 
    + 205            for (const name in condition) {
    + 206                let conditionMet = and; // initialize with false for OR, and true for AND conjunction
    + 207                const setCond = condition;
    + 208                
    + 209                // resolve SetConditions:
    + 210                switch (name) {
    + 211                    case 'or':  conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break;
    + 212                    case 'and': conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break;
    + 213                    case 'not': conditionMet = !resolveCondition(setCond.not, row, r, colNumber, true); break;
    + 214                    default:    conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); 
    + 215                }
    + 216                if (conditionMet) { orResult  = true;  if(!and) { break; }} // OR conjunction: exit for name loop if condition met
    + 217                             else { andResult = false; if(and)  { break; }} // AND conjunction: exit for name loop if condition not met
    + 218            }
    + 219        }    
    + 220    } else {
    + 221        console.error(`unrecognized condition: ${JSON.stringify(condition)}`);
    + 222        return false;
    + 223    }
    + 224    return and? andResult : orResult;
    + 225}
    + 226
    + 227/**
    + 228 * filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which
    + 229 * `cond` holds true.
    + 230 * @param data the `Data` object to filter
    + 231 * @param cond the complex condition to test against
    + 232 * @return a new `Data` object with the filtered rows 
    + 233 */

    + 234export function filter(data:Data, cond:Condition):Data {
    + 235    const colNumber = (name:string):number => data.colNumber(name);
    + 236    try {
    + 237        return new Data({
    + 238            name:     data.getName(),
    + 239            colNames: data.colNames(), 
    + 240            rows:data.getData().filter((row:DataRow, i:number) => {
    + 241                const keep = resolveCondition(cond, row, i, colNumber);
    + 242                return keep;
    + 243            })
    + 244        });
    + 245    } catch(err) {
    + 246        console.log(err);
    + 247        console.log(err.stack);
    + 248    }
    + 249}
    + 250
    + + \ No newline at end of file diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..6172591 --- /dev/null +++ b/src/index.html @@ -0,0 +1,32 @@ + + +

    index.ts

    +
       1export { NumRange,
    +   2         NumDomain,
    +   3         DateDomain,
    +   4         NameDomain,
    +   5         Domain,
    +   6         ColumnReference,
    +   7         DataVal,
    +   8         DataRow,
    +   9         DataSet
    +  10        }       from './Data';
    +  11
    +  12export { Data } from './Data';
    +  13export { Condition} from './DataFilters';
    +  14
    +  15
    + + \ No newline at end of file diff --git a/src/overview.html b/src/overview.html new file mode 100644 index 0000000..5a4ae06 --- /dev/null +++ b/src/overview.html @@ -0,0 +1,96 @@ + + +

    overview.ts

    +
       1/**
    +   2 * # hsDatab
    +   3 * 
    +   4 * Helpful Scripts framework-independent data management functions. 
    +   5 * 
    +   6 * *hsdatab* provides a JavaScript-based data management and query mechanism.
    +   7 * Data is managed in a simple in-memory database that holds data in rows of columns. 
    +   8 * It autodetermines the types of data held in each column, along with the 
    +   9 * domain range for each column of data. 
    +  10 * Complex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure. 
    +  11 * 
    +  12 * ## Data Types
    +  13 * supported {@link Data.Data.type data types} include
    +  14 * - **number**: numeric values
    +  15 * - **name**: nominal values, represented by arbitrary words
    +  16 * - **date**: date values
    +  17 * - **currency**: Currently supported: '$dd[,ddd]'
    +  18 * - **percent**: 'd%'
    +  19 * 
    +  20 * ## Data Class
    +  21 * The fundamental object in this library is {@link Data.Data `Data`}, 
    +  22 * a simple row-column based database object, 
    +  23 * featuring named columns, sorting, mapping and filtering functions.
    +  24 *
    +  25 * ## Example
    +  26 * 
    +  27 * 
    +  28 * const colNames = ['Name', 'Value', 'Start', 'End'];
    +  29 * const rows = [
    +  30 *   ['Harry', '100', '3/1/14', '11/20/14'], 
    +  31 *   ['Mary', '1500', '7/1/14',  '9/30/14'],
    +  32 *   ['Peter', '400', '5/20/14', '4/30/15'],  
    +  33 *   ['Jane', '700', '11/13/14', '8/15/15']
    +  34 * ]
    +  35 * const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  36 * 
    +  37 * query = {Name:["Peter", "Jane"]};
    +  38 * const result = data.filter(query);
    +  39 *
    +  40 * m.mount(root, {
    +  41 *   view:() => m('', [
    +  42 *       m('h3', 'Given the data set:'),
    +  43 *       m('pre',
    +  44 *       m('table#data', [
    +  45 *           m('tr', colNames.map(n => m('th', n))),
    +  46 *           ...rows.map(row => m('tr', [
    +  47 *              m('td', row[0]),
    +  48 *              m('td', row[1]),
    +  49 *              m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),
    +  50 *              m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)
    +  51 *          ]))
    +  52 *       ])),
    +  53 *       m('h3', 'The column types and domains are'),
    +  54 *       m('pre', m('table', 
    +  55 *                  m('tr', m('th', 'Column'),   m('th', 'Type'),   m('th', 'Domain')),
    +  56 *                  m('tr', m('td', '"Name":'),  m('td', data.colType("Name")),   m('td', data.findDomain("Name").join(', '))),
    +  57 *                  m('tr', m('td', '"Value":'), m('td', data.colType("Value")),  m('td', data.findDomain("Value").join(' - '))),
    +  58 *                  m('tr', m('td', '"Start":'), m('td', data.colType("Start")),  m('td', data.findDomain("Start").map(d => d.toDateString()).join(' - '))),
    +  59 *                  m('tr', m('td', '"Stop":'),  m('td', data.colType("End")),    m('td', data.findDomain("End").map(d => d.toDateString()).join(' - ')))
    +  60 *       )),
    +  61 *       m('h3', 'The query:'),
    +  62 *       m('code', '{Name:["Peter", "Jane"]}'),
    +  63 *       m('h3', 'yields results with "Name"'),
    +  64 *       m('code', result.getColumn('Name').join(', '))
    +  65 *   ])
    +  66 * });
    +  67 * 
    +  68 * 
    +  69 *   $exampleID { height: 600px; }
    +  70 *   #data th { width:15%; }
    +  71 *   #data  { font-size: 11pt; }
    +  72 * 
    +  73 *      
    +  74 */

    +  75
    +  76 /** */
    +  77
    +  78 
    +  79
    + + \ No newline at end of file From 79e4a3e4d010ed3e69fe7e6df47d171efcb63a5d Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 16 Jun 2018 12:37:30 +0200 Subject: [PATCH 09/17] camelcased filename --- docs/data/hsDatab.json | 3293 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3293 insertions(+) create mode 100644 docs/data/hsDatab.json diff --git a/docs/data/hsDatab.json b/docs/data/hsDatab.json new file mode 100644 index 0000000..a535f27 --- /dev/null +++ b/docs/data/hsDatab.json @@ -0,0 +1,3293 @@ +{ + "id": 0, + "name": "hsDatab", + "kind": 0, + "flags": {}, + "children": [ + { + "id": 42, + "name": "\"Data\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.ts", + "comment": {}, + "children": [ + { + "id": 56, + "name": "Data", + "kind": 128, + "kindString": "Class", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "# Data\nA simple in-memory database that holds data in rows of columns." + }, + "children": [ + { + "id": 67, + "name": "constructor", + "kind": 512, + "kindString": "Constructor", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 68, + "name": "new Data", + "kind": 16384, + "kindString": "Constructor signature", + "flags": {}, + "parameters": [ + { + "id": 69, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 86, + "character": 5 + } + ] + }, + { + "id": 117, + "name": "data", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 392, + "character": 16 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + "defaultValue": " []" + }, + { + "id": 118, + "name": "meta", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 393, + "character": 16 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "MetaStruct", + "id": 50 + } + }, + "defaultValue": " []" + }, + { + "id": 119, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 394, + "character": 16 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 134, + "name": "allRows", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 135, + "name": "allRows", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "A generator that provides the specified column value for each row in `Data` in sequence." + }, + "parameters": [ + { + "id": 136, + "name": "column", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "\n" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "Iterable", + "typeArguments": [ + { + "type": "reference", + "name": "DataVal", + "id": 151 + } + ] + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 493, + "character": 21 + } + ] + }, + { + "id": 104, + "name": "castData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 105, + "name": "castData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 260, + "character": 19 + } + ] + }, + { + "id": 141, + "name": "castVal", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 142, + "name": "castVal", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "The result of the cast.", + "tags": [ + { + "tag": "description", + "text": "Casts the sample to the specified data type.\n" + } + ] + }, + "parameters": [ + { + "id": 143, + "name": "type", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "The type to cast into. In case of _any_ - i.e. `type`\ndoes not match any of the previous keywords, no casting occurs." + }, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 144, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 529, + "character": 19 + } + ] + }, + { + "id": 82, + "name": "colAdd", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 83, + "name": "colAdd", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "adds a new column to the data set. if `newCol` already exists,\nthe column index is returned withoput change.", + "returns": "the index for the new column\n" + }, + "parameters": [ + { + "id": 84, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the name of the new column" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 140, + "character": 17 + } + ] + }, + { + "id": 85, + "name": "colInitialize", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 86, + "name": "colInitialize", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "initializes the specifed column with values, adding a new column if needed.\nIf `val`is a function, it is called as ```\nval(colValue:DataVal, rowIndex:number, row:DataRow)\n```" + }, + "parameters": [ + { + "id": 87, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the column to initialize" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + }, + { + "id": 88, + "name": "initializer", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the value to initialize with, or a function whose return\nvalue is used to initialize the column\n" + }, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 162, + "character": 24 + } + ] + }, + { + "id": 92, + "name": "colName", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 93, + "name": "colName", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column name for the specified column.\n`col` can be either an index or a name.", + "returns": "the column name or `undefined`.\n" + }, + "parameters": [ + { + "id": 94, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 194, + "character": 18 + } + ] + }, + { + "id": 95, + "name": "colNames", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 96, + "name": "colNames", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the names for all columns.", + "returns": "an array of strings with the names.\n" + }, + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 205, + "character": 19 + } + ] + }, + { + "id": 89, + "name": "colNumber", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 90, + "name": "colNumber", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column index of the specified column.\n`col` can be either an index or a name.", + "returns": "the column number or `undefined`.\n" + }, + "parameters": [ + { + "id": 91, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 179, + "character": 20 + } + ] + }, + { + "id": 97, + "name": "colType", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 98, + "name": "colType", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column type for the specified column.\n`col` can be either an index or a name.", + "returns": "the column type.\n" + }, + "parameters": [ + { + "id": 99, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 215, + "character": 18 + } + ] + }, + { + "id": 75, + "name": "export", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 76, + "name": "export", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Exports to an object literal" + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 111, + "character": 17 + } + ] + }, + { + "id": 106, + "name": "filter", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 107, + "name": "filter", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "filters this data set and returns a new data set with a\nshallow copy of rows that pass the `condition`.\nSee {@link DataFilters DataFilters} for rules and examples on how to construct conditions.", + "returns": "a new Data object with rows that pass the filter\n" + }, + "parameters": [ + { + "id": 108, + "name": "condition", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "filters" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 277, + "character": 17 + } + ] + }, + { + "id": 100, + "name": "findDomain", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 101, + "name": "findDomain", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "modifies `domain` to include all values in column `col`.\nIf no `col` is specified, the range of data indexes is returned.", + "returns": "the updated domain\n" + }, + "parameters": [ + { + "id": 102, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the column name or index" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + }, + { + "id": 103, + "name": "domain", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the Domain range to update" + }, + "type": { + "type": "reference", + "name": "Domain", + "id": 149 + } + } + ], + "type": { + "type": "reference", + "name": "Domain", + "id": 149 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 227, + "character": 21 + } + ] + }, + { + "id": 131, + "name": "findType", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 132, + "name": "findType", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample\n", + "tags": [ + { + "tag": "description", + "text": "determines the data type. Supported types are\n```\n'date': sample represents a Date, either as a Date object or a String\n'number': sample represents a number\n'percent': sample represents a percentage (special case of a real number)\n'nominal': sample represents a nominal (ordinal or categorical) value\n```" + } + ] + }, + "parameters": [ + { + "id": 133, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the value to bve typed." + }, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 462, + "character": 20 + } + ] + }, + { + "id": 128, + "name": "findTypes", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 129, + "name": "findTypes", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Determines the type of data in `col`. An array of counts is created for all\nencountered types, sorted by descending frequency. THe most likely type in position 0\nof the array is returned.", + "returns": "the most likely type of data in `col`.\n" + }, + "parameters": [ + { + "id": 130, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the index of the column to be typed." + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 430, + "character": 21 + } + ] + }, + { + "id": 79, + "name": "getColumn", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 80, + "name": "getColumn", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Returns the values in the specified column as a new array." + }, + "parameters": [ + { + "id": 81, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the column to return.\n" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 129, + "character": 20 + } + ] + }, + { + "id": 77, + "name": "getData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 78, + "name": "getData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the 2D array underlying the data base." + }, + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 121, + "character": 18 + } + ] + }, + { + "id": 120, + "name": "getMeta", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 121, + "name": "getMeta", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 122, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "MetaStruct", + "id": 50 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 396, + "character": 19 + } + ] + }, + { + "id": 70, + "name": "getName", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 71, + "name": "getName", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the `name` field for this data base, if any\n" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 95, + "character": 18 + } + ] + }, + { + "id": 72, + "name": "import", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 73, + "name": "import", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Imports data from an object literal `data`" + }, + "parameters": [ + { + "id": 74, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data set to import\n" + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 103, + "character": 17 + } + ] + }, + { + "id": 113, + "name": "map", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 114, + "name": "map", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": " Maps one or more columns in each rows of values based\non the result of the `mapFn`, which behaves similarly to the Array.map() method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the `mapFn` is passed the column arrays per row as parameter.\nThis allows for complex mapping combining conditions across multiple columns.\n```\ndata.map(function(values){\n values[1] = values[3] * values[5];\n return values;\n});\n```\nBe sure to return the `values` array as a result.\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `mapFn`, along with the row index and the entire row array. This allows for simple mapping.\n```\ndata.map('Price', function(value, i, values) {\n return value * 2;\n});\n```", + "returns": "a new Data object containing the mapping.\n" + }, + "parameters": [ + { + "id": 115, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data column, or columns, to apply the mapping to." + }, + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "ColumnReference", + "id": 150 + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ] + } + }, + { + "id": 116, + "name": "mapFn", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "a function to implement the mapping,\ncalled on each row of the data set in turn as `mapFn(val, i, c, rows)`, where\n- `val`: the column value in the current row\n- `c`: the column index in the current row\n- `i`: the row index\n- `rows`: the rows being iterated over\n` *\nfollows the same specifications as the function passed to Array.map().
    \nFor column mode, some predefined map functions can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.
    " + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "mapFn", + "id": 116 + } + ] + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 359, + "character": 14 + } + ] + }, + { + "id": 123, + "name": "setData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 124, + "name": "setData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "sets `data` to the existing data set. If data has previously been set,\n`data` will be added to the end of the list if all `names` match those of the\nexisting set." + }, + "parameters": [ + { + "id": 125, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data to add" + }, + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + }, + { + "id": 126, + "name": "names", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "an array of names that match the columns" + }, + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 127, + "name": "autoType", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "unless set to false, the method will attempt to determine the\ntype of data and automatically cast data points to their correct value\n" + }, + "type": { + "type": "intrinsic", + "name": "boolean" + }, + "defaultValue": "true" + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 412, + "character": 19 + } + ] + }, + { + "id": 109, + "name": "sort", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 110, + "name": "sort", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the Data object in order to allow for chaining.\n", + "tags": [ + { + "tag": "description", + "text": "Sorts the rows of values based on the result of the `sortFn`,\nwhich behaves similarly to the Array.sort method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the column arrays are passed as samples into the `sortFn`.\nThis allows for complex sorts, combining conditions across multiple columns.\n```\ndata.sort((row1, row2) => row1[5] - row2[5] );\n```\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `sortFn`. This allows filtering for simple conditions.
    \n**The specified column will be automatically cast prior to sorting**
    \n`data.sort('Date', function(val1, val2) { return val1 - val2; });`" + } + ] + }, + "parameters": [ + { + "id": 111, + "name": "sortFn", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "a function to implement the conditions,\nfollows the same specifications as the function passed to Array.sort().\nSome predefined sort function can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.
    " + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "sortFn", + "id": 111 + } + ] + } + }, + { + "id": 112, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the data column to use for sorting." + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 307, + "character": 15 + } + ] + }, + { + "id": 137, + "name": "toDate", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 138, + "name": "toDate", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "a new Date object parsed from `str`.", + "tags": [ + { + "tag": "description", + "text": "returns a new Date object parsed from `str` and corrects for a difference in\ninterpreting centuries between webkit and mozilla in converting strings to Dates:\nThe string \"15/7/03\" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.\nIf `limitYear` is not specified this method uses 1970 as the decision date:\nyears 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.\n" + } + ] + }, + "parameters": [ + { + "id": 139, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the string to convert to a date" + }, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "id": 140, + "name": "limitYear", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the year below which the century is corrected. Defaults to 1970." + }, + "type": { + "type": "intrinsic", + "name": "number" + }, + "defaultValue": "1970" + } + ], + "type": { + "type": "reference", + "name": "Date" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 510, + "character": 18 + } + ] + }, + { + "id": 63, + "name": "toDataSet", + "kind": 2048, + "kindString": "Method", + "flags": { + "isStatic": true, + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 64, + "name": "toDataSet", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 65, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataLiteralSet", + "id": 153 + } + }, + { + "id": 66, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 80, + "character": 27 + } + ] + }, + { + "id": 57, + "name": "type", + "kind": 2097152, + "kindString": "Object literal", + "flags": { + "isStatic": true, + "isExported": true, + "isPublic": true + }, + "children": [ + { + "id": 61, + "name": "currency", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "currency values. Currently support6ed are values ofg the format '$dd[,ddd]'" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 74, + "character": 16 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"currency\"" + }, + { + "id": 60, + "name": "date", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "date values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 72, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"date\"" + }, + { + "id": 59, + "name": "name", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "nominal values, represented by arbitrary words" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 70, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"name\"" + }, + { + "id": 58, + "name": "number", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "numeric values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 68, + "character": 14 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"number\"" + }, + { + "id": 62, + "name": "percent", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "percent values: 'd%'" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 76, + "character": 15 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"percent\"" + } + ], + "groups": [ + { + "title": "Variables", + "kind": 32, + "children": [ + 61, + 60, + 59, + 58, + 62 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 66, + "character": 22 + } + ], + "type": { + "type": "intrinsic", + "name": "object" + } + } + ], + "groups": [ + { + "title": "Constructors", + "kind": 512, + "children": [ + 67 + ] + }, + { + "title": "Properties", + "kind": 1024, + "children": [ + 117, + 118, + 119 + ] + }, + { + "title": "Methods", + "kind": 2048, + "children": [ + 134, + 104, + 141, + 82, + 85, + 92, + 95, + 89, + 97, + 75, + 106, + 100, + 131, + 128, + 79, + 77, + 120, + 70, + 72, + 113, + 123, + 109, + 137, + 63 + ] + }, + { + "title": "Object literals", + "kind": 2097152, + "children": [ + 57 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 62, + "character": 17 + } + ] + }, + { + "id": 43, + "name": "DataSet", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a JSON format data set, using arrays of names and rows" + }, + "children": [ + { + "id": 45, + "name": "colNames", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "an array of column names. Each name matches the column with the same index in DataRow" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 36, + "character": 12 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 44, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "comment": { + "shortText": "an optional name for the data set" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 34, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 46, + "name": "rows", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "rows of data" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 38, + "character": 8 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 45, + 44, + 46 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 32, + "character": 24 + } + ] + }, + { + "id": 50, + "name": "MetaStruct", + "kind": 256, + "kindString": "Interface", + "flags": {}, + "children": [ + { + "id": 53, + "name": "accessed", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 49, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 54, + "name": "cast", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 50, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 52, + "name": "column", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 48, + "character": 10 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 51, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 47, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 55, + "name": "types", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 51, + "character": 9 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "TypeStruct", + "id": 47 + } + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 53, + 54, + 52, + 51, + 55 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 46, + "character": 20 + } + ] + }, + { + "id": 47, + "name": "TypeStruct", + "kind": 256, + "kindString": "Interface", + "flags": {}, + "children": [ + { + "id": 49, + "name": "count", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 42 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 48, + "name": "type", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 27 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 49, + 48 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 20 + } + ] + }, + { + "id": 150, + "name": "ColumnReference", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 23, + "character": 27 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "string" + } + ] + } + }, + { + "id": 153, + "name": "DataLiteralSet", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a JSON format data set, using an array of {name:value, ...} literals" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 42, + "character": 26 + } + ], + "type": { + "type": "reference", + "name": "Array", + "typeArguments": [ + { + "type": "intrinsic", + "name": "any" + } + ] + } + }, + { + "id": 152, + "name": "DataRow", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a single row of column values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 29, + "character": 19 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + }, + { + "id": 151, + "name": "DataVal", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a generic data value type, used in the {@link Data.DataRow `DataRow`} array" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 26, + "character": 19 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "Date" + } + ] + } + }, + { + "id": 147, + "name": "DateDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a Date domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 14, + "character": 22 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "reference", + "name": "Date" + }, + { + "type": "reference", + "name": "Date" + } + ] + } + }, + { + "id": 149, + "name": "Domain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a generic domain that can be any of the typed domains." + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 20, + "character": 18 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "NumDomain", + "id": 146 + }, + { + "type": "reference", + "name": "DateDomain", + "id": 147 + }, + { + "type": "reference", + "name": "NameDomain", + "id": 148 + } + ] + } + }, + { + "id": 148, + "name": "NameDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a categorical domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 17, + "character": 22 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 146, + "name": "NumDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a numeric domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 11, + "character": 21 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "number" + } + ] + } + }, + { + "id": 145, + "name": "NumRange", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a [min-max] range" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 8, + "character": 20 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "number" + } + ] + } + }, + { + "id": 159, + "name": "mapFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 55, + "character": 17 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 160, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 161, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 162, + "name": "colVal", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 163, + "name": "colIndex", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 164, + "name": "rowIndex", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 165, + "name": "rows", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "array", + "elementType": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "any" + } + } + } + } + ], + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 55, + "character": 20 + } + ] + } + } + }, + { + "id": 154, + "name": "sortFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 54, + "character": 18 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 155, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 156, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 157, + "name": "x", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 158, + "name": "y", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 54, + "character": 20 + } + ] + } + } + } + ], + "groups": [ + { + "title": "Classes", + "kind": 128, + "children": [ + 56 + ] + }, + { + "title": "Interfaces", + "kind": 256, + "children": [ + 43, + 50, + 47 + ] + }, + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 150, + 153, + 152, + 151, + 147, + 149, + 148, + 146, + 145, + 159, + 154 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 1, + "name": "\"DataFilters\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/DataFilters.ts", + "comment": { + "shortText": "Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object.\nEach row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object.", + "text": "# Condition construction\n\n### General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n### IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n### RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n### Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" + }, + "children": [ + { + "id": 2, + "name": "SetAndCondition", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "children": [ + { + "id": 4, + "name": "and", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 140, + "character": 7 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + }, + { + "id": 5, + "name": "not", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 141, + "character": 7 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + }, + { + "id": 3, + "name": "or", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 139, + "character": 6 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 4, + 5, + 3 + ] + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 138, + "character": 32 + } + ] + }, + { + "id": 6, + "name": "TermAndCondition", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "indexSignature": [ + { + "id": 7, + "name": "__index", + "kind": 8192, + "kindString": "Index signature", + "flags": {}, + "parameters": [ + { + "id": 8, + "name": "colDesc", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "DataVal", + "id": 151 + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "type": "reference", + "name": "TermConditionFunction", + "id": 14 + } + ] + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 144, + "character": 33 + } + ] + }, + { + "id": 13, + "name": "AndCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 136, + "character": 24 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "SetAndCondition", + "id": 2 + }, + { + "type": "reference", + "name": "TermAndCondition", + "id": 6 + } + ] + } + }, + { + "id": 9, + "name": "Condition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 129, + "character": 21 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "IndexCondition", + "id": 10 + }, + { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + ] + } + }, + { + "id": 10, + "name": "IndexCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "true if row index matches the number(s)" + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 132, + "character": 26 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 12, + "name": "OrCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 135, + "character": 23 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "array", + "elementType": { + "type": "reference", + "name": "AndCondition", + "id": 13 + } + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "IndexCondition", + "id": 10 + } + } + ] + } + }, + { + "id": 11, + "name": "RecursiveCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 134, + "character": 30 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "AndCondition", + "id": 13 + }, + { + "type": "reference", + "name": "OrCondition", + "id": 12 + } + ] + } + }, + { + "id": 14, + "name": "TermConditionFunction", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 152, + "character": 33 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 15, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 16, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 17, + "name": "value", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "id": 18, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 152, + "character": 35 + } + ] + } + } + }, + { + "id": 38, + "name": "filter", + "kind": 64, + "kindString": "Function", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 39, + "name": "filter", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which\n`cond` holds true.", + "returns": "a new `Data` object with the filtered rows\n" + }, + "parameters": [ + { + "id": 40, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the `Data` object to filter" + }, + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + }, + { + "id": 41, + "name": "cond", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the complex condition to test against" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 234, + "character": 22 + } + ] + }, + { + "id": 28, + "name": "resolveCondition", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 29, + "name": "resolveCondition", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "applies `condition` to a row of data and returns `true` if the row passes." + }, + "parameters": [ + { + "id": 30, + "name": "condition", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the complex condition to test against" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + }, + { + "id": 31, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the row values" + }, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + { + "id": 32, + "name": "r", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the row index in the data set" + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 33, + "name": "colNumber", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reflection", + "declaration": { + "id": 34, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 35, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 36, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 181, + "character": 80 + } + ] + } + } + }, + { + "id": 37, + "name": "and", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "\n" + }, + "type": { + "type": "intrinsic", + "name": "boolean" + }, + "defaultValue": "true" + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 181, + "character": 25 + } + ] + }, + { + "id": 19, + "name": "resolveTerminalCondition", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 20, + "name": "resolveTerminalCondition", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 21, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 22, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 23, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + { + "id": 24, + "name": "colNumber", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reflection", + "declaration": { + "id": 25, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 26, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 27, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 155, + "character": 79 + } + ] + } + } + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 155, + "character": 33 + } + ] + } + ], + "groups": [ + { + "title": "Interfaces", + "kind": 256, + "children": [ + 2, + 6 + ] + }, + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 13, + 9, + 10, + 12, + 11, + 14 + ] + }, + { + "title": "Functions", + "kind": 64, + "children": [ + 38, + 28, + 19 + ] + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 166, + "name": "\"index\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/index.ts", + "sources": [ + { + "fileName": "index.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 167, + "name": "\"overview\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", + "comment": { + "shortText": "# hsDatab", + "text": "Helpful Scripts framework-independent data management functions.\n\n*hsdatab* provides a JavaScript-based data management and query mechanism.\nData is managed in a simple in-memory database that holds data in rows of columns.\nIt autodetermines the types of data held in each column, along with the\ndomain range for each column of data.\nComplex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure.\n\n## Data Types\nsupported {@link Data.Data.type data types} include\n- **number**: numeric values\n- **name**: nominal values, represented by arbitrary words\n- **date**: date values\n- **currency**: Currently supported: '$dd[,ddd]'\n- **percent**: 'd%'\n\n## Data Class\nThe fundamental object in this library is {@link Data.Data `Data`},\na simple row-column based database object,\nfeaturing named columns, sorting, mapping and filtering functions.\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query);\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('pre',\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [\n m('td', row[0]),\n m('td', row[1]),\n m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),\n m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)\n ]))\n ])),\n m('h3', 'The column types and domains are'),\n m('pre', m('table',\n m('tr', m('th', 'Column'), m('th', 'Type'), m('th', 'Domain')),\n m('tr', m('td', '\"Name\":'), m('td', data.colType(\"Name\")), m('td', data.findDomain(\"Name\").join(', '))),\n m('tr', m('td', '\"Value\":'), m('td', data.colType(\"Value\")), m('td', data.findDomain(\"Value\").join(' - '))),\n m('tr', m('td', '\"Start\":'), m('td', data.colType(\"Start\")), m('td', data.findDomain(\"Start\").map(d => d.toDateString()).join(' - '))),\n m('tr', m('td', '\"Stop\":'), m('td', data.colType(\"End\")), m('td', data.findDomain(\"End\").map(d => d.toDateString()).join(' - ')))\n )),\n m('h3', 'The query:'),\n m('code', '{Name:[\"Peter\", \"Jane\"]}'),\n m('h3', 'yields results with \"Name\"'),\n m('code', result.getColumn('Name').join(', '))\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n #data { font-size: 11pt; }\n\n\n" + }, + "sources": [ + { + "fileName": "overview.ts", + "line": 1, + "character": 0 + } + ] + } + ], + "groups": [ + { + "title": "External modules", + "kind": 1, + "children": [ + 42, + 1, + 166, + 167 + ] + } + ] +} \ No newline at end of file From 3c8698f43296e00d96837450bd0b12f737d9542d Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 16 Jun 2018 17:43:57 +0200 Subject: [PATCH 10/17] docs update --- src/Data.html | 2 +- src/DataFilters.html | 2 +- src/index.html | 2 +- src/overview.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Data.html b/src/Data.html index d2b7bfa..8e87921 100644 --- a/src/Data.html +++ b/src/Data.html @@ -12,7 +12,7 @@ height:90%; } code { padding: 5px 0;} -

    Data.ts

    +

    src/Data.ts

       1/**
       2 */

       3
    diff --git a/src/DataFilters.html b/src/DataFilters.html index cd063c1..7669d54 100644 --- a/src/DataFilters.html +++ b/src/DataFilters.html @@ -12,7 +12,7 @@ height:90%; } code { padding: 5px 0;} -

    DataFilters.ts

    +

    src/DataFilters.ts

       1
       2/**
       3* Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object. 
    diff --git a/src/index.html b/src/index.html index 6172591..07a3840 100644 --- a/src/index.html +++ b/src/index.html @@ -12,7 +12,7 @@ height:90%; } code { padding: 5px 0;} -

    index.ts

    +

    src/index.ts

       1export { NumRange,
       2         NumDomain,
       3         DateDomain,
    diff --git a/src/overview.html b/src/overview.html index 5a4ae06..28af118 100644 --- a/src/overview.html +++ b/src/overview.html @@ -12,7 +12,7 @@ height:90%; } code { padding: 5px 0;} -

    overview.ts

    +

    src/overview.ts

       1/**
       2 * # hsDatab
       3 * 
    From c3c5bc4353e7681525a61cbee51c9bc253e82ff2 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 16 Jun 2018 18:06:54 +0200 Subject: [PATCH 11/17] cleaning up --- docs/src/Data.spec.html | 54 ++++ src/Data.html | 568 ---------------------------------------- src/DataFilters.html | 267 ------------------- src/index.html | 32 --- src/overview.html | 96 ------- 5 files changed, 54 insertions(+), 963 deletions(-) create mode 100644 docs/src/Data.spec.html delete mode 100644 src/Data.html delete mode 100644 src/DataFilters.html delete mode 100644 src/index.html delete mode 100644 src/overview.html diff --git a/docs/src/Data.spec.html b/docs/src/Data.spec.html new file mode 100644 index 0000000..a9221cc --- /dev/null +++ b/docs/src/Data.spec.html @@ -0,0 +1,54 @@ + + +

    src/Data.spec.ts

    +
       1import { o }            from 'hslayout';
    +   2import * as hsdatab     from 'hsdatab';
    +   3
    +   4const colNames = ['Name', 'Value', 'Start', 'End'];
    +   5const rows = [
    +   6  ['Harry', '100', '3/1/14', '11/20/14'], 
    +   7  ['Mary', '1500', '7/1/14',  '9/30/14'],
    +   8  ['Peter', '400', '5/20/14', '4/30/15'],  
    +   9  ['Jane', '700', '11/13/14', '8/15/15']
    +  10];
    +  11
    +  12const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  13
    +  14const query = {Name:["Peter", "Jane"]};
    +  15const result = data.filter(query);
    +  16
    +  17o.spec("Data", () => {
    +  18    o("is created with 4 rows", () => {
    +  19        o(data.getData.length).equals(4);
    +  20    });
    +  21});
    +  22o.spec('Data Filters', () => {
    +  23    o('Query for {Name:["Peter", "Jane"]}', () => {
    +  24        o(result.getData.length).equals(2)('has two rows');
    +  25        o(result.getColumn('Name')[0]).equals('Peter')('has first row name Peter');
    +  26    });
    +  27});
    +  28
    +  29
    +  30/*
    +  31        var vnode = MyComponent.view()
    +  32
    +  33        o(vnode.tag).equals("div")
    +  34        o(vnode.children.length).equals(1)
    +  35        o(vnode.children[0].tag).equals("p")
    +  36        o(vnode.children[0].children).equals("Hello world")
    +  37*/

    + + \ No newline at end of file diff --git a/src/Data.html b/src/Data.html deleted file mode 100644 index 8e87921..0000000 --- a/src/Data.html +++ /dev/null @@ -1,568 +0,0 @@ - - -

    src/Data.ts

    -
       1/**
    -   2 */

    -   3
    -   4 /** */
    -   5import { Condition, filter } from './DataFilters';
    -   6
    -   7/** defines a [min-max] range */
    -   8export type NumRange = [number, number];
    -   9
    -  10/** defines a numeric domain that includes all values of a column */
    -  11export type NumDomain = [number, number];
    -  12
    -  13/** defines a Date domain that includes all values of a column */
    -  14export type DateDomain = [Date, Date];
    -  15
    -  16/** defines a categorical domain that includes all values of a column */
    -  17export type NameDomain = string[];
    -  18
    -  19/** defines a generic domain that can be any of the typed domains. */
    -  20export type Domain = NumDomain | DateDomain | NameDomain;
    -  21
    -  22/** defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    -  23export type ColumnReference = number|string;
    -  24
    -  25/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    -  26export type DataVal = number|string|Date;
    -  27
    -  28/** a single row of column values */
    -  29export type DataRow = DataVal[];
    -  30
    -  31/** a JSON format data set, using arrays of names and rows */
    -  32export interface DataSet {
    -  33    /** an optional name for the data set */
    -  34    name?:  string;
    -  35    /** an array of column names. Each name matches the column with the same index in DataRow */
    -  36    colNames:  string[];   
    -  37    /** rows of data */
    -  38    rows:   DataRow[];
    -  39}
    -  40
    -  41/** a JSON format data set, using an array of {name:value, ...} literals*/
    -  42export type DataLiteralSet = Array;
    -  43
    -  44interface TypeStruct { type: string; count: number;};
    -  45
    -  46interface MetaStruct {
    -  47    name:       string;         // column name
    -  48    column:     number;         // column index
    -  49    accessed:   boolean;        // has column data been accessed?
    -  50    cast:       boolean;        // has column data been cast 
    -  51    types:      TypeStruct[];   // data types, sorted by likelihood
    -  52}
    -  53
    -  54export type sortFn = (x:any, y:any) => number;
    -  55export type mapFn  = (colVal:any, colIndex?:number, rowIndex?:number, rows?:any[][]) => any;
    -  56
    -  57/**
    -  58 * # Data
    -  59 * A simple in-memory database that holds data in rows of columns.
    -  60 * 
    -  61 */

    -  62export class Data {
    -  63    //----------------------------
    -  64    // public part
    -  65    //----------------------------
    -  66    public static type = {
    -  67        /** numeric values */
    -  68        number:     'number',
    -  69        /** nominal values, represented by arbitrary words */
    -  70        name:       'name',
    -  71        /** date values */
    -  72        date:       'date',
    -  73        /** currency values. Currently support6ed are values ofg the format '$dd[,ddd]' */
    -  74        currency:   'currency',
    -  75        /** percent values: 'd%' */
    -  76        percent:    'percent',
    -  77//        nominal:    'nominal'
    -  78    };
    -  79
    -  80    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    -  81        data = data || [{}];
    -  82        const names = Object.keys(data[0]);
    -  83        const rows = data.map((r:any) => 
    -  84            names.map((n:string) => r[n]));
    -  85        return { rows:rows, colNames:names, name:name||undefined };
    -  86    }
    -  87
    -  88    constructor(data?:DataSet) {
    -  89        this.import(data);
    -  90    }
    -  91
    -  92    /**
    -  93     * @return the `name` field for this data base, if any
    -  94     */

    -  95    public getName():string {
    -  96        return this.name;
    -  97    }
    -  98
    -  99    /**
    - 100     * Imports data from an object literal `data`
    - 101     * @param data the data set to import
    - 102     */

    - 103    public import(data:DataSet) {
    - 104        this.name = data.name;
    - 105        this.setData(data.rows, data.colNames);
    - 106    }
    - 107
    - 108    /**
    - 109     * Exports to an object literal
    - 110     */

    - 111    public export():DataSet {
    - 112        return {
    - 113            rows: this.getData(),
    - 114            colNames:this.colNames()
    - 115        };
    - 116    }
    - 117
    - 118    /**
    - 119     * returns the 2D array underlying the data base.
    - 120     */

    - 121    public getData():DataRow[] {
    - 122        return this.data;
    - 123    }
    - 124
    - 125    /**
    - 126     * Returns the values in the specified column as a new array.
    - 127     * @param col the column to return.
    - 128     */

    - 129    public getColumn(col:ColumnReference): DataVal[] {
    - 130        const cn = this.colNumber(col);
    - 131        return this.data.map((row:DataRow) => row[cn]);
    - 132    }
    - 133
    - 134    /**
    - 135     * adds a new column to the data set. if `newCol` already exists, 
    - 136     * the column index is returned withoput change.
    - 137     * @param col the name of the new column
    - 138     * @return the index for the new column
    - 139     */

    - 140    public colAdd(col:string):number {
    - 141        let m = this.getMeta(col);
    - 142        if (m === undefined) { 
    - 143            m = this.meta[col] = {};
    - 144            m.name   = col; 
    - 145            m.column = this.meta.length;
    - 146            this.meta.push(m);      // access name by both column name and index
    - 147            m.cast     = false;         // has not been cast yet
    - 148            m.accessed = false;         // has not been accessed yet
    - 149        }
    - 150        return m.column;
    - 151    }
    - 152
    - 153    /**
    - 154     * initializes the specifed column with values, adding a new column if needed. 
    - 155     * If `val`is a function, it is called as ```
    - 156     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    - 157     * ```
    - 158     * @param col the column to initialize
    - 159     * @param initializer the value to initialize with, or a function whose return
    - 160     * value is used to initialize the column
    - 161     */

    - 162    public colInitialize(col:ColumnReference, initializer:any) {
    - 163        const cn = this.colNumber(col);
    - 164        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    - 165        const fn = typeof initializer === 'function';
    - 166        if (cn!==undefined) {
    - 167            this.data.map((r:DataRow, i:number) =>
    - 168                r[cn] = fn? initializer(r[cn], i, r) : initializer
    - 169            );
    - 170        }
    - 171    }
    - 172
    - 173    /**
    - 174     * returns the column index of the specified column. 
    - 175     * `col` can be either an index or a name.
    - 176     * @param column the data column, name or index, for which to return the index. 
    - 177     * @return the column number or `undefined`.
    - 178     */

    - 179    public colNumber(col:ColumnReference) {
    - 180        const m = this.getMeta(col);
    - 181        if (!m) { return undefined; }
    - 182        else {
    - 183            m.accessed = true; 
    - 184            return m.column; 
    - 185        }
    - 186    }
    - 187    
    - 188    /**
    - 189     * returns the column name for the specified column. 
    - 190     * `col` can be either an index or a name.
    - 191     * @param column the data column, name or index. 
    - 192     * @return the column name or `undefined`.
    - 193     */

    - 194    public colName(col:ColumnReference) {
    - 195        var m = this.getMeta(col);
    - 196        if (!m) { return undefined; }
    - 197        m.accessed = true; 
    - 198        return m.name; 
    - 199    }
    - 200
    - 201    /**
    - 202     * returns the names for all columns. 
    - 203     * @return an array of strings with the names.
    - 204     */

    - 205    public colNames():string[] {
    - 206        return this.meta.map((m:MetaStruct) => m.name); 
    - 207    }
    - 208
    - 209    /**
    - 210     * returns the column type for the specified column. 
    - 211     * `col` can be either an index or a name.
    - 212     * @param column the data column, name or index. 
    - 213     * @return the column type.
    - 214     */

    - 215    public colType(col:ColumnReference) { 
    - 216        const meta = this.getMeta(col);
    - 217        return meta? meta.types[0].type : Data.type.name;
    - 218    }
    - 219
    - 220    /**
    - 221     * modifies `domain` to include all values in column `col`.
    - 222     * If no `col` is specified, the range of data indexes is returned.
    - 223     * @param col optional; the column name or index 
    - 224     * @param domain optional; the Domain range to update
    - 225     * @return the updated domain
    - 226     */

    - 227    public findDomain(col?:ColumnReference, domain?:Domain):Domain {
    - 228        if (domain===undefined) { domain = []; }
    - 229        if (col === undefined) { // use array index as domain
    - 230            domain[0] = 0;
    - 231            domain[1] = this.data.length-1;
    - 232        } else {
    - 233            const c = this.colNumber(col);
    - 234            const type = this.colType(col);
    - 235            if (this.data === undefined) {
    - 236                console.log('no data'); 
    - 237            }
    - 238            switch(type) {
    - 239                case Data.type.name: 
    - 240                    this.data.forEach((r:DataRow) => {
    - 241                        const nomDom = domain;
    - 242                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    - 243                    });
    - 244                    break;
    - 245                default: 
    - 246                    this.data.forEach((r:DataRow) => {
    - 247                        let v:number = r[c];
    - 248                        if (domain[0]===undefined) { domain[0] = v; }
    - 249                        if (domain[1]===undefined) { domain[1] = v; }
    - 250                        if (v!==undefined && v!==null) {
    - 251                            if (v - 252                            else if (v>domain[1]) { domain[1] = v; }
    - 253                        }
    - 254                    });
    - 255            }
    - 256        }
    - 257        return domain;
    - 258    }
    - 259
    - 260    public castData() {
    - 261        this.meta.forEach((c:MetaStruct) => {
    - 262            const col = c.column;
    - 263            if (!c.cast) {
    - 264                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    - 265            }
    - 266            c.cast = true;
    - 267        });
    - 268    }
    - 269
    - 270    /**
    - 271     * filters this data set and returns a new data set with a 
    - 272     * shallow copy of rows that pass the `condition`.
    - 273     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    - 274     * @param condition filters 
    - 275     * @return a new Data object with rows that pass the filter
    - 276     */

    - 277    public filter(condition:Condition):Data {
    - 278        return filter(this, condition);
    - 279    }
    - 280
    - 281    /**
    - 282     * @description Sorts the rows of values based on the result of the `sortFn`, 
    - 283     * which behaves similarly to the Array.sort method.  
    - 284     * Two modes are supported:
    - 285     * # Array Mode
    - 286     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    - 287     * This allows for complex sorts, combining conditions across multiple columns.
    - 288     * ```
    - 289     * data.sort((row1, row2) => row1[5] - row2[5] );
    - 290     * ```
    - 291     * # Column mode
    - 292     * If `col` is specified, either as index or by column name, the respective column value is passed
    - 293     * into `sortFn`. This allows filtering for simple conditions.

    - 294     * **The specified column will be automatically cast prior to sorting**

    - 295     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    - 296     * @param col optional; the data column to use for sorting. 
    - 297     * @param sortFn a function to implement the conditions, 
    - 298     * follows the same specifications as the function passed to Array.sort(). 
    - 299     * Some predefined sort function can be invoked by providing a 
    - 300     * respective string instead of a function. The following functions are defined:
    - 301        
    - 302        
    - 303        
    - 304        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    - 305     * @return the Data object in order to allow for chaining.
    - 306     */

    - 307    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    - 308        let fn = sortFn;
    - 309        if (!col) {
    - 310            this.data.sort(fn);
    - 311        } else {
    - 312            col = this.colNumber(col);
    - 313            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b - 314            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    - 315            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    - 316        }
    - 317        return this;
    - 318    }
    - 319
    - 320    /** 
    - 321    *  Maps one or more columns in each rows of values based 
    - 322     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    - 323     * Two modes are supported:
    - 324     * # Array Mode
    - 325     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    - 326     * This allows for complex mapping combining conditions across multiple columns.
    - 327     * ```
    - 328     * data.map(function(values){ 
    - 329     *    values[1] = values[3] * values[5]; 
    - 330     *    return values; 
    - 331     * });
    - 332     * ```
    - 333     * Be sure to return the `values` array as a result.
    - 334     * # Column mode
    - 335     * If `col` is specified, either as index or by column name, the respective column value is passed
    - 336     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    - 337     * ```
    - 338     * data.map('Price', function(value, i, values) { 
    - 339     *    return value * 2; 
    - 340     * });
    - 341     * ```
    - 342     * @param col the data column, or columns, to apply the mapping to. 
    - 343     * @param mapFn a function to implement the mapping,
    - 344     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    - 345     * - `val`: the column value in the current row
    - 346     * - `c`: the column index in the current row
    - 347     * - `i`: the row index 
    - 348     * - `rows`: the rows being iterated over
    - 349`    * 
    - 350     * follows the same specifications as the function passed to Array.map().

    - 351     * For column mode, some predefined map functions can be invoked by providing a 
    - 352     * respective string instead of a function. The following functions are defined:
    - 353        
    - 354        
    - 355        
    - 356        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    - 357     * @return a new Data object containing the mapping.
    - 358     */

    - 359    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    - 360        const noop = (val:any) => val;
    - 361        const cumulate = () => { 
    - 362            let sum=0; 
    - 363            return (val:number, i:number) => { sum += +val; return sum; };
    - 364        };
    - 365        function getFn() {
    - 366            let fn; // define fn inside each col loop to ensure initialization
    - 367            switch (mapFn) {
    - 368                case 'cumulate': fn = cumulate(); break;
    - 369                case 'noop':     fn = noop; break;
    - 370                default:         fn = mapFn;
    - 371            }
    - 372            return fn;
    - 373        }
    - 374
    - 375        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    - 376
    - 377        const names = col['length']? col : [col];            
    - 378        names.map((cn:ColumnReference) => {
    - 379            const c = this.colNumber(cn);
    - 380            let fn = getFn(); // define fn inside each col loop to ensure initialization
    - 381            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    - 382                row[c] = fn(row[c], c, i, rows); 
    - 383                return row;
    - 384            });
    - 385        });
    - 386        return result;
    - 387    }
    - 388
    - 389    //----------------------------
    - 390    // private part
    - 391    //----------------------------
    - 392    private data: DataRow[]    = [];
    - 393    private meta: MetaStruct[] = [];
    - 394    private name: string;
    - 395
    - 396    private getMeta(col:ColumnReference):MetaStruct { 
    - 397        if (!this.meta) { this.meta = []; }
    - 398        if (!this.meta[col]) { return undefined; }
    - 399        this.meta[col].accessed = true;
    - 400        return this.meta[col]; 
    - 401    }
    - 402
    - 403    /**
    - 404     * sets `data` to the existing data set. If data has previously been set, 
    - 405     * `data` will be added to the end of the list if all `names`  match those of the 
    - 406     * existing set. 
    - 407     * @param data the data to add
    - 408     * @param names an array of names that match the columns
    - 409     * @param autoType unless set to false, the method will attempt to determine the 
    - 410     * type of data and automatically cast data points to their correct value
    - 411     */

    - 412    private setData(data:DataRow[], names:string[], autoType=true):void {
    - 413        this.meta = [];
    - 414        this.data = data;
    - 415        if (!names) {
    - 416            console.log();
    - 417        }
    - 418        names.forEach((col:string) => this.colAdd(col));
    - 419        names.forEach((col:string) => this.findTypes(col));
    - 420        this.castData();
    - 421    }
    - 422
    - 423    /**
    - 424     * Determines the type of data in `col`. An array of counts is created for all
    - 425     * encountered types, sorted by descending frequency. THe most likely type in position 0
    - 426     * of the array is returned.
    - 427     * @param col the index of the column to be typed. 
    - 428     * @return the most likely type of data in `col`.
    - 429     */

    - 430    private findTypes(col:ColumnReference):string {
    - 431        const m = this.getMeta(col);
    - 432        const types:TypeStruct[] = [];
    - 433        Object.keys(Data.type).forEach((t:string) => {
    - 434            const ts = { type: Data.type[t], count: 0 }; 
    - 435            types.push(ts);
    - 436            types[Data.type[t]] = ts;
    - 437        });
    - 438        for (let v of this.allRows(col)) {
    - 439            const t = this.findType(v);
    - 440            if (t !== null) { types[t].count++; }
    - 441        }
    - 442        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    - 443            if (a.type==='currency'&&a.count>0) { return -1; }
    - 444            if (b.type==='currency'&&b.count>0) { return 1; }
    - 445            return b.count - a.count;
    - 446        });
    - 447        m.types = types;
    - 448        return types[0].type;
    - 449    }
    - 450
    - 451    /**
    - 452     * @description determines the data type. Supported types are 
    - 453     * ```
    - 454     * 'date':    sample represents a Date, either as a Date object or a String 
    - 455     * 'number':  sample represents a number
    - 456     * 'percent': sample represents a percentage (special case of a real number)
    - 457     * 'nominal': sample represents a nominal (ordinal or categorical) value
    - 458     * ```
    - 459     * @param val the value to bve typed.
    - 460     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    - 461     */

    - 462    private findType(val:DataVal) {
    - 463        if (val && val!=='') {
    - 464            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    - 465            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    - 466
    - 467            // else: val is a string:
    - 468            const strVal = ''+val;
    - 469            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    - 470            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    - 471            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    - 472            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    - 473
    - 474            // european large number currency representation: '$dd[,ddd]'
    - 475            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    - 476                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    - 477                    return Data.type.currency; 
    - 478                }
    - 479            }
    - 480            switch (strVal.toLowerCase()) {
    - 481                case "null": break;
    - 482                case "#ref!": break;
    - 483                default: if (val.length>0) { return Data.type.name; }
    - 484            }
    - 485        }
    - 486        return null;
    - 487    }    
    - 488
    - 489    /**
    - 490     * A generator that provides the specified column value for each row in `Data` in sequence. 
    - 491     * @param column 
    - 492     */

    - 493    private * allRows(column:ColumnReference):Iterable {
    - 494        const c = this.colNumber(column);
    - 495        for (let r=0; r - 496            yield this.data[r][c];
    - 497        }
    - 498    }
    - 499
    - 500    /**
    - 501     * @param val the string to convert to a date
    - 502     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    - 503     * @returns a new Date object parsed from `str`.
    - 504     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    - 505     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    - 506     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    - 507     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    - 508     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    - 509     */

    - 510    private toDate(val:DataVal, limitYear=1970):Date {
    - 511        let d:Date;
    - 512        if (val instanceof Date) { d = val; }
    - 513                            else { d = new Date(val); }   
    - 514        let yr=d.getFullYear();
    - 515        if (yr < 100) { 
    - 516            yr += 1900; 
    - 517            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    - 518        }
    - 519        return d;
    - 520    }
    - 521
    - 522    /**
    - 523     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    - 524     * does not match any of the previous keywords, no casting occurs.
    - 525     * @param sample The value to cast.
    - 526     * @returns The result of the cast. 
    - 527     * @description Casts the sample to the specified data type.
    - 528     */

    - 529    private castVal(type:string, val:DataVal):DataVal {
    - 530        switch (type) {
    - 531            case Data.type.date:    if (val instanceof Date) { return val; }
    - 532                            val = this.toDate(val);
    - 533                            if (isNaN(val.getTime())) { val = null; }
    - 534                            break;
    - 535            case Data.type.percent: if (typeof val === 'string') {
    - 536                                const num = parseFloat(val);
    - 537                                val = (val).endsWith('%')? num/100 : num;
    - 538                            } 
    - 539                            if (isNaN(val)) { val = null; }
    - 540                            break;
    - 541            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    - 542             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    - 543             /* falls through */
    - 544            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    - 545                            if (isNaN(val)) { val = null; }
    - 546                            break;
    - 547            default:        val = ''+val;
    - 548        }
    - 549        return val;
    - 550     }     
    - 551}
    - - \ No newline at end of file diff --git a/src/DataFilters.html b/src/DataFilters.html deleted file mode 100644 index 7669d54..0000000 --- a/src/DataFilters.html +++ /dev/null @@ -1,267 +0,0 @@ - - -

    src/DataFilters.ts

    -
       1
    -   2/**
    -   3* Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object. 
    -   4* Each row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object. 
    -   5
    -   6* # Condition construction
    -   7*  
    -   8* ### General Condition
    -   9* ```
    -  10* Condition = 
    -  11*    IndexCondition            -> conditions on the row index
    -  12* || RecursiveCondition        -> (set of) conditions on column values
    -  13* ```
    -  14
    -  15* ### IndexCondition
    -  16* ```
    -  17* IndexCondition =
    -  18*    rowIndex:number           -> true if row index matches
    -  19* ```
    -  20
    -  21* ### RecursiveCondition
    -  22* ```
    -  23* RecursiveCondition =
    -  24*    OrCondition               -> OR: true if any compound condition is true
    -  25* || AndCondition              -> AND: true if all compound conditions are true
    -  26
    -  27* OrCondition =                -> OR: true if
    -  28*    AndCondition[]               -> any of the AndConditions are true
    -  29* || IndexCondition[]             -> any of thr IndexConditions are true
    -  30
    -  31* AndCondition =               -> AND: true if
    -  32*    SetAndCondition              -> all SetAndConditions are true
    -  33* || TermAndCondition             -> or if all TermAndConditions are true
    -  34*
    -  35* SetAndCondition = {          -> AND: true if all sub-conditions are true
    -  36*    'or':  RecursiveCondition    -> true if any RecursiveCondition is true
    -  37* || 'and': RecursiveCondition    -> true if all RecursiveCondition are true
    -  38* || 'not': RecursiveCondition    -> true if the condition is false
    -  39*
    -  40* TermAndCondition = {         -> Terminal AND: true if all terminal sub-conditions are true
    -  41*    colDesc:colValue             -> true if colValue matches 
    -  42* || colDesc:[colValue, ...]      -> true if any of the colValues match
    -  43* || colDesc:function(value,row)  -> true if function returns true 
    -  44* }
    -  45
    -  46* colDesc = either column name or index
    -  47* ```
    -  48
    -  49* ### Practical Tips
    -  50* ```
    -  51*    {'or': [recurCond, ...]}    -> OR, same as [recurCond, ...]
    -  52* || {'or': {SetCond, ...}}      -> OR, same as [SetCond, ...]
    -  53* || {'and': [recurCond, ...]}   -> AND, true if all recurCond are true
    -  54* || {'and': {SetCond, ...}}     -> AND, same as {SetCond, ...}
    -  55* || {'not': {SetCond, ...}}     -> NAND: true if the SetCond are true
    -  56* || {'not': [recurCond, ...]}   -> NOR: true if any of the recurCond are true
    -  57* ```
    -  58*      
    -  59* # Example
    -  60
    -  61
    -  62* const colNames = ['Name', 'Value', 'Start', 'End'];
    -  63* const rows = [
    -  64*   ['Harry', '100', '3/1/14', '11/20/14'], 
    -  65*   ['Mary', '1500', '7/1/14',  '9/30/14'],
    -  66*   ['Peter', '400', '5/20/14', '4/30/15'],  
    -  67*   ['Jane', '700', '11/13/14', '8/15/15']
    -  68* ]
    -  69* const data = new hsdatab.Data({colNames:colNames, rows:rows});
    -  70
    -  71* queries = [
    -  72*   ['0', undefined,                           'undefined query => pass all'],
    -  73*   ['1', [],                                  'empty OR:  []   => fail all'],
    -  74*   ['2', {},                                  'empty AND: {}   => pass all'],
    -  75*   ['3', 1,                                   '2nd row: pass row 1'],
    -  76*   ['4', [1,3],                               '2nd+4th: pass rows: 1 and 3'],
    -  77*   ['5', {Name:"Jane"},                       'Name is Jane'],
    -  78*   ['6', {1:1500},                            'Column 2 is 1500'],
    -  79*   ['7', {Name:["Peter", "Jane"]},            'Name is Peter or Jane'],
    -  80*   ['8', [{Name:"Peter"}, {Value:1500}],      'Name is Peter or Value is 1500'],
    -  81*   ['9', {or:{Name:"Peter", Value:1500}},     'OR:  same as 8:'],
    -  82*   ['A', {or:[{Name:"Peter"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],
    -  83*   ['B', {Name:"Peter", Value:400},           'Name is Peter and Value is 400'],
    -  84*   ['C', {and:{Name:"Peter", Value:400}},     'AND: {Name is Peter, Value is 400}'],
    -  85*   ['D', {and:{Name:"Peter", Value:1500}},    'AND: {Name is Peter, Value is 1500}'],
    -  86*   ['E', {and:[{Name:"Peter"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],
    -  87*   ['F', {and:[{Name:"Peter"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],
    -  88*   ['G', {not:{Name:"Peter", Value:400}},     'NAND: not {Name is Peter and Value is 400}'],
    -  89*   ['H', {not:{Name:"Peter", Value:1500}},    'NAND: not {Name is Peter and Value is 1500}'],
    -  90*   ['I', {not:[{Name:"Peter"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],
    -  91*   ['J', {Name:(v) => v.length===4},          'Name has 4 letters']
    -  92* ];
    -  93*
    -  94* m.mount(root, { 
    -  95*   view:() => m('', [
    -  96*       m('h3', 'Given the data set:'),
    -  97*       m('table#data', [
    -  98*           m('tr', colNames.map(n => m('th', n))),
    -  99*           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    - 100*       ]),
    - 101*       m('h3', 'The following queries yield:'),
    - 102*       m('table', [
    - 103*           m('tr', [m('th','#'), m('th','Query'), m('th',"Live Result, by 'Name' field")]),
    - 104*           ...queries.map(q => {
    - 105*               const result = data.filter(q[1]).getColumn('Name').join(', ');
    - 106*               return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);
    - 107*           })
    - 108*       ])
    - 109*   ])
    - 110* });
    - 111
    - 112
    - 113*   $exampleID { height: 600px; }
    - 114*   #data th { width:15%; }
    - 115*   table { 
    - 116*       font-size: 10pt;
    - 117*       margin-left: 10px;
    - 118*   }
    - 119
    - 120*      
    - 121*/

    - 122
    - 123/** */
    - 124import { Data,
    - 125         DataVal,
    - 126         DataRow
    - 127} from './Data'; 
    - 128
    - 129export type Condition = IndexCondition | RecursiveCondition;
    - 130
    - 131/** true if row index matches the number(s) */
    - 132export type IndexCondition = number;
    - 133
    - 134export type RecursiveCondition = AndCondition | OrCondition;
    - 135export type OrCondition = AndCondition[] | IndexCondition[];
    - 136export type AndCondition = SetAndCondition | TermAndCondition;
    - 137
    - 138export interface SetAndCondition {
    - 139    or?: RecursiveCondition;
    - 140    and?:RecursiveCondition;
    - 141    not?:RecursiveCondition;
    - 142};
    - 143
    - 144export interface TermAndCondition { 
    - 145    [colDesc:string]: 
    - 146        DataVal 
    - 147      | DataVal[]
    - 148      | TermConditionFunction
    - 149    ;
    - 150};
    - 151
    - 152export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean;
    - 153
    - 154
    - 155function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { 
    - 156    const col = colNumber(name);
    - 157    const valIsFunction = (typeof val === 'function');
    - 158    const valIsArray = ((typeof val === 'object') && (val.length!==undefined));
    - 159    if (isNaN(col)) { 
    - 160        console.log(`column name '${name}' cannot be resolved in terminal condition ${name}=${val}`);
    - 161        console.log(row);
    - 162        return false; // -> this condition is not met;
    - 163    } else if (valIsFunction) { 
    - 164        // query true if function evaluates to true
    - 165        return val(row[col], row);
    - 166    } else if (valIsArray) {
    - 167        // query true if empty array, or at least one c true
    - 168        return (val.length === 0) || val.some((v:any) => row[col] === v); 
    - 169    } else { // object: all conditions have to be met, unless specified as or
    - 170        return (row[col] === val); 
    - 171    }
    - 172}
    - 173
    - 174/**
    - 175 * applies `condition` to a row of data and returns `true` if the row passes.
    - 176 * @param condition the complex condition to test against
    - 177 * @param r the row index in the data set
    - 178 * @param row the row values 
    - 179 * @param and 
    - 180 */

    - 181function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and=true):boolean { 
    - 182    let orResult = false;
    - 183    let andResult= true;          
    - 184    // undefined condition is TRUE
    - 185    if (condition===undefined) { return true; }
    - 186    
    - 187    // Simple Index Condition on row index:
    - 188    else if (typeof condition === 'number') { return (condition === r); }
    - 189
    - 190    // Recursive Condition - OR: [...], AND {...}: 
    - 191    else if (typeof condition === 'object') {
    - 192        // array -> or condition on a list of row indices or compound conditions
    - 193        const mc = condition;
    - 194
    - 195        // OR condition: [...] 
    - 196        if (mc.length !== undefined) {            
    - 197            return (mc.length === 0)? 
    - 198                // empty OR is false:
    - 199                false : 
    - 200                // else: OR is true if any sub-condition is met
    - 201                mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, false));
    - 202        } 
    - 203        // AND condition: {...}
    - 204        else { 
    - 205            for (const name in condition) {
    - 206                let conditionMet = and; // initialize with false for OR, and true for AND conjunction
    - 207                const setCond = condition;
    - 208                
    - 209                // resolve SetConditions:
    - 210                switch (name) {
    - 211                    case 'or':  conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break;
    - 212                    case 'and': conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break;
    - 213                    case 'not': conditionMet = !resolveCondition(setCond.not, row, r, colNumber, true); break;
    - 214                    default:    conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); 
    - 215                }
    - 216                if (conditionMet) { orResult  = true;  if(!and) { break; }} // OR conjunction: exit for name loop if condition met
    - 217                             else { andResult = false; if(and)  { break; }} // AND conjunction: exit for name loop if condition not met
    - 218            }
    - 219        }    
    - 220    } else {
    - 221        console.error(`unrecognized condition: ${JSON.stringify(condition)}`);
    - 222        return false;
    - 223    }
    - 224    return and? andResult : orResult;
    - 225}
    - 226
    - 227/**
    - 228 * filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which
    - 229 * `cond` holds true.
    - 230 * @param data the `Data` object to filter
    - 231 * @param cond the complex condition to test against
    - 232 * @return a new `Data` object with the filtered rows 
    - 233 */

    - 234export function filter(data:Data, cond:Condition):Data {
    - 235    const colNumber = (name:string):number => data.colNumber(name);
    - 236    try {
    - 237        return new Data({
    - 238            name:     data.getName(),
    - 239            colNames: data.colNames(), 
    - 240            rows:data.getData().filter((row:DataRow, i:number) => {
    - 241                const keep = resolveCondition(cond, row, i, colNumber);
    - 242                return keep;
    - 243            })
    - 244        });
    - 245    } catch(err) {
    - 246        console.log(err);
    - 247        console.log(err.stack);
    - 248    }
    - 249}
    - 250
    - - \ No newline at end of file diff --git a/src/index.html b/src/index.html deleted file mode 100644 index 07a3840..0000000 --- a/src/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - -

    src/index.ts

    -
       1export { NumRange,
    -   2         NumDomain,
    -   3         DateDomain,
    -   4         NameDomain,
    -   5         Domain,
    -   6         ColumnReference,
    -   7         DataVal,
    -   8         DataRow,
    -   9         DataSet
    -  10        }       from './Data';
    -  11
    -  12export { Data } from './Data';
    -  13export { Condition} from './DataFilters';
    -  14
    -  15
    - - \ No newline at end of file diff --git a/src/overview.html b/src/overview.html deleted file mode 100644 index 28af118..0000000 --- a/src/overview.html +++ /dev/null @@ -1,96 +0,0 @@ - - -

    src/overview.ts

    -
       1/**
    -   2 * # hsDatab
    -   3 * 
    -   4 * Helpful Scripts framework-independent data management functions. 
    -   5 * 
    -   6 * *hsdatab* provides a JavaScript-based data management and query mechanism.
    -   7 * Data is managed in a simple in-memory database that holds data in rows of columns. 
    -   8 * It autodetermines the types of data held in each column, along with the 
    -   9 * domain range for each column of data. 
    -  10 * Complex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure. 
    -  11 * 
    -  12 * ## Data Types
    -  13 * supported {@link Data.Data.type data types} include
    -  14 * - **number**: numeric values
    -  15 * - **name**: nominal values, represented by arbitrary words
    -  16 * - **date**: date values
    -  17 * - **currency**: Currently supported: '$dd[,ddd]'
    -  18 * - **percent**: 'd%'
    -  19 * 
    -  20 * ## Data Class
    -  21 * The fundamental object in this library is {@link Data.Data `Data`}, 
    -  22 * a simple row-column based database object, 
    -  23 * featuring named columns, sorting, mapping and filtering functions.
    -  24 *
    -  25 * ## Example
    -  26 * 
    -  27 * 
    -  28 * const colNames = ['Name', 'Value', 'Start', 'End'];
    -  29 * const rows = [
    -  30 *   ['Harry', '100', '3/1/14', '11/20/14'], 
    -  31 *   ['Mary', '1500', '7/1/14',  '9/30/14'],
    -  32 *   ['Peter', '400', '5/20/14', '4/30/15'],  
    -  33 *   ['Jane', '700', '11/13/14', '8/15/15']
    -  34 * ]
    -  35 * const data = new hsdatab.Data({colNames:colNames, rows:rows});
    -  36 * 
    -  37 * query = {Name:["Peter", "Jane"]};
    -  38 * const result = data.filter(query);
    -  39 *
    -  40 * m.mount(root, {
    -  41 *   view:() => m('', [
    -  42 *       m('h3', 'Given the data set:'),
    -  43 *       m('pre',
    -  44 *       m('table#data', [
    -  45 *           m('tr', colNames.map(n => m('th', n))),
    -  46 *           ...rows.map(row => m('tr', [
    -  47 *              m('td', row[0]),
    -  48 *              m('td', row[1]),
    -  49 *              m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),
    -  50 *              m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)
    -  51 *          ]))
    -  52 *       ])),
    -  53 *       m('h3', 'The column types and domains are'),
    -  54 *       m('pre', m('table', 
    -  55 *                  m('tr', m('th', 'Column'),   m('th', 'Type'),   m('th', 'Domain')),
    -  56 *                  m('tr', m('td', '"Name":'),  m('td', data.colType("Name")),   m('td', data.findDomain("Name").join(', '))),
    -  57 *                  m('tr', m('td', '"Value":'), m('td', data.colType("Value")),  m('td', data.findDomain("Value").join(' - '))),
    -  58 *                  m('tr', m('td', '"Start":'), m('td', data.colType("Start")),  m('td', data.findDomain("Start").map(d => d.toDateString()).join(' - '))),
    -  59 *                  m('tr', m('td', '"Stop":'),  m('td', data.colType("End")),    m('td', data.findDomain("End").map(d => d.toDateString()).join(' - ')))
    -  60 *       )),
    -  61 *       m('h3', 'The query:'),
    -  62 *       m('code', '{Name:["Peter", "Jane"]}'),
    -  63 *       m('h3', 'yields results with "Name"'),
    -  64 *       m('code', result.getColumn('Name').join(', '))
    -  65 *   ])
    -  66 * });
    -  67 * 
    -  68 * 
    -  69 *   $exampleID { height: 600px; }
    -  70 *   #data th { width:15%; }
    -  71 *   #data  { font-size: 11pt; }
    -  72 * 
    -  73 *      
    -  74 */

    -  75
    -  76 /** */
    -  77
    -  78 
    -  79
    - - \ No newline at end of file From 877c21c98a628ed26631da0846aa4a9706948659 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sat, 16 Jun 2018 19:00:06 +0200 Subject: [PATCH 12/17] updated docs --- docs/data/hsDatab.json | 775 +++++++++++++++++++++++--------------- docs/src/Data.html | 2 +- docs/src/DataFilters.html | 2 +- docs/src/index.html | 2 +- docs/src/overview.html | 2 +- 5 files changed, 479 insertions(+), 304 deletions(-) diff --git a/docs/data/hsDatab.json b/docs/data/hsDatab.json index a535f27..843d869 100644 --- a/docs/data/hsDatab.json +++ b/docs/data/hsDatab.json @@ -5,7 +5,7 @@ "flags": {}, "children": [ { - "id": 42, + "id": 49, "name": "\"Data\"", "kind": 1, "kindString": "External module", @@ -16,7 +16,7 @@ "comment": {}, "children": [ { - "id": 56, + "id": 63, "name": "Data", "kind": 128, "kindString": "Class", @@ -28,7 +28,7 @@ }, "children": [ { - "id": 67, + "id": 74, "name": "constructor", "kind": 512, "kindString": "Constructor", @@ -37,14 +37,14 @@ }, "signatures": [ { - "id": 68, + "id": 75, "name": "new Data", "kind": 16384, "kindString": "Constructor signature", "flags": {}, "parameters": [ { - "id": 69, + "id": 76, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -54,14 +54,14 @@ "type": { "type": "reference", "name": "DataSet", - "id": 43 + "id": 50 } } ], "type": { "type": "reference", "name": "Data", - "id": 56 + "id": 63 } } ], @@ -74,7 +74,7 @@ ] }, { - "id": 117, + "id": 124, "name": "data", "kind": 1024, "kindString": "Property", @@ -94,13 +94,13 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 152 + "id": 159 } }, "defaultValue": " []" }, { - "id": 118, + "id": 125, "name": "meta", "kind": 1024, "kindString": "Property", @@ -120,13 +120,13 @@ "elementType": { "type": "reference", "name": "MetaStruct", - "id": 50 + "id": 57 } }, "defaultValue": " []" }, { - "id": 119, + "id": 126, "name": "name", "kind": 1024, "kindString": "Property", @@ -147,7 +147,7 @@ } }, { - "id": 134, + "id": 141, "name": "allRows", "kind": 2048, "kindString": "Method", @@ -157,7 +157,7 @@ }, "signatures": [ { - "id": 135, + "id": 142, "name": "allRows", "kind": 4096, "kindString": "Call signature", @@ -167,7 +167,7 @@ }, "parameters": [ { - "id": 136, + "id": 143, "name": "column", "kind": 32768, "kindString": "Parameter", @@ -178,7 +178,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ], @@ -189,7 +189,7 @@ { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } ] } @@ -204,7 +204,7 @@ ] }, { - "id": 104, + "id": 111, "name": "castData", "kind": 2048, "kindString": "Method", @@ -214,7 +214,7 @@ }, "signatures": [ { - "id": 105, + "id": 112, "name": "castData", "kind": 4096, "kindString": "Call signature", @@ -234,7 +234,7 @@ ] }, { - "id": 141, + "id": 148, "name": "castVal", "kind": 2048, "kindString": "Method", @@ -244,7 +244,7 @@ }, "signatures": [ { - "id": 142, + "id": 149, "name": "castVal", "kind": 4096, "kindString": "Call signature", @@ -260,7 +260,7 @@ }, "parameters": [ { - "id": 143, + "id": 150, "name": "type", "kind": 32768, "kindString": "Parameter", @@ -274,7 +274,7 @@ } }, { - "id": 144, + "id": 151, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -282,14 +282,14 @@ "type": { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } } ], "type": { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } } ], @@ -302,7 +302,7 @@ ] }, { - "id": 82, + "id": 89, "name": "colAdd", "kind": 2048, "kindString": "Method", @@ -312,7 +312,7 @@ }, "signatures": [ { - "id": 83, + "id": 90, "name": "colAdd", "kind": 4096, "kindString": "Call signature", @@ -323,7 +323,7 @@ }, "parameters": [ { - "id": 84, + "id": 91, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -352,7 +352,7 @@ ] }, { - "id": 85, + "id": 92, "name": "colInitialize", "kind": 2048, "kindString": "Method", @@ -362,7 +362,7 @@ }, "signatures": [ { - "id": 86, + "id": 93, "name": "colInitialize", "kind": 4096, "kindString": "Call signature", @@ -372,7 +372,7 @@ }, "parameters": [ { - "id": 87, + "id": 94, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -383,11 +383,11 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } }, { - "id": 88, + "id": 95, "name": "initializer", "kind": 32768, "kindString": "Parameter", @@ -416,7 +416,7 @@ ] }, { - "id": 92, + "id": 99, "name": "colName", "kind": 2048, "kindString": "Method", @@ -426,7 +426,7 @@ }, "signatures": [ { - "id": 93, + "id": 100, "name": "colName", "kind": 4096, "kindString": "Call signature", @@ -437,7 +437,7 @@ }, "parameters": [ { - "id": 94, + "id": 101, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -445,7 +445,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ], @@ -464,7 +464,7 @@ ] }, { - "id": 95, + "id": 102, "name": "colNames", "kind": 2048, "kindString": "Method", @@ -474,7 +474,7 @@ }, "signatures": [ { - "id": 96, + "id": 103, "name": "colNames", "kind": 4096, "kindString": "Call signature", @@ -501,7 +501,7 @@ ] }, { - "id": 89, + "id": 96, "name": "colNumber", "kind": 2048, "kindString": "Method", @@ -511,7 +511,7 @@ }, "signatures": [ { - "id": 90, + "id": 97, "name": "colNumber", "kind": 4096, "kindString": "Call signature", @@ -522,7 +522,7 @@ }, "parameters": [ { - "id": 91, + "id": 98, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -530,7 +530,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ], @@ -549,7 +549,7 @@ ] }, { - "id": 97, + "id": 104, "name": "colType", "kind": 2048, "kindString": "Method", @@ -559,7 +559,7 @@ }, "signatures": [ { - "id": 98, + "id": 105, "name": "colType", "kind": 4096, "kindString": "Call signature", @@ -570,7 +570,7 @@ }, "parameters": [ { - "id": 99, + "id": 106, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -578,7 +578,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ], @@ -597,7 +597,7 @@ ] }, { - "id": 75, + "id": 82, "name": "export", "kind": 2048, "kindString": "Method", @@ -607,7 +607,7 @@ }, "signatures": [ { - "id": 76, + "id": 83, "name": "export", "kind": 4096, "kindString": "Call signature", @@ -618,7 +618,7 @@ "type": { "type": "reference", "name": "DataSet", - "id": 43 + "id": 50 } } ], @@ -631,7 +631,7 @@ ] }, { - "id": 106, + "id": 113, "name": "filter", "kind": 2048, "kindString": "Method", @@ -641,7 +641,7 @@ }, "signatures": [ { - "id": 107, + "id": 114, "name": "filter", "kind": 4096, "kindString": "Call signature", @@ -652,7 +652,7 @@ }, "parameters": [ { - "id": 108, + "id": 115, "name": "condition", "kind": 32768, "kindString": "Parameter", @@ -663,14 +663,14 @@ "type": { "type": "reference", "name": "Condition", - "id": 9 + "id": 16 } } ], "type": { "type": "reference", "name": "Data", - "id": 56 + "id": 63 } } ], @@ -683,7 +683,7 @@ ] }, { - "id": 100, + "id": 107, "name": "findDomain", "kind": 2048, "kindString": "Method", @@ -693,7 +693,7 @@ }, "signatures": [ { - "id": 101, + "id": 108, "name": "findDomain", "kind": 4096, "kindString": "Call signature", @@ -704,7 +704,7 @@ }, "parameters": [ { - "id": 102, + "id": 109, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -717,11 +717,11 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } }, { - "id": 103, + "id": 110, "name": "domain", "kind": 32768, "kindString": "Parameter", @@ -734,14 +734,14 @@ "type": { "type": "reference", "name": "Domain", - "id": 149 + "id": 156 } } ], "type": { "type": "reference", "name": "Domain", - "id": 149 + "id": 156 } } ], @@ -754,7 +754,7 @@ ] }, { - "id": 131, + "id": 138, "name": "findType", "kind": 2048, "kindString": "Method", @@ -764,7 +764,7 @@ }, "signatures": [ { - "id": 132, + "id": 139, "name": "findType", "kind": 4096, "kindString": "Call signature", @@ -780,7 +780,7 @@ }, "parameters": [ { - "id": 133, + "id": 140, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -791,7 +791,7 @@ "type": { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } } ], @@ -810,7 +810,7 @@ ] }, { - "id": 128, + "id": 135, "name": "findTypes", "kind": 2048, "kindString": "Method", @@ -820,7 +820,7 @@ }, "signatures": [ { - "id": 129, + "id": 136, "name": "findTypes", "kind": 4096, "kindString": "Call signature", @@ -831,7 +831,7 @@ }, "parameters": [ { - "id": 130, + "id": 137, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -842,7 +842,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ], @@ -861,7 +861,7 @@ ] }, { - "id": 79, + "id": 86, "name": "getColumn", "kind": 2048, "kindString": "Method", @@ -871,7 +871,7 @@ }, "signatures": [ { - "id": 80, + "id": 87, "name": "getColumn", "kind": 4096, "kindString": "Call signature", @@ -881,7 +881,7 @@ }, "parameters": [ { - "id": 81, + "id": 88, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -892,7 +892,7 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ], @@ -901,7 +901,7 @@ "elementType": { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } } } @@ -915,7 +915,7 @@ ] }, { - "id": 77, + "id": 84, "name": "getData", "kind": 2048, "kindString": "Method", @@ -925,7 +925,7 @@ }, "signatures": [ { - "id": 78, + "id": 85, "name": "getData", "kind": 4096, "kindString": "Call signature", @@ -938,7 +938,7 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 152 + "id": 159 } } } @@ -952,7 +952,7 @@ ] }, { - "id": 120, + "id": 127, "name": "getMeta", "kind": 2048, "kindString": "Method", @@ -962,14 +962,14 @@ }, "signatures": [ { - "id": 121, + "id": 128, "name": "getMeta", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 122, + "id": 129, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -977,14 +977,14 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ], "type": { "type": "reference", "name": "MetaStruct", - "id": 50 + "id": 57 } } ], @@ -997,7 +997,7 @@ ] }, { - "id": 70, + "id": 77, "name": "getName", "kind": 2048, "kindString": "Method", @@ -1007,7 +1007,7 @@ }, "signatures": [ { - "id": 71, + "id": 78, "name": "getName", "kind": 4096, "kindString": "Call signature", @@ -1030,7 +1030,7 @@ ] }, { - "id": 72, + "id": 79, "name": "import", "kind": 2048, "kindString": "Method", @@ -1040,7 +1040,7 @@ }, "signatures": [ { - "id": 73, + "id": 80, "name": "import", "kind": 4096, "kindString": "Call signature", @@ -1050,7 +1050,7 @@ }, "parameters": [ { - "id": 74, + "id": 81, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1061,7 +1061,7 @@ "type": { "type": "reference", "name": "DataSet", - "id": 43 + "id": 50 } } ], @@ -1080,7 +1080,7 @@ ] }, { - "id": 113, + "id": 120, "name": "map", "kind": 2048, "kindString": "Method", @@ -1090,7 +1090,7 @@ }, "signatures": [ { - "id": 114, + "id": 121, "name": "map", "kind": 4096, "kindString": "Call signature", @@ -1101,7 +1101,7 @@ }, "parameters": [ { - "id": 115, + "id": 122, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -1115,21 +1115,21 @@ { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 }, { "type": "array", "elementType": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ] } }, { - "id": 116, + "id": 123, "name": "mapFn", "kind": 32768, "kindString": "Parameter", @@ -1147,7 +1147,7 @@ { "type": "reference", "name": "mapFn", - "id": 116 + "id": 123 } ] } @@ -1156,7 +1156,7 @@ "type": { "type": "reference", "name": "Data", - "id": 56 + "id": 63 } } ], @@ -1169,7 +1169,7 @@ ] }, { - "id": 123, + "id": 130, "name": "setData", "kind": 2048, "kindString": "Method", @@ -1179,7 +1179,7 @@ }, "signatures": [ { - "id": 124, + "id": 131, "name": "setData", "kind": 4096, "kindString": "Call signature", @@ -1189,7 +1189,7 @@ }, "parameters": [ { - "id": 125, + "id": 132, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1202,12 +1202,12 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 152 + "id": 159 } } }, { - "id": 126, + "id": 133, "name": "names", "kind": 32768, "kindString": "Parameter", @@ -1224,7 +1224,7 @@ } }, { - "id": 127, + "id": 134, "name": "autoType", "kind": 32768, "kindString": "Parameter", @@ -1254,7 +1254,7 @@ ] }, { - "id": 109, + "id": 116, "name": "sort", "kind": 2048, "kindString": "Method", @@ -1264,7 +1264,7 @@ }, "signatures": [ { - "id": 110, + "id": 117, "name": "sort", "kind": 4096, "kindString": "Call signature", @@ -1280,7 +1280,7 @@ }, "parameters": [ { - "id": 111, + "id": 118, "name": "sortFn", "kind": 32768, "kindString": "Parameter", @@ -1298,13 +1298,13 @@ { "type": "reference", "name": "sortFn", - "id": 111 + "id": 118 } ] } }, { - "id": 112, + "id": 119, "name": "col", "kind": 32768, "kindString": "Parameter", @@ -1317,14 +1317,14 @@ "type": { "type": "reference", "name": "ColumnReference", - "id": 150 + "id": 157 } } ], "type": { "type": "reference", "name": "Data", - "id": 56 + "id": 63 } } ], @@ -1337,7 +1337,7 @@ ] }, { - "id": 137, + "id": 144, "name": "toDate", "kind": 2048, "kindString": "Method", @@ -1347,7 +1347,7 @@ }, "signatures": [ { - "id": 138, + "id": 145, "name": "toDate", "kind": 4096, "kindString": "Call signature", @@ -1363,7 +1363,7 @@ }, "parameters": [ { - "id": 139, + "id": 146, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -1374,11 +1374,11 @@ "type": { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } }, { - "id": 140, + "id": 147, "name": "limitYear", "kind": 32768, "kindString": "Parameter", @@ -1408,7 +1408,7 @@ ] }, { - "id": 63, + "id": 70, "name": "toDataSet", "kind": 2048, "kindString": "Method", @@ -1419,14 +1419,14 @@ }, "signatures": [ { - "id": 64, + "id": 71, "name": "toDataSet", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 65, + "id": 72, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -1434,11 +1434,11 @@ "type": { "type": "reference", "name": "DataLiteralSet", - "id": 153 + "id": 160 } }, { - "id": 66, + "id": 73, "name": "name", "kind": 32768, "kindString": "Parameter", @@ -1454,7 +1454,7 @@ "type": { "type": "reference", "name": "DataSet", - "id": 43 + "id": 50 } } ], @@ -1467,7 +1467,7 @@ ] }, { - "id": 57, + "id": 64, "name": "type", "kind": 2097152, "kindString": "Object literal", @@ -1478,7 +1478,7 @@ }, "children": [ { - "id": 61, + "id": 68, "name": "currency", "kind": 32, "kindString": "Variable", @@ -1502,7 +1502,7 @@ "defaultValue": "\"currency\"" }, { - "id": 60, + "id": 67, "name": "date", "kind": 32, "kindString": "Variable", @@ -1526,7 +1526,7 @@ "defaultValue": "\"date\"" }, { - "id": 59, + "id": 66, "name": "name", "kind": 32, "kindString": "Variable", @@ -1550,7 +1550,7 @@ "defaultValue": "\"name\"" }, { - "id": 58, + "id": 65, "name": "number", "kind": 32, "kindString": "Variable", @@ -1574,7 +1574,7 @@ "defaultValue": "\"number\"" }, { - "id": 62, + "id": 69, "name": "percent", "kind": 32, "kindString": "Variable", @@ -1603,11 +1603,11 @@ "title": "Variables", "kind": 32, "children": [ - 61, - 60, - 59, - 58, - 62 + 68, + 67, + 66, + 65, + 69 ] } ], @@ -1629,53 +1629,53 @@ "title": "Constructors", "kind": 512, "children": [ - 67 + 74 ] }, { "title": "Properties", "kind": 1024, "children": [ - 117, - 118, - 119 + 124, + 125, + 126 ] }, { "title": "Methods", "kind": 2048, "children": [ - 134, - 104, 141, - 82, - 85, - 92, - 95, + 111, + 148, 89, - 97, - 75, - 106, - 100, - 131, - 128, - 79, + 92, + 99, + 102, + 96, + 104, + 82, + 113, + 107, + 138, + 135, + 86, + 84, + 127, 77, + 79, 120, - 70, - 72, - 113, - 123, - 109, - 137, - 63 + 130, + 116, + 144, + 70 ] }, { "title": "Object literals", "kind": 2097152, "children": [ - 57 + 64 ] } ], @@ -1688,7 +1688,7 @@ ] }, { - "id": 43, + "id": 50, "name": "DataSet", "kind": 256, "kindString": "Interface", @@ -1700,7 +1700,7 @@ }, "children": [ { - "id": 45, + "id": 52, "name": "colNames", "kind": 1024, "kindString": "Property", @@ -1726,7 +1726,7 @@ } }, { - "id": 44, + "id": 51, "name": "name", "kind": 1024, "kindString": "Property", @@ -1750,7 +1750,7 @@ } }, { - "id": 46, + "id": 53, "name": "rows", "kind": 1024, "kindString": "Property", @@ -1772,7 +1772,7 @@ "elementType": { "type": "reference", "name": "DataRow", - "id": 152 + "id": 159 } } } @@ -1782,9 +1782,9 @@ "title": "Properties", "kind": 1024, "children": [ - 45, - 44, - 46 + 52, + 51, + 53 ] } ], @@ -1797,14 +1797,14 @@ ] }, { - "id": 50, + "id": 57, "name": "MetaStruct", "kind": 256, "kindString": "Interface", "flags": {}, "children": [ { - "id": 53, + "id": 60, "name": "accessed", "kind": 1024, "kindString": "Property", @@ -1822,7 +1822,7 @@ } }, { - "id": 54, + "id": 61, "name": "cast", "kind": 1024, "kindString": "Property", @@ -1840,7 +1840,7 @@ } }, { - "id": 52, + "id": 59, "name": "column", "kind": 1024, "kindString": "Property", @@ -1858,7 +1858,7 @@ } }, { - "id": 51, + "id": 58, "name": "name", "kind": 1024, "kindString": "Property", @@ -1876,7 +1876,7 @@ } }, { - "id": 55, + "id": 62, "name": "types", "kind": 1024, "kindString": "Property", @@ -1893,7 +1893,7 @@ "elementType": { "type": "reference", "name": "TypeStruct", - "id": 47 + "id": 54 } } } @@ -1903,11 +1903,11 @@ "title": "Properties", "kind": 1024, "children": [ - 53, - 54, - 52, - 51, - 55 + 60, + 61, + 59, + 58, + 62 ] } ], @@ -1920,14 +1920,14 @@ ] }, { - "id": 47, + "id": 54, "name": "TypeStruct", "kind": 256, "kindString": "Interface", "flags": {}, "children": [ { - "id": 49, + "id": 56, "name": "count", "kind": 1024, "kindString": "Property", @@ -1945,7 +1945,7 @@ } }, { - "id": 48, + "id": 55, "name": "type", "kind": 1024, "kindString": "Property", @@ -1968,8 +1968,8 @@ "title": "Properties", "kind": 1024, "children": [ - 49, - 48 + 56, + 55 ] } ], @@ -1982,7 +1982,7 @@ ] }, { - "id": 150, + "id": 157, "name": "ColumnReference", "kind": 4194304, "kindString": "Type alias", @@ -2014,7 +2014,7 @@ } }, { - "id": 153, + "id": 160, "name": "DataLiteralSet", "kind": 4194304, "kindString": "Type alias", @@ -2043,7 +2043,7 @@ } }, { - "id": 152, + "id": 159, "name": "DataRow", "kind": 4194304, "kindString": "Type alias", @@ -2065,12 +2065,12 @@ "elementType": { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } } }, { - "id": 151, + "id": 158, "name": "DataVal", "kind": 4194304, "kindString": "Type alias", @@ -2106,7 +2106,7 @@ } }, { - "id": 147, + "id": 154, "name": "DateDomain", "kind": 4194304, "kindString": "Type alias", @@ -2138,7 +2138,7 @@ } }, { - "id": 149, + "id": 156, "name": "Domain", "kind": 4194304, "kindString": "Type alias", @@ -2161,23 +2161,23 @@ { "type": "reference", "name": "NumDomain", - "id": 146 + "id": 153 }, { "type": "reference", "name": "DateDomain", - "id": 147 + "id": 154 }, { "type": "reference", "name": "NameDomain", - "id": 148 + "id": 155 } ] } }, { - "id": 148, + "id": 155, "name": "NameDomain", "kind": 4194304, "kindString": "Type alias", @@ -2203,7 +2203,7 @@ } }, { - "id": 146, + "id": 153, "name": "NumDomain", "kind": 4194304, "kindString": "Type alias", @@ -2235,7 +2235,7 @@ } }, { - "id": 145, + "id": 152, "name": "NumRange", "kind": 4194304, "kindString": "Type alias", @@ -2267,7 +2267,7 @@ } }, { - "id": 159, + "id": 166, "name": "mapFn", "kind": 4194304, "kindString": "Type alias", @@ -2284,21 +2284,21 @@ "type": { "type": "reflection", "declaration": { - "id": 160, + "id": 167, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 161, + "id": 168, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 162, + "id": 169, "name": "colVal", "kind": 32768, "kindString": "Parameter", @@ -2309,7 +2309,7 @@ } }, { - "id": 163, + "id": 170, "name": "colIndex", "kind": 32768, "kindString": "Parameter", @@ -2322,7 +2322,7 @@ } }, { - "id": 164, + "id": 171, "name": "rowIndex", "kind": 32768, "kindString": "Parameter", @@ -2335,7 +2335,7 @@ } }, { - "id": 165, + "id": 172, "name": "rows", "kind": 32768, "kindString": "Parameter", @@ -2371,7 +2371,7 @@ } }, { - "id": 154, + "id": 161, "name": "sortFn", "kind": 4194304, "kindString": "Type alias", @@ -2388,21 +2388,21 @@ "type": { "type": "reflection", "declaration": { - "id": 155, + "id": 162, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 156, + "id": 163, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 157, + "id": 164, "name": "x", "kind": 32768, "kindString": "Parameter", @@ -2413,7 +2413,7 @@ } }, { - "id": 158, + "id": 165, "name": "y", "kind": 32768, "kindString": "Parameter", @@ -2446,33 +2446,33 @@ "title": "Classes", "kind": 128, "children": [ - 56 + 63 ] }, { "title": "Interfaces", "kind": 256, "children": [ - 43, 50, - 47 + 57, + 54 ] }, { "title": "Type aliases", "kind": 4194304, "children": [ - 150, + 157, + 160, + 159, + 158, + 154, + 156, + 155, 153, 152, - 151, - 147, - 149, - 148, - 146, - 145, - 159, - 154 + 166, + 161 ] } ], @@ -2486,6 +2486,180 @@ }, { "id": 1, + "name": "\"Data.spec\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.spec.ts", + "children": [ + { + "id": 2, + "name": "colNames", + "kind": 32, + "kindString": "Variable", + "flags": {}, + "sources": [ + { + "fileName": "Data.spec.ts", + "line": 4, + "character": 14 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + }, + "defaultValue": " ['Name', 'Value', 'Start', 'End']" + }, + { + "id": 4, + "name": "data", + "kind": 32, + "kindString": "Variable", + "flags": {}, + "sources": [ + { + "fileName": "Data.spec.ts", + "line": 12, + "character": 10 + } + ], + "type": { + "type": "reference", + "name": "Data" + }, + "defaultValue": " new hsdatab.Data({colNames:colNames, rows:rows})" + }, + { + "id": 7, + "name": "result", + "kind": 32, + "kindString": "Variable", + "flags": {}, + "sources": [ + { + "fileName": "Data.spec.ts", + "line": 15, + "character": 12 + } + ], + "type": { + "type": "reference", + "name": "Data" + }, + "defaultValue": " data.filter(query)" + }, + { + "id": 3, + "name": "rows", + "kind": 32, + "kindString": "Variable", + "flags": {}, + "sources": [ + { + "fileName": "Data.spec.ts", + "line": 5, + "character": 10 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + "defaultValue": " [\n ['Harry', '100', '3/1/14', '11/20/14'], \n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'], \n ['Jane', '700', '11/13/14', '8/15/15']\n]" + }, + { + "id": 5, + "name": "query", + "kind": 2097152, + "kindString": "Object literal", + "flags": {}, + "children": [ + { + "id": 6, + "name": "Name", + "kind": 32, + "kindString": "Variable", + "flags": {}, + "sources": [ + { + "fileName": "Data.spec.ts", + "line": 14, + "character": 19 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + }, + "defaultValue": "[\"Peter\", \"Jane\"]" + } + ], + "groups": [ + { + "title": "Variables", + "kind": 32, + "children": [ + 6 + ] + } + ], + "sources": [ + { + "fileName": "Data.spec.ts", + "line": 14, + "character": 11 + } + ], + "type": { + "type": "intrinsic", + "name": "object" + } + } + ], + "groups": [ + { + "title": "Variables", + "kind": 32, + "children": [ + 2, + 4, + 7, + 3 + ] + }, + { + "title": "Object literals", + "kind": 2097152, + "children": [ + 5 + ] + } + ], + "sources": [ + { + "fileName": "Data.spec.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 8, "name": "\"DataFilters\"", "kind": 1, "kindString": "External module", @@ -2499,7 +2673,7 @@ }, "children": [ { - "id": 2, + "id": 9, "name": "SetAndCondition", "kind": 256, "kindString": "Interface", @@ -2508,7 +2682,7 @@ }, "children": [ { - "id": 4, + "id": 11, "name": "and", "kind": 1024, "kindString": "Property", @@ -2526,11 +2700,11 @@ "type": { "type": "reference", "name": "RecursiveCondition", - "id": 11 + "id": 18 } }, { - "id": 5, + "id": 12, "name": "not", "kind": 1024, "kindString": "Property", @@ -2548,11 +2722,11 @@ "type": { "type": "reference", "name": "RecursiveCondition", - "id": 11 + "id": 18 } }, { - "id": 3, + "id": 10, "name": "or", "kind": 1024, "kindString": "Property", @@ -2570,7 +2744,7 @@ "type": { "type": "reference", "name": "RecursiveCondition", - "id": 11 + "id": 18 } } ], @@ -2579,9 +2753,9 @@ "title": "Properties", "kind": 1024, "children": [ - 4, - 5, - 3 + 11, + 12, + 10 ] } ], @@ -2594,7 +2768,7 @@ ] }, { - "id": 6, + "id": 13, "name": "TermAndCondition", "kind": 256, "kindString": "Interface", @@ -2603,14 +2777,14 @@ }, "indexSignature": [ { - "id": 7, + "id": 14, "name": "__index", "kind": 8192, "kindString": "Index signature", "flags": {}, "parameters": [ { - "id": 8, + "id": 15, "name": "colDesc", "kind": 32768, "kindString": "Parameter", @@ -2627,20 +2801,20 @@ { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 }, { "type": "array", "elementType": { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } }, { "type": "reference", "name": "TermConditionFunction", - "id": 14 + "id": 21 } ] } @@ -2655,7 +2829,7 @@ ] }, { - "id": 13, + "id": 20, "name": "AndCondition", "kind": 4194304, "kindString": "Type alias", @@ -2675,18 +2849,18 @@ { "type": "reference", "name": "SetAndCondition", - "id": 2 + "id": 9 }, { "type": "reference", "name": "TermAndCondition", - "id": 6 + "id": 13 } ] } }, { - "id": 9, + "id": 16, "name": "Condition", "kind": 4194304, "kindString": "Type alias", @@ -2706,18 +2880,18 @@ { "type": "reference", "name": "IndexCondition", - "id": 10 + "id": 17 }, { "type": "reference", "name": "RecursiveCondition", - "id": 11 + "id": 18 } ] } }, { - "id": 10, + "id": 17, "name": "IndexCondition", "kind": 4194304, "kindString": "Type alias", @@ -2740,7 +2914,7 @@ } }, { - "id": 12, + "id": 19, "name": "OrCondition", "kind": 4194304, "kindString": "Type alias", @@ -2762,7 +2936,7 @@ "elementType": { "type": "reference", "name": "AndCondition", - "id": 13 + "id": 20 } }, { @@ -2770,14 +2944,14 @@ "elementType": { "type": "reference", "name": "IndexCondition", - "id": 10 + "id": 17 } } ] } }, { - "id": 11, + "id": 18, "name": "RecursiveCondition", "kind": 4194304, "kindString": "Type alias", @@ -2797,18 +2971,18 @@ { "type": "reference", "name": "AndCondition", - "id": 13 + "id": 20 }, { "type": "reference", "name": "OrCondition", - "id": 12 + "id": 19 } ] } }, { - "id": 14, + "id": 21, "name": "TermConditionFunction", "kind": 4194304, "kindString": "Type alias", @@ -2825,21 +2999,21 @@ "type": { "type": "reflection", "declaration": { - "id": 15, + "id": 22, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 16, + "id": 23, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 17, + "id": 24, "name": "value", "kind": 32768, "kindString": "Parameter", @@ -2847,11 +3021,11 @@ "type": { "type": "reference", "name": "DataVal", - "id": 151 + "id": 158 } }, { - "id": 18, + "id": 25, "name": "row", "kind": 32768, "kindString": "Parameter", @@ -2859,7 +3033,7 @@ "type": { "type": "reference", "name": "DataRow", - "id": 152 + "id": 159 } } ], @@ -2880,7 +3054,7 @@ } }, { - "id": 38, + "id": 45, "name": "filter", "kind": 64, "kindString": "Function", @@ -2889,7 +3063,7 @@ }, "signatures": [ { - "id": 39, + "id": 46, "name": "filter", "kind": 4096, "kindString": "Call signature", @@ -2900,7 +3074,7 @@ }, "parameters": [ { - "id": 40, + "id": 47, "name": "data", "kind": 32768, "kindString": "Parameter", @@ -2911,11 +3085,11 @@ "type": { "type": "reference", "name": "Data", - "id": 56 + "id": 63 } }, { - "id": 41, + "id": 48, "name": "cond", "kind": 32768, "kindString": "Parameter", @@ -2926,14 +3100,14 @@ "type": { "type": "reference", "name": "Condition", - "id": 9 + "id": 16 } } ], "type": { "type": "reference", "name": "Data", - "id": 56 + "id": 63 } } ], @@ -2946,14 +3120,14 @@ ] }, { - "id": 28, + "id": 35, "name": "resolveCondition", "kind": 64, "kindString": "Function", "flags": {}, "signatures": [ { - "id": 29, + "id": 36, "name": "resolveCondition", "kind": 4096, "kindString": "Call signature", @@ -2963,7 +3137,7 @@ }, "parameters": [ { - "id": 30, + "id": 37, "name": "condition", "kind": 32768, "kindString": "Parameter", @@ -2974,11 +3148,11 @@ "type": { "type": "reference", "name": "Condition", - "id": 9 + "id": 16 } }, { - "id": 31, + "id": 38, "name": "row", "kind": 32768, "kindString": "Parameter", @@ -2989,11 +3163,11 @@ "type": { "type": "reference", "name": "DataRow", - "id": 152 + "id": 159 } }, { - "id": 32, + "id": 39, "name": "r", "kind": 32768, "kindString": "Parameter", @@ -3007,7 +3181,7 @@ } }, { - "id": 33, + "id": 40, "name": "colNumber", "kind": 32768, "kindString": "Parameter", @@ -3015,21 +3189,21 @@ "type": { "type": "reflection", "declaration": { - "id": 34, + "id": 41, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 35, + "id": 42, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 36, + "id": 43, "name": "name", "kind": 32768, "kindString": "Parameter", @@ -3057,7 +3231,7 @@ } }, { - "id": 37, + "id": 44, "name": "and", "kind": 32768, "kindString": "Parameter", @@ -3087,21 +3261,21 @@ ] }, { - "id": 19, + "id": 26, "name": "resolveTerminalCondition", "kind": 64, "kindString": "Function", "flags": {}, "signatures": [ { - "id": 20, + "id": 27, "name": "resolveTerminalCondition", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 21, + "id": 28, "name": "name", "kind": 32768, "kindString": "Parameter", @@ -3112,7 +3286,7 @@ } }, { - "id": 22, + "id": 29, "name": "val", "kind": 32768, "kindString": "Parameter", @@ -3123,7 +3297,7 @@ } }, { - "id": 23, + "id": 30, "name": "row", "kind": 32768, "kindString": "Parameter", @@ -3131,11 +3305,11 @@ "type": { "type": "reference", "name": "DataRow", - "id": 152 + "id": 159 } }, { - "id": 24, + "id": 31, "name": "colNumber", "kind": 32768, "kindString": "Parameter", @@ -3143,21 +3317,21 @@ "type": { "type": "reflection", "declaration": { - "id": 25, + "id": 32, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "signatures": [ { - "id": 26, + "id": 33, "name": "__call", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 27, + "id": 34, "name": "name", "kind": 32768, "kindString": "Parameter", @@ -3205,29 +3379,29 @@ "title": "Interfaces", "kind": 256, "children": [ - 2, - 6 + 9, + 13 ] }, { "title": "Type aliases", "kind": 4194304, "children": [ - 13, - 9, - 10, - 12, - 11, - 14 + 20, + 16, + 17, + 19, + 18, + 21 ] }, { "title": "Functions", "kind": 64, "children": [ - 38, - 28, - 19 + 45, + 35, + 26 ] } ], @@ -3240,7 +3414,7 @@ ] }, { - "id": 166, + "id": 173, "name": "\"index\"", "kind": 1, "kindString": "External module", @@ -3257,7 +3431,7 @@ ] }, { - "id": 167, + "id": 174, "name": "\"overview\"", "kind": 1, "kindString": "External module", @@ -3283,10 +3457,11 @@ "title": "External modules", "kind": 1, "children": [ - 42, + 49, 1, - 166, - 167 + 8, + 173, + 174 ] } ] diff --git a/docs/src/Data.html b/docs/src/Data.html index d2b7bfa..8e87921 100644 --- a/docs/src/Data.html +++ b/docs/src/Data.html @@ -12,7 +12,7 @@ height:90%; } code { padding: 5px 0;} -

    Data.ts

    +

    src/Data.ts

       1/**
       2 */

       3
    diff --git a/docs/src/DataFilters.html b/docs/src/DataFilters.html index cd063c1..7669d54 100644 --- a/docs/src/DataFilters.html +++ b/docs/src/DataFilters.html @@ -12,7 +12,7 @@ height:90%; } code { padding: 5px 0;} -

    DataFilters.ts

    +

    src/DataFilters.ts

       1
       2/**
       3* Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object. 
    diff --git a/docs/src/index.html b/docs/src/index.html index 6172591..07a3840 100644 --- a/docs/src/index.html +++ b/docs/src/index.html @@ -12,7 +12,7 @@ height:90%; } code { padding: 5px 0;} -

    index.ts

    +

    src/index.ts

       1export { NumRange,
       2         NumDomain,
       3         DateDomain,
    diff --git a/docs/src/overview.html b/docs/src/overview.html index 5a4ae06..28af118 100644 --- a/docs/src/overview.html +++ b/docs/src/overview.html @@ -12,7 +12,7 @@ height:90%; } code { padding: 5px 0;} -

    overview.ts

    +

    src/overview.ts

       1/**
       2 * # hsDatab
       3 * 
    From 242e871d143da5046f79f15621ecce3a52796334 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sun, 17 Jun 2018 09:12:32 +0200 Subject: [PATCH 13/17] docs update --- .gitignore | 1 - docs/data/hsDatab.json | 3468 ------------------------------------- docs/data/index.json | 1 - docs/indexGH.html | 11 - docs/src/Data.html | 568 ------ docs/src/Data.spec.html | 54 - docs/src/DataFilters.html | 267 --- docs/src/index.html | 32 - docs/src/overview.html | 96 - 9 files changed, 4498 deletions(-) delete mode 100644 docs/data/hsDatab.json delete mode 100644 docs/data/index.json delete mode 100644 docs/indexGH.html delete mode 100644 docs/src/Data.html delete mode 100644 docs/src/Data.spec.html delete mode 100644 docs/src/DataFilters.html delete mode 100644 docs/src/index.html delete mode 100644 docs/src/overview.html diff --git a/.gitignore b/.gitignore index 19cc2c8..c35f00f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ _dist -_example node_modules .DS_Store .tscache diff --git a/docs/data/hsDatab.json b/docs/data/hsDatab.json deleted file mode 100644 index 843d869..0000000 --- a/docs/data/hsDatab.json +++ /dev/null @@ -1,3468 +0,0 @@ -{ - "id": 0, - "name": "hsDatab", - "kind": 0, - "flags": {}, - "children": [ - { - "id": 49, - "name": "\"Data\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.ts", - "comment": {}, - "children": [ - { - "id": 63, - "name": "Data", - "kind": 128, - "kindString": "Class", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "# Data\nA simple in-memory database that holds data in rows of columns." - }, - "children": [ - { - "id": 74, - "name": "constructor", - "kind": 512, - "kindString": "Constructor", - "flags": { - "isExported": true - }, - "signatures": [ - { - "id": 75, - "name": "new Data", - "kind": 16384, - "kindString": "Constructor signature", - "flags": {}, - "parameters": [ - { - "id": 76, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 50 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 63 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 86, - "character": 5 - } - ] - }, - { - "id": 124, - "name": "data", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 392, - "character": 16 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 159 - } - }, - "defaultValue": " []" - }, - { - "id": 125, - "name": "meta", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 393, - "character": 16 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "MetaStruct", - "id": 57 - } - }, - "defaultValue": " []" - }, - { - "id": 126, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 394, - "character": 16 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 141, - "name": "allRows", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 142, - "name": "allRows", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "A generator that provides the specified column value for each row in `Data` in sequence." - }, - "parameters": [ - { - "id": 143, - "name": "column", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "\n" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ], - "type": { - "type": "reference", - "name": "Iterable", - "typeArguments": [ - { - "type": "reference", - "name": "DataVal", - "id": 158 - } - ] - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 493, - "character": 21 - } - ] - }, - { - "id": 111, - "name": "castData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 112, - "name": "castData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 260, - "character": 19 - } - ] - }, - { - "id": 148, - "name": "castVal", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 149, - "name": "castVal", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "The result of the cast.", - "tags": [ - { - "tag": "description", - "text": "Casts the sample to the specified data type.\n" - } - ] - }, - "parameters": [ - { - "id": 150, - "name": "type", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "The type to cast into. In case of _any_ - i.e. `type`\ndoes not match any of the previous keywords, no casting occurs." - }, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 151, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataVal", - "id": 158 - } - } - ], - "type": { - "type": "reference", - "name": "DataVal", - "id": 158 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 529, - "character": 19 - } - ] - }, - { - "id": 89, - "name": "colAdd", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 90, - "name": "colAdd", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "adds a new column to the data set. if `newCol` already exists,\nthe column index is returned withoput change.", - "returns": "the index for the new column\n" - }, - "parameters": [ - { - "id": 91, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the name of the new column" - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 140, - "character": 17 - } - ] - }, - { - "id": 92, - "name": "colInitialize", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 93, - "name": "colInitialize", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "initializes the specifed column with values, adding a new column if needed.\nIf `val`is a function, it is called as ```\nval(colValue:DataVal, rowIndex:number, row:DataRow)\n```" - }, - "parameters": [ - { - "id": 94, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the column to initialize" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - }, - { - "id": 95, - "name": "initializer", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the value to initialize with, or a function whose return\nvalue is used to initialize the column\n" - }, - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 162, - "character": 24 - } - ] - }, - { - "id": 99, - "name": "colName", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 100, - "name": "colName", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column name for the specified column.\n`col` can be either an index or a name.", - "returns": "the column name or `undefined`.\n" - }, - "parameters": [ - { - "id": 101, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 194, - "character": 18 - } - ] - }, - { - "id": 102, - "name": "colNames", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 103, - "name": "colNames", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the names for all columns.", - "returns": "an array of strings with the names.\n" - }, - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 205, - "character": 19 - } - ] - }, - { - "id": 96, - "name": "colNumber", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 97, - "name": "colNumber", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column index of the specified column.\n`col` can be either an index or a name.", - "returns": "the column number or `undefined`.\n" - }, - "parameters": [ - { - "id": 98, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 179, - "character": 20 - } - ] - }, - { - "id": 104, - "name": "colType", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 105, - "name": "colType", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column type for the specified column.\n`col` can be either an index or a name.", - "returns": "the column type.\n" - }, - "parameters": [ - { - "id": 106, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 215, - "character": 18 - } - ] - }, - { - "id": 82, - "name": "export", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 83, - "name": "export", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Exports to an object literal" - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 50 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 111, - "character": 17 - } - ] - }, - { - "id": 113, - "name": "filter", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 114, - "name": "filter", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "filters this data set and returns a new data set with a\nshallow copy of rows that pass the `condition`.\nSee {@link DataFilters DataFilters} for rules and examples on how to construct conditions.", - "returns": "a new Data object with rows that pass the filter\n" - }, - "parameters": [ - { - "id": 115, - "name": "condition", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "filters" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 16 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 63 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 277, - "character": 17 - } - ] - }, - { - "id": 107, - "name": "findDomain", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 108, - "name": "findDomain", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "modifies `domain` to include all values in column `col`.\nIf no `col` is specified, the range of data indexes is returned.", - "returns": "the updated domain\n" - }, - "parameters": [ - { - "id": 109, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the column name or index" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - }, - { - "id": 110, - "name": "domain", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the Domain range to update" - }, - "type": { - "type": "reference", - "name": "Domain", - "id": 156 - } - } - ], - "type": { - "type": "reference", - "name": "Domain", - "id": 156 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 227, - "character": 21 - } - ] - }, - { - "id": 138, - "name": "findType", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 139, - "name": "findType", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample\n", - "tags": [ - { - "tag": "description", - "text": "determines the data type. Supported types are\n```\n'date': sample represents a Date, either as a Date object or a String\n'number': sample represents a number\n'percent': sample represents a percentage (special case of a real number)\n'nominal': sample represents a nominal (ordinal or categorical) value\n```" - } - ] - }, - "parameters": [ - { - "id": 140, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the value to bve typed." - }, - "type": { - "type": "reference", - "name": "DataVal", - "id": 158 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 462, - "character": 20 - } - ] - }, - { - "id": 135, - "name": "findTypes", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 136, - "name": "findTypes", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Determines the type of data in `col`. An array of counts is created for all\nencountered types, sorted by descending frequency. THe most likely type in position 0\nof the array is returned.", - "returns": "the most likely type of data in `col`.\n" - }, - "parameters": [ - { - "id": 137, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the index of the column to be typed." - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 430, - "character": 21 - } - ] - }, - { - "id": 86, - "name": "getColumn", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 87, - "name": "getColumn", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Returns the values in the specified column as a new array." - }, - "parameters": [ - { - "id": 88, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the column to return.\n" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 158 - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 129, - "character": 20 - } - ] - }, - { - "id": 84, - "name": "getData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 85, - "name": "getData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the 2D array underlying the data base." - }, - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 159 - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 121, - "character": 18 - } - ] - }, - { - "id": 127, - "name": "getMeta", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 128, - "name": "getMeta", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 129, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ], - "type": { - "type": "reference", - "name": "MetaStruct", - "id": 57 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 396, - "character": 19 - } - ] - }, - { - "id": 77, - "name": "getName", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 78, - "name": "getName", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the `name` field for this data base, if any\n" - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 95, - "character": 18 - } - ] - }, - { - "id": 79, - "name": "import", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 80, - "name": "import", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Imports data from an object literal `data`" - }, - "parameters": [ - { - "id": 81, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data set to import\n" - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 50 - } - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 103, - "character": 17 - } - ] - }, - { - "id": 120, - "name": "map", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 121, - "name": "map", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": " Maps one or more columns in each rows of values based\non the result of the `mapFn`, which behaves similarly to the Array.map() method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the `mapFn` is passed the column arrays per row as parameter.\nThis allows for complex mapping combining conditions across multiple columns.\n```\ndata.map(function(values){\n values[1] = values[3] * values[5];\n return values;\n});\n```\nBe sure to return the `values` array as a result.\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `mapFn`, along with the row index and the entire row array. This allows for simple mapping.\n```\ndata.map('Price', function(value, i, values) {\n return value * 2;\n});\n```", - "returns": "a new Data object containing the mapping.\n" - }, - "parameters": [ - { - "id": 122, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data column, or columns, to apply the mapping to." - }, - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "ColumnReference", - "id": 157 - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ] - } - }, - { - "id": 123, - "name": "mapFn", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "a function to implement the mapping,\ncalled on each row of the data set in turn as `mapFn(val, i, c, rows)`, where\n- `val`: the column value in the current row\n- `c`: the column index in the current row\n- `i`: the row index\n- `rows`: the rows being iterated over\n` *\nfollows the same specifications as the function passed to Array.map().
    \nFor column mode, some predefined map functions can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.
    " - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "mapFn", - "id": 123 - } - ] - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 63 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 359, - "character": 14 - } - ] - }, - { - "id": 130, - "name": "setData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 131, - "name": "setData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "sets `data` to the existing data set. If data has previously been set,\n`data` will be added to the end of the list if all `names` match those of the\nexisting set." - }, - "parameters": [ - { - "id": 132, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data to add" - }, - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 159 - } - } - }, - { - "id": 133, - "name": "names", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "an array of names that match the columns" - }, - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 134, - "name": "autoType", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "unless set to false, the method will attempt to determine the\ntype of data and automatically cast data points to their correct value\n" - }, - "type": { - "type": "intrinsic", - "name": "boolean" - }, - "defaultValue": "true" - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 412, - "character": 19 - } - ] - }, - { - "id": 116, - "name": "sort", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 117, - "name": "sort", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the Data object in order to allow for chaining.\n", - "tags": [ - { - "tag": "description", - "text": "Sorts the rows of values based on the result of the `sortFn`,\nwhich behaves similarly to the Array.sort method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the column arrays are passed as samples into the `sortFn`.\nThis allows for complex sorts, combining conditions across multiple columns.\n```\ndata.sort((row1, row2) => row1[5] - row2[5] );\n```\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `sortFn`. This allows filtering for simple conditions.
    \n**The specified column will be automatically cast prior to sorting**
    \n`data.sort('Date', function(val1, val2) { return val1 - val2; });`" - } - ] - }, - "parameters": [ - { - "id": 118, - "name": "sortFn", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "a function to implement the conditions,\nfollows the same specifications as the function passed to Array.sort().\nSome predefined sort function can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.
    " - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "sortFn", - "id": 118 - } - ] - } - }, - { - "id": 119, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the data column to use for sorting." - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 157 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 63 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 307, - "character": 15 - } - ] - }, - { - "id": 144, - "name": "toDate", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 145, - "name": "toDate", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "a new Date object parsed from `str`.", - "tags": [ - { - "tag": "description", - "text": "returns a new Date object parsed from `str` and corrects for a difference in\ninterpreting centuries between webkit and mozilla in converting strings to Dates:\nThe string \"15/7/03\" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.\nIf `limitYear` is not specified this method uses 1970 as the decision date:\nyears 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.\n" - } - ] - }, - "parameters": [ - { - "id": 146, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the string to convert to a date" - }, - "type": { - "type": "reference", - "name": "DataVal", - "id": 158 - } - }, - { - "id": 147, - "name": "limitYear", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the year below which the century is corrected. Defaults to 1970." - }, - "type": { - "type": "intrinsic", - "name": "number" - }, - "defaultValue": "1970" - } - ], - "type": { - "type": "reference", - "name": "Date" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 510, - "character": 18 - } - ] - }, - { - "id": 70, - "name": "toDataSet", - "kind": 2048, - "kindString": "Method", - "flags": { - "isStatic": true, - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 71, - "name": "toDataSet", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 72, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataLiteralSet", - "id": 160 - } - }, - { - "id": 73, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "reference", - "name": "DataSet", - "id": 50 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 80, - "character": 27 - } - ] - }, - { - "id": 64, - "name": "type", - "kind": 2097152, - "kindString": "Object literal", - "flags": { - "isStatic": true, - "isExported": true, - "isPublic": true - }, - "children": [ - { - "id": 68, - "name": "currency", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "currency values. Currently support6ed are values ofg the format '$dd[,ddd]'" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 74, - "character": 16 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"currency\"" - }, - { - "id": 67, - "name": "date", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "date values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 72, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"date\"" - }, - { - "id": 66, - "name": "name", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "nominal values, represented by arbitrary words" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 70, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"name\"" - }, - { - "id": 65, - "name": "number", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "numeric values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 68, - "character": 14 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"number\"" - }, - { - "id": 69, - "name": "percent", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "percent values: 'd%'" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 76, - "character": 15 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"percent\"" - } - ], - "groups": [ - { - "title": "Variables", - "kind": 32, - "children": [ - 68, - 67, - 66, - 65, - 69 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 66, - "character": 22 - } - ], - "type": { - "type": "intrinsic", - "name": "object" - } - } - ], - "groups": [ - { - "title": "Constructors", - "kind": 512, - "children": [ - 74 - ] - }, - { - "title": "Properties", - "kind": 1024, - "children": [ - 124, - 125, - 126 - ] - }, - { - "title": "Methods", - "kind": 2048, - "children": [ - 141, - 111, - 148, - 89, - 92, - 99, - 102, - 96, - 104, - 82, - 113, - 107, - 138, - 135, - 86, - 84, - 127, - 77, - 79, - 120, - 130, - 116, - 144, - 70 - ] - }, - { - "title": "Object literals", - "kind": 2097152, - "children": [ - 64 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 62, - "character": 17 - } - ] - }, - { - "id": 50, - "name": "DataSet", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a JSON format data set, using arrays of names and rows" - }, - "children": [ - { - "id": 52, - "name": "colNames", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "an array of column names. Each name matches the column with the same index in DataRow" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 36, - "character": 12 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 51, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "comment": { - "shortText": "an optional name for the data set" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 34, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 53, - "name": "rows", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "rows of data" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 38, - "character": 8 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 159 - } - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 52, - 51, - 53 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 32, - "character": 24 - } - ] - }, - { - "id": 57, - "name": "MetaStruct", - "kind": 256, - "kindString": "Interface", - "flags": {}, - "children": [ - { - "id": 60, - "name": "accessed", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 49, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - }, - { - "id": 61, - "name": "cast", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 50, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - }, - { - "id": 59, - "name": "column", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 48, - "character": 10 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 58, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 47, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 62, - "name": "types", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 51, - "character": 9 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "TypeStruct", - "id": 54 - } - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 60, - 61, - 59, - 58, - 62 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 46, - "character": 20 - } - ] - }, - { - "id": 54, - "name": "TypeStruct", - "kind": 256, - "kindString": "Interface", - "flags": {}, - "children": [ - { - "id": 56, - "name": "count", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 42 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 55, - "name": "type", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 27 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 56, - 55 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 20 - } - ] - }, - { - "id": 157, - "name": "ColumnReference", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 23, - "character": 27 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "string" - } - ] - } - }, - { - "id": 160, - "name": "DataLiteralSet", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a JSON format data set, using an array of {name:value, ...} literals" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 42, - "character": 26 - } - ], - "type": { - "type": "reference", - "name": "Array", - "typeArguments": [ - { - "type": "intrinsic", - "name": "any" - } - ] - } - }, - { - "id": 159, - "name": "DataRow", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a single row of column values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 29, - "character": 19 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 158 - } - } - }, - { - "id": 158, - "name": "DataVal", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a generic data value type, used in the {@link Data.DataRow `DataRow`} array" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 26, - "character": 19 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "Date" - } - ] - } - }, - { - "id": 154, - "name": "DateDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a Date domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 14, - "character": 22 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "reference", - "name": "Date" - }, - { - "type": "reference", - "name": "Date" - } - ] - } - }, - { - "id": 156, - "name": "Domain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a generic domain that can be any of the typed domains." - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 20, - "character": 18 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "NumDomain", - "id": 153 - }, - { - "type": "reference", - "name": "DateDomain", - "id": 154 - }, - { - "type": "reference", - "name": "NameDomain", - "id": 155 - } - ] - } - }, - { - "id": 155, - "name": "NameDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a categorical domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 17, - "character": 22 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 153, - "name": "NumDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a numeric domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 11, - "character": 21 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "number" - } - ] - } - }, - { - "id": 152, - "name": "NumRange", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a [min-max] range" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 8, - "character": 20 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "number" - } - ] - } - }, - { - "id": 166, - "name": "mapFn", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 55, - "character": 17 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 167, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 168, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 169, - "name": "colVal", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 170, - "name": "colIndex", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 171, - "name": "rowIndex", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 172, - "name": "rows", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "array", - "elementType": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "any" - } - } - } - } - ], - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 55, - "character": 20 - } - ] - } - } - }, - { - "id": 161, - "name": "sortFn", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 54, - "character": 18 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 162, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 163, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 164, - "name": "x", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 165, - "name": "y", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 54, - "character": 20 - } - ] - } - } - } - ], - "groups": [ - { - "title": "Classes", - "kind": 128, - "children": [ - 63 - ] - }, - { - "title": "Interfaces", - "kind": 256, - "children": [ - 50, - 57, - 54 - ] - }, - { - "title": "Type aliases", - "kind": 4194304, - "children": [ - 157, - 160, - 159, - 158, - 154, - 156, - 155, - 153, - 152, - 166, - 161 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 1, - "name": "\"Data.spec\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.spec.ts", - "children": [ - { - "id": 2, - "name": "colNames", - "kind": 32, - "kindString": "Variable", - "flags": {}, - "sources": [ - { - "fileName": "Data.spec.ts", - "line": 4, - "character": 14 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - }, - "defaultValue": " ['Name', 'Value', 'Start', 'End']" - }, - { - "id": 4, - "name": "data", - "kind": 32, - "kindString": "Variable", - "flags": {}, - "sources": [ - { - "fileName": "Data.spec.ts", - "line": 12, - "character": 10 - } - ], - "type": { - "type": "reference", - "name": "Data" - }, - "defaultValue": " new hsdatab.Data({colNames:colNames, rows:rows})" - }, - { - "id": 7, - "name": "result", - "kind": 32, - "kindString": "Variable", - "flags": {}, - "sources": [ - { - "fileName": "Data.spec.ts", - "line": 15, - "character": 12 - } - ], - "type": { - "type": "reference", - "name": "Data" - }, - "defaultValue": " data.filter(query)" - }, - { - "id": 3, - "name": "rows", - "kind": 32, - "kindString": "Variable", - "flags": {}, - "sources": [ - { - "fileName": "Data.spec.ts", - "line": 5, - "character": 10 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - "defaultValue": " [\n ['Harry', '100', '3/1/14', '11/20/14'], \n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'], \n ['Jane', '700', '11/13/14', '8/15/15']\n]" - }, - { - "id": 5, - "name": "query", - "kind": 2097152, - "kindString": "Object literal", - "flags": {}, - "children": [ - { - "id": 6, - "name": "Name", - "kind": 32, - "kindString": "Variable", - "flags": {}, - "sources": [ - { - "fileName": "Data.spec.ts", - "line": 14, - "character": 19 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - }, - "defaultValue": "[\"Peter\", \"Jane\"]" - } - ], - "groups": [ - { - "title": "Variables", - "kind": 32, - "children": [ - 6 - ] - } - ], - "sources": [ - { - "fileName": "Data.spec.ts", - "line": 14, - "character": 11 - } - ], - "type": { - "type": "intrinsic", - "name": "object" - } - } - ], - "groups": [ - { - "title": "Variables", - "kind": 32, - "children": [ - 2, - 4, - 7, - 3 - ] - }, - { - "title": "Object literals", - "kind": 2097152, - "children": [ - 5 - ] - } - ], - "sources": [ - { - "fileName": "Data.spec.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 8, - "name": "\"DataFilters\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/DataFilters.ts", - "comment": { - "shortText": "Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object.\nEach row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object.", - "text": "# Condition construction\n\n### General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n### IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n### RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n### Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" - }, - "children": [ - { - "id": 9, - "name": "SetAndCondition", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "children": [ - { - "id": 11, - "name": "and", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 140, - "character": 7 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 18 - } - }, - { - "id": 12, - "name": "not", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 141, - "character": 7 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 18 - } - }, - { - "id": 10, - "name": "or", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 139, - "character": 6 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 18 - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 11, - 12, - 10 - ] - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 138, - "character": 32 - } - ] - }, - { - "id": 13, - "name": "TermAndCondition", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "indexSignature": [ - { - "id": 14, - "name": "__index", - "kind": 8192, - "kindString": "Index signature", - "flags": {}, - "parameters": [ - { - "id": 15, - "name": "colDesc", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "DataVal", - "id": 158 - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 158 - } - }, - { - "type": "reference", - "name": "TermConditionFunction", - "id": 21 - } - ] - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 144, - "character": 33 - } - ] - }, - { - "id": 20, - "name": "AndCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 136, - "character": 24 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "SetAndCondition", - "id": 9 - }, - { - "type": "reference", - "name": "TermAndCondition", - "id": 13 - } - ] - } - }, - { - "id": 16, - "name": "Condition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 129, - "character": 21 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "IndexCondition", - "id": 17 - }, - { - "type": "reference", - "name": "RecursiveCondition", - "id": 18 - } - ] - } - }, - { - "id": 17, - "name": "IndexCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "true if row index matches the number(s)" - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 132, - "character": 26 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 19, - "name": "OrCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 135, - "character": 23 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "array", - "elementType": { - "type": "reference", - "name": "AndCondition", - "id": 20 - } - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "IndexCondition", - "id": 17 - } - } - ] - } - }, - { - "id": 18, - "name": "RecursiveCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 134, - "character": 30 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "AndCondition", - "id": 20 - }, - { - "type": "reference", - "name": "OrCondition", - "id": 19 - } - ] - } - }, - { - "id": 21, - "name": "TermConditionFunction", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 152, - "character": 33 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 22, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 23, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 24, - "name": "value", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataVal", - "id": 158 - } - }, - { - "id": 25, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataRow", - "id": 159 - } - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 152, - "character": 35 - } - ] - } - } - }, - { - "id": 45, - "name": "filter", - "kind": 64, - "kindString": "Function", - "flags": { - "isExported": true - }, - "signatures": [ - { - "id": 46, - "name": "filter", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which\n`cond` holds true.", - "returns": "a new `Data` object with the filtered rows\n" - }, - "parameters": [ - { - "id": 47, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the `Data` object to filter" - }, - "type": { - "type": "reference", - "name": "Data", - "id": 63 - } - }, - { - "id": 48, - "name": "cond", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the complex condition to test against" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 16 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 63 - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 234, - "character": 22 - } - ] - }, - { - "id": 35, - "name": "resolveCondition", - "kind": 64, - "kindString": "Function", - "flags": {}, - "signatures": [ - { - "id": 36, - "name": "resolveCondition", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "applies `condition` to a row of data and returns `true` if the row passes." - }, - "parameters": [ - { - "id": 37, - "name": "condition", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the complex condition to test against" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 16 - } - }, - { - "id": 38, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the row values" - }, - "type": { - "type": "reference", - "name": "DataRow", - "id": 159 - } - }, - { - "id": 39, - "name": "r", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the row index in the data set" - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 40, - "name": "colNumber", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reflection", - "declaration": { - "id": 41, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 42, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 43, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 181, - "character": 80 - } - ] - } - } - }, - { - "id": 44, - "name": "and", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "\n" - }, - "type": { - "type": "intrinsic", - "name": "boolean" - }, - "defaultValue": "true" - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 181, - "character": 25 - } - ] - }, - { - "id": 26, - "name": "resolveTerminalCondition", - "kind": 64, - "kindString": "Function", - "flags": {}, - "signatures": [ - { - "id": 27, - "name": "resolveTerminalCondition", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 28, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 29, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 30, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataRow", - "id": 159 - } - }, - { - "id": 31, - "name": "colNumber", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reflection", - "declaration": { - "id": 32, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 33, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 34, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 155, - "character": 79 - } - ] - } - } - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 155, - "character": 33 - } - ] - } - ], - "groups": [ - { - "title": "Interfaces", - "kind": 256, - "children": [ - 9, - 13 - ] - }, - { - "title": "Type aliases", - "kind": 4194304, - "children": [ - 20, - 16, - 17, - 19, - 18, - 21 - ] - }, - { - "title": "Functions", - "kind": 64, - "children": [ - 45, - 35, - 26 - ] - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 173, - "name": "\"index\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/index.ts", - "sources": [ - { - "fileName": "index.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 174, - "name": "\"overview\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", - "comment": { - "shortText": "# hsDatab", - "text": "Helpful Scripts framework-independent data management functions.\n\n*hsdatab* provides a JavaScript-based data management and query mechanism.\nData is managed in a simple in-memory database that holds data in rows of columns.\nIt autodetermines the types of data held in each column, along with the\ndomain range for each column of data.\nComplex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure.\n\n## Data Types\nsupported {@link Data.Data.type data types} include\n- **number**: numeric values\n- **name**: nominal values, represented by arbitrary words\n- **date**: date values\n- **currency**: Currently supported: '$dd[,ddd]'\n- **percent**: 'd%'\n\n## Data Class\nThe fundamental object in this library is {@link Data.Data `Data`},\na simple row-column based database object,\nfeaturing named columns, sorting, mapping and filtering functions.\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query);\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('pre',\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [\n m('td', row[0]),\n m('td', row[1]),\n m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),\n m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)\n ]))\n ])),\n m('h3', 'The column types and domains are'),\n m('pre', m('table',\n m('tr', m('th', 'Column'), m('th', 'Type'), m('th', 'Domain')),\n m('tr', m('td', '\"Name\":'), m('td', data.colType(\"Name\")), m('td', data.findDomain(\"Name\").join(', '))),\n m('tr', m('td', '\"Value\":'), m('td', data.colType(\"Value\")), m('td', data.findDomain(\"Value\").join(' - '))),\n m('tr', m('td', '\"Start\":'), m('td', data.colType(\"Start\")), m('td', data.findDomain(\"Start\").map(d => d.toDateString()).join(' - '))),\n m('tr', m('td', '\"Stop\":'), m('td', data.colType(\"End\")), m('td', data.findDomain(\"End\").map(d => d.toDateString()).join(' - ')))\n )),\n m('h3', 'The query:'),\n m('code', '{Name:[\"Peter\", \"Jane\"]}'),\n m('h3', 'yields results with \"Name\"'),\n m('code', result.getColumn('Name').join(', '))\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n #data { font-size: 11pt; }\n\n\n" - }, - "sources": [ - { - "fileName": "overview.ts", - "line": 1, - "character": 0 - } - ] - } - ], - "groups": [ - { - "title": "External modules", - "kind": 1, - "children": [ - 49, - 1, - 8, - 173, - 174 - ] - } - ] -} \ No newline at end of file diff --git a/docs/data/index.json b/docs/data/index.json deleted file mode 100644 index c9f319f..0000000 --- a/docs/data/index.json +++ /dev/null @@ -1 +0,0 @@ -{"docs": ["hsDatab.json"], "title": "HS Libraries"} \ No newline at end of file diff --git a/docs/indexGH.html b/docs/indexGH.html deleted file mode 100644 index 2854c97..0000000 --- a/docs/indexGH.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - HS Docs - - - - - - \ No newline at end of file diff --git a/docs/src/Data.html b/docs/src/Data.html deleted file mode 100644 index 8e87921..0000000 --- a/docs/src/Data.html +++ /dev/null @@ -1,568 +0,0 @@ - - -

    src/Data.ts

    -
       1/**
    -   2 */

    -   3
    -   4 /** */
    -   5import { Condition, filter } from './DataFilters';
    -   6
    -   7/** defines a [min-max] range */
    -   8export type NumRange = [number, number];
    -   9
    -  10/** defines a numeric domain that includes all values of a column */
    -  11export type NumDomain = [number, number];
    -  12
    -  13/** defines a Date domain that includes all values of a column */
    -  14export type DateDomain = [Date, Date];
    -  15
    -  16/** defines a categorical domain that includes all values of a column */
    -  17export type NameDomain = string[];
    -  18
    -  19/** defines a generic domain that can be any of the typed domains. */
    -  20export type Domain = NumDomain | DateDomain | NameDomain;
    -  21
    -  22/** defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    -  23export type ColumnReference = number|string;
    -  24
    -  25/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    -  26export type DataVal = number|string|Date;
    -  27
    -  28/** a single row of column values */
    -  29export type DataRow = DataVal[];
    -  30
    -  31/** a JSON format data set, using arrays of names and rows */
    -  32export interface DataSet {
    -  33    /** an optional name for the data set */
    -  34    name?:  string;
    -  35    /** an array of column names. Each name matches the column with the same index in DataRow */
    -  36    colNames:  string[];   
    -  37    /** rows of data */
    -  38    rows:   DataRow[];
    -  39}
    -  40
    -  41/** a JSON format data set, using an array of {name:value, ...} literals*/
    -  42export type DataLiteralSet = Array;
    -  43
    -  44interface TypeStruct { type: string; count: number;};
    -  45
    -  46interface MetaStruct {
    -  47    name:       string;         // column name
    -  48    column:     number;         // column index
    -  49    accessed:   boolean;        // has column data been accessed?
    -  50    cast:       boolean;        // has column data been cast 
    -  51    types:      TypeStruct[];   // data types, sorted by likelihood
    -  52}
    -  53
    -  54export type sortFn = (x:any, y:any) => number;
    -  55export type mapFn  = (colVal:any, colIndex?:number, rowIndex?:number, rows?:any[][]) => any;
    -  56
    -  57/**
    -  58 * # Data
    -  59 * A simple in-memory database that holds data in rows of columns.
    -  60 * 
    -  61 */

    -  62export class Data {
    -  63    //----------------------------
    -  64    // public part
    -  65    //----------------------------
    -  66    public static type = {
    -  67        /** numeric values */
    -  68        number:     'number',
    -  69        /** nominal values, represented by arbitrary words */
    -  70        name:       'name',
    -  71        /** date values */
    -  72        date:       'date',
    -  73        /** currency values. Currently support6ed are values ofg the format '$dd[,ddd]' */
    -  74        currency:   'currency',
    -  75        /** percent values: 'd%' */
    -  76        percent:    'percent',
    -  77//        nominal:    'nominal'
    -  78    };
    -  79
    -  80    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    -  81        data = data || [{}];
    -  82        const names = Object.keys(data[0]);
    -  83        const rows = data.map((r:any) => 
    -  84            names.map((n:string) => r[n]));
    -  85        return { rows:rows, colNames:names, name:name||undefined };
    -  86    }
    -  87
    -  88    constructor(data?:DataSet) {
    -  89        this.import(data);
    -  90    }
    -  91
    -  92    /**
    -  93     * @return the `name` field for this data base, if any
    -  94     */

    -  95    public getName():string {
    -  96        return this.name;
    -  97    }
    -  98
    -  99    /**
    - 100     * Imports data from an object literal `data`
    - 101     * @param data the data set to import
    - 102     */

    - 103    public import(data:DataSet) {
    - 104        this.name = data.name;
    - 105        this.setData(data.rows, data.colNames);
    - 106    }
    - 107
    - 108    /**
    - 109     * Exports to an object literal
    - 110     */

    - 111    public export():DataSet {
    - 112        return {
    - 113            rows: this.getData(),
    - 114            colNames:this.colNames()
    - 115        };
    - 116    }
    - 117
    - 118    /**
    - 119     * returns the 2D array underlying the data base.
    - 120     */

    - 121    public getData():DataRow[] {
    - 122        return this.data;
    - 123    }
    - 124
    - 125    /**
    - 126     * Returns the values in the specified column as a new array.
    - 127     * @param col the column to return.
    - 128     */

    - 129    public getColumn(col:ColumnReference): DataVal[] {
    - 130        const cn = this.colNumber(col);
    - 131        return this.data.map((row:DataRow) => row[cn]);
    - 132    }
    - 133
    - 134    /**
    - 135     * adds a new column to the data set. if `newCol` already exists, 
    - 136     * the column index is returned withoput change.
    - 137     * @param col the name of the new column
    - 138     * @return the index for the new column
    - 139     */

    - 140    public colAdd(col:string):number {
    - 141        let m = this.getMeta(col);
    - 142        if (m === undefined) { 
    - 143            m = this.meta[col] = {};
    - 144            m.name   = col; 
    - 145            m.column = this.meta.length;
    - 146            this.meta.push(m);      // access name by both column name and index
    - 147            m.cast     = false;         // has not been cast yet
    - 148            m.accessed = false;         // has not been accessed yet
    - 149        }
    - 150        return m.column;
    - 151    }
    - 152
    - 153    /**
    - 154     * initializes the specifed column with values, adding a new column if needed. 
    - 155     * If `val`is a function, it is called as ```
    - 156     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    - 157     * ```
    - 158     * @param col the column to initialize
    - 159     * @param initializer the value to initialize with, or a function whose return
    - 160     * value is used to initialize the column
    - 161     */

    - 162    public colInitialize(col:ColumnReference, initializer:any) {
    - 163        const cn = this.colNumber(col);
    - 164        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    - 165        const fn = typeof initializer === 'function';
    - 166        if (cn!==undefined) {
    - 167            this.data.map((r:DataRow, i:number) =>
    - 168                r[cn] = fn? initializer(r[cn], i, r) : initializer
    - 169            );
    - 170        }
    - 171    }
    - 172
    - 173    /**
    - 174     * returns the column index of the specified column. 
    - 175     * `col` can be either an index or a name.
    - 176     * @param column the data column, name or index, for which to return the index. 
    - 177     * @return the column number or `undefined`.
    - 178     */

    - 179    public colNumber(col:ColumnReference) {
    - 180        const m = this.getMeta(col);
    - 181        if (!m) { return undefined; }
    - 182        else {
    - 183            m.accessed = true; 
    - 184            return m.column; 
    - 185        }
    - 186    }
    - 187    
    - 188    /**
    - 189     * returns the column name for the specified column. 
    - 190     * `col` can be either an index or a name.
    - 191     * @param column the data column, name or index. 
    - 192     * @return the column name or `undefined`.
    - 193     */

    - 194    public colName(col:ColumnReference) {
    - 195        var m = this.getMeta(col);
    - 196        if (!m) { return undefined; }
    - 197        m.accessed = true; 
    - 198        return m.name; 
    - 199    }
    - 200
    - 201    /**
    - 202     * returns the names for all columns. 
    - 203     * @return an array of strings with the names.
    - 204     */

    - 205    public colNames():string[] {
    - 206        return this.meta.map((m:MetaStruct) => m.name); 
    - 207    }
    - 208
    - 209    /**
    - 210     * returns the column type for the specified column. 
    - 211     * `col` can be either an index or a name.
    - 212     * @param column the data column, name or index. 
    - 213     * @return the column type.
    - 214     */

    - 215    public colType(col:ColumnReference) { 
    - 216        const meta = this.getMeta(col);
    - 217        return meta? meta.types[0].type : Data.type.name;
    - 218    }
    - 219
    - 220    /**
    - 221     * modifies `domain` to include all values in column `col`.
    - 222     * If no `col` is specified, the range of data indexes is returned.
    - 223     * @param col optional; the column name or index 
    - 224     * @param domain optional; the Domain range to update
    - 225     * @return the updated domain
    - 226     */

    - 227    public findDomain(col?:ColumnReference, domain?:Domain):Domain {
    - 228        if (domain===undefined) { domain = []; }
    - 229        if (col === undefined) { // use array index as domain
    - 230            domain[0] = 0;
    - 231            domain[1] = this.data.length-1;
    - 232        } else {
    - 233            const c = this.colNumber(col);
    - 234            const type = this.colType(col);
    - 235            if (this.data === undefined) {
    - 236                console.log('no data'); 
    - 237            }
    - 238            switch(type) {
    - 239                case Data.type.name: 
    - 240                    this.data.forEach((r:DataRow) => {
    - 241                        const nomDom = domain;
    - 242                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    - 243                    });
    - 244                    break;
    - 245                default: 
    - 246                    this.data.forEach((r:DataRow) => {
    - 247                        let v:number = r[c];
    - 248                        if (domain[0]===undefined) { domain[0] = v; }
    - 249                        if (domain[1]===undefined) { domain[1] = v; }
    - 250                        if (v!==undefined && v!==null) {
    - 251                            if (v - 252                            else if (v>domain[1]) { domain[1] = v; }
    - 253                        }
    - 254                    });
    - 255            }
    - 256        }
    - 257        return domain;
    - 258    }
    - 259
    - 260    public castData() {
    - 261        this.meta.forEach((c:MetaStruct) => {
    - 262            const col = c.column;
    - 263            if (!c.cast) {
    - 264                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    - 265            }
    - 266            c.cast = true;
    - 267        });
    - 268    }
    - 269
    - 270    /**
    - 271     * filters this data set and returns a new data set with a 
    - 272     * shallow copy of rows that pass the `condition`.
    - 273     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    - 274     * @param condition filters 
    - 275     * @return a new Data object with rows that pass the filter
    - 276     */

    - 277    public filter(condition:Condition):Data {
    - 278        return filter(this, condition);
    - 279    }
    - 280
    - 281    /**
    - 282     * @description Sorts the rows of values based on the result of the `sortFn`, 
    - 283     * which behaves similarly to the Array.sort method.  
    - 284     * Two modes are supported:
    - 285     * # Array Mode
    - 286     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    - 287     * This allows for complex sorts, combining conditions across multiple columns.
    - 288     * ```
    - 289     * data.sort((row1, row2) => row1[5] - row2[5] );
    - 290     * ```
    - 291     * # Column mode
    - 292     * If `col` is specified, either as index or by column name, the respective column value is passed
    - 293     * into `sortFn`. This allows filtering for simple conditions.

    - 294     * **The specified column will be automatically cast prior to sorting**

    - 295     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    - 296     * @param col optional; the data column to use for sorting. 
    - 297     * @param sortFn a function to implement the conditions, 
    - 298     * follows the same specifications as the function passed to Array.sort(). 
    - 299     * Some predefined sort function can be invoked by providing a 
    - 300     * respective string instead of a function. The following functions are defined:
    - 301        
    - 302        
    - 303        
    - 304        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    - 305     * @return the Data object in order to allow for chaining.
    - 306     */

    - 307    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    - 308        let fn = sortFn;
    - 309        if (!col) {
    - 310            this.data.sort(fn);
    - 311        } else {
    - 312            col = this.colNumber(col);
    - 313            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b - 314            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    - 315            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    - 316        }
    - 317        return this;
    - 318    }
    - 319
    - 320    /** 
    - 321    *  Maps one or more columns in each rows of values based 
    - 322     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    - 323     * Two modes are supported:
    - 324     * # Array Mode
    - 325     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    - 326     * This allows for complex mapping combining conditions across multiple columns.
    - 327     * ```
    - 328     * data.map(function(values){ 
    - 329     *    values[1] = values[3] * values[5]; 
    - 330     *    return values; 
    - 331     * });
    - 332     * ```
    - 333     * Be sure to return the `values` array as a result.
    - 334     * # Column mode
    - 335     * If `col` is specified, either as index or by column name, the respective column value is passed
    - 336     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    - 337     * ```
    - 338     * data.map('Price', function(value, i, values) { 
    - 339     *    return value * 2; 
    - 340     * });
    - 341     * ```
    - 342     * @param col the data column, or columns, to apply the mapping to. 
    - 343     * @param mapFn a function to implement the mapping,
    - 344     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    - 345     * - `val`: the column value in the current row
    - 346     * - `c`: the column index in the current row
    - 347     * - `i`: the row index 
    - 348     * - `rows`: the rows being iterated over
    - 349`    * 
    - 350     * follows the same specifications as the function passed to Array.map().

    - 351     * For column mode, some predefined map functions can be invoked by providing a 
    - 352     * respective string instead of a function. The following functions are defined:
    - 353        
    - 354        
    - 355        
    - 356        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    - 357     * @return a new Data object containing the mapping.
    - 358     */

    - 359    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    - 360        const noop = (val:any) => val;
    - 361        const cumulate = () => { 
    - 362            let sum=0; 
    - 363            return (val:number, i:number) => { sum += +val; return sum; };
    - 364        };
    - 365        function getFn() {
    - 366            let fn; // define fn inside each col loop to ensure initialization
    - 367            switch (mapFn) {
    - 368                case 'cumulate': fn = cumulate(); break;
    - 369                case 'noop':     fn = noop; break;
    - 370                default:         fn = mapFn;
    - 371            }
    - 372            return fn;
    - 373        }
    - 374
    - 375        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    - 376
    - 377        const names = col['length']? col : [col];            
    - 378        names.map((cn:ColumnReference) => {
    - 379            const c = this.colNumber(cn);
    - 380            let fn = getFn(); // define fn inside each col loop to ensure initialization
    - 381            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    - 382                row[c] = fn(row[c], c, i, rows); 
    - 383                return row;
    - 384            });
    - 385        });
    - 386        return result;
    - 387    }
    - 388
    - 389    //----------------------------
    - 390    // private part
    - 391    //----------------------------
    - 392    private data: DataRow[]    = [];
    - 393    private meta: MetaStruct[] = [];
    - 394    private name: string;
    - 395
    - 396    private getMeta(col:ColumnReference):MetaStruct { 
    - 397        if (!this.meta) { this.meta = []; }
    - 398        if (!this.meta[col]) { return undefined; }
    - 399        this.meta[col].accessed = true;
    - 400        return this.meta[col]; 
    - 401    }
    - 402
    - 403    /**
    - 404     * sets `data` to the existing data set. If data has previously been set, 
    - 405     * `data` will be added to the end of the list if all `names`  match those of the 
    - 406     * existing set. 
    - 407     * @param data the data to add
    - 408     * @param names an array of names that match the columns
    - 409     * @param autoType unless set to false, the method will attempt to determine the 
    - 410     * type of data and automatically cast data points to their correct value
    - 411     */

    - 412    private setData(data:DataRow[], names:string[], autoType=true):void {
    - 413        this.meta = [];
    - 414        this.data = data;
    - 415        if (!names) {
    - 416            console.log();
    - 417        }
    - 418        names.forEach((col:string) => this.colAdd(col));
    - 419        names.forEach((col:string) => this.findTypes(col));
    - 420        this.castData();
    - 421    }
    - 422
    - 423    /**
    - 424     * Determines the type of data in `col`. An array of counts is created for all
    - 425     * encountered types, sorted by descending frequency. THe most likely type in position 0
    - 426     * of the array is returned.
    - 427     * @param col the index of the column to be typed. 
    - 428     * @return the most likely type of data in `col`.
    - 429     */

    - 430    private findTypes(col:ColumnReference):string {
    - 431        const m = this.getMeta(col);
    - 432        const types:TypeStruct[] = [];
    - 433        Object.keys(Data.type).forEach((t:string) => {
    - 434            const ts = { type: Data.type[t], count: 0 }; 
    - 435            types.push(ts);
    - 436            types[Data.type[t]] = ts;
    - 437        });
    - 438        for (let v of this.allRows(col)) {
    - 439            const t = this.findType(v);
    - 440            if (t !== null) { types[t].count++; }
    - 441        }
    - 442        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    - 443            if (a.type==='currency'&&a.count>0) { return -1; }
    - 444            if (b.type==='currency'&&b.count>0) { return 1; }
    - 445            return b.count - a.count;
    - 446        });
    - 447        m.types = types;
    - 448        return types[0].type;
    - 449    }
    - 450
    - 451    /**
    - 452     * @description determines the data type. Supported types are 
    - 453     * ```
    - 454     * 'date':    sample represents a Date, either as a Date object or a String 
    - 455     * 'number':  sample represents a number
    - 456     * 'percent': sample represents a percentage (special case of a real number)
    - 457     * 'nominal': sample represents a nominal (ordinal or categorical) value
    - 458     * ```
    - 459     * @param val the value to bve typed.
    - 460     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    - 461     */

    - 462    private findType(val:DataVal) {
    - 463        if (val && val!=='') {
    - 464            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    - 465            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    - 466
    - 467            // else: val is a string:
    - 468            const strVal = ''+val;
    - 469            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    - 470            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    - 471            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    - 472            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    - 473
    - 474            // european large number currency representation: '$dd[,ddd]'
    - 475            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    - 476                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    - 477                    return Data.type.currency; 
    - 478                }
    - 479            }
    - 480            switch (strVal.toLowerCase()) {
    - 481                case "null": break;
    - 482                case "#ref!": break;
    - 483                default: if (val.length>0) { return Data.type.name; }
    - 484            }
    - 485        }
    - 486        return null;
    - 487    }    
    - 488
    - 489    /**
    - 490     * A generator that provides the specified column value for each row in `Data` in sequence. 
    - 491     * @param column 
    - 492     */

    - 493    private * allRows(column:ColumnReference):Iterable {
    - 494        const c = this.colNumber(column);
    - 495        for (let r=0; r - 496            yield this.data[r][c];
    - 497        }
    - 498    }
    - 499
    - 500    /**
    - 501     * @param val the string to convert to a date
    - 502     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    - 503     * @returns a new Date object parsed from `str`.
    - 504     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    - 505     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    - 506     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    - 507     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    - 508     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    - 509     */

    - 510    private toDate(val:DataVal, limitYear=1970):Date {
    - 511        let d:Date;
    - 512        if (val instanceof Date) { d = val; }
    - 513                            else { d = new Date(val); }   
    - 514        let yr=d.getFullYear();
    - 515        if (yr < 100) { 
    - 516            yr += 1900; 
    - 517            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    - 518        }
    - 519        return d;
    - 520    }
    - 521
    - 522    /**
    - 523     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    - 524     * does not match any of the previous keywords, no casting occurs.
    - 525     * @param sample The value to cast.
    - 526     * @returns The result of the cast. 
    - 527     * @description Casts the sample to the specified data type.
    - 528     */

    - 529    private castVal(type:string, val:DataVal):DataVal {
    - 530        switch (type) {
    - 531            case Data.type.date:    if (val instanceof Date) { return val; }
    - 532                            val = this.toDate(val);
    - 533                            if (isNaN(val.getTime())) { val = null; }
    - 534                            break;
    - 535            case Data.type.percent: if (typeof val === 'string') {
    - 536                                const num = parseFloat(val);
    - 537                                val = (val).endsWith('%')? num/100 : num;
    - 538                            } 
    - 539                            if (isNaN(val)) { val = null; }
    - 540                            break;
    - 541            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    - 542             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    - 543             /* falls through */
    - 544            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    - 545                            if (isNaN(val)) { val = null; }
    - 546                            break;
    - 547            default:        val = ''+val;
    - 548        }
    - 549        return val;
    - 550     }     
    - 551}
    - - \ No newline at end of file diff --git a/docs/src/Data.spec.html b/docs/src/Data.spec.html deleted file mode 100644 index a9221cc..0000000 --- a/docs/src/Data.spec.html +++ /dev/null @@ -1,54 +0,0 @@ - - -

    src/Data.spec.ts

    -
       1import { o }            from 'hslayout';
    -   2import * as hsdatab     from 'hsdatab';
    -   3
    -   4const colNames = ['Name', 'Value', 'Start', 'End'];
    -   5const rows = [
    -   6  ['Harry', '100', '3/1/14', '11/20/14'], 
    -   7  ['Mary', '1500', '7/1/14',  '9/30/14'],
    -   8  ['Peter', '400', '5/20/14', '4/30/15'],  
    -   9  ['Jane', '700', '11/13/14', '8/15/15']
    -  10];
    -  11
    -  12const data = new hsdatab.Data({colNames:colNames, rows:rows});
    -  13
    -  14const query = {Name:["Peter", "Jane"]};
    -  15const result = data.filter(query);
    -  16
    -  17o.spec("Data", () => {
    -  18    o("is created with 4 rows", () => {
    -  19        o(data.getData.length).equals(4);
    -  20    });
    -  21});
    -  22o.spec('Data Filters', () => {
    -  23    o('Query for {Name:["Peter", "Jane"]}', () => {
    -  24        o(result.getData.length).equals(2)('has two rows');
    -  25        o(result.getColumn('Name')[0]).equals('Peter')('has first row name Peter');
    -  26    });
    -  27});
    -  28
    -  29
    -  30/*
    -  31        var vnode = MyComponent.view()
    -  32
    -  33        o(vnode.tag).equals("div")
    -  34        o(vnode.children.length).equals(1)
    -  35        o(vnode.children[0].tag).equals("p")
    -  36        o(vnode.children[0].children).equals("Hello world")
    -  37*/

    - - \ No newline at end of file diff --git a/docs/src/DataFilters.html b/docs/src/DataFilters.html deleted file mode 100644 index 7669d54..0000000 --- a/docs/src/DataFilters.html +++ /dev/null @@ -1,267 +0,0 @@ - - -

    src/DataFilters.ts

    -
       1
    -   2/**
    -   3* Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object. 
    -   4* Each row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object. 
    -   5
    -   6* # Condition construction
    -   7*  
    -   8* ### General Condition
    -   9* ```
    -  10* Condition = 
    -  11*    IndexCondition            -> conditions on the row index
    -  12* || RecursiveCondition        -> (set of) conditions on column values
    -  13* ```
    -  14
    -  15* ### IndexCondition
    -  16* ```
    -  17* IndexCondition =
    -  18*    rowIndex:number           -> true if row index matches
    -  19* ```
    -  20
    -  21* ### RecursiveCondition
    -  22* ```
    -  23* RecursiveCondition =
    -  24*    OrCondition               -> OR: true if any compound condition is true
    -  25* || AndCondition              -> AND: true if all compound conditions are true
    -  26
    -  27* OrCondition =                -> OR: true if
    -  28*    AndCondition[]               -> any of the AndConditions are true
    -  29* || IndexCondition[]             -> any of thr IndexConditions are true
    -  30
    -  31* AndCondition =               -> AND: true if
    -  32*    SetAndCondition              -> all SetAndConditions are true
    -  33* || TermAndCondition             -> or if all TermAndConditions are true
    -  34*
    -  35* SetAndCondition = {          -> AND: true if all sub-conditions are true
    -  36*    'or':  RecursiveCondition    -> true if any RecursiveCondition is true
    -  37* || 'and': RecursiveCondition    -> true if all RecursiveCondition are true
    -  38* || 'not': RecursiveCondition    -> true if the condition is false
    -  39*
    -  40* TermAndCondition = {         -> Terminal AND: true if all terminal sub-conditions are true
    -  41*    colDesc:colValue             -> true if colValue matches 
    -  42* || colDesc:[colValue, ...]      -> true if any of the colValues match
    -  43* || colDesc:function(value,row)  -> true if function returns true 
    -  44* }
    -  45
    -  46* colDesc = either column name or index
    -  47* ```
    -  48
    -  49* ### Practical Tips
    -  50* ```
    -  51*    {'or': [recurCond, ...]}    -> OR, same as [recurCond, ...]
    -  52* || {'or': {SetCond, ...}}      -> OR, same as [SetCond, ...]
    -  53* || {'and': [recurCond, ...]}   -> AND, true if all recurCond are true
    -  54* || {'and': {SetCond, ...}}     -> AND, same as {SetCond, ...}
    -  55* || {'not': {SetCond, ...}}     -> NAND: true if the SetCond are true
    -  56* || {'not': [recurCond, ...]}   -> NOR: true if any of the recurCond are true
    -  57* ```
    -  58*      
    -  59* # Example
    -  60
    -  61
    -  62* const colNames = ['Name', 'Value', 'Start', 'End'];
    -  63* const rows = [
    -  64*   ['Harry', '100', '3/1/14', '11/20/14'], 
    -  65*   ['Mary', '1500', '7/1/14',  '9/30/14'],
    -  66*   ['Peter', '400', '5/20/14', '4/30/15'],  
    -  67*   ['Jane', '700', '11/13/14', '8/15/15']
    -  68* ]
    -  69* const data = new hsdatab.Data({colNames:colNames, rows:rows});
    -  70
    -  71* queries = [
    -  72*   ['0', undefined,                           'undefined query => pass all'],
    -  73*   ['1', [],                                  'empty OR:  []   => fail all'],
    -  74*   ['2', {},                                  'empty AND: {}   => pass all'],
    -  75*   ['3', 1,                                   '2nd row: pass row 1'],
    -  76*   ['4', [1,3],                               '2nd+4th: pass rows: 1 and 3'],
    -  77*   ['5', {Name:"Jane"},                       'Name is Jane'],
    -  78*   ['6', {1:1500},                            'Column 2 is 1500'],
    -  79*   ['7', {Name:["Peter", "Jane"]},            'Name is Peter or Jane'],
    -  80*   ['8', [{Name:"Peter"}, {Value:1500}],      'Name is Peter or Value is 1500'],
    -  81*   ['9', {or:{Name:"Peter", Value:1500}},     'OR:  same as 8:'],
    -  82*   ['A', {or:[{Name:"Peter"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],
    -  83*   ['B', {Name:"Peter", Value:400},           'Name is Peter and Value is 400'],
    -  84*   ['C', {and:{Name:"Peter", Value:400}},     'AND: {Name is Peter, Value is 400}'],
    -  85*   ['D', {and:{Name:"Peter", Value:1500}},    'AND: {Name is Peter, Value is 1500}'],
    -  86*   ['E', {and:[{Name:"Peter"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],
    -  87*   ['F', {and:[{Name:"Peter"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],
    -  88*   ['G', {not:{Name:"Peter", Value:400}},     'NAND: not {Name is Peter and Value is 400}'],
    -  89*   ['H', {not:{Name:"Peter", Value:1500}},    'NAND: not {Name is Peter and Value is 1500}'],
    -  90*   ['I', {not:[{Name:"Peter"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],
    -  91*   ['J', {Name:(v) => v.length===4},          'Name has 4 letters']
    -  92* ];
    -  93*
    -  94* m.mount(root, { 
    -  95*   view:() => m('', [
    -  96*       m('h3', 'Given the data set:'),
    -  97*       m('table#data', [
    -  98*           m('tr', colNames.map(n => m('th', n))),
    -  99*           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    - 100*       ]),
    - 101*       m('h3', 'The following queries yield:'),
    - 102*       m('table', [
    - 103*           m('tr', [m('th','#'), m('th','Query'), m('th',"Live Result, by 'Name' field")]),
    - 104*           ...queries.map(q => {
    - 105*               const result = data.filter(q[1]).getColumn('Name').join(', ');
    - 106*               return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);
    - 107*           })
    - 108*       ])
    - 109*   ])
    - 110* });
    - 111
    - 112
    - 113*   $exampleID { height: 600px; }
    - 114*   #data th { width:15%; }
    - 115*   table { 
    - 116*       font-size: 10pt;
    - 117*       margin-left: 10px;
    - 118*   }
    - 119
    - 120*      
    - 121*/

    - 122
    - 123/** */
    - 124import { Data,
    - 125         DataVal,
    - 126         DataRow
    - 127} from './Data'; 
    - 128
    - 129export type Condition = IndexCondition | RecursiveCondition;
    - 130
    - 131/** true if row index matches the number(s) */
    - 132export type IndexCondition = number;
    - 133
    - 134export type RecursiveCondition = AndCondition | OrCondition;
    - 135export type OrCondition = AndCondition[] | IndexCondition[];
    - 136export type AndCondition = SetAndCondition | TermAndCondition;
    - 137
    - 138export interface SetAndCondition {
    - 139    or?: RecursiveCondition;
    - 140    and?:RecursiveCondition;
    - 141    not?:RecursiveCondition;
    - 142};
    - 143
    - 144export interface TermAndCondition { 
    - 145    [colDesc:string]: 
    - 146        DataVal 
    - 147      | DataVal[]
    - 148      | TermConditionFunction
    - 149    ;
    - 150};
    - 151
    - 152export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean;
    - 153
    - 154
    - 155function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { 
    - 156    const col = colNumber(name);
    - 157    const valIsFunction = (typeof val === 'function');
    - 158    const valIsArray = ((typeof val === 'object') && (val.length!==undefined));
    - 159    if (isNaN(col)) { 
    - 160        console.log(`column name '${name}' cannot be resolved in terminal condition ${name}=${val}`);
    - 161        console.log(row);
    - 162        return false; // -> this condition is not met;
    - 163    } else if (valIsFunction) { 
    - 164        // query true if function evaluates to true
    - 165        return val(row[col], row);
    - 166    } else if (valIsArray) {
    - 167        // query true if empty array, or at least one c true
    - 168        return (val.length === 0) || val.some((v:any) => row[col] === v); 
    - 169    } else { // object: all conditions have to be met, unless specified as or
    - 170        return (row[col] === val); 
    - 171    }
    - 172}
    - 173
    - 174/**
    - 175 * applies `condition` to a row of data and returns `true` if the row passes.
    - 176 * @param condition the complex condition to test against
    - 177 * @param r the row index in the data set
    - 178 * @param row the row values 
    - 179 * @param and 
    - 180 */

    - 181function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and=true):boolean { 
    - 182    let orResult = false;
    - 183    let andResult= true;          
    - 184    // undefined condition is TRUE
    - 185    if (condition===undefined) { return true; }
    - 186    
    - 187    // Simple Index Condition on row index:
    - 188    else if (typeof condition === 'number') { return (condition === r); }
    - 189
    - 190    // Recursive Condition - OR: [...], AND {...}: 
    - 191    else if (typeof condition === 'object') {
    - 192        // array -> or condition on a list of row indices or compound conditions
    - 193        const mc = condition;
    - 194
    - 195        // OR condition: [...] 
    - 196        if (mc.length !== undefined) {            
    - 197            return (mc.length === 0)? 
    - 198                // empty OR is false:
    - 199                false : 
    - 200                // else: OR is true if any sub-condition is met
    - 201                mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, false));
    - 202        } 
    - 203        // AND condition: {...}
    - 204        else { 
    - 205            for (const name in condition) {
    - 206                let conditionMet = and; // initialize with false for OR, and true for AND conjunction
    - 207                const setCond = condition;
    - 208                
    - 209                // resolve SetConditions:
    - 210                switch (name) {
    - 211                    case 'or':  conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break;
    - 212                    case 'and': conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break;
    - 213                    case 'not': conditionMet = !resolveCondition(setCond.not, row, r, colNumber, true); break;
    - 214                    default:    conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); 
    - 215                }
    - 216                if (conditionMet) { orResult  = true;  if(!and) { break; }} // OR conjunction: exit for name loop if condition met
    - 217                             else { andResult = false; if(and)  { break; }} // AND conjunction: exit for name loop if condition not met
    - 218            }
    - 219        }    
    - 220    } else {
    - 221        console.error(`unrecognized condition: ${JSON.stringify(condition)}`);
    - 222        return false;
    - 223    }
    - 224    return and? andResult : orResult;
    - 225}
    - 226
    - 227/**
    - 228 * filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which
    - 229 * `cond` holds true.
    - 230 * @param data the `Data` object to filter
    - 231 * @param cond the complex condition to test against
    - 232 * @return a new `Data` object with the filtered rows 
    - 233 */

    - 234export function filter(data:Data, cond:Condition):Data {
    - 235    const colNumber = (name:string):number => data.colNumber(name);
    - 236    try {
    - 237        return new Data({
    - 238            name:     data.getName(),
    - 239            colNames: data.colNames(), 
    - 240            rows:data.getData().filter((row:DataRow, i:number) => {
    - 241                const keep = resolveCondition(cond, row, i, colNumber);
    - 242                return keep;
    - 243            })
    - 244        });
    - 245    } catch(err) {
    - 246        console.log(err);
    - 247        console.log(err.stack);
    - 248    }
    - 249}
    - 250
    - - \ No newline at end of file diff --git a/docs/src/index.html b/docs/src/index.html deleted file mode 100644 index 07a3840..0000000 --- a/docs/src/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - -

    src/index.ts

    -
       1export { NumRange,
    -   2         NumDomain,
    -   3         DateDomain,
    -   4         NameDomain,
    -   5         Domain,
    -   6         ColumnReference,
    -   7         DataVal,
    -   8         DataRow,
    -   9         DataSet
    -  10        }       from './Data';
    -  11
    -  12export { Data } from './Data';
    -  13export { Condition} from './DataFilters';
    -  14
    -  15
    - - \ No newline at end of file diff --git a/docs/src/overview.html b/docs/src/overview.html deleted file mode 100644 index 28af118..0000000 --- a/docs/src/overview.html +++ /dev/null @@ -1,96 +0,0 @@ - - -

    src/overview.ts

    -
       1/**
    -   2 * # hsDatab
    -   3 * 
    -   4 * Helpful Scripts framework-independent data management functions. 
    -   5 * 
    -   6 * *hsdatab* provides a JavaScript-based data management and query mechanism.
    -   7 * Data is managed in a simple in-memory database that holds data in rows of columns. 
    -   8 * It autodetermines the types of data held in each column, along with the 
    -   9 * domain range for each column of data. 
    -  10 * Complex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure. 
    -  11 * 
    -  12 * ## Data Types
    -  13 * supported {@link Data.Data.type data types} include
    -  14 * - **number**: numeric values
    -  15 * - **name**: nominal values, represented by arbitrary words
    -  16 * - **date**: date values
    -  17 * - **currency**: Currently supported: '$dd[,ddd]'
    -  18 * - **percent**: 'd%'
    -  19 * 
    -  20 * ## Data Class
    -  21 * The fundamental object in this library is {@link Data.Data `Data`}, 
    -  22 * a simple row-column based database object, 
    -  23 * featuring named columns, sorting, mapping and filtering functions.
    -  24 *
    -  25 * ## Example
    -  26 * 
    -  27 * 
    -  28 * const colNames = ['Name', 'Value', 'Start', 'End'];
    -  29 * const rows = [
    -  30 *   ['Harry', '100', '3/1/14', '11/20/14'], 
    -  31 *   ['Mary', '1500', '7/1/14',  '9/30/14'],
    -  32 *   ['Peter', '400', '5/20/14', '4/30/15'],  
    -  33 *   ['Jane', '700', '11/13/14', '8/15/15']
    -  34 * ]
    -  35 * const data = new hsdatab.Data({colNames:colNames, rows:rows});
    -  36 * 
    -  37 * query = {Name:["Peter", "Jane"]};
    -  38 * const result = data.filter(query);
    -  39 *
    -  40 * m.mount(root, {
    -  41 *   view:() => m('', [
    -  42 *       m('h3', 'Given the data set:'),
    -  43 *       m('pre',
    -  44 *       m('table#data', [
    -  45 *           m('tr', colNames.map(n => m('th', n))),
    -  46 *           ...rows.map(row => m('tr', [
    -  47 *              m('td', row[0]),
    -  48 *              m('td', row[1]),
    -  49 *              m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),
    -  50 *              m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)
    -  51 *          ]))
    -  52 *       ])),
    -  53 *       m('h3', 'The column types and domains are'),
    -  54 *       m('pre', m('table', 
    -  55 *                  m('tr', m('th', 'Column'),   m('th', 'Type'),   m('th', 'Domain')),
    -  56 *                  m('tr', m('td', '"Name":'),  m('td', data.colType("Name")),   m('td', data.findDomain("Name").join(', '))),
    -  57 *                  m('tr', m('td', '"Value":'), m('td', data.colType("Value")),  m('td', data.findDomain("Value").join(' - '))),
    -  58 *                  m('tr', m('td', '"Start":'), m('td', data.colType("Start")),  m('td', data.findDomain("Start").map(d => d.toDateString()).join(' - '))),
    -  59 *                  m('tr', m('td', '"Stop":'),  m('td', data.colType("End")),    m('td', data.findDomain("End").map(d => d.toDateString()).join(' - ')))
    -  60 *       )),
    -  61 *       m('h3', 'The query:'),
    -  62 *       m('code', '{Name:["Peter", "Jane"]}'),
    -  63 *       m('h3', 'yields results with "Name"'),
    -  64 *       m('code', result.getColumn('Name').join(', '))
    -  65 *   ])
    -  66 * });
    -  67 * 
    -  68 * 
    -  69 *   $exampleID { height: 600px; }
    -  70 *   #data th { width:15%; }
    -  71 *   #data  { font-size: 11pt; }
    -  72 * 
    -  73 *      
    -  74 */

    -  75
    -  76 /** */
    -  77
    -  78 
    -  79
    - - \ No newline at end of file From c711ea52116edc2680084c156a8955a703d33587 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sun, 17 Jun 2018 09:24:25 +0200 Subject: [PATCH 14/17] updated docs --- data/index.json | 1 + hsDatab.json | 3285 ++++++++++++++++++++++++++++++++++++++++++ src/Data.html | 568 ++++++++ src/Data.spec.html | 54 + src/DataFilters.html | 267 ++++ src/index.html | 32 + src/overview.html | 96 ++ 7 files changed, 4303 insertions(+) create mode 100644 data/index.json create mode 100644 hsDatab.json create mode 100644 src/Data.html create mode 100644 src/Data.spec.html create mode 100644 src/DataFilters.html create mode 100644 src/index.html create mode 100644 src/overview.html diff --git a/data/index.json b/data/index.json new file mode 100644 index 0000000..c9f319f --- /dev/null +++ b/data/index.json @@ -0,0 +1 @@ +{"docs": ["hsDatab.json"], "title": "HS Libraries"} \ No newline at end of file diff --git a/hsDatab.json b/hsDatab.json new file mode 100644 index 0000000..db6ebdd --- /dev/null +++ b/hsDatab.json @@ -0,0 +1,3285 @@ +{ + "id": 0, + "name": "hsDatab", + "kind": 0, + "flags": {}, + "children": [ + { + "id": 42, + "name": "\"Data\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.ts", + "comment": {}, + "children": [ + { + "id": 56, + "name": "Data", + "kind": 128, + "kindString": "Class", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "# Data\nA simple in-memory database that holds data in rows of columns." + }, + "children": [ + { + "id": 67, + "name": "constructor", + "kind": 512, + "kindString": "Constructor", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 68, + "name": "new Data", + "kind": 16384, + "kindString": "Constructor signature", + "flags": {}, + "parameters": [ + { + "id": 69, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 86, + "character": 5 + } + ] + }, + { + "id": 117, + "name": "data", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 392, + "character": 16 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + "defaultValue": " []" + }, + { + "id": 118, + "name": "meta", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 393, + "character": 16 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "MetaStruct", + "id": 50 + } + }, + "defaultValue": " []" + }, + { + "id": 119, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 394, + "character": 16 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 134, + "name": "allRows", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 135, + "name": "allRows", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "A generator that provides the specified column value for each row in `Data` in sequence." + }, + "parameters": [ + { + "id": 136, + "name": "column", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "\n" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "Iterable", + "typeArguments": [ + { + "type": "reference", + "name": "DataVal", + "id": 151 + } + ] + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 493, + "character": 21 + } + ] + }, + { + "id": 104, + "name": "castData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 105, + "name": "castData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 260, + "character": 19 + } + ] + }, + { + "id": 141, + "name": "castVal", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 142, + "name": "castVal", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "The result of the cast.", + "tags": [ + { + "tag": "description", + "text": "Casts the sample to the specified data type.\n" + } + ] + }, + "parameters": [ + { + "id": 143, + "name": "type", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "The type to cast into. In case of _any_ - i.e. `type`\ndoes not match any of the previous keywords, no casting occurs." + }, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 144, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 529, + "character": 19 + } + ] + }, + { + "id": 82, + "name": "colAdd", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 83, + "name": "colAdd", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "adds a new column to the data set. if `newCol` already exists,\nthe column index is returned withoput change.", + "returns": "the index for the new column\n" + }, + "parameters": [ + { + "id": 84, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the name of the new column" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 140, + "character": 17 + } + ] + }, + { + "id": 85, + "name": "colInitialize", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 86, + "name": "colInitialize", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "initializes the specifed column with values, adding a new column if needed.\nIf `val`is a function, it is called as ```\nval(colValue:DataVal, rowIndex:number, row:DataRow)\n```\n@param col the column to initialize\n@param initializer the value to initialize with, or a function whose return\nvalue is used to initialize the column" + }, + "parameters": [ + { + "id": 87, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + }, + { + "id": 88, + "name": "initializer", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 162, + "character": 24 + } + ] + }, + { + "id": 92, + "name": "colName", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 93, + "name": "colName", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column name for the specified column.\n`col` can be either an index or a name.", + "returns": "the column name or `undefined`.\n" + }, + "parameters": [ + { + "id": 94, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 194, + "character": 18 + } + ] + }, + { + "id": 95, + "name": "colNames", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 96, + "name": "colNames", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the names for all columns.", + "returns": "an array of strings with the names.\n" + }, + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 205, + "character": 19 + } + ] + }, + { + "id": 89, + "name": "colNumber", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 90, + "name": "colNumber", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column index of the specified column.\n`col` can be either an index or a name.", + "returns": "the column number or `undefined`.\n" + }, + "parameters": [ + { + "id": 91, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 179, + "character": 20 + } + ] + }, + { + "id": 97, + "name": "colType", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 98, + "name": "colType", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column type for the specified column.\n`col` can be either an index or a name.", + "returns": "the column type.\n" + }, + "parameters": [ + { + "id": 99, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 215, + "character": 18 + } + ] + }, + { + "id": 75, + "name": "export", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 76, + "name": "export", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Exports to an object literal" + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 111, + "character": 17 + } + ] + }, + { + "id": 106, + "name": "filter", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 107, + "name": "filter", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "filters this data set and returns a new data set with a\nshallow copy of rows that pass the `condition`.\nSee {@link DataFilters DataFilters} for rules and examples on how to construct conditions.", + "returns": "a new Data object with rows that pass the filter\n" + }, + "parameters": [ + { + "id": 108, + "name": "condition", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "filters" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 277, + "character": 17 + } + ] + }, + { + "id": 100, + "name": "findDomain", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 101, + "name": "findDomain", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "modifies `domain` to include all values in column `col`.\nIf no `col` is specified, the range of data indexes is returned.", + "returns": "the updated domain\n" + }, + "parameters": [ + { + "id": 102, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the column name or index" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + }, + { + "id": 103, + "name": "domain", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the Domain range to update" + }, + "type": { + "type": "reference", + "name": "Domain", + "id": 149 + } + } + ], + "type": { + "type": "reference", + "name": "Domain", + "id": 149 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 227, + "character": 21 + } + ] + }, + { + "id": 131, + "name": "findType", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 132, + "name": "findType", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample\n", + "tags": [ + { + "tag": "description", + "text": "determines the data type. Supported types are\n```\n'date': sample represents a Date, either as a Date object or a String\n'number': sample represents a number\n'percent': sample represents a percentage (special case of a real number)\n'nominal': sample represents a nominal (ordinal or categorical) value\n```" + } + ] + }, + "parameters": [ + { + "id": 133, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the value to bve typed." + }, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 462, + "character": 20 + } + ] + }, + { + "id": 128, + "name": "findTypes", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 129, + "name": "findTypes", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Determines the type of data in `col`. An array of counts is created for all\nencountered types, sorted by descending frequency. THe most likely type in position 0\nof the array is returned.", + "returns": "the most likely type of data in `col`.\n" + }, + "parameters": [ + { + "id": 130, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the index of the column to be typed." + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 430, + "character": 21 + } + ] + }, + { + "id": 79, + "name": "getColumn", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 80, + "name": "getColumn", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Returns the values in the specified column as a new array." + }, + "parameters": [ + { + "id": 81, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the column to return.\n" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 129, + "character": 20 + } + ] + }, + { + "id": 77, + "name": "getData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 78, + "name": "getData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the 2D array underlying the data base." + }, + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 121, + "character": 18 + } + ] + }, + { + "id": 120, + "name": "getMeta", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 121, + "name": "getMeta", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 122, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "MetaStruct", + "id": 50 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 396, + "character": 19 + } + ] + }, + { + "id": 70, + "name": "getName", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 71, + "name": "getName", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the `name` field for this data base, if any\n" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 95, + "character": 18 + } + ] + }, + { + "id": 72, + "name": "import", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 73, + "name": "import", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Imports data from an object literal `data`" + }, + "parameters": [ + { + "id": 74, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data set to import\n" + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 103, + "character": 17 + } + ] + }, + { + "id": 113, + "name": "map", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 114, + "name": "map", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": " Maps one or more columns in each rows of values based\non the result of the `mapFn`, which behaves similarly to the Array.map() method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the `mapFn` is passed the column arrays per row as parameter.\nThis allows for complex mapping combining conditions across multiple columns.\n```\ndata.map(function(values){\n values[1] = values[3] * values[5];\n return values;\n});\n```\nBe sure to return the `values` array as a result.\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `mapFn`, along with the row index and the entire row array. This allows for simple mapping.\n```\ndata.map('Price', function(value, i, values) {\n return value * 2;\n});\n```", + "returns": "a new Data object containing the mapping.\n" + }, + "parameters": [ + { + "id": 115, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data column, or columns, to apply the mapping to." + }, + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "ColumnReference", + "id": 150 + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ] + } + }, + { + "id": 116, + "name": "mapFn", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "a function to implement the mapping,\ncalled on each row of the data set in turn as `mapFn(val, i, c, rows)`, where\n- `val`: the column value in the current row\n- `c`: the column index in the current row\n- `i`: the row index\n- `rows`: the rows being iterated over\n` *\nfollows the same specifications as the function passed to Array.map().
    \nFor column mode, some predefined map functions can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.
    " + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "mapFn", + "id": 116 + } + ] + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 359, + "character": 14 + } + ] + }, + { + "id": 123, + "name": "setData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 124, + "name": "setData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "sets `data` to the existing data set. If data has previously been set,\n`data` will be added to the end of the list if all `names` match those of the\nexisting set." + }, + "parameters": [ + { + "id": 125, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data to add" + }, + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + }, + { + "id": 126, + "name": "names", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "an array of names that match the columns" + }, + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 127, + "name": "autoType", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "unless set to false, the method will attempt to determine the\ntype of data and automatically cast data points to their correct value\n" + }, + "type": { + "type": "intrinsic", + "name": "boolean" + }, + "defaultValue": "true" + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 412, + "character": 19 + } + ] + }, + { + "id": 109, + "name": "sort", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 110, + "name": "sort", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the Data object in order to allow for chaining.\n", + "tags": [ + { + "tag": "description", + "text": "Sorts the rows of values based on the result of the `sortFn`,\nwhich behaves similarly to the Array.sort method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the column arrays are passed as samples into the `sortFn`.\nThis allows for complex sorts, combining conditions across multiple columns.\n```\ndata.sort((row1, row2) => row1[5] - row2[5] );\n```\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `sortFn`. This allows filtering for simple conditions.
    \n**The specified column will be automatically cast prior to sorting**
    \n`data.sort('Date', function(val1, val2) { return val1 - val2; });`" + } + ] + }, + "parameters": [ + { + "id": 111, + "name": "sortFn", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "a function to implement the conditions,\nfollows the same specifications as the function passed to Array.sort().\nSome predefined sort function can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.
    " + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "sortFn", + "id": 111 + } + ] + } + }, + { + "id": 112, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the data column to use for sorting." + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 307, + "character": 15 + } + ] + }, + { + "id": 137, + "name": "toDate", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 138, + "name": "toDate", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "a new Date object parsed from `str`.", + "tags": [ + { + "tag": "description", + "text": "returns a new Date object parsed from `str` and corrects for a difference in\ninterpreting centuries between webkit and mozilla in converting strings to Dates:\nThe string \"15/7/03\" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.\nIf `limitYear` is not specified this method uses 1970 as the decision date:\nyears 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.\n" + } + ] + }, + "parameters": [ + { + "id": 139, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the string to convert to a date" + }, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "id": 140, + "name": "limitYear", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the year below which the century is corrected. Defaults to 1970." + }, + "type": { + "type": "intrinsic", + "name": "number" + }, + "defaultValue": "1970" + } + ], + "type": { + "type": "reference", + "name": "Date" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 510, + "character": 18 + } + ] + }, + { + "id": 63, + "name": "toDataSet", + "kind": 2048, + "kindString": "Method", + "flags": { + "isStatic": true, + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 64, + "name": "toDataSet", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 65, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataLiteralSet", + "id": 153 + } + }, + { + "id": 66, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 80, + "character": 27 + } + ] + }, + { + "id": 57, + "name": "type", + "kind": 2097152, + "kindString": "Object literal", + "flags": { + "isStatic": true, + "isExported": true, + "isPublic": true + }, + "children": [ + { + "id": 61, + "name": "currency", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "currency values. Currently support6ed are values ofg the format '$dd[,ddd]'" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 74, + "character": 16 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"currency\"" + }, + { + "id": 60, + "name": "date", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "date values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 72, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"date\"" + }, + { + "id": 59, + "name": "name", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "nominal values, represented by arbitrary words" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 70, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"name\"" + }, + { + "id": 58, + "name": "number", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "numeric values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 68, + "character": 14 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"number\"" + }, + { + "id": 62, + "name": "percent", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "percent values: 'd%'" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 76, + "character": 15 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"percent\"" + } + ], + "groups": [ + { + "title": "Variables", + "kind": 32, + "children": [ + 61, + 60, + 59, + 58, + 62 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 66, + "character": 22 + } + ], + "type": { + "type": "intrinsic", + "name": "object" + } + } + ], + "groups": [ + { + "title": "Constructors", + "kind": 512, + "children": [ + 67 + ] + }, + { + "title": "Properties", + "kind": 1024, + "children": [ + 117, + 118, + 119 + ] + }, + { + "title": "Methods", + "kind": 2048, + "children": [ + 134, + 104, + 141, + 82, + 85, + 92, + 95, + 89, + 97, + 75, + 106, + 100, + 131, + 128, + 79, + 77, + 120, + 70, + 72, + 113, + 123, + 109, + 137, + 63 + ] + }, + { + "title": "Object literals", + "kind": 2097152, + "children": [ + 57 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 62, + "character": 17 + } + ] + }, + { + "id": 43, + "name": "DataSet", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a JSON format data set, using arrays of names and rows" + }, + "children": [ + { + "id": 45, + "name": "colNames", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "an array of column names. Each name matches the column with the same index in DataRow" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 36, + "character": 12 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 44, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "comment": { + "shortText": "an optional name for the data set" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 34, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 46, + "name": "rows", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "rows of data" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 38, + "character": 8 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 45, + 44, + 46 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 32, + "character": 24 + } + ] + }, + { + "id": 50, + "name": "MetaStruct", + "kind": 256, + "kindString": "Interface", + "flags": {}, + "children": [ + { + "id": 53, + "name": "accessed", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 49, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 54, + "name": "cast", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 50, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 52, + "name": "column", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 48, + "character": 10 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 51, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 47, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 55, + "name": "types", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 51, + "character": 9 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "TypeStruct", + "id": 47 + } + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 53, + 54, + 52, + 51, + 55 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 46, + "character": 20 + } + ] + }, + { + "id": 47, + "name": "TypeStruct", + "kind": 256, + "kindString": "Interface", + "flags": {}, + "children": [ + { + "id": 49, + "name": "count", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 42 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 48, + "name": "type", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 27 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 49, + 48 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 20 + } + ] + }, + { + "id": 150, + "name": "ColumnReference", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 23, + "character": 27 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "string" + } + ] + } + }, + { + "id": 153, + "name": "DataLiteralSet", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a JSON format data set, using an array of {name:value, ...} literals" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 42, + "character": 26 + } + ], + "type": { + "type": "reference", + "name": "Array", + "typeArguments": [ + { + "type": "intrinsic", + "name": "any" + } + ] + } + }, + { + "id": 152, + "name": "DataRow", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a single row of column values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 29, + "character": 19 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + }, + { + "id": 151, + "name": "DataVal", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a generic data value type, used in the {@link Data.DataRow `DataRow`} array" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 26, + "character": 19 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "Date" + } + ] + } + }, + { + "id": 147, + "name": "DateDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a Date domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 14, + "character": 22 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "reference", + "name": "Date" + }, + { + "type": "reference", + "name": "Date" + } + ] + } + }, + { + "id": 149, + "name": "Domain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a generic domain that can be any of the typed domains." + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 20, + "character": 18 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "NumDomain", + "id": 146 + }, + { + "type": "reference", + "name": "DateDomain", + "id": 147 + }, + { + "type": "reference", + "name": "NameDomain", + "id": 148 + } + ] + } + }, + { + "id": 148, + "name": "NameDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a categorical domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 17, + "character": 22 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 146, + "name": "NumDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a numeric domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 11, + "character": 21 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "number" + } + ] + } + }, + { + "id": 145, + "name": "NumRange", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a [min-max] range" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 8, + "character": 20 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "number" + } + ] + } + }, + { + "id": 159, + "name": "mapFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 55, + "character": 17 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 160, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 161, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 162, + "name": "colVal", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 163, + "name": "colIndex", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 164, + "name": "rowIndex", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 165, + "name": "rows", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "array", + "elementType": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "any" + } + } + } + } + ], + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 55, + "character": 20 + } + ] + } + } + }, + { + "id": 154, + "name": "sortFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 54, + "character": 18 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 155, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 156, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 157, + "name": "x", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 158, + "name": "y", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 54, + "character": 20 + } + ] + } + } + } + ], + "groups": [ + { + "title": "Classes", + "kind": 128, + "children": [ + 56 + ] + }, + { + "title": "Interfaces", + "kind": 256, + "children": [ + 43, + 50, + 47 + ] + }, + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 150, + 153, + 152, + 151, + 147, + 149, + 148, + 146, + 145, + 159, + 154 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 1, + "name": "\"DataFilters\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/DataFilters.ts", + "comment": { + "shortText": "Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object.\nEach row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object.", + "text": "# Condition construction\n\n### General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n### IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n### RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n### Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" + }, + "children": [ + { + "id": 2, + "name": "SetAndCondition", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "children": [ + { + "id": 4, + "name": "and", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 140, + "character": 7 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + }, + { + "id": 5, + "name": "not", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 141, + "character": 7 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + }, + { + "id": 3, + "name": "or", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 139, + "character": 6 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 4, + 5, + 3 + ] + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 138, + "character": 32 + } + ] + }, + { + "id": 6, + "name": "TermAndCondition", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "indexSignature": { + "id": 7, + "name": "__index", + "kind": 8192, + "kindString": "Index signature", + "flags": {}, + "parameters": [ + { + "id": 8, + "name": "colDesc", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "DataVal", + "id": 151 + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "type": "reference", + "name": "TermConditionFunction", + "id": 14 + } + ] + } + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 144, + "character": 33 + } + ] + }, + { + "id": 13, + "name": "AndCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 136, + "character": 24 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "SetAndCondition", + "id": 2 + }, + { + "type": "reference", + "name": "TermAndCondition", + "id": 6 + } + ] + } + }, + { + "id": 9, + "name": "Condition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 129, + "character": 21 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "IndexCondition", + "id": 10 + }, + { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + ] + } + }, + { + "id": 10, + "name": "IndexCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "true if row index matches the number(s)" + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 132, + "character": 26 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 12, + "name": "OrCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 135, + "character": 23 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "array", + "elementType": { + "type": "reference", + "name": "AndCondition", + "id": 13 + } + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "IndexCondition", + "id": 10 + } + } + ] + } + }, + { + "id": 11, + "name": "RecursiveCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 134, + "character": 30 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "AndCondition", + "id": 13 + }, + { + "type": "reference", + "name": "OrCondition", + "id": 12 + } + ] + } + }, + { + "id": 14, + "name": "TermConditionFunction", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 152, + "character": 33 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 15, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 16, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 17, + "name": "value", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "id": 18, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 152, + "character": 35 + } + ] + } + } + }, + { + "id": 38, + "name": "filter", + "kind": 64, + "kindString": "Function", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 39, + "name": "filter", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which\n`cond` holds true.", + "returns": "a new `Data` object with the filtered rows\n" + }, + "parameters": [ + { + "id": 40, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the `Data` object to filter" + }, + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + }, + { + "id": 41, + "name": "cond", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the complex condition to test against" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 234, + "character": 22 + } + ] + }, + { + "id": 28, + "name": "resolveCondition", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 29, + "name": "resolveCondition", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "applies `condition` to a row of data and returns `true` if the row passes." + }, + "parameters": [ + { + "id": 30, + "name": "condition", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the complex condition to test against" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + }, + { + "id": 31, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the row values" + }, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + { + "id": 32, + "name": "r", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the row index in the data set" + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 33, + "name": "colNumber", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reflection", + "declaration": { + "id": 34, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 35, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 36, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 181, + "character": 80 + } + ] + } + } + }, + { + "id": 37, + "name": "and", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "\n" + }, + "type": { + "type": "intrinsic", + "name": "boolean" + }, + "defaultValue": "true" + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 181, + "character": 25 + } + ] + }, + { + "id": 19, + "name": "resolveTerminalCondition", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 20, + "name": "resolveTerminalCondition", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 21, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 22, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 23, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + { + "id": 24, + "name": "colNumber", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reflection", + "declaration": { + "id": 25, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 26, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 27, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 155, + "character": 79 + } + ] + } + } + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 155, + "character": 33 + } + ] + } + ], + "groups": [ + { + "title": "Interfaces", + "kind": 256, + "children": [ + 2, + 6 + ] + }, + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 13, + 9, + 10, + 12, + 11, + 14 + ] + }, + { + "title": "Functions", + "kind": 64, + "children": [ + 38, + 28, + 19 + ] + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 166, + "name": "\"index\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/index.ts", + "sources": [ + { + "fileName": "index.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 167, + "name": "\"overview\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", + "comment": { + "shortText": "# hsDatab", + "text": "Helpful Scripts framework-independent data management functions. [Github page](https://github.com/HelpfulScripts/hsDatab)\n\n**hsDatab** provides a JavaScript-based data management and query mechanism.\nData is managed in a simple in-memory database that holds data in rows of columns.\nIt autodetermines the types of data held in each column, along with the\ndomain range for each column of data.\nComplex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure.\n\n## Data Types\nsupported {@link Data.Data.type data types} include\n- **number**: numeric values\n- **name**: nominal values, represented by arbitrary words\n- **date**: date values\n- **currency**: Currently supported: '$dd[,ddd]'\n- **percent**: 'd%'\n\n## Data Class\nThe fundamental object in this library is {@link Data.Data `Data`},\na simple row-column based database object,\nfeaturing named columns, sorting, mapping and filtering functions.\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query);\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('pre',\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [\n m('td', row[0]),\n m('td', row[1]),\n m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),\n m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)\n ]))\n ])),\n m('h3', 'The column types and domains are'),\n m('pre', m('table',\n m('tr', m('th', 'Column'), m('th', 'Type'), m('th', 'Domain')),\n m('tr', m('td', '\"Name\":'), m('td', data.colType(\"Name\")), m('td', data.findDomain(\"Name\").join(', '))),\n m('tr', m('td', '\"Value\":'), m('td', data.colType(\"Value\")), m('td', data.findDomain(\"Value\").join(' - '))),\n m('tr', m('td', '\"Start\":'), m('td', data.colType(\"Start\")), m('td', data.findDomain(\"Start\").map(d => d.toDateString()).join(' - '))),\n m('tr', m('td', '\"Stop\":'), m('td', data.colType(\"End\")), m('td', data.findDomain(\"End\").map(d => d.toDateString()).join(' - ')))\n )),\n m('h3', 'The query:'),\n m('code', '{Name:[\"Peter\", \"Jane\"]}'),\n m('h3', 'yields results with \"Name\"'),\n m('code', result.getColumn('Name').join(', '))\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n #data { font-size: 11pt; }\n\n\n" + }, + "sources": [ + { + "fileName": "overview.ts", + "line": 1, + "character": 0 + } + ] + } + ], + "groups": [ + { + "title": "External modules", + "kind": 1, + "children": [ + 42, + 1, + 166, + 167 + ] + } + ] +} \ No newline at end of file diff --git a/src/Data.html b/src/Data.html new file mode 100644 index 0000000..8e87921 --- /dev/null +++ b/src/Data.html @@ -0,0 +1,568 @@ + + +

    src/Data.ts

    +
       1/**
    +   2 */

    +   3
    +   4 /** */
    +   5import { Condition, filter } from './DataFilters';
    +   6
    +   7/** defines a [min-max] range */
    +   8export type NumRange = [number, number];
    +   9
    +  10/** defines a numeric domain that includes all values of a column */
    +  11export type NumDomain = [number, number];
    +  12
    +  13/** defines a Date domain that includes all values of a column */
    +  14export type DateDomain = [Date, Date];
    +  15
    +  16/** defines a categorical domain that includes all values of a column */
    +  17export type NameDomain = string[];
    +  18
    +  19/** defines a generic domain that can be any of the typed domains. */
    +  20export type Domain = NumDomain | DateDomain | NameDomain;
    +  21
    +  22/** defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array */
    +  23export type ColumnReference = number|string;
    +  24
    +  25/** a generic data value type, used in the {@link Data.DataRow `DataRow`} array */
    +  26export type DataVal = number|string|Date;
    +  27
    +  28/** a single row of column values */
    +  29export type DataRow = DataVal[];
    +  30
    +  31/** a JSON format data set, using arrays of names and rows */
    +  32export interface DataSet {
    +  33    /** an optional name for the data set */
    +  34    name?:  string;
    +  35    /** an array of column names. Each name matches the column with the same index in DataRow */
    +  36    colNames:  string[];   
    +  37    /** rows of data */
    +  38    rows:   DataRow[];
    +  39}
    +  40
    +  41/** a JSON format data set, using an array of {name:value, ...} literals*/
    +  42export type DataLiteralSet = Array;
    +  43
    +  44interface TypeStruct { type: string; count: number;};
    +  45
    +  46interface MetaStruct {
    +  47    name:       string;         // column name
    +  48    column:     number;         // column index
    +  49    accessed:   boolean;        // has column data been accessed?
    +  50    cast:       boolean;        // has column data been cast 
    +  51    types:      TypeStruct[];   // data types, sorted by likelihood
    +  52}
    +  53
    +  54export type sortFn = (x:any, y:any) => number;
    +  55export type mapFn  = (colVal:any, colIndex?:number, rowIndex?:number, rows?:any[][]) => any;
    +  56
    +  57/**
    +  58 * # Data
    +  59 * A simple in-memory database that holds data in rows of columns.
    +  60 * 
    +  61 */

    +  62export class Data {
    +  63    //----------------------------
    +  64    // public part
    +  65    //----------------------------
    +  66    public static type = {
    +  67        /** numeric values */
    +  68        number:     'number',
    +  69        /** nominal values, represented by arbitrary words */
    +  70        name:       'name',
    +  71        /** date values */
    +  72        date:       'date',
    +  73        /** currency values. Currently support6ed are values ofg the format '$dd[,ddd]' */
    +  74        currency:   'currency',
    +  75        /** percent values: 'd%' */
    +  76        percent:    'percent',
    +  77//        nominal:    'nominal'
    +  78    };
    +  79
    +  80    public static toDataSet(data:DataLiteralSet, name?:string):DataSet {
    +  81        data = data || [{}];
    +  82        const names = Object.keys(data[0]);
    +  83        const rows = data.map((r:any) => 
    +  84            names.map((n:string) => r[n]));
    +  85        return { rows:rows, colNames:names, name:name||undefined };
    +  86    }
    +  87
    +  88    constructor(data?:DataSet) {
    +  89        this.import(data);
    +  90    }
    +  91
    +  92    /**
    +  93     * @return the `name` field for this data base, if any
    +  94     */

    +  95    public getName():string {
    +  96        return this.name;
    +  97    }
    +  98
    +  99    /**
    + 100     * Imports data from an object literal `data`
    + 101     * @param data the data set to import
    + 102     */

    + 103    public import(data:DataSet) {
    + 104        this.name = data.name;
    + 105        this.setData(data.rows, data.colNames);
    + 106    }
    + 107
    + 108    /**
    + 109     * Exports to an object literal
    + 110     */

    + 111    public export():DataSet {
    + 112        return {
    + 113            rows: this.getData(),
    + 114            colNames:this.colNames()
    + 115        };
    + 116    }
    + 117
    + 118    /**
    + 119     * returns the 2D array underlying the data base.
    + 120     */

    + 121    public getData():DataRow[] {
    + 122        return this.data;
    + 123    }
    + 124
    + 125    /**
    + 126     * Returns the values in the specified column as a new array.
    + 127     * @param col the column to return.
    + 128     */

    + 129    public getColumn(col:ColumnReference): DataVal[] {
    + 130        const cn = this.colNumber(col);
    + 131        return this.data.map((row:DataRow) => row[cn]);
    + 132    }
    + 133
    + 134    /**
    + 135     * adds a new column to the data set. if `newCol` already exists, 
    + 136     * the column index is returned withoput change.
    + 137     * @param col the name of the new column
    + 138     * @return the index for the new column
    + 139     */

    + 140    public colAdd(col:string):number {
    + 141        let m = this.getMeta(col);
    + 142        if (m === undefined) { 
    + 143            m = this.meta[col] = {};
    + 144            m.name   = col; 
    + 145            m.column = this.meta.length;
    + 146            this.meta.push(m);      // access name by both column name and index
    + 147            m.cast     = false;         // has not been cast yet
    + 148            m.accessed = false;         // has not been accessed yet
    + 149        }
    + 150        return m.column;
    + 151    }
    + 152
    + 153    /**
    + 154     * initializes the specifed column with values, adding a new column if needed. 
    + 155     * If `val`is a function, it is called as ```
    + 156     * val(colValue:DataVal, rowIndex:number, row:DataRow)
    + 157     * ```
    + 158     * @param col the column to initialize
    + 159     * @param initializer the value to initialize with, or a function whose return
    + 160     * value is used to initialize the column
    + 161     */

    + 162    public colInitialize(col:ColumnReference, initializer:any) {
    + 163        const cn = this.colNumber(col);
    + 164        if (!cn  && typeof col === 'string') { this.colAdd(col); }
    + 165        const fn = typeof initializer === 'function';
    + 166        if (cn!==undefined) {
    + 167            this.data.map((r:DataRow, i:number) =>
    + 168                r[cn] = fn? initializer(r[cn], i, r) : initializer
    + 169            );
    + 170        }
    + 171    }
    + 172
    + 173    /**
    + 174     * returns the column index of the specified column. 
    + 175     * `col` can be either an index or a name.
    + 176     * @param column the data column, name or index, for which to return the index. 
    + 177     * @return the column number or `undefined`.
    + 178     */

    + 179    public colNumber(col:ColumnReference) {
    + 180        const m = this.getMeta(col);
    + 181        if (!m) { return undefined; }
    + 182        else {
    + 183            m.accessed = true; 
    + 184            return m.column; 
    + 185        }
    + 186    }
    + 187    
    + 188    /**
    + 189     * returns the column name for the specified column. 
    + 190     * `col` can be either an index or a name.
    + 191     * @param column the data column, name or index. 
    + 192     * @return the column name or `undefined`.
    + 193     */

    + 194    public colName(col:ColumnReference) {
    + 195        var m = this.getMeta(col);
    + 196        if (!m) { return undefined; }
    + 197        m.accessed = true; 
    + 198        return m.name; 
    + 199    }
    + 200
    + 201    /**
    + 202     * returns the names for all columns. 
    + 203     * @return an array of strings with the names.
    + 204     */

    + 205    public colNames():string[] {
    + 206        return this.meta.map((m:MetaStruct) => m.name); 
    + 207    }
    + 208
    + 209    /**
    + 210     * returns the column type for the specified column. 
    + 211     * `col` can be either an index or a name.
    + 212     * @param column the data column, name or index. 
    + 213     * @return the column type.
    + 214     */

    + 215    public colType(col:ColumnReference) { 
    + 216        const meta = this.getMeta(col);
    + 217        return meta? meta.types[0].type : Data.type.name;
    + 218    }
    + 219
    + 220    /**
    + 221     * modifies `domain` to include all values in column `col`.
    + 222     * If no `col` is specified, the range of data indexes is returned.
    + 223     * @param col optional; the column name or index 
    + 224     * @param domain optional; the Domain range to update
    + 225     * @return the updated domain
    + 226     */

    + 227    public findDomain(col?:ColumnReference, domain?:Domain):Domain {
    + 228        if (domain===undefined) { domain = []; }
    + 229        if (col === undefined) { // use array index as domain
    + 230            domain[0] = 0;
    + 231            domain[1] = this.data.length-1;
    + 232        } else {
    + 233            const c = this.colNumber(col);
    + 234            const type = this.colType(col);
    + 235            if (this.data === undefined) {
    + 236                console.log('no data'); 
    + 237            }
    + 238            switch(type) {
    + 239                case Data.type.name: 
    + 240                    this.data.forEach((r:DataRow) => {
    + 241                        const nomDom = domain;
    + 242                        if (nomDom.indexOf(''+r[c]) < 0) { nomDom.push(''+r[c]); }
    + 243                    });
    + 244                    break;
    + 245                default: 
    + 246                    this.data.forEach((r:DataRow) => {
    + 247                        let v:number = r[c];
    + 248                        if (domain[0]===undefined) { domain[0] = v; }
    + 249                        if (domain[1]===undefined) { domain[1] = v; }
    + 250                        if (v!==undefined && v!==null) {
    + 251                            if (v + 252                            else if (v>domain[1]) { domain[1] = v; }
    + 253                        }
    + 254                    });
    + 255            }
    + 256        }
    + 257        return domain;
    + 258    }
    + 259
    + 260    public castData() {
    + 261        this.meta.forEach((c:MetaStruct) => {
    + 262            const col = c.column;
    + 263            if (!c.cast) {
    + 264                this.data.forEach((row:DataRow) => row[col] = this.castVal(c.types[0].type, row[col]));
    + 265            }
    + 266            c.cast = true;
    + 267        });
    + 268    }
    + 269
    + 270    /**
    + 271     * filters this data set and returns a new data set with a 
    + 272     * shallow copy of rows that pass the `condition`.
    + 273     * See {@link DataFilters DataFilters} for rules and examples on how to construct conditions.
    + 274     * @param condition filters 
    + 275     * @return a new Data object with rows that pass the filter
    + 276     */

    + 277    public filter(condition:Condition):Data {
    + 278        return filter(this, condition);
    + 279    }
    + 280
    + 281    /**
    + 282     * @description Sorts the rows of values based on the result of the `sortFn`, 
    + 283     * which behaves similarly to the Array.sort method.  
    + 284     * Two modes are supported:
    + 285     * # Array Mode
    + 286     * If `col` is omitted, the column arrays are passed as samples into the `sortFn`. 
    + 287     * This allows for complex sorts, combining conditions across multiple columns.
    + 288     * ```
    + 289     * data.sort((row1, row2) => row1[5] - row2[5] );
    + 290     * ```
    + 291     * # Column mode
    + 292     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 293     * into `sortFn`. This allows filtering for simple conditions.

    + 294     * **The specified column will be automatically cast prior to sorting**

    + 295     * `data.sort('Date', function(val1, val2) { return val1 - val2; });`
    + 296     * @param col optional; the data column to use for sorting. 
    + 297     * @param sortFn a function to implement the conditions, 
    + 298     * follows the same specifications as the function passed to Array.sort(). 
    + 299     * Some predefined sort function can be invoked by providing a 
    + 300     * respective string instead of a function. The following functions are defined:
    + 301        
    + 302        
    + 303        
    + 304        
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.

    + 305     * @return the Data object in order to allow for chaining.
    + 306     */

    + 307    public sort(sortFn:string|sortFn, col?:ColumnReference):Data {
    + 308        let fn = sortFn;
    + 309        if (!col) {
    + 310            this.data.sort(fn);
    + 311        } else {
    + 312            col = this.colNumber(col);
    + 313            if (sortFn === 'descending') { fn = (a:any, b:any)  => (b>a)?1:((b + 314            if (sortFn === 'ascending')  { fn = (a:any, b:any)  => (ba)?-1:0); }
    + 315            this.data.sort((r1:any[], r2:any[]) => fn(r1[col], r2[col])); 
    + 316        }
    + 317        return this;
    + 318    }
    + 319
    + 320    /** 
    + 321    *  Maps one or more columns in each rows of values based 
    + 322     * on the result of the `mapFn`, which behaves similarly to the Array.map() method.
    + 323     * Two modes are supported:
    + 324     * # Array Mode
    + 325     * If `col` is omitted, the `mapFn` is passed the column arrays per row as parameter. 
    + 326     * This allows for complex mapping combining conditions across multiple columns.
    + 327     * ```
    + 328     * data.map(function(values){ 
    + 329     *    values[1] = values[3] * values[5]; 
    + 330     *    return values; 
    + 331     * });
    + 332     * ```
    + 333     * Be sure to return the `values` array as a result.
    + 334     * # Column mode
    + 335     * If `col` is specified, either as index or by column name, the respective column value is passed
    + 336     * into `mapFn`, along with the row index and the entire row array. This allows for simple mapping.
    + 337     * ```
    + 338     * data.map('Price', function(value, i, values) { 
    + 339     *    return value * 2; 
    + 340     * });
    + 341     * ```
    + 342     * @param col the data column, or columns, to apply the mapping to. 
    + 343     * @param mapFn a function to implement the mapping,
    + 344     * called on each row of the data set in turn as `mapFn(val, i, c, rows)`, where
    + 345     * - `val`: the column value in the current row
    + 346     * - `c`: the column index in the current row
    + 347     * - `i`: the row index 
    + 348     * - `rows`: the rows being iterated over
    + 349`    * 
    + 350     * follows the same specifications as the function passed to Array.map().

    + 351     * For column mode, some predefined map functions can be invoked by providing a 
    + 352     * respective string instead of a function. The following functions are defined:
    + 353        
    + 354        
    + 355        
    + 356        
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.

    + 357     * @return a new Data object containing the mapping.
    + 358     */

    + 359    public map(col:ColumnReference|ColumnReference[], mapFn:string|mapFn):Data {
    + 360        const noop = (val:any) => val;
    + 361        const cumulate = () => { 
    + 362            let sum=0; 
    + 363            return (val:number, i:number) => { sum += +val; return sum; };
    + 364        };
    + 365        function getFn() {
    + 366            let fn; // define fn inside each col loop to ensure initialization
    + 367            switch (mapFn) {
    + 368                case 'cumulate': fn = cumulate(); break;
    + 369                case 'noop':     fn = noop; break;
    + 370                default:         fn = mapFn;
    + 371            }
    + 372            return fn;
    + 373        }
    + 374
    + 375        let result = new Data({colNames:this.colNames(), rows:this.data.slice(), name:this.getName()});
    + 376
    + 377        const names = col['length']? col : [col];            
    + 378        names.map((cn:ColumnReference) => {
    + 379            const c = this.colNumber(cn);
    + 380            let fn = getFn(); // define fn inside each col loop to ensure initialization
    + 381            result.data = result.data.map((row:any[], i:number, rows:any[][]) => { 
    + 382                row[c] = fn(row[c], c, i, rows); 
    + 383                return row;
    + 384            });
    + 385        });
    + 386        return result;
    + 387    }
    + 388
    + 389    //----------------------------
    + 390    // private part
    + 391    //----------------------------
    + 392    private data: DataRow[]    = [];
    + 393    private meta: MetaStruct[] = [];
    + 394    private name: string;
    + 395
    + 396    private getMeta(col:ColumnReference):MetaStruct { 
    + 397        if (!this.meta) { this.meta = []; }
    + 398        if (!this.meta[col]) { return undefined; }
    + 399        this.meta[col].accessed = true;
    + 400        return this.meta[col]; 
    + 401    }
    + 402
    + 403    /**
    + 404     * sets `data` to the existing data set. If data has previously been set, 
    + 405     * `data` will be added to the end of the list if all `names`  match those of the 
    + 406     * existing set. 
    + 407     * @param data the data to add
    + 408     * @param names an array of names that match the columns
    + 409     * @param autoType unless set to false, the method will attempt to determine the 
    + 410     * type of data and automatically cast data points to their correct value
    + 411     */

    + 412    private setData(data:DataRow[], names:string[], autoType=true):void {
    + 413        this.meta = [];
    + 414        this.data = data;
    + 415        if (!names) {
    + 416            console.log();
    + 417        }
    + 418        names.forEach((col:string) => this.colAdd(col));
    + 419        names.forEach((col:string) => this.findTypes(col));
    + 420        this.castData();
    + 421    }
    + 422
    + 423    /**
    + 424     * Determines the type of data in `col`. An array of counts is created for all
    + 425     * encountered types, sorted by descending frequency. THe most likely type in position 0
    + 426     * of the array is returned.
    + 427     * @param col the index of the column to be typed. 
    + 428     * @return the most likely type of data in `col`.
    + 429     */

    + 430    private findTypes(col:ColumnReference):string {
    + 431        const m = this.getMeta(col);
    + 432        const types:TypeStruct[] = [];
    + 433        Object.keys(Data.type).forEach((t:string) => {
    + 434            const ts = { type: Data.type[t], count: 0 }; 
    + 435            types.push(ts);
    + 436            types[Data.type[t]] = ts;
    + 437        });
    + 438        for (let v of this.allRows(col)) {
    + 439            const t = this.findType(v);
    + 440            if (t !== null) { types[t].count++; }
    + 441        }
    + 442        types.sort(function(a:TypeStruct, b:TypeStruct) { 
    + 443            if (a.type==='currency'&&a.count>0) { return -1; }
    + 444            if (b.type==='currency'&&b.count>0) { return 1; }
    + 445            return b.count - a.count;
    + 446        });
    + 447        m.types = types;
    + 448        return types[0].type;
    + 449    }
    + 450
    + 451    /**
    + 452     * @description determines the data type. Supported types are 
    + 453     * ```
    + 454     * 'date':    sample represents a Date, either as a Date object or a String 
    + 455     * 'number':  sample represents a number
    + 456     * 'percent': sample represents a percentage (special case of a real number)
    + 457     * 'nominal': sample represents a nominal (ordinal or categorical) value
    + 458     * ```
    + 459     * @param val the value to bve typed.
    + 460     * @returns the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample
    + 461     */

    + 462    private findType(val:DataVal) {
    + 463        if (val && val!=='') {
    + 464            if (val instanceof Date) { return Data.type.date; }         // if val is already a date
    + 465            if (typeof val === 'number') { return Data.type.number; }   // if val is already a number
    + 466
    + 467            // else: val is a string:
    + 468            const strVal = ''+val;
    + 469            if (''+parseFloat(strVal) === strVal)                              { return Data.type.number; }
    + 470            if (strVal.startsWith('$') && !isNaN(parseFloat(strVal.slice(1)))) { return Data.type.currency; }
    + 471            if (strVal.endsWith('%') && !isNaN(parseFloat(strVal)))            { return Data.type.percent; }
    + 472            if (!isNaN(this.toDate(strVal).getTime()))                        { return Data.type.date; }
    + 473
    + 474            // european large number currency representation: '$dd[,ddd]'
    + 475            if ((/^\$\d{0,2}((,\d\d\d)*)/g).test(val)) { 
    + 476                if (!isNaN(parseFloat(val.trim().replace(/[^eE\+\-\.\d]/g, '').replace(/,/g, '')))) { 
    + 477                    return Data.type.currency; 
    + 478                }
    + 479            }
    + 480            switch (strVal.toLowerCase()) {
    + 481                case "null": break;
    + 482                case "#ref!": break;
    + 483                default: if (val.length>0) { return Data.type.name; }
    + 484            }
    + 485        }
    + 486        return null;
    + 487    }    
    + 488
    + 489    /**
    + 490     * A generator that provides the specified column value for each row in `Data` in sequence. 
    + 491     * @param column 
    + 492     */

    + 493    private * allRows(column:ColumnReference):Iterable {
    + 494        const c = this.colNumber(column);
    + 495        for (let r=0; r + 496            yield this.data[r][c];
    + 497        }
    + 498    }
    + 499
    + 500    /**
    + 501     * @param val the string to convert to a date
    + 502     * @param limitYear the year below which the century is corrected. Defaults to 1970.
    + 503     * @returns a new Date object parsed from `str`.
    + 504     * @description returns a new Date object parsed from `str` and corrects for a difference in 
    + 505     * interpreting centuries between webkit and mozilla in converting strings to Dates:
    + 506     * The string "15/7/03" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.
    + 507     * If `limitYear` is not specified this method uses 1970 as the decision date: 
    + 508     * years 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.
    + 509     */

    + 510    private toDate(val:DataVal, limitYear=1970):Date {
    + 511        let d:Date;
    + 512        if (val instanceof Date) { d = val; }
    + 513                            else { d = new Date(val); }   
    + 514        let yr=d.getFullYear();
    + 515        if (yr < 100) { 
    + 516            yr += 1900; 
    + 517            d.setFullYear( (yr < limitYear)? yr+100 : yr);
    + 518        }
    + 519        return d;
    + 520    }
    + 521
    + 522    /**
    + 523     * @param type ['date' | 'percent' | 'real' | _any_] The type to cast into. In case of _any_ - i.e. `type` 
    + 524     * does not match any of the previous keywords, no casting occurs.
    + 525     * @param sample The value to cast.
    + 526     * @returns The result of the cast. 
    + 527     * @description Casts the sample to the specified data type.
    + 528     */

    + 529    private castVal(type:string, val:DataVal):DataVal {
    + 530        switch (type) {
    + 531            case Data.type.date:    if (val instanceof Date) { return val; }
    + 532                            val = this.toDate(val);
    + 533                            if (isNaN(val.getTime())) { val = null; }
    + 534                            break;
    + 535            case Data.type.percent: if (typeof val === 'string') {
    + 536                                const num = parseFloat(val);
    + 537                                val = (val).endsWith('%')? num/100 : num;
    + 538                            } 
    + 539                            if (isNaN(val)) { val = null; }
    + 540                            break;
    + 541            case Data.type.currency:// replace all except 'e/E', '.', '+/-' and digits
    + 542             if (typeof val === 'string') { val = val.replace(/[^eE\+\-\.\d]/g, ''); }            
    + 543             /* falls through */
    + 544            case Data.type.number:  if (typeof val === 'string') { val = parseFloat(val); }
    + 545                            if (isNaN(val)) { val = null; }
    + 546                            break;
    + 547            default:        val = ''+val;
    + 548        }
    + 549        return val;
    + 550     }     
    + 551}
    + + \ No newline at end of file diff --git a/src/Data.spec.html b/src/Data.spec.html new file mode 100644 index 0000000..7f18f3f --- /dev/null +++ b/src/Data.spec.html @@ -0,0 +1,54 @@ + + +

    src/Data.spec.ts

    +
       1var o = require("mithril/ospec/ospec");
    +   2import * as hsdatab     from './';
    +   3
    +   4const colNames = ['Name', 'Value', 'Start', 'End'];
    +   5const rows = [
    +   6  ['Harry', '100', '3/1/14', '11/20/14'], 
    +   7  ['Mary', '1500', '7/1/14',  '9/30/14'],
    +   8  ['Peter', '400', '5/20/14', '4/30/15'],  
    +   9  ['Jane', '700', '11/13/14', '8/15/15']
    +  10];
    +  11
    +  12const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  13
    +  14const query = {Name:["Peter", "Jane"]};
    +  15const result = data.filter(query);
    +  16
    +  17o.spec("Data", () => {
    +  18    o("is created with 4 rows", () => {
    +  19        o(data.getData().length).equals(4);
    +  20    });
    +  21});
    +  22o.spec('Data Filters', () => {
    +  23    o('Query for {Name:["Peter", "Jane"]}', () => {
    +  24        o(result.getData().length).equals(2)('has two rows');
    +  25        o(result.getColumn('Name')[0]).equals('Peter')('has first row name Peter');
    +  26    });
    +  27});
    +  28
    +  29
    +  30/*
    +  31        var vnode = MyComponent.view()
    +  32
    +  33        o(vnode.tag).equals("div")
    +  34        o(vnode.children.length).equals(1)
    +  35        o(vnode.children[0].tag).equals("p")
    +  36        o(vnode.children[0].children).equals("Hello world")
    +  37*/

    + + \ No newline at end of file diff --git a/src/DataFilters.html b/src/DataFilters.html new file mode 100644 index 0000000..7669d54 --- /dev/null +++ b/src/DataFilters.html @@ -0,0 +1,267 @@ + + +

    src/DataFilters.ts

    +
       1
    +   2/**
    +   3* Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object. 
    +   4* Each row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object. 
    +   5
    +   6* # Condition construction
    +   7*  
    +   8* ### General Condition
    +   9* ```
    +  10* Condition = 
    +  11*    IndexCondition            -> conditions on the row index
    +  12* || RecursiveCondition        -> (set of) conditions on column values
    +  13* ```
    +  14
    +  15* ### IndexCondition
    +  16* ```
    +  17* IndexCondition =
    +  18*    rowIndex:number           -> true if row index matches
    +  19* ```
    +  20
    +  21* ### RecursiveCondition
    +  22* ```
    +  23* RecursiveCondition =
    +  24*    OrCondition               -> OR: true if any compound condition is true
    +  25* || AndCondition              -> AND: true if all compound conditions are true
    +  26
    +  27* OrCondition =                -> OR: true if
    +  28*    AndCondition[]               -> any of the AndConditions are true
    +  29* || IndexCondition[]             -> any of thr IndexConditions are true
    +  30
    +  31* AndCondition =               -> AND: true if
    +  32*    SetAndCondition              -> all SetAndConditions are true
    +  33* || TermAndCondition             -> or if all TermAndConditions are true
    +  34*
    +  35* SetAndCondition = {          -> AND: true if all sub-conditions are true
    +  36*    'or':  RecursiveCondition    -> true if any RecursiveCondition is true
    +  37* || 'and': RecursiveCondition    -> true if all RecursiveCondition are true
    +  38* || 'not': RecursiveCondition    -> true if the condition is false
    +  39*
    +  40* TermAndCondition = {         -> Terminal AND: true if all terminal sub-conditions are true
    +  41*    colDesc:colValue             -> true if colValue matches 
    +  42* || colDesc:[colValue, ...]      -> true if any of the colValues match
    +  43* || colDesc:function(value,row)  -> true if function returns true 
    +  44* }
    +  45
    +  46* colDesc = either column name or index
    +  47* ```
    +  48
    +  49* ### Practical Tips
    +  50* ```
    +  51*    {'or': [recurCond, ...]}    -> OR, same as [recurCond, ...]
    +  52* || {'or': {SetCond, ...}}      -> OR, same as [SetCond, ...]
    +  53* || {'and': [recurCond, ...]}   -> AND, true if all recurCond are true
    +  54* || {'and': {SetCond, ...}}     -> AND, same as {SetCond, ...}
    +  55* || {'not': {SetCond, ...}}     -> NAND: true if the SetCond are true
    +  56* || {'not': [recurCond, ...]}   -> NOR: true if any of the recurCond are true
    +  57* ```
    +  58*      
    +  59* # Example
    +  60
    +  61
    +  62* const colNames = ['Name', 'Value', 'Start', 'End'];
    +  63* const rows = [
    +  64*   ['Harry', '100', '3/1/14', '11/20/14'], 
    +  65*   ['Mary', '1500', '7/1/14',  '9/30/14'],
    +  66*   ['Peter', '400', '5/20/14', '4/30/15'],  
    +  67*   ['Jane', '700', '11/13/14', '8/15/15']
    +  68* ]
    +  69* const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  70
    +  71* queries = [
    +  72*   ['0', undefined,                           'undefined query => pass all'],
    +  73*   ['1', [],                                  'empty OR:  []   => fail all'],
    +  74*   ['2', {},                                  'empty AND: {}   => pass all'],
    +  75*   ['3', 1,                                   '2nd row: pass row 1'],
    +  76*   ['4', [1,3],                               '2nd+4th: pass rows: 1 and 3'],
    +  77*   ['5', {Name:"Jane"},                       'Name is Jane'],
    +  78*   ['6', {1:1500},                            'Column 2 is 1500'],
    +  79*   ['7', {Name:["Peter", "Jane"]},            'Name is Peter or Jane'],
    +  80*   ['8', [{Name:"Peter"}, {Value:1500}],      'Name is Peter or Value is 1500'],
    +  81*   ['9', {or:{Name:"Peter", Value:1500}},     'OR:  same as 8:'],
    +  82*   ['A', {or:[{Name:"Peter"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],
    +  83*   ['B', {Name:"Peter", Value:400},           'Name is Peter and Value is 400'],
    +  84*   ['C', {and:{Name:"Peter", Value:400}},     'AND: {Name is Peter, Value is 400}'],
    +  85*   ['D', {and:{Name:"Peter", Value:1500}},    'AND: {Name is Peter, Value is 1500}'],
    +  86*   ['E', {and:[{Name:"Peter"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],
    +  87*   ['F', {and:[{Name:"Peter"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],
    +  88*   ['G', {not:{Name:"Peter", Value:400}},     'NAND: not {Name is Peter and Value is 400}'],
    +  89*   ['H', {not:{Name:"Peter", Value:1500}},    'NAND: not {Name is Peter and Value is 1500}'],
    +  90*   ['I', {not:[{Name:"Peter"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],
    +  91*   ['J', {Name:(v) => v.length===4},          'Name has 4 letters']
    +  92* ];
    +  93*
    +  94* m.mount(root, { 
    +  95*   view:() => m('', [
    +  96*       m('h3', 'Given the data set:'),
    +  97*       m('table#data', [
    +  98*           m('tr', colNames.map(n => m('th', n))),
    +  99*           ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))
    + 100*       ]),
    + 101*       m('h3', 'The following queries yield:'),
    + 102*       m('table', [
    + 103*           m('tr', [m('th','#'), m('th','Query'), m('th',"Live Result, by 'Name' field")]),
    + 104*           ...queries.map(q => {
    + 105*               const result = data.filter(q[1]).getColumn('Name').join(', ');
    + 106*               return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);
    + 107*           })
    + 108*       ])
    + 109*   ])
    + 110* });
    + 111
    + 112
    + 113*   $exampleID { height: 600px; }
    + 114*   #data th { width:15%; }
    + 115*   table { 
    + 116*       font-size: 10pt;
    + 117*       margin-left: 10px;
    + 118*   }
    + 119
    + 120*      
    + 121*/

    + 122
    + 123/** */
    + 124import { Data,
    + 125         DataVal,
    + 126         DataRow
    + 127} from './Data'; 
    + 128
    + 129export type Condition = IndexCondition | RecursiveCondition;
    + 130
    + 131/** true if row index matches the number(s) */
    + 132export type IndexCondition = number;
    + 133
    + 134export type RecursiveCondition = AndCondition | OrCondition;
    + 135export type OrCondition = AndCondition[] | IndexCondition[];
    + 136export type AndCondition = SetAndCondition | TermAndCondition;
    + 137
    + 138export interface SetAndCondition {
    + 139    or?: RecursiveCondition;
    + 140    and?:RecursiveCondition;
    + 141    not?:RecursiveCondition;
    + 142};
    + 143
    + 144export interface TermAndCondition { 
    + 145    [colDesc:string]: 
    + 146        DataVal 
    + 147      | DataVal[]
    + 148      | TermConditionFunction
    + 149    ;
    + 150};
    + 151
    + 152export type TermConditionFunction = (value:DataVal, row:DataRow) => boolean;
    + 153
    + 154
    + 155function resolveTerminalCondition(name:string, val:any, row:DataRow, colNumber:(name:string)=>number):boolean { 
    + 156    const col = colNumber(name);
    + 157    const valIsFunction = (typeof val === 'function');
    + 158    const valIsArray = ((typeof val === 'object') && (val.length!==undefined));
    + 159    if (isNaN(col)) { 
    + 160        console.log(`column name '${name}' cannot be resolved in terminal condition ${name}=${val}`);
    + 161        console.log(row);
    + 162        return false; // -> this condition is not met;
    + 163    } else if (valIsFunction) { 
    + 164        // query true if function evaluates to true
    + 165        return val(row[col], row);
    + 166    } else if (valIsArray) {
    + 167        // query true if empty array, or at least one c true
    + 168        return (val.length === 0) || val.some((v:any) => row[col] === v); 
    + 169    } else { // object: all conditions have to be met, unless specified as or
    + 170        return (row[col] === val); 
    + 171    }
    + 172}
    + 173
    + 174/**
    + 175 * applies `condition` to a row of data and returns `true` if the row passes.
    + 176 * @param condition the complex condition to test against
    + 177 * @param r the row index in the data set
    + 178 * @param row the row values 
    + 179 * @param and 
    + 180 */

    + 181function resolveCondition(condition:Condition, row:DataRow, r:number, colNumber:(name:string)=>number, and=true):boolean { 
    + 182    let orResult = false;
    + 183    let andResult= true;          
    + 184    // undefined condition is TRUE
    + 185    if (condition===undefined) { return true; }
    + 186    
    + 187    // Simple Index Condition on row index:
    + 188    else if (typeof condition === 'number') { return (condition === r); }
    + 189
    + 190    // Recursive Condition - OR: [...], AND {...}: 
    + 191    else if (typeof condition === 'object') {
    + 192        // array -> or condition on a list of row indices or compound conditions
    + 193        const mc = condition;
    + 194
    + 195        // OR condition: [...] 
    + 196        if (mc.length !== undefined) {            
    + 197            return (mc.length === 0)? 
    + 198                // empty OR is false:
    + 199                false : 
    + 200                // else: OR is true if any sub-condition is met
    + 201                mc.some((cd:AndCondition) => resolveCondition(cd, row, r, colNumber, false));
    + 202        } 
    + 203        // AND condition: {...}
    + 204        else { 
    + 205            for (const name in condition) {
    + 206                let conditionMet = and; // initialize with false for OR, and true for AND conjunction
    + 207                const setCond = condition;
    + 208                
    + 209                // resolve SetConditions:
    + 210                switch (name) {
    + 211                    case 'or':  conditionMet = resolveCondition(setCond.or, row, r, colNumber, false); break;
    + 212                    case 'and': conditionMet = resolveCondition(setCond.and, row, r, colNumber, true); break;
    + 213                    case 'not': conditionMet = !resolveCondition(setCond.not, row, r, colNumber, true); break;
    + 214                    default:    conditionMet = resolveTerminalCondition(name, condition[name], row, colNumber); 
    + 215                }
    + 216                if (conditionMet) { orResult  = true;  if(!and) { break; }} // OR conjunction: exit for name loop if condition met
    + 217                             else { andResult = false; if(and)  { break; }} // AND conjunction: exit for name loop if condition not met
    + 218            }
    + 219        }    
    + 220    } else {
    + 221        console.error(`unrecognized condition: ${JSON.stringify(condition)}`);
    + 222        return false;
    + 223    }
    + 224    return and? andResult : orResult;
    + 225}
    + 226
    + 227/**
    + 228 * filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which
    + 229 * `cond` holds true.
    + 230 * @param data the `Data` object to filter
    + 231 * @param cond the complex condition to test against
    + 232 * @return a new `Data` object with the filtered rows 
    + 233 */

    + 234export function filter(data:Data, cond:Condition):Data {
    + 235    const colNumber = (name:string):number => data.colNumber(name);
    + 236    try {
    + 237        return new Data({
    + 238            name:     data.getName(),
    + 239            colNames: data.colNames(), 
    + 240            rows:data.getData().filter((row:DataRow, i:number) => {
    + 241                const keep = resolveCondition(cond, row, i, colNumber);
    + 242                return keep;
    + 243            })
    + 244        });
    + 245    } catch(err) {
    + 246        console.log(err);
    + 247        console.log(err.stack);
    + 248    }
    + 249}
    + 250
    + + \ No newline at end of file diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..07a3840 --- /dev/null +++ b/src/index.html @@ -0,0 +1,32 @@ + + +

    src/index.ts

    +
       1export { NumRange,
    +   2         NumDomain,
    +   3         DateDomain,
    +   4         NameDomain,
    +   5         Domain,
    +   6         ColumnReference,
    +   7         DataVal,
    +   8         DataRow,
    +   9         DataSet
    +  10        }       from './Data';
    +  11
    +  12export { Data } from './Data';
    +  13export { Condition} from './DataFilters';
    +  14
    +  15
    + + \ No newline at end of file diff --git a/src/overview.html b/src/overview.html new file mode 100644 index 0000000..bc9c4aa --- /dev/null +++ b/src/overview.html @@ -0,0 +1,96 @@ + + +

    src/overview.ts

    +
       1/**
    +   2 * # hsDatab
    +   3 * 
    +   4 * Helpful Scripts framework-independent data management functions. [Github page](https://github.com/HelpfulScripts/hsDatab)
    +   5 * 
    +   6 * **hsDatab** provides a JavaScript-based data management and query mechanism.
    +   7 * Data is managed in a simple in-memory database that holds data in rows of columns. 
    +   8 * It autodetermines the types of data held in each column, along with the 
    +   9 * domain range for each column of data. 
    +  10 * Complex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure. 
    +  11 * 
    +  12 * ## Data Types
    +  13 * supported {@link Data.Data.type data types} include
    +  14 * - **number**: numeric values
    +  15 * - **name**: nominal values, represented by arbitrary words
    +  16 * - **date**: date values
    +  17 * - **currency**: Currently supported: '$dd[,ddd]'
    +  18 * - **percent**: 'd%'
    +  19 * 
    +  20 * ## Data Class
    +  21 * The fundamental object in this library is {@link Data.Data `Data`}, 
    +  22 * a simple row-column based database object, 
    +  23 * featuring named columns, sorting, mapping and filtering functions.
    +  24 *
    +  25 * ## Example
    +  26 * 
    +  27 * 
    +  28 * const colNames = ['Name', 'Value', 'Start', 'End'];
    +  29 * const rows = [
    +  30 *   ['Harry', '100', '3/1/14', '11/20/14'], 
    +  31 *   ['Mary', '1500', '7/1/14',  '9/30/14'],
    +  32 *   ['Peter', '400', '5/20/14', '4/30/15'],  
    +  33 *   ['Jane', '700', '11/13/14', '8/15/15']
    +  34 * ]
    +  35 * const data = new hsdatab.Data({colNames:colNames, rows:rows});
    +  36 * 
    +  37 * query = {Name:["Peter", "Jane"]};
    +  38 * const result = data.filter(query);
    +  39 *
    +  40 * m.mount(root, {
    +  41 *   view:() => m('', [
    +  42 *       m('h3', 'Given the data set:'),
    +  43 *       m('pre',
    +  44 *       m('table#data', [
    +  45 *           m('tr', colNames.map(n => m('th', n))),
    +  46 *           ...rows.map(row => m('tr', [
    +  47 *              m('td', row[0]),
    +  48 *              m('td', row[1]),
    +  49 *              m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),
    +  50 *              m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)
    +  51 *          ]))
    +  52 *       ])),
    +  53 *       m('h3', 'The column types and domains are'),
    +  54 *       m('pre', m('table', 
    +  55 *                  m('tr', m('th', 'Column'),   m('th', 'Type'),   m('th', 'Domain')),
    +  56 *                  m('tr', m('td', '"Name":'),  m('td', data.colType("Name")),   m('td', data.findDomain("Name").join(', '))),
    +  57 *                  m('tr', m('td', '"Value":'), m('td', data.colType("Value")),  m('td', data.findDomain("Value").join(' - '))),
    +  58 *                  m('tr', m('td', '"Start":'), m('td', data.colType("Start")),  m('td', data.findDomain("Start").map(d => d.toDateString()).join(' - '))),
    +  59 *                  m('tr', m('td', '"Stop":'),  m('td', data.colType("End")),    m('td', data.findDomain("End").map(d => d.toDateString()).join(' - ')))
    +  60 *       )),
    +  61 *       m('h3', 'The query:'),
    +  62 *       m('code', '{Name:["Peter", "Jane"]}'),
    +  63 *       m('h3', 'yields results with "Name"'),
    +  64 *       m('code', result.getColumn('Name').join(', '))
    +  65 *   ])
    +  66 * });
    +  67 * 
    +  68 * 
    +  69 *   $exampleID { height: 600px; }
    +  70 *   #data th { width:15%; }
    +  71 *   #data  { font-size: 11pt; }
    +  72 * 
    +  73 *      
    +  74 */

    +  75
    +  76 /** */
    +  77
    +  78 
    +  79
    + + \ No newline at end of file From 7aac8017f3e2bb6adc5236d1b71b853fef32c02e Mon Sep 17 00:00:00 2001 From: hs <> Date: Sun, 17 Jun 2018 11:02:06 +0200 Subject: [PATCH 15/17] updated doicsw --- data/hsDatab.json | 3285 +++++++++++++++++++++++++++++++++++++++++++++ index.html | 11 + indexGH.html | 11 + 3 files changed, 3307 insertions(+) create mode 100644 data/hsDatab.json create mode 100644 index.html create mode 100644 indexGH.html diff --git a/data/hsDatab.json b/data/hsDatab.json new file mode 100644 index 0000000..db6ebdd --- /dev/null +++ b/data/hsDatab.json @@ -0,0 +1,3285 @@ +{ + "id": 0, + "name": "hsDatab", + "kind": 0, + "flags": {}, + "children": [ + { + "id": 42, + "name": "\"Data\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.ts", + "comment": {}, + "children": [ + { + "id": 56, + "name": "Data", + "kind": 128, + "kindString": "Class", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "# Data\nA simple in-memory database that holds data in rows of columns." + }, + "children": [ + { + "id": 67, + "name": "constructor", + "kind": 512, + "kindString": "Constructor", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 68, + "name": "new Data", + "kind": 16384, + "kindString": "Constructor signature", + "flags": {}, + "parameters": [ + { + "id": 69, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 86, + "character": 5 + } + ] + }, + { + "id": 117, + "name": "data", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 392, + "character": 16 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + "defaultValue": " []" + }, + { + "id": 118, + "name": "meta", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 393, + "character": 16 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "MetaStruct", + "id": 50 + } + }, + "defaultValue": " []" + }, + { + "id": 119, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": { + "isPrivate": true, + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 394, + "character": 16 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 134, + "name": "allRows", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 135, + "name": "allRows", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "A generator that provides the specified column value for each row in `Data` in sequence." + }, + "parameters": [ + { + "id": 136, + "name": "column", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "\n" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "Iterable", + "typeArguments": [ + { + "type": "reference", + "name": "DataVal", + "id": 151 + } + ] + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 493, + "character": 21 + } + ] + }, + { + "id": 104, + "name": "castData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 105, + "name": "castData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 260, + "character": 19 + } + ] + }, + { + "id": 141, + "name": "castVal", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 142, + "name": "castVal", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "The result of the cast.", + "tags": [ + { + "tag": "description", + "text": "Casts the sample to the specified data type.\n" + } + ] + }, + "parameters": [ + { + "id": 143, + "name": "type", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "The type to cast into. In case of _any_ - i.e. `type`\ndoes not match any of the previous keywords, no casting occurs." + }, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 144, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 529, + "character": 19 + } + ] + }, + { + "id": 82, + "name": "colAdd", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 83, + "name": "colAdd", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "adds a new column to the data set. if `newCol` already exists,\nthe column index is returned withoput change.", + "returns": "the index for the new column\n" + }, + "parameters": [ + { + "id": 84, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the name of the new column" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 140, + "character": 17 + } + ] + }, + { + "id": 85, + "name": "colInitialize", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 86, + "name": "colInitialize", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "initializes the specifed column with values, adding a new column if needed.\nIf `val`is a function, it is called as ```\nval(colValue:DataVal, rowIndex:number, row:DataRow)\n```\n@param col the column to initialize\n@param initializer the value to initialize with, or a function whose return\nvalue is used to initialize the column" + }, + "parameters": [ + { + "id": 87, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + }, + { + "id": 88, + "name": "initializer", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 162, + "character": 24 + } + ] + }, + { + "id": 92, + "name": "colName", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 93, + "name": "colName", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column name for the specified column.\n`col` can be either an index or a name.", + "returns": "the column name or `undefined`.\n" + }, + "parameters": [ + { + "id": 94, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 194, + "character": 18 + } + ] + }, + { + "id": 95, + "name": "colNames", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 96, + "name": "colNames", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the names for all columns.", + "returns": "an array of strings with the names.\n" + }, + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 205, + "character": 19 + } + ] + }, + { + "id": 89, + "name": "colNumber", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 90, + "name": "colNumber", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column index of the specified column.\n`col` can be either an index or a name.", + "returns": "the column number or `undefined`.\n" + }, + "parameters": [ + { + "id": 91, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 179, + "character": 20 + } + ] + }, + { + "id": 97, + "name": "colType", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 98, + "name": "colType", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the column type for the specified column.\n`col` can be either an index or a name.", + "returns": "the column type.\n" + }, + "parameters": [ + { + "id": 99, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 215, + "character": 18 + } + ] + }, + { + "id": 75, + "name": "export", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 76, + "name": "export", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Exports to an object literal" + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 111, + "character": 17 + } + ] + }, + { + "id": 106, + "name": "filter", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 107, + "name": "filter", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "filters this data set and returns a new data set with a\nshallow copy of rows that pass the `condition`.\nSee {@link DataFilters DataFilters} for rules and examples on how to construct conditions.", + "returns": "a new Data object with rows that pass the filter\n" + }, + "parameters": [ + { + "id": 108, + "name": "condition", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "filters" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 277, + "character": 17 + } + ] + }, + { + "id": 100, + "name": "findDomain", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 101, + "name": "findDomain", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "modifies `domain` to include all values in column `col`.\nIf no `col` is specified, the range of data indexes is returned.", + "returns": "the updated domain\n" + }, + "parameters": [ + { + "id": 102, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the column name or index" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + }, + { + "id": 103, + "name": "domain", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the Domain range to update" + }, + "type": { + "type": "reference", + "name": "Domain", + "id": 149 + } + } + ], + "type": { + "type": "reference", + "name": "Domain", + "id": 149 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 227, + "character": 21 + } + ] + }, + { + "id": 131, + "name": "findType", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 132, + "name": "findType", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample\n", + "tags": [ + { + "tag": "description", + "text": "determines the data type. Supported types are\n```\n'date': sample represents a Date, either as a Date object or a String\n'number': sample represents a number\n'percent': sample represents a percentage (special case of a real number)\n'nominal': sample represents a nominal (ordinal or categorical) value\n```" + } + ] + }, + "parameters": [ + { + "id": 133, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the value to bve typed." + }, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 462, + "character": 20 + } + ] + }, + { + "id": 128, + "name": "findTypes", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 129, + "name": "findTypes", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Determines the type of data in `col`. An array of counts is created for all\nencountered types, sorted by descending frequency. THe most likely type in position 0\nof the array is returned.", + "returns": "the most likely type of data in `col`.\n" + }, + "parameters": [ + { + "id": 130, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the index of the column to be typed." + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 430, + "character": 21 + } + ] + }, + { + "id": 79, + "name": "getColumn", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 80, + "name": "getColumn", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Returns the values in the specified column as a new array." + }, + "parameters": [ + { + "id": 81, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the column to return.\n" + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 129, + "character": 20 + } + ] + }, + { + "id": 77, + "name": "getData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 78, + "name": "getData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "returns the 2D array underlying the data base." + }, + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 121, + "character": 18 + } + ] + }, + { + "id": 120, + "name": "getMeta", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 121, + "name": "getMeta", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 122, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "MetaStruct", + "id": 50 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 396, + "character": 19 + } + ] + }, + { + "id": 70, + "name": "getName", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 71, + "name": "getName", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the `name` field for this data base, if any\n" + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 95, + "character": 18 + } + ] + }, + { + "id": 72, + "name": "import", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 73, + "name": "import", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Imports data from an object literal `data`" + }, + "parameters": [ + { + "id": 74, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data set to import\n" + }, + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 103, + "character": 17 + } + ] + }, + { + "id": 113, + "name": "map", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 114, + "name": "map", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": " Maps one or more columns in each rows of values based\non the result of the `mapFn`, which behaves similarly to the Array.map() method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the `mapFn` is passed the column arrays per row as parameter.\nThis allows for complex mapping combining conditions across multiple columns.\n```\ndata.map(function(values){\n values[1] = values[3] * values[5];\n return values;\n});\n```\nBe sure to return the `values` array as a result.\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `mapFn`, along with the row index and the entire row array. This allows for simple mapping.\n```\ndata.map('Price', function(value, i, values) {\n return value * 2;\n});\n```", + "returns": "a new Data object containing the mapping.\n" + }, + "parameters": [ + { + "id": 115, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data column, or columns, to apply the mapping to." + }, + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "ColumnReference", + "id": 150 + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ] + } + }, + { + "id": 116, + "name": "mapFn", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "a function to implement the mapping,\ncalled on each row of the data set in turn as `mapFn(val, i, c, rows)`, where\n- `val`: the column value in the current row\n- `c`: the column index in the current row\n- `i`: the row index\n- `rows`: the rows being iterated over\n` *\nfollows the same specifications as the function passed to Array.map().
    \nFor column mode, some predefined map functions can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.
    " + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "mapFn", + "id": 116 + } + ] + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 359, + "character": 14 + } + ] + }, + { + "id": 123, + "name": "setData", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 124, + "name": "setData", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "sets `data` to the existing data set. If data has previously been set,\n`data` will be added to the end of the list if all `names` match those of the\nexisting set." + }, + "parameters": [ + { + "id": 125, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the data to add" + }, + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + }, + { + "id": 126, + "name": "names", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "an array of names that match the columns" + }, + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 127, + "name": "autoType", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "unless set to false, the method will attempt to determine the\ntype of data and automatically cast data points to their correct value\n" + }, + "type": { + "type": "intrinsic", + "name": "boolean" + }, + "defaultValue": "true" + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 412, + "character": 19 + } + ] + }, + { + "id": 109, + "name": "sort", + "kind": 2048, + "kindString": "Method", + "flags": { + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 110, + "name": "sort", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "the Data object in order to allow for chaining.\n", + "tags": [ + { + "tag": "description", + "text": "Sorts the rows of values based on the result of the `sortFn`,\nwhich behaves similarly to the Array.sort method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the column arrays are passed as samples into the `sortFn`.\nThis allows for complex sorts, combining conditions across multiple columns.\n```\ndata.sort((row1, row2) => row1[5] - row2[5] );\n```\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `sortFn`. This allows filtering for simple conditions.
    \n**The specified column will be automatically cast prior to sorting**
    \n`data.sort('Date', function(val1, val2) { return val1 - val2; });`" + } + ] + }, + "parameters": [ + { + "id": 111, + "name": "sortFn", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "a function to implement the conditions,\nfollows the same specifications as the function passed to Array.sort().\nSome predefined sort function can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.
    " + }, + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "sortFn", + "id": 111 + } + ] + } + }, + { + "id": 112, + "name": "col", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "comment": { + "text": "optional; the data column to use for sorting." + }, + "type": { + "type": "reference", + "name": "ColumnReference", + "id": 150 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 307, + "character": 15 + } + ] + }, + { + "id": 137, + "name": "toDate", + "kind": 2048, + "kindString": "Method", + "flags": { + "isPrivate": true, + "isExported": true + }, + "signatures": [ + { + "id": 138, + "name": "toDate", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "returns": "a new Date object parsed from `str`.", + "tags": [ + { + "tag": "description", + "text": "returns a new Date object parsed from `str` and corrects for a difference in\ninterpreting centuries between webkit and mozilla in converting strings to Dates:\nThe string \"15/7/03\" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.\nIf `limitYear` is not specified this method uses 1970 as the decision date:\nyears 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.\n" + } + ] + }, + "parameters": [ + { + "id": 139, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the string to convert to a date" + }, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "id": 140, + "name": "limitYear", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the year below which the century is corrected. Defaults to 1970." + }, + "type": { + "type": "intrinsic", + "name": "number" + }, + "defaultValue": "1970" + } + ], + "type": { + "type": "reference", + "name": "Date" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 510, + "character": 18 + } + ] + }, + { + "id": 63, + "name": "toDataSet", + "kind": 2048, + "kindString": "Method", + "flags": { + "isStatic": true, + "isExported": true, + "isPublic": true + }, + "signatures": [ + { + "id": 64, + "name": "toDataSet", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 65, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataLiteralSet", + "id": 153 + } + }, + { + "id": 66, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "reference", + "name": "DataSet", + "id": 43 + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 80, + "character": 27 + } + ] + }, + { + "id": 57, + "name": "type", + "kind": 2097152, + "kindString": "Object literal", + "flags": { + "isStatic": true, + "isExported": true, + "isPublic": true + }, + "children": [ + { + "id": 61, + "name": "currency", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "currency values. Currently support6ed are values ofg the format '$dd[,ddd]'" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 74, + "character": 16 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"currency\"" + }, + { + "id": 60, + "name": "date", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "date values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 72, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"date\"" + }, + { + "id": 59, + "name": "name", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "nominal values, represented by arbitrary words" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 70, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"name\"" + }, + { + "id": 58, + "name": "number", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "numeric values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 68, + "character": 14 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"number\"" + }, + { + "id": 62, + "name": "percent", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "percent values: 'd%'" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 76, + "character": 15 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + }, + "defaultValue": "\"percent\"" + } + ], + "groups": [ + { + "title": "Variables", + "kind": 32, + "children": [ + 61, + 60, + 59, + 58, + 62 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 66, + "character": 22 + } + ], + "type": { + "type": "intrinsic", + "name": "object" + } + } + ], + "groups": [ + { + "title": "Constructors", + "kind": 512, + "children": [ + 67 + ] + }, + { + "title": "Properties", + "kind": 1024, + "children": [ + 117, + 118, + 119 + ] + }, + { + "title": "Methods", + "kind": 2048, + "children": [ + 134, + 104, + 141, + 82, + 85, + 92, + 95, + 89, + 97, + 75, + 106, + 100, + 131, + 128, + 79, + 77, + 120, + 70, + 72, + 113, + 123, + 109, + 137, + 63 + ] + }, + { + "title": "Object literals", + "kind": 2097152, + "children": [ + 57 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 62, + "character": 17 + } + ] + }, + { + "id": 43, + "name": "DataSet", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a JSON format data set, using arrays of names and rows" + }, + "children": [ + { + "id": 45, + "name": "colNames", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "an array of column names. Each name matches the column with the same index in DataRow" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 36, + "character": 12 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 44, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "comment": { + "shortText": "an optional name for the data set" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 34, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 46, + "name": "rows", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "rows of data" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 38, + "character": 8 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 45, + 44, + 46 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 32, + "character": 24 + } + ] + }, + { + "id": 50, + "name": "MetaStruct", + "kind": 256, + "kindString": "Interface", + "flags": {}, + "children": [ + { + "id": 53, + "name": "accessed", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 49, + "character": 12 + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 54, + "name": "cast", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 50, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + }, + { + "id": 52, + "name": "column", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 48, + "character": 10 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 51, + "name": "name", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 47, + "character": 8 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 55, + "name": "types", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 51, + "character": 9 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "TypeStruct", + "id": 47 + } + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 53, + 54, + 52, + 51, + 55 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 46, + "character": 20 + } + ] + }, + { + "id": 47, + "name": "TypeStruct", + "kind": 256, + "kindString": "Interface", + "flags": {}, + "children": [ + { + "id": 49, + "name": "count", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 42 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 48, + "name": "type", + "kind": 1024, + "kindString": "Property", + "flags": {}, + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 27 + } + ], + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 49, + 48 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 44, + "character": 20 + } + ] + }, + { + "id": 150, + "name": "ColumnReference", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 23, + "character": 27 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "string" + } + ] + } + }, + { + "id": 153, + "name": "DataLiteralSet", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a JSON format data set, using an array of {name:value, ...} literals" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 42, + "character": 26 + } + ], + "type": { + "type": "reference", + "name": "Array", + "typeArguments": [ + { + "type": "intrinsic", + "name": "any" + } + ] + } + }, + { + "id": 152, + "name": "DataRow", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a single row of column values" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 29, + "character": 19 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + } + }, + { + "id": 151, + "name": "DataVal", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "a generic data value type, used in the {@link Data.DataRow `DataRow`} array" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 26, + "character": 19 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "string" + }, + { + "type": "reference", + "name": "Date" + } + ] + } + }, + { + "id": 147, + "name": "DateDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a Date domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 14, + "character": 22 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "reference", + "name": "Date" + }, + { + "type": "reference", + "name": "Date" + } + ] + } + }, + { + "id": 149, + "name": "Domain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a generic domain that can be any of the typed domains." + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 20, + "character": 18 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "NumDomain", + "id": 146 + }, + { + "type": "reference", + "name": "DateDomain", + "id": 147 + }, + { + "type": "reference", + "name": "NameDomain", + "id": 148 + } + ] + } + }, + { + "id": 148, + "name": "NameDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a categorical domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 17, + "character": 22 + } + ], + "type": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "string" + } + } + }, + { + "id": 146, + "name": "NumDomain", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a numeric domain that includes all values of a column" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 11, + "character": 21 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "number" + } + ] + } + }, + { + "id": 145, + "name": "NumRange", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "defines a [min-max] range" + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 8, + "character": 20 + } + ], + "type": { + "type": "tuple", + "elements": [ + { + "type": "intrinsic", + "name": "number" + }, + { + "type": "intrinsic", + "name": "number" + } + ] + } + }, + { + "id": 159, + "name": "mapFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 55, + "character": 17 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 160, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 161, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 162, + "name": "colVal", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 163, + "name": "colIndex", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 164, + "name": "rowIndex", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 165, + "name": "rows", + "kind": 32768, + "kindString": "Parameter", + "flags": { + "isOptional": true + }, + "type": { + "type": "array", + "elementType": { + "type": "array", + "elementType": { + "type": "intrinsic", + "name": "any" + } + } + } + } + ], + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 55, + "character": 20 + } + ] + } + } + }, + { + "id": 154, + "name": "sortFn", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "Data.ts", + "line": 54, + "character": 18 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 155, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 156, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 157, + "name": "x", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 158, + "name": "y", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 54, + "character": 20 + } + ] + } + } + } + ], + "groups": [ + { + "title": "Classes", + "kind": 128, + "children": [ + 56 + ] + }, + { + "title": "Interfaces", + "kind": 256, + "children": [ + 43, + 50, + 47 + ] + }, + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 150, + 153, + 152, + 151, + 147, + 149, + 148, + 146, + 145, + 159, + 154 + ] + } + ], + "sources": [ + { + "fileName": "Data.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 1, + "name": "\"DataFilters\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/DataFilters.ts", + "comment": { + "shortText": "Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object.\nEach row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object.", + "text": "# Condition construction\n\n### General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n### IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n### RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n### Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" + }, + "children": [ + { + "id": 2, + "name": "SetAndCondition", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "children": [ + { + "id": 4, + "name": "and", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 140, + "character": 7 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + }, + { + "id": 5, + "name": "not", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 141, + "character": 7 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + }, + { + "id": 3, + "name": "or", + "kind": 1024, + "kindString": "Property", + "flags": { + "isExported": true, + "isOptional": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 139, + "character": 6 + } + ], + "type": { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + } + ], + "groups": [ + { + "title": "Properties", + "kind": 1024, + "children": [ + 4, + 5, + 3 + ] + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 138, + "character": 32 + } + ] + }, + { + "id": 6, + "name": "TermAndCondition", + "kind": 256, + "kindString": "Interface", + "flags": { + "isExported": true + }, + "indexSignature": { + "id": 7, + "name": "__index", + "kind": 8192, + "kindString": "Index signature", + "flags": {}, + "parameters": [ + { + "id": 8, + "name": "colDesc", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "DataVal", + "id": 151 + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "type": "reference", + "name": "TermConditionFunction", + "id": 14 + } + ] + } + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 144, + "character": 33 + } + ] + }, + { + "id": 13, + "name": "AndCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 136, + "character": 24 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "SetAndCondition", + "id": 2 + }, + { + "type": "reference", + "name": "TermAndCondition", + "id": 6 + } + ] + } + }, + { + "id": 9, + "name": "Condition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 129, + "character": 21 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "IndexCondition", + "id": 10 + }, + { + "type": "reference", + "name": "RecursiveCondition", + "id": 11 + } + ] + } + }, + { + "id": 10, + "name": "IndexCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "comment": { + "shortText": "true if row index matches the number(s)" + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 132, + "character": 26 + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 12, + "name": "OrCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 135, + "character": 23 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "array", + "elementType": { + "type": "reference", + "name": "AndCondition", + "id": 13 + } + }, + { + "type": "array", + "elementType": { + "type": "reference", + "name": "IndexCondition", + "id": 10 + } + } + ] + } + }, + { + "id": 11, + "name": "RecursiveCondition", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 134, + "character": 30 + } + ], + "type": { + "type": "union", + "types": [ + { + "type": "reference", + "name": "AndCondition", + "id": 13 + }, + { + "type": "reference", + "name": "OrCondition", + "id": 12 + } + ] + } + }, + { + "id": 14, + "name": "TermConditionFunction", + "kind": 4194304, + "kindString": "Type alias", + "flags": { + "isExported": true + }, + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 152, + "character": 33 + } + ], + "type": { + "type": "reflection", + "declaration": { + "id": 15, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 16, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 17, + "name": "value", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataVal", + "id": 151 + } + }, + { + "id": 18, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 152, + "character": 35 + } + ] + } + } + }, + { + "id": 38, + "name": "filter", + "kind": 64, + "kindString": "Function", + "flags": { + "isExported": true + }, + "signatures": [ + { + "id": 39, + "name": "filter", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which\n`cond` holds true.", + "returns": "a new `Data` object with the filtered rows\n" + }, + "parameters": [ + { + "id": 40, + "name": "data", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the `Data` object to filter" + }, + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + }, + { + "id": 41, + "name": "cond", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the complex condition to test against" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + } + ], + "type": { + "type": "reference", + "name": "Data", + "id": 56 + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 234, + "character": 22 + } + ] + }, + { + "id": 28, + "name": "resolveCondition", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 29, + "name": "resolveCondition", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "applies `condition` to a row of data and returns `true` if the row passes." + }, + "parameters": [ + { + "id": 30, + "name": "condition", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the complex condition to test against" + }, + "type": { + "type": "reference", + "name": "Condition", + "id": 9 + } + }, + { + "id": 31, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the row values" + }, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + { + "id": 32, + "name": "r", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "the row index in the data set" + }, + "type": { + "type": "intrinsic", + "name": "number" + } + }, + { + "id": 33, + "name": "colNumber", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reflection", + "declaration": { + "id": 34, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 35, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 36, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 181, + "character": 80 + } + ] + } + } + }, + { + "id": 37, + "name": "and", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "comment": { + "text": "\n" + }, + "type": { + "type": "intrinsic", + "name": "boolean" + }, + "defaultValue": "true" + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 181, + "character": 25 + } + ] + }, + { + "id": 19, + "name": "resolveTerminalCondition", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 20, + "name": "resolveTerminalCondition", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 21, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + }, + { + "id": 22, + "name": "val", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "any" + } + }, + { + "id": 23, + "name": "row", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reference", + "name": "DataRow", + "id": 152 + } + }, + { + "id": 24, + "name": "colNumber", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "reflection", + "declaration": { + "id": 25, + "name": "__type", + "kind": 65536, + "kindString": "Type literal", + "flags": {}, + "signatures": [ + { + "id": 26, + "name": "__call", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 27, + "name": "name", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "string" + } + } + ], + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 155, + "character": 79 + } + ] + } + } + } + ], + "type": { + "type": "intrinsic", + "name": "boolean" + } + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 155, + "character": 33 + } + ] + } + ], + "groups": [ + { + "title": "Interfaces", + "kind": 256, + "children": [ + 2, + 6 + ] + }, + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 13, + 9, + 10, + 12, + 11, + 14 + ] + }, + { + "title": "Functions", + "kind": 64, + "children": [ + 38, + 28, + 19 + ] + } + ], + "sources": [ + { + "fileName": "DataFilters.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 166, + "name": "\"index\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/index.ts", + "sources": [ + { + "fileName": "index.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 167, + "name": "\"overview\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", + "comment": { + "shortText": "# hsDatab", + "text": "Helpful Scripts framework-independent data management functions. [Github page](https://github.com/HelpfulScripts/hsDatab)\n\n**hsDatab** provides a JavaScript-based data management and query mechanism.\nData is managed in a simple in-memory database that holds data in rows of columns.\nIt autodetermines the types of data held in each column, along with the\ndomain range for each column of data.\nComplex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure.\n\n## Data Types\nsupported {@link Data.Data.type data types} include\n- **number**: numeric values\n- **name**: nominal values, represented by arbitrary words\n- **date**: date values\n- **currency**: Currently supported: '$dd[,ddd]'\n- **percent**: 'd%'\n\n## Data Class\nThe fundamental object in this library is {@link Data.Data `Data`},\na simple row-column based database object,\nfeaturing named columns, sorting, mapping and filtering functions.\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query);\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('pre',\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [\n m('td', row[0]),\n m('td', row[1]),\n m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),\n m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)\n ]))\n ])),\n m('h3', 'The column types and domains are'),\n m('pre', m('table',\n m('tr', m('th', 'Column'), m('th', 'Type'), m('th', 'Domain')),\n m('tr', m('td', '\"Name\":'), m('td', data.colType(\"Name\")), m('td', data.findDomain(\"Name\").join(', '))),\n m('tr', m('td', '\"Value\":'), m('td', data.colType(\"Value\")), m('td', data.findDomain(\"Value\").join(' - '))),\n m('tr', m('td', '\"Start\":'), m('td', data.colType(\"Start\")), m('td', data.findDomain(\"Start\").map(d => d.toDateString()).join(' - '))),\n m('tr', m('td', '\"Stop\":'), m('td', data.colType(\"End\")), m('td', data.findDomain(\"End\").map(d => d.toDateString()).join(' - ')))\n )),\n m('h3', 'The query:'),\n m('code', '{Name:[\"Peter\", \"Jane\"]}'),\n m('h3', 'yields results with \"Name\"'),\n m('code', result.getColumn('Name').join(', '))\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n #data { font-size: 11pt; }\n\n\n" + }, + "sources": [ + { + "fileName": "overview.ts", + "line": 1, + "character": 0 + } + ] + } + ], + "groups": [ + { + "title": "External modules", + "kind": 1, + "children": [ + 42, + 1, + 166, + 167 + ] + } + ] +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..0bc10a0 --- /dev/null +++ b/index.html @@ -0,0 +1,11 @@ + + + + + HS Docs + + + + + + \ No newline at end of file diff --git a/indexGH.html b/indexGH.html new file mode 100644 index 0000000..0bc10a0 --- /dev/null +++ b/indexGH.html @@ -0,0 +1,11 @@ + + + + + HS Docs + + + + + + \ No newline at end of file From 012c9e65b2b10f460acdf5bd7ab1f7448580fbac Mon Sep 17 00:00:00 2001 From: hs <> Date: Sun, 17 Jun 2018 11:06:27 +0200 Subject: [PATCH 16/17] fixed indexGH --- indexGH.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indexGH.html b/indexGH.html index 0bc10a0..2854c97 100644 --- a/indexGH.html +++ b/indexGH.html @@ -3,9 +3,9 @@ HS Docs - + - + \ No newline at end of file From 6dea5051f4d1abd214d262fcbc5a33b5abe8f2d6 Mon Sep 17 00:00:00 2001 From: hs <> Date: Sun, 17 Jun 2018 12:31:08 +0200 Subject: [PATCH 17/17] removed bin from gh-pages repo --- hsDatab.json | 3285 -------------------------------------------------- 1 file changed, 3285 deletions(-) delete mode 100644 hsDatab.json diff --git a/hsDatab.json b/hsDatab.json deleted file mode 100644 index db6ebdd..0000000 --- a/hsDatab.json +++ /dev/null @@ -1,3285 +0,0 @@ -{ - "id": 0, - "name": "hsDatab", - "kind": 0, - "flags": {}, - "children": [ - { - "id": 42, - "name": "\"Data\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/Data.ts", - "comment": {}, - "children": [ - { - "id": 56, - "name": "Data", - "kind": 128, - "kindString": "Class", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "# Data\nA simple in-memory database that holds data in rows of columns." - }, - "children": [ - { - "id": 67, - "name": "constructor", - "kind": 512, - "kindString": "Constructor", - "flags": { - "isExported": true - }, - "signatures": [ - { - "id": 68, - "name": "new Data", - "kind": 16384, - "kindString": "Constructor signature", - "flags": {}, - "parameters": [ - { - "id": 69, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 43 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 86, - "character": 5 - } - ] - }, - { - "id": 117, - "name": "data", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 392, - "character": 16 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - }, - "defaultValue": " []" - }, - { - "id": 118, - "name": "meta", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 393, - "character": 16 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "MetaStruct", - "id": 50 - } - }, - "defaultValue": " []" - }, - { - "id": 119, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": { - "isPrivate": true, - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 394, - "character": 16 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 134, - "name": "allRows", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 135, - "name": "allRows", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "A generator that provides the specified column value for each row in `Data` in sequence." - }, - "parameters": [ - { - "id": 136, - "name": "column", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "\n" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "reference", - "name": "Iterable", - "typeArguments": [ - { - "type": "reference", - "name": "DataVal", - "id": 151 - } - ] - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 493, - "character": 21 - } - ] - }, - { - "id": 104, - "name": "castData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 105, - "name": "castData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 260, - "character": 19 - } - ] - }, - { - "id": 141, - "name": "castVal", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 142, - "name": "castVal", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "The result of the cast.", - "tags": [ - { - "tag": "description", - "text": "Casts the sample to the specified data type.\n" - } - ] - }, - "parameters": [ - { - "id": 143, - "name": "type", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "The type to cast into. In case of _any_ - i.e. `type`\ndoes not match any of the previous keywords, no casting occurs." - }, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 144, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - ], - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 529, - "character": 19 - } - ] - }, - { - "id": 82, - "name": "colAdd", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 83, - "name": "colAdd", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "adds a new column to the data set. if `newCol` already exists,\nthe column index is returned withoput change.", - "returns": "the index for the new column\n" - }, - "parameters": [ - { - "id": 84, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the name of the new column" - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 140, - "character": 17 - } - ] - }, - { - "id": 85, - "name": "colInitialize", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 86, - "name": "colInitialize", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "initializes the specifed column with values, adding a new column if needed.\nIf `val`is a function, it is called as ```\nval(colValue:DataVal, rowIndex:number, row:DataRow)\n```\n@param col the column to initialize\n@param initializer the value to initialize with, or a function whose return\nvalue is used to initialize the column" - }, - "parameters": [ - { - "id": 87, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - }, - { - "id": 88, - "name": "initializer", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 162, - "character": 24 - } - ] - }, - { - "id": 92, - "name": "colName", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 93, - "name": "colName", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column name for the specified column.\n`col` can be either an index or a name.", - "returns": "the column name or `undefined`.\n" - }, - "parameters": [ - { - "id": 94, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 194, - "character": 18 - } - ] - }, - { - "id": 95, - "name": "colNames", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 96, - "name": "colNames", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the names for all columns.", - "returns": "an array of strings with the names.\n" - }, - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 205, - "character": 19 - } - ] - }, - { - "id": 89, - "name": "colNumber", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 90, - "name": "colNumber", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column index of the specified column.\n`col` can be either an index or a name.", - "returns": "the column number or `undefined`.\n" - }, - "parameters": [ - { - "id": 91, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 179, - "character": 20 - } - ] - }, - { - "id": 97, - "name": "colType", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 98, - "name": "colType", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the column type for the specified column.\n`col` can be either an index or a name.", - "returns": "the column type.\n" - }, - "parameters": [ - { - "id": 99, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 215, - "character": 18 - } - ] - }, - { - "id": 75, - "name": "export", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 76, - "name": "export", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Exports to an object literal" - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 43 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 111, - "character": 17 - } - ] - }, - { - "id": 106, - "name": "filter", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 107, - "name": "filter", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "filters this data set and returns a new data set with a\nshallow copy of rows that pass the `condition`.\nSee {@link DataFilters DataFilters} for rules and examples on how to construct conditions.", - "returns": "a new Data object with rows that pass the filter\n" - }, - "parameters": [ - { - "id": 108, - "name": "condition", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "filters" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 9 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 277, - "character": 17 - } - ] - }, - { - "id": 100, - "name": "findDomain", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 101, - "name": "findDomain", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "modifies `domain` to include all values in column `col`.\nIf no `col` is specified, the range of data indexes is returned.", - "returns": "the updated domain\n" - }, - "parameters": [ - { - "id": 102, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the column name or index" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - }, - { - "id": 103, - "name": "domain", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the Domain range to update" - }, - "type": { - "type": "reference", - "name": "Domain", - "id": 149 - } - } - ], - "type": { - "type": "reference", - "name": "Domain", - "id": 149 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 227, - "character": 21 - } - ] - }, - { - "id": 131, - "name": "findType", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 132, - "name": "findType", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the type ('number', 'date', 'percent', 'nominal', 'currency') corresponding to the sample\n", - "tags": [ - { - "tag": "description", - "text": "determines the data type. Supported types are\n```\n'date': sample represents a Date, either as a Date object or a String\n'number': sample represents a number\n'percent': sample represents a percentage (special case of a real number)\n'nominal': sample represents a nominal (ordinal or categorical) value\n```" - } - ] - }, - "parameters": [ - { - "id": 133, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the value to bve typed." - }, - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 462, - "character": 20 - } - ] - }, - { - "id": 128, - "name": "findTypes", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 129, - "name": "findTypes", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Determines the type of data in `col`. An array of counts is created for all\nencountered types, sorted by descending frequency. THe most likely type in position 0\nof the array is returned.", - "returns": "the most likely type of data in `col`.\n" - }, - "parameters": [ - { - "id": 130, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the index of the column to be typed." - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 430, - "character": 21 - } - ] - }, - { - "id": 79, - "name": "getColumn", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 80, - "name": "getColumn", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Returns the values in the specified column as a new array." - }, - "parameters": [ - { - "id": 81, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the column to return.\n" - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 129, - "character": 20 - } - ] - }, - { - "id": 77, - "name": "getData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 78, - "name": "getData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "returns the 2D array underlying the data base." - }, - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 121, - "character": 18 - } - ] - }, - { - "id": 120, - "name": "getMeta", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 121, - "name": "getMeta", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 122, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "reference", - "name": "MetaStruct", - "id": 50 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 396, - "character": 19 - } - ] - }, - { - "id": 70, - "name": "getName", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 71, - "name": "getName", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the `name` field for this data base, if any\n" - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 95, - "character": 18 - } - ] - }, - { - "id": 72, - "name": "import", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 73, - "name": "import", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "Imports data from an object literal `data`" - }, - "parameters": [ - { - "id": 74, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data set to import\n" - }, - "type": { - "type": "reference", - "name": "DataSet", - "id": 43 - } - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 103, - "character": 17 - } - ] - }, - { - "id": 113, - "name": "map", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 114, - "name": "map", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": " Maps one or more columns in each rows of values based\non the result of the `mapFn`, which behaves similarly to the Array.map() method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the `mapFn` is passed the column arrays per row as parameter.\nThis allows for complex mapping combining conditions across multiple columns.\n```\ndata.map(function(values){\n values[1] = values[3] * values[5];\n return values;\n});\n```\nBe sure to return the `values` array as a result.\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `mapFn`, along with the row index and the entire row array. This allows for simple mapping.\n```\ndata.map('Price', function(value, i, values) {\n return value * 2;\n});\n```", - "returns": "a new Data object containing the mapping.\n" - }, - "parameters": [ - { - "id": 115, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data column, or columns, to apply the mapping to." - }, - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "ColumnReference", - "id": 150 - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ] - } - }, - { - "id": 116, - "name": "mapFn", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "a function to implement the mapping,\ncalled on each row of the data set in turn as `mapFn(val, i, c, rows)`, where\n- `val`: the column value in the current row\n- `c`: the column index in the current row\n- `i`: the row index\n- `rows`: the rows being iterated over\n` *\nfollows the same specifications as the function passed to Array.map().
    \nFor column mode, some predefined map functions can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    'noop'replace value with itself, performing no operation.
    'cumulate'replace value with the cumulative sum of values up to the current element.
    " - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "mapFn", - "id": 116 - } - ] - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 359, - "character": 14 - } - ] - }, - { - "id": 123, - "name": "setData", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 124, - "name": "setData", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "sets `data` to the existing data set. If data has previously been set,\n`data` will be added to the end of the list if all `names` match those of the\nexisting set." - }, - "parameters": [ - { - "id": 125, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the data to add" - }, - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - } - }, - { - "id": 126, - "name": "names", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "an array of names that match the columns" - }, - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 127, - "name": "autoType", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "unless set to false, the method will attempt to determine the\ntype of data and automatically cast data points to their correct value\n" - }, - "type": { - "type": "intrinsic", - "name": "boolean" - }, - "defaultValue": "true" - } - ], - "type": { - "type": "intrinsic", - "name": "void" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 412, - "character": 19 - } - ] - }, - { - "id": 109, - "name": "sort", - "kind": 2048, - "kindString": "Method", - "flags": { - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 110, - "name": "sort", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "the Data object in order to allow for chaining.\n", - "tags": [ - { - "tag": "description", - "text": "Sorts the rows of values based on the result of the `sortFn`,\nwhich behaves similarly to the Array.sort method.\nTwo modes are supported:\n# Array Mode\nIf `col` is omitted, the column arrays are passed as samples into the `sortFn`.\nThis allows for complex sorts, combining conditions across multiple columns.\n```\ndata.sort((row1, row2) => row1[5] - row2[5] );\n```\n# Column mode\nIf `col` is specified, either as index or by column name, the respective column value is passed\ninto `sortFn`. This allows filtering for simple conditions.
    \n**The specified column will be automatically cast prior to sorting**
    \n`data.sort('Date', function(val1, val2) { return val1 - val2; });`" - } - ] - }, - "parameters": [ - { - "id": 111, - "name": "sortFn", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "a function to implement the conditions,\nfollows the same specifications as the function passed to Array.sort().\nSome predefined sort function can be invoked by providing a\nrespective string instead of a function. The following functions are defined:\n\n\n\n
    '`ascending`'sort in ascending order.
    '`descending`'sort in decending order.
    " - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "sortFn", - "id": 111 - } - ] - } - }, - { - "id": 112, - "name": "col", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "comment": { - "text": "optional; the data column to use for sorting." - }, - "type": { - "type": "reference", - "name": "ColumnReference", - "id": 150 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 307, - "character": 15 - } - ] - }, - { - "id": 137, - "name": "toDate", - "kind": 2048, - "kindString": "Method", - "flags": { - "isPrivate": true, - "isExported": true - }, - "signatures": [ - { - "id": 138, - "name": "toDate", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "returns": "a new Date object parsed from `str`.", - "tags": [ - { - "tag": "description", - "text": "returns a new Date object parsed from `str` and corrects for a difference in\ninterpreting centuries between webkit and mozilla in converting strings to Dates:\nThe string \"15/7/03\" will convert to Jul 15 1903 in Mozilla and July 15 2003 in Webkit.\nIf `limitYear` is not specified this method uses 1970 as the decision date:\nyears 00-69 will be interpreted as 2000-2069, years 70-99 as 1970-1999.\n" - } - ] - }, - "parameters": [ - { - "id": 139, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the string to convert to a date" - }, - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - }, - { - "id": 140, - "name": "limitYear", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the year below which the century is corrected. Defaults to 1970." - }, - "type": { - "type": "intrinsic", - "name": "number" - }, - "defaultValue": "1970" - } - ], - "type": { - "type": "reference", - "name": "Date" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 510, - "character": 18 - } - ] - }, - { - "id": 63, - "name": "toDataSet", - "kind": 2048, - "kindString": "Method", - "flags": { - "isStatic": true, - "isExported": true, - "isPublic": true - }, - "signatures": [ - { - "id": 64, - "name": "toDataSet", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 65, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataLiteralSet", - "id": 153 - } - }, - { - "id": 66, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "reference", - "name": "DataSet", - "id": 43 - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 80, - "character": 27 - } - ] - }, - { - "id": 57, - "name": "type", - "kind": 2097152, - "kindString": "Object literal", - "flags": { - "isStatic": true, - "isExported": true, - "isPublic": true - }, - "children": [ - { - "id": 61, - "name": "currency", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "currency values. Currently support6ed are values ofg the format '$dd[,ddd]'" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 74, - "character": 16 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"currency\"" - }, - { - "id": 60, - "name": "date", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "date values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 72, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"date\"" - }, - { - "id": 59, - "name": "name", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "nominal values, represented by arbitrary words" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 70, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"name\"" - }, - { - "id": 58, - "name": "number", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "numeric values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 68, - "character": 14 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"number\"" - }, - { - "id": 62, - "name": "percent", - "kind": 32, - "kindString": "Variable", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "percent values: 'd%'" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 76, - "character": 15 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - }, - "defaultValue": "\"percent\"" - } - ], - "groups": [ - { - "title": "Variables", - "kind": 32, - "children": [ - 61, - 60, - 59, - 58, - 62 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 66, - "character": 22 - } - ], - "type": { - "type": "intrinsic", - "name": "object" - } - } - ], - "groups": [ - { - "title": "Constructors", - "kind": 512, - "children": [ - 67 - ] - }, - { - "title": "Properties", - "kind": 1024, - "children": [ - 117, - 118, - 119 - ] - }, - { - "title": "Methods", - "kind": 2048, - "children": [ - 134, - 104, - 141, - 82, - 85, - 92, - 95, - 89, - 97, - 75, - 106, - 100, - 131, - 128, - 79, - 77, - 120, - 70, - 72, - 113, - 123, - 109, - 137, - 63 - ] - }, - { - "title": "Object literals", - "kind": 2097152, - "children": [ - 57 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 62, - "character": 17 - } - ] - }, - { - "id": 43, - "name": "DataSet", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a JSON format data set, using arrays of names and rows" - }, - "children": [ - { - "id": 45, - "name": "colNames", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "an array of column names. Each name matches the column with the same index in DataRow" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 36, - "character": 12 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 44, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "comment": { - "shortText": "an optional name for the data set" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 34, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 46, - "name": "rows", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "rows of data" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 38, - "character": 8 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 45, - 44, - 46 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 32, - "character": 24 - } - ] - }, - { - "id": 50, - "name": "MetaStruct", - "kind": 256, - "kindString": "Interface", - "flags": {}, - "children": [ - { - "id": 53, - "name": "accessed", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 49, - "character": 12 - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - }, - { - "id": 54, - "name": "cast", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 50, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - }, - { - "id": 52, - "name": "column", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 48, - "character": 10 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 51, - "name": "name", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 47, - "character": 8 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 55, - "name": "types", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 51, - "character": 9 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "TypeStruct", - "id": 47 - } - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 53, - 54, - 52, - 51, - 55 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 46, - "character": 20 - } - ] - }, - { - "id": 47, - "name": "TypeStruct", - "kind": 256, - "kindString": "Interface", - "flags": {}, - "children": [ - { - "id": 49, - "name": "count", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 42 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 48, - "name": "type", - "kind": 1024, - "kindString": "Property", - "flags": {}, - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 27 - } - ], - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 49, - 48 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 44, - "character": 20 - } - ] - }, - { - "id": 150, - "name": "ColumnReference", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a Column Reference, either as column name or index in the {@link Data.DataRow `DataRow`} array" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 23, - "character": 27 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "string" - } - ] - } - }, - { - "id": 153, - "name": "DataLiteralSet", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a JSON format data set, using an array of {name:value, ...} literals" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 42, - "character": 26 - } - ], - "type": { - "type": "reference", - "name": "Array", - "typeArguments": [ - { - "type": "intrinsic", - "name": "any" - } - ] - } - }, - { - "id": 152, - "name": "DataRow", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a single row of column values" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 29, - "character": 19 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - } - }, - { - "id": 151, - "name": "DataVal", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "a generic data value type, used in the {@link Data.DataRow `DataRow`} array" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 26, - "character": 19 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "reference", - "name": "Date" - } - ] - } - }, - { - "id": 147, - "name": "DateDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a Date domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 14, - "character": 22 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "reference", - "name": "Date" - }, - { - "type": "reference", - "name": "Date" - } - ] - } - }, - { - "id": 149, - "name": "Domain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a generic domain that can be any of the typed domains." - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 20, - "character": 18 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "NumDomain", - "id": 146 - }, - { - "type": "reference", - "name": "DateDomain", - "id": 147 - }, - { - "type": "reference", - "name": "NameDomain", - "id": 148 - } - ] - } - }, - { - "id": 148, - "name": "NameDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a categorical domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 17, - "character": 22 - } - ], - "type": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "string" - } - } - }, - { - "id": 146, - "name": "NumDomain", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a numeric domain that includes all values of a column" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 11, - "character": 21 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "number" - } - ] - } - }, - { - "id": 145, - "name": "NumRange", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "defines a [min-max] range" - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 8, - "character": 20 - } - ], - "type": { - "type": "tuple", - "elements": [ - { - "type": "intrinsic", - "name": "number" - }, - { - "type": "intrinsic", - "name": "number" - } - ] - } - }, - { - "id": 159, - "name": "mapFn", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 55, - "character": 17 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 160, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 161, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 162, - "name": "colVal", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 163, - "name": "colIndex", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 164, - "name": "rowIndex", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 165, - "name": "rows", - "kind": 32768, - "kindString": "Parameter", - "flags": { - "isOptional": true - }, - "type": { - "type": "array", - "elementType": { - "type": "array", - "elementType": { - "type": "intrinsic", - "name": "any" - } - } - } - } - ], - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 55, - "character": 20 - } - ] - } - } - }, - { - "id": 154, - "name": "sortFn", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "Data.ts", - "line": 54, - "character": 18 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 155, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 156, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 157, - "name": "x", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 158, - "name": "y", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 54, - "character": 20 - } - ] - } - } - } - ], - "groups": [ - { - "title": "Classes", - "kind": 128, - "children": [ - 56 - ] - }, - { - "title": "Interfaces", - "kind": 256, - "children": [ - 43, - 50, - 47 - ] - }, - { - "title": "Type aliases", - "kind": 4194304, - "children": [ - 150, - 153, - 152, - 151, - 147, - 149, - 148, - 146, - 145, - 159, - 154 - ] - } - ], - "sources": [ - { - "fileName": "Data.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 1, - "name": "\"DataFilters\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/DataFilters.ts", - "comment": { - "shortText": "Use the {@link filter `filter`} function to executes a queries on a {@link Data `Data`} object.\nEach row in the data is checked and those for which `conditions` holds true are returned as a new `Data` object.", - "text": "# Condition construction\n\n### General Condition\n```\nCondition =\n IndexCondition -> conditions on the row index\n|| RecursiveCondition -> (set of) conditions on column values\n```\n\n### IndexCondition\n```\nIndexCondition =\n rowIndex:number -> true if row index matches\n```\n\n### RecursiveCondition\n```\nRecursiveCondition =\n OrCondition -> OR: true if any compound condition is true\n|| AndCondition -> AND: true if all compound conditions are true\n\nOrCondition = -> OR: true if\n AndCondition[] -> any of the AndConditions are true\n|| IndexCondition[] -> any of thr IndexConditions are true\n\nAndCondition = -> AND: true if\n SetAndCondition -> all SetAndConditions are true\n|| TermAndCondition -> or if all TermAndConditions are true\n\nSetAndCondition = { -> AND: true if all sub-conditions are true\n 'or': RecursiveCondition -> true if any RecursiveCondition is true\n|| 'and': RecursiveCondition -> true if all RecursiveCondition are true\n|| 'not': RecursiveCondition -> true if the condition is false\n\nTermAndCondition = { -> Terminal AND: true if all terminal sub-conditions are true\n colDesc:colValue -> true if colValue matches\n|| colDesc:[colValue, ...] -> true if any of the colValues match\n|| colDesc:function(value,row) -> true if function returns true\n}\n\ncolDesc = either column name or index\n```\n\n### Practical Tips\n```\n {'or': [recurCond, ...]} -> OR, same as [recurCond, ...]\n|| {'or': {SetCond, ...}} -> OR, same as [SetCond, ...]\n|| {'and': [recurCond, ...]} -> AND, true if all recurCond are true\n|| {'and': {SetCond, ...}} -> AND, same as {SetCond, ...}\n|| {'not': {SetCond, ...}} -> NAND: true if the SetCond are true\n|| {'not': [recurCond, ...]} -> NOR: true if any of the recurCond are true\n```\n\n# Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nqueries = [\n ['0', undefined, 'undefined query => pass all'],\n ['1', [], 'empty OR: [] => fail all'],\n ['2', {}, 'empty AND: {} => pass all'],\n ['3', 1, '2nd row: pass row 1'],\n ['4', [1,3], '2nd+4th: pass rows: 1 and 3'],\n ['5', {Name:\"Jane\"}, 'Name is Jane'],\n ['6', {1:1500}, 'Column 2 is 1500'],\n ['7', {Name:[\"Peter\", \"Jane\"]}, 'Name is Peter or Jane'],\n ['8', [{Name:\"Peter\"}, {Value:1500}], 'Name is Peter or Value is 1500'],\n ['9', {or:{Name:\"Peter\", Value:1500}}, 'OR: same as 8:'],\n ['A', {or:[{Name:\"Peter\"}, {Value:1500}]}, 'OR: [{Name is Peter}, {Value is 1500}]'],\n ['B', {Name:\"Peter\", Value:400}, 'Name is Peter and Value is 400'],\n ['C', {and:{Name:\"Peter\", Value:400}}, 'AND: {Name is Peter, Value is 400}'],\n ['D', {and:{Name:\"Peter\", Value:1500}}, 'AND: {Name is Peter, Value is 1500}'],\n ['E', {and:[{Name:\"Peter\"}, {Value:400}]}, 'AND:[{Name is Peter}, {Value is 400}]'],\n ['F', {and:[{Name:\"Peter\"}, {Value:1500}]},'AND:[{Name is Peter}, {Value is 1500}]'],\n ['G', {not:{Name:\"Peter\", Value:400}}, 'NAND: not {Name is Peter and Value is 400}'],\n ['H', {not:{Name:\"Peter\", Value:1500}}, 'NAND: not {Name is Peter and Value is 1500}'],\n ['I', {not:[{Name:\"Peter\"}, {Value:1500}]},'NOR: not [{Name is Peter} or {Value is 1500}]'],\n ['J', {Name:(v) => v.length===4}, 'Name has 4 letters']\n];\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [m('td', row[0]),m('td', row[1]),m('td', row[2].toDateString()),m('td', row[3].toDateString())]))\n ]),\n m('h3', 'The following queries yield:'),\n m('table', [\n m('tr', [m('th','#'), m('th','Query'), m('th',\"Live Result, by 'Name' field\")]),\n ...queries.map(q => {\n const result = data.filter(q[1]).getColumn('Name').join(', ');\n return m('tr', [m('td',`${q[0]}:`), m('td',`${q[2]}`), m('td',`[ ${result} ]`)]);\n })\n ])\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n table {\n font-size: 10pt;\n margin-left: 10px;\n }\n\n\n" - }, - "children": [ - { - "id": 2, - "name": "SetAndCondition", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "children": [ - { - "id": 4, - "name": "and", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 140, - "character": 7 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 11 - } - }, - { - "id": 5, - "name": "not", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 141, - "character": 7 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 11 - } - }, - { - "id": 3, - "name": "or", - "kind": 1024, - "kindString": "Property", - "flags": { - "isExported": true, - "isOptional": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 139, - "character": 6 - } - ], - "type": { - "type": "reference", - "name": "RecursiveCondition", - "id": 11 - } - } - ], - "groups": [ - { - "title": "Properties", - "kind": 1024, - "children": [ - 4, - 5, - 3 - ] - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 138, - "character": 32 - } - ] - }, - { - "id": 6, - "name": "TermAndCondition", - "kind": 256, - "kindString": "Interface", - "flags": { - "isExported": true - }, - "indexSignature": { - "id": 7, - "name": "__index", - "kind": 8192, - "kindString": "Index signature", - "flags": {}, - "parameters": [ - { - "id": 8, - "name": "colDesc", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "DataVal", - "id": 151 - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - }, - { - "type": "reference", - "name": "TermConditionFunction", - "id": 14 - } - ] - } - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 144, - "character": 33 - } - ] - }, - { - "id": 13, - "name": "AndCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 136, - "character": 24 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "SetAndCondition", - "id": 2 - }, - { - "type": "reference", - "name": "TermAndCondition", - "id": 6 - } - ] - } - }, - { - "id": 9, - "name": "Condition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 129, - "character": 21 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "IndexCondition", - "id": 10 - }, - { - "type": "reference", - "name": "RecursiveCondition", - "id": 11 - } - ] - } - }, - { - "id": 10, - "name": "IndexCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "comment": { - "shortText": "true if row index matches the number(s)" - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 132, - "character": 26 - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 12, - "name": "OrCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 135, - "character": 23 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "array", - "elementType": { - "type": "reference", - "name": "AndCondition", - "id": 13 - } - }, - { - "type": "array", - "elementType": { - "type": "reference", - "name": "IndexCondition", - "id": 10 - } - } - ] - } - }, - { - "id": 11, - "name": "RecursiveCondition", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 134, - "character": 30 - } - ], - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "name": "AndCondition", - "id": 13 - }, - { - "type": "reference", - "name": "OrCondition", - "id": 12 - } - ] - } - }, - { - "id": 14, - "name": "TermConditionFunction", - "kind": 4194304, - "kindString": "Type alias", - "flags": { - "isExported": true - }, - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 152, - "character": 33 - } - ], - "type": { - "type": "reflection", - "declaration": { - "id": 15, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 16, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 17, - "name": "value", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataVal", - "id": 151 - } - }, - { - "id": 18, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 152, - "character": 35 - } - ] - } - } - }, - { - "id": 38, - "name": "filter", - "kind": 64, - "kindString": "Function", - "flags": { - "isExported": true - }, - "signatures": [ - { - "id": 39, - "name": "filter", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "filters a `Data` object for the given `Condition`s and returns a new `Data` object with those rows for which\n`cond` holds true.", - "returns": "a new `Data` object with the filtered rows\n" - }, - "parameters": [ - { - "id": 40, - "name": "data", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the `Data` object to filter" - }, - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - }, - { - "id": 41, - "name": "cond", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the complex condition to test against" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 9 - } - } - ], - "type": { - "type": "reference", - "name": "Data", - "id": 56 - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 234, - "character": 22 - } - ] - }, - { - "id": 28, - "name": "resolveCondition", - "kind": 64, - "kindString": "Function", - "flags": {}, - "signatures": [ - { - "id": 29, - "name": "resolveCondition", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "comment": { - "shortText": "applies `condition` to a row of data and returns `true` if the row passes." - }, - "parameters": [ - { - "id": 30, - "name": "condition", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the complex condition to test against" - }, - "type": { - "type": "reference", - "name": "Condition", - "id": 9 - } - }, - { - "id": 31, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the row values" - }, - "type": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - }, - { - "id": 32, - "name": "r", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "the row index in the data set" - }, - "type": { - "type": "intrinsic", - "name": "number" - } - }, - { - "id": 33, - "name": "colNumber", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reflection", - "declaration": { - "id": 34, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 35, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 36, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 181, - "character": 80 - } - ] - } - } - }, - { - "id": 37, - "name": "and", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "comment": { - "text": "\n" - }, - "type": { - "type": "intrinsic", - "name": "boolean" - }, - "defaultValue": "true" - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 181, - "character": 25 - } - ] - }, - { - "id": 19, - "name": "resolveTerminalCondition", - "kind": 64, - "kindString": "Function", - "flags": {}, - "signatures": [ - { - "id": 20, - "name": "resolveTerminalCondition", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 21, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 22, - "name": "val", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "any" - } - }, - { - "id": 23, - "name": "row", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reference", - "name": "DataRow", - "id": 152 - } - }, - { - "id": 24, - "name": "colNumber", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "reflection", - "declaration": { - "id": 25, - "name": "__type", - "kind": 65536, - "kindString": "Type literal", - "flags": {}, - "signatures": [ - { - "id": 26, - "name": "__call", - "kind": 4096, - "kindString": "Call signature", - "flags": {}, - "parameters": [ - { - "id": 27, - "name": "name", - "kind": 32768, - "kindString": "Parameter", - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "type": { - "type": "intrinsic", - "name": "number" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 155, - "character": 79 - } - ] - } - } - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - } - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 155, - "character": 33 - } - ] - } - ], - "groups": [ - { - "title": "Interfaces", - "kind": 256, - "children": [ - 2, - 6 - ] - }, - { - "title": "Type aliases", - "kind": 4194304, - "children": [ - 13, - 9, - 10, - 12, - 11, - 14 - ] - }, - { - "title": "Functions", - "kind": 64, - "children": [ - 38, - 28, - 19 - ] - } - ], - "sources": [ - { - "fileName": "DataFilters.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 166, - "name": "\"index\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/index.ts", - "sources": [ - { - "fileName": "index.ts", - "line": 1, - "character": 0 - } - ] - }, - { - "id": 167, - "name": "\"overview\"", - "kind": 1, - "kindString": "External module", - "flags": { - "isExported": true - }, - "originalName": "/Users/sth1pal/Documents/Development/JavaScript/node.js/ts6/dev/hsLibs/standalone/hsDatab/src/overview.ts", - "comment": { - "shortText": "# hsDatab", - "text": "Helpful Scripts framework-independent data management functions. [Github page](https://github.com/HelpfulScripts/hsDatab)\n\n**hsDatab** provides a JavaScript-based data management and query mechanism.\nData is managed in a simple in-memory database that holds data in rows of columns.\nIt autodetermines the types of data held in each column, along with the\ndomain range for each column of data.\nComplex filters can be applied by defining {@link DataFilters `Condition`}s using a simple query object structure.\n\n## Data Types\nsupported {@link Data.Data.type data types} include\n- **number**: numeric values\n- **name**: nominal values, represented by arbitrary words\n- **date**: date values\n- **currency**: Currently supported: '$dd[,ddd]'\n- **percent**: 'd%'\n\n## Data Class\nThe fundamental object in this library is {@link Data.Data `Data`},\na simple row-column based database object,\nfeaturing named columns, sorting, mapping and filtering functions.\n\n## Example\n\n\nconst colNames = ['Name', 'Value', 'Start', 'End'];\nconst rows = [\n ['Harry', '100', '3/1/14', '11/20/14'],\n ['Mary', '1500', '7/1/14', '9/30/14'],\n ['Peter', '400', '5/20/14', '4/30/15'],\n ['Jane', '700', '11/13/14', '8/15/15']\n]\nconst data = new hsdatab.Data({colNames:colNames, rows:rows});\n\nquery = {Name:[\"Peter\", \"Jane\"]};\nconst result = data.filter(query);\n\nm.mount(root, {\n view:() => m('', [\n m('h3', 'Given the data set:'),\n m('pre',\n m('table#data', [\n m('tr', colNames.map(n => m('th', n))),\n ...rows.map(row => m('tr', [\n m('td', row[0]),\n m('td', row[1]),\n m('td', `${row[2].getMonth()+1}/${row[2].getDate()}/${row[2].getFullYear()}`),\n m('td', `${row[3].getMonth()+1}/${row[3].getDate()}/${row[3].getFullYear()}`)\n ]))\n ])),\n m('h3', 'The column types and domains are'),\n m('pre', m('table',\n m('tr', m('th', 'Column'), m('th', 'Type'), m('th', 'Domain')),\n m('tr', m('td', '\"Name\":'), m('td', data.colType(\"Name\")), m('td', data.findDomain(\"Name\").join(', '))),\n m('tr', m('td', '\"Value\":'), m('td', data.colType(\"Value\")), m('td', data.findDomain(\"Value\").join(' - '))),\n m('tr', m('td', '\"Start\":'), m('td', data.colType(\"Start\")), m('td', data.findDomain(\"Start\").map(d => d.toDateString()).join(' - '))),\n m('tr', m('td', '\"Stop\":'), m('td', data.colType(\"End\")), m('td', data.findDomain(\"End\").map(d => d.toDateString()).join(' - ')))\n )),\n m('h3', 'The query:'),\n m('code', '{Name:[\"Peter\", \"Jane\"]}'),\n m('h3', 'yields results with \"Name\"'),\n m('code', result.getColumn('Name').join(', '))\n ])\n});\n\n\n $exampleID { height: 600px; }\n #data th { width:15%; }\n #data { font-size: 11pt; }\n\n\n" - }, - "sources": [ - { - "fileName": "overview.ts", - "line": 1, - "character": 0 - } - ] - } - ], - "groups": [ - { - "title": "External modules", - "kind": 1, - "children": [ - 42, - 1, - 166, - 167 - ] - } - ] -} \ No newline at end of file