diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 1ff0c42..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,63 +0,0 @@
-###############################################################################
-# Set default behavior to automatically normalize line endings.
-###############################################################################
-* text=auto
-
-###############################################################################
-# Set default behavior for command prompt diff.
-#
-# This is need for earlier builds of msysgit that does not have it on by
-# default for csharp files.
-# Note: This is only used by command line
-###############################################################################
-#*.cs diff=csharp
-
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-#*.sln merge=binary
-#*.csproj merge=binary
-#*.vbproj merge=binary
-#*.vcxproj merge=binary
-#*.vcproj merge=binary
-#*.dbproj merge=binary
-#*.fsproj merge=binary
-#*.lsproj merge=binary
-#*.wixproj merge=binary
-#*.modelproj merge=binary
-#*.sqlproj merge=binary
-#*.wwaproj merge=binary
-
-###############################################################################
-# behavior for image files
-#
-# image files are treated as binary by default.
-###############################################################################
-#*.jpg binary
-#*.png binary
-#*.gif binary
-
-###############################################################################
-# diff behavior for common document formats
-#
-# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the
-# entries below.
-###############################################################################
-#*.doc diff=astextplain
-#*.DOC diff=astextplain
-#*.docx diff=astextplain
-#*.DOCX diff=astextplain
-#*.dot diff=astextplain
-#*.DOT diff=astextplain
-#*.pdf diff=astextplain
-#*.PDF diff=astextplain
-#*.rtf diff=astextplain
-#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
index 54a42e0..5148e52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,157 +1,37 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.sln.docstates
-
-# Build results
-
-[Dd]ebug/
-[Rr]elease/
-x64/
-build/
-[Bb]in/
-[Oo]bj/
-
-# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
-!packages/*/build/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-*_i.c
-*_p.c
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
+# Logs
+logs
*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.log
-*.scc
-*.sln
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opensdf
-*.sdf
-*.cachefile
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-*.ncrunch*
-.*crunch*.local.xml
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.Publish.xml
-
-# NuGet Packages Directory
-## TODO: If you have NuGet Package Restore enabled, uncomment the next line
-#packages/
-
-# Windows Azure Build Output
-csx
-*.build.csdef
-
-# Windows Store app package directory
-AppPackages/
-
-# Others
-sql/
-*.Cache
-ClientBin/
-[Ss]tyle[Cc]op.*
-~$*
-*~
-*.dbmdl
-*.[Pp]ublish.xml
-*.pfx
-*.publishsettings
+npm-debug.log*
-# RIA/Silverlight projects
-Generated_Code/
+# Runtime data
+pids
+*.pid
+*.seed
-# Backup & report files from converting an old project file to a newer
-# Visual Studio version. Backup files are not needed, because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
-# SQL Server files
-App_Data/*.mdf
-App_Data/*.ldf
+# Coverage directory used by tools like istanbul
+coverage
+# nyc test coverage
+.nyc_output
-#LightSwitch generated files
-GeneratedArtifacts/
-_Pvt_Extensions/
-ModelManifest.xml
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
-# =========================
-# Windows detritus
-# =========================
+# node-waf configuration
+.lock-wscript
-# Windows image file caches
-Thumbs.db
-ehthumbs.db
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
-# Folder config file
-Desktop.ini
+# Dependency directories
+node_modules
+jspm_packages
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
+# Optional npm cache directory
+.npm
-# Mac desktop service store files
-.DS_Store
+# Optional REPL history
+.node_repl_history
diff --git a/README.md b/README.md
index 4e02eea..ecadb2f 100644
--- a/README.md
+++ b/README.md
@@ -26,18 +26,24 @@ var ctx = canvas.getContext('2d');
ctx.fillStyle = "slateGray";
ctx.fillRect(28, 28, 200, 200)(); // function call is intentional!
```
-this gives you an error on startup? check out [startup-errors](https://github.com/indus/ncc#startup-errors)
+
### Examples
+
1. **[draw ncc logo](https://github.com/indus/ncc/blob/master/examples/1_draw_ncc_logo.js)**
>>> **learn** how to setup ncc and draw shapes to canvas
+
2. **[early access](https://github.com/indus/ncc/blob/master/examples/2_early_access.js)**
>>> **learn** how to start using ncc even before it is fully set up
+
3. **[get return values](https://github.com/indus/ncc/blob/master/examples/3_get_return_values.js)**
>>> **learn** how to get return values of non-void functions
+
4. **[gardients/patterns](https://github.com/indus/ncc/blob/master/examples/4_gradients_and_patterns.js)**
>>> **learn** how to use gradients and patterns
+
5. **[images](https://github.com/indus/ncc/blob/master/examples/5_images.js)**
>>> **learn** how to apply images from urls or the filesystem
+
6. **[shadow canvas](https://github.com/indus/ncc/blob/master/examples/6_shadow_canvas.js)**
>>> **learn** how work with more than one canvas
@@ -52,7 +58,7 @@ this gives you an error on startup? check out [startup-errors](https://github.co
... as close as possible.
Differences are a result of the asynchronous nature of **ncc**. All object creations, method calls and property manipulations don't get processed directly, but get serialized and stored until a return value is necessary and a request is therefore unavoidable.
-Every 'Object' provided by **ncc** (and also every of their methods returns) is actually a function to trigger a synchronization. You can pass a error-first-callback ( 'function(error, result){...}' ) to such a function to receive the return value of the last action (see [examples](https://github.com/indus/ncc#examples)).
+Every 'Object' provided by **ncc** (and also every return value of a method) is actually a function to trigger a synchronization. You can pass a error-first-callback ( 'function(error, result){...}' ) to such a function to receive the return value of the last action (see [examples](https://github.com/indus/ncc#examples)).
@@ -66,7 +72,7 @@ Methods and properties beyond the native API are marked with a leading underscor
* **ncc(** <options> **,** <callback> **)** >>> **[canvas]**
**ncc(** <callback> **)** >>> **[canvas]**
-* **ncc.createCanvas()** >>> **[canvas]**
+* **ncc.createCanvas()** >>> **[canvas]** *if one is not enough*
* **ncc.createImage(** <src> **,** <onloadFn> **,** <onerrorFn> **)** >>> **[image]**
@@ -78,35 +84,10 @@ Methods and properties beyond the native API are marked with a leading underscor
#### options (with defaults)
```javascript
-{ logLevel: 2,
+{ logLevel: 'info', //['log','info','warn','error']
port: 9222,
- retry: 3,
- retryDelay: 1000,
- spawn: {
- command: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
- args: [ '--app=' + __dirname + '\\index.html',
- '--remote-debugging-port={PORT}',
- '--user-data-dir=' + os.tmpdir() + '\\nccanvas' ],
- options: {}
- }
+ retry: 9,
+ retryDelay: 500,
+ headless: false
}
```
-### startup-errors
-**ncc** is preconfigured to start a chrome childprocess on a Windows system with a default Chrome installation. If you are facing problems getting **ncc** started (especially on a non-windows system) you should make changes to the 'spawn'-[options](https://github.com/indus/ncc#options). If you are not sure what options you need, you can try to **[spawn](http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options)** a blank chrome instance first...
-```javascript
-var spawn = require('child_process').spawn,
- args = [],
- chrome = spawn('path/to/chromeExecutable', args);
-
-chrome.stdout.on('data', function (data) {
- console.log('stdout: ' + data);
-});
-
-chrome.stderr.on('data', function (data) {
- console.log('stderr: ' + data);
-});
-
-chrome.on('close', function (code) {
- console.log('child process exited with code ' + code);
-});
-```
diff --git a/examples/1_draw_ncc_logo.js b/examples/1_draw_ncc_logo.js
index c012cac..695e112 100644
--- a/examples/1_draw_ncc_logo.js
+++ b/examples/1_draw_ncc_logo.js
@@ -1,23 +1,15 @@
// NCC Example 1 - draw ncc logo
-var ncc = require('ncc');
+var ncc = require('../index.js'); // require('ncc');
console.time("ncc startup time");
// --- INFO ---
// ncc uses error-first callbacks
-ncc(function (err, canvas) {
+ncc({ logLevel: 'log' }, function (err, canvas) {
- // --- INFO ---
- // if you see errors you probably have to call 'ncc' with options
- //
- // 'ncc(,)'
-
- if (err) {
- console.error("ncc startup Error:", err);
- return;
- }
+ if (err) throw err;
console.timeEnd("ncc startup time");
console.time("ncc draw time");
@@ -84,10 +76,10 @@ ncc(function (err, canvas) {
// to actually trigger the action and see a result you have to call a function:
ctx(function (err, ctx) {
- if (err)
- console.error("ncc draw Error:", err);
+ if (err) throw err;
+
console.timeEnd("ncc draw time");
- console.log("\n\033[46m\t" + "Tataa!" + "\033[49m\n");
+ console.log("Tataa!");
})
// --- ALTERNATIVES ---
diff --git a/examples/2_early_access.js b/examples/2_early_access.js
index 520ad9e..404f2c5 100644
--- a/examples/2_early_access.js
+++ b/examples/2_early_access.js
@@ -1,18 +1,15 @@
// NCC Example 2 - early access
-var ncc = require('ncc');
+var ncc = require('../index.js'); // require('ncc');
// --- INFO ---
// 'ncc' returns the very same canvas two times; in the startup-callback and also directly
// you can use canvas before the startup has finished, all callbacks will be invoked in order when 'ncc' is ready
var canvas = ncc(function (err, canvas) {
- if (err) {
- console.error("ncc startup Error:", err);
- return;
- }
+ if (err) throw err;
- console.log("\n\033[46m\t" + "... in order of creation!" + "\033[49m\n");
+ console.log("... in order of creation!");
})
// --- ALTERNATIVES ---
@@ -33,6 +30,8 @@ ctx.textAlign = "center";
ctx.fillText("NCC Example 2 - early access", canvas.width / 2, 60, canvas.width-50);
ctx(function (err, res) {
- console.log("\n\033[46m\t" + "all callbacks get invoked ..." + "\033[49m\n");
+ if (err) throw err;
+
+ console.log("all callbacks get invoked ...");
})
diff --git a/examples/3_get_return_values.js b/examples/3_get_return_values.js
index fda6247..68a2e6f 100644
--- a/examples/3_get_return_values.js
+++ b/examples/3_get_return_values.js
@@ -1,12 +1,9 @@
// NCC Example 3 - get return values
-var ncc = require('ncc');
+var ncc = require('../index.js'); // require('ncc');
var canvas = ncc(function (err, canvas) {
- if (err) {
- console.error("ncc startup Error:", err);
- return;
- }
+ if (err) throw err;
var ctx = canvas.getContext("2d");
@@ -14,15 +11,12 @@ var canvas = ncc(function (err, canvas) {
var text = "look how exact this fits"
ctx.measureText(text)(function (err, val) {
- if (err) {
- console.error("measureText Error:", err);
- return;
- }
+ if (err) throw err;
// --- INFO ---
// 'val' is whatever the function-call would have returned directly in the browser
- console.log("\n\033[46m\t" + "textWidth: '" + val.width + "'" + "\033[49m\n");
+ console.log(">>> textWidth: '" + val.width + "'");
canvas.width = val.width;
canvas.height = 22;
@@ -40,12 +34,9 @@ var canvas = ncc(function (err, canvas) {
// 'canvas.toDataURL()(callback)' not! 'canvas.toDataURL(callback)'
canvas.toDataURL('image/jpeg', .5)(function (err, val) {
- if (err) {
- console.error("toDataURL Error:", err);
- return;
- }
+ if (err) throw err;
- console.log("\n\033[46m\t" + "dataURL: '" + val.substring(0, 40) + "...' [length: " + val.length + "]" + "\033[49m\n");
+ console.log(">>> dataURL: '" + val.substring(0, 40) + "...' [length: " + val.length + "]");
})
});
})
diff --git a/examples/4_gradients_and_patterns.js b/examples/4_gradients_and_patterns.js
index 1ee9b4c..b157e39 100644
--- a/examples/4_gradients_and_patterns.js
+++ b/examples/4_gradients_and_patterns.js
@@ -1,12 +1,9 @@
// NCC Example 4 - gradients and patterns
-var ncc = require('ncc');
+var ncc = require('../index.js'); // require('ncc');
var canvas = ncc(function (err, canvas) {
- if (err) {
- console.error("ncc startup Error:", err);
- return;
- }
+ if (err) throw err;
canvas.width = 256;
canvas.height = 256;
@@ -23,11 +20,7 @@ var canvas = ncc(function (err, canvas) {
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 256, 256)(function (err, val) {
-
- if (err) {
- console.error("gradient Error:", err);
- return;
- }
+ if (err) throw err;
// --- INFO ---
// now we reuse the filled canvas in a pattern and draw it back to canvas
@@ -38,12 +31,9 @@ var canvas = ncc(function (err, canvas) {
ctx.scale(.1, .1)
ctx.fill()(function (err, res) {
- if (err) {
- console.error("pattern Error:", err);
- return;
- }
+ if (err) throw err;
- console.error("\n\033[46m\t" + "Tataa!" + "\033[49m\n");
+ console.error("Tataa!");
});
});
diff --git a/examples/5_images.js b/examples/5_images.js
index eeabe03..0516211 100644
--- a/examples/5_images.js
+++ b/examples/5_images.js
@@ -1,12 +1,9 @@
// NCC Example 5 - images
-var ncc = require('ncc');
+var ncc = require('../index.js'); // require('ncc');
var canvas = ncc(function (err, canvas) {
- if (err) {
- console.error("ncc startup Error:", err);
- return;
- }
+ if (err) throw err;
var img = ncc.createImage();
@@ -24,12 +21,9 @@ var canvas = ncc(function (err, canvas) {
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 10, 10)(function (err,res) {
- if (err) {
- console.error("drawImage Error:", err);
- return;
- }
+ if (err) throw err;
- console.log("\n\033[46m\t" + "Hi! My name is Stefan, but you can call me 'indus'!" + "\033[49m\n");
+ console.log("Hi! My name is Stefan, but you can call me 'indus'!");
});
}
@@ -37,7 +31,7 @@ var canvas = ncc(function (err, canvas) {
// setting 'src' triggers image loading:
//
// from the filesystem: 'img.src = "path/to/image.png"'
- // from a url: 'img.src = "http://www.yourSite.com/image.png"' ('https://...' and 'ftp://..' is not supported)
+ // from a URL: 'img.src = "http://www.yourSite.com/image.png"' ('https://...' and 'ftp://..' is not supported)
// from a dataURL: 'img.src = "data:image/png;base64, ..."'
img.src = __dirname + "/dummy.jpg"
@@ -54,7 +48,7 @@ var canvas = ncc(function (err, canvas) {
//
// 'var dataURL = img._base64'
//
- // and also it has a hidden function to write it to the filesystem
+ // and it also has a hidden function to write it directly to the filesystem
//
// 'img._toFile('path/to/newImg.png',)'
diff --git a/examples/6_shadow_canvas.js b/examples/6_shadow_canvas.js
index 745014f..9a812e0 100644
--- a/examples/6_shadow_canvas.js
+++ b/examples/6_shadow_canvas.js
@@ -1,29 +1,28 @@
// NCC Example 6 - shadow-canvas
-var ncc = require('ncc');
+var ncc = require('../index.js'); // require('ncc');
// --- INFO ---
// first we create a shadow-canvas and fill it with a simple stroke pattern
-var canvas_shadow = ncc.createCanvas()
+var shadow_canvas = ncc.createCanvas()
-canvas_shadow.width = 150;
-canvas_shadow.height = 150;
+shadow_canvas.width = 150;
+shadow_canvas.height = 150;
-var ctx_shadow = canvas_shadow.getContext("2d");
+var ctx_shadow = shadow_canvas.getContext("2d");
ctx_shadow.strokeStyle = "slateGrey";
for (var i = 20; i < 150; i += 10) {
- ctx_shadow.lineWidth = i/50;
+ ctx_shadow.lineWidth = i / 50;
ctx_shadow.strokeRect((150 - i) / 2, (150 - i) / 2, i, i);
+ console.log((150 - i) / 2, (150 - i) / 2, i, i);
}
+
ncc(function (err, canvas_main) {
- if (err) {
- console.error("ncc startup Error:", err);
- return;
- }
+ if (err) throw err;
// --- INFO ---
// now after startup finished we use the shadow-canvas to draw it on the main-canvas two times
@@ -35,30 +34,27 @@ ncc(function (err, canvas_main) {
ctx_main.save()
ctx_main.translate(128, 128);
- ctx_main.rotate(Math.PI / 180 * 45)();
+ ctx_main.rotate(Math.PI / 180 * 45);
ctx_main.translate(-75, -75);
- ctx_main.drawImage(canvas_shadow, 0, 0)
+ ctx_main.drawImage(shadow_canvas, 0, 0)
ctx_main.restore()
ctx_main.translate(128, 128);
ctx_main.rotate(Math.PI / 180 * 90);
ctx_main.translate(-75, -75);
- ctx_main.drawImage(canvas_shadow, 0, 0);
+ ctx_main.drawImage(shadow_canvas, 0, 0);
// --- INFO ---
// to give garbage collection a chance you should nullify all proxy-objects (image, canvas, etc.) that are no longer in use
- // every proxy-object has a hidden attribute '_remote' taht has to be set to 'null' explicitly:
-
- canvas_shadow = canvas_shadow._remote = null;
+ // every proxy-object has a hidden attribute '_remote' that has to be set to 'null' explicitly:
+
+ shadow_canvas = shadow_canvas._remote = null;
ctx_main(function (err, res) {
- if (err) {
- console.error("shadow canvas Error:", err);
- return;
- }
- console.log("\n\033[46m\t" + "Tataa!" + "\033[49m\n");
+ if (err) throw err;
+ console.log("Tataa!");
})
// --- INFO ---
diff --git a/lib/chrome-launcher.ts b/lib/chrome-launcher.ts
new file mode 100644
index 0000000..55d4f2e
--- /dev/null
+++ b/lib/chrome-launcher.ts
@@ -0,0 +1,474 @@
+/**
+ * This is a stripped down and bundeled version of
+ * - https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-cli/chrome-launcher.ts
+ * - https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-cli/chrome-finder.ts
+ * It be replaced when the ChromeLauncher becomes a module: https://github.com/GoogleChrome/lighthouse/issues/2092
+ * But for now this saves us about 60 MB of modules
+ */
+
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+var ChromeLauncher = (() => {
+ var childProcess = require('child_process');
+ var fs = require('fs');
+ var path = require('path');
+
+ const mkdirp = require('mkdirp');
+ var net = require('net');
+ const rimraf = require('rimraf');
+ const spawn = childProcess.spawn;
+ const execSync = childProcess.execSync;
+ const isWindows = process.platform === 'win32';
+ const execFileSync = require('child_process').execFileSync;
+
+ const newLineRegex = /\r?\n/;
+
+ type Priorities = Array<{ regex: RegExp, weight: number }>;
+
+ function darwin() {
+ const suffixes = ['/Contents/MacOS/Google Chrome Canary', '/Contents/MacOS/Google Chrome'];
+
+ const LSREGISTER = '/System/Library/Frameworks/CoreServices.framework' +
+ '/Versions/A/Frameworks/LaunchServices.framework' +
+ '/Versions/A/Support/lsregister';
+
+ const installations: Array = [];
+
+ execSync(
+ `${LSREGISTER} -dump` +
+ ' | grep -i \'google chrome\\( canary\\)\\?.app$\'' +
+ ' | awk \'{$1=""; print $0}\'')
+ .toString()
+ .split(newLineRegex)
+ .forEach((inst: string) => {
+ suffixes.forEach(suffix => {
+ const execPath = path.join(inst.trim(), suffix);
+ if (canAccess(execPath)) {
+ installations.push(execPath);
+ }
+ });
+ });
+
+ // Retains one per line to maintain readability.
+ // clang-format off
+ const priorities: Priorities = [
+ { regex: new RegExp(`^${process.env.HOME}/Applications/.*Chrome.app`), weight: 50 },
+ { regex: new RegExp(`^${process.env.HOME}/Applications/.*Chrome Canary.app`), weight: 51 },
+ { regex: /^\/Applications\/.*Chrome.app/, weight: 100 },
+ { regex: /^\/Applications\/.*Chrome Canary.app/, weight: 101 },
+ { regex: /^\/Volumes\/.*Chrome.app/, weight: -2 },
+ { regex: /^\/Volumes\/.*Chrome Canary.app/, weight: -1 }
+ ];
+ // clang-format on
+
+ return sort(installations, priorities);
+ }
+
+ /**
+ * Look for linux executables in 3 ways
+ * 1. Look into LIGHTHOUSE_CHROMIUM_PATH env variable
+ * 2. Look into the directories where .desktop are saved on gnome based distro's
+ * 3. Look for google-chrome-stable & google-chrome executables by using the which command
+ */
+ function linux() {
+ let installations: Array = [];
+
+ // 1. Look into LIGHTHOUSE_CHROMIUM_PATH env variable
+ if (canAccess(process.env.LIGHTHOUSE_CHROMIUM_PATH)) {
+ installations.push(process.env.LIGHTHOUSE_CHROMIUM_PATH);
+ }
+
+ // 2. Look into the directories where .desktop are saved on gnome based distro's
+ const desktopInstallationFolders = [
+ path.join(require('os').homedir(), '.local/share/applications/'),
+ '/usr/share/applications/',
+ ];
+ desktopInstallationFolders.forEach(folder => {
+ installations = installations.concat(findChromeExecutables(folder));
+ });
+
+ // Look for google-chrome-stable & google-chrome executables by using the which command
+ const executables = [
+ 'google-chrome-stable',
+ 'google-chrome',
+ ];
+ executables.forEach((executable: string) => {
+ try {
+ const chromePath = execFileSync('which', [executable]).toString().split(newLineRegex)[0];
+
+ if (canAccess(chromePath)) {
+ installations.push(chromePath);
+ }
+ } catch (e) {
+ // Not installed.
+ }
+ });
+
+ if (!installations.length) {
+ throw new Error(
+ 'The environment variable LIGHTHOUSE_CHROMIUM_PATH must be set to ' +
+ 'executable of a build of Chromium version 54.0 or later.');
+ }
+
+ const priorities: Priorities = [
+ { regex: /chrome-wrapper$/, weight: 51 }, { regex: /google-chrome-stable$/, weight: 50 },
+ { regex: /google-chrome$/, weight: 49 },
+ { regex: new RegExp(process.env.LIGHTHOUSE_CHROMIUM_PATH), weight: 100 }
+ ];
+
+ return sort(uniq(installations.filter(Boolean)), priorities);
+ }
+
+ function win32() {
+ const installations: Array = [];
+ const suffixes = [
+ '\\Google\\Chrome SxS\\Application\\chrome.exe', '\\Google\\Chrome\\Application\\chrome.exe'
+ ];
+ const prefixes =
+ [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']];
+
+ if (canAccess(process.env.LIGHTHOUSE_CHROMIUM_PATH)) {
+ installations.push(process.env.LIGHTHOUSE_CHROMIUM_PATH);
+ }
+
+ prefixes.forEach(prefix => suffixes.forEach(suffix => {
+ const chromePath = path.join(prefix, suffix);
+ if (canAccess(chromePath)) {
+ installations.push(chromePath);
+ }
+ }));
+ return installations;
+ }
+
+ function sort(installations: Array, priorities: Priorities) {
+ const defaultPriority = 10;
+ return installations
+ // assign priorities
+ .map((inst: string) => {
+ for (const pair of priorities) {
+ if (pair.regex.test(inst)) {
+ return [inst, pair.weight];
+ }
+ }
+ return [inst, defaultPriority];
+ })
+ // sort based on priorities
+ .sort((a, b) => (b)[1] - (a)[1])
+ // remove priority flag
+ .map(pair => pair[0]);
+ }
+
+ function canAccess(file: string): Boolean {
+ if (!file) {
+ return false;
+ }
+
+ try {
+ fs.accessSync(file);
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+
+ function uniq(arr: Array) {
+ return Array.from(new Set(arr));
+ }
+
+ function findChromeExecutables(folder: string): Array {
+ const argumentsRegex = /(^[^ ]+).*/; // Take everything up to the first space
+ const chromeExecRegex = '^Exec=\/.*\/(google|chrome|chromium)-.*';
+
+ let installations: Array = [];
+ if (canAccess(folder)) {
+ // Output of the grep & print looks like:
+ // /opt/google/chrome/google-chrome --profile-directory
+ // /home/user/Downloads/chrome-linux/chrome-wrapper %U
+ let execPaths = execSync(`grep -ER "${chromeExecRegex}" ${folder} | awk -F '=' '{print $2}'`)
+ .toString()
+ .split(newLineRegex)
+ .map((execPath: string) => execPath.replace(argumentsRegex, '$1'));
+
+ execPaths.forEach((execPath: string) => canAccess(execPath) && installations.push(execPath));
+ }
+
+ return installations;
+ }
+
+ var chromeFinder = {
+ darwin: darwin,
+ linux: linux,
+ win32: win32
+ }
+
+ class ChromeLauncher {
+ prepared = false;
+ pollInterval: number = 500;
+ autoSelectChrome: boolean;
+ TMP_PROFILE_DIR: string;
+ outFile?: number;
+ errFile?: number;
+ pidFile: string;
+ startingUrl: string;
+ chromeFlags: Array;
+ chrome?: any;
+ port: number;
+
+ constructor(opts: {
+ startingUrl?: string,
+ chromeFlags?: Array,
+ autoSelectChrome?: boolean,
+ port?: number
+ } = {}) {
+ // choose the first one (default)
+ this.autoSelectChrome = defaults(opts.autoSelectChrome, true);
+ this.startingUrl = defaults(opts.startingUrl, 'about:blank');
+ this.chromeFlags = defaults(opts.chromeFlags, []);
+ this.port = defaults(opts.port, 9222);
+ }
+
+ flags() {
+ const flags = [
+ `--remote-debugging-port=${this.port}`,
+ // Disable built-in Google Translate service
+ '--disable-translate',
+ // Disable all chrome extensions entirely
+ '--disable-extensions',
+ // Disable various background network services, including extension updating,
+ // safe browsing service, upgrade detector, translate, UMA
+ '--disable-background-networking',
+ // Disable fetching safebrowsing lists, likely redundant due to disable-background-networking
+ '--safebrowsing-disable-auto-update',
+ // Disable syncing to a Google account
+ '--disable-sync',
+ // Disable reporting to UMA, but allows for collection
+ '--metrics-recording-only',
+ // Disable installation of default apps on first run
+ '--disable-default-apps',
+ // Skip first run wizards
+ '--no-first-run',
+ // Place Chrome profile in a custom location we'll rm -rf later
+ `--user-data-dir=${this.TMP_PROFILE_DIR}`
+ ];
+
+ if (process.platform === 'linux') {
+ flags.push('--disable-setuid-sandbox');
+ }
+
+ flags.push(...this.chromeFlags);
+ flags.push(this.startingUrl);
+
+ return flags;
+ }
+
+ prepare() {
+ switch (process.platform) {
+ case 'darwin':
+ case 'linux':
+ this.TMP_PROFILE_DIR = unixTmpDir();
+ break;
+
+ case 'win32':
+ this.TMP_PROFILE_DIR = win32TmpDir();
+ break;
+
+ default:
+ throw new Error('Platform ' + process.platform + ' is not supported');
+ }
+
+ this.outFile = fs.openSync(`${this.TMP_PROFILE_DIR}/chrome-out.log`, 'a');
+ this.errFile = fs.openSync(`${this.TMP_PROFILE_DIR}/chrome-err.log`, 'a');
+
+ // fix for Node4
+ // you can't pass a fd to fs.writeFileSync
+ this.pidFile = `${this.TMP_PROFILE_DIR}/chrome.pid`;
+
+ console.log('ChromeLauncher', `created ${this.TMP_PROFILE_DIR}`);
+
+ this.prepared = true;
+ }
+
+ run() {
+ if (!this.prepared) {
+ this.prepare();
+ }
+
+ return Promise.resolve()
+ .then(() => {
+ const installations = (chromeFinder)[process.platform]();
+
+ if (installations.length < 1) {
+ return Promise.reject(new Error('No Chrome Installations Found'));
+ } else if (installations.length === 1 || this.autoSelectChrome) {
+ return installations[0];
+ }
+
+ //return ask('Choose a Chrome installation to use with Lighthouse', installations);
+ })
+ .then(execPath => this.spawn(execPath));
+ }
+
+ spawn(execPath: string) {
+ const spawnPromise = new Promise(resolve => {
+ if (this.chrome) {
+ console.log('ChromeLauncher', `Chrome already running with pid ${this.chrome.pid}.`);
+ return resolve(this.chrome.pid);
+ }
+
+ const chrome = spawn(
+ execPath, this.flags(), { detached: true, stdio: ['ignore', this.outFile, this.errFile] });
+ this.chrome = chrome;
+
+ fs.writeFileSync(this.pidFile, chrome.pid.toString());
+
+ console.log('ChromeLauncher', `Chrome running with pid ${chrome.pid} on port ${this.port}.`);
+ resolve(chrome.pid);
+ });
+
+ return spawnPromise.then(pid => Promise.all([pid, this.waitUntilReady()]));
+ }
+
+ cleanup(client?: any) {
+ if (client) {
+ client.removeAllListeners();
+ client.end();
+ client.destroy();
+ client.unref();
+ }
+ }
+
+ // resolves if ready, rejects otherwise
+ isDebuggerReady(): Promise<{}> {
+ return new Promise((resolve, reject) => {
+ const client = net.createConnection(this.port);
+ client.once('error', err => {
+ this.cleanup(client);
+ reject(err);
+ });
+ client.once('connect', () => {
+ this.cleanup(client);
+ resolve();
+ });
+ });
+ }
+
+ // resolves when debugger is ready, rejects after 10 polls
+ waitUntilReady() {
+ const launcher = this;
+
+ return new Promise((resolve, reject) => {
+ let retries = 0;
+ let waitStatus = 'Waiting for browser.';
+ (function poll() {
+ if (retries === 0) {
+ console.log('ChromeLauncher', waitStatus);
+ }
+ retries++;
+ waitStatus += '..';
+ console.log('ChromeLauncher', waitStatus);
+
+ launcher.isDebuggerReady()
+ .then(() => {
+ console.log('ChromeLauncher', waitStatus);
+ resolve();
+ })
+ .catch(err => {
+ if (retries > 10) {
+ return reject(err);
+ }
+ delay(launcher.pollInterval).then(poll);
+ });
+ })();
+ });
+ }
+
+ kill() {
+ return new Promise(resolve => {
+ if (this.chrome) {
+ this.chrome.on('close', () => {
+ this.destroyTmp().then(resolve);
+ });
+
+ console.log('ChromeLauncher', 'Killing all Chrome Instances');
+ try {
+ if (isWindows) {
+ execSync(`taskkill /pid ${this.chrome.pid} /T /F`);
+ } else {
+ process.kill(-this.chrome.pid);
+ }
+ } catch (err) {
+ console.log('ChromeLauncher', `Chrome could not be killed ${err.message}`);
+ }
+
+ delete this.chrome;
+ } else {
+ // fail silently as we did not start chrome
+ resolve();
+ }
+ });
+ }
+
+ destroyTmp() {
+ return new Promise(resolve => {
+ if (!this.TMP_PROFILE_DIR) {
+ return resolve();
+ }
+
+ console.log('ChromeLauncher', `Removing ${this.TMP_PROFILE_DIR}`);
+
+ if (this.outFile) {
+ fs.closeSync(this.outFile);
+ delete this.outFile;
+ }
+
+ if (this.errFile) {
+ fs.closeSync(this.errFile);
+ delete this.errFile;
+ }
+
+ rimraf(this.TMP_PROFILE_DIR, () => resolve());
+ });
+ }
+ };
+
+ function defaults(val: T | undefined, def: T): T {
+ return typeof val === 'undefined' ? def : val;
+ }
+
+ function delay(time: number) {
+ return new Promise(resolve => setTimeout(resolve, time));
+ }
+
+ function unixTmpDir() {
+ return execSync('mktemp -d -t ncc.XXXXXXX').toString().trim();
+ }
+
+ function win32TmpDir() {
+ const winTmpPath = process.env.TEMP || process.env.TMP ||
+ (process.env.SystemRoot || process.env.windir) + '\\temp';
+ const randomNumber = Math.floor(Math.random() * 9e7 + 1e7);
+ const tmpdir = path.join(winTmpPath, 'ncc.' + randomNumber);
+
+ mkdirp.sync(tmpdir);
+ return tmpdir;
+ }
+ return ChromeLauncher;
+})()
+
diff --git a/lib/ncc.js b/lib/ncc.js
index 314cf6e..4c1cfa0 100644
--- a/lib/ncc.js
+++ b/lib/ncc.js
@@ -1,974 +1,1193 @@
-var DEBUG = false;
-
-var spawn = require('child_process').spawn, http = require('http'), fs = require('fs'), ws = require('ws'), os = require('os');
-
-var NCC = (function () {
- var NCC = function (options_, callback_) {
- if (callback_ !== false)
- console.log("\n\033[46m\t" + "[ncc] v0.2.0" + " \033[49m\n");
-
- var canvas = NCC.createCanvas(undefined, undefined, true);
-
- if (typeof (options_) == 'function') {
- callback_ = options_;
- options_ = null;
- }
-
- var callback = callback_;
-
- if (options_)
- for (var key in NCC.options)
- if (options_[key] !== undefined)
- NCC.options[key] = options_[key];
-
- if (NCC.options.spawn && NCC.chromePid === undefined) {
- NCC.log("[ncc | CP] start", 2);
-
- var command = NCC.options.spawn.command, args = NCC.options.spawn.args, options = NCC.options.spawn.options;
-
- var regExp = new RegExp('{(.*?)}'), re;
-
- for (var i = 0, l = args.length; i < l; i++) {
- re = regExp.exec(args[i]);
- if (re)
- args[i] = args[i].replace(re[0], NCC.options[re[1].toLowerCase()]);
+/**
+ * This is a stripped down and bundeled version of
+ * - https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-cli/chrome-launcher.ts
+ * - https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-cli/chrome-finder.ts
+ * It be replaced when the ChromeLauncher becomes a module: https://github.com/GoogleChrome/lighthouse/issues/2092
+ * But for now this saves us about 60 MB of modules
+ */
+/**
+ * @license
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'use strict';
+var ChromeLauncher = (() => {
+ var childProcess = require('child_process');
+ var fs = require('fs');
+ var path = require('path');
+ const mkdirp = require('mkdirp');
+ var net = require('net');
+ const rimraf = require('rimraf');
+ const spawn = childProcess.spawn;
+ const execSync = childProcess.execSync;
+ const isWindows = process.platform === 'win32';
+ const execFileSync = require('child_process').execFileSync;
+ const newLineRegex = /\r?\n/;
+ function darwin() {
+ const suffixes = ['/Contents/MacOS/Google Chrome Canary', '/Contents/MacOS/Google Chrome'];
+ const LSREGISTER = '/System/Library/Frameworks/CoreServices.framework' +
+ '/Versions/A/Frameworks/LaunchServices.framework' +
+ '/Versions/A/Support/lsregister';
+ const installations = [];
+ execSync(`${LSREGISTER} -dump` +
+ ' | grep -i \'google chrome\\( canary\\)\\?.app$\'' +
+ ' | awk \'{$1=""; print $0}\'')
+ .toString()
+ .split(newLineRegex)
+ .forEach((inst) => {
+ suffixes.forEach(suffix => {
+ const execPath = path.join(inst.trim(), suffix);
+ if (canAccess(execPath)) {
+ installations.push(execPath);
+ }
+ });
+ });
+ // Retains one per line to maintain readability.
+ // clang-format off
+ const priorities = [
+ { regex: new RegExp(`^${process.env.HOME}/Applications/.*Chrome.app`), weight: 50 },
+ { regex: new RegExp(`^${process.env.HOME}/Applications/.*Chrome Canary.app`), weight: 51 },
+ { regex: /^\/Applications\/.*Chrome.app/, weight: 100 },
+ { regex: /^\/Applications\/.*Chrome Canary.app/, weight: 101 },
+ { regex: /^\/Volumes\/.*Chrome.app/, weight: -2 },
+ { regex: /^\/Volumes\/.*Chrome Canary.app/, weight: -1 }
+ ];
+ // clang-format on
+ return sort(installations, priorities);
+ }
+ /**
+ * Look for linux executables in 3 ways
+ * 1. Look into LIGHTHOUSE_CHROMIUM_PATH env variable
+ * 2. Look into the directories where .desktop are saved on gnome based distro's
+ * 3. Look for google-chrome-stable & google-chrome executables by using the which command
+ */
+ function linux() {
+ let installations = [];
+ // 1. Look into LIGHTHOUSE_CHROMIUM_PATH env variable
+ if (canAccess(process.env.LIGHTHOUSE_CHROMIUM_PATH)) {
+ installations.push(process.env.LIGHTHOUSE_CHROMIUM_PATH);
+ }
+ // 2. Look into the directories where .desktop are saved on gnome based distro's
+ const desktopInstallationFolders = [
+ path.join(require('os').homedir(), '.local/share/applications/'),
+ '/usr/share/applications/',
+ ];
+ desktopInstallationFolders.forEach(folder => {
+ installations = installations.concat(findChromeExecutables(folder));
+ });
+ // Look for google-chrome-stable & google-chrome executables by using the which command
+ const executables = [
+ 'google-chrome-stable',
+ 'google-chrome',
+ ];
+ executables.forEach((executable) => {
+ try {
+ const chromePath = execFileSync('which', [executable]).toString().split(newLineRegex)[0];
+ if (canAccess(chromePath)) {
+ installations.push(chromePath);
+ }
+ }
+ catch (e) {
+ // Not installed.
+ }
+ });
+ if (!installations.length) {
+ throw new Error('The environment variable LIGHTHOUSE_CHROMIUM_PATH must be set to ' +
+ 'executable of a build of Chromium version 54.0 or later.');
+ }
+ const priorities = [
+ { regex: /chrome-wrapper$/, weight: 51 }, { regex: /google-chrome-stable$/, weight: 50 },
+ { regex: /google-chrome$/, weight: 49 },
+ { regex: new RegExp(process.env.LIGHTHOUSE_CHROMIUM_PATH), weight: 100 }
+ ];
+ return sort(uniq(installations.filter(Boolean)), priorities);
+ }
+ function win32() {
+ const installations = [];
+ const suffixes = [
+ '\\Google\\Chrome SxS\\Application\\chrome.exe', '\\Google\\Chrome\\Application\\chrome.exe'
+ ];
+ const prefixes = [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']];
+ if (canAccess(process.env.LIGHTHOUSE_CHROMIUM_PATH)) {
+ installations.push(process.env.LIGHTHOUSE_CHROMIUM_PATH);
+ }
+ prefixes.forEach(prefix => suffixes.forEach(suffix => {
+ const chromePath = path.join(prefix, suffix);
+ if (canAccess(chromePath)) {
+ installations.push(chromePath);
+ }
+ }));
+ return installations;
+ }
+ function sort(installations, priorities) {
+ const defaultPriority = 10;
+ return installations
+ .map((inst) => {
+ for (const pair of priorities) {
+ if (pair.regex.test(inst)) {
+ return [inst, pair.weight];
+ }
}
-
- NCC.log("[ncc | CP] spawn: " + command + " " + NCC.options.spawn.args.join(" "), 2);
-
- var chrome = spawn(command, args, options);
-
- NCC.chromePid = chrome.pid;
-
- chrome.on('close', function (code) {
- NCC.log('[ncc | CP] exited with code: ' + code, (code !== 0) ? 1 : 2);
- NCC.chromePid = null;
+ return [inst, defaultPriority];
+ })
+ .sort((a, b) => b[1] - a[1])
+ .map(pair => pair[0]);
+ }
+ function canAccess(file) {
+ if (!file) {
+ return false;
+ }
+ try {
+ fs.accessSync(file);
+ return true;
+ }
+ catch (e) {
+ return false;
+ }
+ }
+ function uniq(arr) {
+ return Array.from(new Set(arr));
+ }
+ function findChromeExecutables(folder) {
+ const argumentsRegex = /(^[^ ]+).*/; // Take everything up to the first space
+ const chromeExecRegex = '^Exec=\/.*\/(google|chrome|chromium)-.*';
+ let installations = [];
+ if (canAccess(folder)) {
+ // Output of the grep & print looks like:
+ // /opt/google/chrome/google-chrome --profile-directory
+ // /home/user/Downloads/chrome-linux/chrome-wrapper %U
+ let execPaths = execSync(`grep -ER "${chromeExecRegex}" ${folder} | awk -F '=' '{print $2}'`)
+ .toString()
+ .split(newLineRegex)
+ .map((execPath) => execPath.replace(argumentsRegex, '$1'));
+ execPaths.forEach((execPath) => canAccess(execPath) && installations.push(execPath));
+ }
+ return installations;
+ }
+ var chromeFinder = {
+ darwin: darwin,
+ linux: linux,
+ win32: win32
+ };
+ class ChromeLauncher {
+ constructor(opts = {}) {
+ this.prepared = false;
+ this.pollInterval = 500;
+ // choose the first one (default)
+ this.autoSelectChrome = defaults(opts.autoSelectChrome, true);
+ this.startingUrl = defaults(opts.startingUrl, 'about:blank');
+ this.chromeFlags = defaults(opts.chromeFlags, []);
+ this.port = defaults(opts.port, 9222);
+ }
+ flags() {
+ const flags = [
+ `--remote-debugging-port=${this.port}`,
+ // Disable built-in Google Translate service
+ '--disable-translate',
+ // Disable all chrome extensions entirely
+ '--disable-extensions',
+ // Disable various background network services, including extension updating,
+ // safe browsing service, upgrade detector, translate, UMA
+ '--disable-background-networking',
+ // Disable fetching safebrowsing lists, likely redundant due to disable-background-networking
+ '--safebrowsing-disable-auto-update',
+ // Disable syncing to a Google account
+ '--disable-sync',
+ // Disable reporting to UMA, but allows for collection
+ '--metrics-recording-only',
+ // Disable installation of default apps on first run
+ '--disable-default-apps',
+ // Skip first run wizards
+ '--no-first-run',
+ // Place Chrome profile in a custom location we'll rm -rf later
+ `--user-data-dir=${this.TMP_PROFILE_DIR}`
+ ];
+ if (process.platform === 'linux') {
+ flags.push('--disable-setuid-sandbox');
+ }
+ flags.push(...this.chromeFlags);
+ flags.push(this.startingUrl);
+ return flags;
+ }
+ prepare() {
+ switch (process.platform) {
+ case 'darwin':
+ case 'linux':
+ this.TMP_PROFILE_DIR = unixTmpDir();
+ break;
+ case 'win32':
+ this.TMP_PROFILE_DIR = win32TmpDir();
+ break;
+ default:
+ throw new Error('Platform ' + process.platform + ' is not supported');
+ }
+ this.outFile = fs.openSync(`${this.TMP_PROFILE_DIR}/chrome-out.log`, 'a');
+ this.errFile = fs.openSync(`${this.TMP_PROFILE_DIR}/chrome-err.log`, 'a');
+ // fix for Node4
+ // you can't pass a fd to fs.writeFileSync
+ this.pidFile = `${this.TMP_PROFILE_DIR}/chrome.pid`;
+ console.log('ChromeLauncher', `created ${this.TMP_PROFILE_DIR}`);
+ this.prepared = true;
+ }
+ run() {
+ if (!this.prepared) {
+ this.prepare();
+ }
+ return Promise.resolve()
+ .then(() => {
+ const installations = chromeFinder[process.platform]();
+ if (installations.length < 1) {
+ return Promise.reject(new Error('No Chrome Installations Found'));
+ }
+ else if (installations.length === 1 || this.autoSelectChrome) {
+ return installations[0];
+ }
+ //return ask('Choose a Chrome installation to use with Lighthouse', installations);
+ })
+ .then(execPath => this.spawn(execPath));
+ }
+ spawn(execPath) {
+ const spawnPromise = new Promise(resolve => {
+ if (this.chrome) {
+ console.log('ChromeLauncher', `Chrome already running with pid ${this.chrome.pid}.`);
+ return resolve(this.chrome.pid);
+ }
+ const chrome = spawn(execPath, this.flags(), { detached: true, stdio: ['ignore', this.outFile, this.errFile] });
+ this.chrome = chrome;
+ fs.writeFileSync(this.pidFile, chrome.pid.toString());
+ console.log('ChromeLauncher', `Chrome running with pid ${chrome.pid} on port ${this.port}.`);
+ resolve(chrome.pid);
});
-
- chrome.stdout.on('data', function (data) {
- NCC.log('[ncc | CP] stdout: ' + data, 2);
+ return spawnPromise.then(pid => Promise.all([pid, this.waitUntilReady()]));
+ }
+ cleanup(client) {
+ if (client) {
+ client.removeAllListeners();
+ client.end();
+ client.destroy();
+ client.unref();
+ }
+ }
+ // resolves if ready, rejects otherwise
+ isDebuggerReady() {
+ return new Promise((resolve, reject) => {
+ const client = net.createConnection(this.port);
+ client.once('error', err => {
+ this.cleanup(client);
+ reject(err);
+ });
+ client.once('connect', () => {
+ this.cleanup(client);
+ resolve();
+ });
});
-
- chrome.stderr.on('data', function (data) {
- NCC.log('[ncc | CP] stderr: ' + data, 1);
+ }
+ // resolves when debugger is ready, rejects after 10 polls
+ waitUntilReady() {
+ const launcher = this;
+ return new Promise((resolve, reject) => {
+ let retries = 0;
+ let waitStatus = 'Waiting for browser.';
+ (function poll() {
+ if (retries === 0) {
+ console.log('ChromeLauncher', waitStatus);
+ }
+ retries++;
+ waitStatus += '..';
+ console.log('ChromeLauncher', waitStatus);
+ launcher.isDebuggerReady()
+ .then(() => {
+ console.log('ChromeLauncher', waitStatus);
+ resolve();
+ })
+ .catch(err => {
+ if (retries > 10) {
+ return reject(err);
+ }
+ delay(launcher.pollInterval).then(poll);
+ });
+ })();
});
-
- chrome.on('error', function (err) {
- NCC.chromePid = null;
- NCC.log("[ncc | CP] error: " + err, 1);
+ }
+ kill() {
+ return new Promise(resolve => {
+ if (this.chrome) {
+ this.chrome.on('close', () => {
+ this.destroyTmp().then(resolve);
+ });
+ console.log('ChromeLauncher', 'Killing all Chrome Instances');
+ try {
+ if (isWindows) {
+ execSync(`taskkill /pid ${this.chrome.pid} /T /F`);
+ }
+ else {
+ process.kill(-this.chrome.pid);
+ }
+ }
+ catch (err) {
+ console.log('ChromeLauncher', `Chrome could not be killed ${err.message}`);
+ }
+ delete this.chrome;
+ }
+ else {
+ // fail silently as we did not start chrome
+ resolve();
+ }
});
}
-
- var url = "http://localhost:" + NCC.options.port + "/json";
-
- http.get(url, function (res) {
- NCC.log("[ncc | RDP] request started", 2);
-
- var rdJson = '';
-
- res.on('data', function (chunk) {
- rdJson += chunk;
+ destroyTmp() {
+ return new Promise(resolve => {
+ if (!this.TMP_PROFILE_DIR) {
+ return resolve();
+ }
+ console.log('ChromeLauncher', `Removing ${this.TMP_PROFILE_DIR}`);
+ if (this.outFile) {
+ fs.closeSync(this.outFile);
+ delete this.outFile;
+ }
+ if (this.errFile) {
+ fs.closeSync(this.errFile);
+ delete this.errFile;
+ }
+ rimraf(this.TMP_PROFILE_DIR, () => resolve());
});
-
- res.on('end', function () {
- NCC.log("[ncc | RDP] request ended", 2);
-
- var list = JSON.parse(rdJson);
-
- for (var i = 0, l = list.length; i < l; i++) {
- if (list[i].title == "ncc" && list[i].webSocketDebuggerUrl) {
- Object.defineProperties(rdp, {
- ws: {
- value: new ws(list[i].webSocketDebuggerUrl)
- }
- });
-
- rdp.ws.on('open', function () {
- NCC.log("[ncc | RDP] session established", 2);
-
- rdp(function (err, res) {
- if (err)
- NCC.log("[ncc] error: " + err.message, 1);
- if (callback)
- err ? callback(err, null) : callback(null, canvas, rdp);
- });
- });
-
- rdp.ws.on('close', function () {
- NCC.log("[ncc | RDP] session closed", 1);
- });
- return;
- } else {
- NCC.log("[ncc | RDP] remote not found" + ((NCC.options.retry) ? " - retry " + NCC.options.retry : ""), 1);
- if (NCC.options.retry--)
- setTimeout(NCC, NCC.options.retryDelay, callback, false);
- else if (callback)
- callback("remote not found");
+ }
+ }
+ ;
+ function defaults(val, def) {
+ return typeof val === 'undefined' ? def : val;
+ }
+ function delay(time) {
+ return new Promise(resolve => setTimeout(resolve, time));
+ }
+ function unixTmpDir() {
+ return execSync('mktemp -d -t ncc.XXXXXXX').toString().trim();
+ }
+ function win32TmpDir() {
+ const winTmpPath = process.env.TEMP || process.env.TMP ||
+ (process.env.SystemRoot || process.env.windir) + '\\temp';
+ const randomNumber = Math.floor(Math.random() * 9e7 + 1e7);
+ const tmpdir = path.join(winTmpPath, 'ncc.' + randomNumber);
+ mkdirp.sync(tmpdir);
+ return tmpdir;
+ }
+ return ChromeLauncher;
+})();
+///
+var http = require('http'), fs = require('fs'), ws = require('ws'), os = require('os');
+var DEBUG = false;
+var logger;
+var NCC = Object.defineProperties((options_, callback_) => {
+ if (typeof (options_) == 'function') {
+ callback_ = options_;
+ options_ = null;
+ }
+ var callback = callback_;
+ if (options_)
+ for (var key in NCC.options)
+ if (options_[key] !== undefined)
+ NCC.options[key] = options_[key];
+ logger = require('tracer').colorConsole({
+ format: "[ncc] {{message}}",
+ level: NCC.options.logLevel
+ });
+ var canvas = NCC.createCanvas(undefined, undefined, true);
+ var attempts = 0;
+ function connect() {
+ var url = `http://localhost:${NCC.options.port}/json`;
+ http.get(url, res => {
+ var rdJson = '';
+ res.on('data', chunk => rdJson += chunk);
+ res.on('end', () => {
+ var ncc_ = JSON.parse(rdJson).find(i => i.title === "ncc" || i.url === `${__dirname}/index.html`);
+ if (!ncc_) {
+ if (attempts < NCC.options.retry) {
+ attempts++;
+ logger.info(`connecting [retry ${attempts}/${NCC.options.retry}]`);
+ setTimeout(connect, NCC.options.retryDelay);
}
+ else
+ logger.error('connection failed');
+ return;
}
+ Object.defineProperties(rdp, { ws: { value: new ws(ncc_.webSocketDebuggerUrl) } });
+ rdp.ws.on('open', () => {
+ logger.info("connected");
+ rdp((err, res) => {
+ if (err)
+ logger.error(`[ncc] error: ${err.message}`);
+ if (callback)
+ err ? callback(err, null) : callback(null, canvas, rdp);
+ });
+ });
+ rdp.ws.on('close', () => logger.info("session closed"));
});
- }).on('error', function (err) {
- NCC.log("[ncc | RDP] request denied" + ((NCC.options.retry) ? " - retry " + NCC.options.retry : ""), 1);
- if (NCC.options.retry--)
- setTimeout(NCC, NCC.options.retryDelay, callback, false);
- else if (callback)
- callback(err.message, null);
});
-
- return canvas;
- };
-
- Object.defineProperties(NCC, {
- options: {
- enumerable: true,
- writable: true,
- value: {
- logLevel: 2,
- port: 9222,
- retry: 3,
- retryDelay: 1000,
- spawn: {
- command: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
- args: [
- '--app=' + __dirname + '\\index.html',
- '--remote-debugging-port={PORT}',
- '--user-data-dir=' + os.tmpdir() + '\\nccanvas'
- ],
- options: {}
- }
- }
- },
- createCanvas: {
- enumerable: true,
- value: function (width, height, main) {
- if (!main) {
- var uid = NCC.uid('canvas');
- rdp("var " + uid + " = document.createElement('canvas')");
- }
-
- var canvas = function (callback) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, canvas);
- } : undefined);
- return canvas;
- };
-
- CanvasPDM["_uid"].value = main ? 'canvas' : uid;
- Object.defineProperties(canvas, CanvasPDM);
- CanvasPDM["_uid"].value = "";
-
- canvas.width = width;
- canvas.height = height;
-
+ }
+ var launcher = new ChromeLauncher({
+ port: NCC.options.port,
+ autoSelectChrome: true,
+ startingUrl: NCC.options.headless ? `${__dirname}/index.html` : '',
+ chromeFlags: NCC.options.headless ?
+ ['--window-size=0,0', '--disable-gpu', '--headless'] :
+ [`--app=${__dirname}/index.html`]
+ });
+ const exitHandler = err => launcher.kill().then(() => process.exit(-1));
+ process.on('SIGINT', exitHandler);
+ process.on('unhandledRejection', exitHandler);
+ process.on('rejectionHandled', exitHandler);
+ process.on('uncaughtException', exitHandler);
+ launcher.run()
+ .then((a) => {
+ logger.info("chrome started");
+ connect();
+ })
+ .catch(err => {
+ return launcher.kill().then(() => {
+ logger.error("failed starting chrome");
+ throw err;
+ }, logger.error);
+ });
+ return canvas;
+}, {
+ options: {
+ enumerable: true,
+ writable: true,
+ value: {
+ logLevel: 'info',
+ port: 9222,
+ retry: 9,
+ retryDelay: 500,
+ headless: false
+ }
+ },
+ createCanvas: {
+ enumerable: true,
+ value: function (width, height, main) {
+ if (!main) {
+ var uid = NCC.uid('canvas');
+ rdp(`var ${uid} = document.createElement('canvas')`);
+ }
+ var canvas = (callback) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, canvas);
+ } : undefined);
return canvas;
- }
- },
- createImage: {
- enumerable: true,
- value: function (src, onload, onerror) {
- var uid = NCC.uid('image');
- rdp("var " + uid + " = new Image()");
- var image = function (callback) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, image);
- } : undefined);
- return image;
- };
-
- ImagePDM["_uid"].value = uid;
- Object.defineProperties(image, ImagePDM);
- ImagePDM["_uid"].value = "";
-
- image.src = src;
- image.onload = onload;
- image.onerror = onerror;
-
+ };
+ CanvasPDM._uid.value = main ? 'canvas' : uid;
+ Object.defineProperties(canvas, CanvasPDM);
+ CanvasPDM._uid.value = '';
+ canvas.width = width;
+ canvas.height = height;
+ return canvas;
+ }
+ },
+ createImage: {
+ enumerable: true,
+ value: function (src, onload, onerror) {
+ var uid = NCC.uid('image');
+ rdp(`var ${uid} = new Image()`);
+ var image = (callback) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, image);
+ } : undefined);
return image;
- }
- },
- uid: {
- enumerable: false,
- value: function (type) {
- return type + "_" + Math.random().toString(36).slice(2);
- }
- },
- log: {
- enumerable: false,
- value: function (msg, level) {
- if (!level || (level <= this.options.logLevel))
- console.log(msg);
- }
+ };
+ ImagePDM._uid.value = uid;
+ Object.defineProperties(image, ImagePDM);
+ ImagePDM._uid.value = '';
+ image.src = src;
+ image.onload = onload;
+ image.onerror = onerror;
+ return image;
}
- });
-
- return NCC;
-})();
-
+ },
+ uid: {
+ enumerable: false,
+ value: type => `${type}_${Math.random().toString(36).slice(2)}`
+ }
+});
// RDP | Remote Debugging Protocol (the bridge to chrome)
-var rdp = (function () {
- var rdp = function (_) {
- if (typeof _ == 'string') {
- if (NCC.options.logLevel >= 3)
- console.log("+ \033[33m" + _ + "\033[39m");
- rdp.cmd += _ + ";";
- return rdp;
- }
-
- if (_ !== null) {
- rdp.queue.push({
- cmd: rdp.cmd,
- callback: _
- });
- rdp.cmd = "";
- }
-
- if (!rdp.queue[0] || rdp.req == rdp.queue[0] || !rdp.ws)
- return rdp;
-
- rdp.req = rdp.queue[0];
-
+var rdp = Object.defineProperties((_) => {
+ if (typeof _ == 'string') {
if (NCC.options.logLevel >= 3)
- console.log("> \033[32m" + rdp.req.cmd.split(';').slice(0, -1).join(';\n ') + "\033[39m");
-
- rdp.ws.send('{"id":0,"method":"Runtime.evaluate", "params":{"expression":"' + rdp.req.cmd + '"}}');
- rdp.ws.once('message', function (data) {
- data = JSON.parse(data);
-
- if (NCC.options.logLevel >= 3)
- console.log("<\033[35m", data.error || data.result, "\033[39m");
-
- var err = data.error || data.result.wasThrown ? data.result.result.description : null, res = err ? null : data.result.result;
-
- if (rdp.req.callback)
- rdp.req.callback(err, res);
- rdp.req = rdp.queue.shift();
- rdp(null);
+ console.log(_);
+ rdp.cmd += _ + ';';
+ return rdp;
+ }
+ if (_ !== null) {
+ rdp.queue.push({
+ cmd: rdp.cmd,
+ callback: _
});
-
+ rdp.cmd = '';
+ }
+ if (!rdp.queue[0] || rdp.req == rdp.queue[0] || !rdp.ws)
return rdp;
- };
-
- Object.defineProperties(rdp, {
- cmd: {
- enumerable: DEBUG,
- writable: true,
- value: ""
- },
- queue: {
- enumerable: DEBUG,
- value: []
- }
+ rdp.req = rdp.queue[0];
+ logger.log(`> ${rdp.req.cmd.split(';').slice(0, -1).join(';\n ')}`);
+ rdp.ws.send(`{"id":0,"method":"Runtime.evaluate", "params":{"expression":"${rdp.req.cmd}"}}`);
+ rdp.ws.once('message', data => {
+ data = JSON.parse(data);
+ logger.log(data.error || data.result);
+ var err = data.error || data.result.wasThrown ? data.result.result.description : null, res = err ? null : data.result.result;
+ if (rdp.req.callback)
+ rdp.req.callback(err, res);
+ rdp.req = rdp.queue.shift();
+ rdp(null);
});
-
return rdp;
-})();
-
-
-
-
-var CanvasPDM = (function () {
- return {
- // private properties
- _uid: {
- configurable: true,
- enumerable: DEBUG,
- value: "canvas"
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- if (this._uid == "canvas")
- throw new Error("you cannot delete the main canvas");
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- this._ctx = null;
- } else
- throw new Error("'_remote' can only be set to 'null'");
- }
- },
- _ctx: {
- enumerable: DEBUG,
- writable: true,
- value: null
- },
- // Properties || proxies with defaults
- width_: {
- enumerable: DEBUG,
- writable: true,
- value: 300
- },
- height_: {
- enumerable: DEBUG,
- writable: true,
- value: 150
- },
- // Web API: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement
- // Properties || getters/setters || https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Properties
- width: {
- enumerable: true,
- get: function () {
- return this.width_;
- },
- set: function (width) {
- if (width === undefined)
- return;
- rdp(this._uid + '.width = ' + width);
- return this.width_ = width;
- }
- },
- height: {
- enumerable: true,
- get: function () {
- return this.height_;
- },
- set: function (height) {
- if (height === undefined)
- return;
- rdp(this._uid + '.height = ' + height);
- return this.height_ = height;
- }
- },
- // Methods || https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Methods
- getContext: {
- enumerable: true,
- value: function (contextId) {
- if (contextId == "2d") {
- var uid = NCC.uid('context2d');
- rdp("var " + uid + " = " + this._uid + ".getContext('2d')");
-
- var context2d = function (callback) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, context2d);
- } : undefined);
- return context2d;
- };
-
- context2dPDM["_uid"].value = uid;
- context2dPDM["canvas"].value = this;
- Object.defineProperties(context2d, context2dPDM);
- context2dPDM["_uid"].value = "";
-
- return context2d;
- }
-
- throw new Error(contextId + " is not implemented");
- }
- },
- toDataURL: {
- enumerable: true,
- value: function (type, args) {
- rdp(this._uid + ".toDataURL(" + (("'" + type + "'") || "") + ")");
-
- return function (callback) {
- rdp(function (err, res) {
- if (err)
- return callback(err, null);
- callback(err, res.value);
- });
- };
- }
+}, {
+ cmd: { enumerable: DEBUG, writable: true, value: '' },
+ queue: { enumerable: DEBUG, value: [] }
+});
+var CanvasPDM = {
+ // private properties
+ _uid: {
+ configurable: true,
+ enumerable: DEBUG,
+ value: "canvas"
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ if (this._uid == 'canvas')
+ return logger.error('you cannot delete the main canvas');
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ this._ctx = null;
+ }
+ else
+ return logger.error('"_remote" can only be set to "null"');
}
- };
-})();
-
-
-var context2dPDM = (function () {
- return {
- // private properties
- _uid: {
- enumerable: DEBUG,
- value: ""
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- } else
- throw new Error("'_remote' can only be set to 'null'");
- }
- },
- // Attributes || proxies with defaults
- fillStyle_: { writable: true, enumerable: DEBUG, value: '#000000' },
- font_: { writable: true, enumerable: DEBUG, value: '10px sans-serif' },
- globalAlpha_: { writable: true, enumerable: DEBUG, value: 1.0 },
- globalCompositeOperation_: { writable: true, enumerable: DEBUG, value: 'source-over' },
- lineCap_: { writable: true, enumerable: DEBUG, value: 'butt' },
- lineDashOffset_: { writable: true, enumerable: DEBUG, value: 0 },
- lineJoin_: { writable: true, enumerable: DEBUG, value: 'miter' },
- lineWidth_: { writable: true, enumerable: DEBUG, value: 1.0 },
- miterLimit_: { writable: true, enumerable: DEBUG, value: 10 },
- shadowBlur_: { writable: true, enumerable: DEBUG, value: 0 },
- shadowColor_: { writable: true, enumerable: DEBUG, value: 'rgba(0, 0, 0, 0)' },
- shadowOffsetX_: { writable: true, enumerable: DEBUG, value: 0 },
- shadowOffsetY_: { writable: true, enumerable: DEBUG, value: 0 },
- strokeStyle_: { writable: true, enumerable: DEBUG, value: '#000000' },
- textAlign_: { writable: true, enumerable: DEBUG, value: 'start' },
- textBaseline_: { writable: true, enumerable: DEBUG, value: 'alphabetic' },
- webkitBackingStorePixelRatio_: { writable: true, enumerable: DEBUG, value: 1 },
- webkitImageSmoothingEnabled_: { writable: true, enumerable: DEBUG, value: true },
- // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d
- // Attributes || getters/setters || https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d#Attributes
- canvas: {
- enumerable: true, value: null
- },
- fillStyle: {
- enumerable: true, get: function () {
- return this.fillStyle_;
- },
- set: function (fillStyle) {
- rdp(this._uid + ".fillStyle = " + (fillStyle._uid || ("'" + fillStyle + "'")));
- return this.fillStyle_ = fillStyle;
- }
- },
- font: {
- enumerable: true, get: function () {
- return this.font_;
- },
- set: function (font) {
- rdp(this._uid + ".font = '" + font + "'");
- return this.font_ = font;
- }
- },
- globalAlpha: {
- enumerable: true, get: function () {
- return this.globalAlpha_;
- },
- set: function (globalAlpha) {
- rdp(this._uid + ".globalAlpha = " + globalAlpha);
- return this.globalAlpha_ = globalAlpha;
- }
- },
- globalCompositeOperation: {
- enumerable: true, get: function () {
- return this.globalCompositeOperation_;
- },
- set: function (globalCompositeOperation) {
- rdp(this._uid + ".globalCompositeOperation = '" + globalCompositeOperation + "'");
- return this.globalCompositeOperation_ = globalCompositeOperation;
- }
- },
- lineCap: {
- enumerable: true, get: function () {
- return this.lineCap_;
- },
- set: function (lineCap) {
- rdp(this._uid + ".lineCap = '" + lineCap + "'");
- return this.lineCap_ = lineCap;
- }
- },
- lineDashOffset: {
- enumerable: true, get: function () {
- return this.lineDashOffset_;
- },
- set: function (lineDashOffset) {
- rdp(this._uid + ".lineDashOffset = " + lineDashOffset);
- return this.lineDashOffset_ = lineDashOffset;
- }
- },
- lineJoin: {
- enumerable: true, get: function () {
- return this.lineJoin_;
- },
- set: function (lineJoin) {
- rdp(this._uid + ".lineJoin = '" + lineJoin + "'");
- return this.lineJoin_ = lineJoin;
- }
- },
- lineWidth: {
- enumerable: true, get: function () {
- return this.lineWidth_;
- },
- set: function (lineWidth) {
- rdp(this._uid + ".lineWidth = " + lineWidth);
- return this.lineWidth_ = lineWidth;
- }
- },
- miterLimit: {
- enumerable: true, get: function () {
- return this.miterLimit_;
- },
- set: function (miterLimit) {
- rdp(this._uid + ".miterLimit = " + miterLimit);
- return this.miterLimit_ = miterLimit;
- }
- },
- shadowBlur: {
- enumerable: true, get: function () {
- return this.shadowBlur_;
- },
- set: function (shadowBlur) {
- rdp(this._uid + ".shadowBlur = " + shadowBlur);
- return this.shadowBlur_ = shadowBlur;
- }
- },
- shadowColor: {
- enumerable: true, get: function () {
- return this.shadowColor;
- },
- set: function (shadowColor) {
- rdp(this._uid + ".shadowColor = '" + shadowColor + "'");
- return this.shadowColor_ = shadowColor;
- }
- },
- shadowOffsetX: {
- enumerable: true, get: function () {
- return this.shadowOffsetX_;
- },
- set: function (shadowOffsetX) {
- rdp(this._uid + ".shadowOffsetX = " + shadowOffsetX);
- return this.shadowOffsetX_ = shadowOffsetX;
- }
- },
- shadowOffsetY: {
- enumerable: true, get: function () {
- return this.shadowOffsetY_;
- },
- set: function (shadowOffsetY) {
- rdp(this._uid + ".shadowOffsetY = " + shadowOffsetY);
- return this.shadowOffsetY_ = shadowOffsetY;
- }
- },
- strokeStyle: {
- enumerable: true, get: function () {
- return this.strokeStyle_;
- },
- set: function (strokeStyle) {
- rdp(this._uid + ".strokeStyle = " + (strokeStyle._uid || ("'" + strokeStyle + "'")));
- return this.strokeStyle_ = strokeStyle;
- }
- },
- textAlign: {
- enumerable: true, get: function () {
- return this.textAlign_;
- },
- set: function (textAlign) {
- rdp(this._uid + ".textAlign = '" + textAlign + "'");
- return this.textAlign_ = textAlign;
- }
- },
- textBaseline: {
- enumerable: true, get: function () {
- return this.textBaseline_;
- },
- set: function (textBaseline) {
- rdp(this._uid + ".textBaseline = '" + textBaseline + "'");
- return this.textBaseline_ = textBaseline;
- }
- },
- webkitBackingStorePixelRatio: {
- enumerable: true, get: function () {
- return this.webkitBackingStorePixelRatio_;
- },
- set: function (webkitBackingStorePixelRatio) {
- rdp(this._uid + ".webkitBackingStorePixelRatio = " + webkitBackingStorePixelRatio);
- return this.webkitBackingStorePixelRatio_ = webkitBackingStorePixelRatio;
- }
- },
- webkitImageSmoothingEnabled: {
- enumerable: true, get: function () {
- return this.webkitImageSmoothingEnabled_;
- },
- set: function (webkitImageSmoothingEnabled) {
- rdp(this._uid + ".webkitImageSmoothingEnabled = " + webkitImageSmoothingEnabled);
- return this.webkitImageSmoothingEnabled_ = webkitImageSmoothingEnabled;
- }
- },
- // Methods || https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d#Methods
- arc: {
- enumerable: true,
- value: function (x, y, radius, startAngle, endAngle, anticlockwise) {
- return rdp(this._uid + ".arc(" + (Array.prototype.slice.call(arguments, 0).join(',')) + ")");
- }
- },
- arcTo: {
- enumerable: true,
- value: function (x1, y1, x2, y2, radius) {
- return rdp(this._uid + ".arcTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + radius + ")");
- }
- },
- beginPath: {
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".beginPath()");
- }
- },
- bezierCurveTo: {
- enumerable: true,
- value: function (cp1x, cp1y, cp2x, cp2y, x, y) {
- return rdp(this._uid + ".bezierCurveTo(" + cp1x + ", " + cp1y + ", " + cp2x + ", " + cp2y + ", " + x + ", " + y + ")");
- }
- },
- clearRect: {
- enumerable: true,
- value: function (x, y, width, height) {
- return rdp(this._uid + ".clearRect(" + x + ", " + y + ", " + width + ", " + height + ")");
- }
- },
- clip: {
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".clip()");
- }
- },
- closePath: {
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".closePath()");
- }
- },
- createImageData: {
- enumerable: true,
- value: function (width, height) {
- if (width.height != undefined) {
- height = width.height;
- width = width.width;
- }
-
- return function (callback) {
- callback(null, {
- data: new Uint8ClampedArray(Array.apply(null, new Array(width * height * 4)).map(Number.prototype.valueOf, 0)),
- width: width,
- height: height
- });
- };
- }
- },
- createLinearGradient: {
- enumerable: true,
- value: function (x0, y0, x1, y1) {
- var uid = NCC.uid('linearGradient');
- rdp("var " + uid + " = " + this._uid + ".createLinearGradient(" + x0 + ", " + y0 + ", " + x1 + ", " + y1 + ")");
-
- var linearGradient = function (callback) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, linearGradient);
+ },
+ _ctx: {
+ enumerable: DEBUG,
+ writable: true,
+ value: null
+ },
+ // Properties || proxies with defaults
+ width_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: 300
+ },
+ height_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: 150
+ },
+ // Web API: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement
+ // Properties || getters/setters || https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Properties
+ width: {
+ enumerable: true,
+ get: function () {
+ return this.width_;
+ },
+ set: function (width) {
+ if (width === undefined)
+ return;
+ rdp(`${this._uid}.width = ${width}`);
+ return this.width_ = width;
+ }
+ },
+ height: {
+ enumerable: true,
+ get: function () {
+ return this.height_;
+ },
+ set: function (height) {
+ if (height === undefined)
+ return;
+ rdp(`${this._uid}.height = ${height}`);
+ return this.height_ = height;
+ }
+ },
+ // Methods || https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Methods
+ getContext: {
+ enumerable: true,
+ value: function (contextId) {
+ if (contextId == '2d') {
+ var uid = this._uid == 'canvas' ? 'context2d' : NCC.uid('context2d');
+ rdp(`var ${uid} = ${this._uid}.getContext('2d')`);
+ var context2d = (callback) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, context2d);
} : undefined);
- return linearGradient;
+ return context2d;
};
-
- GradientPDM["_uid"].value = uid;
- Object.defineProperties(linearGradient, GradientPDM);
- GradientPDM["_uid"].value = "";
-
+ context2dPDM._uid.value = uid;
+ context2dPDM['canvas'].value = this;
+ Object.defineProperties(context2d, context2dPDM);
+ context2dPDM._uid.value = '';
+ return context2d;
+ }
+ else
+ logger.error(`${contextId} is not implemented`);
+ }
+ },
+ toDataURL: {
+ enumerable: true,
+ value: function (type, args) {
+ rdp(`${this._uid}.toDataURL(${`'${type}'` || ''})`);
+ return (callback) => {
+ rdp((err, res) => {
+ if (err)
+ return callback(err, null);
+ callback(err, res.value);
+ });
+ };
+ }
+ }
+};
+var context2dPDM = {
+ // private properties
+ _uid: {
+ enumerable: DEBUG,
+ value: ''
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ }
+ else
+ logger.error('"_remote" can only be set to "null"');
+ }
+ },
+ // Attributes || proxies with defaults
+ fillStyle_: { writable: true, enumerable: DEBUG, value: '#000000' },
+ font_: { writable: true, enumerable: DEBUG, value: '10px sans-serif' },
+ globalAlpha_: { writable: true, enumerable: DEBUG, value: 1.0 },
+ globalCompositeOperation_: { writable: true, enumerable: DEBUG, value: 'source-over' },
+ lineCap_: { writable: true, enumerable: DEBUG, value: 'butt' },
+ lineDashOffset_: { writable: true, enumerable: DEBUG, value: 0 },
+ lineJoin_: { writable: true, enumerable: DEBUG, value: 'miter' },
+ lineWidth_: { writable: true, enumerable: DEBUG, value: 1.0 },
+ miterLimit_: { writable: true, enumerable: DEBUG, value: 10 },
+ shadowBlur_: { writable: true, enumerable: DEBUG, value: 0 },
+ shadowColor_: { writable: true, enumerable: DEBUG, value: 'rgba(0, 0, 0, 0)' },
+ shadowOffsetX_: { writable: true, enumerable: DEBUG, value: 0 },
+ shadowOffsetY_: { writable: true, enumerable: DEBUG, value: 0 },
+ strokeStyle_: { writable: true, enumerable: DEBUG, value: '#000000' },
+ textAlign_: { writable: true, enumerable: DEBUG, value: 'start' },
+ textBaseline_: { writable: true, enumerable: DEBUG, value: 'alphabetic' },
+ webkitBackingStorePixelRatio_: { writable: true, enumerable: DEBUG, value: 1 },
+ webkitImageSmoothingEnabled_: { writable: true, enumerable: DEBUG, value: true },
+ // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d
+ // Attributes || getters/setters || https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d#Attributes
+ canvas: {
+ enumerable: true, value: null // will be overridden on creation
+ },
+ fillStyle: {
+ enumerable: true, get: function () { return this.fillStyle_; },
+ set: function (fillStyle) {
+ rdp(`${this._uid}.fillStyle = ${fillStyle._uid || `'${fillStyle}'`}`);
+ return this.fillStyle_ = fillStyle;
+ }
+ },
+ font: {
+ enumerable: true, get: function () { return this.font_; },
+ set: function (font) {
+ rdp(`${this._uid}.font = '${font}'`);
+ return this.font_ = font;
+ }
+ },
+ globalAlpha: {
+ enumerable: true, get: function () { return this.globalAlpha_; },
+ set: function (globalAlpha) {
+ rdp(`${this._uid}.globalAlpha = ${globalAlpha}`);
+ return this.globalAlpha_ = globalAlpha;
+ }
+ },
+ globalCompositeOperation: {
+ enumerable: true, get: function () { return this.globalCompositeOperation_; },
+ set: function (globalCompositeOperation) {
+ rdp(`${this._uid}.globalCompositeOperation = '${globalCompositeOperation}'`);
+ return this.globalCompositeOperation_ = globalCompositeOperation;
+ }
+ },
+ lineCap: {
+ enumerable: true, get: function () { return this.lineCap_; },
+ set: function (lineCap) {
+ rdp(`${this._uid}.lineCap = '${lineCap}'`);
+ return this.lineCap_ = lineCap;
+ }
+ },
+ lineDashOffset: {
+ enumerable: true, get: function () { return this.lineDashOffset_; },
+ set: function (lineDashOffset) {
+ rdp(`${this._uid}.lineDashOffset = ${lineDashOffset}`);
+ return this.lineDashOffset_ = lineDashOffset;
+ }
+ },
+ lineJoin: {
+ enumerable: true, get: function () { return this.lineJoin_; },
+ set: function (lineJoin) {
+ rdp(`${this._uid}.lineJoin = '${lineJoin}'`);
+ return this.lineJoin_ = lineJoin;
+ }
+ },
+ lineWidth: {
+ enumerable: true, get: function () { return this.lineWidth_; },
+ set: function (lineWidth) {
+ rdp(`${this._uid}.lineWidth = ${lineWidth}`);
+ return this.lineWidth_ = lineWidth;
+ }
+ },
+ miterLimit: {
+ enumerable: true, get: function () { return this.miterLimit_; },
+ set: function (miterLimit) {
+ rdp(`${this._uid}.miterLimit = ${miterLimit}`);
+ return this.miterLimit_ = miterLimit;
+ }
+ },
+ shadowBlur: {
+ enumerable: true, get: function () { return this.shadowBlur_; },
+ set: function (shadowBlur) {
+ rdp(`${this._uid}.shadowBlur = ${shadowBlur}`);
+ return this.shadowBlur_ = shadowBlur;
+ }
+ },
+ shadowColor: {
+ enumerable: true, get: function () { return this.shadowColor; },
+ set: function (shadowColor) {
+ rdp(`${this._uid}.shadowColor = '${shadowColor}'`);
+ return this.shadowColor_ = shadowColor;
+ }
+ },
+ shadowOffsetX: {
+ enumerable: true, get: function () { return this.shadowOffsetX_; },
+ set: function (shadowOffsetX) {
+ rdp(`${this._uid}.shadowOffsetX = ${shadowOffsetX}`);
+ return this.shadowOffsetX_ = shadowOffsetX;
+ }
+ },
+ shadowOffsetY: {
+ enumerable: true, get: function () { return this.shadowOffsetY_; },
+ set: function (shadowOffsetY) {
+ rdp(`${this._uid}.shadowOffsetY = ${shadowOffsetY}`);
+ return this.shadowOffsetY_ = shadowOffsetY;
+ }
+ },
+ strokeStyle: {
+ enumerable: true, get: function () { return this.strokeStyle_; },
+ set: function (strokeStyle) {
+ rdp(`${this._uid}.strokeStyle = ${strokeStyle._uid || `'${strokeStyle}'`}`);
+ return this.strokeStyle_ = strokeStyle;
+ }
+ },
+ textAlign: {
+ enumerable: true, get: function () { return this.textAlign_; },
+ set: function (textAlign) {
+ rdp(`${this._uid}.textAlign = '${textAlign}'`);
+ return this.textAlign_ = textAlign;
+ }
+ },
+ textBaseline: {
+ enumerable: true, get: function () { return this.textBaseline_; },
+ set: function (textBaseline) {
+ rdp(`${this._uid}.textBaseline = '${textBaseline}'`);
+ return this.textBaseline_ = textBaseline;
+ }
+ },
+ webkitBackingStorePixelRatio: {
+ enumerable: true, get: function () { return this.webkitBackingStorePixelRatio_; },
+ set: function (webkitBackingStorePixelRatio) {
+ rdp(`${this._uid}.webkitBackingStorePixelRatio = ${webkitBackingStorePixelRatio}`);
+ return this.webkitBackingStorePixelRatio_ = webkitBackingStorePixelRatio;
+ }
+ },
+ webkitImageSmoothingEnabled: {
+ enumerable: true, get: function () { return this.webkitImageSmoothingEnabled_; },
+ set: function (webkitImageSmoothingEnabled) {
+ rdp(`${this._uid}.webkitImageSmoothingEnabled = ${webkitImageSmoothingEnabled}`);
+ return this.webkitImageSmoothingEnabled_ = webkitImageSmoothingEnabled;
+ }
+ },
+ // Methods || https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d#Methods
+ arc: {
+ enumerable: true,
+ value: function (x, y, radius, startAngle, endAngle, anticlockwise) {
+ return rdp(`${this._uid}.arc(${Array.prototype.slice.call(arguments, 0).join(',')})`);
+ }
+ },
+ arcTo: {
+ enumerable: true,
+ value: function (x1, y1, x2, y2, radius) {
+ return rdp(`${this._uid}.arcTo(${x1},${y1},${x2},${y2},${radius})`);
+ }
+ },
+ beginPath: {
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.beginPath()`);
+ }
+ },
+ bezierCurveTo: {
+ enumerable: true,
+ value: function (cp1x, cp1y, cp2x, cp2y, x, y) {
+ return rdp(`${this._uid}.bezierCurveTo(${cp1x},${cp1y},${cp2x},${cp2y},${x},${y})`);
+ }
+ },
+ clearRect: {
+ enumerable: true,
+ value: function (x, y, width, height) {
+ return rdp(`${this._uid}.clearRect(${x},${y},${width},${height})`);
+ }
+ },
+ clip: {
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.clip()`);
+ }
+ },
+ closePath: {
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.closePath()`);
+ }
+ },
+ createImageData: {
+ enumerable: true,
+ value: function (width, height) {
+ if (width.height != undefined) {
+ height = width.height;
+ width = width.width;
+ }
+ return (callback) => {
+ callback(null, {
+ data: new Uint8ClampedArray(Array.apply(null, new Array(width * height * 4)).map(Number.prototype.valueOf, 0)),
+ width: width,
+ height: height
+ });
+ };
+ }
+ },
+ createLinearGradient: {
+ enumerable: true,
+ value: function (x0, y0, x1, y1) {
+ var uid = NCC.uid('linearGradient');
+ rdp(`var ${uid} = ${this._uid}.createLinearGradient(${x0},${y0},${x1},${y1})`);
+ var linearGradient = (callback) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, linearGradient);
+ } : undefined);
return linearGradient;
- }
- },
- createPattern: {
- enumerable: true,
- value: function (image, repetition) {
- var uid = NCC.uid('pattern');
- rdp("var " + uid + " = " + this._uid + ".createPattern(" + image._uid + ", '" + repetition + "')");
-
- var pattern = function (callback) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, pattern);
- } : undefined);
- return pattern;
- };
-
- PatternPDM["_uid"].value = uid;
- Object.defineProperties(pattern, PatternPDM);
- PatternPDM["_uid"].value = "";
-
+ };
+ GradientPDM._uid.value = uid;
+ Object.defineProperties(linearGradient, GradientPDM);
+ GradientPDM._uid.value = '';
+ return linearGradient;
+ }
+ },
+ createPattern: {
+ enumerable: true,
+ value: function (image, repetition) {
+ var uid = NCC.uid('pattern');
+ rdp(`var ${uid} = ${this._uid}.createPattern(${image._uid},'${repetition}')`);
+ var pattern = (callback) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, pattern);
+ } : undefined);
return pattern;
- }
- },
- createRadialGradient: {
- enumerable: true,
- value: function (x0, y0, r0, x1, y1, r1) {
- var uid = NCC.uid('pattern');
- rdp("var " + uid + " = " + this._uid + ".createRadialGradient(" + x0 + ", " + y0 + ", " + r0 + ", " + x1 + ", " + y1 + ", " + r1 + ")");
-
- var radialGradient = function (callback) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, radialGradient);
- } : undefined);
- return radialGradient;
- };
-
- GradientPDM["_uid"].value = NCC.uid('radialGradient');
- Object.defineProperties(radialGradient, GradientPDM);
- GradientPDM["_uid"].value = "";
-
+ };
+ PatternPDM._uid.value = uid;
+ Object.defineProperties(pattern, PatternPDM);
+ PatternPDM._uid.value = '';
+ return pattern;
+ }
+ },
+ createRadialGradient: {
+ enumerable: true,
+ value: function (x0, y0, r0, x1, y1, r1) {
+ var uid = NCC.uid('pattern');
+ rdp(`var ${uid} = ${this._uid}.createRadialGradient(${x0},${y0},${r0},${x1},${y1},${r1})`);
+ var radialGradient = (callback) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, radialGradient);
+ } : undefined);
return radialGradient;
- }
- },
- drawImage: {
- enumerable: true,
- value: function (image, a1, a2, a3, a4, a5, a6, a7, a8) {
- return rdp(this._uid + ".drawImage(" + image._uid + ", " + (Array.prototype.slice.call(arguments, 1).join(',')) + ")");
- }
- },
- // no use
- //drawCustomFocusRing: { //RETURN/ boolean //IN/ Element element
- // enumerable:true,
- // value: function (element) {
- // rdp(this._uid + ".drawCustomFocusRing(" + element + ")");
- // return this;
- // }
- //},
- // no use
- //drawSystemFocusRing: { //RETURN/ void //IN/ Element element
- // enumerable:true,
- // value: function (element) {
- // rdp(this._uid + ".drawSystemFocusRinelementg()");
- // return this;
- // }
- //},
- fill: {
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".fill()");
- }
- },
- fillRect: {
- enumerable: true,
- value: function (x, y, width, height) {
- return rdp(this._uid + ".fillRect(" + x + ", " + y + ", " + width + ", " + height + ")");
- }
- },
- fillText: {
- enumerable: true,
- value: function (text, x, y, maxWidth) {
- return rdp(this._uid + ".fillText('" + text + "', " + (Array.prototype.slice.call(arguments, 1).join(',')) + ")");
- }
- },
- getImageData: {
- enumerable: true,
- value: function (x, y, width, height) {
- rdp("Array.prototype.slice.call(" + this._uid + ".getImageData(" + x + "," + y + "," + width + "," + height + ").data).join(',')");
- return function (callback) {
- rdp(function (err, res) {
- if (err)
- return callback(err, null);
-
- var imageData = {
- data: new Uint8ClampedArray(res.value.split(',')),
- width: width,
- height: height
- };
-
- callback(null, imageData);
- });
- };
- }
- },
- getLineDash: {
- enumerable: true,
- value: function () {
- rdp(this._uid + ".getLineDash().join(',')");
- return function (callback) {
- rdp(function (err, res) {
- if (err)
- return callback(err);
-
- res.value = res.value.split(',');
- for (var i = 0, l = res.value.length; i < l; i++)
- res.value[i] = +res.value[i];
-
- callback(err, res.value);
- });
- };
- }
- },
- isPointInPath: {
- enumerable: true,
- value: function (x, y) {
- rdp(this._uid + ".isPointInPath(" + x + ", " + y + ")");
- return function (callback) {
- rdp(function (err, res) {
- callback(err, res.value);
- });
- };
- }
- },
- isPointInStroke: {
- enumerable: true,
- value: function (x, y) {
- rdp(this._uid + ".isPointInStroke(" + x + ", " + y + ")");
- return function (callback) {
- rdp(function (err, res) {
- callback(err, res.value);
- });
- };
- }
- },
- lineTo: {
- enumerable: true,
- value: function (x, y) {
- return rdp(this._uid + ".lineTo(" + x + ", " + y + ")");
- }
- },
- measureText: {
- enumerable: true,
- value: function (text) {
- rdp(this._uid + ".measureText('" + text + "').width");
- return function (callback) {
- rdp(function (err, res) {
- if (err)
- return callback(err);
-
- callback(null, { width: res.value });
- });
- };
- }
- },
- moveTo: {
- enumerable: true,
- value: function (x, y) {
- return rdp(this._uid + ".moveTo(" + x + ", " + y + ")");
- }
- },
- putImageData: {
- enumerable: true,
- value: function (imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) {
- return rdp("var data = [" + Array.prototype.slice.call(imagedata.data).join(',') + "]; var iD = " + this._uid + ".createImageData(" + imagedata.width + ", " + imagedata.height + "); for (var i = 0, l = iD.data.length; i < l; i++) iD.data[i] = +data[i]; " + this._uid + ".putImageData(iD, " + (Array.prototype.slice.call(arguments, 1).join(',')) + ")");
- }
- },
- quadraticCurveTo: {
- enumerable: true,
- value: function (cpx, cpy, x, y) {
- return rdp(this._uid + ".quadraticCurveTo(" + cpx + ", " + cpy + ", " + x + ", " + y + ")");
- }
- },
- rect: {
- enumerable: true,
- value: function (x, y, width, height) {
- return rdp(this._uid + ".rect(" + x + ", " + y + ", " + width + ", " + height + ")");
- }
- },
- restore: {
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".restore()");
- }
- },
- rotate: {
- enumerable: true,
- value: function (angle) {
- return rdp(this._uid + ".rotate(" + angle + ")");
- }
- },
- save: {
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".save()");
- }
- },
- scale: {
- enumerable: true,
- value: function (x, y) {
- return rdp(this._uid + ".scale(" + x + ", " + y + ")");
- }
- },
- // no use
- //scrollPathIntoView: { //RETURN/ void //IN/
- // enumerable: true,
- // value: function () {
- // rdp(this._uid + ".scrollPathIntoView()");
- // return this;
- // }
- //},
- setLineDash: {
- enumerable: true,
- value: function (segments) {
- return rdp(this._uid + ".setLineDash([" + segments.join(',') + "])");
- }
- },
- setTransform: {
- enumerable: true,
- value: function (m11, m12, m21, m22, dx, dy) {
- return rdp(this._uid + ".setTransform(" + m11 + ", " + m12 + ", " + m21 + ", " + m22 + ", " + dx + ", " + dy + ")");
- }
- },
- stroke: {
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".stroke()");
- }
- },
- strokeRect: {
- enumerable: true,
- value: function (x, y, w, h) {
- return rdp(this._uid + ".strokeRect(" + x + ", " + y + ", " + w + ", " + h + ")");
- }
- },
- strokeText: {
- enumerable: true,
- value: function (text, x, y, maxWidth) {
- rdp(this._uid + ".strokeText('" + text + "', " + (Array.prototype.slice.call(arguments, 1).join(',')) + ")");
- return this;
- }
- },
- transform: {
- enumerable: true,
- value: function (m11, m12, m21, m22, dx, dy) {
- return rdp(this._uid + ".transform(" + m11 + ", " + m12 + ", " + m21 + ", " + m22 + ", " + dx + ", " + dy + ")");
- }
- },
- translate: {
- enumerable: true,
- value: function (x, y) {
- return rdp(this._uid + ".translate(" + x + ", " + y + ")");
- }
+ };
+ GradientPDM._uid.value = NCC.uid('radialGradient');
+ Object.defineProperties(radialGradient, GradientPDM);
+ GradientPDM._uid.value = '';
+ return radialGradient;
}
- };
-})();
-
-
-var GradientPDM = (function () {
- return {
- // private properties
- _uid: {
- enumerable: DEBUG,
- value: ""
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- } else
- throw new Error("'_remote' can only be set to 'null'");
- }
- },
- // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient
- // Methods
- addColorStop: {
- enumerable: true,
- value: function (offset, color) {
- return rdp(this._uid + ".addColorStop(" + offset + ", '" + color + "')");
- }
+ },
+ drawImage: {
+ enumerable: true,
+ value: function (image, a1, a2, a3, a4, a5, a6, a7, a8) {
+ return rdp(`${this._uid}.drawImage(${image._uid}, ${Array.prototype.slice.call(arguments, 1).join(',')})`);
}
- };
-})();
-
-
-var PatternPDM = (function () {
- return {
- // private properties
- _uid: {
- enumerable: DEBUG,
- value: ""
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- } else
- throw new Error("'_remote' can only be set to 'null'");
- }
+ },
+ // no use
+ //drawCustomFocusRing: { //RETURN/ boolean //IN/ Element element
+ // enumerable:true,
+ // value: function (element) {
+ // rdp(`${this._uid}.drawCustomFocusRing(" + element + ")`);
+ // return this;
+ // }
+ //},
+ // no use
+ //drawSystemFocusRing: { //RETURN/ void //IN/ Element element
+ // enumerable:true,
+ // value: function (element) {
+ // rdp(`${this._uid}.drawSystemFocusRinelementg()`);
+ // return this;
+ // }
+ //},
+ fill: {
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.fill()`);
}
- };
-})();
-
-
+ },
+ fillRect: {
+ enumerable: true,
+ value: function (x, y, width, height) {
+ return rdp(`${this._uid}.fillRect(${x},${y},${width},${height})`);
+ }
+ },
+ fillText: {
+ enumerable: true,
+ value: function (text, x, y, maxWidth) {
+ return rdp(`${this._uid}.fillText('${text}',${Array.prototype.slice.call(arguments, 1).join(',')})`);
+ }
+ },
+ getImageData: {
+ enumerable: true,
+ value: function (x, y, width, height) {
+ rdp(`Array.prototype.slice.call(${this._uid}.getImageData(${x},${y},${width},${height}).data).join(',')`);
+ return (callback) => {
+ rdp((err, res) => {
+ if (err)
+ return callback(err, null);
+ var imageData = {
+ data: new Uint8ClampedArray(res.value.split(',')),
+ width: width,
+ height: height
+ };
+ callback(null, imageData);
+ });
+ };
+ }
+ },
+ getLineDash: {
+ enumerable: true,
+ value: function () {
+ rdp(`${this._uid}.getLineDash().join(',')`);
+ return (callback) => {
+ rdp((err, res) => {
+ if (err)
+ return callback(err);
+ res.value = res.value.split(',');
+ for (var i = 0, l = res.value.length; i < l; i++)
+ res.value[i] = +res.value[i];
+ callback(err, res.value);
+ });
+ };
+ }
+ },
+ isPointInPath: {
+ enumerable: true,
+ value: function (x, y) {
+ rdp(`${this._uid}.isPointInPath(${x},${y})`);
+ return (callback) => {
+ rdp((err, res) => {
+ callback(err, res.value);
+ });
+ };
+ }
+ },
+ isPointInStroke: {
+ enumerable: true,
+ value: function (x, y) {
+ rdp(`${this._uid}.isPointInStroke(${x},${y})`);
+ return (callback) => {
+ rdp((err, res) => {
+ callback(err, res.value);
+ });
+ };
+ }
+ },
+ lineTo: {
+ enumerable: true,
+ value: function (x, y) {
+ return rdp(`${this._uid}.lineTo(${x},${y})`);
+ }
+ },
+ measureText: {
+ enumerable: true,
+ value: function (text) {
+ rdp(`${this._uid}.measureText('${text}').width`);
+ return (callback) => {
+ rdp((err, res) => {
+ if (err)
+ return callback(err);
+ callback(null, { width: res.value });
+ });
+ };
+ }
+ },
+ moveTo: {
+ enumerable: true,
+ value: function (x, y) {
+ return rdp(`${this._uid}.moveTo(${x},${y})`);
+ }
+ },
+ putImageData: {
+ enumerable: true,
+ value: function (imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) {
+ return rdp(`var data = [${Array.prototype.slice.call(imagedata.data).join(',')}]; var iD = ${this._uid}.createImageData(${imagedata.width}, ${imagedata.height}); for (var i = 0, l = iD.data.length; i < l; i++) iD.data[i] = +data[i]; ${this._uid}.putImageData(iD, ${Array.prototype.slice.call(arguments, 1).join(',')})`);
+ }
+ },
+ quadraticCurveTo: {
+ enumerable: true,
+ value: function (cpx, cpy, x, y) {
+ return rdp(`${this._uid}.quadraticCurveTo(${cpx},${cpy},${x},${y})`);
+ }
+ },
+ rect: {
+ enumerable: true,
+ value: function (x, y, width, height) {
+ return rdp(`${this._uid}.rect(${x},${y},${width},${height})`);
+ }
+ },
+ restore: {
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.restore()`);
+ }
+ },
+ rotate: {
+ enumerable: true,
+ value: function (angle) {
+ return rdp(`${this._uid}.rotate(${angle})`);
+ }
+ },
+ save: {
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.save()`);
+ }
+ },
+ scale: {
+ enumerable: true,
+ value: function (x, y) {
+ return rdp(`${this._uid}.scale(${x},${y})`);
+ }
+ },
+ // no use
+ //scrollPathIntoView: { //RETURN/ void //IN/
+ // enumerable: true,
+ // value: function () {
+ // rdp(`${this._uid}.scrollPathIntoView()`);
+ // return this;
+ // }
+ //},
+ setLineDash: {
+ enumerable: true,
+ value: function (segments) {
+ return rdp(`${this._uid}.setLineDash([${segments.join(',')}])`);
+ }
+ },
+ setTransform: {
+ enumerable: true,
+ value: function (m11, m12, m21, m22, dx, dy) {
+ return rdp(`${this._uid}.setTransform(${m11},${m12},${m21},${m22},${dx},${dy})`);
+ }
+ },
+ stroke: {
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.stroke()`);
+ }
+ },
+ strokeRect: {
+ enumerable: true,
+ value: function (x, y, w, h) {
+ return rdp(`${this._uid}.strokeRect(${x},${y},${w},${h})`);
+ }
+ },
+ strokeText: {
+ enumerable: true,
+ value: function (text, x, y, maxWidth) {
+ rdp(`${this._uid}.strokeText('${text}',${(Array.prototype.slice.call(arguments, 1).join(','))})`);
+ return this;
+ }
+ },
+ transform: {
+ enumerable: true,
+ value: function (m11, m12, m21, m22, dx, dy) {
+ return rdp(`${this._uid}.transform(${m11},${m12},${m21},${m22},${dx},${dy})`);
+ }
+ },
+ translate: {
+ enumerable: true,
+ value: function (x, y) {
+ return rdp(`${this._uid}.translate(${x},${y})`);
+ }
+ }
+};
+var GradientPDM = {
+ // private properties
+ _uid: {
+ enumerable: DEBUG,
+ value: ''
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ }
+ else
+ logger.error('"_remote" can only be set to "null"');
+ }
+ },
+ // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient
+ // Methods
+ addColorStop: {
+ enumerable: true,
+ value: function (offset, color) {
+ return rdp(`${this._uid}.addColorStop(${offset},'${color}')`);
+ }
+ }
+};
+var PatternPDM = {
+ // private properties
+ _uid: {
+ enumerable: DEBUG,
+ value: ''
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ }
+ else
+ logger.error('"_remote" can only be set to "null"');
+ }
+ },
+};
var mimeMap = {
png: 'image/png',
webp: 'image/webp',
@@ -977,170 +1196,158 @@ var mimeMap = {
svg: 'image/svg+xml',
gif: 'image/gif'
};
-
var regExp_http = new RegExp('^(http:\\/\\/.+)', 'i');
var regExp_data = new RegExp('^(data:image\\/\\w+;base64,.+)');
var regExp_type = new RegExp('^data:image\\/(\\w+);base64,');
-
-var ImagePDM = (function () {
- return {
- // private properties
- _uid: {
- enumerable: DEBUG,
- value: ""
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- } else
- throw new Error("'_remote' can only be set to 'null'");
- }
- },
- // Properties
- src_: {
- enumerable: DEBUG,
- writable: true,
- value: ""
- },
- width_: {
- enumerable: DEBUG,
- writable: true,
- value: undefined
- },
- height_: {
- enumerable: DEBUG,
- writable: true,
- value: undefined
- },
- _base64_: {
- enumerable: DEBUG,
- writable: true,
- value: null
- },
- _base64: {
- enumerable: DEBUG,
- get: function () {
- return this._base64_;
- },
- set: function (base64) {
- var img = this;
- rdp(this._uid + ".src = " + "'" + base64 + "';" + this._uid + ".width+'_'+" + this._uid + ".height");
- rdp(function (err, res) {
- if (err && img.onerror)
- return img.onerror(err);
-
+var ImagePDM = {
+ // private properties
+ _uid: {
+ enumerable: DEBUG,
+ value: ''
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ }
+ else
+ logger.error('"_remote" can only be set to "null"');
+ }
+ },
+ // Properties
+ src_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: ''
+ },
+ width_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: undefined
+ },
+ height_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: undefined
+ },
+ _base64_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: null
+ },
+ _base64: {
+ enumerable: DEBUG,
+ get: function () {
+ return this._base64_;
+ },
+ set: function (base64) {
+ rdp(`${this._uid}.src = '${base64}'`);
+ rdp(() => {
+ rdp(`${this._uid}.width + '_' + ${this._uid}.height`);
+ rdp((err, res) => {
+ if (err && this.onerror)
+ return this.onerror(err);
var size = res.value.split('_');
- img.width_ = +size[0];
- img.height_ = +size[1];
-
- if (img.onload)
- return img.onload(img);
+ this.width_ = +size[0];
+ this.height_ = +size[1];
+ if (this.onload)
+ return this.onload(this);
});
-
- this._base64_ = base64;
- return this._base64_;
- }
- },
- // Methods
- _toFile: {
- enumerable: DEBUG,
- value: function (filename, callback) {
- var head = regExp_type.exec(this._base64_), type = filename.split('.').pop();
-
- if (!head || !head[1] || (head[1] != ((type == "jpg") ? "jpeg" : type)))
- if (callback)
- return callback("type mismatch " + (head ? head[1] : "'unknown'") + " !> " + type);
- else
- throw new Error("type mismatch " + (head ? head[1] : "'unknown'") + " !> " + type);
-
- NCC.log('[ncc] writing image to: ' + filename, 2);
- fs.writeFile(filename, new Buffer(this._base64_.replace(/^data:image\/\w+;base64,/, ""), 'base64'), {}, callback);
- }
- },
- // Web API
- // Properties
- src: {
- enumerable: true,
- get: function () {
- return this.src_;
- },
- set: function (src) {
- var img = this;
- this._src = src;
- if (!src || src === "")
- return;
-
- if (regExp_data.test(src))
- img._base64 = src;
- else if (regExp_http.test(src)) {
- NCC.log('[ncc] loading image from URL: ' + src, 2);
- http.get(src, function (res) {
- var data = '';
- res.setEncoding('base64');
-
- if (res.statusCode != 200) {
- if (img.onerror)
- return img.onerror("loading image failed with status " + res.statusCode);
- else
- throw new Error("loading image failed with status " + res.statusCode);
- }
-
- res.on('data', function (chunk) {
- data += chunk;
- });
-
- res.on('end', function () {
- img._base64 = "data:" + (res.headers["content-type"] || mimeMap[src.split('.').pop()]) + ";base64," + data;
- NCC.log('[ncc] loading image from URL completed', 2);
- });
- }).on('error', this.onerror || function (err) {
+ });
+ this._base64_ = base64;
+ return this._base64_;
+ }
+ },
+ // Methods
+ _toFile: {
+ enumerable: DEBUG,
+ value: function (filename, callback) {
+ var head = regExp_type.exec(this._base64_), type = filename.split('.').pop();
+ if (!head || !head[1] || (head[1] != ((type == "jpg") ? "jpeg" : type)))
+ if (callback)
+ return callback(`type mismatch ${head ? head[1] : "'unknown'"} !> ${type}`);
+ else
+ throw new Error(`type mismatch ${head ? head[1] : "'unknown'"} !> ${type}`);
+ logger.info(`[ncc] writing image to: ${filename}`);
+ fs.writeFile(filename, new Buffer(this._base64_.replace(/^data:image\/\w+;base64,/, ''), 'base64'), {}, callback);
+ }
+ },
+ // Web API
+ // Properties
+ src: {
+ enumerable: true,
+ get: function () {
+ return this.src_;
+ },
+ set: function (src) {
+ var img = this;
+ this._src = src;
+ if (!src || src === '')
+ return;
+ if (regExp_data.test(src))
+ img._base64 = src;
+ else if (regExp_http.test(src)) {
+ logger.info(`[ncc] loading image from URL: ${src}`);
+ http.get(src, function (res) {
+ var data = '';
+ res.setEncoding('base64');
+ if (res.statusCode != 200) {
if (img.onerror)
- return img.onerror(err);
+ return img.onerror(`loading image failed with status ${res.statusCode}`);
else
- throw err;
- });
- } else {
- NCC.log('[ncc] loading image from FS: ' + src, 2);
- fs.readFile(src, 'base64', function (err, data) {
- if (err) {
- if (img.onerror)
- img.onerror(err);
- else
- throw err;
- }
- img._base64 = "data:" + mimeMap[src.split('.').pop()] + ";base64," + data;
- NCC.log('[ncc] loading image from FS completed', 2);
+ logger.error(`loading image failed with status ${res.statusCode}`);
+ }
+ res.on('data', function (chunk) { data += chunk; });
+ res.on('end', function () {
+ img._base64 = `data:${(res.headers["content-type"] || mimeMap[src.split('.').pop()])};base64,${data}`;
+ logger.info('[ncc] loading image from URL completed');
});
- }
- return this.src_;
- }
- },
- onload: {
- writable: true,
- enumerable: true,
- value: undefined
- },
- onerror: {
- writable: true,
- enumerable: true,
- value: undefined
- },
- width: {
- enumerable: true,
- get: function () {
- return this.width_;
+ }).on('error', this.onerror || function (err) {
+ if (img.onerror)
+ return img.onerror(err);
+ else
+ logger.error(`loading image failed with err ${err}`);
+ });
}
- },
- height: {
- enumerable: true,
- get: function () {
- return this.height_;
+ else {
+ logger.info(`[ncc] loading image from FS: ${src}`);
+ fs.readFile(src, 'base64', function (err, data) {
+ if (err) {
+ if (img.onerror)
+ img.onerror(err);
+ else
+ logger.error(`loading image failed with err ${err}`);
+ }
+ img._base64 = `data:${mimeMap[src.split('.').pop()]};base64,${data}`;
+ logger.info('[ncc] loading image from FS completed');
+ });
}
+ return this.src_;
}
- };
-})();
-
+ },
+ onload: {
+ writable: true,
+ enumerable: true,
+ value: undefined
+ },
+ onerror: {
+ writable: true,
+ enumerable: true,
+ value: undefined
+ },
+ width: {
+ enumerable: true,
+ get: function () {
+ return this.width_;
+ }
+ },
+ height: {
+ enumerable: true,
+ get: function () {
+ return this.height_;
+ }
+ }
+};
module.exports = NCC;
diff --git a/lib/ncc.ts b/lib/ncc.ts
index b63c26c..897df67 100644
--- a/lib/ncc.ts
+++ b/lib/ncc.ts
@@ -1,17 +1,16 @@
-declare var require: (id: string) => any;
-declare var module: any;
-declare var Buffer: any;
-declare var Uint8ClampedArray:any;
-declare var __dirname: string;
+///
-var DEBUG = false;
-
-var spawn = require('child_process').spawn
- , http = require('http')
+var http = require('http')
, fs = require('fs')
, ws = require('ws')
, os = require('os');
+var DEBUG = false;
+
+var logger;
+
+
+
interface NCC {
(options?, callback?): Canvas;
options: any;
@@ -21,15 +20,8 @@ interface NCC {
log(msg: string, level?: number): void;
}
-var NCC = ((): NCC => {
-
- var NCC: any = function (options_, callback_): Object {
-
- if (callback_ !== false)
- console.log("\n\033[46m\t" + "[ncc] v0.2.0" + " \033[49m\n");
-
- var canvas = NCC.createCanvas(undefined, undefined, true);
-
+var NCC = Object.defineProperties(
+ (options_, callback_) => {
if (typeof (options_) == 'function') {
callback_ = options_;
options_ = null;
@@ -37,147 +29,121 @@ var NCC = ((): NCC => {
var callback = callback_;
- if (options_) for (var key in NCC.options)
- if (options_[key] !== undefined) NCC.options[key] = options_[key];
-
+ if (options_)
+ for (var key in NCC.options)
+ if (options_[key] !== undefined)
+ NCC.options[key] = options_[key];
- if (NCC.options.spawn && NCC.chromePid === undefined) {
- NCC.log("[ncc | CP] start", 2);
- var command = NCC.options.spawn.command,
- args = NCC.options.spawn.args,
- options = NCC.options.spawn.options;
-
- var regExp = new RegExp('{(.*?)}'), re;
+ logger = require('tracer').colorConsole({
+ format: "[ncc] {{message}}",
+ level: NCC.options.logLevel
+ });
- for (var i = 0, l = args.length; i < l; i++) {
- re = regExp.exec(args[i]);
- if (re) args[i] = args[i].replace(re[0], NCC.options[re[1].toLowerCase()]);
- }
+ var canvas = NCC.createCanvas(undefined, undefined, true);
- NCC.log("[ncc | CP] spawn: " + command + " " + NCC.options.spawn.args.join(" "), 2);
+ var attempts = 0;
+ function connect() {
+ var url = `http://localhost:${NCC.options.port}/json`;
- var chrome = spawn(command, args, options);
+ http.get(url, res => {
+ var rdJson = '';
- NCC.chromePid = chrome.pid;
+ res.on('data', chunk => rdJson += chunk);
- chrome.on('close', function (code) {
- NCC.log('[ncc | CP] exited with code: ' + code, (code !== 0) ? 1 : 2);
- NCC.chromePid = null;
- });
+ res.on('end', () => {
+ var ncc_ = JSON.parse(rdJson).find(i => i.title === "ncc" || i.url === `${__dirname}/index.html`);
+ if (!ncc_) {
+ if (attempts < NCC.options.retry) {
+ attempts++;
+ logger.info(`connecting [retry ${attempts}/${NCC.options.retry}]`);
+ setTimeout(connect, NCC.options.retryDelay);
+ } else logger.error('connection failed');
+ return;
+ }
- chrome.stdout.on('data', function (data) {
- NCC.log('[ncc | CP] stdout: ' + data, 2);
- });
+ Object.defineProperties(rdp, { ws: { value: new ws(ncc_.webSocketDebuggerUrl) } });
- chrome.stderr.on('data', function (data) {
- NCC.log('[ncc | CP] stderr: ' + data, 1);
- });
+ rdp.ws.on('open', () => {
+ logger.info("connected");
- chrome.on('error', function (err) {
- NCC.chromePid = null;
- NCC.log("[ncc | CP] error: " + err, 1);
- });
+ rdp((err, res) => {
+ if (err)
+ logger.error(`[ncc] error: ${err.message}`);
+ if (callback)
+ err ? callback(err, null) : callback(null, canvas, rdp);
+ });
+ });
+ rdp.ws.on('close', () => logger.info("session closed"));
+ })
+ })
}
- var url = "http://localhost:" + NCC.options.port + "/json";
- http.get(url, function (res) {
- NCC.log("[ncc | RDP] request started", 2);
-
- var rdJson = '';
-
- res.on('data', function (chunk) {
- rdJson += chunk;
+ var launcher = new ChromeLauncher({
+ port: NCC.options.port,
+ autoSelectChrome: true,
+ startingUrl: NCC.options.headless ? `${__dirname}/index.html` : '',
+ chromeFlags: NCC.options.headless ?
+ ['--window-size=0,0', '--disable-gpu', '--headless'] :
+ [`--app=${__dirname}/index.html`]
+ })
+
+ const exitHandler = err => launcher.kill().then(() => process.exit(-1));
+
+ process.on('SIGINT', exitHandler);
+ process.on('unhandledRejection', exitHandler);
+ process.on('rejectionHandled', exitHandler);
+ process.on('uncaughtException', exitHandler);
+
+ launcher.run()
+ .then((a) => {
+ logger.info("chrome started");
+ connect()
+ })
+ .catch(err => {
+ return launcher.kill().then(() => {
+ logger.error("failed starting chrome");
+ throw err;
+ }, logger.error);
});
- res.on('end', function () {
- NCC.log("[ncc | RDP] request ended", 2);
-
- var list = JSON.parse(rdJson);
-
- for (var i = 0, l = list.length; i < l; i++) {
-
- if (list[i].title == "ncc" && list[i].webSocketDebuggerUrl) {
-
- Object.defineProperties(rdp, {
- ws: {
- value: new ws(list[i].webSocketDebuggerUrl)
- }
- });
-
- rdp.ws.on('open', function () {
- NCC.log("[ncc | RDP] session established", 2);
-
- rdp(function (err, res) {
- if (err)
- NCC.log("[ncc] error: " + err.message, 1);
- if (callback)
- err ? callback(err, null) : callback(null, canvas, rdp);
- });
- });
-
- rdp.ws.on('close', function () {
- NCC.log("[ncc | RDP] session closed", 1);
- });
- return;
-
- } else {
- NCC.log("[ncc | RDP] remote not found" + ((NCC.options.retry) ? " - retry " + NCC.options.retry : ""), 1);
- if (NCC.options.retry--)
- setTimeout(NCC, NCC.options.retryDelay, callback, false);
- else if (callback) callback("remote not found");
- }
- }
- });
- }).on('error', function (err) {
- NCC.log("[ncc | RDP] request denied" + ((NCC.options.retry) ? " - retry " + NCC.options.retry : ""), 1);
- if (NCC.options.retry--)
- setTimeout(NCC, NCC.options.retryDelay, callback, false);
- else if (callback) callback(err.message, null);
- });
return canvas;
- }
- Object.defineProperties(NCC, {
+ }, {
options: {
enumerable: true,
writable: true,
value: {
- logLevel: 2,
+ logLevel: 'info',
port: 9222,
- retry: 3,
- retryDelay: 1000,
- spawn: {
- command: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
- args: ['--app=' + __dirname + '\\index.html',
- '--remote-debugging-port={PORT}',
- '--user-data-dir=' + os.tmpdir() + '\\nccanvas'
- ],
- options: {}
- }
+ retry: 9,
+ retryDelay: 500,
+ headless: false
}
},
createCanvas: {
enumerable: true,
value: function (width?: number, height?: number, main?: boolean) {
+
if (!main) {
var uid = NCC.uid('canvas')
- rdp("var " + uid + " = document.createElement('canvas')");
+ rdp(`var ${uid} = document.createElement('canvas')`);
}
- var canvas: any = function (callback?) {
- rdp(callback ? function (err, res) {
+ var canvas: any = (callback?) => {
+
+ rdp(callback ? (err, res) => {
err ? callback(err, null) : callback(null, canvas);
} : undefined);
return canvas;
}
- CanvasPDM["_uid"].value = main ? 'canvas' : uid;
+ CanvasPDM._uid.value = main ? 'canvas' : uid;
Object.defineProperties(canvas, CanvasPDM);
- CanvasPDM["_uid"].value = "";
+ CanvasPDM._uid.value = '';
canvas.width = width;
canvas.height = height;
@@ -189,17 +155,17 @@ var NCC = ((): NCC => {
enumerable: true,
value: function (src?: string, onload?: Function, onerror?: Function) {
var uid = NCC.uid('image')
- rdp("var " + uid + " = new Image()");
- var image: any = function (callback?) {
- rdp(callback ? function (err, res) {
+ rdp(`var ${uid} = new Image()`);
+ var image: any = (callback?) => {
+ rdp(callback ? (err, res) => {
err ? callback(err, null) : callback(null, image);
} : undefined);
return image;
}
- ImagePDM["_uid"].value = uid;
+ ImagePDM._uid.value = uid;
Object.defineProperties(image, ImagePDM);
- ImagePDM["_uid"].value = "";
+ ImagePDM._uid.value = '';
image.src = src;
image.onload = onload;
@@ -211,39 +177,28 @@ var NCC = ((): NCC => {
},
uid: {
enumerable: false,
- value: function (type) {
- return type + "_" + Math.random().toString(36).slice(2);
- }
- },
- log: {
- enumerable: false,
- value: function (msg, level) {
- if (!level || (level <= this.options.logLevel)) console.log(msg);
- }
+ value: type => `${type}_${Math.random().toString(36).slice(2)}`
}
})
- return NCC;
-})();
+
interface RDP {
(_?: any): RDP;
cmd: string;
- req: any;
queue: any[];
ws: any;
- //addCmd(cmd: string): RDP;
}
// RDP | Remote Debugging Protocol (the bridge to chrome)
-var rdp = ((): RDP => {
- var rdp: any = function (_): RDP {
+var rdp = Object.defineProperties(
+ (_): RDP => {
if (typeof _ == 'string') {
if (NCC.options.logLevel >= 3)
- console.log("+ \033[33m" + _ + "\033[39m");
- rdp.cmd += _ + ";";
+ console.log(_);
+ rdp.cmd += _ + ';';
return rdp;
}
@@ -252,22 +207,20 @@ var rdp = ((): RDP => {
cmd: rdp.cmd,
callback: _
});
- rdp.cmd = "";
+ rdp.cmd = '';
}
if (!rdp.queue[0] || rdp.req == rdp.queue[0] || !rdp.ws) return rdp;
rdp.req = rdp.queue[0];
- if (NCC.options.logLevel >= 3)
- console.log("> \033[32m" + rdp.req.cmd.split(';').slice(0, -1).join(';\n ') + "\033[39m");
+ logger.log(`> ${rdp.req.cmd.split(';').slice(0, -1).join(';\n ')}`);
- rdp.ws.send('{"id":0,"method":"Runtime.evaluate", "params":{"expression":"' + rdp.req.cmd + '"}}');
- rdp.ws.once('message', function (data) {
+ rdp.ws.send(`{"id":0,"method":"Runtime.evaluate", "params":{"expression":"${rdp.req.cmd}"}}`);
+ rdp.ws.once('message', data => {
data = JSON.parse(data);
- if (NCC.options.logLevel >= 3)
- console.log("<\033[35m", data.error || data.result, "\033[39m");
+ logger.log(data.error || data.result);
var err = data.error || data.result.wasThrown ? data.result.result.description : null,
res = err ? null : data.result.result;
@@ -278,32 +231,11 @@ var rdp = ((): RDP => {
});
return rdp;
- }
-
- Object.defineProperties(rdp, {
- cmd: {
- enumerable: DEBUG,
- writable: true,
- value: ""
- },
- queue: {
- enumerable: DEBUG,
- value: []
- }/*,
- addCmd: {
- enumerable: DEBUG,
- value: function (cmd: string) {
- NCC.log("+ \033[33m" + cmd + "\033[39m", 3);
- rdp.cmd += cmd + ";";
- return rdp;
-
- }
- }*/
+ }, {
+ cmd: { enumerable: DEBUG, writable: true, value: '' },
+ queue: { enumerable: DEBUG, value: [] }
})
- return rdp;
-})();
-
// Callback || abstract interface
interface Callback {
(callback?: Function): Callback;
@@ -324,118 +256,115 @@ interface Canvas extends ProxyObj {
getContext: (contextId: string) => Context2d;
}
-var CanvasPDM = (function (): PropertyDescriptorMap {
- return {
-
- // private properties
- _uid: {
- configurable: true,
- enumerable: DEBUG,
- value: "canvas"
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- if (this._uid == "canvas")
- throw new Error("you cannot delete the main canvas")
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- this._ctx = null;
- } else throw new Error("'_remote' can only be set to 'null'")
- }
- },
-
- _ctx: {
- enumerable: DEBUG,
- writable: true,
- value: null
- },
-
- // Properties || proxies with defaults
- width_: {
- enumerable: DEBUG,
- writable: true,
- value: 300
- },
- height_: {
- enumerable: DEBUG,
- writable: true,
- value: 150
- },
-
- // Web API: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement
-
- // Properties || getters/setters || https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Properties
- width: {
- enumerable: true,
- get: function () {
- return this.width_;
- },
- set: function (width) {
- if (width === undefined) return;
- rdp(this._uid + '.width = ' + width)
+var CanvasPDM = {
+
+ // private properties
+ _uid: {
+ configurable: true,
+ enumerable: DEBUG,
+ value: "canvas"
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ if (this._uid == 'canvas')
+ return logger.error('you cannot delete the main canvas')
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ this._ctx = null;
+ } else return logger.error('"_remote" can only be set to "null"')
+ }
+ },
+
+ _ctx: {
+ enumerable: DEBUG,
+ writable: true,
+ value: null
+ },
+
+ // Properties || proxies with defaults
+ width_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: 300
+ },
+ height_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: 150
+ },
+
+ // Web API: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement
+
+ // Properties || getters/setters || https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Properties
+ width: {
+ enumerable: true,
+ get: function () {
+ return this.width_;
+ },
+ set: function (width) {
+ if (width === undefined) return;
+ rdp(`${this._uid}.width = ${width}`)
return this.width_ = width;
- }
- },
- height: {
- enumerable: true,
- get: function () {
- return this.height_;
- },
- set: function (height) {
- if (height === undefined) return;
- rdp(this._uid + '.height = ' + height)
+ }
+ },
+ height: {
+ enumerable: true,
+ get: function () {
+ return this.height_;
+ },
+ set: function (height) {
+ if (height === undefined) return;
+ rdp(`${this._uid}.height = ${height}`)
return this.height_ = height;
- }
- },
-
- // Methods || https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Methods
- getContext: {
- enumerable: true,
- value: function (contextId: string) {
- if (contextId == "2d") {
-
- var uid = NCC.uid('context2d')
- rdp("var " + uid + " = " + this._uid + ".getContext('2d')");
+ }
+ },
- var context2d: any = function (callback?) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, context2d);
- } : undefined);
- return context2d;
- }
+ // Methods || https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement#Methods
+ getContext: {
+ enumerable: true,
+ value: function (contextId: string) {
+ if (contextId == '2d') {
- context2dPDM["_uid"].value = uid;
- context2dPDM["canvas"].value = this;
- Object.defineProperties(context2d, context2dPDM);
- context2dPDM["_uid"].value = "";
+ var uid = this._uid == 'canvas' ? 'context2d' : NCC.uid('context2d')
+ rdp(`var ${uid} = ${this._uid}.getContext('2d')`);
+ var context2d: any = (callback?) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, context2d);
+ } : undefined);
return context2d;
}
- throw new Error(contextId + " is not implemented");
- }
- },
- toDataURL: {
- enumerable: true,
- value: function (type, args) {
+ context2dPDM._uid.value = uid;
+ context2dPDM['canvas'].value = this;
+ Object.defineProperties(context2d, context2dPDM);
+ context2dPDM._uid.value = '';
- rdp(this._uid + ".toDataURL(" + (("'" + type + "'") || "") + ")");
+ return context2d;
+ } else
+ logger.error(`${contextId} is not implemented`);
+ }
+ },
+ toDataURL: {
+ enumerable: true,
+ value: function (type, args) {
- return function (callback) {
- rdp(function (err, res) {
- if (err)
- return callback(err, null);
- callback(err, res.value);
- });
- };
+ rdp(`${this._uid}.toDataURL(${`'${type}'` || ''})`);
- }
+ return (callback) => {
+ rdp((err, res) => {
+ if (err)
+ return callback(err, null);
+ callback(err, res.value);
+ });
+ };
}
- };
-})()
+ }
+};
+
// context2d
interface Context2d extends ProxyObj {
@@ -458,7 +387,7 @@ interface Context2d extends ProxyObj {
textBaseline: string;
webkitBackingStorePixelRatio: number;
webkitImageSmoothingEnabled: boolean;
- arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, anticlockwise?: boolean): Context2d;
+ arc(x: number, y: number, radius: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): Context2d;
arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): Context2d;
beginPath(): Context2d;
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): Context2d;
@@ -496,560 +425,559 @@ interface Context2d extends ProxyObj {
translate(x: number, y: number): Context2d;
}
-var context2dPDM = (function (): PropertyDescriptorMap {
- return {
-
- // private properties
- _uid: {
- enumerable: DEBUG,
- value: ""
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- } else throw new Error("'_remote' can only be set to 'null'")
- }
- },
-
- // Attributes || proxies with defaults
- fillStyle_: { writable: true, enumerable: DEBUG, value: '#000000' },
- font_: { writable: true, enumerable: DEBUG, value: '10px sans-serif' },
- globalAlpha_: { writable: true, enumerable: DEBUG, value: 1.0 },
- globalCompositeOperation_: { writable: true, enumerable: DEBUG, value: 'source-over' },
- lineCap_: { writable: true, enumerable: DEBUG, value: 'butt' },
- lineDashOffset_: { writable: true, enumerable: DEBUG, value: 0 },
- lineJoin_: { writable: true, enumerable: DEBUG, value: 'miter' },
- lineWidth_: { writable: true, enumerable: DEBUG, value: 1.0 },
- miterLimit_: { writable: true, enumerable: DEBUG, value: 10 },
- shadowBlur_: { writable: true, enumerable: DEBUG, value: 0 },
- shadowColor_: { writable: true, enumerable: DEBUG, value: 'rgba(0, 0, 0, 0)' },
- shadowOffsetX_: { writable: true, enumerable: DEBUG, value: 0 },
- shadowOffsetY_: { writable: true, enumerable: DEBUG, value: 0 },
- strokeStyle_: { writable: true, enumerable: DEBUG, value: '#000000' },
- textAlign_: { writable: true, enumerable: DEBUG, value: 'start' },
- textBaseline_: { writable: true, enumerable: DEBUG, value: 'alphabetic' },
- webkitBackingStorePixelRatio_: { writable: true, enumerable: DEBUG, value: 1 },
- webkitImageSmoothingEnabled_: { writable: true, enumerable: DEBUG, value: true },
-
- // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d
-
- // Attributes || getters/setters || https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d#Attributes
- canvas: {
- enumerable: true, value: null // will be overridden on creation
- },
- fillStyle: {
- enumerable: true, get: function () { return this.fillStyle_; },
- set: function (fillStyle) {
- rdp(this._uid + ".fillStyle = " + (fillStyle._uid || ("'" + fillStyle + "'")));
- return this.fillStyle_ = fillStyle;
- }
- },
- font: {
- enumerable: true, get: function () { return this.font_; },
- set: function (font) {
- rdp(this._uid + ".font = '" + font + "'");
- return this.font_ = font;
- }
- },
- globalAlpha: {
- enumerable: true, get: function () { return this.globalAlpha_; },
- set: function (globalAlpha) {
- rdp(this._uid + ".globalAlpha = " + globalAlpha);
- return this.globalAlpha_ = globalAlpha;
- }
- },
- globalCompositeOperation: {
- enumerable: true, get: function () { return this.globalCompositeOperation_; },
- set: function (globalCompositeOperation) {
- rdp(this._uid + ".globalCompositeOperation = '" + globalCompositeOperation + "'");
- return this.globalCompositeOperation_ = globalCompositeOperation;
- }
- },
- lineCap: {
- enumerable: true, get: function () { return this.lineCap_; },
- set: function (lineCap) {
- rdp(this._uid + ".lineCap = '" + lineCap + "'");
- return this.lineCap_ = lineCap;
- }
- },
- lineDashOffset: {
- enumerable: true, get: function () { return this.lineDashOffset_; },
- set: function (lineDashOffset) {
- rdp(this._uid + ".lineDashOffset = " + lineDashOffset);
- return this.lineDashOffset_ = lineDashOffset;
- }
- },
- lineJoin: {
- enumerable: true, get: function () { return this.lineJoin_; },
- set: function (lineJoin) {
- rdp(this._uid + ".lineJoin = '" + lineJoin + "'");
- return this.lineJoin_ = lineJoin;
- }
- },
- lineWidth: {
- enumerable: true, get: function () { return this.lineWidth_; },
- set: function (lineWidth) {
- rdp(this._uid + ".lineWidth = " + lineWidth);
- return this.lineWidth_ = lineWidth;
- }
- },
- miterLimit: {
- enumerable: true, get: function () { return this.miterLimit_; },
- set: function (miterLimit) {
- rdp(this._uid + ".miterLimit = " + miterLimit);
- return this.miterLimit_ = miterLimit;
- }
- },
- shadowBlur: {
- enumerable: true, get: function () { return this.shadowBlur_; },
- set: function (shadowBlur) {
- rdp(this._uid + ".shadowBlur = " + shadowBlur);
- return this.shadowBlur_ = shadowBlur;
- }
- },
- shadowColor: {
- enumerable: true, get: function () { return this.shadowColor; },
- set: function (shadowColor) {
- rdp(this._uid + ".shadowColor = '" + shadowColor + "'");
- return this.shadowColor_ = shadowColor;
- }
- },
- shadowOffsetX: {
- enumerable: true, get: function () { return this.shadowOffsetX_; },
- set: function (shadowOffsetX) {
- rdp(this._uid + ".shadowOffsetX = " + shadowOffsetX);
- return this.shadowOffsetX_ = shadowOffsetX;
- }
- },
- shadowOffsetY: {
- enumerable: true, get: function () { return this.shadowOffsetY_; },
- set: function (shadowOffsetY) {
- rdp(this._uid + ".shadowOffsetY = " + shadowOffsetY);
- return this.shadowOffsetY_ = shadowOffsetY;
- }
- },
- strokeStyle: {
- enumerable: true, get: function () { return this.strokeStyle_; },
- set: function (strokeStyle) {
- rdp(this._uid + ".strokeStyle = " + (strokeStyle._uid || ("'" + strokeStyle + "'")));
- return this.strokeStyle_ = strokeStyle;
- }
- },
- textAlign: {
- enumerable: true, get: function () { return this.textAlign_; },
- set: function (textAlign) {
- rdp(this._uid + ".textAlign = '" + textAlign + "'");
- return this.textAlign_ = textAlign;
- }
- },
- textBaseline: {
- enumerable: true, get: function () { return this.textBaseline_; },
- set: function (textBaseline) {
- rdp(this._uid + ".textBaseline = '" + textBaseline + "'");
- return this.textBaseline_ = textBaseline;
- }
- },
- webkitBackingStorePixelRatio: {
- enumerable: true, get: function () { return this.webkitBackingStorePixelRatio_; },
- set: function (webkitBackingStorePixelRatio) {
- rdp(this._uid + ".webkitBackingStorePixelRatio = " + webkitBackingStorePixelRatio);
- return this.webkitBackingStorePixelRatio_ = webkitBackingStorePixelRatio;
- }
- },
- webkitImageSmoothingEnabled: {
- enumerable: true, get: function () { return this.webkitImageSmoothingEnabled_; },
- set: function (webkitImageSmoothingEnabled) {
- rdp(this._uid + ".webkitImageSmoothingEnabled = " + webkitImageSmoothingEnabled);
- return this.webkitImageSmoothingEnabled_ = webkitImageSmoothingEnabled;
- }
- },
-
- // Methods || https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d#Methods
- arc: { //RETURN/ void //IN/ in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise Optional
- enumerable: true,
- value: function (x, y, radius, startAngle, endAngle, anticlockwise) {
- return rdp(this._uid + ".arc(" + (Array.prototype.slice.call(arguments, 0).join(',')) + ")");
- }
- },
+var context2dPDM = {
+
+ // private properties
+ _uid: {
+ enumerable: DEBUG,
+ value: ''
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ } else
+ logger.error('"_remote" can only be set to "null"')
+ }
+ },
+
+ // Attributes || proxies with defaults
+ fillStyle_: { writable: true, enumerable: DEBUG, value: '#000000' },
+ font_: { writable: true, enumerable: DEBUG, value: '10px sans-serif' },
+ globalAlpha_: { writable: true, enumerable: DEBUG, value: 1.0 },
+ globalCompositeOperation_: { writable: true, enumerable: DEBUG, value: 'source-over' },
+ lineCap_: { writable: true, enumerable: DEBUG, value: 'butt' },
+ lineDashOffset_: { writable: true, enumerable: DEBUG, value: 0 },
+ lineJoin_: { writable: true, enumerable: DEBUG, value: 'miter' },
+ lineWidth_: { writable: true, enumerable: DEBUG, value: 1.0 },
+ miterLimit_: { writable: true, enumerable: DEBUG, value: 10 },
+ shadowBlur_: { writable: true, enumerable: DEBUG, value: 0 },
+ shadowColor_: { writable: true, enumerable: DEBUG, value: 'rgba(0, 0, 0, 0)' },
+ shadowOffsetX_: { writable: true, enumerable: DEBUG, value: 0 },
+ shadowOffsetY_: { writable: true, enumerable: DEBUG, value: 0 },
+ strokeStyle_: { writable: true, enumerable: DEBUG, value: '#000000' },
+ textAlign_: { writable: true, enumerable: DEBUG, value: 'start' },
+ textBaseline_: { writable: true, enumerable: DEBUG, value: 'alphabetic' },
+ webkitBackingStorePixelRatio_: { writable: true, enumerable: DEBUG, value: 1 },
+ webkitImageSmoothingEnabled_: { writable: true, enumerable: DEBUG, value: true },
+
+ // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d
+
+ // Attributes || getters/setters || https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d#Attributes
+ canvas: {
+ enumerable: true, value: null // will be overridden on creation
+ },
+ fillStyle: {
+ enumerable: true, get: function () { return this.fillStyle_; },
+ set: function (fillStyle) {
+ rdp(`${this._uid}.fillStyle = ${fillStyle._uid || `'${fillStyle}'`}`);
+ return this.fillStyle_ = fillStyle;
+ }
+ },
+ font: {
+ enumerable: true, get: function () { return this.font_; },
+ set: function (font) {
+ rdp(`${this._uid}.font = '${font}'`);
+ return this.font_ = font;
+ }
+ },
+ globalAlpha: {
+ enumerable: true, get: function () { return this.globalAlpha_; },
+ set: function (globalAlpha) {
+ rdp(`${this._uid}.globalAlpha = ${globalAlpha}`);
+ return this.globalAlpha_ = globalAlpha;
+ }
+ },
+ globalCompositeOperation: {
+ enumerable: true, get: function () { return this.globalCompositeOperation_; },
+ set: function (globalCompositeOperation) {
+ rdp(`${this._uid}.globalCompositeOperation = '${globalCompositeOperation}'`);
+ return this.globalCompositeOperation_ = globalCompositeOperation;
+ }
+ },
+ lineCap: {
+ enumerable: true, get: function () { return this.lineCap_; },
+ set: function (lineCap) {
+ rdp(`${this._uid}.lineCap = '${lineCap}'`);
+ return this.lineCap_ = lineCap;
+ }
+ },
+ lineDashOffset: {
+ enumerable: true, get: function () { return this.lineDashOffset_; },
+ set: function (lineDashOffset) {
+ rdp(`${this._uid}.lineDashOffset = ${lineDashOffset}`);
+ return this.lineDashOffset_ = lineDashOffset;
+ }
+ },
+ lineJoin: {
+ enumerable: true, get: function () { return this.lineJoin_; },
+ set: function (lineJoin) {
+ rdp(`${this._uid}.lineJoin = '${lineJoin}'`);
+ return this.lineJoin_ = lineJoin;
+ }
+ },
+ lineWidth: {
+ enumerable: true, get: function () { return this.lineWidth_; },
+ set: function (lineWidth) {
+ rdp(`${this._uid}.lineWidth = ${lineWidth}`);
+ return this.lineWidth_ = lineWidth;
+ }
+ },
+ miterLimit: {
+ enumerable: true, get: function () { return this.miterLimit_; },
+ set: function (miterLimit) {
+ rdp(`${this._uid}.miterLimit = ${miterLimit}`);
+ return this.miterLimit_ = miterLimit;
+ }
+ },
+ shadowBlur: {
+ enumerable: true, get: function () { return this.shadowBlur_; },
+ set: function (shadowBlur) {
+ rdp(`${this._uid}.shadowBlur = ${shadowBlur}`);
+ return this.shadowBlur_ = shadowBlur;
+ }
+ },
+ shadowColor: {
+ enumerable: true, get: function () { return this.shadowColor; },
+ set: function (shadowColor) {
+ rdp(`${this._uid}.shadowColor = '${shadowColor}'`);
+ return this.shadowColor_ = shadowColor;
+ }
+ },
+ shadowOffsetX: {
+ enumerable: true, get: function () { return this.shadowOffsetX_; },
+ set: function (shadowOffsetX) {
+ rdp(`${this._uid}.shadowOffsetX = ${shadowOffsetX}`);
+ return this.shadowOffsetX_ = shadowOffsetX;
+ }
+ },
+ shadowOffsetY: {
+ enumerable: true, get: function () { return this.shadowOffsetY_; },
+ set: function (shadowOffsetY) {
+ rdp(`${this._uid}.shadowOffsetY = ${shadowOffsetY}`);
+ return this.shadowOffsetY_ = shadowOffsetY;
+ }
+ },
+ strokeStyle: {
+ enumerable: true, get: function () { return this.strokeStyle_; },
+ set: function (strokeStyle) {
+ rdp(`${this._uid}.strokeStyle = ${strokeStyle._uid || `'${strokeStyle}'`}`);
+ return this.strokeStyle_ = strokeStyle;
+ }
+ },
+ textAlign: {
+ enumerable: true, get: function () { return this.textAlign_; },
+ set: function (textAlign) {
+ rdp(`${this._uid}.textAlign = '${textAlign}'`);
+ return this.textAlign_ = textAlign;
+ }
+ },
+ textBaseline: {
+ enumerable: true, get: function () { return this.textBaseline_; },
+ set: function (textBaseline) {
+ rdp(`${this._uid}.textBaseline = '${textBaseline}'`);
+ return this.textBaseline_ = textBaseline;
+ }
+ },
+ webkitBackingStorePixelRatio: {
+ enumerable: true, get: function () { return this.webkitBackingStorePixelRatio_; },
+ set: function (webkitBackingStorePixelRatio) {
+ rdp(`${this._uid}.webkitBackingStorePixelRatio = ${webkitBackingStorePixelRatio}`);
+ return this.webkitBackingStorePixelRatio_ = webkitBackingStorePixelRatio;
+ }
+ },
+ webkitImageSmoothingEnabled: {
+ enumerable: true, get: function () { return this.webkitImageSmoothingEnabled_; },
+ set: function (webkitImageSmoothingEnabled) {
+ rdp(`${this._uid}.webkitImageSmoothingEnabled = ${webkitImageSmoothingEnabled}`);
+ return this.webkitImageSmoothingEnabled_ = webkitImageSmoothingEnabled;
+ }
+ },
- arcTo: { //RETURN/ void //IN/ in float x1, in float y1, in float x2, in float y2, in float radius
- enumerable: true,
- value: function (x1, y1, x2, y2, radius) {
- return rdp(this._uid + ".arcTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + radius + ")");
- }
- },
+ // Methods || https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingcontext2d#Methods
+ arc: { //RETURN/ void //IN/ in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise Optional
+ enumerable: true,
+ value: function (x, y, radius, startAngle, endAngle, anticlockwise) {
+ return rdp(`${this._uid}.arc(${Array.prototype.slice.call(arguments, 0).join(',')})`);
+ }
+ },
- beginPath: { //RETURN/ void //IN/
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".beginPath()");
- }
- },
+ arcTo: { //RETURN/ void //IN/ in float x1, in float y1, in float x2, in float y2, in float radius
+ enumerable: true,
+ value: function (x1, y1, x2, y2, radius) {
+ return rdp(`${this._uid}.arcTo(${x1},${y1},${x2},${y2},${radius})`);
+ }
+ },
- bezierCurveTo: { //RETURN/ void //IN/ in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y
- enumerable: true,
- value: function (cp1x, cp1y, cp2x, cp2y, x, y) {
- return rdp(this._uid + ".bezierCurveTo(" + cp1x + ", " + cp1y + ", " + cp2x + ", " + cp2y + ", " + x + ", " + y + ")");
- }
- },
+ beginPath: { //RETURN/ void //IN/
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.beginPath()`);
+ }
+ },
- clearRect: { //RETURN/ void //IN/ in float x, in float y, in float width, in float height
- enumerable: true,
- value: function (x, y, width, height) {
- return rdp(this._uid + ".clearRect(" + x + ", " + y + ", " + width + ", " + height + ")");
- }
- },
+ bezierCurveTo: { //RETURN/ void //IN/ in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y
+ enumerable: true,
+ value: function (cp1x, cp1y, cp2x, cp2y, x, y) {
+ return rdp(`${this._uid}.bezierCurveTo(${cp1x},${cp1y},${cp2x},${cp2y},${x},${y})`);
+ }
+ },
- clip: { //RETURN/ void //IN/
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".clip()");
- }
- },
+ clearRect: { //RETURN/ void //IN/ in float x, in float y, in float width, in float height
+ enumerable: true,
+ value: function (x, y, width, height) {
+ return rdp(`${this._uid}.clearRect(${x},${y},${width},${height})`);
+ }
+ },
- closePath: { //RETURN/ void //IN/
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".closePath()");
- }
- },
+ clip: { //RETURN/ void //IN/
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.clip()`);
+ }
+ },
- createImageData: { //RETURN/ ImageData //IN/ in float width, in float height
- enumerable: true,
- value: function (width, height) {
+ closePath: { //RETURN/ void //IN/
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.closePath()`);
+ }
+ },
- if (width.height != undefined) { // if image data is passed
- height = width.height;
- width = width.width;
- }
+ createImageData: { //RETURN/ ImageData //IN/ in float width, in float height
+ enumerable: true,
+ value: function (width, height) {
- return function (callback) {
- callback(null, {
- data: new Uint8ClampedArray(Array.apply(null, new Array(width * height * 4)).map(Number.prototype.valueOf, 0)),
- width: width,
- height: height
- });
- };
+ if (width.height != undefined) { // if image data is passed
+ height = width.height;
+ width = width.width;
}
- },
-
- createLinearGradient: { //RETURN/ nsIDOMCanvasGradient //IN/ in float x0, in float y0, in float x1, in float y1
- enumerable: true,
- value: function (x0, y0, x1, y1) {
- var uid = NCC.uid('linearGradient')
- rdp("var " + uid + " = " + this._uid + ".createLinearGradient(" + x0 + ", " + y0 + ", " + x1 + ", " + y1 + ")");
-
- var linearGradient: any = function (callback?) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, linearGradient);
- } : undefined);
- return linearGradient;
- }
-
- GradientPDM["_uid"].value = uid;
- Object.defineProperties(linearGradient, GradientPDM);
- GradientPDM["_uid"].value = "";
+ return (callback) => {
+ callback(null, {
+ data: new Uint8ClampedArray(Array.apply(null, new Array(width * height * 4)).map(Number.prototype.valueOf, 0)),
+ width: width,
+ height: height
+ });
+ };
+ }
+ },
+
+ createLinearGradient: { //RETURN/ nsIDOMCanvasGradient //IN/ in float x0, in float y0, in float x1, in float y1
+ enumerable: true,
+ value: function (x0, y0, x1, y1) {
+ var uid = NCC.uid('linearGradient')
+ rdp(`var ${uid} = ${this._uid}.createLinearGradient(${x0},${y0},${x1},${y1})`);
+
+ var linearGradient: any = (callback?) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, linearGradient);
+ } : undefined);
return linearGradient;
}
- },
-
- createPattern: { //RETURN/ nsIDOMCanvasPattern //IN/ in nsIDOMHTMLElement image, in DOMString repetition
- enumerable: true,
- value: function (image, repetition) {
- var uid = NCC.uid('pattern')
- rdp("var " + uid + " = " + this._uid + ".createPattern(" + image._uid + ", '" + repetition + "')");
+ GradientPDM._uid.value = uid;
+ Object.defineProperties(linearGradient, GradientPDM);
+ GradientPDM._uid.value = '';
+ return linearGradient;
+ }
+ },
- var pattern: any = function (callback?) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, pattern);
- } : undefined);
- return pattern;
- }
+ createPattern: { //RETURN/ nsIDOMCanvasPattern //IN/ in nsIDOMHTMLElement image, in DOMString repetition
+ enumerable: true,
+ value: function (image, repetition) {
- PatternPDM["_uid"].value = uid;
- Object.defineProperties(pattern, PatternPDM);
- PatternPDM["_uid"].value = "";
+ var uid = NCC.uid('pattern');
+ rdp(`var ${uid} = ${this._uid}.createPattern(${image._uid},'${repetition}')`);
+ var pattern: any = (callback?) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, pattern);
+ } : undefined);
return pattern;
}
- },
- createRadialGradient: { //RETURN/ nsIDOMCanvasGradient //IN/ in float x0, in float y0, in float r0, in float x1, in float y1, in float r1
- enumerable: true,
- value: function (x0, y0, r0, x1, y1, r1) {
+ PatternPDM._uid.value = uid;
+ Object.defineProperties(pattern, PatternPDM);
+ PatternPDM._uid.value = '';
- var uid = NCC.uid('pattern')
- rdp("var " + uid + " = " + this._uid + ".createRadialGradient(" + x0 + ", " + y0 + ", " + r0 + ", " + x1 + ", " + y1 + ", " + r1 + ")");
+ return pattern;
+ }
+ },
- var radialGradient: any = function (callback?) {
- rdp(callback ? function (err, res) {
- err ? callback(err, null) : callback(null, radialGradient);
- } : undefined);
- return radialGradient;
- }
+ createRadialGradient: { //RETURN/ nsIDOMCanvasGradient //IN/ in float x0, in float y0, in float r0, in float x1, in float y1, in float r1
+ enumerable: true,
+ value: function (x0, y0, r0, x1, y1, r1) {
- GradientPDM["_uid"].value = NCC.uid('radialGradient');
- Object.defineProperties(radialGradient, GradientPDM);
- GradientPDM["_uid"].value = "";
+ var uid = NCC.uid('pattern')
+ rdp(`var ${uid} = ${this._uid}.createRadialGradient(${x0},${y0},${r0},${x1},${y1},${r1})`);
+ var radialGradient: any = (callback?) => {
+ rdp(callback ? (err, res) => {
+ err ? callback(err, null) : callback(null, radialGradient);
+ } : undefined);
return radialGradient;
}
- },
-
- drawImage: { //RETURN/ void //IN/ in nsIDOMElement image, in float a1, in float a2, in float a3 Optional, in float a4 Optional, in float a5 Optional, in float a6 Optional, in float a7 Optional, in float a8 Optional
- enumerable: true,
- value: function (image, a1, a2, a3, a4, a5, a6, a7, a8) {
- return rdp(this._uid + ".drawImage(" + image._uid + ", " + (Array.prototype.slice.call(arguments, 1).join(',')) + ")");
- }
- },
-
- // no use
- //drawCustomFocusRing: { //RETURN/ boolean //IN/ Element element
- // enumerable:true,
- // value: function (element) {
- // rdp(this._uid + ".drawCustomFocusRing(" + element + ")");
- // return this;
- // }
- //},
-
- // no use
- //drawSystemFocusRing: { //RETURN/ void //IN/ Element element
- // enumerable:true,
- // value: function (element) {
- // rdp(this._uid + ".drawSystemFocusRinelementg()");
- // return this;
- // }
- //},
-
- fill: { //RETURN/ void //IN/
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".fill()");
- }
- },
-
- fillRect: { //RETURN/ void //IN/ in float x, in float y, in float width, in float height
- enumerable: true,
- value: function (x, y, width, height) {
- return rdp(this._uid + ".fillRect(" + x + ", " + y + ", " + width + ", " + height + ")");
- }
- },
- fillText: { //RETURN/ void //IN/ in DOMString text, in float x, in float y, in float maxWidth Optional
- enumerable: true,
- value: function (text, x, y, maxWidth) {
- return rdp(this._uid + ".fillText('" + text + "', " + (Array.prototype.slice.call(arguments, 1).join(',')) + ")");
- }
- },
+ GradientPDM._uid.value = NCC.uid('radialGradient');
+ Object.defineProperties(radialGradient, GradientPDM);
+ GradientPDM._uid.value = '';
- getImageData: { //RETURN/ //IN/ in float x, in float y, in float width, in float height
- enumerable: true,
- value: function (x, y, width, height) {
- rdp("Array.prototype.slice.call(" + this._uid + ".getImageData(" + x + "," + y + "," + width + "," + height + ").data).join(',')");
- return function (callback) {
- rdp(function (err, res) {
- if (err)
- return callback(err, null);
-
- var imageData = {
- data: new Uint8ClampedArray(res.value.split(',')),
- width: width,
- height: height
- };
-
- callback(null, imageData);
- });
- };
- }
- },
-
- getLineDash: { //RETURN/ sequence //IN/
- enumerable: true,
- value: function () {
- rdp(this._uid + ".getLineDash().join(',')");
- return function (callback) {
- rdp(function (err, res) {
- if (err)
- return callback(err);
-
- res.value = res.value.split(',');
- for (var i = 0, l = res.value.length; i < l; i++)
- res.value[i] = +res.value[i];
-
- callback(err, res.value);
- });
- };
- }
- },
-
- isPointInPath: { //RETURN/ boolean //IN/ in float x, in float y
- enumerable: true,
- value: function (x, y) {
- rdp(this._uid + ".isPointInPath(" + x + ", " + y + ")");
- return function (callback) {
- rdp(function (err, res) {
- callback(err, res.value);
- });
- };
- }
- },
+ return radialGradient;
+ }
+ },
- isPointInStroke: { //RETURN/ boolean //IN/ in float x, in float y
- enumerable: true,
- value: function (x, y) {
- rdp(this._uid + ".isPointInStroke(" + x + ", " + y + ")");
- return function (callback) {
- rdp(function (err, res) {
- callback(err, res.value);
- });
- };
- }
- },
+ drawImage: { //RETURN/ void //IN/ in nsIDOMElement image, in float a1, in float a2, in float a3 Optional, in float a4 Optional, in float a5 Optional, in float a6 Optional, in float a7 Optional, in float a8 Optional
+ enumerable: true,
+ value: function (image, a1, a2, a3, a4, a5, a6, a7, a8) {
+ return rdp(`${this._uid}.drawImage(${image._uid}, ${Array.prototype.slice.call(arguments, 1).join(',')})`);
+ }
+ },
+
+ // no use
+ //drawCustomFocusRing: { //RETURN/ boolean //IN/ Element element
+ // enumerable:true,
+ // value: function (element) {
+ // rdp(`${this._uid}.drawCustomFocusRing(" + element + ")`);
+ // return this;
+ // }
+ //},
+
+ // no use
+ //drawSystemFocusRing: { //RETURN/ void //IN/ Element element
+ // enumerable:true,
+ // value: function (element) {
+ // rdp(`${this._uid}.drawSystemFocusRinelementg()`);
+ // return this;
+ // }
+ //},
+
+ fill: { //RETURN/ void //IN/
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.fill()`);
+ }
+ },
- lineTo: { //RETURN/ void //IN/ in float x, in float y
- enumerable: true,
- value: function (x, y) {
- return rdp(this._uid + ".lineTo(" + x + ", " + y + ")");
- }
- },
+ fillRect: { //RETURN/ void //IN/ in float x, in float y, in float width, in float height
+ enumerable: true,
+ value: function (x, y, width, height) {
+ return rdp(`${this._uid}.fillRect(${x},${y},${width},${height})`);
+ }
+ },
- measureText: { //RETURN/ nsIDOMTextMetrics //IN/ in DOMString text
- enumerable: true,
- value: function (text) {
- rdp(this._uid + ".measureText('" + text + "').width");
- return function (callback) {
- rdp(function (err, res) {
- if (err)
- return callback(err);
-
- callback(null, { width: res.value });
- });
- };
- }
- },
+ fillText: { //RETURN/ void //IN/ in DOMString text, in float x, in float y, in float maxWidth Optional
+ enumerable: true,
+ value: function (text, x, y, maxWidth) {
+ return rdp(`${this._uid}.fillText('${text}',${Array.prototype.slice.call(arguments, 1).join(',')})`);
+ }
+ },
+
+ getImageData: { //RETURN/ //IN/ in float x, in float y, in float width, in float height
+ enumerable: true,
+ value: function (x, y, width, height) {
+ rdp(`Array.prototype.slice.call(${this._uid}.getImageData(${x},${y},${width},${height}).data).join(',')`);
+ return (callback) => {
+ rdp((err, res) => {
+ if (err)
+ return callback(err, null);
+
+ var imageData = {
+ data: new Uint8ClampedArray(res.value.split(',')),
+ width: width,
+ height: height
+ };
- moveTo: { //RETURN/ void //IN/ in float x, in float y
- enumerable: true,
- value: function (x, y) {
- return rdp(this._uid + ".moveTo(" + x + ", " + y + ")");
- }
- },
+ callback(null, imageData);
+ });
+ };
+ }
+ },
+
+ getLineDash: { //RETURN/ sequence //IN/
+ enumerable: true,
+ value: function () {
+ rdp(`${this._uid}.getLineDash().join(',')`);
+ return (callback) => {
+ rdp((err, res) => {
+ if (err)
+ return callback(err);
+
+ res.value = res.value.split(',');
+ for (var i = 0, l = res.value.length; i < l; i++)
+ res.value[i] = +res.value[i];
+
+ callback(err, res.value);
+ });
+ };
+ }
+ },
+
+ isPointInPath: { //RETURN/ boolean //IN/ in float x, in float y
+ enumerable: true,
+ value: function (x, y) {
+ rdp(`${this._uid}.isPointInPath(${x},${y})`);
+ return (callback) => {
+ rdp((err, res) => {
+ callback(err, res.value);
+ });
+ };
+ }
+ },
+
+ isPointInStroke: { //RETURN/ boolean //IN/ in float x, in float y
+ enumerable: true,
+ value: function (x, y) {
+ rdp(`${this._uid}.isPointInStroke(${x},${y})`);
+ return (callback) => {
+ rdp((err, res) => {
+ callback(err, res.value);
+ });
+ };
+ }
+ },
- putImageData: { //RETURN/ void //IN/ in ImageData imagedata, in float dx, double dy, in float dirtyX Optional, in float dirtyY Optional, in float dirtyWidth Optional, in float dirtyHeight Optional
- enumerable: true,
- value: function (imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) {
- return rdp("var data = [" + Array.prototype.slice.call(imagedata.data).join(',') + "]; var iD = " + this._uid + ".createImageData(" + imagedata.width + ", " + imagedata.height + "); for (var i = 0, l = iD.data.length; i < l; i++) iD.data[i] = +data[i]; " + this._uid + ".putImageData(iD, " + (Array.prototype.slice.call(arguments, 1).join(',')) + ")");
- }
- },
+ lineTo: { //RETURN/ void //IN/ in float x, in float y
+ enumerable: true,
+ value: function (x, y) {
+ return rdp(`${this._uid}.lineTo(${x},${y})`);
+ }
+ },
+
+ measureText: { //RETURN/ nsIDOMTextMetrics //IN/ in DOMString text
+ enumerable: true,
+ value: function (text) {
+ rdp(`${this._uid}.measureText('${text}').width`);
+ return (callback) => {
+ rdp((err, res) => {
+ if (err)
+ return callback(err);
+
+ callback(null, { width: res.value });
+ });
+ };
+ }
+ },
- quadraticCurveTo: { //RETURN/ void //IN/ in float cpx, in float cpy, in float x, in float y
- enumerable: true,
- value: function (cpx, cpy, x, y) {
- return rdp(this._uid + ".quadraticCurveTo(" + cpx + ", " + cpy + ", " + x + ", " + y + ")");
- }
- },
+ moveTo: { //RETURN/ void //IN/ in float x, in float y
+ enumerable: true,
+ value: function (x, y) {
+ return rdp(`${this._uid}.moveTo(${x},${y})`);
+ }
+ },
- rect: { //RETURN/ void //IN/ in float x, in float y, in float width, in float height
- enumerable: true,
- value: function (x, y, width, height) {
- return rdp(this._uid + ".rect(" + x + ", " + y + ", " + width + ", " + height + ")");
- }
- },
+ putImageData: { //RETURN/ void //IN/ in ImageData imagedata, in float dx, double dy, in float dirtyX Optional, in float dirtyY Optional, in float dirtyWidth Optional, in float dirtyHeight Optional
+ enumerable: true,
+ value: function (imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) {
+ return rdp(`var data = [${Array.prototype.slice.call(imagedata.data).join(',')}]; var iD = ${this._uid}.createImageData(${imagedata.width}, ${imagedata.height}); for (var i = 0, l = iD.data.length; i < l; i++) iD.data[i] = +data[i]; ${this._uid}.putImageData(iD, ${Array.prototype.slice.call(arguments, 1).join(',')})`);
+ }
+ },
- restore: { //RETURN/ void //IN/
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".restore()");
- }
- },
+ quadraticCurveTo: { //RETURN/ void //IN/ in float cpx, in float cpy, in float x, in float y
+ enumerable: true,
+ value: function (cpx, cpy, x, y) {
+ return rdp(`${this._uid}.quadraticCurveTo(${cpx},${cpy},${x},${y})`);
+ }
+ },
- rotate: { //RETURN/ void //IN/ in float angle
- enumerable: true,
- value: function (angle) {
- return rdp(this._uid + ".rotate(" + angle + ")");
- }
- },
+ rect: { //RETURN/ void //IN/ in float x, in float y, in float width, in float height
+ enumerable: true,
+ value: function (x, y, width, height) {
+ return rdp(`${this._uid}.rect(${x},${y},${width},${height})`);
+ }
+ },
- save: { //RETURN/ void //IN/
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".save()");
- }
- },
+ restore: { //RETURN/ void //IN/
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.restore()`);
+ }
+ },
- scale: { //RETURN/ void //IN/ in float x, in float y
- enumerable: true,
- value: function (x, y) {
- return rdp(this._uid + ".scale(" + x + ", " + y + ")");
- }
- },
+ rotate: { //RETURN/ void //IN/ in float angle
+ enumerable: true,
+ value: function (angle) {
+ return rdp(`${this._uid}.rotate(${angle})`);
+ }
+ },
- // no use
- //scrollPathIntoView: { //RETURN/ void //IN/
- // enumerable: true,
- // value: function () {
- // rdp(this._uid + ".scrollPathIntoView()");
- // return this;
- // }
- //},
+ save: { //RETURN/ void //IN/
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.save()`);
+ }
+ },
- setLineDash: { //RETURN/ void //IN/ in sequence segments
- enumerable: true,
- value: function (segments) {
- return rdp(this._uid + ".setLineDash([" + segments.join(',') + "])");
- }
- },
+ scale: { //RETURN/ void //IN/ in float x, in float y
+ enumerable: true,
+ value: function (x, y) {
+ return rdp(`${this._uid}.scale(${x},${y})`);
+ }
+ },
+
+ // no use
+ //scrollPathIntoView: { //RETURN/ void //IN/
+ // enumerable: true,
+ // value: function () {
+ // rdp(`${this._uid}.scrollPathIntoView()`);
+ // return this;
+ // }
+ //},
+
+ setLineDash: { //RETURN/ void //IN/ in sequence segments
+ enumerable: true,
+ value: function (segments) {
+ return rdp(`${this._uid}.setLineDash([${segments.join(',')}])`);
+ }
+ },
- setTransform: { //RETURN/ void //IN/ in float m11, in float m12, in float m21, in float m22, in float dx, in float dy
- enumerable: true,
- value: function (m11, m12, m21, m22, dx, dy) {
- return rdp(this._uid + ".setTransform(" + m11 + ", " + m12 + ", " + m21 + ", " + m22 + ", " + dx + ", " + dy + ")");
- }
- },
+ setTransform: { //RETURN/ void //IN/ in float m11, in float m12, in float m21, in float m22, in float dx, in float dy
+ enumerable: true,
+ value: function (m11, m12, m21, m22, dx, dy) {
+ return rdp(`${this._uid}.setTransform(${m11},${m12},${m21},${m22},${dx},${dy})`);
+ }
+ },
- stroke: { //RETURN/ void //IN/
- enumerable: true,
- value: function () {
- return rdp(this._uid + ".stroke()");
- }
- },
+ stroke: { //RETURN/ void //IN/
+ enumerable: true,
+ value: function () {
+ return rdp(`${this._uid}.stroke()`);
+ }
+ },
- strokeRect: { //RETURN/ void //IN/ in float x, in float y, in float w, in float h
- enumerable: true,
- value: function (x, y, w, h) {
- return rdp(this._uid + ".strokeRect(" + x + ", " + y + ", " + w + ", " + h + ")");
- }
- },
+ strokeRect: { //RETURN/ void //IN/ in float x, in float y, in float w, in float h
+ enumerable: true,
+ value: function (x, y, w, h) {
+ return rdp(`${this._uid}.strokeRect(${x},${y},${w},${h})`);
+ }
+ },
- strokeText: { //RETURN/ void //IN/ in DOMString text, in float x, in float y, in float maxWidth Optional
- enumerable: true,
- value: function (text, x, y, maxWidth) {
- rdp(this._uid + ".strokeText('" + text + "', " + (Array.prototype.slice.call(arguments, 1).join(',')) + ")");
- return this;
- }
- },
+ strokeText: { //RETURN/ void //IN/ in DOMString text, in float x, in float y, in float maxWidth Optional
+ enumerable: true,
+ value: function (text, x, y, maxWidth) {
+ rdp(`${this._uid}.strokeText('${text}',${(Array.prototype.slice.call(arguments, 1).join(','))})`);
+ return this;
+ }
+ },
- transform: { //RETURN/ void //IN/ in float m11, in float m12, in float m21, in float m22, in float dx, in float dy
- enumerable: true,
- value: function (m11, m12, m21, m22, dx, dy) {
- return rdp(this._uid + ".transform(" + m11 + ", " + m12 + ", " + m21 + ", " + m22 + ", " + dx + ", " + dy + ")");
- }
- },
+ transform: { //RETURN/ void //IN/ in float m11, in float m12, in float m21, in float m22, in float dx, in float dy
+ enumerable: true,
+ value: function (m11, m12, m21, m22, dx, dy) {
+ return rdp(`${this._uid}.transform(${m11},${m12},${m21},${m22},${dx},${dy})`);
+ }
+ },
- translate: { //RETURN/ void //IN/ in float x, in float y
- enumerable: true,
- value: function (x, y) {
- return rdp(this._uid + ".translate(" + x + ", " + y + ")");
- }
+ translate: { //RETURN/ void //IN/ in float x, in float y
+ enumerable: true,
+ value: function (x, y) {
+ return rdp(`${this._uid}.translate(${x},${y})`);
}
+ }
+
+};
- };
-})()
// Gradient
interface Gradient extends ProxyObj {
@@ -1057,63 +985,63 @@ interface Gradient extends ProxyObj {
addColorStop(offset: number, color: string): Callback;
}
-var GradientPDM = (function (): PropertyDescriptorMap {
- return {
-
- // private properties
- _uid: {
- enumerable: DEBUG,
- value: ""
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- } else throw new Error("'_remote' can only be set to 'null'")
- }
- },
+var GradientPDM = {
+
+ // private properties
+ _uid: {
+ enumerable: DEBUG,
+ value: ''
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ } else
+ logger.error('"_remote" can only be set to "null"')
+ }
+ },
- // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient
+ // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient
- // Methods
+ // Methods
- addColorStop: {
- enumerable: true,
- value: function (offset, color) {
- return rdp(this._uid + ".addColorStop(" + offset + ", '" + color + "')");
- }
+ addColorStop: {
+ enumerable: true,
+ value: function (offset, color) {
+ return rdp(`${this._uid}.addColorStop(${offset},'${color}')`);
}
}
-})()
+};
+
// Pattern
interface Pattern extends ProxyObj {
(callback?): Pattern;
}
-var PatternPDM = (function (): PropertyDescriptorMap {
- return {
+var PatternPDM = {
+
+ // private properties
+ _uid: {
+ enumerable: DEBUG,
+ value: ''
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ } else
+ logger.error('"_remote" can only be set to "null"')
+ }
+ },
- // private properties
- _uid: {
- enumerable: DEBUG,
- value: ""
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- } else throw new Error("'_remote' can only be set to 'null'")
- }
- },
+ // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern
+};
- // Web API: https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern
- }
-})()
// Image
interface Image extends ProxyObj {
@@ -1141,162 +1069,163 @@ var regExp_data = new RegExp('^(data:image\\/\\w+;base64,.+)');
var regExp_type = new RegExp('^data:image\\/(\\w+);base64,');
-var ImagePDM = (function (): PropertyDescriptorMap {
- return {
-
- // private properties
- _uid: {
- enumerable: DEBUG,
- value: ""
- },
- _remote: {
- enumerable: DEBUG,
- set: function (null_) {
- if (null_ === null) {
- rdp(this._uid + " = null");
- Object.defineProperty(this, '_uid', { value: null });
- } else throw new Error("'_remote' can only be set to 'null'")
- }
- },
-
- // Properties
- src_: {
- enumerable: DEBUG,
- writable: true,
- value: ""
- },
- width_: {
- enumerable: DEBUG,
- writable: true,
- value: undefined
- },
- height_: {
- enumerable: DEBUG,
- writable: true,
- value: undefined
- },
- _base64_: {
- enumerable: DEBUG,
- writable: true,
- value: null
- },
- _base64: {
- enumerable: DEBUG,
- get: function () {
- return this._base64_;
- },
- set: function (base64) {
- var img = this;
- rdp(this._uid + ".src = " + "'" + base64 + "';" + this._uid + ".width+'_'+" + this._uid + ".height");
- rdp(function (err, res) {
- if (err && img.onerror)
- return img.onerror(err);
+var ImagePDM = {
+
+ // private properties
+ _uid: {
+ enumerable: DEBUG,
+ value: ''
+ },
+ _remote: {
+ enumerable: DEBUG,
+ set: function (null_) {
+ if (null_ === null) {
+ rdp(`${this._uid} = null`);
+ Object.defineProperty(this, '_uid', { value: null });
+ } else
+ logger.error('"_remote" can only be set to "null"')
+ }
+ },
+
+ // Properties
+ src_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: ''
+ },
+ width_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: undefined
+ },
+ height_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: undefined
+ },
+ _base64_: {
+ enumerable: DEBUG,
+ writable: true,
+ value: null
+ },
+ _base64: {
+ enumerable: DEBUG,
+ get: function () {
+ return this._base64_;
+ },
+ set: function (base64) {
+ rdp(`${this._uid}.src = '${base64}'`);
+ rdp(() => {
+ rdp(`${this._uid}.width + '_' + ${this._uid}.height`);
+ rdp((err, res) => {
+ if (err && this.onerror)
+ return this.onerror(err);
var size = res.value.split('_');
- img.width_ = +size[0];
- img.height_ = +size[1];
+ this.width_ = +size[0];
+ this.height_ = +size[1];
- if (img.onload)
- return img.onload(img);
+ if (this.onload)
+ return this.onload(this);
});
+ });
- this._base64_ = base64;
- return this._base64_;
- }
- },
+ this._base64_ = base64;
+ return this._base64_;
+ }
+ },
- // Methods
- _toFile: {
- enumerable: DEBUG,
- value: function (filename, callback) {
- var head = regExp_type.exec(this._base64_),
- type = filename.split('.').pop();
+ // Methods
+ _toFile: {
+ enumerable: DEBUG,
+ value: function (filename, callback) {
+ var head = regExp_type.exec(this._base64_),
+ type = filename.split('.').pop();
- if (!head || !head[1] || (head[1] != ((type == "jpg") ? "jpeg" : type)))
- if (callback) return callback("type mismatch " + (head ? head[1] : "'unknown'") + " !> " + type);
- else throw new Error("type mismatch " + (head ? head[1] : "'unknown'") + " !> " + type)
+ if (!head || !head[1] || (head[1] != ((type == "jpg") ? "jpeg" : type)))
+ if (callback) return callback(`type mismatch ${head ? head[1] : "'unknown'"} !> ${type}`);
+ else throw new Error(`type mismatch ${head ? head[1] : "'unknown'"} !> ${type}`)
- NCC.log('[ncc] writing image to: ' + filename, 2);
- fs.writeFile(filename, new Buffer(this._base64_.replace(/^data:image\/\w+;base64,/, ""), 'base64'), {}, callback);
- }
- },
+ logger.info(`[ncc] writing image to: ${filename}`);
+ fs.writeFile(filename, new Buffer(this._base64_.replace(/^data:image\/\w+;base64,/, ''), 'base64'), {}, callback);
+ }
+ },
+
+ // Web API
+
+ // Properties
+ src: {
+ enumerable: true,
+ get: function () {
+ return this.src_;
+ },
+ set: function (src) {
+ var img = this;
+ this._src = src;
+ if (!src || src === '') return;
+
+ if (regExp_data.test(src)) img._base64 = src;
+ else if (regExp_http.test(src)) {
+ logger.info(`[ncc] loading image from URL: ${src}`);
+ http.get(src, function (res) {
+ var data = '';
+ res.setEncoding('base64');
+
+ if (res.statusCode != 200) {
+ if (img.onerror) return img.onerror(`loading image failed with status ${res.statusCode}`);
+ else logger.error(`loading image failed with status ${res.statusCode}`);
+ }
- // Web API
+ res.on('data', function (chunk) { data += chunk; });
- // Properties
- src: {
- enumerable: true,
- get: function () {
- return this.src_;
- },
- set: function (src) {
- var img = this;
- this._src = src;
- if (!src || src === "") return;
-
- if (regExp_data.test(src)) img._base64 = src;
- else if (regExp_http.test(src)) {
- NCC.log('[ncc] loading image from URL: ' + src, 2);
- http.get(src, function (res) {
- var data = '';
- res.setEncoding('base64');
-
- if (res.statusCode != 200) {
- if (img.onerror) return img.onerror("loading image failed with status " + res.statusCode);
- else throw new Error("loading image failed with status " + res.statusCode);
- }
-
- res.on('data', function (chunk) { data += chunk; });
-
- res.on('end', function () {
- img._base64 = "data:" + (res.headers["content-type"] || mimeMap[src.split('.').pop()]) + ";base64," + data;
- NCC.log('[ncc] loading image from URL completed', 2);
- });
-
- }).on('error', this.onerror || function (err) {
- if (img.onerror) return img.onerror(err);
- else throw err;
- });
- } else {
- NCC.log('[ncc] loading image from FS: ' + src, 2);
- fs.readFile(src, 'base64', function (err, data) {
- if (err) {
- if (img.onerror) img.onerror(err);
- else throw err;
- }
- img._base64 = "data:" + mimeMap[src.split('.').pop()] + ";base64," + data;
- NCC.log('[ncc] loading image from FS completed', 2);
+ res.on('end', function () {
+ img._base64 = `data:${(res.headers["content-type"] || mimeMap[src.split('.').pop()])};base64,${data}`;
+ logger.info('[ncc] loading image from URL completed');
});
- }
- return this.src_;
- }
- },
- onload: {
- writable:true,
- enumerable: true,
- value: undefined
- },
- onerror: {
- writable: true,
- enumerable: true,
- value: undefined
- },
- width: {
- enumerable: true,
- get: function () {
- return this.width_;
- }
- },
- height: {
- enumerable: true,
- get: function () {
- return this.height_;
+
+ }).on('error', this.onerror || function (err) {
+ if (img.onerror) return img.onerror(err);
+ else logger.error(`loading image failed with err ${err}`);
+ });
+ } else {
+ logger.info(`[ncc] loading image from FS: ${src}`);
+ fs.readFile(src, 'base64', function (err, data) {
+ if (err) {
+ if (img.onerror) img.onerror(err);
+ else logger.error(`loading image failed with err ${err}`);
+ }
+ img._base64 = `data:${mimeMap[src.split('.').pop()]};base64,${data}`;
+ logger.info('[ncc] loading image from FS completed');
+ });
}
+ return this.src_;
+ }
+ },
+ onload: {
+ writable: true,
+ enumerable: true,
+ value: undefined
+ },
+ onerror: {
+ writable: true,
+ enumerable: true,
+ value: undefined
+ },
+ width: {
+ enumerable: true,
+ get: function () {
+ return this.width_;
+ }
+ },
+ height: {
+ enumerable: true,
+ get: function () {
+ return this.height_;
}
-
}
-})()
+
+};
module.exports = NCC;
\ No newline at end of file
diff --git a/package.json b/package.json
index 6ac8b65..b33b2df 100644
--- a/package.json
+++ b/package.json
@@ -1,28 +1,44 @@
{
- "author": "Stefan Keim (indus) <42o8o1oo@googlemail.com>",
+ "author": "Stefan Keim (indus)",
"name": "ncc",
- "description": "node-chrome-canvas || a simple to use and performant HTML5 canvas for Node.js",
+ "description": "node-chrome-canvas | a simple to use and performant HTML5 canvas for Node.js",
"version": "0.2.0",
- "keywords": [
- "canvas",
- "chrome",
- "draw",
- "image",
- "images",
- "graphic",
- "graphics",
- "gif",
- "png",
- "webp",
- "jpg",
- "jpeg"
- ],
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "dev": "run-p dev:*",
+ "dev:tsc_lib": "tsc -w --target ES6 --outfile lib/ncc.js lib/ncc.ts",
+ "dev:run": "nodemon index.js"
+ },
+ "dependencies": {
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.6.1",
+ "tracer": "^0.8.7",
+ "ws": "^2.3.1"
+ },
+ "devDependencies": {
+ "@types/node": "^7.0.18"
+ },
"repository": {
"type": "git",
"url": "git://github.com/indus/ncc.git"
},
- "dependencies": {
- "ws": "0.4.x"
+ "bugs": {
+ "url": "https://github.com/indus/ncc2/issues"
},
- "license":"MIT"
+ "keywords": [
+ "canvas",
+ "chrome",
+ "draw",
+ "image",
+ "images",
+ "graphic",
+ "graphics",
+ "gif",
+ "png",
+ "webp",
+ "jpg",
+ "jpeg"
+ ],
+ "homepage": "https://github.com/indus/ncc2#readme",
+ "license": "MIT"
}