Skip to content

Commit e157866

Browse files
committed
Code to capture the visualization using Nightmare.
1 parent 0967576 commit e157866

File tree

10 files changed

+624
-0
lines changed

10 files changed

+624
-0
lines changed

Diff for: capture-visualization/index.js

+434
Large diffs are not rendered by default.

Diff for: capture-visualization/output/placeholder.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This file is just to ensure that the output directory exists.

Diff for: capture-visualization/package.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
}

Diff for: capture-visualization/toolkit/capture-web-page.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.

Diff for: capture-visualization/toolkit/charts.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"use strict";
2+
3+
const webServer = require('./template-chart/web-server.js');
4+
const captureWebPage = require('./capture-web-page.js');
5+
6+
//
7+
// A function that renders data to a line chart. Outputs an image file at the specified path.
8+
//
9+
function renderLineChart (data, chartSize, outputImagePath) {
10+
return webServer.start(data, chartSize)
11+
.then(server => {
12+
const urlToCapture = "http://localhost:3000";
13+
return captureWebPage(urlToCapture, "svg", outputImagePath)
14+
.then(() => server.close());
15+
});
16+
};
17+
18+
module.exports = {
19+
renderLineChart: renderLineChart,
20+
21+
// ... You might want to add other chart types here ...
22+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
body {
3+
background: white;
4+
}
5+
6+
/*
7+
Make the output image look better.
8+
*/
9+
svg {
10+
padding: 5px;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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: data, // The entire data object is now being passed through from Node.js.
11+
transition: {
12+
duration: 0 // Disable animated transitions when we are capturing a static image.
13+
}
14+
});
15+
};
16+
17+
$(function () {
18+
19+
$.get("chart-data") // Now using a new 'chart-data' REST API that provides the entire data object for the chart.
20+
.then(function (response) {
21+
renderChart("#chart", response.data, response.chartSize);
22+
})
23+
.catch(function (err) {
24+
console.error(err);
25+
});
26+
});
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "c3-template-web-page",
3+
"homepage": "https://github.com/JavaScript-Data-Wrangling/Chapter-10",
4+
"authors": [
5+
"Ashley Davis <[email protected]>"
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+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<title>NYC average yearly temperature</title>
5+
6+
<link href="bower_components/c3/c3.css" rel="stylesheet">
7+
<link href="app.css" rel="stylesheet">
8+
9+
<script src="bower_components/jquery/dist/jquery.js"></script>
10+
<script src="bower_components/d3/d3.js"></script>
11+
<script src="bower_components/c3/c3.js"></script>
12+
<script src="app.js"></script>
13+
</head>
14+
<body>
15+
<div id='chart'></div>
16+
</body>
17+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"use strict";
2+
3+
const express = require('express');
4+
const path = require('path');
5+
6+
module.exports = {
7+
start: (data, chartSize) => { // Start a web server, we pass the C3 data object through to the web-server via the 'start' function.
8+
return new Promise((resolve, reject) => {
9+
const app = express();
10+
11+
const staticFilesPath = path.join(__dirname, "public");
12+
const staticFilesMiddleWare = express.static(staticFilesPath);
13+
app.use("/", staticFilesMiddleWare);
14+
15+
app.get("/chart-data", (request, response) => { // Make the data available to the web-app via the REST API (HTTP GET).
16+
response.json({
17+
data: data,
18+
chartSize: chartSize,
19+
});
20+
});
21+
22+
const server = app.listen(3000, err => { // Start our web server!
23+
if (err) {
24+
reject(err);
25+
}
26+
else {
27+
resolve(server);
28+
}
29+
});
30+
});
31+
}
32+
}

0 commit comments

Comments
 (0)