├── .circleci
└── config.yml
├── .editorconfig
├── .eslintrc
├── .gitattributes
├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .jscsrc
├── .npmignore
├── .nvmrc
├── .sublimets
├── Gruntfile.js
├── LICENSE
├── README.md
├── license_header.txt
├── package.json
├── plottable.css
├── quicktests
├── color
│ ├── index.html
│ ├── main.css
│ └── main.js
├── dev
│ ├── dev.css
│ ├── dev.js
│ └── index.html
├── exampleUtil.js
├── fiddle.html
├── index.html
├── maxLabelWidth.html
├── overlaying
│ ├── data
│ │ ├── AAPL_20140401_20140901.csv
│ │ ├── GOOG_20140401_20140901.csv
│ │ ├── baseball.csv
│ │ ├── cities.csv
│ │ ├── hockey.csv
│ │ └── worldcup.json
│ ├── index.html
│ ├── overlaying.css
│ ├── overlaying.js
│ └── tests
│ │ ├── animations
│ │ ├── animate_area.js
│ │ ├── animate_horizontalBar.js
│ │ ├── animate_line.js
│ │ ├── animate_scatter.js
│ │ ├── animate_verticalBar.js
│ │ └── inflationsegment.js
│ │ ├── basic
│ │ ├── bar_horizontal_labels.js
│ │ ├── basic_allPlots.js
│ │ ├── canvas_bar.js
│ │ ├── canvas_grid.js
│ │ ├── canvas_line.js
│ │ ├── canvas_scatter.js
│ │ ├── categoryAxis_timeAxis.js
│ │ ├── gridlines.js
│ │ ├── half_pies.js
│ │ ├── histogram.js
│ │ ├── layout_tables.js
│ │ ├── log_scale.js
│ │ ├── missing_clustered_bar.js
│ │ ├── missing_stacked_area.js
│ │ ├── modified_log_scale.js
│ │ ├── negative_stacked_bar.js
│ │ ├── non_canvas_scatter.js
│ │ ├── pies.js
│ │ ├── scatter_labels.js
│ │ ├── stacked_area_with_scatterplot.js
│ │ ├── waterfall.js
│ │ └── wrapped_label.js
│ │ ├── functional
│ │ ├── axisTickLabelDataOnElement.js
│ │ ├── bar_plot_label_font_size.js
│ │ ├── base_animator.js
│ │ ├── categoryFormatter.js
│ │ ├── category_axis_label_font_size.js
│ │ ├── category_axis_long_ticks.js
│ │ ├── category_axis_rotated_ticks.js
│ │ ├── doubleAxes.js
│ │ ├── formatter.js
│ │ ├── loading_high_scale.js
│ │ ├── nearestEntity.js
│ │ ├── numeric_axis_label_font_size.js
│ │ ├── padding.js
│ │ ├── scatter_plot_label_font_size.js
│ │ ├── time_axis_label_font_size.js
│ │ └── titleLegend_change.js
│ │ ├── interactions
│ │ ├── angle_text.js
│ │ ├── barHover.js
│ │ ├── barHover_canvas.js
│ │ ├── css_transforms.js
│ │ ├── dragbox.js
│ │ ├── dragbox_scales.js
│ │ ├── guidelines.js
│ │ ├── interaction_hover_scatter.js
│ │ ├── key_zoom_pointer.js
│ │ ├── pan_zoom_reverse.js
│ │ ├── scale_interactive.js
│ │ ├── select_bars.js
│ │ ├── select_clustered_bars.js
│ │ └── single_and_double_click.js
│ │ └── realistic
│ │ ├── add_remove_dataset.js
│ │ ├── animals.js
│ │ ├── bar_and_legend_and_panzoom.js
│ │ ├── baseball.js
│ │ ├── basic_pie_real.js
│ │ ├── category_grid.js
│ │ ├── cities.js
│ │ ├── hockey.js
│ │ ├── legend_select.js
│ │ ├── many_bars.js
│ │ ├── numeric_grid.js
│ │ ├── phones.js
│ │ ├── rainfall_ClusteredBar.js
│ │ ├── rectangle.js
│ │ ├── scatter_bar.js
│ │ ├── stocks.js
│ │ ├── symbols.js
│ │ └── vertical_line.js
└── umd
│ ├── app.js
│ └── index.html
├── scripts
├── authenticateNpm.sh
├── publishSnapshot.sh
└── submit-comment-with-artifact-links.js
├── src
├── animators
│ ├── animator.ts
│ ├── easingAnimator.ts
│ ├── index.ts
│ └── nullAnimator.ts
├── axes
│ ├── axis.ts
│ ├── categoryAxis.ts
│ ├── index.ts
│ ├── numericAxis.ts
│ └── timeAxis.ts
├── components
│ ├── component.ts
│ ├── componentContainer.ts
│ ├── dragBoxLayer.ts
│ ├── dragLineLayer.ts
│ ├── gridlines.ts
│ ├── group.ts
│ ├── guideLineLayer.ts
│ ├── index.ts
│ ├── interpolatedColorLegend.ts
│ ├── label.ts
│ ├── legend.ts
│ ├── plotGroup.ts
│ ├── selectionBoxLayer.ts
│ ├── table.ts
│ ├── wrappedLabel.ts
│ ├── xDragBoxLayer.ts
│ └── yDragBoxLayer.ts
├── core
│ ├── config.ts
│ ├── dataset.ts
│ ├── formatters.ts
│ ├── interfaces.ts
│ ├── renderController.ts
│ ├── renderPolicy.ts
│ ├── symbolFactories.ts
│ └── version.ts
├── dispatchers
│ ├── dispatcher.ts
│ ├── index.ts
│ ├── keyDispatcher.ts
│ ├── mouseDispatcher.ts
│ └── touchDispatcher.ts
├── drawers
│ ├── arcDrawer.ts
│ ├── arcOutlineDrawer.ts
│ ├── areaDrawer.ts
│ ├── canvasBuffer.ts
│ ├── canvasDrawer.ts
│ ├── drawStep.ts
│ ├── drawer.ts
│ ├── index.ts
│ ├── lineDrawer.ts
│ ├── rectangleDrawer.ts
│ ├── segmentDrawer.ts
│ ├── svgDrawer.ts
│ └── symbolDrawer.ts
├── index.ts
├── interactions
│ ├── clickInteraction.ts
│ ├── dragInteraction.ts
│ ├── index.ts
│ ├── interaction.ts
│ ├── keyInteraction.ts
│ ├── panZoomConstraints.ts
│ ├── panZoomInteraction.ts
│ └── pointerInteraction.ts
├── memoize
│ ├── index.ts
│ ├── memThunk.ts
│ ├── memoize.ts
│ ├── memoizeProjectors.ts
│ └── signature.ts
├── plots
│ ├── areaPlot.ts
│ ├── barPlot.ts
│ ├── clusteredBarPlot.ts
│ ├── commons.ts
│ ├── deferredRenderer.ts
│ ├── index.ts
│ ├── linePlot.ts
│ ├── piePlot.ts
│ ├── plot.ts
│ ├── rectanglePlot.ts
│ ├── scatterPlot.ts
│ ├── segmentPlot.ts
│ ├── stackedAreaPlot.ts
│ ├── stackedBarPlot.ts
│ ├── waterfallPlot.ts
│ └── xyPlot.ts
├── scales
│ ├── categoryScale.ts
│ ├── colorScale.ts
│ ├── index.ts
│ ├── interpolatedColorScale.ts
│ ├── linearScale.ts
│ ├── logScale.ts
│ ├── modifiedLogScale.ts
│ ├── quantitativeScale.ts
│ ├── scale.ts
│ ├── tickGenerators.ts
│ └── timeScale.ts
└── utils
│ ├── addD3SelectionMulti.ts
│ ├── arrayUtils.ts
│ ├── bucket.ts
│ ├── callbackSet.ts
│ ├── coerceD3.ts
│ ├── colorUtils.ts
│ ├── domUtils.ts
│ ├── entityStore.ts
│ ├── index.ts
│ ├── makeEnum.ts
│ ├── map.ts
│ ├── mathUtils.ts
│ ├── objectUtils.ts
│ ├── rTree.ts
│ ├── rTreeSplitStrategies.ts
│ ├── set.ts
│ ├── stackingUtils.ts
│ ├── transformAwareTranslator.ts
│ └── windowUtils.ts
├── test
├── animators
│ ├── easingAnimatorTests.ts
│ └── nullAnimatorTests.ts
├── axes
│ ├── axisTests.ts
│ ├── categoryAxisTests.ts
│ ├── numericAxisTests.ts
│ └── timeAxisTests.ts
├── blanket_mocha.js
├── components
│ ├── componentTests.ts
│ ├── dragBoxLayerTests.ts
│ ├── dragLineLayerTests.ts
│ ├── gridlinesTests.ts
│ ├── groupTests.ts
│ ├── guideLineLayerTests.ts
│ ├── interpolatedColorLegendTests.ts
│ ├── labelTests.ts
│ ├── legendTests.ts
│ ├── plotGroupTests.ts
│ ├── selectionBoxLayerTests.ts
│ ├── tableTests.ts
│ ├── xDragBoxLayerTests.ts
│ └── yDragBoxLayerTests.ts
├── core
│ ├── datasetTests.ts
│ ├── formattersTests.ts
│ ├── metadataTests.ts
│ ├── renderControllerTests.ts
│ └── symbolFactoriesTests.ts
├── coverage.html
├── dispatchers
│ ├── dispatcherTests.ts
│ ├── keyDispatcherTests.ts
│ ├── mouseDispatcherTests.ts
│ └── touchDispatcherTests.ts
├── drawers
│ ├── arcDrawerTests.ts
│ ├── arcOutlineDrawerTests.ts
│ ├── areaDrawerTests.ts
│ ├── canvasDrawerTests.ts
│ ├── drawerTests.ts
│ ├── lineDrawerTests.ts
│ ├── svgDrawerTests.ts
│ └── symbolDrawerTests.ts
├── globalInitialization.ts
├── index.ts
├── interactions
│ ├── clickInteractionTests.ts
│ ├── dragInteractionTests.ts
│ ├── interactionTests.ts
│ ├── keyInteractionTests.ts
│ ├── panZoomInteractionTests.ts
│ └── pointerInteractionTests.ts
├── memoize
│ ├── memThunkTests.ts
│ ├── memoizeTests.ts
│ └── signatureTests.ts
├── mocks.ts
├── namespacingTests.ts
├── plots
│ ├── areaPlotTests.ts
│ ├── barPlotTests.ts
│ ├── clusteredBarPlotTests.ts
│ ├── linePlotTests.ts
│ ├── piePlotTests.ts
│ ├── plotTests.ts
│ ├── rectanglePlotTests.ts
│ ├── scatterPlotTests.ts
│ ├── segmentPlotTests.ts
│ ├── stackedAreaPlotTests.ts
│ ├── stackedBarPlotTests.ts
│ ├── stackedPlotTests.ts
│ ├── waterfallPlotTests.ts
│ └── xyPlotTests.ts
├── scales
│ ├── categoryScaleTests.ts
│ ├── colorScaleTests.ts
│ ├── interpolatedColorScaleTests.ts
│ ├── linearScaleTests.ts
│ ├── logScaleTests.ts
│ ├── modifiedLogScaleTests.ts
│ ├── quantitativeScaleTests.ts
│ ├── scaleTests.ts
│ ├── tickGeneratorsTests.ts
│ └── timeScaleTests.ts
├── testMethods.ts
├── tests.css
├── tests.html
├── utils
│ ├── arrayUtilsTests.ts
│ ├── callbackSetTests.ts
│ ├── colorUtilsTests.ts
│ ├── domUtilsTests.ts
│ ├── mapTests.ts
│ ├── mathUtilsTests.ts
│ ├── rTreeTests.ts
│ ├── setTests.ts
│ ├── stackingUtilsTests.ts
│ ├── transformAwareTranslatorTests.ts
│ └── windowUtilsTests.ts
└── window.d.ts
├── tsconfig.json
├── tslint.json
├── webpack.config.js
├── webpackConfig
├── build.js
└── test.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 |
7 | [*.{json,js,ts}]
8 | charset = utf-8
9 | indent_style = space
10 |
11 | [*.{js,ts}]
12 | indent_size = 2
13 |
14 | [{package.json,.travis.yml,.tslintrc}]
15 | indent_size = 2
16 |
17 | [{tsconfig.json}]
18 | indent_size = 4
19 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es6": true,
4 | "browser": true,
5 | "jquery": true
6 | },
7 | "globals": {
8 | "d3": true,
9 | "Plottable": true,
10 | "makeRandomData": true,
11 | "makeRandomNamedData": true,
12 | "deepCopy": true
13 | },
14 | "rules": {
15 | "no-eval": 0,
16 | "quotes": [2, "double", "avoid-escape"],
17 | "no-unused-vars": [2, {"vars": "local"}],
18 | "no-multi-spaces": 0,
19 | "no-use-before-define": [2, "nofunc"]
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.d.ts text
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
11 |
12 | ## Bug report
13 |
14 | Live example URL:
15 |
16 | Steps to repro:
17 | 1.
18 | 1.
19 | 1.
20 |
21 | ### Expected behavior
22 |
23 |
24 | ### Actual behavior
25 |
26 |
27 | ### Possible Solution
28 |
29 |
30 | ### Context
31 |
32 |
33 |
34 | ### Environment
35 |
36 |
37 | - Plottable version:
38 | - Browser name/version:
39 | - OS name/version:
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build files
2 | build/
3 | test/tests.js
4 | test/tests.js.map
5 | plottable.js
6 | plottable.js.map
7 | plottable.d.ts
8 | plottable.min.js
9 |
10 | # Typescript
11 | .baseDir.ts
12 | .tscache/
13 |
14 | # Project specific
15 | node_modules/
16 | local/
17 | quicktests/github_token.txt
18 | quicktests/overlaying/list_of_quicktests.json
19 |
20 | # Mac
21 | .DS_Store
22 | *.tmp.txt
23 |
24 | # IntelliJ
25 | .idea/
26 |
27 | # Emacs
28 | .#*
29 |
30 | # Vim
31 | *.swp
32 | *~
33 |
34 | # Eclipse
35 | *.project
36 |
37 | # Visual Studio Code
38 | .settings/
39 | .vscode/
40 |
41 | yarn-error.log
42 |
--------------------------------------------------------------------------------
/.jscsrc:
--------------------------------------------------------------------------------
1 | {
2 | "disallowMultipleLineBreaks": true
3 | }
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | **/*
2 | !README.md
3 | !LICENSE
4 | !package.json
5 | !plottable.js
6 | !plottable.js.map
7 | !plottable.d.ts
8 | !plottable.css
9 | !plottable.min.js
10 | !build/src/**/*
11 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v8.10
2 |
--------------------------------------------------------------------------------
/.sublimets:
--------------------------------------------------------------------------------
1 | {
2 | "root":"build/sublime.d.ts"
3 | }
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2017 Palantir Technologies, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/license_header.txt:
--------------------------------------------------------------------------------
1 | /*!
2 | Plottable @VERSION (https://github.com/palantir/plottable)
3 | Copyright 2014-present Palantir Technologies
4 | Licensed under MIT (https://github.com/palantir/plottable/blob/master/LICENSE)
5 | */
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "plottable",
3 | "description": "A modular charting library built on D3",
4 | "version": "3.13.0",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/palantir/plottable.git"
9 | },
10 | "author": "Palantir Technologies",
11 | "main": "build/src/index.js",
12 | "typings": "build/src/index.d.ts",
13 | "scripts": {
14 | "build": "npm-run-all -p lint:tslint build:tsc -s build:webpack",
15 | "build:tsc": "tsc -p .",
16 | "build:webpack": "webpack",
17 | "clean": "rm -rf build",
18 | "check_version": "echo ${npm_package_version} $(npm view ${npm_package_name} version) | awk '{ if ($1 == $2) { exit 1 }}'",
19 | "dist": "npm-run-all clean build:tsc dist:sed-version",
20 | "dist:sed-version": "sed -i.bak -e \"s/exports.version = __VERSION__/exports.version = \\\"${npm_package_version}\\\"/\" build/src/core/version.js",
21 | "lint": "npm-run-all lint:tslint lint:eslint",
22 | "lint:eslint": "grunt eslint",
23 | "lint:tslint": "tslint --project tsconfig.json",
24 | "start": "npm-run-all -p start:update-quicktests start:watch-tsc start:watch-quicktests start:webpack-dev-server",
25 | "start:update-quicktests": "grunt update-quicktests",
26 | "start:watch-quicktests": "grunt watch-quicktests",
27 | "start:watch-tsc": "tsc -w -p .",
28 | "start:webpack-dev-server": "webpack-dev-server",
29 | "test": "grunt test-local",
30 | "test:ci": "grunt test-ci"
31 | },
32 | "devDependencies": {
33 | "@types/chai": "^3.4.34",
34 | "@types/d3-selection-multi": "1.0.4",
35 | "@types/lodash": "^4.14.109",
36 | "@types/lodash-es": "^4.17.3",
37 | "@types/mocha": "^2.2.27",
38 | "@types/sinon": "^1.16.36",
39 | "awesome-typescript-loader": "^3.4.1",
40 | "chai": "2.0.0",
41 | "circle-github-bot": "^2.1.0",
42 | "grunt": "~0.4.5",
43 | "grunt-blanket-mocha": "^1.0.0",
44 | "grunt-bump": "0.7.0",
45 | "grunt-cli": "0.1.13",
46 | "grunt-contrib-connect": "0.11.2",
47 | "grunt-contrib-watch": "0.6.1",
48 | "grunt-eslint": "17.3.1",
49 | "grunt-exec": "1.0.1",
50 | "grunt-jscs": "2.6.0",
51 | "jquery": "^3.3.1",
52 | "load-grunt-tasks": "3.4.0",
53 | "mocha": "2.2.5",
54 | "npm-run-all": "4.0.1",
55 | "requirejs": "2.1.18",
56 | "sinon": "^2.1.0",
57 | "tslint": "5.18.0",
58 | "typescript": "~4.4",
59 | "webpack": "2.6.1",
60 | "webpack-dev-server": "2.11.1",
61 | "webpack-merge": "^4.1.0"
62 | },
63 | "dependencies": {
64 | "@types/d3": "^4.13.0",
65 | "@types/d3-shape": "^1.2.5",
66 | "@types/is-plain-object": "^0.0.2",
67 | "d3": "^4.13.0",
68 | "d3-ease": "^1.0.0",
69 | "d3-shape": "^1.0.0",
70 | "is-plain-object": "^2.0.4",
71 | "lodash-es": "^4.17.15",
72 | "tslib": "~2.3.1",
73 | "typesettable": "4.1.0"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/quicktests/color/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Plottable Color Quick Test
14 |
15 |
16 |
17 |
18 |
19 |
20 |
Test different color schemes with Plottable plots!
21 |
Locally change default plottable colors in plottable.css
22 |
Enter a number of series to render in SVGs of specified width and height
23 |
Control what plots to hide/show using the sidebar
24 |
25 |
26 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/quicktests/color/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: sans-serif;
4 | }
5 |
6 | svg {
7 | float: left;
8 | }
9 |
10 | .controls {
11 | background-color: #db2e65;
12 | width: 100%;
13 | height: 50px;
14 | position: fixed;
15 | text-align: center;
16 | z-index: 1;
17 | min-width: 600px;
18 | }
19 |
20 | .results {
21 | margin-top: 50px;
22 | position: relative;
23 | }
24 |
25 | input:not([type=checkbox]) {
26 | top: 10px;
27 | position: relative;
28 | border: solid 1px;
29 | border-color: white;
30 | border-radius: 5px;
31 | -moz-border-radius: 5px;
32 | width: 150px;
33 | height: 30px;
34 | font-weight: 100;
35 | font-size: 13px;
36 | text-align: center;
37 | font-family: sans-serif;
38 | }
39 |
40 | #render {
41 | background-color: white;
42 | width: 50px;
43 | }
44 |
45 | #render:hover {
46 | background-color: whitesmoke;
47 | }
48 |
49 | #render:active {
50 | background-color: white;
51 | }
52 |
53 | .content {
54 | left: 0px;
55 | margin: 0 auto;
56 | position: absolute;
57 | }
58 |
59 | .sidebar {
60 | width: 20%;
61 | height: 100%;
62 | background-color: #343434;
63 | position: fixed;
64 | visibility: hidden;
65 | color: whitesmoke;
66 | left: -20%;
67 | padding-top: 50px;
68 | }
69 |
70 | .sidebar input{
71 | margin: 10px;
72 | }
73 | .sidebar-quicktest {
74 | padding: 10px;
75 | font-family: sans-serif;
76 | font-weight: lighter;
77 | font-size: 15px;
78 | text-align: left;
79 | border-top: 1px solid #494949;
80 | }
81 |
82 | #expand-sidebar {
83 | float: left;
84 | top: 10px;
85 | color: white;
86 | margin: 10 0 0 10;
87 | font-size: 1.3rem;
88 | text-decoration: none;
89 | }
90 |
91 | #help{
92 | width: 30px;
93 | height: 30px;
94 | float: right;
95 | margin-right: 10px;
96 | }
97 |
98 | #help:hover{
99 | background-color: white;
100 | }
101 |
102 | .button{
103 | background-color: white;
104 | }
105 |
106 | .button:hover{
107 | background-color: whitesmoke;
108 | }
109 |
110 | .button:active{
111 | background-color: white;
112 | }
113 |
114 | #help-description{
115 | width: 300px;
116 | display: none;
117 | position: absolute;
118 | z-index: 2;
119 | border: 1px solid #333;
120 | background-color:#161616;
121 | border-radius:5px;
122 | padding:10px;
123 | color:#fff;
124 | font-size: 13px;
125 | font-weight: lighter;
126 | }
127 |
128 | .single-plot{
129 | display: inline-block;
130 | }
131 |
--------------------------------------------------------------------------------
/quicktests/dev/dev.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palantir/plottable/b7e04580f6ba8071ca49453ab92070f074ebc8d0/quicktests/dev/dev.css
--------------------------------------------------------------------------------
/quicktests/dev/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Plottable Quicktests
5 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | All Plottable QuickTests
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/quicktests/fiddle.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | JSFiddle Redirect
5 |
6 |
7 |
13 |
14 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/quicktests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Plottable Quicktests
5 |
32 |
33 |
34 | Plottable Quicktests
35 | Dev
36 | Colors
37 | Overlaying
38 | Max Label Width
39 |
40 |
--------------------------------------------------------------------------------
/quicktests/overlaying/data/baseball.csv:
--------------------------------------------------------------------------------
1 | season,low,high,average,tigers
2 | 1985,04.61,014.81,10.08,010.35
3 | 1986,05.96,018.49,11.84,012.34
4 | 1987,00.88,017.10,10.48,012.12
5 | 1988,05.34,019.44,11.56,012.87
6 | 1989,07.27,021.07,13.85,015.15
7 | 1990,09.49,023.26,17.07,017.59
8 | 1991,10.73,037.00,23.58,023.84
9 | 1992,09.37,044.79,30.98,027.32
10 | 1993,10.35,047.28,32.21,038.15
11 | 1994,14.92,049.38,33.14,041.45
12 | 1995,12.36,050.59,33.98,037.04
13 | 1996,16.26,054.49,34.18,023.44
14 | 1997,10.77,062.24,40.26,017.27
15 | 1998,10.64,072.36,42.61,024.07
16 | 1999,17.90,086.73,49.81,036.49
17 | 2000,16.52,092.34,55.54,058.27
18 | 2001,24.13,112.29,65.36,053.42
19 | 2002,34.38,125.93,67.47,055.05
20 | 2003,19.63,152.75,70.94,049.17
21 | 2004,27.53,184.19,69.02,046.83
22 | 2005,29.68,208.31,72.96,069.09
23 | 2006,15.00,194.66,77.41,082.61
24 | 2007,24.12,189.26,82.56,094.80
25 | 2008,21.81,207.90,89.50,137.69
26 | 2009,36.83,201.45,88.84,115.09
27 | 2010,34.94,206.33,90.71,122.86
28 |
--------------------------------------------------------------------------------
/quicktests/overlaying/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Overlaying Plottable QuickTests
12 |
13 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
42 |
43 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
Basic: Quicktests That Show Basic Components & Basic Plots under Different Scales
58 |
Animation: Single Plots with Animations
59 |
Interaction: Single Plots with Interactions
60 |
Functional: Quicktests that Showcase Specific Functionalities (ex. TickGenerators, Formatters)
61 |
Realistic: Quicktests that Demonstrate Realistic Usages
62 |
63 |
Hotkeys:
64 |
1 - Show only the first branch
65 |
2 - Show only the second branch
66 |
3 - Show both overlaying on each other
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/animations/animate_area.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | var data = makeRandomData(20);
5 | data[0].y = NaN;
6 | data[13].x = undefined;
7 | return data;
8 | }
9 |
10 | function run(svg, data, Plottable) {
11 | "use strict";
12 |
13 | var doAnimate = true;
14 |
15 | var xScale = new Plottable.Scales.Linear();
16 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
17 |
18 | var yScale = new Plottable.Scales.Linear();
19 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
20 |
21 | var dataset = new Plottable.Dataset(data);
22 | var areaRenderer = new Plottable.Plots.Area()
23 | .addDataset(dataset)
24 | .attr("opacity", 0.75)
25 | .x(function(d) { return d.x; }, xScale)
26 | .y(function(d) { return d.y; }, yScale)
27 | .animated(doAnimate);
28 |
29 | var areaChart = new Plottable.Components.Table([[yAxis, areaRenderer],
30 | [null, xAxis]]);
31 |
32 | areaChart.renderTo(svg);
33 |
34 | var cb = function(){
35 | var d = dataset.data();
36 | dataset.data(d);
37 | };
38 |
39 | new Plottable.Interactions.Click().onClick(cb).attachTo(areaRenderer);
40 | }
41 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/animations/animate_horizontalBar.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return makeRandomData(6);
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 |
10 | var doAnimate = true;
11 |
12 | var xScale = new Plottable.Scales.Linear();
13 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
14 |
15 | var yScale = new Plottable.Scales.Linear();
16 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
17 |
18 | var dataset = new Plottable.Dataset(data);
19 |
20 | var hBarRenderer = new Plottable.Plots.Bar("horizontal");
21 | hBarRenderer.addDataset(dataset);
22 | hBarRenderer.attr("opacity", 0.75);
23 | hBarRenderer.x(function(d) { return d.x; }, xScale);
24 | hBarRenderer.y(function(d) { return d.y; }, yScale);
25 | hBarRenderer.animated(doAnimate);
26 |
27 | var hBarChart = new Plottable.Components.Table([[yAxis, hBarRenderer],
28 | [null, xAxis]]);
29 | hBarChart.renderTo(svg);
30 |
31 | var cb = function(){
32 | var d = dataset.data();
33 | dataset.data(d);
34 | };
35 |
36 | new Plottable.Interactions.Click().onClick(cb).attachTo(hBarRenderer);
37 | }
38 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/animations/animate_line.js:
--------------------------------------------------------------------------------
1 |
2 | function makeData() {
3 | "use strict";
4 | var data = [{x: new Date("4/1/2014 00:24"), y: 4},
5 | {x: new Date("8/29/2014 00:24"), y: 6}];
6 | return data;
7 | }
8 |
9 | function run(svg, data, Plottable) {
10 | "use strict";
11 | var doAnimate = true;
12 | var xScale = new Plottable.Scales.Time();
13 | var xAxis = new Plottable.Axes.Time(xScale, "bottom");
14 |
15 | var extent = function(){ return [new Date("4/1/2014 00:24"), new Date("8/29/2014 00:24")]; };
16 | xScale.addPaddingExceptionsProvider(extent);
17 |
18 | var yScale = new Plottable.Scales.Linear();
19 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
20 |
21 | var dataset = new Plottable.Dataset(data);
22 | var lineRenderer = new Plottable.Plots.Line()
23 | .addDataset(dataset)
24 | .x(function(d) { return d.x; }, xScale)
25 | .y(function(d) { return d.y; }, yScale)
26 | .attr("opacity", 0.75)
27 | .animated(doAnimate);
28 |
29 | var lineChart = new Plottable.Components.Table([[yAxis, lineRenderer],
30 | [null, xAxis]]);
31 | lineChart.renderTo(svg);
32 |
33 | var cb = function(){
34 | var d = dataset.data();
35 | dataset.data(d);
36 | };
37 |
38 | new Plottable.Interactions.Click().onClick(cb).attachTo(lineRenderer);
39 | }
40 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/animations/animate_scatter.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return [makeRandomData(20), makeRandomData(20)];
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 |
10 | var xScale = new Plottable.Scales.Linear();
11 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
12 |
13 | var yScale = new Plottable.Scales.Linear();
14 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
15 |
16 | var d1 = new Plottable.Dataset(data[0]);
17 | var d2 = new Plottable.Dataset(data[1]);
18 |
19 | var circleRenderer = new Plottable.Plots.Scatter().addDataset(d1)
20 | .addDataset(d2)
21 | .size(16)
22 | .x(function(d) { return d.x; }, xScale)
23 | .y(function(d) { return d.y; }, yScale)
24 | .attr("opacity", 0.75)
25 | .animated(true);
26 |
27 | var circleChart = new Plottable.Components.Table([[yAxis, circleRenderer],
28 | [null, xAxis]]);
29 | circleChart.renderTo(svg);
30 |
31 | var cb = function() {
32 | var tmp = d1.data();
33 | d1.data(d2.data());
34 | d2.data(tmp);
35 | };
36 |
37 | new Plottable.Interactions.Click().onClick(cb).attachTo(circleRenderer);
38 | }
39 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/animations/animate_verticalBar.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return makeRandomData(6);
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 |
10 | var doAnimate = true;
11 |
12 | var xScale = new Plottable.Scales.Linear();
13 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
14 |
15 | var yScale = new Plottable.Scales.Linear();
16 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
17 |
18 | var dataset = new Plottable.Dataset(data);
19 | var verticalBarPlot = new Plottable.Plots.Bar("vertical")
20 | .addDataset(dataset)
21 | .x(function(d) { return d.x; }, xScale)
22 | .y(function(d) { return d.y; }, yScale)
23 | .attr("opacity", 0.75)
24 | .animated(doAnimate);
25 |
26 | var chart = new Plottable.Components.Table([[yAxis, verticalBarPlot],
27 | [null, xAxis]]);
28 |
29 | chart.renderTo(svg);
30 |
31 | var cb = function(){
32 | var d = dataset.data();
33 | dataset.data(d);
34 | };
35 |
36 | new Plottable.Interactions.Click().onClick(cb).attachTo(verticalBarPlot);
37 | }
38 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/bar_horizontal_labels.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return [
5 | { y: "none", x: 550 },
6 | { y: "government", x: 500 },
7 | { y: "contractor", x: 330 },
8 | { y: "developer (inhouse)", x: 300 },
9 | { y: "developer (outsourced)", x: 270 },
10 | { y: "corporation", x: 210 },
11 | { y: "unknown", x: 115 },
12 | { y: "retired", x: 55 },
13 | { y: "x", x: 25 },
14 | { y: "y", x: 15 },
15 | { y: "z", x: 10 },
16 | ];
17 | }
18 |
19 | function run(div, data, Plottable) {
20 | "use strict";
21 |
22 | var xScale = new Plottable.Scales.Linear();
23 | var yScale = new Plottable.Scales.Category();
24 |
25 | var dataset = new Plottable.Dataset(data);
26 | var horizontalBarPlot = new Plottable.Plots.Bar("horizontal")
27 | .addDataset(dataset)
28 | .x(function(d) { return d.x; }, xScale)
29 | .y(function(d) { return d.y; }, yScale)
30 | .labelsEnabled(true)
31 | .attr("opacity", 0.8);
32 |
33 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
34 | var yAxis = new Plottable.Axes.Category(yScale, "left");
35 |
36 | var chart = new Plottable.Components.Table([
37 | [yAxis, horizontalBarPlot],
38 | [null, xAxis]
39 | ]);
40 |
41 | chart.renderTo(div);
42 | }
43 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/basic_allPlots.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return makeRandomData(8);
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 | //Axis
10 | var xScale = new Plottable.Scales.Linear();
11 | var yScale = new Plottable.Scales.Linear();
12 |
13 | var axes = [];
14 | for(var i = 0; i < 5; i++){
15 | axes.push(new Plottable.Axes.Numeric(xScale, "bottom"));
16 | axes.push(new Plottable.Axes.Numeric(yScale, "left"));
17 | }
18 |
19 | var dataset = new Plottable.Dataset(data);
20 | //rendering
21 | var scatterPlot = new Plottable.Plots.Scatter().addDataset(dataset).x(function(d) { return d.x; }, xScale).y(function(d) { return d.y; }, yScale);
22 | var linePlot = new Plottable.Plots.Line().addDataset(dataset).x(function(d) { return d.x; }, xScale).y(function(d) { return d.y; }, yScale);
23 | var areaPlot = new Plottable.Plots.Area().addDataset(dataset).x(function(d) { return d.x; }, xScale).y(function(d) { return d.y; }, yScale);
24 | var vbarPlot = new Plottable.Plots.Bar("vertical").addDataset(dataset).x(function(d) { return d.x; }, xScale).y(function(d) { return d.y; }, yScale);
25 | var hbarPlot = new Plottable.Plots.Bar("horizontal").addDataset(dataset).x(function(d) { return d.x; }, xScale).y(function(d) { return d.y; }, yScale);
26 |
27 | //title + legend
28 |
29 | var scatterTable = new Plottable.Components.Table([[axes[1], scatterPlot],
30 | [null, axes[0]]]);
31 | var lineTable = new Plottable.Components.Table([[axes[3], linePlot],
32 | [null, axes[2]]]);
33 | var areaTable = new Plottable.Components.Table([[axes[5], areaPlot],
34 | [null, axes[4]]]);
35 | var vbarTable = new Plottable.Components.Table([[axes[7], vbarPlot],
36 | [null, axes[6]]]);
37 | var hbarTable = new Plottable.Components.Table([[axes[9], hbarPlot],
38 | [null, axes[8]]]);
39 | var bigTable = new Plottable.Components.Table([[scatterTable, lineTable],
40 | [areaTable, vbarTable],
41 | [hbarTable, null]]);
42 |
43 | bigTable.renderTo(svg);
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/canvas_bar.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return Array.apply(null, Array(1)).map((_, datasetIndex) => {
5 | return Array.apply(null, Array(100 * 1000)).map((_, i) => {
6 | return {
7 | // one data point per day, offset by one hour per dataset
8 | x: new Date(i * 1000 * 3600 * 24 + datasetIndex * 1000 * 3600),
9 | y: datasetIndex + 10 + Math.random()
10 | };
11 | });
12 | });
13 | }
14 |
15 | function run(div, data, Plottable) {
16 | "use strict";
17 | var xScale = new Plottable.Scales.Time()
18 | .padProportion(0);
19 | var yScale = new Plottable.Scales.Linear();
20 | var xAxis = new Plottable.Axes.Time(xScale, "bottom");
21 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
22 | var colorScale = new Plottable.Scales.Color();
23 |
24 | const datasets = data.map((dataArray, index) => {
25 | return new Plottable.Dataset(dataArray).metadata(index);
26 | });
27 | var plot = new Plottable.Plots.Bar()
28 | .datasets(datasets)
29 | .renderer("canvas")
30 | .deferredRendering(true)
31 | .x((d) => d.x, xScale)
32 | .barEnd((d) => new Date(1000 * 3600 * 24 + d.x.valueOf()))
33 | .y((d) => d.y, yScale)
34 | .attr("gap", () => 1)
35 | .attr("fill", (d,i,ds) => ds.metadata(), colorScale);
36 |
37 | var table = new Plottable.Components.Table([
38 | [yAxis, plot],
39 | [null, xAxis]
40 | ]);
41 |
42 | const defaultEntityLabel = "Hover for nearest entity";
43 | const nearestEntityLabel = div.append("div").style("text-align", "center").text(defaultEntityLabel);
44 | new Plottable.Interactions.Pointer()
45 | .onPointerMove((p) => {
46 | const nearestEntity = plot.entityNearest(p);
47 | let text = defaultEntityLabel;
48 | if (nearestEntity != null) {
49 | const datum = nearestEntity.datum;
50 | if (datum != null) {
51 | text = `Nearest Entity: ${datum.x.toString()} ${datum.y.toFixed(2)}`;
52 | }
53 | }
54 | nearestEntityLabel.text(text);
55 | })
56 | .onPointerExit(() => {
57 | nearestEntityLabel.text(defaultEntityLabel);
58 | })
59 | .attachTo(plot);
60 |
61 | new Plottable.Interactions.PanZoom(xScale, null)
62 | .attachTo(plot);
63 |
64 | table.renderTo(div);
65 |
66 | window.addEventListener("resize", () => {
67 | table.redraw();
68 | });
69 | }
70 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/canvas_grid.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | // makes 10k points
5 | const SIDE = 100;
6 | return Array.apply(null, Array(SIDE * SIDE)).map((_, i) => ({
7 | x: Math.floor(i / SIDE).toString(),
8 | y: Math.floor(i % SIDE).toString(),
9 | val: Math.random() * 100
10 | }));
11 | }
12 |
13 | function run(div, data, Plottable) {
14 | "use strict";
15 | var xScale = new Plottable.Scales.Category();
16 | var yScale = new Plottable.Scales.Category();
17 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
18 | var yAxis = new Plottable.Axes.Category(yScale, "left");
19 |
20 | var colorScale = new Plottable.Scales.InterpolatedColor();
21 |
22 | var plot = new Plottable.Plots.Rectangle().addDataset(new Plottable.Dataset(data))
23 | .renderer("canvas")
24 | .x((d) => d.x, xScale)
25 | .y((d) => d.y, yScale)
26 | .attr("fill", (d) => d.val, colorScale);
27 |
28 | var table = new Plottable.Components.Table([
29 | [yAxis, plot],
30 | [null, xAxis]
31 | ]);
32 |
33 | new Plottable.Interactions.PanZoom(xScale, yScale)
34 | .attachTo(plot)
35 | .setMinMaxDomainValuesTo(xScale)
36 | .setMinMaxDomainValuesTo(yScale);
37 |
38 | table.renderTo(div);
39 | window.addEventListener("resize", () => {
40 | table.redraw();
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/canvas_line.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | // makes 10 datasets of 10000 points
5 | return Array.apply(null, Array(10)).map((_, datasetIndex) => {
6 | return Array.apply(null, Array(10000)).map((_, i) => {
7 | return {
8 | // one data point per day, offset by one hour per dataset
9 | x: new Date(i * 1000 * 3600 * 24 + datasetIndex * 1000 * 3600),
10 | y: datasetIndex + Math.random()
11 | };
12 | });
13 | });
14 | }
15 |
16 | function run(div, data, Plottable) {
17 | "use strict";
18 | var xScale = new Plottable.Scales.Time();
19 | var yScale = new Plottable.Scales.Linear();
20 | var xAxis = new Plottable.Axes.Time(xScale, "bottom");
21 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
22 | var colorScale = new Plottable.Scales.Color();
23 |
24 | const datasets = data.map((dataArray, index) => {
25 | return new Plottable.Dataset(dataArray).metadata(index);
26 | });
27 | var plot = new Plottable.Plots.Line().datasets(datasets)
28 | .renderer("canvas")
29 | .deferredRendering(true)
30 | .collapseDenseLinesEnabled(true)
31 | .x((d) => d.x, xScale)
32 | .y((d) => d.y, yScale)
33 | .attr("stroke", (d,i,ds) => ds.metadata(), colorScale);
34 |
35 | var table = new Plottable.Components.Table([
36 | [yAxis, plot],
37 | [null, xAxis]
38 | ]);
39 |
40 | const defaultEntityLabel = "Hover for nearest entity";
41 | const nearestEntityLabel = div.append("div").style("text-align", "center").text(defaultEntityLabel);
42 | new Plottable.Interactions.Pointer()
43 | .onPointerMove((p) => {
44 | const nearestEntity = plot.entityNearest(p);
45 | let text = defaultEntityLabel;
46 | if (nearestEntity != null) {
47 | const datum = nearestEntity.datum;
48 | if (datum != null) {
49 | text = `Nearest Entity: ${datum.x.toString()} ${datum.y.toFixed(2)}`;
50 | }
51 | }
52 | nearestEntityLabel.text(text);
53 | })
54 | .onPointerExit(() => {
55 | nearestEntityLabel.text(defaultEntityLabel);
56 | })
57 | .attachTo(plot);
58 |
59 | new Plottable.Interactions.PanZoom(xScale, null)
60 | .attachTo(plot);
61 |
62 | table.renderTo(div);
63 |
64 | window.addEventListener("resize", () => {
65 | table.redraw();
66 | });
67 | }
68 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/categoryAxis_timeAxis.js:
--------------------------------------------------------------------------------
1 |
2 | function makeData() {
3 | "use strict";
4 | return [
5 | {x: "5/2/2014", y: "category1"},
6 | {x: "2/24/2017", y: "category2"},
7 | {x: "8/8/2020", y: "category3"},
8 | {x: "1/23/2025", y: "category4"}
9 | ];
10 | }
11 |
12 | function run(svg, data, Plottable) {
13 | "use strict";
14 |
15 | var xScale = new Plottable.Scales.Time();
16 | var yScale = new Plottable.Scales.Category();
17 |
18 | var hBarPlot = new Plottable.Plots.Bar("horizontal");
19 | hBarPlot.addDataset(new Plottable.Dataset(data))
20 | .x(function (d) { return d3.timeParse("%x")(d.x); }, xScale)
21 | .y(function(d) { return d.y; }, yScale);
22 |
23 | var xAxis = new Plottable.Axes.Time(xScale, "bottom");
24 | xAxis.formatter(Plottable.Formatters.multiTime());
25 | var yAxis = new Plottable.Axes.Category(yScale, "left");
26 |
27 | var gridlines = new Plottable.Components.Gridlines(xScale, null);
28 | var renderGroup = new Plottable.Components.Group([hBarPlot, gridlines]);
29 |
30 | var chart = new Plottable.Components.Table([
31 | [yAxis, renderGroup],
32 | [null, xAxis]]);
33 |
34 | chart.renderTo(svg);
35 |
36 | new Plottable.Interactions.PanZoom(xScale, null).attachTo(hBarPlot);
37 | }
38 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/half_pies.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return [
4 | {key: "banana", value: 4},
5 | {key: "grape", value: 5},
6 | {key: "raspberry", value: 9},
7 | {key: "cherry", value: 2},
8 | {key: "peach", value: 8},
9 | {key: "apple", value: 6}
10 | ];
11 | }
12 |
13 | function run(svg, data, Plottable){
14 | "use strict";
15 |
16 | var cs = new Plottable.Scales.Color();
17 |
18 | var topPie = new Plottable.Plots.Pie();
19 | topPie.addDataset(new Plottable.Dataset(data));
20 | topPie.sectorValue(function(d){ return d.value; })
21 | .innerRadius(0)
22 | .startAngle(0)
23 | .endAngle(Math.PI / 2)
24 | .attr("opacity", .5)
25 | .attr("fill", function(d){ return d.key; }, cs);
26 |
27 | var bottomPie = new Plottable.Plots.Pie();
28 | bottomPie.addDataset(new Plottable.Dataset(data));
29 | bottomPie.sectorValue(function(d){ return d.value; })
30 | .innerRadius(0)
31 | .startAngle(3 * Math.PI / 4)
32 | .attr("fill", function(d){ return d.key; }, cs);
33 |
34 | var leftPie = new Plottable.Plots.Pie();
35 | leftPie.addDataset(new Plottable.Dataset(data));
36 | leftPie.sectorValue(function(d){ return d.value; })
37 | .innerRadius(0)
38 | .endAngle(Math.PI)
39 | .attr("opacity", .5)
40 | .attr("fill", function(d){ return d.key; }, cs);
41 |
42 | var rightPie = new Plottable.Plots.Pie();
43 | rightPie.addDataset(new Plottable.Dataset(data));
44 | rightPie.sectorValue(function(d){ return d.value; })
45 | .innerRadius(0)
46 | .startAngle(Math.PI)
47 | .attr("fill", function(d){ return d.key; }, cs);
48 |
49 | var pies = new Plottable.Components.Table([[topPie, rightPie], [leftPie, bottomPie]]);
50 | pies.renderTo(svg);
51 | }
52 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/histogram.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | const data = [];
5 | let start = 0;
6 | for (let i = 1; i < 5; i++) {
7 | const end = start + 10 + i * i;
8 | data.push({start, end, val: 100/i, category: "Experiment Group " + i});
9 | start = end;
10 | }
11 | return data;
12 | }
13 |
14 | function run(svg, data, Plottable) {
15 | "use strict";
16 |
17 | function table() {
18 | const x = new Plottable.Scales.Linear();
19 | const y = new Plottable.Scales.Linear();
20 | return {
21 | x, y,
22 | table: new Plottable.Components.Table([
23 | [new Plottable.Axes.Numeric(y, "left"), null],
24 | [null, new Plottable.Axes.Numeric(x, "bottom")],
25 | ])
26 | }
27 | }
28 |
29 | const dataset = new Plottable.Dataset(data);
30 | const align = "start";
31 |
32 | // normal vertical bar plot
33 | const vert = table();
34 | const vbarPlot = new Plottable.Plots.Bar("vertical")
35 | .addDataset(dataset)
36 | .barAlignment(align)
37 | .attr("gap", 1)
38 | .x((d) => d.start, vert.x)
39 | .y((d) => d.val, vert.y)
40 | .barEnd((d) => d.end, vert.x)
41 | .labelsEnabled(true);
42 | vert.table.add(vbarPlot, 0, 1);
43 |
44 | // horizontal bar plot
45 | const horiz = table();
46 | const hbarPlot = new Plottable.Plots.Bar("horizontal")
47 | .addDataset(dataset)
48 | .barAlignment(align)
49 | .attr("gap", 1)
50 | .x((d) => d.val, horiz.x)
51 | .y((d) => d.start, horiz.y)
52 | .barEnd((d) => d.end, horiz.y)
53 | .labelsEnabled(true);
54 | horiz.table.add(hbarPlot, 0, 1);
55 |
56 | // stacked bar plot
57 | const stack = table();
58 | const colors = new Plottable.Scales.Color().range();
59 | const stackPlot = new Plottable.Plots.StackedBar()
60 | .addDataset(new Plottable.Dataset(data, {series: 0}))
61 | .addDataset(new Plottable.Dataset(data, {series: 1}))
62 | .addDataset(new Plottable.Dataset(data, {series: 2}))
63 | .barAlignment(align)
64 | .attr("gap", 1)
65 | .attr("fill", (d, i, dataset) => colors[dataset.metadata().series])
66 | .x((d) => d.start, stack.x)
67 | .y((d) => d.val, stack.y)
68 | .barEnd((d) => d.end, stack.x)
69 | .labelsEnabled(true);
70 | stack.table.add(stackPlot, 0, 1);
71 |
72 | const layout = new Plottable.Components.Table([
73 | [vert.table],
74 | [horiz.table],
75 | [stack.table],
76 | ]);
77 | layout.renderTo(svg);
78 | }
79 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/log_scale.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | var exponent = 3;
5 | var data = [];
6 |
7 | for (var i = 0; i < 10; i++) {
8 | var x = Math.pow(3, i)/100;
9 | data.push({x: x, y: Math.pow(x, exponent)});
10 | }
11 |
12 | return data;
13 | }
14 |
15 | function run(div, data, Plottable) {
16 | "use strict";
17 |
18 | var xScale = new Plottable.Scales.Log();
19 | var yScale = new Plottable.Scales.Log();
20 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom")
21 | .formatter(Plottable.Formatters.siSuffix());
22 | var yAxis = new Plottable.Axes.Numeric(yScale, "left")
23 | .formatter(Plottable.Formatters.siSuffix());
24 |
25 | var plot = new Plottable.Plots.Scatter()
26 | .renderer("svg")
27 | .deferredRendering(true)
28 | .addDataset(new Plottable.Dataset(data))
29 | .labelsEnabled(true)
30 | .x((d) => d.x, xScale)
31 | .y((d) => d.y, yScale);
32 |
33 | var table = new Plottable.Components.Table([
34 | [yAxis, plot],
35 | [null, xAxis]
36 | ]);
37 |
38 | var panZoom = new Plottable.Interactions.PanZoom(xScale, yScale).attachTo(plot);
39 |
40 | table.renderTo(div);
41 |
42 | panZoom.setMinMaxDomainValuesTo(xScale);
43 | panZoom.setMinMaxDomainValuesTo(yScale);
44 | }
45 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/missing_clustered_bar.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | var data1 = [{name: "jon", y: 1, type: "q1"}, {name: "dan", y: 2, type: "q1"}, {name: "zoo", y: 1, type: "q1"}];
5 | var data2 = [{name: "jon", y: 2, type: "q2"}, {name: "dan", y: -4, type: "q2"}];
6 | var data3 = [{name: "dan", y: 15, type: "q3"}, {name: "zoo", y: 15, type: "q3"}];
7 | return [data1, data2, data3];
8 | }
9 |
10 | function run(svg, data, Plottable) {
11 | "use strict";
12 |
13 | var xScale = new Plottable.Scales.Category();
14 | var yScale = new Plottable.Scales.Linear();
15 | var colorScale = new Plottable.Scales.Color("10");
16 |
17 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
18 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
19 | var clusteredBarRenderer = new Plottable.Plots.ClusteredBar()
20 | .addDataset(new Plottable.Dataset(data[0]))
21 | .addDataset(new Plottable.Dataset(data[1]))
22 | .addDataset(new Plottable.Dataset(data[2]))
23 | .x(function(d) { return d.name; }, xScale)
24 | .y(function(d) { return d.y; }, yScale)
25 | .attr("fill", function(d) { return d.type; }, colorScale)
26 | .attr("type", function(d) { return d.type; })
27 | .attr("yval", function(d) { return d.y; })
28 | .labelsEnabled(true);
29 |
30 | var center = new Plottable.Components.Group([clusteredBarRenderer, new Plottable.Components.Legend(colorScale)]);
31 |
32 | new Plottable.Components.Table([
33 | [yAxis, center], [null, xAxis]
34 | ]).renderTo(svg);
35 | }
36 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/missing_stacked_area.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | var data1 = [{name: "jon", y: 1, type: "q1"}, {name: "dan", y: 2, type: "q1"}, {name: "zoo", y: 1, type: "q1"}];
5 | var data2 = [{name: "jon", y: 2, type: "q2"}, {name: "dan", y: 4, type: "q2"}];
6 | var data3 = [{name: "dan", y: 15, type: "q3"}, {name: "zoo", y: 15, type: "q3"}];
7 | return [data1, data2, data3];
8 | }
9 |
10 | function run(svg, data, Plottable) {
11 | "use strict";
12 |
13 | var xScale = new Plottable.Scales.Category();
14 | var yScale = new Plottable.Scales.Linear();
15 | var colorScale = new Plottable.Scales.Color("10");
16 |
17 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
18 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
19 | var stackedAreaPlot = new Plottable.Plots.StackedArea()
20 | .renderer("canvas")
21 | .x(function(d) { return d.name; }, xScale)
22 | .y(function(d) { return d.y; }, yScale)
23 | .attr("fill", function(d) { return d.type; }, colorScale)
24 | .attr("type", function(d) { return d.type; })
25 | .attr("yval", function(d) { return d.y; })
26 | .addDataset(new Plottable.Dataset(data[0]))
27 | .addDataset(new Plottable.Dataset(data[1]))
28 | .addDataset(new Plottable.Dataset(data[2]))
29 | .animated(true);
30 |
31 | var center = new Plottable.Components.Group([stackedAreaPlot, new Plottable.Components.Legend(colorScale)]);
32 |
33 | new Plottable.Components.Table([
34 | [yAxis, center], [null, xAxis]
35 | ]).renderTo(svg);
36 | }
37 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/modified_log_scale.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | var exponent = 3;
5 | var data = [];
6 |
7 | for (var i = 0; i < 10; i++) {
8 | var x = Math.pow(3, i)/100;
9 | data.push({x: x, y: Math.pow(x, exponent)});
10 | }
11 |
12 | return data;
13 | }
14 |
15 | function run(div, data, Plottable) {
16 | "use strict";
17 |
18 | var xScale = new Plottable.Scales.ModifiedLog();
19 | var yScale = new Plottable.Scales.ModifiedLog();
20 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
21 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
22 |
23 | var plot = new Plottable.Plots.Scatter()
24 | .renderer("svg")
25 | .deferredRendering(true)
26 | .addDataset(new Plottable.Dataset(data))
27 | .labelsEnabled(true)
28 | .x((d) => d.x, xScale)
29 | .y((d) => d.y, yScale);
30 |
31 | var table = new Plottable.Components.Table([
32 | [yAxis, plot],
33 | [null, xAxis]
34 | ]);
35 |
36 | var panZoom = new Plottable.Interactions.PanZoom(xScale, yScale).attachTo(plot);
37 |
38 | table.renderTo(div);
39 |
40 | panZoom.setMinMaxDomainValuesTo(xScale);
41 | panZoom.setMinMaxDomainValuesTo(yScale);
42 | }
43 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/non_canvas_scatter.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | // makes 1k random points
5 | return Array.apply(null, Array(1000)).map(() => ({
6 | x: Math.random(),
7 | y: Math.random(),
8 | }));
9 | }
10 |
11 | function run(div, data, Plottable) {
12 | "use strict";
13 |
14 | var xScale = new Plottable.Scales.Linear();
15 | var yScale = new Plottable.Scales.Linear();
16 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
17 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
18 |
19 | var plot = new Plottable.Plots.Scatter().addDataset(new Plottable.Dataset(data))
20 | .x((d) => d.x, xScale)
21 | .y((d) => d.y, yScale)
22 | .size(() => 20)
23 | .symbol(() => new Plottable.SymbolFactories.cross());
24 |
25 | var table = new Plottable.Components.Table([
26 | [yAxis, plot],
27 | [null, xAxis]
28 | ]);
29 |
30 | new Plottable.Interactions.PanZoom(xScale, yScale)
31 | .attachTo(plot)
32 | .setMinMaxDomainValuesTo(xScale)
33 | .setMinMaxDomainValuesTo(yScale);
34 |
35 | table.renderTo(div);
36 | window.addEventListener("resize", () => {
37 | table.redraw();
38 | });
39 | }
40 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/pies.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | var inner = [
4 | {key: "banana", value: 4},
5 | {key: "grape", value: 5},
6 | {key: "raspberry", value: 9},
7 | {key: "cherry", value: 2},
8 | {key: "peach", value: 8},
9 | {key: "apple", value: 6}
10 | ];
11 |
12 | var outer = [
13 | {key: "engine", value: 4},
14 | {key: "post-it note", value: 5},
15 | {key: "sunflower", value: 9},
16 | {key: "highlighter", value: 2}
17 | ];
18 |
19 | return [inner, outer];
20 | }
21 |
22 | function run(svg, data, Plottable){
23 | "use strict";
24 |
25 | var cs = new Plottable.Scales.Color();
26 |
27 | var innerPie = new Plottable.Plots.Pie();
28 | innerPie.addDataset(new Plottable.Dataset(data[0]));
29 | innerPie.sectorValue(function(d){ return d.value; })
30 | .innerRadius(0)
31 | .outerRadius(100)
32 | .labelsEnabled(true)
33 | .attr("opacity", .5)
34 | .attr("fill", function(d){ return d.key; }, cs);
35 |
36 | var outerPie = new Plottable.Plots.Pie();
37 | outerPie.addDataset(new Plottable.Dataset(data[1]));
38 | outerPie.sectorValue(function(d){ return d.value; })
39 | .innerRadius(100)
40 | .outerRadius(200)
41 | .labelsEnabled(true)
42 | .labelFormatter(function(v, datum){return datum.key + ": " + v; })
43 | .attr("fill", function(d){ return d.key; }, cs);
44 |
45 | var pies = new Plottable.Components.Group([innerPie, outerPie]);
46 | pies.renderTo(svg);
47 |
48 | new Plottable.Interactions.Pointer()
49 | .onPointerMove(function(p){
50 | innerPie.entities().forEach(function(e){
51 | e.selection.attr("opacity", .5);
52 | });
53 | var entity = innerPie.entitiesAt(p)[0];
54 | if(entity){
55 | entity.selection.attr("opacity", 1);
56 | }
57 | })
58 | .attachTo(innerPie);
59 | }
60 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/scatter_labels.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | var data = [
5 | {
6 | x: 10,
7 | y: 10,
8 | label: "these",
9 | size: 100
10 | },
11 | {
12 | x: 15,
13 | y: 30,
14 | label: "Label on bubble",
15 | size: 30
16 | },
17 | {
18 | x: 20,
19 | y: 40,
20 | label: "Label off bubble",
21 | size: 10
22 | },
23 | {
24 | x: 20,
25 | y: 20,
26 | label: "are",
27 | size: 150
28 | },
29 | {
30 | x: 30,
31 | y: 30,
32 | label: "scatter",
33 | size: 200
34 | },
35 | {
36 | x: 40,
37 | y: 40,
38 | label: "plot",
39 | size: 300
40 | },
41 | {
42 | x: 50,
43 | y: 50,
44 | label: "labels",
45 | size: 150
46 | }
47 | ];
48 |
49 | return data;
50 | }
51 |
52 | function run(div, data, Plottable) {
53 | "use strict";
54 |
55 | var xScale = new Plottable.Scales.Linear();
56 | var yScale = new Plottable.Scales.Linear();
57 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
58 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
59 |
60 | var plot = new Plottable.Plots.Scatter()
61 | .renderer("svg")
62 | .deferredRendering(true)
63 | .addDataset(new Plottable.Dataset(data))
64 | .labelsEnabled(true)
65 | .x((d) => d.x, xScale)
66 | .y((d) => d.y, yScale)
67 | .size((d) => d.size);
68 |
69 | var table = new Plottable.Components.Table([
70 | [yAxis, plot],
71 | [null, xAxis]
72 | ]);
73 |
74 | var panZoom = new Plottable.Interactions.PanZoom(xScale, yScale).attachTo(plot);
75 |
76 | table.renderTo(div);
77 |
78 | panZoom.setMinMaxDomainValuesTo(xScale);
79 | panZoom.setMinMaxDomainValuesTo(yScale);
80 | }
81 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/stacked_area_with_scatterplot.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | var data1 = [{x: 1, y: 5, type: "q1"}, {x: 2, y: 2, type: "q1"}, {x: 3, y: 4, type: "q1"}, {x: 4, y: 2, type: "q1"}];
5 | var data2 = [{x: 1, y: 4, type: "q2"}, {x: 2, y: 3, type: "q2"}, {x: 3, y: 3, type: "q2"}, {x: 4, y: 1, type: "q2"}];
6 | return [data1, data2];
7 | }
8 |
9 | function run(svg, data, Plottable) {
10 | "use strict";
11 |
12 | var xScale = new Plottable.Scales.Category();
13 | var yScale = new Plottable.Scales.Linear();
14 | var colorScale = new Plottable.Scales.Color("10");
15 |
16 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
17 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
18 |
19 | var dataset1 = new Plottable.Dataset(data[0]);
20 | var dataset2 = new Plottable.Dataset(data[1])
21 |
22 | var stackedAreaPlot = new Plottable.Plots.StackedArea()
23 | .renderer("canvas")
24 | .x(function(d) { return d.x; }, xScale)
25 | .y(function(d) { return d.y; }, yScale)
26 | .attr("fill", function(d) { return d.type; }, colorScale)
27 | .attr("stroke", function(d) { return d.type; }, colorScale)
28 | .addDataset(dataset1)
29 | .addDataset(dataset2);
30 | var scatterPlot = new Plottable.Plots.Scatter()
31 | .renderer("canvas")
32 | .size(10)
33 | .x(function(d) { return d.x; }, xScale)
34 | .y(function(d, index, dataset) {
35 | return stackedAreaPlot.yOffset(dataset, d.x) + d.y;
36 | }, yScale)
37 | .attr("fill", function(d) { return d.type; }, colorScale)
38 | .addDataset(dataset1)
39 | .addDataset(dataset2);
40 |
41 | var center = new Plottable.Components.Group([stackedAreaPlot, scatterPlot, new Plottable.Components.Legend(colorScale)]);
42 |
43 | new Plottable.Components.Table([
44 | [yAxis, center], [null, xAxis]
45 | ]).renderTo(svg);
46 | }
47 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/waterfall.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | var makeWaterfallData = function(cycles, startTotal){
4 | var data = [];
5 | if(startTotal){
6 | data.push({
7 | x: "start",
8 | y: startTotal,
9 | type: "total"
10 | });
11 | }
12 | var total = startTotal || 0;
13 | for( var i = 0; i < cycles; i++){
14 | var deltaPos = Math.random() * 10;
15 | var deltaNeg = Math.random() * -5;
16 | total = total + deltaPos + deltaNeg;
17 | data.push({
18 | x: i.toString() + " N",
19 | y: deltaNeg,
20 | type: "delta"
21 | });
22 | data.push({
23 | x: i.toString() + " P",
24 | y: deltaPos,
25 | type: "delta"
26 | });
27 | data.push({
28 | x: i.toString() + " T",
29 | y: total,
30 | type: "total"
31 | });
32 | }
33 | return data;
34 | };
35 | return makeWaterfallData(5, 3);
36 | }
37 |
38 | function run(svg, data, Plottable) {
39 | "use strict";
40 | var xScale = new Plottable.Scales.Category();
41 | var yScale = new Plottable.Scales.Linear();
42 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
43 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
44 |
45 | var waterfall = new Plottable.Plots.Waterfall();
46 | waterfall.x(function(d) { return d.x; }, xScale);
47 | waterfall.y(function(d) { return d.y; }, yScale);
48 | waterfall.total(function(d) { return d.type === "total" ? true : false; });
49 | waterfall.connectorsEnabled(true);
50 | waterfall.baselineValue(0);
51 | waterfall.attr("fill", function(d){
52 | if(d.type === "total"){
53 | return "#abbabb";
54 | }
55 | else if (d.y > 0){
56 | return "#09cd2e";
57 | }
58 | else{
59 | return "#de345c";
60 | }
61 | });
62 | waterfall.addDataset(new Plottable.Dataset(data));
63 |
64 | new Plottable.Components.Table([
65 | [yAxis, waterfall],
66 | [null, xAxis]
67 | ]).renderTo(svg);
68 | }
69 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/basic/wrapped_label.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return [
5 | { y: "none", x: 550 },
6 | { y: "government", x: 500 },
7 | { y: "contractor", x: 330 },
8 | { y: "developer (inhouse)", x: 300 },
9 | { y: "developer (outsourced)", x: 270 },
10 | { y: "corporation", x: 210 },
11 | { y: "unknown", x: 115 },
12 | { y: "retired", x: 55 },
13 | { y: "x", x: 25 },
14 | { y: "y", x: 15 },
15 | { y: "z", x: 10 },
16 | ];
17 | }
18 |
19 | function run(div, data, Plottable) {
20 | "use strict";
21 |
22 | var xScale = new Plottable.Scales.Linear();
23 | var yScale = new Plottable.Scales.Category();
24 |
25 | var dataset = new Plottable.Dataset(data);
26 | var horizontalBarPlot = new Plottable.Plots.Bar("horizontal")
27 | .addDataset(dataset)
28 | .x(function(d) { return d.x; }, xScale)
29 | .y(function(d) { return d.y; }, yScale)
30 | .labelsEnabled(true)
31 | .attr("opacity", 0.8);
32 |
33 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
34 | var yAxis = new Plottable.Axes.Category(yScale, "left");
35 |
36 | var longString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin non pretium diam. Sed dolor turpis, maximus sit amet bibendum vel, elementum eu urna. Nam nunc ligula, placerat non consequat nec, mollis eu velit. Morbi odio sapien, posuere ut hendrerit at, hendrerit vitae nulla. Donec fringilla, felis sed vehicula viverra, dui lectus commodo dolor, non viverra nisl tellus vitae orci. Donec pharetra mauris enim, a porttitor augue bibendum vitae. Maecenas magna risus, tempus eu dapibus a, eleifend ac orci. Nam iaculis scelerisque velit non congue. Nullam sodales augue vel erat mattis, at volutpat eros tristique. Nam varius mattis lectus, ut eleifend velit ullamcorper eget.";
37 | // var label = new Plottable.Components.Label(longString);
38 | var botLabel = new Plottable.Components.WrappedLabel(longString).maxLines(4);
39 | var leftLabel = new Plottable.Components.WrappedLabel(longString).angle(-90).maxLines(2);
40 | var rightLabel = new Plottable.Components.WrappedLabel(longString).angle(90).maxLines(2);
41 |
42 | var chart = new Plottable.Components.Table([
43 | [leftLabel, yAxis, horizontalBarPlot, rightLabel],
44 | [null, null, xAxis],
45 | [null, null, botLabel],
46 | ]);
47 |
48 | chart.renderTo(div);
49 | }
50 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/functional/axisTickLabelDataOnElement.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | var data1 = [{month: "January", avg: 0.75, city: "Palo Alto"}, {month: "February", avg: 3.07, city: "Palo Alto"}, {month: "March", avg: 2.26, city: "Palo Alto"}, {month: "April", avg: 0.98, city: "Palo Alto"}];
5 | var data2 = [{month: "January", avg: 4.21, city: "San Francisco"}, {month: "February", avg: 4.10, city: "San Francisco"}, {month: "March", avg: 2.74, city: "San Francisco"}, {month: "April", avg: 1.18, city: "San Francisco"}];
6 | var data3 = [{month: "January", avg: 2.99, city: "San Jose"}, {month: "February", avg: 3.32, city: "San Jose"}, {month: "March", avg: 2.04, city: "San Jose"}, {month: "April", avg: 1.06, city: "San Jose"}];
7 |
8 | return [data1, data2, data3];
9 | }
10 |
11 | function run(svg, data, Plottable){
12 | "use strict";
13 |
14 | var xScale = new Plottable.Scales.Category();
15 | var yScale = new Plottable.Scales.Linear();
16 | var colorScale = new Plottable.Scales.Color();
17 |
18 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
19 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
20 |
21 | var clusteredPlot = new Plottable.Plots.ClusteredBar("vertical")
22 | .addDataset(new Plottable.Dataset(data[0]))
23 | .addDataset(new Plottable.Dataset(data[1]))
24 | .addDataset(new Plottable.Dataset(data[2]))
25 | .x(function(d) { return d.month; }, xScale)
26 | .y(function(d) { return d.avg; }, yScale)
27 | .attr("label", function(d) { return d.avg; })
28 | .attr("fill", function(d) { return d.city; }, colorScale);
29 |
30 | var title = new Plottable.Components.TitleLabel("Click on a axis label");
31 |
32 | var chart = new Plottable.Components.Table([
33 | [null, title],
34 | [yAxis, clusteredPlot],
35 | [null, xAxis]
36 | ]);
37 |
38 | [xAxis, yAxis].forEach((axis) => {
39 | var clickInteraction = new Plottable.Interactions.Click();
40 | clickInteraction.onClick((point, event) => {
41 | const label = JSON.stringify(axis.tickLabelDataOnElement(event.target));
42 | title.text(label ? label : "no label");
43 | });
44 | clickInteraction.attachTo(axis);
45 | });
46 |
47 | new Plottable.Interactions.PanZoom(xScale).attachTo(clusteredPlot);
48 |
49 | chart.renderTo(svg);
50 | }
51 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/functional/base_animator.js:
--------------------------------------------------------------------------------
1 |
2 | function makeData() {
3 | "use strict";
4 |
5 | var data1 = [{x: "0", y: 0}, {x: "1", y: 1}, {x: "2", y: 1}, {x: "3", y: 2}, {x: "4", y: 3}, {x: "5", y: 4}, {x: "6", y: 5}, {x: "7", y: -2}];
6 |
7 | return data1;
8 | }
9 |
10 | function run(svg, data, Plottable) {
11 | "use strict";
12 |
13 | var xScale = new Plottable.Scales.Category();
14 | var yScale = new Plottable.Scales.Linear();
15 | var colorScale = new Plottable.Scales.Color();
16 |
17 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
18 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
19 | var animator;
20 | if (Plottable.Animators.Base === undefined) {
21 | animator = new Plottable.Animators.Easing();
22 | animator.stepDuration(1000);
23 | animator.maxTotalDuration(2000);
24 | animator.stepDelay(100);
25 | } else {
26 | animator = new Plottable.Animators.Base();
27 | animator.stepDuration(1000);
28 | animator.maxTotalDuration(2000);
29 | animator.iterativeDelay(100);
30 | }
31 |
32 | var vbar = new Plottable.Plots.Bar()
33 | .x(function(d) { return d.x; }, xScale)
34 | .y(function(d) { return d.y; }, yScale)
35 | .attr("fill", function(d) { return d.type; }, colorScale)
36 | .labelsEnabled(true)
37 | .addDataset(new Plottable.Dataset(data))
38 | .animator(Plottable.Plots.Animator.MAIN, animator)
39 | .animated(true);
40 | if (typeof vbar.labelsFormatter === "function") {
41 | vbar.labelsFormatter(function(text){return text + "!"; });
42 | } else {
43 | vbar.labelFormatter(function(text){return text + "!"; });
44 | }
45 |
46 | var chart = new Plottable.Components.Table([
47 | [yAxis, vbar],
48 | [null, xAxis]
49 | ]);
50 |
51 | var cb = function(){
52 | vbar.datasets()[0].data(data);
53 | };
54 | var click = new Plottable.Interactions.Click().onClick(cb);
55 |
56 | click.attachTo(vbar);
57 |
58 | chart.renderTo(svg);
59 | }
60 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/functional/categoryFormatter.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return [makeRandomData(50), makeRandomData(50)];
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 |
10 | data = [{x: "0", y: 1}, {x: "1", y: 2}, {x: "2", y: 4}, {x: "3", y: 6}, {x: "4", y: 5}, {x: "5", y: 3}, {x: "6", y: 0.5}];
11 | var DOW = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
12 | var Emp = ["Justin", "Cassie", "Brandon", "Roger", "Dan", "Lewin", "Brian"];
13 |
14 | var xScale = new Plottable.Scales.Category();
15 | var yScale = new Plottable.Scales.Linear();
16 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
17 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
18 |
19 | var IdTitle = new Plottable.Components.Label("Identity");
20 | var DowTitle = new Plottable.Components.Label("Day of Week");
21 | var EmpIDTitle = new Plottable.Components.Label("Emp ID");
22 |
23 | var DOWFormatter = function(d) {
24 | return DOW[d % 7];
25 | };
26 | var EmpIDFormatter = function(d) {
27 | return Emp[d % 7];
28 | };
29 |
30 | var plot = new Plottable.Plots.Bar().addDataset(new Plottable.Dataset(data));
31 | plot.x(function(d) { return d.x; }, xScale).y(function(d) { return d.y; }, yScale);
32 | var basicTable = new Plottable.Components.Table([[yAxis, plot], [null, xAxis]]);
33 | var formatChoices = new Plottable.Components.Table([[IdTitle], [DowTitle], [EmpIDTitle]]);
34 | var bigTable = new Plottable.Components.Table([[basicTable], [formatChoices]]);
35 | formatChoices.xAlignment("center");
36 |
37 | bigTable.renderTo(svg);
38 |
39 | function useIdentityFormatter() {
40 | xAxis.formatter(Plottable.Formatters.identity());
41 | }
42 | function useDOWFormatter() {
43 | xAxis.formatter(DOWFormatter);
44 | }
45 | function useEmpIdFormatter() {
46 | xAxis.formatter(EmpIDFormatter);
47 | }
48 |
49 | new Plottable.Interactions.Click().onClick(useIdentityFormatter).attachTo(IdTitle);
50 | new Plottable.Interactions.Click().onClick(useDOWFormatter).attachTo(DowTitle);
51 | new Plottable.Interactions.Click().onClick(useEmpIdFormatter).attachTo(EmpIDTitle);
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/functional/category_axis_rotated_ticks.js:
--------------------------------------------------------------------------------
1 |
2 | function makeData() {
3 | "use strict";
4 |
5 | var data = [{x: "Jan 2015", y: 0}, {x: "Jan 2016", y: 0}, {x: "Jan 2017", y: 0}, {x: "Jan 2018", y: 0}];
6 |
7 | return data;
8 | }
9 |
10 | function run(svg, data, Plottable) {
11 | "use strict";
12 |
13 | var xScale = new Plottable.Scales.Category();
14 | var yScale = new Plottable.Scales.Linear();
15 | var colorScale = new Plottable.Scales.Color();
16 |
17 | var yAxis1 = new Plottable.Axes.Numeric(yScale, "left");
18 | var xAxis1 = new Plottable.Axes.Category(xScale, "bottom");
19 | xAxis1.tickLabelAngle(-90);
20 |
21 | var yAxis2 = new Plottable.Axes.Numeric(yScale, "left");
22 | var xAxis2 = new Plottable.Axes.Category(xScale, "bottom");
23 | xAxis2.tickLabelAngle(90);
24 |
25 | var yAxis3 = new Plottable.Axes.Numeric(yScale, "left");
26 | var xAxis3 = new Plottable.Axes.Category(xScale, "bottom");
27 | xAxis3.tickLabelAngle(0);
28 |
29 | var dataset = new Plottable.Dataset(data);
30 |
31 | var plot1 = new Plottable.Plots.Scatter()
32 | .x(function(d) { return d.x; }, xScale)
33 | .y(function(d) { return d.y; }, yScale)
34 | .attr("fill", function(d) { return d.type; }, colorScale)
35 | .addDataset(dataset);
36 |
37 | var plot2 = new Plottable.Plots.Scatter()
38 | .x(function(d) { return d.x; }, xScale)
39 | .y(function(d) { return d.y; }, yScale)
40 | .attr("fill", function(d) { return d.type; }, colorScale)
41 | .addDataset(dataset);
42 |
43 | var plot3 = new Plottable.Plots.Scatter()
44 | .x(function(d) { return d.x; }, xScale)
45 | .y(function(d) { return d.y; }, yScale)
46 | .attr("fill", function(d) { return d.type; }, colorScale)
47 | .addDataset(dataset);
48 |
49 | var chart1 = new Plottable.Components.Table([
50 | [yAxis1, plot1],
51 | [null, xAxis1]
52 | ]);
53 |
54 | var chart2 = new Plottable.Components.Table([
55 | [yAxis2, plot2],
56 | [null, xAxis2]
57 | ]);
58 |
59 | var chart3 = new Plottable.Components.Table([
60 | [yAxis3, plot3],
61 | [null, xAxis3]
62 | ]);
63 |
64 | var chart = new Plottable.Components.Table([
65 | [chart1],
66 | [chart2],
67 | [chart3]
68 | ]);
69 |
70 | chart.renderTo(svg);
71 | }
72 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/functional/doubleAxes.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return makeRandomData(6);
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 |
10 | var ds1 = new Plottable.Dataset([{x: "200", y: 1}, {x: "250", y: 2}, {x: "400", y: 3}]);
11 | var ds2 = new Plottable.Dataset([{x: "200", y: 4}, {x: "300", y: 2}, {x: "400", y: 1}]);
12 |
13 | var xScale1 = new Plottable.Scales.Category();
14 | var xScale2 = new Plottable.Scales.Category();
15 | var yScale = new Plottable.Scales.Linear();
16 |
17 | var plot1 = new Plottable.Plots.Area();
18 | plot1.addDataset(ds1);
19 | plot1.x(function(d) { return d.x; }, xScale1).y(function(d) { return d.y; }, yScale);
20 |
21 | var plot2 = new Plottable.Plots.Line();
22 | plot2.addDataset(ds2);
23 | plot2.x(function(d) { return d.x; }, xScale2).y(function(d) { return d.y; }, yScale);
24 |
25 | var plots = new Plottable.Components.Group([plot1, plot2]);
26 |
27 | var xAxis1 = new Plottable.Axes.Category(xScale1, "bottom");
28 | var xAxis2 = new Plottable.Axes.Category(xScale2, "bottom");
29 |
30 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
31 | var xAxes = new Plottable.Components.Table([[xAxis1],
32 | [new Plottable.Components.Label("")],
33 | [xAxis2],
34 | [new Plottable.Components.Label("")]]);
35 |
36 | var chart = new Plottable.Components.Table([
37 | [yAxis, plots],
38 | [null, xAxes]
39 | ]);
40 |
41 | chart.renderTo(svg);
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/functional/numeric_axis_label_font_size.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return makeRandomData(8);
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 |
10 | const slider = $('');
11 | const indicator = $("axis.tickLabelFontSize(12)
");
12 | $(svg.node()).parent().prepend(slider);
13 | $(svg.node()).parent().prepend(indicator);
14 |
15 | const xScale = new Plottable.Scales.Linear();
16 | const xAxisTop = new Plottable.Axes.Numeric(xScale, "top")
17 | .tickLabelFontSize(12)
18 | .margin(50);
19 | const xAxisBottom = new Plottable.Axes.Numeric(xScale, "bottom")
20 | .tickLabelFontSize(12)
21 | .margin(50);
22 | const yScale = new Plottable.Scales.Linear();
23 | const yAxisLeft = new Plottable.Axes.Numeric(yScale, "left")
24 | .tickLabelFontSize(12)
25 | .margin(50);
26 | const yAxisRight = new Plottable.Axes.Numeric(yScale, "right")
27 | .tickLabelFontSize(12)
28 | .margin(50);
29 |
30 | const dataset = new Plottable.Dataset(data);
31 | const plot = new Plottable.Plots.Scatter()
32 | .addDataset(dataset)
33 | .x(function(d) { return d.x; }, xScale)
34 | .y(function(d) { return d.y; }, yScale);
35 | new Plottable.Interactions.PanZoom(xScale, yScale).attachTo(plot);
36 |
37 | slider.on("input", function() {
38 | indicator.text("axis.tickLabelFontSize(" + this.value + ")");
39 | xAxisTop.tickLabelFontSize(this.valueAsNumber);
40 | xAxisBottom.tickLabelFontSize(this.valueAsNumber);
41 | yAxisLeft.tickLabelFontSize(this.valueAsNumber);
42 | yAxisRight.tickLabelFontSize(this.valueAsNumber);
43 | });
44 |
45 | const table = new Plottable.Components.Table([
46 | [null, xAxisTop, null],
47 | [yAxisLeft, plot, yAxisRight],
48 | [null, xAxisBottom, null],
49 | ]);
50 | table.renderTo(svg);
51 | }
52 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/functional/scatter_plot_label_font_size.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return [
5 | { x: 0, y: 1, label: "Cat" },
6 | { x: 1, y: 4, label: "Dog" },
7 | { x: -3, y: 3, label: "Rattlesnake" },
8 | { x: 2, y: 9, label: "A multi-word label" },
9 | ];
10 | }
11 |
12 | function run(svg, data, Plottable) {
13 | "use strict";
14 |
15 | const slider = $('');
16 | const indicator = $("axis.tickLabelFontSize(12)
");
17 | $(svg.node()).parent().prepend(slider);
18 | $(svg.node()).parent().prepend(indicator);
19 |
20 | const xScale = new Plottable.Scales.Linear();
21 | const yScale = new Plottable.Scales.Linear();
22 | var dataset = new Plottable.Dataset(data);
23 | const plot = new Plottable.Plots.Scatter()
24 | .addDataset(dataset)
25 | .x((d) => d.x, xScale)
26 | .y((d) => d.y, yScale)
27 | .size(50)
28 | .labelsEnabled(true)
29 | .labelFontSize(12);
30 | new Plottable.Interactions.PanZoom(xScale, yScale).attachTo(plot);
31 |
32 | slider.on("input", function() {
33 | indicator.text("axis.tickLabelFontSize(" + this.value + ")");
34 | plot.labelFontSize(this.valueAsNumber);
35 | });
36 |
37 | const table = new Plottable.Components.Table([
38 | [plot],
39 | ]);
40 | table.renderTo(svg);
41 | }
42 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/functional/time_axis_label_font_size.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return [
5 | {x: new Date("4/1/2021 05:00"), y: 10},
6 | {x: new Date("7/4/2021 20:00"), y: 94},
7 | {x: new Date("10/31/2021 19:00"), y: 55},
8 | {x: new Date("12/25/2021 21:30"), y: 55},
9 | ];
10 | }
11 |
12 | function run(svg, data, Plottable) {
13 | "use strict";
14 |
15 | const slider = $('');
16 | const indicator = $("axis.tickLabelFontSize(12)
");
17 | $(svg.node()).parent().prepend(slider);
18 | $(svg.node()).parent().prepend(indicator);
19 |
20 | const xScale = new Plottable.Scales.Time()
21 | .domain([
22 | // new Date(Math.min.apply(...data.map((point) => point.x.getTime()))),
23 | // new Date(Math.max.apply(...data.map((point) => point.x.getTime()))),
24 | new Date("4/1/2021 05:00"), new Date("12/25/2021 21:30")
25 | ]);
26 | const xAxisTop = new Plottable.Axes.Time(xScale, "top")
27 | .tickLabelFontSize(12)
28 | .margin(50);
29 | const xAxisBottom = new Plottable.Axes.Time(xScale, "bottom")
30 | .tickLabelFontSize(12)
31 | .margin(50);
32 | const yScale = new Plottable.Scales.Linear();
33 |
34 | const dataset = new Plottable.Dataset(data);
35 | const plot = new Plottable.Plots.Line()
36 | .addDataset(dataset)
37 | .x(function(d) { return d.x; }, xScale)
38 | .y(function(d) { return d.y; }, yScale);
39 | new Plottable.Interactions.PanZoom(xScale).attachTo(plot);
40 |
41 | slider.on("input", function() {
42 | indicator.text("axis.tickLabelFontSize(" + this.value + ")");
43 | xAxisTop.tickLabelFontSize(this.valueAsNumber);
44 | xAxisBottom.tickLabelFontSize(this.valueAsNumber);
45 | });
46 |
47 | const table = new Plottable.Components.Table([
48 | [null, xAxisTop],
49 | [null, plot],
50 | [null, xAxisBottom],
51 | ]);
52 | table.renderTo(svg);
53 | }
54 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/barHover.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return [{name: "Frodo", y: 3}, {name: "Sam", y: 2}, {name: "Gollum", y: 4}];
4 | }
5 |
6 | function run(svg, data, Plottable) {
7 | "use strict";
8 |
9 | var xScale = new Plottable.Scales.Category();
10 | var yScale = new Plottable.Scales.Linear();
11 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
12 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
13 | var title = new Plottable.Components.TitleLabel("Hover over bars");
14 | var colorScale = new Plottable.Scales.Color();
15 |
16 | var ds = new Plottable.Dataset(data, { foo: "!" });
17 |
18 | var plot = new Plottable.Plots.Bar("vertical")
19 | .addDataset(ds)
20 | .x(function (d, i, dataset) { return d.name + dataset.metadata().foo; }, xScale)
21 | .y(function(d) { return d.y; }, yScale)
22 | .attr("fill", function(d) { return d.name; }, colorScale);
23 |
24 | var chart = new Plottable.Components.Table([
25 | [null, title],
26 | [yAxis, plot],
27 | [null, xAxis]]);
28 |
29 | chart.renderTo(svg);
30 |
31 | var pointer = new Plottable.Interactions.Pointer();
32 | pointer.onPointerMove(function(p) {
33 | var datum;
34 | if (typeof plot.entityNearest === "function") {
35 | var nearestEntity = plot.entityNearest(p);
36 | datum = nearestEntity != null ? nearestEntity.datum : null;
37 | } else {
38 | var cpd = plot.getClosestPlotData(p);
39 | datum = cpd.data.length > 0 ? cpd.data[0] : null;
40 | }
41 | if (datum != null) {
42 | title.text("" + datum.name);
43 | } else {
44 | title.text("Who?");
45 | }
46 | });
47 | pointer.onPointerExit(function() { title.text("Who?"); });
48 | pointer.attachTo(plot);
49 | }
50 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/barHover_canvas.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return [{name: "Frodo", y: 3}, {name: "Sam", y: 2}, {name: "Gollum", y: 4}];
4 | }
5 |
6 | function run(div, data, Plottable) {
7 | "use strict";
8 |
9 | var xScale = new Plottable.Scales.Category();
10 | var yScale = new Plottable.Scales.Linear();
11 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
12 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
13 | var title = new Plottable.Components.TitleLabel("Hover over bars");
14 | var colorScale = new Plottable.Scales.Color();
15 |
16 | var ds = new Plottable.Dataset(data, { foo: "!" });
17 |
18 | var plot = new Plottable.Plots.Bar("vertical")
19 | .renderer("canvas")
20 | .addDataset(ds)
21 | .x(function (d, i, dataset) { return d.name + dataset.metadata().foo; }, xScale)
22 | .y(function(d) { return d.y; }, yScale)
23 | .attr("fill", function(d) { return d.name; }, colorScale);
24 |
25 | var chart = new Plottable.Components.Table([
26 | [null, title],
27 | [yAxis, plot],
28 | [null, xAxis]]);
29 |
30 | chart.renderTo(div);
31 |
32 | var pointer = new Plottable.Interactions.Pointer();
33 | pointer.onPointerMove(function(p) {
34 | var nearestEntity = plot.entityNearest(p);
35 | var datum = nearestEntity != null ? nearestEntity.datum : null;
36 | if (datum != null) {
37 | title.text("" + datum.name);
38 | } else {
39 | title.text("Who?");
40 | }
41 | });
42 | pointer.onPointerExit(function() { title.text("Who?"); });
43 | pointer.attachTo(plot);
44 | }
45 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/dragbox.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | var data = [];
4 | for (var i = 0; i < 250; i++) { data.push({
5 | "x": i,
6 | "y": Math.random(),
7 | "symbol": Math.floor(6 * Math.random()),
8 | "size": Math.floor(10 * Math.random()) + 10
9 | }); }
10 | return data;
11 |
12 | }
13 |
14 | function run(svg, data, Plottable) {
15 | "use strict";
16 |
17 | var symbols = [
18 | Plottable.SymbolFactories.square(),
19 | Plottable.SymbolFactories.circle(),
20 | Plottable.SymbolFactories.cross(),
21 | Plottable.SymbolFactories.diamond(),
22 | Plottable.SymbolFactories.triangle(),
23 | Plottable.SymbolFactories.star(),
24 | Plottable.SymbolFactories.wye(),
25 | ];
26 |
27 | var xScale = new Plottable.Scales.Linear();
28 | var yScale = new Plottable.Scales.Linear();
29 | var plot = new Plottable.Plots.Scatter()
30 | .x(function(d) { return d.x; }, xScale)
31 | .y(function(d) { return d.y; }, yScale)
32 | .symbol(function(d) { return symbols[d.symbol]; })
33 | .attr("fill", "#dddddd")
34 | .size(function(d) { return d.size; })
35 | .addDataset(new Plottable.Dataset(data));
36 |
37 | var dragLabel = new Plottable.Components.Label("EntitiesIn", 0);
38 | var clickLabel = new Plottable.Components.Label("EntitiesAt", 0);
39 |
40 | var dblX = new Plottable.Components.XDragBoxLayer()
41 | .onDrag(function(bounds){
42 | plot.entities().forEach(function(e){
43 | e.selection.attr("fill", "#dddddd");
44 | });
45 | plot.entitiesIn(bounds).forEach(function(e){
46 | e.selection.attr("fill", "#34be6c");
47 | });
48 | })
49 | .xScale(xScale)
50 | .movable(true);
51 |
52 | var hover = new Plottable.Interactions.Pointer()
53 | .onPointerMove(function(p){
54 | plot.entities().forEach(function(e){
55 | e.selection.attr("fill", "#dddddd");
56 | });
57 | plot.entitiesAt(p).forEach(function(e){
58 | e.selection.attr("fill", "#be346c");
59 | });
60 | })
61 | .attachTo(plot)
62 | .enabled(false);
63 |
64 | new Plottable.Interactions.Click()
65 | .onClick(function(){
66 | hover.enabled(false);
67 | dblX.enabled(true);
68 | })
69 | .attachTo(dragLabel);
70 |
71 | new Plottable.Interactions.Click()
72 | .onClick(function(){
73 | hover.enabled(true);
74 | dblX.enabled(false);
75 | })
76 | .attachTo(clickLabel);
77 |
78 | var labels = new Plottable.Components.Table([[dragLabel], [clickLabel]]);
79 | var group = new Plottable.Components.Group([plot, dblX]);
80 | new Plottable.Components.Table([[group], [labels]]).renderTo(svg);
81 | }
82 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/dragbox_scales.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | var segmentData = [];
4 | for (var i = 0; i < 10; i++) { segmentData.push({
5 | "x": i,
6 | "y": Math.random(),
7 | "x2": i + Math.random()
8 | }); }
9 | var rectData = [];
10 | for (i = 0; i < 10; i++) { rectData.push({
11 | "x": i,
12 | "y": Math.random(),
13 | "x2": i + Math.random()
14 | }); }
15 | return [segmentData, rectData];
16 |
17 | }
18 |
19 | function run(svg, data, Plottable) {
20 | "use strict";
21 | var xScale = new Plottable.Scales.Linear();
22 | var yScale = new Plottable.Scales.Linear();
23 |
24 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
25 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
26 |
27 | var segment = new Plottable.Plots.Segment()
28 | .x(function(d) { return d.x; }, xScale)
29 | .x2(function(d) { return d.x2; })
30 | .y(function(d) { return d.y; }, yScale)
31 | .attr("stroke", "#dddddd")
32 | .addDataset(new Plottable.Dataset(data[0]));
33 |
34 | var rectangle = new Plottable.Plots.Rectangle()
35 | .x(function(d) { return d.x; }, xScale)
36 | .x2(function(d) { return d.x2; })
37 | .y(function(d) { return d.y; }, yScale)
38 | .y2(function(d){ return d.y + .1; })
39 | .attr("fill", "#dddddd")
40 | .addDataset(new Plottable.Dataset(data[1]));
41 |
42 | var dbl = new Plottable.Components.DragBoxLayer()
43 | .onDrag(function(bounds){
44 | segment.entities().forEach(function(e){
45 | e.selection.attr("stroke", "#dddddd");
46 | });
47 | segment.entitiesIn(bounds).forEach(function(e){
48 | e.selection.attr("stroke", "#be346c");
49 | });
50 | rectangle.entities().forEach(function(e){
51 | e.selection.attr("fill", "#dddddd");
52 | });
53 | rectangle.entitiesIn(bounds).forEach(function(e){
54 | e.selection.attr("fill", "#34be6c");
55 | });
56 | })
57 | .xScale(xScale)
58 | .yScale(yScale)
59 | .movable(true);
60 |
61 | var group = new Plottable.Components.Group([segment, rectangle, dbl]);
62 | new Plottable.Components.Table([[yAxis, group], [null, xAxis]]).renderTo(svg);
63 | }
64 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/guidelines.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | var makeGridData = function(x, y){
4 | var d = [];
5 | for(var i = 0; i < x; i++){
6 | for(var j = 0; j < y; j++){
7 | d.push({x: i, x2: i + Math.random(), y: j, y2: j + Math.random()});
8 | }
9 | }
10 | return d;
11 | };
12 | return makeGridData(10, 10);
13 | }
14 |
15 | function run(svg, data, Plottable) {
16 | "use strict";
17 | var ds = new Plottable.Dataset(data);
18 |
19 | var xScale = new Plottable.Scales.Linear().domain([0, 9.5]);
20 | var yScale = new Plottable.Scales.Linear().domain([0, 9.5]);
21 |
22 | var accessor = function(key){
23 | return function(d){
24 | return d[key];
25 | };
26 | };
27 |
28 | var plot = new Plottable.Plots.Rectangle()
29 | .addDataset(ds)
30 | .x(accessor("x"), xScale)
31 | .y(accessor("y"), yScale)
32 | .x2(accessor("x2"))
33 | .y2(accessor("y2"))
34 | .attr("fill", "#75acC7");
35 |
36 | var val = 5;
37 | var gllv = new Plottable.Components.GuideLineLayer("vertical");
38 | gllv.scale(xScale).value(val);
39 | var gllh = new Plottable.Components.GuideLineLayer("horizontal");
40 | gllh.scale(yScale).value(val);
41 |
42 | var fillArea = function(xRange, yRange, fill){
43 | plot.entitiesIn(xRange, yRange).forEach(function(entity) {
44 | entity.selection.attr("fill", fill);
45 | });
46 | };
47 |
48 | var updateColors = function(point){
49 | gllh.pixelPosition(point.y);
50 | gllv.pixelPosition(point.x);
51 | var plotLeft = xScale.range()[0];
52 | var plotRight = xScale.range()[1];
53 | var plotTop = yScale.range()[0];
54 | var plotBottom = yScale.range()[1];
55 | fillArea({min: point.x, max: plotRight},
56 | {min: point.y, max: plotTop},
57 | "#75acC7");
58 | fillArea({min: plotLeft, max: point.x},
59 | {min: point.y, max: plotTop},
60 | "#c775ac");
61 | fillArea({min: plotLeft, max: point.x},
62 | {min: plotBottom, max: point.y},
63 | "#acc775");
64 | fillArea({min: point.x, max: plotRight},
65 | {min: plotBottom, max: point.y},
66 | "#c7b975");
67 | };
68 |
69 | new Plottable.Components.Group([plot, gllh, gllv])
70 | .renderTo(svg);
71 | updateColors({x: gllv.pixelPosition(), y: gllh.pixelPosition()});
72 |
73 | new Plottable.Interactions.Pointer()
74 | .onPointerMove(function(point){
75 | updateColors(point);
76 | })
77 | .attachTo(plot);
78 | }
79 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/pan_zoom_reverse.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return makeRandomData(20);
4 | }
5 |
6 | function run(svg, data, Plottable) {
7 | "use strict";
8 |
9 | function makePlot(xDomain, yDomain) {
10 | const xScale = new Plottable.Scales.Linear().domain(xDomain);
11 | const yScale = new Plottable.Scales.Linear().domain(yDomain);
12 | const scatterPlot = new Plottable.Plots.Scatter()
13 | .addDataset(new Plottable.Dataset(data))
14 | .x((d) => d.x, xScale)
15 | .y((d) => d.y, yScale);
16 |
17 | // layout components
18 | const xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
19 | const yAxis = new Plottable.Axes.Numeric(yScale, "left");
20 | const gridlines = new Plottable.Components.Gridlines(xScale, yScale);
21 | const renderGroup = new Plottable.Components.Group([scatterPlot, gridlines]);
22 | const table = new Plottable.Components.Table([
23 | [yAxis, renderGroup],
24 | [null, xAxis],
25 | ]);
26 |
27 | new Plottable.Interactions.PanZoom(xScale, yScale)
28 | .attachTo(renderGroup)
29 | .setMinMaxDomainValuesTo(xScale)
30 | .setMinMaxDomainValuesTo(yScale);
31 |
32 | new Plottable.Interactions.PanZoom(xScale, null)
33 | .attachTo(xAxis)
34 | .setMinMaxDomainValuesTo(xScale);
35 |
36 | new Plottable.Interactions.PanZoom(null, yScale)
37 | .attachTo(yAxis)
38 | .setMinMaxDomainValuesTo(yScale);
39 |
40 | return table;
41 | }
42 |
43 | new Plottable.Components.Table([
44 | [makePlot([3, -1], [3, -1]), makePlot([-1, 3], [3, -1])],
45 | [makePlot([3, -1], [-1, 3]), makePlot([-1, 3], [-1, 3])],
46 | ]).renderTo(svg);
47 | }
48 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/scale_interactive.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | return [makeRandomData(50), makeRandomData(50)];
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 |
10 | var dataseries = new Plottable.Dataset(data[0].slice(0, 20));
11 |
12 | var xScale = new Plottable.Scales.Linear();
13 | var xAxisLeft = new Plottable.Axes.Numeric(xScale, "bottom").tickLabelPosition("left");
14 | var xAxisCenter = new Plottable.Axes.Numeric(xScale, "bottom");
15 | var xAxisRight = new Plottable.Axes.Numeric(xScale, "bottom").tickLabelPosition("right");
16 | var xAxisTable = new Plottable.Components.Table([[xAxisLeft],
17 | [xAxisCenter],
18 | [xAxisRight]]);
19 |
20 | var xAxisLeft2 = new Plottable.Axes.Numeric(xScale, "top").tickLabelPosition("left");
21 | var xAxisCenter2 = new Plottable.Axes.Numeric(xScale, "top");
22 | var xAxisRight2 = new Plottable.Axes.Numeric(xScale, "top").tickLabelPosition("right");
23 | var xAxisTable2 = new Plottable.Components.Table([[xAxisLeft2],
24 | [xAxisCenter2],
25 | [xAxisRight2]]);
26 |
27 | var yScale = new Plottable.Scales.Linear();
28 | var yAxisTop = new Plottable.Axes.Numeric(yScale, "left").tickLabelPosition("top");
29 | var yAxisMiddle = new Plottable.Axes.Numeric(yScale, "left");
30 | var yAxisBottom = new Plottable.Axes.Numeric(yScale, "left").tickLabelPosition("bottom");
31 | var yAxisTable = new Plottable.Components.Table([[yAxisTop, yAxisMiddle, yAxisBottom]]);
32 |
33 | var yAxisTop2 = new Plottable.Axes.Numeric(yScale, "right").tickLabelPosition("top");
34 | var yAxisMiddle2 = new Plottable.Axes.Numeric(yScale, "right");
35 | var yAxisBottom2 = new Plottable.Axes.Numeric(yScale, "right").tickLabelPosition("bottom");
36 | var yAxisTable2 = new Plottable.Components.Table([[yAxisTop2, yAxisMiddle2, yAxisBottom2]]);
37 |
38 | var scatterPlot = new Plottable.Plots.Scatter().addDataset(dataseries);
39 | scatterPlot.x(function(d) { return d.x; }, xScale).y(function(d) { return d.y; }, yScale);
40 | var gridlines = new Plottable.Components.Gridlines(xScale, yScale);
41 | var renderGroup = new Plottable.Components.Group([scatterPlot, gridlines]);
42 |
43 | var basicTable = new Plottable.Components.Table([[null, xAxisTable2, null],
44 | [yAxisTable, renderGroup, yAxisTable2],
45 | [null, xAxisTable, null]]);
46 |
47 | basicTable.renderTo(svg);
48 |
49 | new Plottable.Interactions.PanZoom(xScale, yScale).attachTo(renderGroup);
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/select_bars.js:
--------------------------------------------------------------------------------
1 |
2 | function makeData() {
3 | "use strict";
4 |
5 | return [
6 | {x: 1, y: 10},
7 | {x: 2, y: 20},
8 | {x: 3, y: 10},
9 | {x: 4, y: 30},
10 | {x: 5, y: 10},
11 | {x: 6, y: 60},
12 | {x: 7, y: 20},
13 | ];
14 | }
15 |
16 | function run(svg, data, Plottable) {
17 | "use strict";
18 |
19 | var xScale = new Plottable.Scales.Linear();
20 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
21 |
22 | // exposes selection misalignment issue
23 | xScale.domainMin(3);
24 |
25 | var yScale = new Plottable.Scales.Linear();
26 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
27 |
28 | var barPlot = new Plottable.Plots.Bar()
29 | .addDataset(new Plottable.Dataset(data))
30 | .x(function(d) { return d.x; }, xScale)
31 | .y(function(d) { return d.y; }, yScale);
32 |
33 | new Plottable.Components.Table([
34 | [yAxis, barPlot],
35 | [null, xAxis],
36 | ]).renderTo(svg);
37 |
38 | var clickInteraction = new Plottable.Interactions.Click();
39 | clickInteraction.attachTo(barPlot);
40 | clickInteraction.onClick(function (p) {
41 | barPlot.selections().style("fill", null);
42 | var bars = barPlot.entitiesAt(p);
43 | if (bars) {
44 | bars.forEach(function(bar) { bar.selection.style("fill", "red"); });
45 | }
46 | });
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/select_clustered_bars.js:
--------------------------------------------------------------------------------
1 |
2 | function makeData() {
3 | "use strict";
4 |
5 | var data1 = [{name: "jon", y: 1, type: "q1"}, {name: "dan", y: 2, type: "q1"}, {name: "zoo", y: 1, type: "q1"}];
6 | var data2 = [{name: "jon", y: 2, type: "q2"}, {name: "dan", y: 4, type: "q2"}, {name: "zoo", y: 2, type: "q2"}];
7 | var data3 = [{name: "jon", y: 4, type: "q3"}, {name: "dan", y: 15, type: "q3"}, {name: "zoo", y: 15, type: "q3"}];
8 | return [data1, data2, data3];
9 | }
10 |
11 | function run(svg, data, Plottable) {
12 | "use strict";
13 |
14 | var xScale = new Plottable.Scales.Category();
15 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
16 |
17 | var yScale = new Plottable.Scales.Linear();
18 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
19 |
20 | var barPlot = new Plottable.Plots.ClusteredBar()
21 | .addDataset(new Plottable.Dataset(data[0]))
22 | .addDataset(new Plottable.Dataset(data[1]))
23 | .addDataset(new Plottable.Dataset(data[2]))
24 | .x(function(d) { return d.name; }, xScale)
25 | .y(function(d) { return d.y; }, yScale);
26 |
27 | new Plottable.Components.Table([
28 | [yAxis, barPlot],
29 | [null, xAxis]]).renderTo(svg);
30 |
31 | var clickInteraction = new Plottable.Interactions.Click();
32 | clickInteraction.attachTo(barPlot);
33 | clickInteraction.onClick(function (p) {
34 | var bars = barPlot.entitiesAt(p);
35 | if (bars.length === 0) {
36 | barPlot.selections().style("fill", null);
37 | } else {
38 | bars.forEach(function(bar) { bar.selection.style("fill", "red"); });
39 | }
40 | });
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/interactions/single_and_double_click.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | var data = [];
4 | for (var i = 1; i < 10; i++) { data.push({"x": i, "y": i}); }
5 | return data;
6 | }
7 |
8 | function run(svg, data, Plottable) {
9 | "use strict";
10 |
11 | var xScale = new Plottable.Scales.Linear();
12 | var yScale = new Plottable.Scales.Linear();
13 |
14 | var plot = new Plottable.Plots.Bar()
15 | .x(function(d) { return d.x; }, xScale)
16 | .y(function(d) { return d.y; }, yScale)
17 | .addDataset(new Plottable.Dataset(data));
18 |
19 | var interaction = new Plottable.Interactions.Click();
20 |
21 | interaction.onDoubleClick(function(point) {
22 | plot.selections().attr("fill", "#5279c7");
23 | var selection = plot.entitiesAt(point)[0].selection;
24 | selection.attr("fill", "orange");
25 | });
26 |
27 | interaction.onClick(function(point) {
28 | plot.selections().attr("fill", "#5279c7");
29 | var selection = plot.entitiesAt(point)[0].selection;
30 | selection.attr("fill", "red");
31 | });
32 |
33 | interaction.attachTo(plot);
34 |
35 | plot.renderTo(svg);
36 | }
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/add_remove_dataset.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | function makeSquigglyData(n, startValue) {
4 | startValue = startValue ? startValue : 0;
5 | var toReturn = new Array(n);
6 | for (var i = 0; i < n; i++) {
7 | toReturn[i] = {
8 | x: startValue + i,
9 | y: i > 0 ? toReturn[i - 1].y + Math.random() * 2 - 1 : Math.random() * 5
10 | };
11 | }
12 | return toReturn;
13 | }
14 |
15 | var data = [];
16 | for (var i = 0; i < 10; i++) {
17 | data.push(makeSquigglyData(100));
18 | }
19 |
20 | return data;
21 | }
22 |
23 | function run(svg, data, Plottable) {
24 | "use strict";
25 |
26 | var xScale = new Plottable.Scales.Linear();
27 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
28 | var yScale = new Plottable.Scales.Linear();
29 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
30 |
31 | var plot = new Plottable.Plots.Area();
32 | plot.x(function(d) { return d.x; }, xScale);
33 | plot.y(function(d) { return d.y; }, yScale);
34 | var colorScale = new Plottable.Scales.Color();
35 | plot.attr("stroke", function(d, i, ds) { return ds.metadata().id; }, colorScale);
36 | plot.attr("fill", function(d, i, ds) { return ds.metadata().id; }, colorScale);
37 | var legend = new Plottable.Components.Legend(colorScale);
38 |
39 | var addButton = new Plottable.Components.Label("Add Dataset");
40 | addButton.xAlignment("left").padding(5);
41 | new Plottable.Interactions.Click()
42 | .onClick(function() {
43 | var numDatasets = plot.datasets().length;
44 | if (numDatasets >= 10) {
45 | return;
46 | }
47 | var datasetID = String(numDatasets);
48 | var dataset = new Plottable.Dataset(data[numDatasets - 1], { id: datasetID });
49 | plot.addDataset(dataset);
50 | })
51 | .attachTo(addButton);
52 | var removeButton = new Plottable.Components.Label("Remove Dataset");
53 | removeButton.xAlignment("right").padding(5);
54 | new Plottable.Interactions.Click()
55 | .onClick(function() {
56 | var datasets = plot.datasets();
57 | if (datasets.length > 0) {
58 | plot.removeDataset(datasets[datasets.length - 1]);
59 | }
60 | })
61 | .attachTo(removeButton);
62 | var buttonGroup = new Plottable.Components.Group([addButton, removeButton]);
63 |
64 | var chart = new Plottable.Components.Table([
65 | [yAxis, plot, legend],
66 | [null, xAxis, null],
67 | [null, buttonGroup, null]
68 | ]);
69 | chart.renderTo(svg);
70 | addButton.background().select(".background-fill").style("stroke", "black");
71 | removeButton.background().select(".background-fill").style("stroke", "black");
72 | }
73 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/bar_and_legend_and_panzoom.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | const rand = d3.randomUniform(0, 1);
4 | const data = [];
5 | for(var i = 0; i < 50; i++) {
6 | data.push({
7 | name: Math.random().toString(16).substr(2),
8 | category: i % 2 === 0 ? "a" : "b",
9 | val: rand()
10 | });
11 | }
12 | return data;
13 | }
14 |
15 | function run(div, data, Plottable) {
16 | "use strict";
17 |
18 | const datasets = data.map((d) => new Plottable.Dataset([d]));
19 |
20 | var xScale = new Plottable.Scales.Category();
21 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
22 |
23 | var yScale = new Plottable.Scales.Linear();
24 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
25 |
26 | var colorScale = new Plottable.Scales.Color();
27 |
28 | var barPlot = new Plottable.Plots.StackedBar("vertical")
29 | .datasets(datasets)
30 | .x(function (d) { return d.category; }, xScale)
31 | .y(function(d) { return d.val; }, yScale)
32 | .attr("fill", function(d) { return d.name; }, colorScale)
33 | .labelsEnabled(true);
34 |
35 | var grid = new Plottable.Components.Gridlines(null, yScale);
36 |
37 | var legend = new Plottable.Components.Legend(colorScale);
38 |
39 | var plots = new Plottable.Components.Group([barPlot, grid]);
40 | var chart = new Plottable.Components.Table([[yAxis, plots, legend],
41 | [null, xAxis]]);
42 |
43 | new Plottable.Interactions.PanZoom(xScale, yScale)
44 | .attachTo(plots);
45 |
46 | chart.renderTo(div);
47 | }
48 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/baseball.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | }
4 |
5 | function run(svg, data, Plottable) {
6 | "use strict";
7 |
8 | d3.csv("data/baseball.csv").get(function(error, rows) {
9 | data = rows;
10 | var dataset = new Plottable.Dataset(data);
11 |
12 | var xScale = new Plottable.Scales.Linear();
13 | var yScale = new Plottable.Scales.Linear();
14 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
15 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
16 |
17 | var projectSeason = function(d){ return +d.season; };
18 | var projectLow = function(d){ return +d.low; };
19 | var projectHigh = function(d){ return +d.high; };
20 | var projectAvg = function(d){ return +d.average; };
21 | var projectTigers = function(d){ return +d.tigers; };
22 |
23 | var bandPlot = new Plottable.Plots.Area(xScale, yScale);
24 | bandPlot.addDataset(dataset);
25 | bandPlot.x(projectSeason, xScale)
26 | .y0(projectLow, yScale)
27 | .y(projectHigh, yScale)
28 | .attr("fill", "#bbbbbb")
29 | .attr("stroke-width", 0);
30 |
31 | var avgPlot = new Plottable.Plots.Line(xScale, yScale);
32 | avgPlot.addDataset(dataset);
33 | avgPlot.x(projectSeason, xScale)
34 | .y(projectAvg, yScale)
35 | .attr("stroke", "#888888");
36 |
37 | var tigerLine = new Plottable.Plots.Line(xScale, yScale);
38 | tigerLine.addDataset(dataset);
39 | tigerLine.x(projectSeason, xScale)
40 | .y(projectTigers, yScale)
41 | .attr("stroke", "#DE4406");
42 |
43 | var tigerScatter = new Plottable.Plots.Scatter(xScale, yScale);
44 | tigerScatter.addDataset(dataset);
45 | tigerScatter.x(projectSeason, xScale)
46 | .y(projectTigers, yScale)
47 | .attr("fill", "#001742");
48 |
49 | var cs = new Plottable.Scales.Color();
50 | cs.range(["#bbbbbb", "#888888", "#DE4406"]);
51 | cs.domain(["Payroll range across MLB", "Average payroll", "Tigers payroll"]);
52 | var legend = new Plottable.Components.Legend(cs);
53 |
54 | var squareFactory = Plottable.SymbolFactories.square();
55 | var circleFactory = Plottable.SymbolFactories.circle();
56 |
57 | if (typeof legend.symbol === "function") {
58 | legend.symbol(function (d, i) {
59 | if(i === 0) { return squareFactory; }
60 | else { return circleFactory; }
61 | });
62 | } else {
63 | legend.symbolFactoryAccessor(function (d, i) {
64 | if(i === 0) { return squareFactory; }
65 | else { return circleFactory; }
66 | });
67 | }
68 |
69 | var plots = new Plottable.Components.Group([bandPlot, avgPlot, tigerLine, tigerScatter]);
70 | var table = new Plottable.Components.Table([[null, legend],
71 | [yAxis, plots],
72 | [null, xAxis]]);
73 | table.renderTo(svg);
74 | });
75 | }
76 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/category_grid.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return [{hospital: "yes", hour: "12 AM", percent: 2.8},
4 | {hospital: "yes", hour: "1 AM", percent: 2.9},
5 | {hospital: "yes", hour: "2 AM", percent: 2.7},
6 | {hospital: "yes", hour: "3 AM", percent: 2.7},
7 | {hospital: "yes", hour: "4 AM", percent: 2.7},
8 | {hospital: "yes", hour: "5 AM", percent: 2.7},
9 | {hospital: "yes", hour: "6 AM", percent: 2.8},
10 | {hospital: "yes", hour: "7 AM", percent: 4.5},
11 | {hospital: "yes", hour: "8 AM", percent: 6.3},
12 | {hospital: "yes", hour: "9 AM", percent: 5.1},
13 | {hospital: "yes", hour: "10 AM", percent: 5.0},
14 | {hospital: "yes", hour: "11 AM", percent: 5.0},
15 | {hospital: "no", hour: "12 AM", percent: 4.2},
16 | {hospital: "no", hour: "1 AM", percent: 5.0},
17 | {hospital: "no", hour: "2 AM", percent: 5.0},
18 | {hospital: "no", hour: "3 AM", percent: 5.2},
19 | {hospital: "no", hour: "4 AM", percent: 5.2},
20 | {hospital: "no", hour: "5 AM", percent: 4.9},
21 | {hospital: "no", hour: "6 AM", percent: 4.6},
22 | {hospital: "no", hour: "7 AM", percent: 4.4},
23 | {hospital: "no", hour: "8 AM", percent: 4.2},
24 | {hospital: "no", hour: "9 AM", percent: 3.9},
25 | {hospital: "no", hour: "10 AM", percent: 3.8},
26 | {hospital: "no", hour: "11 AM", percent: 3.7}
27 | ];
28 | }
29 |
30 | function run(svg, data, Plottable) {
31 | "use strict";
32 |
33 | var xScale = new Plottable.Scales.Category();
34 | var yScale = new Plottable.Scales.Category();
35 | var cs = new Plottable.Scales.InterpolatedColor();
36 | cs.range(["#ADD8E6", "#67818A"]);
37 |
38 | var xAxis = new Plottable.Axes.Category(xScale, "top");
39 | var yAxis = new Plottable.Axes.Category(yScale, "left");
40 | var plot = new Plottable.Plots.Rectangle();
41 | plot.addDataset(new Plottable.Dataset(data));
42 | plot.x(function(d){ return d.hospital; }, xScale)
43 | .y(function(d) { return d.hour; }, yScale)
44 | .label(function(d) { return d.percent + "%"; })
45 | .labelsEnabled(true)
46 | .attr("fill", function(d) { return d.percent; }, cs);
47 |
48 | var label = new Plottable.Components.Label("Born in hospital?", 0);
49 | var legend = new Plottable.Components.InterpolatedColorLegend(cs)
50 | .xAlignment("center")
51 | .expands(true);
52 |
53 | var table = new Plottable.Components.Table([[null, legend],
54 | [null, label],
55 | [null, xAxis],
56 | [yAxis, plot]]);
57 | table.renderTo(svg);
58 | }
59 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/cities.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 |
4 | }
5 |
6 | function run(svg, data, Plottable) {
7 | "use strict";
8 |
9 | d3.csv("data/cities.csv").get(function(error, rows) {
10 | data = rows;
11 | var ds = new Plottable.Dataset(data);
12 |
13 | var csRange = [];
14 | for(var i = 0; i < 30; i++){
15 | var c = "#" + Math.floor(Math.random() * 16777215).toString(16);
16 | csRange.push(c);
17 | }
18 |
19 | var cs = new Plottable.Scales.Color();
20 | cs.range(csRange);
21 |
22 | var xScale = new Plottable.Scales.Linear().domain([-110, -90]);
23 | var yScale = new Plottable.Scales.Linear().domain([25, 40]);
24 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
25 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
26 |
27 | var plot = new Plottable.Plots.Scatter(xScale, yScale);
28 | plot.addDataset(ds);
29 | plot.x(function(d){ return d.lng; }, xScale)
30 | .y(function(d){ return d.lat; }, yScale)
31 | .attr("fill", function(d){ return d.state; }, cs);
32 |
33 | var table = new Plottable.Components.Table([[yAxis, plot],
34 | [null, xAxis]]);
35 | table.renderTo(svg);
36 | });
37 | }
38 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/legend_select.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | var data = {};
4 | data.blue = makeRandomData(12);
5 | data.red = makeRandomData(12);
6 | data.green = makeRandomData(12);
7 | return data;
8 |
9 | }
10 |
11 | function run(svg, data, Plottable) {
12 | "use strict";
13 | var title = new Plottable.Components.TitleLabel("Click legend entries to highlight plots", 0);
14 |
15 | var cs = new Plottable.Scales.Color();
16 | cs.range(["#ff0000", "#009900", "#0000ff"]);
17 | cs.domain(["red", "green", "blue"]);
18 | var legend = new Plottable.Components.Legend(cs);
19 | legend.symbol(function (_data, index) {
20 | return index === 0 ? new Plottable.SymbolFactories.cross() : new Plottable.SymbolFactories.square();
21 | });
22 |
23 | var xScale = new Plottable.Scales.Linear();
24 | var yScale = new Plottable.Scales.Linear();
25 |
26 | var getX = function(d) { return d.x; };
27 | var getY = function(d) { return d.y; };
28 |
29 | var plots = {};
30 | var plotGroupArray = [];
31 |
32 | var addPlot = function(color){
33 | var ds = new Plottable.Dataset(data[color]);
34 | plots[color] = new Plottable.Plots.Line()
35 | .addDataset(ds)
36 | .x(getX, xScale)
37 | .y(getY, yScale)
38 | .attr("stroke", color, cs)
39 | .curve("step");
40 | plotGroupArray.push(plots[color]);
41 | };
42 |
43 | addPlot("red");
44 | addPlot("blue");
45 | addPlot("green");
46 |
47 | var plotGroup = new Plottable.Components.Group(plotGroupArray);
48 | var table = new Plottable.Components.Table([[title, null],
49 | [plotGroup, legend]]);
50 | table.renderTo(svg);
51 |
52 | var legendInteraction = new Plottable.Interactions.Click();
53 | legendInteraction.onClick(function(point) {
54 | Object.keys(plots).forEach(function(key) { plots[key].selections().attr("opacity", .3); });
55 | var datum = legend.entitiesAt(point)[0].datum;
56 | plots[datum].selections().attr("opacity", 1);
57 | legend.symbolOpacity(function(d) {
58 | if (d === datum) {
59 | return 1;
60 | }
61 | else{
62 | return .3;
63 | }
64 | });
65 | });
66 | legendInteraction.attachTo(legend);
67 |
68 | var plotInteraction = new Plottable.Interactions.Click();
69 | plotInteraction.onClick(function() {
70 | Object.keys(plots).forEach(function(key) { plots[key].selections().attr("opacity", 1); });
71 | legend.symbolOpacity(function() {
72 | return 1;
73 | });
74 | });
75 | plotInteraction.attachTo(plotGroup);
76 | }
77 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/many_bars.js:
--------------------------------------------------------------------------------
1 |
2 | function makeData() {
3 | "use strict";
4 | var JAN_01_2012 = new Date(2012, 0, 0).valueOf();
5 | var MILLIS_IN_DAY = 1000 * 60 * 60 * 24;
6 | var data1 = [];
7 | var data2 = [];
8 | var data3 = [];
9 | var data4 = [];
10 | for (var i = 0; i < 1000; i++) {
11 | data1.push({
12 | x: new Date(JAN_01_2012 + MILLIS_IN_DAY * i),
13 | y: Math.random() * 50 - 25,
14 | });
15 | data2.push({
16 | x: new Date(JAN_01_2012 + MILLIS_IN_DAY * i),
17 | y: Math.random() * 50 - 25,
18 | });
19 | data3.push({
20 | x: new Date(JAN_01_2012 + MILLIS_IN_DAY * i),
21 | y: Math.random() * 50 - 25,
22 | });
23 | data4.push({
24 | x: new Date(JAN_01_2012 + MILLIS_IN_DAY * i),
25 | y: Math.random() * 50 - 25,
26 | });
27 | }
28 | return [data1, data2, data3, data4];
29 | }
30 |
31 | function run(div, datas, Plottable) {
32 | "use strict";
33 |
34 | var xScale = new Plottable.Scales.Time();
35 | var yScale = new Plottable.Scales.Linear();
36 | var colorScale = new Plottable.Scales.Color();
37 |
38 | var ds1 = new Plottable.Dataset(datas[0]).metadata(1);
39 | var ds2 = new Plottable.Dataset(datas[1]).metadata(2);
40 | var ds3 = new Plottable.Dataset(datas[2]).metadata(3);
41 | var ds4 = new Plottable.Dataset(datas[3]).metadata(4);
42 | var plot = new Plottable.Plots.StackedBar()
43 | .datasets([ds1, ds2, ds3, ds4])
44 | .x(function (d) { return d.x; }, xScale)
45 | .y(function (d) { return d.y; }, yScale)
46 | .labelsEnabled(true, "middle")
47 | .attr("fill", function (d, i, ds) { return ds.metadata()}, colorScale);
48 | plot.renderTo(div);
49 |
50 | new Plottable.Interactions.PanZoom(xScale, null).attachTo(plot).setMinMaxDomainValuesTo(xScale);
51 | }
52 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/numeric_grid.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return [{fill: "#FFFFFF", x: 0, x2: 13, y: 0, y2: 7},
4 | {fill: "#FF0000", x: 0, x2: 13, y: 7, y2: 20},
5 | {fill: "#0000FF", x: 13, x2: 20, y: 0, y2: 7},
6 | {fill: "#FFFFFF", x: 13, x2: 20, y: 7, y2: 13},
7 | {fill: "#FFFF00", x: 13, x2: 20, y: 13, y2: 20},
8 | {fill: "#FFFF00", x: 20, x2: 30, y: 0, y2: 10},
9 | {fill: "#0000FF", x: 20, x2: 27, y: 10, y2: 13},
10 | {fill: "#FFFFFF", x: 27, x2: 30, y: 10, y2: 17},
11 | {fill: "#FFFFFF", x: 20, x2: 27, y: 13, y2: 20},
12 | {fill: "#FF0000", x: 27, x2: 30, y: 17, y2: 20}
13 | ];
14 | }
15 |
16 | function run(svg, data, Plottable) {
17 | "use strict";
18 |
19 | var xScale = new Plottable.Scales.Linear();
20 | var yScale = new Plottable.Scales.Linear();
21 |
22 | var plot = new Plottable.Plots.Rectangle();
23 | plot.addDataset(new Plottable.Dataset(data));
24 | plot.x(function(d){ return d.x; }, xScale)
25 | .y(function(d) { return d.y; }, yScale)
26 | .x2(function(d){ return d.x2; })
27 | .y2(function(d) { return d.y2; })
28 | .attr("fill", function(d) { return d.fill; })
29 | .attr("opacity", .5)
30 | .attr("stroke", function(){ return "#000000"; })
31 | .attr("stroke-width", function(){ return 4; });
32 |
33 | plot.renderTo(svg);
34 |
35 | var hover = new Plottable.Interactions.Pointer().attachTo(plot);
36 | hover.onPointerEnter(function() {
37 | plot.entities().forEach(function(entity) { entity.selection.attr("opacity", 0.3); });
38 | });
39 |
40 | var lastEntities = [];
41 | hover.onPointerMove(function(p) {
42 | lastEntities.forEach(function(entity) { entity.selection.attr("opacity", 0.3); });
43 | var entities = plot.entitiesAt(p);
44 | entities.forEach(function(entity) { entity.selection.attr("opacity", 1); });
45 | lastEntities = entities;
46 | });
47 |
48 | hover.onPointerExit(function() {
49 | plot.entities().forEach(function(entity) { entity.selection.attr("opacity", 1); });
50 | lastEntities = [];
51 | });
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/rectangle.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return [{team: "Detroit Tigers", x: "4/1/1901", x2: "8/1/2015",
4 | y: 0, y2: 1,
5 | fill: "#DE4406", stroke: "#001742"},
6 |
7 | {team: "Detroit Wolverines", x: "4/1/1881", x2: "8/1/1888",
8 | y: 1, y2: 2,
9 | fill: "#f5f5dc", stroke: "#CF0032"},
10 |
11 | {team: "Detroit Stars", x: "4/1/1919", x2: "8/1/1931",
12 | y: 2, y2: 3,
13 | fill: "#00529B", stroke: "#CF0032"},
14 |
15 | {team: "Detroit Stars", x: "4/1/1933", x2: "8/1/1933",
16 | y: 2, y2: 3,
17 | fill: "#00529B", stroke: "#CF0032"},
18 |
19 | {team: "Detroit Stars", x: "4/1/1937", x2: "8/1/1937",
20 | y: 2, y2: 3,
21 | fill: "#00529B", stroke: "#CF0032"},
22 |
23 | {team: "Detroit Stars", x: "4/1/1954", x2: "8/1/1957",
24 | y: 2, y2: 3,
25 | fill: "#00529B", stroke: "#CF0032"},
26 |
27 | {team: "Detroit Stars", x: "4/1/1959", x2: "8/1/1959",
28 | y: 2, y2: 3,
29 | fill: "#00529B", stroke: "#CF0032"}
30 | ];
31 | }
32 |
33 | function run(svg, data, Plottable) {
34 | "use strict";
35 | var timeFormatStart = function (d) { return d3.timeParse("%m/%d/%Y")(d.x); };
36 | var timeFormatEnd = function (d) { return d3.timeParse("%m/%d/%Y")(d.x2); };
37 |
38 | var xScale = new Plottable.Scales.Time();
39 | var yScale = new Plottable.Scales.Category();
40 | yScale.innerPadding(0.25).outerPadding(0.25);
41 | var xAxis = new Plottable.Axes.Time(xScale, "bottom");
42 | var yAxis = new Plottable.Axes.Category(yScale, "left");
43 | var plot = new Plottable.Plots.Rectangle();
44 | plot.addDataset(new Plottable.Dataset(data));
45 | plot.x(timeFormatStart, xScale)
46 | .y(function(d) { return d.team; }, yScale)
47 | .x2(timeFormatEnd)
48 | .attr("fill", function(d) { return d.fill; })
49 | .attr("stroke", function(d) { return d.stroke; });
50 |
51 | var table = new Plottable.Components.Table([[yAxis, plot],
52 | [null, xAxis]]);
53 | table.renderTo(svg);
54 | }
55 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/scatter_bar.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return [{company: "Amazon", overall: 0.37, leadership: 0.25},
4 | {company: "Apple", overall: 0.30, leadership: 0.28},
5 | {company: "Facebook", overall: 0.31, leadership: 0.23},
6 | {company: "Google", overall: 0.30, leadership: 0.21},
7 | {company: "Intel", overall: 0.24, leadership: 0.16},
8 | {company: "Microsoft", overall: 0.29, leadership: 0.17},
9 | {company: "Twitter", overall: 0.30, leadership: 0.21}];
10 | }
11 |
12 | function run(svg, data, Plottable) {
13 | "use strict";
14 |
15 | var xScale = new Plottable.Scales.Linear().domain([0, 0.50]);
16 | var yScale = new Plottable.Scales.Category();
17 |
18 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
19 | xAxis.formatter(Plottable.Formatters.percentage(0));
20 | var yAxis = new Plottable.Axes.Category(yScale, "left");
21 |
22 | var ds1 = new Plottable.Dataset(data);
23 | var ds2 = new Plottable.Dataset(data);
24 |
25 | var bars = new Plottable.Plots.Rectangle()
26 | .addDataset(ds1)
27 | .x(function (d) { return d.overall; }, xScale)
28 | .x2(function(d) { return d.leadership; })
29 | .y(function(d) { return d.company; }, yScale)
30 | .attr("fill", function() { return "#aaaaaa"; })
31 | .attr("height", function() { return 20; });
32 |
33 | yScale.innerPadding(2).outerPadding(0.5);
34 |
35 | var dots = new Plottable.Plots.Scatter()
36 | .addDataset(ds1)
37 | .addDataset(ds2)
38 | .x(function(d, i, ds) {
39 | if(ds === ds1){
40 | return d.overall;
41 | }
42 | else{
43 | return d.leadership;
44 | }
45 | }, xScale)
46 | .y(function(d) { return d.company; }, yScale)
47 | .attr("fill", function(d, i, ds) {
48 | if(ds === ds1){
49 | return "#000059";
50 | }
51 | else{
52 | return "#660066";
53 | }
54 | })
55 | .attr("opacity", function(){return 1; })
56 | .size(function(){ return yScale.rangeBand(); });
57 |
58 | var grid = new Plottable.Components.Gridlines(xScale, null);
59 |
60 | var plots = new Plottable.Components.Group([bars, dots, grid]);
61 | var chart = new Plottable.Components.Table([[yAxis, plots],
62 | [null, xAxis]]);
63 |
64 | chart.renderTo(svg);
65 | }
66 |
--------------------------------------------------------------------------------
/quicktests/overlaying/tests/realistic/vertical_line.js:
--------------------------------------------------------------------------------
1 | function makeData() {
2 | "use strict";
3 | return makeRandomData(20);
4 |
5 | }
6 |
7 | function run(svg, data, Plottable) {
8 | "use strict";
9 |
10 | var ds = new Plottable.Dataset(data);
11 |
12 | var customFormatter = function(d){
13 | return d.toFixed(2) + " units";
14 | };
15 |
16 | var xScale = new Plottable.Scales.Linear();
17 | var yScale = new Plottable.Scales.Linear();
18 | var xAxis = new Plottable.Axes.Numeric(xScale, "bottom")
19 | .formatter(customFormatter);
20 | var yAxis = new Plottable.Axes.Numeric(yScale, "left")
21 | .formatter(customFormatter);
22 |
23 | var plot = new Plottable.Plots.Line();
24 | plot.addDataset(ds);
25 | plot.x(function(d){ return d.y; }, xScale)
26 | .y(function(d){ return d.x; }, yScale);
27 | plot.autorangeMode("x")
28 | .autorangeSmooth(true);
29 |
30 | var sbl = new Plottable.Components.SelectionBoxLayer()
31 | .boxVisible(true)
32 | .xScale(xScale)
33 | .yScale(yScale)
34 | .xExtent([0.6, 1.0])
35 | .yExtent([0.3, 0.5]);
36 |
37 | var group = new Plottable.Components.Group([plot, sbl]);
38 |
39 | var table = new Plottable.Components.Table([[yAxis, group],
40 | [null, xAxis]]);
41 | table.renderTo(svg);
42 |
43 | var pzi = new Plottable.Interactions.PanZoom(null, yScale);
44 | pzi.attachTo(plot);
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/quicktests/umd/app.js:
--------------------------------------------------------------------------------
1 | /*eslint-env amd */
2 |
3 | require.config({
4 | paths: {
5 | d3: "../../node_modules/d3/d3",
6 | plottable: "../../plottable"
7 | }
8 | });
9 |
10 | require(["d3"], function(d3) {
11 | "use strict";
12 | require(["plottable"], function(Plottable) {
13 | var output = d3.select("#output");
14 | output.text(String(window.Plottable));
15 | output.style("background-color", window.Plottable ? "#F00" : "#0F0");
16 |
17 | var dataset1 = new Plottable.Dataset([
18 | { name: "A", value: 2 },
19 | { name: "B", value: 5 },
20 | { name: "C", value: 3 }
21 | ]);
22 |
23 | var xScale = new Plottable.Scales.Category();
24 | var xAxis = new Plottable.Axes.Category(xScale, "bottom");
25 | var yScale = new Plottable.Scales.Linear();
26 | var yAxis = new Plottable.Axes.Numeric(yScale, "left");
27 |
28 | var plot = new Plottable.Plots.Bar("vertical");
29 | plot.addDataset(dataset1);
30 | plot.x(function(d) { return d.name; }, xScale);
31 | plot.y(function(d) { return d.value; }, yScale);
32 |
33 | var chart = new Plottable.Components.Table([
34 | [yAxis, plot],
35 | [null, xAxis]
36 | ]);
37 | chart.renderTo(d3.select("#chart"));
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/quicktests/umd/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | RequireJS loading
5 |
6 |
11 |
12 |
13 |
14 |
15 |
16 | window.Plottable is (undefined expected)
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/scripts/authenticateNpm.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo "//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}" > .npmrc
4 | chmod 0600 .npmrc
5 |
--------------------------------------------------------------------------------
/scripts/publishSnapshot.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | GIT_DESCRIBE=`git describe --tags --match "*-dev"`
4 | # set package.json version
5 | npm --no-git-tag-version version $GIT_DESCRIBE
6 | yarn dist
7 | npm publish --tag next
8 |
--------------------------------------------------------------------------------
/scripts/submit-comment-with-artifact-links.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const bot = require("circle-github-bot").create();
4 |
5 | demos = [
6 | bot.artifactLink("quicktests/index.html", "quicktests"),
7 | bot.artifactLink("quicktests/fiddle.html", "fiddle"),
8 | ];
9 |
10 | bot.comment(process.env.GITHUB_API_TOKEN, `
11 | ${bot.commitMessage()}
12 | Demo: ${demos.join(" | ")}
13 | `);
14 |
--------------------------------------------------------------------------------
/src/animators/animator.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as d3 from "d3";
7 |
8 | import { AttributeToAppliedProjector, SimpleSelection } from "../core/interfaces";
9 |
10 | export interface IAnimator {
11 | /**
12 | * Applies the supplied attributes to a d3.Selection with some animation.
13 | *
14 | * @param {d3.Selection} selection The update selection or transition selection that we wish to animate.
15 | * @param {AttributeToAppliedProjector} attrToAppliedProjector The set of
16 | * AppliedProjectors that we will use to set attributes on the selection.
17 | * @return {any} Animators should return the selection or
18 | * transition object so that plots may chain the transitions between
19 | * animators.
20 | */
21 | animate(selection: SimpleSelection, attrToAppliedProjector: AttributeToAppliedProjector): SimpleSelection | d3.Transition;
22 |
23 | /**
24 | * Given the number of elements, return the total time the animation requires
25 | *
26 | * @param {number} numberofIterations The number of elements that will be drawn
27 | * @returns {number}
28 | */
29 | totalTime(numberOfIterations: number): number;
30 | }
31 |
--------------------------------------------------------------------------------
/src/animators/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export * from "./easingAnimator";
7 | export * from "./nullAnimator";
8 |
--------------------------------------------------------------------------------
/src/animators/nullAnimator.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { AttributeToAppliedProjector, SimpleSelection } from "../core/interfaces";
7 | import { coerceExternalD3 } from "../utils/coerceD3";
8 | import { IAnimator } from "./animator";
9 | /**
10 | * An animator implementation with no animation. The attributes are
11 | * immediately set on the selection.
12 | */
13 | export class Null implements IAnimator {
14 | public totalTime(selection: any) {
15 | return 0;
16 | }
17 |
18 | public animate(selection: SimpleSelection, attrToAppliedProjector: AttributeToAppliedProjector): SimpleSelection {
19 | selection = coerceExternalD3(selection);
20 | return selection.attrs(attrToAppliedProjector);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/axes/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export * from "./categoryAxis";
7 | export * from "./numericAxis";
8 | export * from "./timeAxis";
9 |
--------------------------------------------------------------------------------
/src/components/componentContainer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as d3 from "d3";
7 | import { coerceExternalD3 } from "../utils/coerceD3";
8 | import { Component, ComponentCallback } from "./component";
9 |
10 | /*
11 | * ComponentContainer class encapsulates Table and ComponentGroup's shared functionality.
12 | * It will not do anything if instantiated directly.
13 | */
14 | export class ComponentContainer extends Component {
15 | private _detachCallback: ComponentCallback;
16 |
17 | constructor() {
18 | super();
19 | this._detachCallback = (component: Component) => this.remove(component);
20 | }
21 |
22 | public anchor(selection: d3.Selection) {
23 | selection = coerceExternalD3(selection);
24 | super.anchor(selection);
25 | this._forEach((c) => c.anchor(this.element()));
26 | return this;
27 | }
28 |
29 | public render() {
30 | this._forEach((c) => c.render());
31 | return this;
32 | }
33 |
34 | /**
35 | * Checks whether the specified Component is in the ComponentContainer.
36 | */
37 | public has(component: Component): boolean {
38 | throw new Error("has() is not implemented on ComponentContainer");
39 | }
40 |
41 | protected _adoptAndAnchor(component: Component) {
42 | component.parent(this);
43 | component.onDetach(this._detachCallback);
44 | if (this._isAnchored) {
45 | component.anchor(this.element());
46 | }
47 | }
48 |
49 | /**
50 | * Removes the specified Component from the ComponentContainer.
51 | */
52 | public remove(component: Component) {
53 | if (this.has(component)) {
54 | component.offDetach(this._detachCallback);
55 | this._remove(component);
56 | component.detach();
57 | this.redraw();
58 | }
59 | return this;
60 | }
61 |
62 | /**
63 | * Carry out the actual removal of a Component.
64 | * Implementation dependent on the type of container.
65 | *
66 | * @return {boolean} true if the Component was successfully removed, false otherwise.
67 | */
68 | protected _remove(component: Component) {
69 | return false;
70 | }
71 |
72 | /**
73 | * Invokes a callback on each Component in the ComponentContainer.
74 | */
75 | protected _forEach(callback: (component: Component) => void) {
76 | throw new Error("_forEach() is not implemented on ComponentContainer");
77 | }
78 |
79 | /**
80 | * Destroys the ComponentContainer and all Components within it.
81 | */
82 | public destroy() {
83 | super.destroy();
84 | this._forEach((c: Component) => c.destroy());
85 | }
86 |
87 | public invalidateCache() {
88 | this._forEach((c: Component) => c.invalidateCache());
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/components/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export * from "./dragBoxLayer";
7 | export * from "./dragLineLayer";
8 | export * from "./gridlines";
9 | export * from "./group";
10 | export * from "./guideLineLayer";
11 | export * from "./interpolatedColorLegend";
12 | export * from "./label";
13 | export * from "./legend";
14 | export * from "./plotGroup";
15 | export * from "./selectionBoxLayer";
16 | export * from "./table";
17 | export * from "./wrappedLabel";
18 | export * from "./xDragBoxLayer";
19 | export * from "./yDragBoxLayer";
20 |
--------------------------------------------------------------------------------
/src/components/plotGroup.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { Point } from "../core/interfaces";
7 | import * as Plots from "../plots";
8 | import { Plot } from "../plots/plot";
9 | import * as Utils from "../utils";
10 |
11 | import { Component } from "./component";
12 | import { Group } from "./group";
13 |
14 | export class PlotGroup extends Group {
15 | public entityNearest(point: Point): Plots.IPlotEntity {
16 | let closestPlotEntity: Plots.IPlotEntity;
17 | let minDistSquared = Infinity;
18 | this.components().forEach((plotComponent: Component) => {
19 | // we know it's a Plot since .append() throws a runtime error otherwise
20 | const plot: Plot = plotComponent;
21 | const candidatePlotEntity = plot.entityNearest(point);
22 | if (candidatePlotEntity == null) {
23 | return;
24 | }
25 |
26 | const distSquared = Utils.Math.distanceSquared(candidatePlotEntity.position, point);
27 | if (distSquared <= minDistSquared) {
28 | minDistSquared = distSquared;
29 | closestPlotEntity = candidatePlotEntity;
30 | }
31 | });
32 |
33 | return closestPlotEntity;
34 | }
35 |
36 | /**
37 | * Adds a Plot to this Plot Group.
38 | * The added Plot will be rendered above Plots already in the Group.
39 | */
40 | public append(plot: Component): this {
41 | if (plot != null && !(plot instanceof Plot)) {
42 | throw new Error("Plot Group only accepts plots");
43 | }
44 | super.append(plot);
45 | return this;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/wrappedLabel.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { SpaceRequest } from "../core/interfaces";
7 | import { Label } from "./label";
8 |
9 | const DEFAULT_MAX_LINES = 2;
10 |
11 | export class WrappedLabel extends Label {
12 | protected _maxLines: number = DEFAULT_MAX_LINES;
13 |
14 | public requestedSpace(offeredWidth: number, offeredHeight: number): SpaceRequest {
15 | this._wrapper.maxLines(this._maxLines);
16 | let offeredLineLength = this.angle() === 0 ? offeredWidth : offeredHeight;
17 | if (offeredLineLength === 0) {
18 | offeredLineLength = Infinity;
19 | }
20 | const wrapped = this._wrapper.wrap(this._text, this._measurer, offeredLineLength);
21 | const measuredWrap = this._measurer.measure(wrapped.wrappedText);
22 | const minWidth = (this.angle() === 0 ? measuredWrap.width : measuredWrap.height) + 2 * this.padding();
23 | const minHeight = (this.angle() === 0 ? measuredWrap.height : measuredWrap.width) + 2 * this.padding();
24 | return { minWidth, minHeight };
25 | }
26 |
27 | /**
28 | * Get the label max number of wrapped lines.
29 | */
30 | public maxLines(): number;
31 | /**
32 | * Set the label's max number of wrapped lines.
33 | * @param maxLines
34 | */
35 | public maxLines(maxLines: number): this;
36 | public maxLines(maxLines?: number): number | this {
37 | // allow user to un-set by passing in null or undefined explicitly
38 | if (arguments.length === 0) {
39 | return this._maxLines;
40 | }
41 | this._maxLines = maxLines;
42 | this.redraw();
43 | return this;
44 | }
45 | }
--------------------------------------------------------------------------------
/src/components/xDragBoxLayer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { Bounds, Point } from "../core/interfaces";
7 | import { QuantitativeScale } from "../scales/quantitativeScale";
8 |
9 | import { DragBoxLayer } from "./dragBoxLayer";
10 |
11 | export class XDragBoxLayer extends DragBoxLayer {
12 | /**
13 | * An XDragBoxLayer is a DragBoxLayer whose size can only be set in the X-direction.
14 | * The y-values of the bounds() are always set to 0 and the height() of the XDragBoxLayer.
15 | *
16 | * @constructor
17 | */
18 | constructor() {
19 | super();
20 | this.addClass("x-drag-box-layer");
21 | this._hasCorners = false;
22 | }
23 |
24 | public computeLayout(origin?: Point, availableWidth?: number, availableHeight?: number) {
25 | super.computeLayout(origin, availableWidth, availableHeight);
26 | // set correct bounds when width/height changes
27 | this._setBounds(this.bounds());
28 | return this;
29 | }
30 |
31 | protected _setBounds(newBounds: Bounds) {
32 | super._setBounds({
33 | topLeft: { x: newBounds.topLeft.x, y: 0 },
34 | bottomRight: { x: newBounds.bottomRight.x, y: this.height() },
35 | });
36 | }
37 |
38 | protected _setResizableClasses(canResize: boolean) {
39 | if (canResize && this.enabled()) {
40 | this.addClass("x-resizable");
41 | } else {
42 | this.removeClass("x-resizable");
43 | }
44 | }
45 |
46 | public yScale(): QuantitativeScale;
47 | public yScale(yScale: QuantitativeScale): this;
48 | public yScale(yScale?: QuantitativeScale): any {
49 | if (yScale == null) {
50 | return super.yScale();
51 | }
52 | throw new Error("yScales cannot be set on an XDragBoxLayer");
53 | }
54 |
55 | public yExtent(): (number | { valueOf(): number })[];
56 | public yExtent(yExtent: (number | { valueOf(): number })[]): this;
57 | public yExtent(yExtent?: (number | { valueOf(): number })[]): any {
58 | if (yExtent == null) {
59 | return super.yExtent();
60 | }
61 | throw new Error("XDragBoxLayer has no yExtent");
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/components/yDragBoxLayer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { Bounds, Point } from "../core/interfaces";
7 | import { QuantitativeScale } from "../scales/quantitativeScale";
8 |
9 | import { DragBoxLayer } from "./dragBoxLayer";
10 |
11 | export class YDragBoxLayer extends DragBoxLayer {
12 | /**
13 | * A YDragBoxLayer is a DragBoxLayer whose size can only be set in the Y-direction.
14 | * The x-values of the bounds() are always set to 0 and the width() of the YDragBoxLayer.
15 | *
16 | * @constructor
17 | */
18 | constructor() {
19 | super();
20 | this.addClass("y-drag-box-layer");
21 | this._hasCorners = false;
22 | }
23 |
24 | public computeLayout(origin?: Point, availableWidth?: number, availableHeight?: number) {
25 | super.computeLayout(origin, availableWidth, availableHeight);
26 | // set correct bounds when width/height changes
27 | this._setBounds(this.bounds());
28 | return this;
29 | }
30 |
31 | protected _setBounds(newBounds: Bounds) {
32 | super._setBounds({
33 | topLeft: { x: 0, y: newBounds.topLeft.y },
34 | bottomRight: { x: this.width(), y: newBounds.bottomRight.y },
35 | });
36 | }
37 |
38 | protected _setResizableClasses(canResize: boolean) {
39 | if (canResize && this.enabled()) {
40 | this.addClass("y-resizable");
41 | } else {
42 | this.removeClass("y-resizable");
43 | }
44 | }
45 |
46 | public xScale(): QuantitativeScale;
47 | public xScale(xScale: QuantitativeScale): this;
48 | public xScale(xScale?: QuantitativeScale): any {
49 | if (xScale == null) {
50 | return super.xScale();
51 | }
52 | throw new Error("xScales cannot be set on an YDragBoxLayer");
53 | }
54 |
55 | public xExtent(): (number | { valueOf(): number })[];
56 | public xExtent(xExtent: (number | { valueOf(): number })[]): this;
57 | public xExtent(xExtent?: (number | { valueOf(): number })[]): any {
58 | if (xExtent == null) {
59 | return super.xExtent();
60 | }
61 | throw new Error("YDragBoxLayer has no xExtent");
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/core/config.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | /**
7 | * Specifies if Plottable should show warnings.
8 | */
9 | export let SHOW_WARNINGS = true;
10 |
11 | /**
12 | * Specifies if Plottable should add elements to text.
13 | */
14 | export let ADD_TITLE_ELEMENTS = true;
15 |
--------------------------------------------------------------------------------
/src/core/renderPolicy.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as Utils from "../utils";
7 |
8 | import * as RenderController from "./renderController";
9 |
10 | /**
11 | * A policy for rendering Components.
12 | */
13 | export interface IRenderPolicy {
14 | render(): any;
15 | }
16 |
17 | /**
18 | * Renders Components immediately after they are enqueued.
19 | * Useful for debugging, horrible for performance.
20 | */
21 | export class Immediate implements IRenderPolicy {
22 | public render() {
23 | RenderController.flush();
24 | }
25 | }
26 |
27 | /**
28 | * The default way to render, which only tries to render every frame
29 | * (usually, 1/60th of a second).
30 | */
31 | export class AnimationFrame implements IRenderPolicy {
32 | public render() {
33 | Utils.DOM.requestAnimationFramePolyfill(RenderController.flush);
34 | }
35 | }
36 |
37 | /**
38 | * Renders with `setTimeout()`.
39 | * Generally an inferior way to render compared to `requestAnimationFrame`,
40 | * but useful for browsers that don't suppoort `requestAnimationFrame`.
41 | */
42 | export class Timeout implements IRenderPolicy {
43 | private _timeoutMsec: number = Utils.DOM.SCREEN_REFRESH_RATE_MILLISECONDS;
44 |
45 | public render() {
46 | setTimeout(RenderController.flush, this._timeoutMsec);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/core/symbolFactories.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as d3 from "d3";
7 | import * as d3Shape from "d3-shape";
8 |
9 | /**
10 | * A SymbolFactory is a function that takes in a symbolSize which is the edge length of the render area
11 | * and returns a d3 symbol generator.
12 | */
13 | export type SymbolFactory = (symbolSize: number) => d3Shape.Symbol;
14 |
15 | export function circle(): SymbolFactory {
16 | return (symbolSize: number) => {
17 | return d3.symbol().type(d3.symbolCircle).size(Math.PI * Math.pow(symbolSize / 2, 2));
18 | };
19 | }
20 |
21 | export function square(): SymbolFactory {
22 | return (symbolSize: number) => {
23 | return d3.symbol().type(d3.symbolSquare).size(Math.pow(symbolSize, 2));
24 | };
25 | }
26 |
27 | export function cross(): SymbolFactory {
28 | return (symbolSize: number) => {
29 | return d3.symbol().type(d3.symbolCross).size((5 / 9) * Math.pow(symbolSize, 2));
30 | };
31 | }
32 |
33 | export function diamond(): SymbolFactory {
34 | return (symbolSize: number) => {
35 | return d3.symbol().type(d3.symbolDiamond).size(Math.tan(Math.PI / 6) * Math.pow(symbolSize, 2) / 2);
36 | };
37 | }
38 |
39 | export function triangle(): SymbolFactory {
40 | return (symbolSize: number) => {
41 | return d3.symbol().type(d3.symbolTriangle).size(Math.sqrt(3) * Math.pow(symbolSize / 2, 2));
42 | };
43 | }
44 |
45 | // copied from https://github.com/d3/d3-shape/blob/e2e57722004acba754ed9edff020282682450c5c/src/symbol/star.js#L3
46 | const ka = 0.89081309152928522810;
47 | export function star(): SymbolFactory {
48 | return (symbolSize: number) => {
49 | return d3.symbol().type(d3.symbolStar).size(ka * Math.pow(symbolSize / 2, 2));
50 | };
51 | }
52 |
53 | // copied from https://github.com/d3/d3-shape/blob/c35b2303eb4836aba3171642f01c2653e4228b9c/src/symbol/wye.js#L2
54 | const a = ((1 / Math.sqrt(12)) / 2 + 1) * 3;
55 | export function wye(): SymbolFactory {
56 | return (symbolSize: number) => {
57 | return d3.symbol().type(d3.symbolWye).size(a * Math.pow(symbolSize / 2.4, 2));
58 | };
59 | }
60 |
--------------------------------------------------------------------------------
/src/core/version.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | // __VERSION__ is a global constant which will be replaced by webpack's DefinePlugin
7 | declare var __VERSION__: string;
8 |
9 | /*
10 | * WARNING: The js output of this expression is searched by string (yes, I know) and replaced with a
11 | * real version number during the dist phase for for npm module publishing. Modifying this line should
12 | * be accompanied by modifying the "sed-version" task in package.json accordingly.
13 | */
14 | export let version = __VERSION__;
15 |
--------------------------------------------------------------------------------
/src/dispatchers/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export * from "./keyDispatcher";
7 | export * from "./mouseDispatcher";
8 | export * from "./touchDispatcher";
9 |
--------------------------------------------------------------------------------
/src/drawers/arcDrawer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { SimpleSelection } from "../core/interfaces";
7 |
8 | import { SVGDrawer } from "./svgDrawer";
9 |
10 | export class ArcSVGDrawer extends SVGDrawer {
11 |
12 | constructor() {
13 | super("path", "arc fill");
14 | }
15 |
16 | protected _applyDefaultAttributes(selection: SimpleSelection) {
17 | selection.style("stroke", "none");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/drawers/arcOutlineDrawer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { SimpleSelection } from "../core/interfaces";
7 | import { SVGDrawer } from "./svgDrawer";
8 |
9 | export class ArcOutlineSVGDrawer extends SVGDrawer {
10 |
11 | constructor() {
12 | super("path", "arc outline");
13 | }
14 |
15 | protected _applyDefaultAttributes(selection: SimpleSelection) {
16 | selection.style("fill", "none");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/drawers/areaDrawer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { AttributeToAppliedProjector, SimpleSelection } from "../core/interfaces";
7 | import { CanvasDrawStep, renderArea, renderLine, resolveAttributes } from "./canvasDrawer";
8 | import { SVGDrawer } from "./svgDrawer";
9 |
10 | export class AreaSVGDrawer extends SVGDrawer {
11 | constructor() {
12 | super("path", "area");
13 | }
14 |
15 | protected _applyDefaultAttributes(selection: SimpleSelection) {
16 | selection.style("stroke", "none");
17 | }
18 |
19 | public getVisualPrimitiveAtIndex(index: number) {
20 | // areas are represented by one single element; always get that element
21 | // regardless of the data index.
22 | return super.getVisualPrimitiveAtIndex(0);
23 | }
24 | }
25 |
26 | const AREA_FILL_ATTRS = [ "opacity", "fill", "fill-opacity" ];
27 | const AREA_STROKE_ATTRS = ["opacity", "stroke", "stroke-width"];
28 |
29 | export function makeAreaCanvasDrawStep(
30 | d3AreaFactory: () => d3.Area,
31 | d3LineFactory: () => d3.Line,
32 | ): CanvasDrawStep {
33 | return (context: CanvasRenderingContext2D, data: any[][], projector: AttributeToAppliedProjector) => {
34 | const fillAttrs = resolveAttributes(projector, AREA_FILL_ATTRS, data[0], 0);
35 | renderArea(context, d3AreaFactory(), data[0], fillAttrs);
36 | const strokeAttrs = resolveAttributes(projector, AREA_STROKE_ATTRS, data[0], 0);
37 | renderLine(context, d3LineFactory(), data[0], strokeAttrs);
38 | };
39 | }
40 |
--------------------------------------------------------------------------------
/src/drawers/drawStep.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { IAnimator } from "../animators/animator";
7 | import { AttributeToAppliedProjector, AttributeToProjector } from "../core/interfaces";
8 |
9 | /**
10 | * A step for the drawer to draw.
11 | *
12 | * Specifies how AttributeToProjector needs to be animated.
13 | */
14 | export type DrawStep = {
15 | attrToProjector: AttributeToProjector;
16 | animator: IAnimator;
17 | };
18 |
19 | /**
20 | * A DrawStep that carries an AttributeToAppliedProjector map.
21 | */
22 | export type AppliedDrawStep = {
23 | attrToAppliedProjector: AttributeToAppliedProjector;
24 | animator: IAnimator;
25 | };
26 |
--------------------------------------------------------------------------------
/src/drawers/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export * from "./arcDrawer";
7 | export * from "./arcOutlineDrawer";
8 | export * from "./areaDrawer";
9 | export * from "./canvasDrawer";
10 | export * from "./drawer";
11 | export * from "./drawStep";
12 | export * from "./lineDrawer";
13 | export * from "./rectangleDrawer";
14 | export * from "./segmentDrawer";
15 | export * from "./svgDrawer";
16 | export * from "./symbolDrawer";
17 |
--------------------------------------------------------------------------------
/src/drawers/lineDrawer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as d3 from "d3";
7 | import { AttributeToAppliedProjector, SimpleSelection } from "../core/interfaces";
8 | import { CanvasDrawStep, renderLine, resolveAttributes } from "./canvasDrawer";
9 | import { SVGDrawer } from "./svgDrawer";
10 |
11 | export class LineSVGDrawer extends SVGDrawer {
12 | constructor() {
13 | super("path", "line");
14 | }
15 |
16 | protected _applyDefaultAttributes(selection: SimpleSelection) {
17 | selection.style("fill", "none");
18 | }
19 |
20 | public getVisualPrimitiveAtIndex(index: number) {
21 | return super.getVisualPrimitiveAtIndex(0);
22 | }
23 | }
24 |
25 | const LINE_ATTRIBUTES = [
26 | "opacity",
27 | "stroke-opacity",
28 | "stroke-width",
29 | "stroke",
30 | "stroke-dasharray",
31 | ];
32 |
33 | /**
34 | * @param d3LineFactory A callback that gives this Line Drawer a d3.Line object which will be
35 | * used to draw with.
36 | *
37 | * TODO put the d3.Line into the attrToAppliedProjector directly
38 | */
39 | export function makeLineCanvasDrawStep(d3LineFactory: () => d3.Line): CanvasDrawStep {
40 | return (context: CanvasRenderingContext2D, data: any[][], attrToAppliedProjector: AttributeToAppliedProjector) => {
41 | const lineStyle = resolveAttributes(attrToAppliedProjector, LINE_ATTRIBUTES, data[0], 0);
42 | renderLine(context, d3LineFactory(), data[0], lineStyle);
43 | };
44 | }
45 |
--------------------------------------------------------------------------------
/src/drawers/rectangleDrawer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import {
7 | CanvasDrawer,
8 | CanvasDrawStep,
9 | ContextStyleAttrs,
10 | renderPathWithStyle,
11 | resolveAttributes,
12 | } from "./canvasDrawer";
13 |
14 | import { AttributeToAppliedProjector } from "../core/interfaces";
15 | import { SVGDrawer } from "./svgDrawer";
16 |
17 | export class RectangleSVGDrawer extends SVGDrawer {
18 | constructor(private _rootClassName: string = "") {
19 | super("rect", "");
20 | this._root.classed(this._rootClassName, true);
21 | }
22 | }
23 |
24 | const RECT_ATTRS = ContextStyleAttrs.concat(["x", "y", "width", "height"]);
25 |
26 | export const RectangleCanvasDrawStep: CanvasDrawStep = (
27 | context: CanvasRenderingContext2D,
28 | data: any[],
29 | projector: AttributeToAppliedProjector) => {
30 | context.save();
31 | const dataLen = data.length;
32 | for (let index = 0; index < dataLen; index++ ) {
33 | const datum = data[index];
34 | if (datum == null) {
35 | continue;
36 | }
37 | const attrs = resolveAttributes(projector, RECT_ATTRS, datum, index);
38 | context.beginPath();
39 | context.rect(attrs["x"], attrs["y"], attrs["width"], attrs["height"]);
40 | renderPathWithStyle(context, attrs);
41 | }
42 | context.restore();
43 | };
44 |
45 | export class RectangleCanvasDrawer extends CanvasDrawer {
46 | constructor(ctx: CanvasRenderingContext2D) {
47 | super(ctx, RectangleCanvasDrawStep);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/drawers/segmentDrawer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { SVGDrawer } from "./svgDrawer";
7 |
8 | export class SegmentSVGDrawer extends SVGDrawer {
9 | constructor() {
10 | super("line", "");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | // HACKHACK d3-selection-multi doesn't play well with default "d3" package in a
2 | // bundler environment (e.g. webpack) - see https://github.com/d3/d3-selection-multi/issues/11
3 | // we add it manually to the default "d3" bundle
4 | import "./utils/addD3SelectionMulti";
5 |
6 | import * as Animators from "./animators";
7 | import * as Axes from "./axes";
8 | import * as Components from "./components";
9 | import * as Configs from "./core/config";
10 | import * as Formatters from "./core/formatters";
11 | import * as RenderController from "./core/renderController";
12 | import * as RenderPolicies from "./core/renderPolicy";
13 | import * as SymbolFactories from "./core/symbolFactories";
14 | import * as Dispatchers from "./dispatchers";
15 | import * as Drawers from "./drawers";
16 | import * as Interactions from "./interactions";
17 | import * as Plots from "./plots";
18 | import * as Scales from "./scales";
19 | import * as Utils from "./utils";
20 |
21 | export {
22 | Animators,
23 | Axes,
24 | Components,
25 | Configs,
26 | Formatters,
27 | RenderController,
28 | RenderPolicies,
29 | SymbolFactories,
30 | Dispatchers,
31 | Drawers,
32 | Interactions,
33 | Plots,
34 | Scales,
35 | Utils,
36 | };
37 |
38 | export * from "./animators/animator";
39 |
40 | export * from "./axes/axis";
41 | export { TimeInterval } from "./axes/timeAxis";
42 |
43 | export * from "./components/component";
44 | export * from "./components/componentContainer";
45 | export { DragBoxCallback } from "./components/dragBoxLayer";
46 | export { IDragLineCallback } from "./components/dragLineLayer";
47 |
48 | export * from "./core/dataset";
49 | export { Formatter, DatumFormatter } from "./core/formatters";
50 | export * from "./core/interfaces";
51 | export { SymbolFactory } from "./core/symbolFactories";
52 | export { version } from "./core/version";
53 |
54 | export * from "./dispatchers/dispatcher";
55 |
56 | export * from "./drawers/drawer";
57 |
58 | export { ClickCallback } from "./interactions/clickInteraction";
59 | export { DragCallback } from "./interactions/dragInteraction";
60 | export * from "./interactions/interaction";
61 | export * from "./interactions/keyInteraction";
62 | export { PointerCallback } from "./interactions/pointerInteraction";
63 |
64 | export * from "./plots/xyPlot";
65 | export * from "./plots/plot";
66 |
67 | export * from "./scales/quantitativeScale";
68 | export * from "./scales/scale";
69 |
--------------------------------------------------------------------------------
/src/interactions/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export * from "./clickInteraction";
7 | export * from "./dragInteraction";
8 | export * from "./keyInteraction";
9 | export * from "./panZoomInteraction";
10 | export * from "./pointerInteraction";
11 | export {zoomOut} from "./panZoomConstraints";
12 |
--------------------------------------------------------------------------------
/src/memoize/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export * from "./memoize";
7 | export * from "./memoizeProjectors";
8 | export * from "./memThunk";
9 | export { sign } from "./signature";
10 |
--------------------------------------------------------------------------------
/src/memoize/memThunk.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | * @fileoverview Implements a convenient thunk function to handle the common case
5 | * of creating a memoized function that takes its inputs from mutable class properties.
6 | */
7 |
8 | import { memoize, MemoizedFunction } from "./index";
9 | export type Thunk = () => R;
10 |
11 | export function memThunk(
12 | arg1: Thunk,
13 | compute: (this: void, arg1: I1) => O,
14 | ): MemoizedFunction>;
15 | export function memThunk(
16 | arg1: Thunk,
17 | arg2: Thunk,
18 | compute: (this: void, arg1: I1, arg2: I2) => O,
19 | ): MemoizedFunction>;
20 | export function memThunk(
21 | arg1: Thunk,
22 | arg2: Thunk,
23 | arg3: Thunk,
24 | compute: (this: void, arg1: I1, arg2: I2, arg3: I3) => O,
25 | ): MemoizedFunction>;
26 | export function memThunk(
27 | arg1: Thunk,
28 | arg2: Thunk,
29 | arg3: Thunk,
30 | arg4: Thunk,
31 | compute: (this: void, arg1: I1, arg2: I2, arg3: I3, arg4: I4) => O,
32 | ): MemoizedFunction>;
33 |
34 | /**
35 | * First pass argument thunks that will be evaluated whenever the memThunk
36 | * is accessed. This should be fast and simple.
37 | *
38 | * Then pass a pure function that, when given the argument thunks' values,
39 | * will output some computed value. It should not use `this` in the body.
40 | *
41 | * We memoize and return this pure function.
42 | *
43 | * This way, memThunk lets you implement a performant, always-up-to-date "computed"
44 | * value getter.
45 | */
46 | export function memThunk(...argsAndCompute: Function[]): Thunk {
47 | const inputs = argsAndCompute.slice(0, -1);
48 | const compute = argsAndCompute[argsAndCompute.length - 1];
49 | const memoizedCompute = memoize(compute);
50 | const memoizedThunk = function () {
51 | const inputEval = inputs.map((inputFn) => inputFn.apply(this));
52 | return memoizedCompute.apply(undefined, inputEval);
53 | };
54 | return memoizedThunk;
55 | }
56 |
--------------------------------------------------------------------------------
/src/plots/clusteredBarPlot.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { Dataset } from "../core/dataset";
7 | import * as Scales from "../scales";
8 | import * as Utils from "../utils";
9 |
10 | import { Bar, BarOrientation } from "./barPlot";
11 | import { Plot } from "./plot";
12 |
13 | export class ClusteredBar extends Bar {
14 |
15 | private _clusterOffsets: Utils.Map;
16 |
17 | /**
18 | * A ClusteredBar Plot groups bars across Datasets based on the primary value of the bars.
19 | * On a vertical ClusteredBar Plot, the bars with the same X value are grouped.
20 | * On a horizontal ClusteredBar Plot, the bars with the same Y value are grouped.
21 | *
22 | * @constructor
23 | * @param {string} [orientation="vertical"] One of "vertical"/"horizontal".
24 | */
25 | constructor(orientation: BarOrientation = "vertical") {
26 | super(orientation);
27 | this._clusterOffsets = new Utils.Map();
28 | }
29 |
30 | protected _generateAttrToProjector() {
31 | const attrToProjector = super._generateAttrToProjector();
32 | // the width is constant, so set the inner scale range to that
33 | const innerScale = this._makeInnerScale();
34 | const innerWidthF = (d: any, i: number) => innerScale.rangeBand();
35 | attrToProjector["width"] = this._isVertical ? innerWidthF : attrToProjector["width"];
36 | attrToProjector["height"] = !this._isVertical ? innerWidthF : attrToProjector["height"];
37 |
38 | const xAttr = attrToProjector["x"];
39 | const yAttr = attrToProjector["y"];
40 | attrToProjector["x"] = this._isVertical ?
41 | (d: any, i: number, ds: Dataset) => xAttr(d, i, ds) + this._clusterOffsets.get(ds) :
42 | (d: any, i: number, ds: Dataset) => xAttr(d, i, ds);
43 | attrToProjector["y"] = this._isVertical ?
44 | (d: any, i: number, ds: Dataset) => yAttr(d, i, ds) :
45 | (d: any, i: number, ds: Dataset) => yAttr(d, i, ds) + this._clusterOffsets.get(ds);
46 |
47 | return attrToProjector;
48 | }
49 |
50 | private _updateClusterPosition() {
51 | const innerScale = this._makeInnerScale();
52 | this.datasets().forEach((d, i) => this._clusterOffsets.set(d, innerScale.scale(String(i)) - innerScale.rangeBand() / 2));
53 | }
54 |
55 | private _makeInnerScale() {
56 | const innerScale = new Scales.Category();
57 | innerScale.domain(this.datasets().map((d, i) => String(i)));
58 | const widthProjector = Plot._scaledAccessor(this.attr(Bar._BAR_THICKNESS_KEY));
59 | innerScale.range([0, widthProjector(null, 0, null)]);
60 | return innerScale;
61 | }
62 |
63 | protected _getDataToDraw(): Utils.Map {
64 | this._updateClusterPosition();
65 | return super._getDataToDraw();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/plots/commons.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { Dataset } from "../core/dataset";
7 | import { IAccessor, IEntity, IRangeProjector, Point } from "../core/interfaces";
8 | import { IDrawer } from "../drawers/drawer";
9 | import { Plot } from "../plots/plot";
10 | import { Scale, TransformableScale } from "../scales/scale";
11 |
12 | /**
13 | * Computing the selection of an entity is an expensive operation. This object aims to
14 | * reproduce the behavior of the Plots.PlotEntity, excluding the selection, but including
15 | * drawer and validDatumIndex, which can be used to compute the selection.
16 | */
17 | export interface ILightweightPlotEntity {
18 | datum: any;
19 | dataset: Dataset;
20 | datasetIndex: number;
21 | position: Point;
22 | index: number;
23 | component: Plot;
24 | drawer: IDrawer;
25 | validDatumIndex: number;
26 | }
27 |
28 | export interface IPlotEntity extends IEntity {
29 | dataset: Dataset;
30 | datasetIndex: number;
31 | index: number;
32 | component: Plot;
33 | }
34 |
35 | export interface IAccessorScaleBinding {
36 | /**
37 | * The (possibly upcasted to a function) user defined accessor.
38 | *
39 | * The first argument in `plot.x((d) => d.x, scale)`.
40 | */
41 | accessor: IAccessor;
42 |
43 | /**
44 | * The Scale that the accessor's result gets passed through.
45 | *
46 | * The second argument in `plot.x((d) => d.x, scale)`.
47 | */
48 | scale?: Scale;
49 |
50 | /**
51 | * Transforms the scaled result of the accessor.
52 | *
53 | * Normally, the accessors ,`(d) => d.x`, will be wrapped like
54 | * `scale.scale((d) => d.x)`. But, this is not sufficient if you want to
55 | * modify the scaled value.
56 | *
57 | * However, moving the scale inside the accessor prevents several useful
58 | * features from working properly (including `computeExtents`, `entityNearest`
59 | * and `deferredRendering`). So, you may optionally provide this projector
60 | * which, if present, will be applied to the scaled accessor result.
61 | * */
62 | postScale?: IRangeProjector;
63 | }
64 |
65 | /**
66 | * TransformableAccessorScaleBinding mapping from property accessor to
67 | * TransformableScale. It is distinct from a plain AccessorScaleBinding
68 | * in that the scale is guaranteed to be invertable.
69 | */
70 | export interface ITransformableAccessorScaleBinding {
71 | accessor: IAccessor;
72 | scale?: TransformableScale;
73 | postScale?: IRangeProjector;
74 | }
75 |
76 | export namespace Animator {
77 | export let MAIN = "main";
78 | export let RESET = "reset";
79 | }
80 |
--------------------------------------------------------------------------------
/src/plots/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export * from "./areaPlot";
7 | export * from "./barPlot";
8 | export * from "./commons";
9 | export * from "./clusteredBarPlot";
10 | export * from "./linePlot";
11 | export * from "./piePlot";
12 | export * from "./rectanglePlot";
13 | export * from "./scatterPlot";
14 | export * from "./segmentPlot";
15 | export * from "./stackedAreaPlot";
16 | export * from "./stackedBarPlot";
17 | export * from "./waterfallPlot";
18 |
--------------------------------------------------------------------------------
/src/scales/linearScale.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as d3 from "d3";
7 |
8 | import { QuantitativeScale } from "./quantitativeScale";
9 |
10 | export class Linear extends QuantitativeScale {
11 | private _d3Scale: d3.ScaleLinear;
12 |
13 | /**
14 | * @constructor
15 | */
16 | constructor() {
17 | super();
18 | this._d3Scale = d3.scaleLinear();
19 | }
20 |
21 | protected _defaultExtent(): number[] {
22 | return [0, 1];
23 | }
24 |
25 | protected _expandSingleValueDomain(singleValueDomain: number[]) {
26 | if (singleValueDomain[0] === singleValueDomain[1]) {
27 | return [singleValueDomain[0] - 1, singleValueDomain[1] + 1];
28 | }
29 | return singleValueDomain;
30 | }
31 |
32 | public scale(value: number) {
33 | return this._d3Scale(value);
34 | }
35 |
36 | public scaleTransformation(value: number) {
37 | return this.scale(value);
38 | }
39 |
40 | public invertedTransformation(value: number) {
41 | return this.invert(value);
42 | }
43 |
44 | public getTransformationExtent() {
45 | return this._getUnboundedExtent(true) as [number, number];
46 | }
47 |
48 | public getTransformationDomain() {
49 | return this.domain() as [number, number];
50 | }
51 |
52 | public setTransformationDomain(domain: [number, number]) {
53 | this.domain(domain);
54 | }
55 |
56 | protected _getDomain() {
57 | return this._backingScaleDomain();
58 | }
59 |
60 | protected _backingScaleDomain(): number[];
61 | protected _backingScaleDomain(values: number[]): this;
62 | protected _backingScaleDomain(values?: number[]): any {
63 | if (values == null) {
64 | return this._d3Scale.domain();
65 | } else {
66 | this._d3Scale.domain(values);
67 | return this;
68 | }
69 | }
70 |
71 | protected _getRange() {
72 | return this._d3Scale.range();
73 | }
74 |
75 | protected _setRange(values: number[]) {
76 | this._d3Scale.range(values);
77 | }
78 |
79 | public invert(value: number) {
80 | return this._d3Scale.invert(value);
81 | }
82 |
83 | public defaultTicks(): number[] {
84 | return this._d3Scale.ticks(Linear._DEFAULT_NUM_TICKS);
85 | }
86 |
87 | protected _niceDomain(domain: number[], count?: number): number[] {
88 | return this._d3Scale.copy().domain(domain).nice(count).domain();
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/scales/logScale.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as d3 from "d3";
7 |
8 | import { QuantitativeScale } from "./quantitativeScale";
9 |
10 | export class Log extends QuantitativeScale {
11 | private _d3Scale: d3.ScaleLogarithmic;
12 |
13 | /**
14 | * @constructor
15 | */
16 | constructor(base = 10) {
17 | super();
18 | this._d3Scale = d3.scaleLog().base(base);
19 | this._setDomain(this._defaultExtent());
20 | }
21 |
22 | protected _defaultExtent(): number[] {
23 | return [1, this._d3Scale.base()];
24 | }
25 |
26 | protected _expandSingleValueDomain(singleValueDomain: number[]) {
27 | if (singleValueDomain[0] === singleValueDomain[1]) {
28 | return [singleValueDomain[0]/this._d3Scale.base(),
29 | singleValueDomain[1]*this._d3Scale.base()];
30 | }
31 | return singleValueDomain;
32 | }
33 |
34 | public scale(value: number) {
35 | return this._d3Scale(value);
36 | }
37 |
38 | public scaleTransformation(value: number) {
39 | return this.scale(value);
40 | }
41 |
42 | public invertedTransformation(value: number) {
43 | return this.invert(value);
44 | }
45 |
46 | public getTransformationExtent() {
47 | return this._getUnboundedExtent(true) as [number, number];
48 | }
49 |
50 | public getTransformationDomain() {
51 | return this.domain() as [number, number];
52 | }
53 |
54 | public setTransformationDomain(domain: [number, number]) {
55 | this.domain(domain);
56 | }
57 |
58 | protected _getDomain() {
59 | return this._backingScaleDomain();
60 | }
61 |
62 | protected _backingScaleDomain(): number[];
63 | protected _backingScaleDomain(values: number[]): this;
64 | protected _backingScaleDomain(values?: number[]): any {
65 | if (values == null) {
66 | return this._d3Scale.domain();
67 | } else {
68 | this._d3Scale.domain(values);
69 | return this;
70 | }
71 | }
72 |
73 | protected _getRange() {
74 | return this._d3Scale.range();
75 | }
76 |
77 | protected _setRange(values: number[]) {
78 | this._d3Scale.range(values);
79 | }
80 |
81 | public invert(value: number) {
82 | return this._d3Scale.invert(value);
83 | }
84 |
85 | public defaultTicks(): number[] {
86 | return this._d3Scale.ticks(Log._DEFAULT_NUM_TICKS);
87 | }
88 |
89 | protected _niceDomain(domain: number[], count?: number): number[] {
90 | return this._d3Scale.copy().domain(domain).nice().domain();
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/scales/tickGenerators.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { QuantitativeScale } from "../scales/quantitativeScale";
7 | import * as Utils from "../utils";
8 |
9 | // HACKHACK: Generic types in type definition fails compilation
10 | // https://github.com/Microsoft/TypeScript/issues/1616
11 | /**
12 | * Generates an array of tick values for the specified scale.
13 | *
14 | * @param {QuantitativeScale} scale
15 | * @returns {D[]}
16 | */
17 | export interface ITickGenerator {
18 | (scale: QuantitativeScale): D[];
19 | }
20 | /**
21 | * Creates a TickGenerator using the specified interval.
22 | *
23 | * Generates ticks at multiples of the interval while also including the domain boundaries.
24 | *
25 | * @param {number} interval
26 | * @returns {TickGenerator}
27 | */
28 | export function intervalTickGenerator(interval: number): ITickGenerator {
29 | if (interval <= 0) {
30 | throw new Error("interval must be positive number");
31 | }
32 |
33 | return function (s: QuantitativeScale) {
34 | const domain = s.domain();
35 | const low = Math.min(domain[0], domain[1]);
36 | const high = Math.max(domain[0], domain[1]);
37 | const firstTick = Math.ceil(low / interval) * interval;
38 | const numTicks = Math.floor((high - firstTick) / interval) + 1;
39 |
40 | const lowTicks = low % interval === 0 ? [] : [low];
41 | const middleTicks = Utils.Math.range(0, numTicks).map((t) => firstTick + t * interval);
42 | const highTicks = high % interval === 0 ? [] : [high];
43 |
44 | return lowTicks.concat(middleTicks).concat(highTicks);
45 | };
46 | }
47 |
48 | /**
49 | * Creates a TickGenerator returns only integer tick values.
50 | *
51 | * @returns {TickGenerator}
52 | */
53 | export function integerTickGenerator(): ITickGenerator {
54 | return function (s: QuantitativeScale) {
55 | const defaultTicks = s.defaultTicks();
56 | return defaultTicks.filter((tick, i) => (tick % 1 === 0) || (i === 0) || (i === defaultTicks.length - 1));
57 | };
58 | }
59 |
--------------------------------------------------------------------------------
/src/utils/arrayUtils.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as d3 from "d3";
7 |
8 | const nativeArray = (window).Array;
9 |
10 | /**
11 | * Takes two arrays of numbers and adds them together
12 | *
13 | * @param {number[]} aList The first array of numbers
14 | * @param {number[]} bList The second array of numbers
15 | * @return {number[]} An array of numbers where x[i] = aList[i] + bList[i]
16 | */
17 | export function add(aList: number[], bList: number[]): number[] {
18 | if (aList.length !== bList.length) {
19 | throw new Error("attempted to add arrays of unequal length");
20 | }
21 | return aList.map((_: number, i: number) => aList[i] + bList[i]);
22 | }
23 |
24 | /**
25 | * Take an array of values, and return the unique values.
26 | * Will work iff ∀ a, b, a.toString() == b.toString() => a == b; will break on Object inputs
27 | *
28 | * @param {T[]} values The values to find uniqueness for
29 | * @return {T[]} The unique values
30 | */
31 | export function uniq(arr: T[]): T[] {
32 | const seen: d3.Set = d3.set();
33 | const result: T[] = [];
34 | arr.forEach((x) => {
35 | if (!seen.has(String(x))) {
36 | seen.add(String(x));
37 | result.push(x);
38 | }
39 | });
40 | return result;
41 | }
42 |
43 | /**
44 | * @param {T[][]} a The 2D array that will have its elements joined together.
45 | * @return {T[]} Every array in a, concatenated together in the order they appear.
46 | */
47 | export function flatten(a: T[][]): T[] {
48 | return nativeArray.prototype.concat.apply([], a);
49 | }
50 |
51 | /**
52 | * Creates an array of length `count`, filled with value or (if value is a function), value()
53 | *
54 | * @param {T | ((index?: number) => T)} value The value to fill the array with or a value generator (called with index as arg)
55 | * @param {number} count The length of the array to generate
56 | * @return {any[]}
57 | */
58 | export function createFilledArray(value: T | ((index?: number) => T), count: number) {
59 | const out: T[] = [];
60 | for (let i = 0; i < count; i++) {
61 | out[i] = typeof(value) === "function" ? (<(index?: number) => T> value)(i) : value;
62 | }
63 | return out;
64 | }
65 |
--------------------------------------------------------------------------------
/src/utils/bucket.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2017-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | /**
7 | * This class keeps track of bucketing state while collapsing dense line
8 | * geometry in a line and area plots.
9 | */
10 | export class Bucket {
11 | private bucketValue: number;
12 | private entryIndex: number;
13 | private exitIndex: number;
14 | private minValue: number;
15 | private maxValue: number;
16 | private minIndex: number;
17 | private maxIndex: number;
18 |
19 | constructor(
20 | index: number,
21 | xValue: number,
22 | yValue: number,
23 | ) {
24 | this.entryIndex = index;
25 | this.exitIndex = index;
26 | this.minIndex = index;
27 | this.maxIndex = index;
28 |
29 | this.bucketValue = xValue;
30 | this.minValue = yValue;
31 | this.maxValue = yValue;
32 | }
33 |
34 | public isInBucket(value: number) {
35 | return value == this.bucketValue;
36 | }
37 |
38 | public addToBucket(value: number, index: number) {
39 | if (value < this.minValue) {
40 | this.minValue = value;
41 | this.minIndex = index;
42 | }
43 |
44 | if (value > this.maxValue) {
45 | this.maxValue = value;
46 | this.maxIndex = index;
47 | }
48 |
49 | this.exitIndex = index;
50 | }
51 |
52 | public getUniqueIndices(): number[] {
53 | const idxs = [this.entryIndex, this.maxIndex, this.minIndex, this.exitIndex];
54 | return idxs.filter((idx, i) => i == 0 || idx != idxs[i - 1]);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/utils/callbackSet.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import { Set } from "./set";
7 |
8 | /**
9 | * A set of callbacks which can be all invoked at once.
10 | * Each callback exists at most once in the set (based on reference equality).
11 | * All callbacks should have the same signature.
12 | */
13 | export class CallbackSet extends Set {
14 | public callCallbacks(...args: any[]) {
15 | this.forEach((callback) => {
16 | callback.apply(this, args);
17 | });
18 | return this;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/utils/coerceD3.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as d3 from "d3";
3 |
4 | /**
5 | * Coerce possibly external d3 instance into our own instance of d3 so we can use d3-selection-multi.
6 | * See https://github.com/d3/d3-selection-multi/issues/11 for why we have to do this.
7 | *
8 | * Any public facing API that accepts a d3 selection should first pass that user-supplied selection
9 | * through here - this ensures all selection objects that go through the Plottable codebase are "vetted".
10 | */
11 | export function coerceExternalD3>(externalD3Selection: S): S {
12 | // if .attrs isn't defined; convert the selection
13 | if (externalD3Selection.attrs == null) {
14 | if (externalD3Selection.nodes == null) {
15 | // nodes isn't defined; this is probably a d3v3 selection. handle it accordingly
16 | const nodes: d3.BaseType[] = [];
17 | externalD3Selection.each(function() {
18 | nodes.push(this);
19 | });
20 | return d3.selectAll(nodes);
21 | } else {
22 | return d3.selectAll(externalD3Selection.nodes());
23 | }
24 | } else {
25 | return externalD3Selection;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as Array from "./arrayUtils";
7 | import * as Color from "./colorUtils";
8 | import * as DOM from "./domUtils";
9 | import * as Math from "./mathUtils";
10 | import * as RTree from "./rTree";
11 | import * as Stacking from "./stackingUtils";
12 | import * as Window from "./windowUtils";
13 |
14 | export {
15 | Array,
16 | Color,
17 | DOM,
18 | Math,
19 | RTree,
20 | Stacking,
21 | Window,
22 | };
23 |
24 | export * from "./bucket";
25 | export * from "./callbackSet";
26 | export * from "./coerceD3";
27 | export * from "./entityStore";
28 | export * from "./map";
29 | export * from "./objectUtils";
30 | export * from "./set";
31 | export * from "./transformAwareTranslator";
32 |
--------------------------------------------------------------------------------
/src/utils/makeEnum.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | export function makeEnum(values: T[]): { [K in T]: K } {
7 | return values.reduce((obj, v) => {
8 | obj[v] = v;
9 | return obj;
10 | }, {} as any);
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/map.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as Math from "./mathUtils";
7 | /**
8 | * Shim for ES6 map.
9 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
10 | */
11 | export class Map {
12 | private _keyValuePairs: { key: K; value: V; }[];
13 | private _es6Map: any;
14 |
15 | public constructor() {
16 | if (typeof (window).Map === "function") {
17 | this._es6Map = new (window).Map();
18 | } else {
19 | this._keyValuePairs = [];
20 | }
21 | }
22 |
23 | public set(key: K, value: V) {
24 | if (Math.isNaN(key)) {
25 | throw new Error("NaN may not be used as a key to the Map");
26 | }
27 |
28 | if (this._es6Map != null) {
29 | this._es6Map.set(key, value);
30 | return this;
31 | }
32 |
33 | for (let i = 0; i < this._keyValuePairs.length; i++) {
34 | if (this._keyValuePairs[i].key === key) {
35 | this._keyValuePairs[i].value = value;
36 | return this;
37 | }
38 | }
39 | this._keyValuePairs.push({ key: key, value: value });
40 | return this;
41 | }
42 |
43 | public get(key: K) {
44 | if (this._es6Map != null) {
45 | return this._es6Map.get(key);
46 | }
47 |
48 | for (let i = 0; i < this._keyValuePairs.length; i++) {
49 | if (this._keyValuePairs[i].key === key) {
50 | return this._keyValuePairs[i].value;
51 | }
52 | }
53 | return undefined;
54 | }
55 |
56 | public has(key: K) {
57 | if (this._es6Map != null) {
58 | return this._es6Map.has(key);
59 | }
60 |
61 | for (let i = 0; i < this._keyValuePairs.length; i++) {
62 | if (this._keyValuePairs[i].key === key) {
63 | return true;
64 | }
65 | }
66 | return false;
67 | }
68 |
69 | public forEach(callbackFn: (value: V, key: K, map: Map) => void, thisArg?: any) {
70 | if (this._es6Map != null) {
71 | const callbackWrapper = (value: V, key: K) => callbackFn.call(thisArg, value, key, this);
72 | this._es6Map.forEach(callbackWrapper, thisArg);
73 | return;
74 | }
75 |
76 | this._keyValuePairs.forEach((keyValuePair) => {
77 | callbackFn.call(thisArg, keyValuePair.value, keyValuePair.key, this);
78 | });
79 | }
80 |
81 | public delete(key: K) {
82 | if (this._es6Map != null) {
83 | return this._es6Map.delete(key);
84 | }
85 |
86 | for (let i = 0; i < this._keyValuePairs.length; i++) {
87 | if (this._keyValuePairs[i].key === key) {
88 | this._keyValuePairs.splice(i, 1);
89 | return true;
90 | }
91 | }
92 | return false;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/utils/objectUtils.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2017-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | /**
7 | * Polyfill for Object.assign
8 | */
9 | export function assign>(...objs: Partial[]): T {
10 | const result: Partial = {};
11 | for(const obj of objs) {
12 | const keys = Object.keys(obj);
13 | for (const key of keys) {
14 | result[key as keyof T] = obj[key];
15 | }
16 | }
17 | return result as T;
18 | }
19 |
--------------------------------------------------------------------------------
/src/utils/set.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | /**
7 | * Shim for ES6 set.
8 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
9 | */
10 | export class Set {
11 | public size: number;
12 |
13 | private _values: T[];
14 | private _es6Set: any;
15 |
16 | constructor() {
17 | if (typeof (window).Set === "function") {
18 | this._es6Set = new (window).Set();
19 | } else {
20 | this._values = [];
21 | }
22 | this.size = 0;
23 | }
24 |
25 | public add(value: T) {
26 | if (this._es6Set != null) {
27 | this._es6Set.add(value);
28 | this.size = this._es6Set.size;
29 | return this;
30 | }
31 |
32 | if (!this.has(value)) {
33 | this._values.push(value);
34 | this.size = this._values.length;
35 | }
36 | return this;
37 | }
38 |
39 | public delete(value: T) {
40 | if (this._es6Set != null) {
41 | const deleted = this._es6Set.delete(value);
42 | this.size = this._es6Set.size;
43 | return deleted;
44 | }
45 |
46 | const index = this._values.indexOf(value);
47 | if (index !== -1) {
48 | this._values.splice(index, 1);
49 | this.size = this._values.length;
50 | return true;
51 | }
52 | return false;
53 | }
54 |
55 | public has(value: T) {
56 | if (this._es6Set != null) {
57 | return this._es6Set.has(value);
58 | }
59 |
60 | return this._values.indexOf(value) !== -1;
61 | }
62 |
63 | public forEach(callback: (value: T, value2: T, set: Set) => void, thisArg?: any) {
64 | if (this._es6Set != null) {
65 | const callbackWrapper = (value: T, value2: T) => callback.call(thisArg, value, value2, this);
66 | this._es6Set.forEach(callbackWrapper, thisArg);
67 | return;
68 | }
69 |
70 | this._values.forEach((value: T) => {
71 | callback.call(thisArg, value, value, this);
72 | });
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/utils/transformAwareTranslator.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2017-present Palantir Technologies
3 | * @license MIT
4 | */
5 |
6 | import * as Utils from "../utils";
7 |
8 | import { Point } from "../";
9 | import { Component } from "../components/component";
10 |
11 | const _TRANSLATOR_KEY = "__Plottable_ClientTranslator";
12 |
13 | /**
14 | * Returns a singleton-ized `Translator` instance associated with the component.
15 | */
16 | export function getTranslator(component: Component): Translator {
17 | const rootElement = component.root().rootElement().node() as HTMLElement;
18 |
19 | let translator: Translator = ( rootElement)[_TRANSLATOR_KEY];
20 | if (translator == null) {
21 | translator = new Translator(rootElement);
22 | ( rootElement)[_TRANSLATOR_KEY] = translator;
23 | }
24 |
25 | return translator;
26 | }
27 |
28 | /**
29 | * The translator implements CSS transform aware position measuring. We manually
30 | * compute a cumulative CSS3 of the root element ancestors up to ``.
31 | */
32 | export class Translator {
33 | constructor(private _rootElement: HTMLElement) {
34 | }
35 |
36 | /**
37 | * Given `document` client coordinates, computes the position relative to the
38 | * `Component`'s root element, taking into account the cumulative CSS3
39 | * transforms of the root element ancestors up to ``.
40 | *
41 | * This triggers a layout but doesn't further modify the DOM, so causes a
42 | * maximum of one layout per frame.
43 | *
44 | * Does not support `transform-origin` CSS property other than the default.
45 | */
46 | public computePosition(clientX: number, clientY: number): Point {
47 | const clientPosition = {
48 | x: clientX,
49 | y: clientY,
50 | };
51 |
52 | const transform = Utils.Math.getCumulativeTransform(this._rootElement);
53 | if (transform == null) {
54 | return clientPosition;
55 | }
56 |
57 | const transformed = Utils.Math.applyTransform(transform, clientPosition);
58 | return transformed;
59 | }
60 |
61 | /**
62 | * Is the event's target part of the given component's DOM tree?
63 | */
64 | public static isEventInside(component: Component, e: Event) {
65 | return Utils.DOM.contains(component.root().rootElement().node() as Element, e.target as Element);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/test/animators/nullAnimatorTests.ts:
--------------------------------------------------------------------------------
1 | import * as d3 from "d3";
2 |
3 | import { assert } from "chai";
4 |
5 | import * as Plottable from "../../src";
6 |
7 | import * as TestMethods from "../testMethods";
8 |
9 | describe("Animators", () => {
10 | describe("Null Animator", () => {
11 | it("has a total animation time of zero", () => {
12 | const animator = new Plottable.Animators.Null();
13 | assert.strictEqual(animator.totalTime(null), 0);
14 | });
15 |
16 | it("applies the requested attributes to the selection", () => {
17 | const attributeName = "foo";
18 | const attributeValues = ["A", "B", "C"];
19 | const attributeProjector = (d: any, i: number) => attributeValues[i];
20 | const attrToAppliedProjector: Plottable.AttributeToAppliedProjector = {};
21 | attrToAppliedProjector[attributeName] = attributeProjector;
22 |
23 | const div = TestMethods.generateDiv();
24 | const elementName = "g";
25 | attributeValues.forEach(() => div.append(elementName));
26 | const elements = div.selectAll(elementName);
27 |
28 | const animator = new Plottable.Animators.Null();
29 | animator.animate(elements, attrToAppliedProjector);
30 |
31 | elements.each(function(d, i) {
32 | const actualAttribute = d3.select(this).attr(attributeName);
33 | const expectedAttribute = attributeProjector(d, i);
34 | assert.strictEqual(actualAttribute, expectedAttribute, `set the correct attribute on element with index ${i}`);
35 | });
36 |
37 | div.remove();
38 | });
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/test/core/datasetTests.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 |
3 | import * as Plottable from "../../src";
4 |
5 | describe("Dataset", () => {
6 | it("Updates listeners when the data is changed", () => {
7 | const ds = new Plottable.Dataset();
8 |
9 | const newData = [1, 2, 3];
10 |
11 | let callbackCalled = false;
12 | const callback = (listenable: Plottable.Dataset) => {
13 | assert.strictEqual(listenable, ds, "Callback received the Dataset as the first argument");
14 | assert.deepEqual(ds.data(), newData, "Dataset arrives with correct data");
15 | callbackCalled = true;
16 | };
17 | ds.onUpdate(callback);
18 |
19 | ds.data(newData);
20 | assert.isTrue(callbackCalled, "callback was called when the data was changed");
21 | });
22 |
23 | it("Updates listeners when the metadata is changed", () => {
24 | const ds = new Plottable.Dataset();
25 |
26 | const newMetadata = "blargh";
27 |
28 | let callbackCalled = false;
29 | const callback = (listenable: Plottable.Dataset) => {
30 | assert.strictEqual(listenable, ds, "Callback received the Dataset as the first argument");
31 | assert.deepEqual(ds.metadata(), newMetadata, "Dataset arrives with correct metadata");
32 | callbackCalled = true;
33 | };
34 | ds.onUpdate(callback);
35 |
36 | ds.metadata(newMetadata);
37 | assert.isTrue(callbackCalled, "callback was called when the metadata was changed");
38 | });
39 |
40 | it("Removing listener from dataset should be possible", () => {
41 | const ds = new Plottable.Dataset();
42 |
43 | const newData1 = [1, 2, 3];
44 | const newData2 = [4, 5, 6];
45 |
46 | let callbackCalled = false;
47 | const callback = (listenable: Plottable.Dataset) => {
48 | assert.strictEqual(listenable, ds, "Callback received the Dataset as the first argument");
49 | callbackCalled = true;
50 | };
51 | ds.onUpdate(callback);
52 |
53 | ds.data(newData1);
54 | assert.isTrue(callbackCalled, "callback was called when the data was changed");
55 |
56 | callbackCalled = false;
57 | ds.offUpdate(callback);
58 | ds.data(newData2);
59 | assert.isFalse(callbackCalled, "callback was called when the data was changed");
60 | });
61 | });
62 |
--------------------------------------------------------------------------------
/test/coverage.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plottable Tests
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
36 |
37 |
38 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/test/drawers/arcDrawerTests.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 | import * as d3 from "d3";
3 |
4 | import * as Plottable from "../../src";
5 |
6 | import * as TestMethods from "../testMethods";
7 |
8 | describe("SVGDrawers", () => {
9 | describe("Arc Drawer", () => {
10 | it("has a stroke of \"none\"", () => {
11 | const drawer = new Plottable.Drawers.ArcSVGDrawer();
12 | const svg = TestMethods.generateSVG();
13 | drawer.attachTo(svg);
14 |
15 | const data = [["A", "B", "C"]]; // arc normally takes single array of data
16 | const drawSteps: Plottable.Drawers.AppliedDrawStep[] = [
17 | {
18 | attrToAppliedProjector: {},
19 | animator: new Plottable.Animators.Null(),
20 | },
21 | ];
22 | drawer.draw(data, drawSteps);
23 |
24 | assert.strictEqual(d3.selectAll(drawer.getVisualPrimitives()).style("stroke"), "none");
25 |
26 | svg.remove();
27 | });
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/test/drawers/arcOutlineDrawerTests.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 | import * as d3 from "d3";
3 |
4 | import * as Plottable from "../../src";
5 |
6 | import * as TestMethods from "../testMethods";
7 |
8 | describe("SVGDrawers", () => {
9 | describe("Arc Outline Drawer", () => {
10 | it("has a fill of \"none\"", () => {
11 | const drawer = new Plottable.Drawers.ArcOutlineSVGDrawer();
12 | const svg = TestMethods.generateSVG();
13 | drawer.attachTo(svg);
14 |
15 | const data = [["A", "B", "C"]]; // arc outline normally takes single array of data
16 | const drawSteps: Plottable.Drawers.AppliedDrawStep[] = [
17 | {
18 | attrToAppliedProjector: {},
19 | animator: new Plottable.Animators.Null(),
20 | },
21 | ];
22 | drawer.draw(data, drawSteps);
23 |
24 | assert.strictEqual(d3.selectAll(drawer.getVisualPrimitives()).style("fill"), "none");
25 |
26 | svg.remove();
27 | });
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/test/drawers/areaDrawerTests.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 | import * as d3 from "d3";
3 |
4 | import * as Plottable from "../../src";
5 |
6 | import * as TestMethods from "../testMethods";
7 |
8 | describe("SVGDrawers", () => {
9 | describe("Area Drawer", () => {
10 | const data = [["A", "B", "C"]]; // area normally takes single array of data
11 | let svg: d3.Selection;
12 | let drawer: Plottable.Drawers.AreaSVGDrawer;
13 |
14 | beforeEach(() => {
15 | svg = TestMethods.generateSVG();
16 | drawer = new Plottable.Drawers.AreaSVGDrawer();
17 | drawer.attachTo(svg);
18 |
19 | const drawSteps: Plottable.Drawers.AppliedDrawStep[] = [
20 | {
21 | attrToAppliedProjector: {},
22 | animator: new Plottable.Animators.Null(),
23 | },
24 | ];
25 | drawer.draw(data, drawSteps);
26 | });
27 |
28 | afterEach(function() {
29 | if (this.currentTest.state === "passed") {
30 | svg.remove();
31 | }
32 | });
33 |
34 | it("has a stroke of \"none\"", () => {
35 | assert.strictEqual(d3.selectAll(drawer.getVisualPrimitives()).style("stroke"), "none");
36 | });
37 |
38 | it("retrieves the same path regardless of requested selection index", () => {
39 | const expectedSelection = svg.selectAll("path");
40 | data[0].forEach((datum, index) => {
41 | const selectionForIndex = d3.select(drawer.getVisualPrimitiveAtIndex(index));
42 | assert.strictEqual(selectionForIndex.size(), 1, `selection for index ${index} contains only one element`);
43 | assert.strictEqual(selectionForIndex.node(), expectedSelection.node(), `selection for index ${index} contains the correct element`);
44 | });
45 | });
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/test/drawers/canvasDrawerTests.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 | import * as sinon from "sinon";
3 |
4 | import * as Plottable from "../../src";
5 | import { CanvasDrawer } from "../../src/drawers/canvasDrawer";
6 |
7 | describe("CanvasDrawer", () => {
8 | it("draw() calls _drawStepCanvas", () => {
9 | const canvas = document.createElement("canvas");
10 | const context = canvas.getContext("2d");
11 | const drawStepSpy = sinon.spy();
12 | const drawer = new CanvasDrawer(context, drawStepSpy);
13 |
14 | const data: any[] = [];
15 | const drawStep: Plottable.Drawers.AppliedDrawStep = {
16 | animator: new Plottable.Animators.Null(),
17 | attrToAppliedProjector: {},
18 | };
19 | drawer.draw(data, [drawStep]);
20 | assert.strictEqual(drawStepSpy.args[0][1], data, "drawStep is called with data");
21 | assert.strictEqual(drawStepSpy.args[0][2], drawStep.attrToAppliedProjector, "drawStep is called with attrToAppliedProjector");
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/test/drawers/drawerTests.ts:
--------------------------------------------------------------------------------
1 | import * as d3 from "d3";
2 | import * as sinon from "sinon";
3 |
4 | import { assert } from "chai";
5 |
6 | import { CanvasDrawer } from "../../src/drawers/canvasDrawer";
7 | import { ProxyDrawer } from "../../src/drawers/drawer";
8 | import { SVGDrawer } from "../../src/drawers/svgDrawer";
9 | import * as TestMethods from "../testMethods";
10 |
11 | describe("ProxyDrawer", () => {
12 | let drawer: ProxyDrawer;
13 | let svgDrawer: SVGDrawer;
14 | let canvasDrawer: CanvasDrawer;
15 |
16 | beforeEach(() => {
17 | svgDrawer = new SVGDrawer("test", "foo");
18 | canvasDrawer = new CanvasDrawer(null, null);
19 | drawer = new ProxyDrawer(() => svgDrawer, () => canvasDrawer);
20 | });
21 |
22 | it("useSVG/useCanvas uses the right renderer", () => {
23 | const svg = TestMethods.generateSVG();
24 | const removeSpy = sinon.stub(svgDrawer, "remove");
25 |
26 | drawer.useSVG(svg);
27 | assert.strictEqual(drawer.getDrawer(), svgDrawer, "svg drawer was used");
28 |
29 | const canvas = d3.select(document.createElement("canvas"));
30 | drawer.useCanvas(canvas);
31 | assert.isTrue(removeSpy.called, "old drawer was removed");
32 | assert.strictEqual(drawer.getDrawer(), canvasDrawer, "canvas drawer was used");
33 | svg.remove();
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/test/globalInitialization.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 | import * as d3 from "d3";
3 |
4 | import * as Plottable from "../src";
5 |
6 | import * as TestMethods from "./testMethods";
7 |
8 | before(() => {
9 | // Set the render policy to immediate to make sure ETE tests can check DOM change immediately
10 | Plottable.RenderController.renderPolicy("immediate");
11 | // Taken from https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
12 | const isFirefox = navigator.userAgent.indexOf("Firefox") !== -1;
13 | if (window.PHANTOMJS) {
14 | window.Pixel_CloseTo_Requirement = 2;
15 | // HACKHACK https://github.com/ariya/phantomjs/issues/13280
16 | (Plottable.Utils.Set.prototype)._updateSize = function() {
17 | this.size = (this)._values.length;
18 | };
19 | } else if (isFirefox) {
20 | // HACKHACK #2122
21 | window.Pixel_CloseTo_Requirement = 2;
22 | } else if (TestMethods.isIE()) {
23 | window.Pixel_CloseTo_Requirement = 2;
24 | } else {
25 | window.Pixel_CloseTo_Requirement = 0.5;
26 | }
27 | });
28 |
29 | after(() => {
30 | assert.strictEqual(d3.selectAll("svg.svg").size(), 0, "all test svgs have been removed");
31 | assert.strictEqual(d3.selectAll("div.div").size(), 0, "all test divs have been removed");
32 | assert.strictEqual(d3.selectAll("style").size(), 0, "all style nodes have been removed");
33 | });
34 |
--------------------------------------------------------------------------------
/test/index.ts:
--------------------------------------------------------------------------------
1 | declare var require: any;
2 |
3 | require("./globalInitialization");
4 |
5 | // create a require context hitting the TestSelector plugin
6 | const testsContext = require.context("TestSelector", true, /Test.js$/);
7 | // invoke the context on each included file name (this runs the test).
8 | testsContext.keys().forEach(testsContext);
9 |
--------------------------------------------------------------------------------
/test/memoize/memThunkTests.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 | import * as sinon from "sinon";
3 |
4 | import * as Plottable from "../../src";
5 |
6 | import { memThunk } from "../../src/memoize/memThunk";
7 |
8 | describe("memThunk", () => {
9 | it("calls compute fn with the result of the input thunks", () => {
10 | const a = new Plottable.Scales.Linear().domain([0, 10]).range([0, 100]);
11 | const b = 2;
12 | const spy = sinon.spy((a: Plottable.Scales.Linear, b: number) => a.scale(b));
13 |
14 | const thunkFn = memThunk(
15 | () => a,
16 | () => b,
17 | spy,
18 | );
19 |
20 | const firstCall = thunkFn();
21 | assert.strictEqual(firstCall, 20);
22 | assert.isTrue(spy.calledWithExactly(a, b));
23 |
24 | // thunk should memoize
25 | spy.reset();
26 | const secondCall = thunkFn();
27 | assert.strictEqual(secondCall, 20);
28 | assert.isFalse(spy.called);
29 |
30 | // when input thunks change, result changes and memoize is re-called
31 | a.range([0, 1000]);
32 | const changedCall = thunkFn();
33 | assert.strictEqual(changedCall, 200);
34 | assert.strictEqual(spy.callCount, 1);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/mocks.ts:
--------------------------------------------------------------------------------
1 |
2 | import { SimpleSelection } from "../src/core/interfaces";
3 |
4 | import * as Plottable from "../src";
5 |
6 | export class FixedSizeComponent extends Plottable.Component {
7 | public fsWidth: number;
8 | public fsHeight: number;
9 |
10 | constructor(width = 0, height = 0) {
11 | super();
12 | this.fsWidth = width;
13 | this.fsHeight = height;
14 | }
15 |
16 | public requestedSpace(availableWidth: number, availableHeight: number): Plottable.SpaceRequest {
17 | return {
18 | minWidth: this.fsWidth,
19 | minHeight: this.fsHeight,
20 | };
21 | }
22 |
23 | public fixedWidth() {
24 | return true;
25 | }
26 |
27 | public fixedHeight() {
28 | return true;
29 | }
30 | }
31 |
32 | export class NoOpAnimator implements Plottable.IAnimator {
33 | /*
34 | * A do-nothing Animator.
35 | * Useful for testing the reset states of Plots by blanking the MAIN Animator.
36 | */
37 |
38 | public totalTime(selection: any) {
39 | return 0;
40 | }
41 |
42 | public animate(selection: SimpleSelection): SimpleSelection {
43 | return selection;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test/namespacingTests.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Tests the namespace structure to ensure all the exports we want to be available, are.
3 | */
4 |
5 | import * as Plottable from "../src";
6 |
7 | // tslint:disable-next-line:no-unused-variable
8 | const test = [
9 | // namespaces and nested namespaces
10 | Plottable.Animators.Easing,
11 | Plottable.Animators.Null,
12 | Plottable.Axes.Category,
13 | Plottable.Axes.Numeric,
14 | Plottable.Components.AxisLabel,
15 | Plottable.Components.TitleLabel,
16 | Plottable.Components.Table,
17 | Plottable.Configs.SHOW_WARNINGS,
18 | Plottable.Dispatchers.Key,
19 | Plottable.Drawers.LineSVGDrawer,
20 | Plottable.Formatters.identity,
21 | Plottable.Plots.Pie,
22 | Plottable.Plots.Animator.MAIN,
23 | Plottable.RenderController.flush,
24 | Plottable.RenderPolicies.AnimationFrame,
25 | Plottable.Scales.Linear,
26 | Plottable.Scales.TickGenerators.integerTickGenerator,
27 | Plottable.SymbolFactories.circle,
28 | Plottable.TimeInterval.day,
29 | Plottable.Utils.Map,
30 | Plottable.Utils.Array.add,
31 |
32 | // classes on the Plottable namespace
33 | Plottable.Axis,
34 | Plottable.Component,
35 | Plottable.ComponentContainer,
36 | Plottable.Dataset,
37 | Plottable.Dispatcher,
38 | Plottable.ProxyDrawer,
39 | Plottable.Interaction,
40 | Plottable.Plot,
41 | Plottable.QuantitativeScale,
42 | Plottable.Scale,
43 | Plottable.XYPlot,
44 | ];
45 |
46 | type TestInterfaces = Plottable.Axes.IDownsampleInfo
47 | | Plottable.Axes.TimeAxisConfiguration
48 | | Plottable.Plots.IAccessorScaleBinding
49 | | Plottable.Scales.TickGenerators.ITickGenerator
50 | | Plottable.Scales.IPaddingExceptionsProvider
51 | | Plottable.IAccessor
52 | | Plottable.IAnimator
53 | | Plottable.IDragLineCallback
54 | | Plottable.DragBoxCallback
55 | | Plottable.IEntity
56 | | Plottable.IScaleCallback;
57 |
58 | type TestTypeAliases = Plottable.Bounds
59 | | Plottable.ClickCallback
60 | | Plottable.DatasetCallback
61 | | Plottable.Formatter
62 | | Plottable.Point
63 | | Plottable.PointerCallback
64 | | Plottable.Projector
65 | | Plottable.Range
66 | | Plottable.SpaceRequest
67 | | Plottable.SymbolFactory
68 | | Plottable.TransformableScale
69 | | Plottable.AxisOrientation;
70 |
71 | // tslint:disable-next-line:no-unused-variable
72 | const version = Plottable.version;
73 |
--------------------------------------------------------------------------------
/test/tests.css:
--------------------------------------------------------------------------------
1 | div.div, svg.svg {
2 | background-color : #DEF;
3 | }
4 |
--------------------------------------------------------------------------------
/test/tests.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plottable Tests
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
22 |
23 |
24 |
29 |
30 |
31 |
32 |
33 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/test/utils/arrayUtilsTests.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 |
3 | import * as Plottable from "../../src";
4 |
5 | describe("Utils", () => {
6 | describe("ArrayUtils", () => {
7 |
8 | it("uniq()", () => {
9 | const strings = ["foo", "bar", "foo", "foo", "baz", "bam"];
10 | assert.deepEqual(Plottable.Utils.Array.uniq(strings), ["foo", "bar", "baz", "bam"]);
11 | });
12 |
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/test/utils/callbackSetTests.ts:
--------------------------------------------------------------------------------
1 | import { assert } from "chai";
2 |
3 | import * as Plottable from "../../src";
4 |
5 | describe("Utils", () => {
6 | describe("CallbackSet", () => {
7 | it("callCallbacks()", () => {
8 | const expectedString = "Plottable";
9 | const expectedIndex = 1;
10 |
11 | let cb1called = false;
12 | const cb1 = (s: string, i: number) => {
13 | assert.strictEqual(s, expectedString, "was passed the correct first argument");
14 | assert.strictEqual(i, expectedIndex, "was passed the correct second argument");
15 | cb1called = true;
16 | };
17 | let cb2called = false;
18 | const cb2 = (s: string, i: number) => {
19 | assert.strictEqual(s, expectedString, "was passed the correct first argument");
20 | assert.strictEqual(i, expectedIndex, "was passed the correct second argument");
21 | cb2called = true;
22 | };
23 |
24 | const callbackSet = new Plottable.Utils.CallbackSet<(s: string, i: number) => any>();
25 | callbackSet.add(cb1);
26 | callbackSet.add(cb2);
27 |
28 | callbackSet.callCallbacks(expectedString, expectedIndex);
29 | assert.isTrue(cb1called, "callback 1 was called");
30 | assert.isTrue(cb2called, "callback 2 was called");
31 | });
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/test/utils/colorUtilsTests.ts:
--------------------------------------------------------------------------------
1 | import * as d3 from "d3";
2 |
3 | import { assert } from "chai";
4 |
5 | import * as Plottable from "../../src";
6 |
7 | describe("Utils.Color", () => {
8 | it("lightenColor()", () => {
9 | const colorHex = "#12fced";
10 | const oldColor = d3.hsl(colorHex);
11 | const lightenedColor = Plottable.Utils.Color.lightenColor(colorHex, 1);
12 | assert.operator(d3.hsl(lightenedColor).l, ">", oldColor.l, "color got lighter");
13 | });
14 |
15 | it("colorTest()", () => {
16 | const colorTester = d3.select("body").append("div").classed("color-tester", true);
17 | const style = colorTester.append("style");
18 | style.attr("type", "text/css");
19 |
20 | style.text(".plottable-colors-0 { background-color: blue; }");
21 | const blueHexcode = Plottable.Utils.Color.colorTest(colorTester, "plottable-colors-0");
22 | assert.strictEqual(blueHexcode, "#0000ff", "hexcode for blue returned");
23 |
24 | style.text(".plottable-colors-2 { background-color: #13EADF; }");
25 | const hexcode = Plottable.Utils.Color.colorTest(colorTester, "plottable-colors-2");
26 | assert.strictEqual(hexcode, "#13eadf", "hexcode for blue returned");
27 |
28 | const nullHexcode = Plottable.Utils.Color.colorTest(colorTester, "plottable-colors-11");
29 | assert.strictEqual(nullHexcode, null, "null hexcode returned");
30 | colorTester.remove();
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/test/utils/transformAwareTranslatorTests.ts:
--------------------------------------------------------------------------------
1 | import * as sinon from "sinon";
2 |
3 | import { assert } from "chai";
4 |
5 | import * as Plottable from "../../src";
6 |
7 | import * as TestMethods from "../testMethods";
8 |
9 | describe("Translator", () => {
10 | it("getTranslator() creates only one Translator per Component", () => {
11 | const svg = TestMethods.generateSVG();
12 | const component = new Plottable.Component();
13 | sinon.stub(component, "rootElement").returns(svg);
14 |
15 | const t1 = Plottable.Utils.getTranslator(component);
16 | assert.isNotNull(t1, "created a new Translator on a Component");
17 | const t2 = Plottable.Utils.getTranslator(component);
18 | assert.strictEqual(t1, t2, "returned the existing Translator if called again with same Component");
19 |
20 | svg.remove();
21 | });
22 |
23 | it("converts points to Component space correctly", () => {
24 | const svg = TestMethods.generateSVG();
25 | const component = new Plottable.Component();
26 | sinon.stub(component, "rootElement").returns(svg);
27 |
28 | const rectOrigin: Plottable.Point = {
29 | x: 19,
30 | y: 85,
31 | };
32 | const rect = svg.append("rect").attrs({
33 | x: rectOrigin.x,
34 | y: rectOrigin.y,
35 | width: 30,
36 | height: 30,
37 | });
38 |
39 | const translator = Plottable.Utils.getTranslator(component);
40 |
41 | const svgBCR = svg.node().getBoundingClientRect();
42 | const rectBCR = (rect.node() as Element).getBoundingClientRect();
43 | // translator returns position relative to component origin
44 | const computedOrigin = translator.computePosition(rectBCR.left - svgBCR.left, rectBCR.top - svgBCR.top);
45 | TestMethods.assertPointsClose(computedOrigin, rectOrigin, 0.5, "translates client coordinates to