├── .gitignore ├── logo.jpg ├── .npmignore ├── babel.config.js ├── examples ├── generate_chart_url.js ├── download_chart_as_image.js ├── download_chart_as_buffer.js ├── enterprise_sign_chart.js └── download_chart_as_data_uri.js ├── .editorconfig ├── package.json ├── types.d.ts ├── lib.js ├── test.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .env 4 | *.log 5 | .jest_cache 6 | -------------------------------------------------------------------------------- /logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/image-charts/chartjs-image-javascript/HEAD/logo.jpg -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test.js 2 | __snapshots__ 3 | node_modules 4 | coverage 5 | .env 6 | *.log 7 | babel.config.js 8 | .jest_cache 9 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | node: 'current' 8 | }, 9 | }, 10 | ], 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /examples/generate_chart_url.js: -------------------------------------------------------------------------------- 1 | // import ChartJSImage from 'chart.js-image'; 2 | const ChartJSImage = require('..'); 3 | 4 | const chart_url = ChartJSImage() 5 | .chart({ 6 | type: 'bar', 7 | data: { labels: ['Hello world', 'Foo bar'], datasets: [{ label: 'Foo', data: [1, 2] }] }, 8 | }) // vertical bar chart 9 | .width(300) // 300px 10 | .height(300) // 300px 11 | .toURL(); // get the generated URL 12 | 13 | console.log(chart_url); // https://image-charts.com/chart?cht=bvg&chs=300x300&chd=a%3A60%2C40 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://editorconfig.org/ 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending for every file 7 | # Indent with 4 spaces 8 | [*] 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chart.js-image", 3 | "version": "6.1.3", 4 | "description": "Render Chart.JS as Image (or URL of Image)", 5 | "main": "lib.js", 6 | "types": "types.d.ts", 7 | "scripts": { 8 | "test": "jest --coverage ./test.js", 9 | "@comment updr": "-r basic : Uses console.log for output, no need for a TTY (e.g when running on CI) => https://www.npmjs.com/package/updtr#--reporter--r", 10 | "updtr": "updtr -r basic" 11 | }, 12 | "engines": { 13 | "node": ">12" 14 | }, 15 | "jest": { 16 | "verbose": true, 17 | "cacheDirectory": ".jest_cache", 18 | "testEnvironment": "node", 19 | "testTimeout": 5000, 20 | "coverageDirectory": "coverage", 21 | "moduleFileExtensions": [ 22 | "js", 23 | "json" 24 | ], 25 | "modulePaths": [ 26 | "/src/" 27 | ], 28 | "reporters": [ 29 | "default", 30 | [ 31 | "jest-junit", 32 | { 33 | "outputDirectory": "coverage", 34 | "outputName": "junit.xml" 35 | } 36 | ] 37 | ], 38 | "coverageThreshold": { 39 | "global": { 40 | "branches": 89, 41 | "functions": 95, 42 | "lines": 100, 43 | "statements": 98 44 | } 45 | } 46 | }, 47 | "author": "Francois-Guillaume Ribreau (http://fgribreau.com/)", 48 | "license": "MIT", 49 | "dependencies": { 50 | "node-fetch": "2.6.0", 51 | "javascript-stringify": "2.0.1" 52 | }, 53 | "devDependencies": { 54 | "updtr": "3.1.0", 55 | "jest": "26.0.1", 56 | "babel-jest": "26.0.1", 57 | "@babel/preset-env": "7.9.6", 58 | "npm-release": "^1.0.0", 59 | "jest-junit": "10.0.0" 60 | }, 61 | "repository": { 62 | "type": "git", 63 | "url": "git+ssh://git@github.com/image-charts/.git" 64 | }, 65 | "keywords": [ 66 | "chart.js", 67 | "charts", 68 | "chart url", 69 | "image", 70 | "imagecharts", 71 | "png", 72 | "jpg", 73 | "jpeg", 74 | "gif", 75 | "animated", 76 | "api", 77 | "pie", 78 | "bar", 79 | "horizontal-bar", 80 | "bubble", 81 | "doughnut", 82 | "line", 83 | "polar" 84 | ], 85 | "bugs": { 86 | "url": "https://github.com/image-charts//issues" 87 | }, 88 | "homepage": "https://github.com/image-charts/#readme", 89 | "contributors": [] 90 | } 91 | -------------------------------------------------------------------------------- /examples/download_chart_as_image.js: -------------------------------------------------------------------------------- 1 | //import ChartJSImage from 'chart.js-image'; 2 | const ChartJSImage = require('..'); 3 | 4 | const chart_path = '/tmp/chart.png'; 5 | 6 | ChartJSImage() 7 | .chart({ 8 | "type": "radar", 9 | "data": { 10 | "labels": [ 11 | "January", 12 | "February", 13 | "March", 14 | "April", 15 | "May", 16 | "June", 17 | "July", 18 | "August" 19 | ], 20 | "datasets": [ 21 | { 22 | "backgroundColor": "rgba(255, 99, 132, 0.5)", 23 | "borderColor": "rgb(255, 99, 132)", 24 | "data": [ 25 | 15.09, 26 | 15.67, 27 | 12.5, 28 | 12.77, 29 | 13.62, 30 | 13.68, 31 | 13.93, 32 | 15.95 33 | ], 34 | "label": "D0" 35 | }, 36 | { 37 | "backgroundColor": "rgba(255, 159, 64, 0.5)", 38 | "borderColor": "rgb(255, 159, 64)", 39 | "data": [ 40 | 24.55, 41 | 28.91, 42 | 21.81, 43 | 23.27, 44 | 26.98, 45 | 26.05, 46 | 25.39, 47 | 24.92 48 | ], 49 | "label": "D1", 50 | "fill": "-1" 51 | }, 52 | { 53 | "backgroundColor": "rgba(255, 205, 86, 0.5)", 54 | "borderColor": "rgb(255, 205, 86)", 55 | "data": [ 56 | 36.35, 57 | 43.93, 58 | 32.54, 59 | 33.54, 60 | 42.82, 61 | 39.34, 62 | 35.84, 63 | 33.5 64 | ], 65 | "label": "D2", 66 | "fill": 1 67 | }, 68 | { 69 | "backgroundColor": "rgba(75, 192, 192, 0.5)", 70 | "borderColor": "rgb(75, 192, 192)", 71 | "data": [ 72 | 47.7, 73 | 58.92, 74 | 44.45, 75 | 49.08, 76 | 53.39, 77 | 51.85, 78 | 48.4, 79 | 49.36 80 | ], 81 | "label": "D3", 82 | "fill": false 83 | }, 84 | { 85 | "backgroundColor": "rgba(54, 162, 235, 0.5)", 86 | "borderColor": "rgb(54, 162, 235)", 87 | "data": [ 88 | 60.73, 89 | 71.97, 90 | 53.96, 91 | 57.22, 92 | 65.09, 93 | 62.06, 94 | 56.91, 95 | 60.52 96 | ], 97 | "label": "D4", 98 | "fill": "-1" 99 | }, 100 | { 101 | "backgroundColor": "rgba(153, 102, 255, 0.5)", 102 | "borderColor": "rgb(153, 102, 255)", 103 | "data": [ 104 | 73.33, 105 | 80.78, 106 | 68.05, 107 | 68.59, 108 | 76.79, 109 | 77.24, 110 | 66.08, 111 | 72.37 112 | ], 113 | "label": "D5", 114 | "fill": "-1" 115 | } 116 | ] 117 | }, 118 | "options": { 119 | "maintainAspectRatio": true, 120 | "spanGaps": false, 121 | "elements": { 122 | "line": { 123 | "tension": 0.000001 124 | } 125 | }, 126 | "plugins": { 127 | "filler": { 128 | "propagate": false 129 | }, 130 | "samples-filler-analyser": { 131 | "target": "chart-analyser" 132 | } 133 | } 134 | } 135 | }) 136 | .bkg('white') 137 | .width(700) 138 | .height(390) 139 | .toFile(chart_path) 140 | .then(() => console.log('Image chart written at %s', chart_path)) 141 | 142 | 143 | -------------------------------------------------------------------------------- /examples/download_chart_as_buffer.js: -------------------------------------------------------------------------------- 1 | //import ChartJSImage from 'chart.js-image'; 2 | const ChartJSImage = require('..'); 3 | 4 | const buffer = ChartJSImage() 5 | .chart({ 6 | "type": "radar", 7 | "data": { 8 | "labels": [ 9 | "January", 10 | "February", 11 | "March", 12 | "April", 13 | "May", 14 | "June", 15 | "July", 16 | "August" 17 | ], 18 | "datasets": [ 19 | { 20 | "backgroundColor": "rgba(255, 99, 132, 0.5)", 21 | "borderColor": "rgb(255, 99, 132)", 22 | "data": [ 23 | 15.09, 24 | 15.67, 25 | 12.5, 26 | 12.77, 27 | 13.62, 28 | 13.68, 29 | 13.93, 30 | 15.95 31 | ], 32 | "label": "D0" 33 | }, 34 | { 35 | "backgroundColor": "rgba(255, 159, 64, 0.5)", 36 | "borderColor": "rgb(255, 159, 64)", 37 | "data": [ 38 | 24.55, 39 | 28.91, 40 | 21.81, 41 | 23.27, 42 | 26.98, 43 | 26.05, 44 | 25.39, 45 | 24.92 46 | ], 47 | "label": "D1", 48 | "fill": "-1" 49 | }, 50 | { 51 | "backgroundColor": "rgba(255, 205, 86, 0.5)", 52 | "borderColor": "rgb(255, 205, 86)", 53 | "data": [ 54 | 36.35, 55 | 43.93, 56 | 32.54, 57 | 33.54, 58 | 42.82, 59 | 39.34, 60 | 35.84, 61 | 33.5 62 | ], 63 | "label": "D2", 64 | "fill": 1 65 | }, 66 | { 67 | "backgroundColor": "rgba(75, 192, 192, 0.5)", 68 | "borderColor": "rgb(75, 192, 192)", 69 | "data": [ 70 | 47.7, 71 | 58.92, 72 | 44.45, 73 | 49.08, 74 | 53.39, 75 | 51.85, 76 | 48.4, 77 | 49.36 78 | ], 79 | "label": "D3", 80 | "fill": false 81 | }, 82 | { 83 | "backgroundColor": "rgba(54, 162, 235, 0.5)", 84 | "borderColor": "rgb(54, 162, 235)", 85 | "data": [ 86 | 60.73, 87 | 71.97, 88 | 53.96, 89 | 57.22, 90 | 65.09, 91 | 62.06, 92 | 56.91, 93 | 60.52 94 | ], 95 | "label": "D4", 96 | "fill": "-1" 97 | }, 98 | { 99 | "backgroundColor": "rgba(153, 102, 255, 0.5)", 100 | "borderColor": "rgb(153, 102, 255)", 101 | "data": [ 102 | 73.33, 103 | 80.78, 104 | 68.05, 105 | 68.59, 106 | 76.79, 107 | 77.24, 108 | 66.08, 109 | 72.37 110 | ], 111 | "label": "D5", 112 | "fill": "-1" 113 | } 114 | ] 115 | }, 116 | "options": { 117 | "maintainAspectRatio": true, 118 | "spanGaps": false, 119 | "elements": { 120 | "line": { 121 | "tension": 0.000001 122 | } 123 | }, 124 | "plugins": { 125 | "filler": { 126 | "propagate": false 127 | }, 128 | "samples-filler-analyser": { 129 | "target": "chart-analyser" 130 | } 131 | } 132 | } 133 | }) 134 | .bkg('white') 135 | .width(700) 136 | .height(390) 137 | .toBuffer() // download chart image as a buffer 138 | .then((buffer) => console.log(buffer)) // console.log(chart_url)); // "data:image/png;base64,iVBORw0KGgoAAAANSUhE"UgAABXgAAAMMCAIAAABmCliNAAHJnElEQVR42uzdeXjc1X3v8e/sq8baF2uXvMkbBmxibMALmN0FGiCBJpT0Ccnl0qRNnockT3vbOuT2Xkpzcxty0yZtnoQCqdliCKaktpEBG2+xkRfJlmzZsiXLlrWPRpp9u38c+DEZybYsy/KM9H794Uf6+aefRufMdj5zzvfo4vG4AAAAAAAAjAc9TQAAAAAAAMYLQQMAAAAAABPhyJEjf/RHf+T1elPkF12h20PQAAAAAADARCgvL1+3bp3Vap3cf6aRngYAAAAAYAK0trauW7fub/7mb37wgx8kHs/KynruuecKCgreeOONF198UR187bXXduzY8eMf/1j79p133lH/u27duuuuuy7p4q+//vpLL70kIn/7t39rt9tF5JFHHjnflVtbW7/zne988YtfVKd9//vfr6ysfPzxx2OxmDpBpSGJ11y8eLF2ERWXfO973xvxryBoAAAAAABgon3ve9/r6ur65S9/+Vd/9Vfnzp174okn1q1b9+KLL2rHjxw58uMf//hrX/taJBJR37744ot/+Zd/2d3dvW7dutdeey3xai0tLS+99JL62WeeeWbdunXarxjxyuvWrfve975nMBjUaaFQ6LHHHvvLv/xLm81msVjMZrNaWJF0Te0i69atS/wViX/Fa6+9RtAAAAAAAMBEu+aaa1pbW0Vk0aJFLS0tw48rc+bMCYVC2rf/9E//VFpa+vOf/9xisdx3333a8WeffVb9rMFgmD9/fjAYHH6p8317zTXX6HS6u+6665/+6Z8qKyu1ORTaaaO5ZuJfQdAAAAAAAEB6WLduXWZmZlFRkRYuJLFYLCUlJYnJxWjY7fYnn3xy5cqVp06d2r1799KlSy/nmhSDBAAAAAAgVRw8ePDYsWPat01NTYnfBgIBt9tdV1cXi8XmJtB+9re//e3DDz8cCAQueuXE4x0dHXV1dX6/PxgM/q//9b96enrq6uqi0ejwa57vIomY0QAAAAAAwNU3d+7ct99++/7771cVGdW3Tz755JkzZ4b/r1avMelny8vL33777SNHjl 139 | -------------------------------------------------------------------------------- /types.d.ts: -------------------------------------------------------------------------------- 1 | export default class ChartJSImage { 2 | constructor(options?: { 3 | timeout?: number; 4 | secret?: string; 5 | host?: string; 6 | protocol?: string; 7 | port?: number; 8 | pathname?: string; 9 | }) 10 | 11 | 12 | /** 13 | * Javascript/JSON definition of the chart. Use a Chart.js configuration object. 14 | * [Reference documentation]{@link } 15 | * @example 16 | * const chart = ImageCharts().c("{type:'bar',data:{labels:['Q1','Q2','Q3','Q4'],datasets:[{label:'Users',data:[50,60,70,180]},{label:'Revenue',data:[100,200,300,400]}]}}"); 17 | * 18 | * @param {string} value - Javascript/JSON definition of the chart. Use a Chart.js configuration object. 19 | * @return {ImageCharts.constructor} 20 | */ 21 | c(value: string): this; 22 | 23 | /** 24 | * Javascript/JSON definition of the chart. Use a Chart.js configuration object. 25 | * [Reference documentation]{@link } 26 | * @example 27 | * const chart = ImageCharts().chart("{type:'bar',data:{labels:['Q1','Q2','Q3','Q4'],datasets:[{label:'Users',data:[50,60,70,180]},{label:'Revenue',data:[100,200,300,400]}]}}"); 28 | * 29 | * @param {string} value - Javascript/JSON definition of the chart. Use a Chart.js configuration object. 30 | * @return {ImageCharts.constructor} 31 | */ 32 | chart(value: string): this; 33 | 34 | /** 35 | * Width of the chart 36 | * [Reference documentation]{@link } 37 | * @example 38 | * const chart = ImageCharts().width("400"); 39 | * @default "500" 40 | * @param {integer} value - Width of the chart 41 | * @return {ImageCharts.constructor} 42 | */ 43 | width(value: string): this; 44 | 45 | /** 46 | * Height of the chart 47 | * [Reference documentation]{@link } 48 | * @example 49 | * const chart = ImageCharts().height("300"); 50 | * @default "300" 51 | * @param {integer} value - Height of the chart 52 | * @return {ImageCharts.constructor} 53 | */ 54 | height(value: string): this; 55 | 56 | /** 57 | * Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 58 | * [Reference documentation]{@link } 59 | * @example 60 | * const chart = ImageCharts().backgroundColor("black"); 61 | * const chart = ImageCharts().backgroundColor("rgb(255,255,120)"); 62 | * const chart = ImageCharts().backgroundColor("%23ff00ff"); 63 | * 64 | * @param {string} value - Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 65 | * @return {ImageCharts.constructor} 66 | */ 67 | backgroundColor(value: string): this; 68 | 69 | /** 70 | * Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 71 | * [Reference documentation]{@link } 72 | * @example 73 | * const chart = ImageCharts().bkg("black"); 74 | * const chart = ImageCharts().bkg("rgb(255,255,120)"); 75 | * const chart = ImageCharts().bkg("%23ff00ff"); 76 | * 77 | * @param {string} value - Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 78 | * @return {ImageCharts.constructor} 79 | */ 80 | bkg(value: string): this; 81 | 82 | /** 83 | * Encoding of your "chart" parameter. Accepted values are url and base64. 84 | * [Reference documentation]{@link } 85 | * @example 86 | * const chart = ImageCharts().encoding("url"); 87 | * const chart = ImageCharts().encoding("base64"); 88 | * @default "url" 89 | * @param {string} value - Encoding of your "chart" parameter. Accepted values are url and base64. 90 | * @return {ImageCharts.constructor} 91 | */ 92 | encoding(value: string): this; 93 | 94 | /** 95 | * image-charts enterprise `account_id` 96 | * [Reference documentation]{@link https://documentation.image-charts.com/enterprise/} 97 | * @example 98 | * const chart = ImageCharts().icac("accountId"); 99 | * 100 | * @param {string} value - image-charts enterprise `account_id` 101 | * @return {ImageCharts.constructor} 102 | */ 103 | icac(value: string): this; 104 | 105 | /** 106 | * HMAC-SHA256 signature required to activate paid features 107 | * [Reference documentation]{@link https://documentation.image-charts.com/enterprise/} 108 | * @example 109 | * const chart = ImageCharts().ichm("0785cf22a0381c2e0239e27c126de4181f501d117c2c81745611e9db928b0376"); 110 | * 111 | * @param {string} value - HMAC-SHA256 signature required to activate paid features 112 | * @return {ImageCharts.constructor} 113 | */ 114 | ichm(value: string): this; 115 | 116 | /** 117 | * Retina is a marketing term coined by Apple that refers to devices and monitors that have a resolution and pixel density so high — roughly 300 or more pixels per inch – that a person is unable to discern the individual pixels at a normal viewing distance. 118 | * In order to generate beautiful charts for these Retina displays, Image-Charts supports a retina mode that can be activated through the icretina=1 parameter 119 | * [Reference documentation]{@link https://documentation.image-charts.com/reference/retina/} 120 | * @example 121 | * const chart = ImageCharts().icretina("1"); 122 | * 123 | * @param {string} value - retina mode 124 | * @return {ImageCharts.constructor} 125 | */ 126 | icretina(value: string): this; 127 | 128 | 129 | /** 130 | * Get the full Image-Charts API url (signed and encoded if necessary) 131 | * @return full generated url 132 | */ 133 | toURL(): string; 134 | 135 | /** 136 | * Do a request to Image-Charts API with current configuration and yield a promise of a NodeJS buffer 137 | * @return binary image represented as a NodeJS Buffer wrapped inside a promise 138 | */ 139 | toBuffer(): Promise; 140 | 141 | /** 142 | * Do a request to Image-Charts API with current configuration and yield a promise of a base64 encoded data URI 143 | * @return base64 data URI wrapped inside a promise 144 | */ 145 | toDataURI(): Promise; 146 | } 147 | -------------------------------------------------------------------------------- /lib.js: -------------------------------------------------------------------------------- 1 | const qs = require('querystring'); 2 | const crypto = require('crypto'); 3 | const fs = require('fs'); 4 | const fetch = require('node-fetch'); 5 | const packageJson = require('./package.json'); 6 | const { stringify } = require('javascript-stringify'); 7 | 8 | /* 9 | * ChartJSImage URL builder 10 | * @typedef ChartJSImage 11 | */ 12 | function ChartJSImage({secret, protocol, host, port, timeout} = {}, previous = {}) { 13 | if (!(this instanceof ChartJSImage)) { 14 | return new ChartJSImage({secret, protocol, host, port, timeout}, previous); 15 | } 16 | this._protocol = protocol || 'https'; 17 | this._host = host || 'image-charts.com'; 18 | this._port = port || 443; 19 | this._pathname = '/chart.js/2.8.0'; 20 | this._timeout = typeof timeout !== 'undefined' ? timeout : 5000; 21 | this._query = {}; 22 | this._secret = secret; 23 | Object.assign(this, previous); 24 | } 25 | 26 | ChartJSImage.prototype._clone = function (param, value) { 27 | return new this.constructor({}, { 28 | ...this, 29 | _query:{ 30 | ...this._query, 31 | [param]: value 32 | } 33 | }); 34 | }; 35 | 36 | 37 | /** 38 | * Javascript/JSON definition of the chart. Use a Chart.js configuration object. 39 | * [Reference documentation]{@link } 40 | * @example 41 | * const chart = ChartJSImage().c("{type:'bar',data:{labels:['Q1','Q2','Q3','Q4'],datasets:[{label:'Users',data:[50,60,70,180]},{label:'Revenue',data:[100,200,300,400]}]}}"); 42 | * 43 | * @param {string} value - Javascript/JSON definition of the chart. Use a Chart.js configuration object. 44 | * @return {ChartJSImage.constructor} 45 | */ 46 | ChartJSImage.prototype.c = function(value) { 47 | return this._clone('c', stringify(value)); 48 | }; 49 | 50 | /** 51 | * Javascript/JSON definition of the chart. Use a Chart.js configuration object. 52 | * [Reference documentation]{@link } 53 | * @example 54 | * const chart = ChartJSImage().chart("{type:'bar',data:{labels:['Q1','Q2','Q3','Q4'],datasets:[{label:'Users',data:[50,60,70,180]},{label:'Revenue',data:[100,200,300,400]}]}}"); 55 | * 56 | * @param {string} value - Javascript/JSON definition of the chart. Use a Chart.js configuration object. 57 | * @return {ChartJSImage.constructor} 58 | */ 59 | ChartJSImage.prototype.chart = function(value) { 60 | return this._clone('chart', stringify(value)); 61 | }; 62 | 63 | /** 64 | * Width of the chart 65 | * [Reference documentation]{@link } 66 | * @example 67 | * const chart = ChartJSImage().width("400"); 68 | * @default "500" 69 | * @param {integer} value - Width of the chart 70 | * @return {ChartJSImage.constructor} 71 | */ 72 | ChartJSImage.prototype.width = function(value) { 73 | return this._clone('width', value); 74 | }; 75 | 76 | /** 77 | * Height of the chart 78 | * [Reference documentation]{@link } 79 | * @example 80 | * const chart = ChartJSImage().height("300"); 81 | * @default "300" 82 | * @param {integer} value - Height of the chart 83 | * @return {ChartJSImage.constructor} 84 | */ 85 | ChartJSImage.prototype.height = function(value) { 86 | return this._clone('height', value); 87 | }; 88 | 89 | /** 90 | * Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 91 | * [Reference documentation]{@link } 92 | * @example 93 | * const chart = ChartJSImage().backgroundColor("black"); 94 | * const chart = ChartJSImage().backgroundColor("rgb(255,255,120)"); 95 | * const chart = ChartJSImage().backgroundColor("%23ff00ff"); 96 | * 97 | * @param {string} value - Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 98 | * @return {ChartJSImage.constructor} 99 | */ 100 | ChartJSImage.prototype.backgroundColor = function(value) { 101 | return this._clone('backgroundColor', value); 102 | }; 103 | 104 | /** 105 | * Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 106 | * [Reference documentation]{@link } 107 | * @example 108 | * const chart = ChartJSImage().bkg("black"); 109 | * const chart = ChartJSImage().bkg("rgb(255,255,120)"); 110 | * const chart = ChartJSImage().bkg("%23ff00ff"); 111 | * 112 | * @param {string} value - Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 113 | * @return {ChartJSImage.constructor} 114 | */ 115 | ChartJSImage.prototype.bkg = function(value) { 116 | return this._clone('bkg', value); 117 | }; 118 | 119 | /** 120 | * Encoding of your "chart" parameter. Accepted values are url and base64. 121 | * [Reference documentation]{@link } 122 | * @example 123 | * const chart = ChartJSImage().encoding("url"); 124 | * const chart = ChartJSImage().encoding("base64"); 125 | * @default "url" 126 | * @param {string} value - Encoding of your "chart" parameter. Accepted values are url and base64. 127 | * @return {ChartJSImage.constructor} 128 | */ 129 | ChartJSImage.prototype.encoding = function(value) { 130 | return this._clone('encoding', value); 131 | }; 132 | 133 | /** 134 | * image-charts enterprise `account_id` 135 | * [Reference documentation]{@link https://documentation.image-charts.com/enterprise/} 136 | * @example 137 | * const chart = ChartJSImage().icac("accountId"); 138 | * 139 | * @param {string} value - image-charts enterprise `account_id` 140 | * @return {ChartJSImage.constructor} 141 | */ 142 | ChartJSImage.prototype.icac = function(value) { 143 | return this._clone('icac', value); 144 | }; 145 | 146 | /** 147 | * HMAC-SHA256 signature required to activate paid features 148 | * [Reference documentation]{@link https://documentation.image-charts.com/enterprise/} 149 | * @example 150 | * const chart = ChartJSImage().ichm("0785cf22a0381c2e0239e27c126de4181f501d117c2c81745611e9db928b0376"); 151 | * 152 | * @param {string} value - HMAC-SHA256 signature required to activate paid features 153 | * @return {ChartJSImage.constructor} 154 | */ 155 | ChartJSImage.prototype.ichm = function(value) { 156 | return this._clone('ichm', value); 157 | }; 158 | 159 | /** 160 | * Retina is a marketing term coined by Apple that refers to devices and monitors that have a resolution and pixel density so high — roughly 300 or more pixels per inch – that a person is unable to discern the individual pixels at a normal viewing distance. 161 | * In order to generate beautiful charts for these Retina displays, Image-Charts supports a retina mode that can be activated through the icretina=1 parameter 162 | * [Reference documentation]{@link https://documentation.image-charts.com/reference/retina/} 163 | * @example 164 | * const chart = ChartJSImage().icretina("1"); 165 | * 166 | * @param {string} value - retina mode 167 | * @return {ChartJSImage.constructor} 168 | */ 169 | ChartJSImage.prototype.icretina = function(value) { 170 | return this._clone('icretina', value); 171 | }; 172 | 173 | 174 | /** 175 | * Get the full ChartJSImage API url (signed and encoded if necessary) 176 | * @return {string} full generated url 177 | */ 178 | ChartJSImage.prototype.toURL = function () { 179 | const url = new URL(`${this._protocol}://${this._host}`); 180 | 181 | /* istanbul ignore else */ 182 | if(this._port) {url.port = this._port} 183 | 184 | url.pathname = this._pathname; 185 | 186 | const searchParams = new URLSearchParams(this._query); 187 | 188 | if (this._query.icac && this._secret && this._secret.length) { 189 | searchParams.append('ichm', crypto.createHmac('sha256', this._secret).update(searchParams.toString()).digest('hex')); 190 | } 191 | 192 | url.search = searchParams.toString(); 193 | 194 | return url.toString(); 195 | }; 196 | 197 | /** 198 | * Do a request to ChartJSImage API with current configuration and yield a promise of a NodeJS buffer 199 | * @return {Promise} binary image represented as a NodeJS Buffer wrapped inside a promise 200 | */ 201 | ChartJSImage.prototype.toBuffer = function () { 202 | const _options = { 203 | timeout: this._timeout, 204 | headers: { 'User-Agent': `javascript-chart.js-image/${packageJson.version}` + (this._query.icac ? ' ' + `(${this._query.icac})` : '') } 205 | }; 206 | return fetch(this.toURL(), _options).then(res => { 207 | return res.buffer().then(buff => { 208 | if(res.status >= 200 && res.status < 300){ 209 | buff._response = res; 210 | buff._request = _options; 211 | return buff; 212 | } 213 | 214 | const validation_message = res.headers.get('x-ic-error-validation'); 215 | const validation_code = res.headers.get('x-ic-error-code'); 216 | let message = validation_message ? JSON.parse(validation_message).map(x => x.message).join('\n').trim() : ''; 217 | /* istanbul ignore next */ 218 | message = message.length > 0 || !validation_code ? message : validation_code; 219 | /* istanbul ignore next */ 220 | message = message.length > 0 ? message : res.statusText; 221 | const err = new Error(message); 222 | /* istanbul ignore next */ 223 | err.code = validation_code || res.statusText; 224 | err.statusCode = res.statusCode; 225 | err._response = res; 226 | err._request = _options; 227 | return Promise.reject(err); 228 | }); 229 | }) 230 | }; 231 | 232 | /** 233 | * Do a request to ChartJSImage API with current configuration and writes the content inside a file 234 | * @return {Promise} 235 | */ 236 | ChartJSImage.prototype.toFile = function (file) { 237 | return this.toBuffer().then(buffer => 238 | new Promise((resolve, reject) => 239 | fs.writeFile(file, buffer, (err) => err ? reject(err) : resolve()))) 240 | }; 241 | 242 | /** 243 | * Do a request to ChartJSImageAPI with current configuration and yield a promise of a base64 encoded data URI 244 | * @return {Promise} base64 data URI wrapped inside a promise 245 | */ 246 | ChartJSImage.prototype.toDataURI = function () { 247 | const encoding = 'base64'; 248 | const mimetype = this._query.chan ? 'image/gif' : 'image/png'; 249 | return this.toBuffer().then(buffer => `data:${mimetype};${encoding},${buffer.toString(encoding)}`); 250 | }; 251 | 252 | module.exports = ChartJSImage; 253 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import ChartJSImage from "./"; 2 | import pkg from "./package.json"; 3 | import fs from "fs"; 4 | 5 | describe("ChartJSImage", () => { 6 | it("works in ES6", () => { 7 | expect(typeof ChartJSImage).toMatchInlineSnapshot(`"function"`); 8 | }); 9 | 10 | it("works in CommonJS", () => { 11 | expect(typeof require("./")).toMatchInlineSnapshot(`"function"`); 12 | }); 13 | 14 | describe("toURL", () => { 15 | it("works", () => { 16 | expect( 17 | ChartJSImage() 18 | .chart({ 19 | type: "bar", 20 | data: { 21 | labels: ["Hello world", "Foo bar"], 22 | datasets: [{ label: "Foo", data: [1, 2] }], 23 | }, 24 | }) 25 | .toURL() 26 | ).toMatchInlineSnapshot( 27 | `"https://image-charts.com/chart.js/2.8.0?chart=%7Btype%3A%27bar%27%2Cdata%3A%7Blabels%3A%5B%27Hello+world%27%2C%27Foo+bar%27%5D%2Cdatasets%3A%5B%7Blabel%3A%27Foo%27%2Cdata%3A%5B1%2C2%5D%7D%5D%7D%7D"` 28 | ); 29 | }); 30 | 31 | it("works port override", () => { 32 | expect( 33 | ChartJSImage({ port: 8080 }) 34 | .chart({ 35 | type: "bar", 36 | data: { 37 | labels: ["Hello world", "Foo bar"], 38 | datasets: [{ label: "Foo", data: [1, 2] }], 39 | }, 40 | }) 41 | .toURL() 42 | ).toMatchInlineSnapshot( 43 | `"https://image-charts.com:8080/chart.js/2.8.0?chart=%7Btype%3A%27bar%27%2Cdata%3A%7Blabels%3A%5B%27Hello+world%27%2C%27Foo+bar%27%5D%2Cdatasets%3A%5B%7Blabel%3A%27Foo%27%2Cdata%3A%5B1%2C2%5D%7D%5D%7D%7D"` 44 | ); 45 | }); 46 | 47 | it("exposes parameters and use them", () => { 48 | const ic = ChartJSImage(); 49 | const { chart, query } = Object.keys(ic.__proto__) 50 | .filter((method) => 51 | [ 52 | "c", 53 | "chart", 54 | "width", 55 | "height", 56 | "backgroundColor", 57 | "encoding", 58 | "bkg", 59 | "icretina", 60 | "ichm", 61 | ].includes(method) 62 | ) 63 | .reduce( 64 | (m, method_name) => { 65 | m.chart = m.chart[method_name]("plop"); 66 | m.query.push(`${method_name}=plop`); 67 | return m; 68 | }, 69 | { chart: ic, query: [] } 70 | ); 71 | 72 | expect(chart.toURL()).toMatchInlineSnapshot( 73 | `"https://image-charts.com/chart.js/2.8.0?c=%27plop%27&chart=%27plop%27&width=plop&height=plop&backgroundColor=plop&bkg=plop&encoding=plop&ichm=plop&icretina=plop"` 74 | ); 75 | }); 76 | 77 | it("adds a signature when icac and secrets are defined", () => 78 | expect( 79 | ChartJSImage({ secret: "plop" }) 80 | .chart({ 81 | type: "bar", 82 | data: { 83 | labels: ["Hello world", "Foo bar"], 84 | datasets: [{ label: "Foo", data: [1, 2] }], 85 | }, 86 | }) 87 | .icac("test_fixture") 88 | .toURL() 89 | ).toMatchInlineSnapshot( 90 | `"https://image-charts.com/chart.js/2.8.0?chart=%7Btype%3A%27bar%27%2Cdata%3A%7Blabels%3A%5B%27Hello+world%27%2C%27Foo+bar%27%5D%2Cdatasets%3A%5B%7Blabel%3A%27Foo%27%2Cdata%3A%5B1%2C2%5D%7D%5D%7D%7D&icac=test_fixture&ichm=49b0554d30517ceee5bb1fd7d5077ee6488cdef49f9574822af4ea7b4ceb136d"` 91 | )); 92 | }); 93 | 94 | describe("toBuffer", () => { 95 | it("rejects if a chs is not defined", () => 96 | expect(ChartJSImage().toBuffer()).rejects.toMatchInlineSnapshot( 97 | `[Error: "value" must contain at least one of [c, chart]]` 98 | )); 99 | 100 | it("rejects if a icac is defined without ichm", () => 101 | expect( 102 | ChartJSImage() 103 | .chart({ 104 | type: "bar", 105 | data: { 106 | labels: ["Hello world", "Foo bar"], 107 | datasets: [{ label: "Foo", data: [1, 2] }], 108 | }, 109 | }) 110 | .icac("test_fixture") 111 | .toBuffer() 112 | ).rejects.toMatchInlineSnapshot( 113 | `[Error: The \`icac\` (ACCOUNT_ID) and \`ichm\` (HMAC-SHA256 request signature) query parameters must both be defined if specified. [Learn more](https://bit.ly/HMACENT)]` 114 | )); 115 | 116 | it("rejects if timeout is reached", () => 117 | expect( 118 | ChartJSImage({ timeout: 1 }) // 1ms 119 | .chart({ 120 | type: "bar", 121 | data: { 122 | labels: ["Hello world", "Foo bar"], 123 | datasets: [{ label: "Foo", data: [1, 2] }], 124 | }, 125 | }) 126 | .toBuffer() 127 | ).rejects.toMatchInlineSnapshot( 128 | `[FetchError: network timeout at: https://image-charts.com/chart.js/2.8.0?chart=%7Btype%3A%27bar%27%2Cdata%3A%7Blabels%3A%5B%27Hello+world%27%2C%27Foo+bar%27%5D%2Cdatasets%3A%5B%7Blabel%3A%27Foo%27%2Cdata%3A%5B1%2C2%5D%7D%5D%7D%7D]` 129 | )); 130 | 131 | it("works", () => 132 | expect( 133 | ChartJSImage() 134 | .chart({ 135 | type: "bar", 136 | data: { 137 | labels: ["Hello world", "Foo bar"], 138 | datasets: [{ label: "Foo", data: [1, 2] }], 139 | }, 140 | }) 141 | .width(1) 142 | .height(1) 143 | .toBuffer() 144 | .then((buff) => buff.slice(0, 10)) 145 | ).resolves.toMatchInlineSnapshot(` 146 | Object { 147 | "data": Array [ 148 | 137, 149 | 80, 150 | 78, 151 | 71, 152 | 13, 153 | 10, 154 | 26, 155 | 10, 156 | 0, 157 | 0, 158 | ], 159 | "type": "Buffer", 160 | } 161 | `)); 162 | 163 | it("forwards package_name/version as user-agent", () => 164 | ChartJSImage() 165 | .chart({ 166 | type: "bar", 167 | data: { 168 | labels: ["Hello world", "Foo bar"], 169 | datasets: [{ label: "Foo", data: [1, 2] }], 170 | }, 171 | }) 172 | .toBuffer() 173 | .then((buff) => 174 | expect(buff._request.headers["User-Agent"]).toStrictEqual( 175 | `javascript-${pkg.name}/${pkg.version}` 176 | ) 177 | )); 178 | 179 | it("forwards package_name/version (icac) as user-agent", () => 180 | ChartJSImage() 181 | .chart({ 182 | type: "bar", 183 | data: { 184 | labels: ["Hello world", "Foo bar"], 185 | datasets: [{ label: "Foo", data: [1, 2] }], 186 | }, 187 | }) 188 | .icac("MY_ACCOUNT_ID") 189 | .toBuffer() 190 | .catch((err) => 191 | expect(err._request.headers["User-Agent"]).toStrictEqual( 192 | `javascript-${pkg.name}/${pkg.version} (MY_ACCOUNT_ID)` 193 | ) 194 | )); 195 | }); 196 | 197 | describe("toDataURI", () => { 198 | it("rejects if there was an error", () => 199 | expect(ChartJSImage().toDataURI()).rejects.toMatchInlineSnapshot( 200 | `[Error: "value" must contain at least one of [c, chart]]` 201 | )); 202 | 203 | it("works", () => 204 | expect( 205 | ChartJSImage() 206 | .chart({ 207 | type: "bar", 208 | data: { 209 | labels: ["Hello world", "Foo bar"], 210 | datasets: [{ label: "Foo", data: [1, 2] }], 211 | }, 212 | }) 213 | .width(2) 214 | .height(2) 215 | .toDataURI() 216 | .then((data_uri) => data_uri.substring(0, 40)) 217 | ).resolves.toMatchInlineSnapshot( 218 | `"data:image/png;base64,iVBORw0KGgoAAAANSU"` 219 | )); 220 | 221 | it("support gifs", () => 222 | ChartJSImage() 223 | .chart({ 224 | type: "bar", 225 | data: { 226 | labels: ["Hello world", "Foo bar"], 227 | datasets: [{ label: "Foo", data: [1, 2] }], 228 | }, 229 | }) 230 | .width(2) 231 | .height(2) 232 | .toDataURI() 233 | .then((data_uri) => 234 | expect(data_uri.substring(0, 30)).toMatchInlineSnapshot( 235 | `"data:image/png;base64,iVBORw0K"` 236 | ) 237 | )); 238 | }); 239 | 240 | describe("toFile", () => { 241 | it("rejects if there was an error", () => 242 | expect( 243 | ChartJSImage().toFile("/tmp/chart.png") 244 | ).rejects.toMatchInlineSnapshot( 245 | `[Error: "value" must contain at least one of [c, chart]]` 246 | )); 247 | 248 | it("rejects when the path is invalid", () => { 249 | const file_path = "/__invalid_path/chart.png"; 250 | return expect( 251 | ChartJSImage() 252 | .chart({ 253 | type: "bar", 254 | data: { 255 | labels: ["Hello world", "Foo bar"], 256 | datasets: [{ label: "Foo", data: [1, 2] }], 257 | }, 258 | }) 259 | .toFile(file_path) 260 | ).rejects.toBeDefined(); 261 | }); 262 | 263 | it("works", () => { 264 | const file_path = "/tmp/chart.png"; 265 | return ChartJSImage() 266 | .chart({ 267 | type: "bar", 268 | data: { 269 | labels: ["Hello world", "Foo bar"], 270 | datasets: [{ label: "Foo", data: [1, 2] }], 271 | }, 272 | }) 273 | .toFile(file_path) 274 | .then(() => expect(fs.existsSync(file_path)).toBe(true)); 275 | }); 276 | }); 277 | 278 | describe("protocol", () => { 279 | it("expose the protocol", () => { 280 | expect(ChartJSImage()._protocol).toMatchInlineSnapshot(`"https"`); 281 | }); 282 | 283 | it("let protocol to be user-defined", () => { 284 | expect( 285 | ChartJSImage({ protocol: "http" })._protocol 286 | ).toMatchInlineSnapshot(`"http"`); 287 | }); 288 | }); 289 | 290 | describe("host", () => { 291 | it("expose the host", () => { 292 | expect(ChartJSImage()._host).toMatchInlineSnapshot(`"image-charts.com"`); 293 | }); 294 | 295 | it("let host to be user-defined", () => { 296 | expect( 297 | ChartJSImage({ host: "on-premise-image-charts.com" })._host 298 | ).toMatchInlineSnapshot(`"on-premise-image-charts.com"`); 299 | }); 300 | }); 301 | 302 | describe("pathname", () => { 303 | it("expose the pathname", () => { 304 | expect(ChartJSImage()._pathname).toMatchInlineSnapshot( 305 | `"/chart.js/2.8.0"` 306 | ); 307 | }); 308 | }); 309 | 310 | describe("port", () => { 311 | it("expose the port", () => { 312 | expect(ChartJSImage()._port).toMatchInlineSnapshot(`443`); 313 | }); 314 | 315 | it("let port to be user-defined", () => { 316 | expect(ChartJSImage({ port: 8080 })._port).toMatchInlineSnapshot(`8080`); 317 | }); 318 | }); 319 | 320 | describe("query", () => { 321 | it("expose the port", () => { 322 | expect(ChartJSImage()._query).toMatchInlineSnapshot(`Object {}`); 323 | }); 324 | 325 | it("expose the query", () => { 326 | expect( 327 | ChartJSImage() 328 | .chart({ 329 | type: "bar", 330 | data: { 331 | labels: ["Hello world", "Foo bar"], 332 | datasets: [{ label: "Foo", data: [1, 2] }], 333 | }, 334 | }) 335 | .icac("plop")._query 336 | ).toMatchInlineSnapshot(` 337 | Object { 338 | "chart": "{type:'bar',data:{labels:['Hello world','Foo bar'],datasets:[{label:'Foo',data:[1,2]}]}}", 339 | "icac": "plop", 340 | } 341 | `); 342 | }); 343 | }); 344 | }); 345 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CHart.JS Image javascript library logo](./logo.jpg)](#getting-started) 2 | 3 | [![NPM VERSION](http://img.shields.io/npm/v/chart.js-image.svg?style=flat)](https://www.npmjs.org/package/chart.js-image) 4 | 5 | ![Libraries.io dependency status for GitHub repo](https://img.shields.io/librariesio/github/image-charts/javascript) 6 | ![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/image-charts/javascript) 7 | 8 | 9 | ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/chart.js-image) 10 | 11 | 16 | 17 | Generate [Chart.JS charts](https://www.chartjs.org/docs/latest/) as image and embed them everywhere in emails, pdf reports, chat bots...! 18 | 19 | ### Getting started 20 | 21 | #### 1. Install Chart.JS Image [npm](https://www.npmjs.com/package/chart.js-image) Package 22 | 23 | ```bash 24 | npm install chart.js-image --save 25 | ``` 26 | 27 | #### 2. Import Chart.JS Image 28 | 29 | > CommonJS 30 | 31 | ```javascript 32 | const ChartJSImage = require('chart.js-image'); 33 | ``` 34 | 35 | > ES6 36 | 37 | ```javascript 38 | import ChartJSImage from 'chart.js-image'; 39 | ``` 40 | 41 | #### 3. Generate a chart image 42 | 43 | ```js 44 | const line_chart = ChartJSImage().chart({ 45 | "type": "line", 46 | "data": { 47 | "labels": [ 48 | "January", 49 | "February", 50 | "March", 51 | "April", 52 | "May", 53 | "June", 54 | "July" 55 | ], 56 | "datasets": [ 57 | { 58 | "label": "My First dataset", 59 | "borderColor": "rgb(255,+99,+132)", 60 | "backgroundColor": "rgba(255,+99,+132,+.5)", 61 | "data": [ 62 | 57, 63 | 90, 64 | 11, 65 | -15, 66 | 37, 67 | -37, 68 | -27 69 | ] 70 | }, 71 | { 72 | "label": "My Second dataset", 73 | "borderColor": "rgb(54,+162,+235)", 74 | "backgroundColor": "rgba(54,+162,+235,+.5)", 75 | "data": [ 76 | 71, 77 | -36, 78 | -94, 79 | 78, 80 | 98, 81 | 65, 82 | -61 83 | ] 84 | }, 85 | { 86 | "label": "My Third dataset", 87 | "borderColor": "rgb(75,+192,+192)", 88 | "backgroundColor": "rgba(75,+192,+192,+.5)", 89 | "data": [ 90 | 48, 91 | -64, 92 | -61, 93 | 98, 94 | 0, 95 | -39, 96 | -70 97 | ] 98 | }, 99 | { 100 | "label": "My Fourth dataset", 101 | "borderColor": "rgb(255,+205,+86)", 102 | "backgroundColor": "rgba(255,+205,+86,+.5)", 103 | "data": [ 104 | -58, 105 | 88, 106 | 29, 107 | 44, 108 | 3, 109 | 78, 110 | -9 111 | ] 112 | } 113 | ] 114 | }, 115 | "options": { 116 | "title": { 117 | "display": true, 118 | "text": "Chart.js Line Chart" 119 | }, 120 | "scales": { 121 | "xAxes": [ 122 | { 123 | "scaleLabel": { 124 | "display": true, 125 | "labelString": "Month" 126 | } 127 | } 128 | ], 129 | "yAxes": [ 130 | { 131 | "stacked": true, 132 | "scaleLabel": { 133 | "display": true, 134 | "labelString": "Value" 135 | } 136 | } 137 | ] 138 | } 139 | } 140 | }) // Line chart 141 | .backgroundColor('white') 142 | .width(500) // 500px 143 | .height(300); // 300px 144 | 145 | line_chart.toURL(); // String: https://image-charts.com/chart.js/2.8.0?icac=documentation&chart=%7Btype%3A%27line%27%2Cdata%3A%7Blabels%3A%5B%27January%27%2C%27February%27%2C%27March%27%2C%27April%27%2C%27May%27%2C%27June%27%2C%27July%27%5D%2Cdatasets%3A%5B%7Blabel%3A%27My+First+dataset%27%2CborderColor%3A%27rgb%28255%2C+99%2C+132%29%27%2CbackgroundColor%3A%27rgba%28255%2C+99%2C+132%2C+.5%29%27%2Cdata%3A%5B57%2C90%2C11%2C-15%2C37%2C-37%2C-27%5D%7D%2C%7Blabel%3A%27My+Second+dataset%27%2CborderColor%3A%27rgb%2854%2C+162%2C+235%29%27%2CbackgroundColor%3A%27rgba%2854%2C+162%2C+235%2C+.5%29%27%2Cdata%3A%5B71%2C-36%2C-94%2C78%2C98%2C65%2C-61%5D%7D%2C%7Blabel%3A%27My+Third+dataset%27%2CborderColor%3A%27rgb%2875%2C+192%2C+192%29%27%2CbackgroundColor%3A%27rgba%2875%2C+192%2C+192%2C+.5%29%27%2Cdata%3A%5B48%2C-64%2C-61%2C98%2C0%2C-39%2C-70%5D%7D%2C%7Blabel%3A%27My+Third+dataset%27%2CborderColor%3A%27rgb%28255%2C+205%2C+86%29%27%2CbackgroundColor%3A%27rgba%28255%2C+205%2C+86%2C+.5%29%27%2Cdata%3A%5B-58%2C88%2C29%2C44%2C3%2C78%2C-9%5D%7D%5D%7D%2Coptions%3A%7Bresponsive%3Atrue%2Ctitle%3A%7Bdisplay%3Atrue%2Ctext%3A%27Chart.js+Line+Chart+-+Stacked+Area%27%7D%2Ctooltips%3A%7Bmode%3A%27index%27%7D%2Chover%3A%7Bmode%3A%27index%27%7D%2Cscales%3A%7BxAxes%3A%5B%7BscaleLabel%3A%7Bdisplay%3Atrue%2ClabelString%3A%27Month%27%7D%7D%5D%2CyAxes%3A%5B%7Bstacked%3Atrue%2CscaleLabel%3A%7Bdisplay%3Atrue%2ClabelString%3A%27Value%27%7D%7D%5D%7D%7D%7D&bkg=white&width=700&height=390&icretina=1&ichm=922e17b749b1ab7fab2a14cb742029dc46e50e658457913a9f548793910d2a0d 146 | line_chart.toFile('/path/to/chart.png'); // Promise<()> 147 | line_chart.toDataURI(); // Promise : data:image/png;base64,iVBORw0KGgo... 148 | line_chart.toBuffer(); // Promise : Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 ... 149 | ``` 150 | 151 |

152 | 153 | 154 | 155 |

Create an instance, the argument within [ ] is optional. See [usage](#usage) 186 | 187 | ```javascript 188 | ChartJSImage( [ Object opt ] ) 189 | // or 190 | new ChartJSImage( [ Object opt ] ) 191 | ``` 192 | 193 | #### Options 194 | 195 | > Default options are listed below. 196 | 197 | ```javascript 198 | opt = { 199 | /* 200 | * Request timeout (in millisecond) when calling toBuffer() or toDataURI() 201 | */ 202 | timeout: 5000, 203 | 204 | /* 205 | * (Enterprise and Enterprise+ subscription only) SECRET_KEY 206 | */ 207 | secret: null, 208 | 209 | /* 210 | * (Enterprise, Enterprise+ and On-Premise subscription only) custom domain 211 | */ 212 | host: 'image-charts.com', 213 | 214 | /* 215 | * (On-Premise subscription only) custom protocol 216 | */ 217 | protocol: 'https', 218 | 219 | /* 220 | * (On-Premise subscription only) custom port 221 | */ 222 | port: 443, 223 | 224 | /* 225 | * (On-Premise subscription only) custom pathname 226 | */ 227 | pathname: '/chart.js/2.8.0' 228 | } 229 | ``` 230 | 231 | - _[Back to Getting started](#getting-started)_ 232 | - _[Back to ToC](#table-of-contents)_ 233 | 234 | ---------------------------------------------------------------------------------------------- 235 | 236 | ### Methods 237 | 238 | ---------------------------------------------------------------------------------------------- 239 | 240 | 241 | #### `toURL()` : `String` 242 | 243 | > Get the full Image-Charts API url (signed and encoded if necessary) 244 | 245 | ##### Usage 246 | 247 | ```javascript 248 | // import ChartJSImage from 'chart.js-image'; 249 | const ChartJSImage = require('..'); 250 | 251 | const chart_url = ChartJSImage() 252 | .chart({ 253 | type: 'bar', 254 | data: { labels: ['Hello world', 'Foo bar'], datasets: [{ label: 'Foo', data: [1, 2] }] }, 255 | }) // vertical bar chart 256 | .width(300) // 300px 257 | .height(300) // 300px 258 | .toURL(); // get the generated URL 259 | 260 | console.log(chart_url); // https://image-charts.com/chart?cht=bvg&chs=300x300&chd=a%3A60%2C40 261 | 262 | ``` 263 | 264 | - _[Back to Getting started](#getting-started)_ 265 | - _[Back to ToC](#table-of-contents)_ 266 | 267 | 268 | ---------------------------------------------------------------------------------------------- 269 | 270 | 271 | #### `toFile(file)` : `Promise<()>` 272 | 273 | > Creates a file containing generated chart image and yield a promise. 274 | 275 | > When `file` is a filename, asynchronously writes data to the file, replacing the file if it already exists. 276 | > When `file` is a file descriptor, the behavior is similar to calling fs.write() directly (which is recommended). 277 | 278 | ##### Usage 279 | 280 | ```javascript 281 | //import ChartJSImage from 'chart.js-image'; 282 | const ChartJSImage = require('..'); 283 | 284 | const chart_path = '/tmp/chart.png'; 285 | 286 | ChartJSImage() 287 | .chart({ 288 | "type": "radar", 289 | "data": { 290 | "labels": [ 291 | "January", 292 | "February", 293 | "March", 294 | "April", 295 | "May", 296 | "June", 297 | "July", 298 | "August" 299 | ], 300 | "datasets": [ 301 | { 302 | "backgroundColor": "rgba(255, 99, 132, 0.5)", 303 | "borderColor": "rgb(255, 99, 132)", 304 | "data": [ 305 | 15.09, 306 | 15.67, 307 | 12.5, 308 | 12.77, 309 | 13.62, 310 | 13.68, 311 | 13.93, 312 | 15.95 313 | ], 314 | "label": "D0" 315 | }, 316 | { 317 | "backgroundColor": "rgba(255, 159, 64, 0.5)", 318 | "borderColor": "rgb(255, 159, 64)", 319 | "data": [ 320 | 24.55, 321 | 28.91, 322 | 21.81, 323 | 23.27, 324 | 26.98, 325 | 26.05, 326 | 25.39, 327 | 24.92 328 | ], 329 | "label": "D1", 330 | "fill": "-1" 331 | }, 332 | { 333 | "backgroundColor": "rgba(255, 205, 86, 0.5)", 334 | "borderColor": "rgb(255, 205, 86)", 335 | "data": [ 336 | 36.35, 337 | 43.93, 338 | 32.54, 339 | 33.54, 340 | 42.82, 341 | 39.34, 342 | 35.84, 343 | 33.5 344 | ], 345 | "label": "D2", 346 | "fill": 1 347 | }, 348 | { 349 | "backgroundColor": "rgba(75, 192, 192, 0.5)", 350 | "borderColor": "rgb(75, 192, 192)", 351 | "data": [ 352 | 47.7, 353 | 58.92, 354 | 44.45, 355 | 49.08, 356 | 53.39, 357 | 51.85, 358 | 48.4, 359 | 49.36 360 | ], 361 | "label": "D3", 362 | "fill": false 363 | }, 364 | { 365 | "backgroundColor": "rgba(54, 162, 235, 0.5)", 366 | "borderColor": "rgb(54, 162, 235)", 367 | "data": [ 368 | 60.73, 369 | 71.97, 370 | 53.96, 371 | 57.22, 372 | 65.09, 373 | 62.06, 374 | 56.91, 375 | 60.52 376 | ], 377 | "label": "D4", 378 | "fill": "-1" 379 | }, 380 | { 381 | "backgroundColor": "rgba(153, 102, 255, 0.5)", 382 | "borderColor": "rgb(153, 102, 255)", 383 | "data": [ 384 | 73.33, 385 | 80.78, 386 | 68.05, 387 | 68.59, 388 | 76.79, 389 | 77.24, 390 | 66.08, 391 | 72.37 392 | ], 393 | "label": "D5", 394 | "fill": "-1" 395 | } 396 | ] 397 | }, 398 | "options": { 399 | "maintainAspectRatio": true, 400 | "spanGaps": false, 401 | "elements": { 402 | "line": { 403 | "tension": 0.000001 404 | } 405 | }, 406 | "plugins": { 407 | "filler": { 408 | "propagate": false 409 | }, 410 | "samples-filler-analyser": { 411 | "target": "chart-analyser" 412 | } 413 | } 414 | } 415 | }) 416 | .bkg('white') 417 | .width(700) 418 | .height(390) 419 | .toFile(chart_path) 420 | .then(() => console.log('Image chart written at %s', chart_path)) 421 | 422 | 423 | 424 | ``` 425 | 426 | - _[Back to Getting started](#getting-started)_ 427 | - _[Back to ToC](#table-of-contents)_ 428 | 429 | ---------------------------------------------------------------------------------------------- 430 | 431 | 432 | #### `toBuffer()` : [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[`Buffer`](https://nodejs.org/api/buffer.html)> 433 | 434 | > Do a request to Image-Charts API with current configuration and yield a promise of a NodeJS buffer 435 | 436 | ##### Usage 437 | 438 | ```javascript 439 | //import ChartJSImage from 'chart.js-image'; 440 | const ChartJSImage = require('..'); 441 | 442 | const buffer = ChartJSImage() 443 | .chart({ 444 | "type": "radar", 445 | "data": { 446 | "labels": [ 447 | "January", 448 | "February", 449 | "March", 450 | "April", 451 | "May", 452 | "June", 453 | "July", 454 | "August" 455 | ], 456 | "datasets": [ 457 | { 458 | "backgroundColor": "rgba(255, 99, 132, 0.5)", 459 | "borderColor": "rgb(255, 99, 132)", 460 | "data": [ 461 | 15.09, 462 | 15.67, 463 | 12.5, 464 | 12.77, 465 | 13.62, 466 | 13.68, 467 | 13.93, 468 | 15.95 469 | ], 470 | "label": "D0" 471 | }, 472 | { 473 | "backgroundColor": "rgba(255, 159, 64, 0.5)", 474 | "borderColor": "rgb(255, 159, 64)", 475 | "data": [ 476 | 24.55, 477 | 28.91, 478 | 21.81, 479 | 23.27, 480 | 26.98, 481 | 26.05, 482 | 25.39, 483 | 24.92 484 | ], 485 | "label": "D1", 486 | "fill": "-1" 487 | }, 488 | { 489 | "backgroundColor": "rgba(255, 205, 86, 0.5)", 490 | "borderColor": "rgb(255, 205, 86)", 491 | "data": [ 492 | 36.35, 493 | 43.93, 494 | 32.54, 495 | 33.54, 496 | 42.82, 497 | 39.34, 498 | 35.84, 499 | 33.5 500 | ], 501 | "label": "D2", 502 | "fill": 1 503 | }, 504 | { 505 | "backgroundColor": "rgba(75, 192, 192, 0.5)", 506 | "borderColor": "rgb(75, 192, 192)", 507 | "data": [ 508 | 47.7, 509 | 58.92, 510 | 44.45, 511 | 49.08, 512 | 53.39, 513 | 51.85, 514 | 48.4, 515 | 49.36 516 | ], 517 | "label": "D3", 518 | "fill": false 519 | }, 520 | { 521 | "backgroundColor": "rgba(54, 162, 235, 0.5)", 522 | "borderColor": "rgb(54, 162, 235)", 523 | "data": [ 524 | 60.73, 525 | 71.97, 526 | 53.96, 527 | 57.22, 528 | 65.09, 529 | 62.06, 530 | 56.91, 531 | 60.52 532 | ], 533 | "label": "D4", 534 | "fill": "-1" 535 | }, 536 | { 537 | "backgroundColor": "rgba(153, 102, 255, 0.5)", 538 | "borderColor": "rgb(153, 102, 255)", 539 | "data": [ 540 | 73.33, 541 | 80.78, 542 | 68.05, 543 | 68.59, 544 | 76.79, 545 | 77.24, 546 | 66.08, 547 | 72.37 548 | ], 549 | "label": "D5", 550 | "fill": "-1" 551 | } 552 | ] 553 | }, 554 | "options": { 555 | "maintainAspectRatio": true, 556 | "spanGaps": false, 557 | "elements": { 558 | "line": { 559 | "tension": 0.000001 560 | } 561 | }, 562 | "plugins": { 563 | "filler": { 564 | "propagate": false 565 | }, 566 | "samples-filler-analyser": { 567 | "target": "chart-analyser" 568 | } 569 | } 570 | } 571 | }) 572 | .bkg('white') 573 | .width(700) 574 | .height(390) 575 | .toBuffer() // download chart image as a buffer 576 | .then((buffer) => console.log(buffer)) // 587 | #### `toDataURI()` : `String` 588 | 589 | > Do a request to Image-Charts API with current configuration and yield a promise of a base64 encoded [data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) 590 | 591 | ##### Usage 592 | 593 | ```javascript 594 | //import ChartJSImage from 'chart.js-image'; 595 | const ChartJSImage = require('..'); 596 | 597 | const chart_url = ChartJSImage() 598 | .chart({ 599 | "type": "radar", 600 | "data": { 601 | "labels": [ 602 | "January", 603 | "February", 604 | "March", 605 | "April", 606 | "May", 607 | "June", 608 | "July", 609 | "August" 610 | ], 611 | "datasets": [ 612 | { 613 | "backgroundColor": "rgba(255, 99, 132, 0.5)", 614 | "borderColor": "rgb(255, 99, 132)", 615 | "data": [ 616 | 15.09, 617 | 15.67, 618 | 12.5, 619 | 12.77, 620 | 13.62, 621 | 13.68, 622 | 13.93, 623 | 15.95 624 | ], 625 | "label": "D0" 626 | }, 627 | { 628 | "backgroundColor": "rgba(255, 159, 64, 0.5)", 629 | "borderColor": "rgb(255, 159, 64)", 630 | "data": [ 631 | 24.55, 632 | 28.91, 633 | 21.81, 634 | 23.27, 635 | 26.98, 636 | 26.05, 637 | 25.39, 638 | 24.92 639 | ], 640 | "label": "D1", 641 | "fill": "-1" 642 | }, 643 | { 644 | "backgroundColor": "rgba(255, 205, 86, 0.5)", 645 | "borderColor": "rgb(255, 205, 86)", 646 | "data": [ 647 | 36.35, 648 | 43.93, 649 | 32.54, 650 | 33.54, 651 | 42.82, 652 | 39.34, 653 | 35.84, 654 | 33.5 655 | ], 656 | "label": "D2", 657 | "fill": 1 658 | }, 659 | { 660 | "backgroundColor": "rgba(75, 192, 192, 0.5)", 661 | "borderColor": "rgb(75, 192, 192)", 662 | "data": [ 663 | 47.7, 664 | 58.92, 665 | 44.45, 666 | 49.08, 667 | 53.39, 668 | 51.85, 669 | 48.4, 670 | 49.36 671 | ], 672 | "label": "D3", 673 | "fill": false 674 | }, 675 | { 676 | "backgroundColor": "rgba(54, 162, 235, 0.5)", 677 | "borderColor": "rgb(54, 162, 235)", 678 | "data": [ 679 | 60.73, 680 | 71.97, 681 | 53.96, 682 | 57.22, 683 | 65.09, 684 | 62.06, 685 | 56.91, 686 | 60.52 687 | ], 688 | "label": "D4", 689 | "fill": "-1" 690 | }, 691 | { 692 | "backgroundColor": "rgba(153, 102, 255, 0.5)", 693 | "borderColor": "rgb(153, 102, 255)", 694 | "data": [ 695 | 73.33, 696 | 80.78, 697 | 68.05, 698 | 68.59, 699 | 76.79, 700 | 77.24, 701 | 66.08, 702 | 72.37 703 | ], 704 | "label": "D5", 705 | "fill": "-1" 706 | } 707 | ] 708 | }, 709 | "options": { 710 | "maintainAspectRatio": true, 711 | "spanGaps": false, 712 | "elements": { 713 | "line": { 714 | "tension": 0.000001 715 | } 716 | }, 717 | "plugins": { 718 | "filler": { 719 | "propagate": false 720 | }, 721 | "samples-filler-analyser": { 722 | "target": "chart-analyser" 723 | } 724 | } 725 | } 726 | }) 727 | .bkg('white') 728 | .width(700) 729 | .height(390) 730 | .toDataURI() // download chart image and generate a data URI string 731 | .then(chart_url => console.log(chart_url)); // "data:image/png;base64,iVBORw0KGgoAAAANSUhE"UgAABXgAAAMMCAIAAABmCliNAAHJnElEQVR42uzdeXjc1X3v8e/sq8baF2uXvMkbBmxibMALmN0FGiCBJpT0Ccnl0qRNnockT3vbOuT2Xkpzcxty0yZtnoQCqdliCKaktpEBG2+xkRfJlmzZsiXLlrWPRpp9u38c+DEZybYsy/KM9H794Uf6+aefRufMdj5zzvfo4vG4AAAAAAAAjAc9TQAAAAAAAMYLQQMAAAAAABPhyJEjf/RHf+T1elPkF12h20PQAAAAAADARCgvL1+3bp3Vap3cf6aRngYAAAAAYAK0trauW7fub/7mb37wgx8kHs/KynruuecKCgreeOONF198UR187bXXduzY8eMf/1j79p133lH/u27duuuuuy7p4q+//vpLL70kIn/7t39rt9tF5JFHHjnflVtbW7/zne988YtfVKd9//vfr6ysfPzxx2OxmDpBpSGJ11y8eLF2ERWXfO973xvxryBoAAAAAABgon3ve9/r6ur65S9/+Vd/9Vfnzp174okn1q1b9+KLL2rHjxw58uMf//hrX/taJBJR37744ot/+Zd/2d3dvW7dutdeey3xai0tLS+99JL62WeeeWbdunXarxjxyuvWrfve975nMBjUaaFQ6LHHHvvLv/xLm81msVjMZrNaWJF0Te0i69atS/wViX/Fa6+9RtAAAAAAAMBEu+aaa1pbW0Vk0aJFLS0tw48rc+bMCYVC2rf/9E//VFpa+vOf/9xisdx3333a8WeffVb9rMFgmD9/fjAYHH6p8317zTXX6HS6u+6665/+6Z8qKyu1ORTaaaO5ZuJfQdAAAAAAAEB6WLduXWZmZlFRkRYuJLFYLCUlJYnJxWjY7fYnn3xy5cqVp06d2r1799KlSy/nmhSDBAAAAAAgVRw8ePDYsWPat01NTYnfBgIBt9tdV1cXi8XmJtB+9re//e3DDz8cCAQueuXE4x0dHXV1dX6/PxgM/q//9b96enrq6uqi0ejwa57vIomY0QAAAAAAwNU3d+7ct99++/7771cVGdW3Tz755JkzZ4b/r1avMelny8vL33777SNHjl 732 | 733 | ``` 734 | 735 | - _[Back to Getting started](#getting-started)_ 736 | - _[Back to ToC](#table-of-contents)_ 737 | 738 | ---------------------------------------------------------------------------------------------- 739 | 740 | #### Enterprise Support 741 | 742 | Image-Charts Enterprise and Enterprise+ subscriptions remove the watermark and enable advanced features like custom-domain, high-resolution charts, custom fonts, multiple axis and mixed charts. 743 | 744 | - [Pricing and plan comparison](https://www.image-charts.com/pricing) 745 | - [Enterprise documentation](https://documentation.image-charts.com/enterprise/) 746 | 747 | ##### Usage 748 | 749 | Once subscribed to a plan you will receive an `ACCOUNT_ID` and a `SECRET_KEY`. 750 | These two parameters are mandatory to sign your request and remove the watermark. 751 | Replace both values in the code example below: 752 | 753 | ```javascript 754 | //import ChartJSImage from 'chart.js-image'; 755 | const ChartJSImage = require('..'); 756 | 757 | const chart_url = ChartJSImage({secret: process.env.SECRET_KEY || 'SECRET_KEY'}) 758 | .icac(process.env.ACCOUNT_ID || 'ACCOUNT_ID') 759 | .chart({ 760 | type: 'line', 761 | data: { 762 | labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], 763 | datasets: [ 764 | { 765 | label: 'My First dataset', 766 | borderColor: 'rgb(255, 99, 132)', 767 | backgroundColor: 'rgba(255, 99, 132, .5)', 768 | data: [57, 90, 11, -15, 37, -37, -27], 769 | }, 770 | { 771 | label: 'My Second dataset', 772 | borderColor: 'rgb(54, 162, 235)', 773 | backgroundColor: 'rgba(54, 162, 235, .5)', 774 | data: [71, -36, -94, 78, 98, 65, -61], 775 | }, 776 | { 777 | label: 'My Third dataset', 778 | borderColor: 'rgb(75, 192, 192)', 779 | backgroundColor: 'rgba(75, 192, 192, .5)', 780 | data: [48, -64, -61, 98, 0, -39, -70], 781 | }, 782 | { 783 | label: 'My Third dataset', 784 | borderColor: 'rgb(255, 205, 86)', 785 | backgroundColor: 'rgba(255, 205, 86, .5)', 786 | data: [-58, 88, 29, 44, 3, 78, -9], 787 | }, 788 | ], 789 | }, 790 | options: { 791 | responsive: true, 792 | title: { 793 | display: true, 794 | text: 'Chart.js Line Chart - Stacked Area', 795 | }, 796 | tooltips: { 797 | mode: 'index', 798 | }, 799 | hover: { 800 | mode: 'index', 801 | }, 802 | scales: { 803 | xAxes: [ 804 | { 805 | scaleLabel: { 806 | display: true, 807 | labelString: 'Month', 808 | }, 809 | }, 810 | ], 811 | yAxes: [ 812 | { 813 | stacked: true, 814 | scaleLabel: { 815 | display: true, 816 | labelString: 'Value', 817 | }, 818 | }, 819 | ], 820 | }, 821 | }, 822 | }) 823 | .bkg('white') 824 | .width(700) 825 | .height(390) 826 | .icretina('1') // enable paid-only features like high-resolution charts 827 | .toURL(); // get the whole (HMAC signed) URL 828 | 829 | console.log(chart_url); 830 | // https://image-charts.com/chart.js/2.8.0?icac=documentation&chart=%7Btype%3A%27line%27%2Cdata%3A%7Blabels%3A%5B%27January%27%2C%27February%27%2C%27March%27%2C%27April%27%2C%27May%27%2C%27June%27%2C%27July%27%5D%2Cdatasets%3A%5B%7Blabel%3A%27My+First+dataset%27%2CborderColor%3A%27rgb%28255%2C+99%2C+132%29%27%2CbackgroundColor%3A%27rgba%28255%2C+99%2C+132%2C+.5%29%27%2Cdata%3A%5B57%2C90%2C11%2C-15%2C37%2C-37%2C-27%5D%7D%2C%7Blabel%3A%27My+Second+dataset%27%2CborderColor%3A%27rgb%2854%2C+162%2C+235%29%27%2CbackgroundColor%3A%27rgba%2854%2C+162%2C+235%2C+.5%29%27%2Cdata%3A%5B71%2C-36%2C-94%2C78%2C98%2C65%2C-61%5D%7D%2C%7Blabel%3A%27My+Third+dataset%27%2CborderColor%3A%27rgb%2875%2C+192%2C+192%29%27%2CbackgroundColor%3A%27rgba%2875%2C+192%2C+192%2C+.5%29%27%2Cdata%3A%5B48%2C-64%2C-61%2C98%2C0%2C-39%2C-70%5D%7D%2C%7Blabel%3A%27My+Third+dataset%27%2CborderColor%3A%27rgb%28255%2C+205%2C+86%29%27%2CbackgroundColor%3A%27rgba%28255%2C+205%2C+86%2C+.5%29%27%2Cdata%3A%5B-58%2C88%2C29%2C44%2C3%2C78%2C-9%5D%7D%5D%7D%2Coptions%3A%7Bresponsive%3Atrue%2Ctitle%3A%7Bdisplay%3Atrue%2Ctext%3A%27Chart.js+Line+Chart+-+Stacked+Area%27%7D%2Ctooltips%3A%7Bmode%3A%27index%27%7D%2Chover%3A%7Bmode%3A%27index%27%7D%2Cscales%3A%7BxAxes%3A%5B%7BscaleLabel%3A%7Bdisplay%3Atrue%2ClabelString%3A%27Month%27%7D%7D%5D%2CyAxes%3A%5B%7Bstacked%3Atrue%2CscaleLabel%3A%7Bdisplay%3Atrue%2ClabelString%3A%27Value%27%7D%7D%5D%7D%7D%7D&bkg=white&width=700&height=390&icretina=1&ichm=922e17b749b1ab7fab2a14cb742029dc46e50e658457913a9f548793910d2a0d 831 | 832 | 833 | ``` 834 | 835 |

836 | 837 | - _[Back to Getting started](#getting-started)_ 838 | - _[Back to ToC](#table-of-contents)_ 839 | 840 | ---------------------------------------------------------------------------------------------- 841 | 842 | #### On-Premise Support 843 | 844 | Image-Charts virtual appliance can be deployed anywhere inside a customer network. 845 | 846 | 847 | ```javascript 848 | import ChartJSImage from 'chart.js-image'; 849 | 850 | const chart_url = ChartJSImage({ 851 | secret: 'SECRET_KEY', 852 | 853 | // override the host with your own endpoint 854 | host: 'custom-domain.tld' 855 | }) 856 | .chart({/* chart.js configuration object */}) 857 | .icretina('1') // enable paid-only features like high-resolution charts 858 | .toURL(); // get the whole (HMAC signed) URL 859 | 860 | console.log(chart_url); 861 | // https://image-charts.com/chart.js/2.8.0?icac=documentation&chart=%7Btype%3A%27line%27%2Cdata%3A%7Blabels%3A%5B%27January%27%2C%27February%27%2C%27March%27%2C%27April%27%2C%27May%27%2C%27June%27%2C%27July%27%5D%2Cdatasets%3A%5B%7Blabel%3A%27Unfilled%27%2Cfill%3Afalse%2CbackgroundColor%3A%27rgb%2854%2C+162%2C+235%29%27%2CborderColor%3A%27rgb%2854%2C+162%2C+235%29%27%2Cdata%3A%5B-73%2C40%2C-4%2C27%2C26%2C53%2C-12%5D%7D%2C%7Blabel%3A%27Dashed%27%2Cfill%3Afalse%2CbackgroundColor%3A%27rgb%2875%2C+192%2C+192%29%27%2CborderColor%3A%27rgb%2875%2C+192%2C+192%29%27%2CborderDash%3A%5B5%2C5%5D%2Cdata%3A%5B99%2C-40%2C93%2C-56%2C0%2C25%2C45%5D%7D%2C%7Blabel%3A%27Filled%27%2CbackgroundColor%3A%27rgb%28255%2C+99%2C+132%29%27%2CborderColor%3A%27rgb%28255%2C+99%2C+132%29%27%2Cdata%3A%5B56%2C68%2C84%2C11%2C-96%2C-56%2C-51%5D%2Cfill%3Atrue%7D%5D%7D%2Coptions%3A%7Btitle%3A%7Bdisplay%3Atrue%2Ctext%3A%27Chart.js+Line+Chart%27%7D%2Cscales%3A%7BxAxes%3A%5B%7Bdisplay%3Atrue%2CscaleLabel%3A%7Bdisplay%3Atrue%2ClabelString%3A%27Month%27%7D%7D%5D%2CyAxes%3A%5B%7Bdisplay%3Atrue%2CscaleLabel%3A%7Bdisplay%3Atrue%2ClabelString%3A%27Value%27%7D%7D%5D%7D%7D%7D&bkg=white&width=700&height=390&icretina=1&ichm=f272aa90e5ec691d41ac6c6c541f9d114c09dd38a1c7f114745c00074da72f69 862 | ``` 863 | 864 | - _[Back to Getting started](#getting-started)_ 865 | - _[Back to ToC](#table-of-contents)_ 866 | 867 | 868 | 869 | ---------------------------------------------------------------------------------------------- 870 | 871 | 872 | #### `c( value )` : [`ChartJSImage`](#constructor) 873 | 874 | > Javascript/JSON definition of the chart. Use a Chart.js configuration object. 875 | 876 | 877 | 878 | ##### Usage 879 | 880 | 881 |
.c("{type:'bar',data:{labels:['Q1','Q2','Q3','Q4'],datasets:[{label:'Users',data:[50,60,70,180]},{label:'Revenue',data:[100,200,300,400]}]}}")
882 | 883 | - _[Back to Getting started](#getting-started)_ 884 | - _[Back to ToC](#table-of-contents)_ 885 | 886 | 887 | 888 | ---------------------------------------------------------------------------------------------- 889 | 890 | 891 | #### `chart( value )` : [`ChartJSImage`](#constructor) 892 | 893 | > Javascript/JSON definition of the chart. Use a Chart.js configuration object. 894 | 895 | 896 | 897 | ##### Usage 898 | 899 | 900 |
.chart("{type:'bar',data:{labels:['Q1','Q2','Q3','Q4'],datasets:[{label:'Users',data:[50,60,70,180]},{label:'Revenue',data:[100,200,300,400]}]}}")
901 | 902 | - _[Back to Getting started](#getting-started)_ 903 | - _[Back to ToC](#table-of-contents)_ 904 | 905 | 906 | 907 | ---------------------------------------------------------------------------------------------- 908 | 909 | 910 | #### `width( value )` : [`ChartJSImage`](#constructor) 911 | 912 | > Width of the chart 913 | 914 | 915 | 916 | ##### Usage 917 | 918 | 919 |
.width("400")
920 | 921 | - _[Back to Getting started](#getting-started)_ 922 | - _[Back to ToC](#table-of-contents)_ 923 | 924 | 925 | 926 | ---------------------------------------------------------------------------------------------- 927 | 928 | 929 | #### `height( value )` : [`ChartJSImage`](#constructor) 930 | 931 | > Height of the chart 932 | 933 | 934 | 935 | ##### Usage 936 | 937 | 938 |
.height("300")
939 | 940 | - _[Back to Getting started](#getting-started)_ 941 | - _[Back to ToC](#table-of-contents)_ 942 | 943 | 944 | 945 | ---------------------------------------------------------------------------------------------- 946 | 947 | 948 | #### `backgroundColor( value )` : [`ChartJSImage`](#constructor) 949 | 950 | > Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 951 | 952 | 953 | 954 | ##### Usage 955 | 956 | 957 |
.backgroundColor("black")
958 |
.backgroundColor("rgb(255,255,120)")
959 |
.backgroundColor("%23ff00ff")
960 | 961 | - _[Back to Getting started](#getting-started)_ 962 | - _[Back to ToC](#table-of-contents)_ 963 | 964 | 965 | 966 | ---------------------------------------------------------------------------------------------- 967 | 968 | 969 | #### `bkg( value )` : [`ChartJSImage`](#constructor) 970 | 971 | > Background of the chart canvas. Accepts rgb (rgb(255,255,120)), colors (red), and url-encoded hex values (%23ff00ff). Abbreviated as "bkg" 972 | 973 | 974 | 975 | ##### Usage 976 | 977 | 978 |
.bkg("black")
979 |
.bkg("rgb(255,255,120)")
980 |
.bkg("%23ff00ff")
981 | 982 | - _[Back to Getting started](#getting-started)_ 983 | - _[Back to ToC](#table-of-contents)_ 984 | 985 | 986 | 987 | ---------------------------------------------------------------------------------------------- 988 | 989 | 990 | #### `encoding( value )` : [`ChartJSImage`](#constructor) 991 | 992 | > Encoding of your "chart" parameter. Accepted values are url and base64. 993 | 994 | 995 | 996 | ##### Allowed values: 997 |
.encoding("url")
998 |
.encoding("base64")
999 | 1000 | 1001 | 1002 | 1003 | - _[Back to Getting started](#getting-started)_ 1004 | - _[Back to ToC](#table-of-contents)_ 1005 | 1006 | 1007 | 1008 | ---------------------------------------------------------------------------------------------- 1009 | 1010 | 1011 | #### `icac( value )` : [`ChartJSImage`](#constructor) 1012 | 1013 | > image-charts enterprise `account_id` 1014 | 1015 | > [Reference](https://documentation.image-charts.com/enterprise/) 1016 | 1017 | 1018 | 1019 | ##### Usage 1020 | 1021 | 1022 |
.icac("accountId")
1023 | 1024 | - _[Back to Getting started](#getting-started)_ 1025 | - _[Back to ToC](#table-of-contents)_ 1026 | 1027 | 1028 | 1029 | ---------------------------------------------------------------------------------------------- 1030 | 1031 | 1032 | #### `ichm( value )` : [`ChartJSImage`](#constructor) 1033 | 1034 | > HMAC-SHA256 signature required to activate paid features 1035 | 1036 | > [Reference](https://documentation.image-charts.com/enterprise/) 1037 | 1038 | 1039 | 1040 | ##### Usage 1041 | 1042 | 1043 |
.ichm("0785cf22a0381c2e0239e27c126de4181f501d117c2c81745611e9db928b0376")
1044 | 1045 | - _[Back to Getting started](#getting-started)_ 1046 | - _[Back to ToC](#table-of-contents)_ 1047 | 1048 | 1049 | 1050 | ---------------------------------------------------------------------------------------------- 1051 | 1052 | 1053 | #### `icretina( value )` : [`ChartJSImage`](#constructor) 1054 | 1055 | > retina mode 1056 | 1057 | > [Reference](https://documentation.image-charts.com/reference/retina/) 1058 | 1059 | 1060 | 1061 | ##### Allowed values: 1062 |
.icretina("0")
1063 |
.icretina("1")
1064 | 1065 | 1066 | 1067 | 1068 | - _[Back to Getting started](#getting-started)_ 1069 | - _[Back to ToC](#table-of-contents)_ 1070 | 1071 | 1072 | --------------------------------------------------------------------------------