├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── basic-visualization
├── app.js
├── bower.json
├── index.html
└── nyc-temperature.csv
├── capture-visualization
├── index.js
├── output
│ └── placeholder.txt
├── package.json
├── public
│ ├── app.css
│ ├── app.js
│ ├── bower.json
│ ├── index.html
│ └── nyc-temperature.csv
├── toolkit
│ └── capture-web-page.js
└── web-server.js
└── images
└── support1.png
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: ashleydavis
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | capture-visualization/output/
61 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Data Wrangling with JavaScript
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nodejs-visualization-example
2 |
3 | An example that shows how to use the Nightmare headless browser to capture web-based visualizations under Node.js.
4 |
5 |
6 |
7 | Example code here accompanies [my article on CSS tricks](http://bit.ly/2HW3W0b) which is an extract from my book [Data Wrangling with JavaScript](http://bit.ly/2t2cJu2).
8 |
9 | [You can support my work here](https://www.codecapers.com.au/about#support-my-work)
10 |
11 | ## Examples
12 |
13 | basic-visualization/
14 |
15 | This sub-directory contains a simple web app swith an example chart using C3.
16 |
17 | capture-visualization/
18 |
19 | Working Node.js example that uses headless browser Nightmare/Electron to capture a browser-based visualization (chart) to a PNG image file.
20 |
21 | ## Data Wrangling with JavaScript
22 |
23 | These examples are an extract from my book [Data Wrangling with JavaScript](http://bit.ly/2t2cJu2).
24 |
--------------------------------------------------------------------------------
/basic-visualization/app.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | //
4 | // Render a chart to a particular element on the page.
5 | //
6 | function renderChart (bindto, data, size) {
7 | var chart = c3.generate({
8 | bindto: bindto,
9 | size: size, // Set the size of the chart. Not used in this example, but we'll make use of this later.
10 | data: {
11 | json: data,
12 | keys: {
13 | x: "Year", // Specify the CSV file column to use as the X axis.
14 | value: [
15 | "AvgTemp"
16 | ]
17 | }
18 | },
19 | transition: {
20 | duration: 0 // Disable animated transitions when we are capturing a static image.
21 | }
22 | });
23 | };
24 |
25 | $(function () {
26 |
27 | $.get("nyc-temperature.csv") // Get CSV data file from the web server.
28 | .then(function (response) {
29 | var parseOptions = {
30 | header: true,
31 | dynamicTyping: true
32 | };
33 | var parsed = Papa.parse(response, parseOptions); // Parse CSV data to JavaScript data.
34 | renderChart("#chart", parsed.data); // Use C3 to render the chart.
35 | })
36 | .catch(function (err) {
37 | console.error(err);
38 | });
39 |
40 | });
41 |
42 |
--------------------------------------------------------------------------------
/basic-visualization/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "c3-template-web-page",
3 | "homepage": "https://github.com/JavaScript-Data-Wrangling/Chapter-10",
4 | "authors": [
5 | "Ashley Davis "
6 | ],
7 | "description": "",
8 | "main": "",
9 | "license": "MIT",
10 | "ignore": [
11 | "**/.*",
12 | "node_modules",
13 | "bower_components",
14 | "test",
15 | "tests"
16 | ],
17 | "dependencies": {
18 | "jquery": "^3.3.1",
19 | "c3": "^0.4.18",
20 | "papaparse": "^4.3.7"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/basic-visualization/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NYC average yearly temperature
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/basic-visualization/nyc-temperature.csv:
--------------------------------------------------------------------------------
1 | Year,MinTemp,MaxTemp,AvgTemp
2 | 1917,-25,37.8,10.547245179063365
3 | 1918,-21.1,40,11.825205479452052
4 | 1919,-18.3,37.2,12.125824175824178
5 | 1920,-18.9,34.4,11.286475409836074
6 | 1921,-15.6,35.6,12.751095890410959
7 | 1922,-18.9,34.4,12.001369863013698
8 | 1923,-13.9,37.2,11.665753424657524
9 | 1924,-15,37.2,11.08784153005464
10 | 1925,-18.9,37.2,11.937637362637368
11 | 1926,-15,37.8,10.772865013774107
12 | 1927,-18.3,33.3,11.932465753424664
13 | 1928,-13.9,34.4,11.961157024793385
14 | 1929,-13.3,37.2,12.328082191780814
15 | 1930,-13.9,38.9,12.53301369863014
16 | 1931,-11.7,37.2,13.26561643835617
17 | 1932,-11.7,35.6,12.900961538461535
18 | 1933,-21.1,38.9,12.447099447513821
19 | 1934,-26.1,38.3,11.733150684931507
20 | 1935,-18.3,35,11.739041095890402
21 | 1936,-19.4,41.1,11.940027322404374
22 | 1937,-10,37.8,12.546428571428576
23 | 1938,-14.4,35.6,12.938356164383551
24 | 1939,-14.4,35.6,12.62821917808219
25 | 1940,-13.9,36.7,11.04616438356164
26 | 1941,-12.2,36.7,12.78082191780821
27 | 1942,-20,36.1,12.310714285714294
28 | 1943,-22.2,37.2,12.117671232876717
29 | 1944,-11.1,38.9,12.637534246575356
30 | 1945,-16.7,36.1,12.307808219178066
31 | 1946,-15,34.4,13.040273972602742
32 | 1947,-13.9,35,12.159041095890403
33 | 1948,-17.8,39.4,12.316986301369864
34 | 1949,-8.3,38.9,13.88131868131868
35 | 1950,-14.4,35,12.076373626373627
36 | 1951,-13.3,34.4,12.815479452054786
37 | 1952,-13.3,37.8,13.236202185792356
38 | 1953,-10,38.9,13.947796143250693
39 | 1954,-13.9,37.8,12.737671232876705
40 | 1955,-17.8,37.8,12.68255494505495
41 | 1956,-10,37.2,11.957240437158474
42 | 1957,-17.8,38.3,13.081318681318683
43 | 1958,-16.1,33.9,11.46863013698631
44 | 1959,-13.9,36.1,13.060273972602742
45 | 1960,-13.3,32.8,12.23196721311476
46 | 1961,-18.9,36.1,12.839589041095888
47 | 1962,-15.6,37.2,11.958630136986303
48 | 1963,-18.9,36.7,12.046575342465754
49 | 1964,-12.8,37.2,12.555191256830605
50 | 1965,-12.8,35,12.37712328767122
51 | 1966,-13.3,39.4,12.846849315068491
52 | 1967,-15.6,35.6,11.705753424657528
53 | 1968,-18.3,36.7,12.284836065573764
54 | 1969,-11.7,36.1,12.702191780821918
55 | 1970,-16.1,34.4,12.42027397260274
56 | 1971,-15.6,35.6,12.939726027397267
57 | 1972,-15,34.4,12.172540983606549
58 | 1973,-13.9,36.7,13.430821917808212
59 | 1974,-14.4,35,12.660684931506855
60 | 1975,-9.4,36.7,12.790684931506851
61 | 1976,-18.3,35.6,11.859699453551904
62 | 1977,-18.9,40,12.458356164383554
63 | 1978,-12.2,35,11.707123287671221
64 | 1979,-17.8,35,13.251780821917801
65 | 1980,-18.3,38.9,12.78374316939891
66 | 1981,-16.7,35.6,12.912876712328769
67 | 1982,-17.8,36.7,12.749178082191776
68 | 1983,-15.6,37.2,13.362191780821927
69 | 1984,-13.3,35.6,13.030327868852472
70 | 1985,-18.9,35,13.110821917808213
71 | 1986,-13.3,36.7,12.983287671232878
72 | 1987,-15.6,36.1,12.903287671232881
73 | 1988,-15,37.2,12.674316939890723
74 | 1989,-14.4,35.6,12.234657534246589
75 | 1990,-13.9,35,14.048219178082192
76 | 1991,-12.2,38.9,14.049178082191775
77 | 1992,-11.7,33.9,12.195081967213117
78 | 1993,-13.9,38.9,13.1131506849315
79 | 1994,-18.9,36.7,12.952602739726041
80 | 1995,-14.4,38.9,13.01150684931507
81 | 1996,-15,35.6,12.081420765027325
82 | 1997,-15.6,36.1,12.414246575342458
83 | 1998,-10,33.9,14.0149315068493
84 | 1999,-12.8,38.3,13.639589041095885
85 | 2000,-16.1,33.9,12.131420765027318
86 | 2001,-8.9,39.4,13.498493150684943
87 | 2002,-7.2,36.7,13.599999999999998
88 | 2003,-13.9,34.4,11.953150684931495
89 | 2004,-17.2,32.8,12.515846994535524
90 | 2005,-15,37.2,13.219863013698642
91 | 2006,-9.4,36.1,13.841506849315062
92 | 2007,-13.3,33.3,12.878493150684925
93 | 2008,-12.2,35.6,12.991803278688527
94 | 2009,-14.4,33.3,12.273972602739729
95 | 2010,-10.6,39.4,13.783698630136989
96 | 2011,-14.4,40,13.620684931506842
97 | 2012,-10.6,37.8,14.093579234972683
98 | 2013,-11.7,36.7,13.033150684931497
99 | 2014,-15.5,33.3,12.514657534246563
100 | 2015,-16.6,36.1,13.809726027397259
101 | 2016,-18.2,35.6,14.016803278688531
102 | 2017,-9.9,34.4,14.783536585365862
--------------------------------------------------------------------------------
/capture-visualization/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const webServer = require('./web-server.js');
4 | const captureWebPage = require('./toolkit/capture-web-page.js');
5 |
6 | webServer.start()
7 | .then(server => {
8 | const urlToCapture = "http://localhost:3000";
9 | const outputImagePath = "./output/nyc-temperatures.png";
10 | return captureWebPage(urlToCapture, "svg", outputImagePath)
11 | .then(() => server.close()); // Stop the web server when we are done.
12 | })
13 | .then(() => {
14 | console.log("All done :)");
15 | })
16 | .catch(err => {
17 | console.error("Something went wrong :(");
18 | console.error(err);
19 | });
20 |
--------------------------------------------------------------------------------
/capture-visualization/output/placeholder.txt:
--------------------------------------------------------------------------------
1 | This file is just to ensure that the output directory exists.
--------------------------------------------------------------------------------
/capture-visualization/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "listing-4",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "MIT",
12 | "dependencies": {
13 | "express": "4.16.2",
14 | "nightmare": "2.10.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/capture-visualization/public/app.css:
--------------------------------------------------------------------------------
1 |
2 | body {
3 | background: white;
4 | }
5 |
6 | /*
7 | Make the output image look better.
8 | */
9 | svg {
10 | padding: 5px;
11 | }
12 |
--------------------------------------------------------------------------------
/capture-visualization/public/app.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | //
4 | // Render a chart to a particular element on the page.
5 | //
6 | function renderChart (bindto, data, size) {
7 | var chart = c3.generate({
8 | bindto: bindto,
9 | size: size,
10 | data: {
11 | json: data,
12 | keys: {
13 | x: "Year",
14 | value: [
15 | "AvgTemp"
16 | ]
17 | }
18 | },
19 | transition: {
20 | duration: 0 // Disable animated transitions when we are capturing a static image.
21 | }
22 | });
23 | };
24 |
25 | $(function () {
26 |
27 | $.get("nyc-temperature.csv")
28 | .then(function (response) {
29 | var parseOptions = {
30 | header: true,
31 | dynamicTyping: true
32 | };
33 | const parsed = Papa.parse(response, parseOptions);
34 | const chartSize = {
35 | width: 600,
36 | height: 300
37 | };
38 | renderChart("#chart", parsed.data, chartSize);
39 | })
40 | .catch(function (err) {
41 | console.error(err);
42 | });
43 |
44 | });
45 |
46 |
--------------------------------------------------------------------------------
/capture-visualization/public/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "c3-template-web-page",
3 | "homepage": "https://github.com/JavaScript-Data-Wrangling/Chapter-10",
4 | "authors": [
5 | "Ashley Davis "
6 | ],
7 | "description": "",
8 | "main": "",
9 | "license": "MIT",
10 | "ignore": [
11 | "**/.*",
12 | "node_modules",
13 | "bower_components",
14 | "test",
15 | "tests"
16 | ],
17 | "dependencies": {
18 | "jquery": "^3.3.1",
19 | "c3": "^0.4.18",
20 | "papaparse": "^4.3.7"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/capture-visualization/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NYC average yearly temperature
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/capture-visualization/public/nyc-temperature.csv:
--------------------------------------------------------------------------------
1 | Year,MinTemp,MaxTemp,AvgTemp
2 | 1917,-25,37.8,10.547245179063365
3 | 1918,-21.1,40,11.825205479452052
4 | 1919,-18.3,37.2,12.125824175824178
5 | 1920,-18.9,34.4,11.286475409836074
6 | 1921,-15.6,35.6,12.751095890410959
7 | 1922,-18.9,34.4,12.001369863013698
8 | 1923,-13.9,37.2,11.665753424657524
9 | 1924,-15,37.2,11.08784153005464
10 | 1925,-18.9,37.2,11.937637362637368
11 | 1926,-15,37.8,10.772865013774107
12 | 1927,-18.3,33.3,11.932465753424664
13 | 1928,-13.9,34.4,11.961157024793385
14 | 1929,-13.3,37.2,12.328082191780814
15 | 1930,-13.9,38.9,12.53301369863014
16 | 1931,-11.7,37.2,13.26561643835617
17 | 1932,-11.7,35.6,12.900961538461535
18 | 1933,-21.1,38.9,12.447099447513821
19 | 1934,-26.1,38.3,11.733150684931507
20 | 1935,-18.3,35,11.739041095890402
21 | 1936,-19.4,41.1,11.940027322404374
22 | 1937,-10,37.8,12.546428571428576
23 | 1938,-14.4,35.6,12.938356164383551
24 | 1939,-14.4,35.6,12.62821917808219
25 | 1940,-13.9,36.7,11.04616438356164
26 | 1941,-12.2,36.7,12.78082191780821
27 | 1942,-20,36.1,12.310714285714294
28 | 1943,-22.2,37.2,12.117671232876717
29 | 1944,-11.1,38.9,12.637534246575356
30 | 1945,-16.7,36.1,12.307808219178066
31 | 1946,-15,34.4,13.040273972602742
32 | 1947,-13.9,35,12.159041095890403
33 | 1948,-17.8,39.4,12.316986301369864
34 | 1949,-8.3,38.9,13.88131868131868
35 | 1950,-14.4,35,12.076373626373627
36 | 1951,-13.3,34.4,12.815479452054786
37 | 1952,-13.3,37.8,13.236202185792356
38 | 1953,-10,38.9,13.947796143250693
39 | 1954,-13.9,37.8,12.737671232876705
40 | 1955,-17.8,37.8,12.68255494505495
41 | 1956,-10,37.2,11.957240437158474
42 | 1957,-17.8,38.3,13.081318681318683
43 | 1958,-16.1,33.9,11.46863013698631
44 | 1959,-13.9,36.1,13.060273972602742
45 | 1960,-13.3,32.8,12.23196721311476
46 | 1961,-18.9,36.1,12.839589041095888
47 | 1962,-15.6,37.2,11.958630136986303
48 | 1963,-18.9,36.7,12.046575342465754
49 | 1964,-12.8,37.2,12.555191256830605
50 | 1965,-12.8,35,12.37712328767122
51 | 1966,-13.3,39.4,12.846849315068491
52 | 1967,-15.6,35.6,11.705753424657528
53 | 1968,-18.3,36.7,12.284836065573764
54 | 1969,-11.7,36.1,12.702191780821918
55 | 1970,-16.1,34.4,12.42027397260274
56 | 1971,-15.6,35.6,12.939726027397267
57 | 1972,-15,34.4,12.172540983606549
58 | 1973,-13.9,36.7,13.430821917808212
59 | 1974,-14.4,35,12.660684931506855
60 | 1975,-9.4,36.7,12.790684931506851
61 | 1976,-18.3,35.6,11.859699453551904
62 | 1977,-18.9,40,12.458356164383554
63 | 1978,-12.2,35,11.707123287671221
64 | 1979,-17.8,35,13.251780821917801
65 | 1980,-18.3,38.9,12.78374316939891
66 | 1981,-16.7,35.6,12.912876712328769
67 | 1982,-17.8,36.7,12.749178082191776
68 | 1983,-15.6,37.2,13.362191780821927
69 | 1984,-13.3,35.6,13.030327868852472
70 | 1985,-18.9,35,13.110821917808213
71 | 1986,-13.3,36.7,12.983287671232878
72 | 1987,-15.6,36.1,12.903287671232881
73 | 1988,-15,37.2,12.674316939890723
74 | 1989,-14.4,35.6,12.234657534246589
75 | 1990,-13.9,35,14.048219178082192
76 | 1991,-12.2,38.9,14.049178082191775
77 | 1992,-11.7,33.9,12.195081967213117
78 | 1993,-13.9,38.9,13.1131506849315
79 | 1994,-18.9,36.7,12.952602739726041
80 | 1995,-14.4,38.9,13.01150684931507
81 | 1996,-15,35.6,12.081420765027325
82 | 1997,-15.6,36.1,12.414246575342458
83 | 1998,-10,33.9,14.0149315068493
84 | 1999,-12.8,38.3,13.639589041095885
85 | 2000,-16.1,33.9,12.131420765027318
86 | 2001,-8.9,39.4,13.498493150684943
87 | 2002,-7.2,36.7,13.599999999999998
88 | 2003,-13.9,34.4,11.953150684931495
89 | 2004,-17.2,32.8,12.515846994535524
90 | 2005,-15,37.2,13.219863013698642
91 | 2006,-9.4,36.1,13.841506849315062
92 | 2007,-13.3,33.3,12.878493150684925
93 | 2008,-12.2,35.6,12.991803278688527
94 | 2009,-14.4,33.3,12.273972602739729
95 | 2010,-10.6,39.4,13.783698630136989
96 | 2011,-14.4,40,13.620684931506842
97 | 2012,-10.6,37.8,14.093579234972683
98 | 2013,-11.7,36.7,13.033150684931497
99 | 2014,-15.5,33.3,12.514657534246563
100 | 2015,-16.6,36.1,13.809726027397259
101 | 2016,-18.2,35.6,14.016803278688531
102 | 2017,-9.9,34.4,14.783536585365862
--------------------------------------------------------------------------------
/capture-visualization/toolkit/capture-web-page.js:
--------------------------------------------------------------------------------
1 | //
2 | // A reusable toolkit function to capture a web page to an image file using Nightmare.
3 | //
4 |
5 | "use strict";
6 |
7 | const Nightmare = require('nightmare');
8 |
9 | //
10 | // Capture the web page specified by URL to the specifed image file.
11 | //
12 | function captureWebPage (urlToCapture, captureElementSelector, outputImagePath) {
13 | console.log("<< " + urlToCapture);
14 | console.log(">> " + outputImagePath);
15 |
16 | const nightmare = new Nightmare(); // Create an Nightmare instance.
17 | return nightmare.goto(urlToCapture) // Point the browser at the requested web page.
18 | .wait(captureElementSelector) // Wait until the specified HTML element appears on the screen.
19 | .evaluate(captureElementSelector => { // Evaluate JavaScript code within the headless browser. This function returns a promise which changes the way our code works.
20 | const body = document.querySelector("body"); // Find the body element of the web page.
21 | const captureElement = document.querySelector(captureElementSelector); // Find the HTML element to be captured in the DOM.
22 | const captureRect = captureElement.getBoundingClientRect(); // Get the area that we want to capture.
23 | return { // Return details computed in the headless browser to Node.js.
24 | documentArea: { // Return the scrollable area of the page, we will expand the size of the browser window to cover the entire documents (thus removing any scrollbars we might otherwise capture).
25 | width: body.scrollWidth,
26 | height: body.scrollHeight
27 | },
28 | captureArea: { // Return the rect of the area of the page (e.g. the chart) that we want to capture.
29 | x: captureRect.left,
30 | y: captureRect.top,
31 | width: captureRect.right - captureRect.left,
32 | height: captureRect.bottom - captureRect.top
33 | }
34 | };
35 | }, captureElementSelector)
36 | .then(pageDetails => { // Retrieve details computed in the headless browser. We can now use these value in subsequent Node.js code.
37 | return nightmare.viewport(pageDetails.documentArea.width, pageDetails.documentArea.height) // Set the viewport to cover the area of the chart.
38 | .screenshot(outputImagePath, pageDetails.captureArea) // Capture a screenshot to an image file.
39 | .end(); // End the Nightmare session. Any queued operations are complated and the headless browser is terminated.
40 | });
41 | };
42 |
43 | module.exports = captureWebPage; // Export the function so we can use it in other code modules.
--------------------------------------------------------------------------------
/capture-visualization/web-server.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const express = require('express');
4 | const path = require('path');
5 |
6 | module.exports = {
7 | start: () => { // Export a start function so our main module can start the web server at its leisure.
8 | return new Promise((resolve, reject) => { // Wrap web server startup in a promise.
9 | const app = express();
10 |
11 | const staticFilesPath = path.join(__dirname, "public"); // Make our 'public' sub-directory accessible via HTTP.
12 | const staticFilesMiddleWare = express.static(staticFilesPath);
13 | app.use('/', staticFilesMiddleWare);
14 |
15 | const server = app.listen(3000, err => { // Start our web server!
16 | if (err) {
17 | reject(err); // Error occurred while starting web server.
18 | }
19 | else {
20 | resolve(server); // Web server started ok.
21 | }
22 | });
23 | });
24 | }
25 | }
--------------------------------------------------------------------------------
/images/support1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Data-Wrangling-with-JavaScript/nodejs-visualization-example/f70c9a1276a842df22a69392deb1b57d200fed72/images/support1.png
--------------------------------------------------------------------------------