Commit 81771252 authored by Paul Lambert's avatar Paul Lambert
Browse files

Downloading sparkline graphs as PNG is working + Removed charts.js repository

parent 740ef2d0
/**
* covert canvas to image
* and save the image file
*/
const Canvas2Image = (function () {
// check if support sth.
const $support = (function () {
const canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
return {
canvas: !!ctx,
imageData: !!ctx.getImageData,
dataURL: !!canvas.toDataURL,
btoa: !!window.btoa,
};
})();
const downloadMime = "image/octet-stream";
function scaleCanvas(canvas, width, height) {
const w = canvas.width,
h = canvas.height;
if (width === undefined) {
width = w;
}
if (height === undefined) {
height = h;
}
let retCanvas = document.createElement("canvas");
let retCtx = retCanvas.getContext("2d");
retCanvas.width = width;
retCanvas.height = height;
retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height);
return retCanvas;
}
function getDataURL(canvas, type, width, height) {
canvas = scaleCanvas(canvas, width, height);
return canvas.toDataURL(type);
}
// save file to local with file name and file type
function saveFile(strData, fileType, fileName = "name") {
// document.location.href = strData;
let saveLink = document.createElement("a");
// download file name
saveLink.download = fileName + "." + fileType;
// download file data
saveLink.href = strData;
// start download
saveLink.click();
}
function genImage(strData) {
let img = document.createElement("img");
img.src = strData;
return img;
}
function fixType(type) {
type = type.toLowerCase().replace(/jpg/i, "jpeg");
const r = type.match(/png|jpeg|bmp|gif/)[0];
return "image/" + r;
}
function encodeData(data) {
if (!window.btoa) {
// eslint-disable-next-line no-throw-literal
throw "btoa undefined";
}
let str = "";
if (typeof data == "string") {
str = data;
} else {
for (let i = 0; i < data.length; i++) {
str += String.fromCharCode(data[i]);
}
}
return btoa(str);
}
function getImageData(canvas) {
const w = canvas.width,
h = canvas.height;
return canvas.getContext("2d").getImageData(0, 0, w, h);
}
function makeURI(strData, type) {
return "data:" + type + ";base64," + strData;
}
/**
* create bitmap image
* 按照规则生成图片响应头和响应体
*/
const genBitmapImage = function (oData) {
//
// BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
// BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
//
const biWidth = oData.width;
const biHeight = oData.height;
const biSizeImage = biWidth * biHeight * 3;
const bfSize = biSizeImage + 54; // total header size = 54 bytes
//
// typedef struct tagBITMAPFILEHEADER {
// WORD bfType;
// DWORD bfSize;
// WORD bfReserved1;
// WORD bfReserved2;
// DWORD bfOffBits;
// } BITMAPFILEHEADER;
//
const BITMAPFILEHEADER = [
// WORD bfType -- The file type signature; must be "BM"
0x42,
0x4d,
// DWORD bfSize -- The size, in bytes, of the bitmap file
bfSize & 0xff,
(bfSize >> 8) & 0xff,
(bfSize >> 16) & 0xff,
(bfSize >> 24) & 0xff,
// WORD bfReserved1 -- Reserved; must be zero
0,
0,
// WORD bfReserved2 -- Reserved; must be zero
0,
0,
// DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
54,
0,
0,
0,
];
//
// typedef struct tagBITMAPINFOHEADER {
// DWORD biSize;
// LONG biWidth;
// LONG biHeight;
// WORD biPlanes;
// WORD biBitCount;
// DWORD biCompression;
// DWORD biSizeImage;
// LONG biXPelsPerMeter;
// LONG biYPelsPerMeter;
// DWORD biClrUsed;
// DWORD biClrImportant;
// } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
//
const BITMAPINFOHEADER = [
// DWORD biSize -- The number of bytes required by the structure
40,
0,
0,
0,
// LONG biWidth -- The width of the bitmap, in pixels
biWidth & 0xff,
(biWidth >> 8) & 0xff,
(biWidth >> 16) & 0xff,
(biWidth >> 24) & 0xff,
// LONG biHeight -- The height of the bitmap, in pixels
biHeight & 0xff,
(biHeight >> 8) & 0xff,
(biHeight >> 16) & 0xff,
(biHeight >> 24) & 0xff,
// WORD biPlanes -- The number of planes for the target device. This value must be set to 1
1,
0,
// WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
// has a maximum of 2^24 colors (16777216, Truecolor)
24,
0,
// DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
0,
0,
0,
0,
// DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
biSizeImage & 0xff,
(biSizeImage >> 8) & 0xff,
(biSizeImage >> 16) & 0xff,
(biSizeImage >> 24) & 0xff,
// LONG biXPelsPerMeter, unused
0,
0,
0,
0,
// LONG biYPelsPerMeter, unused
0,
0,
0,
0,
// DWORD biClrUsed, the number of color indexes of palette, unused
0,
0,
0,
0,
// DWORD biClrImportant, unused
0,
0,
0,
0,
];
const iPadding = (4 - ((biWidth * 3) % 4)) % 4;
const aImgData = oData.data;
let strPixelData = "";
const biWidth4 = biWidth << 2;
let y = biHeight;
const fromCharCode = String.fromCharCode;
do {
const iOffsetY = biWidth4 * (y - 1);
let strPixelRow = "";
for (let x = 0; x < biWidth; x++) {
const iOffsetX = x << 2;
strPixelRow +=
fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) +
fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) +
fromCharCode(aImgData[iOffsetY + iOffsetX]);
}
for (let c = 0; c < iPadding; c++) {
strPixelRow += String.fromCharCode(0);
}
strPixelData += strPixelRow;
} while (--y);
return (
encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) +
encodeData(strPixelData)
);
};
/**
* saveAsImage
* @param canvas canvasElement
* @param width {String} image type
* @param height {Number} [optional] png width
* @param type {string} [optional] png height
* @param fileName {String} image name
*/
const saveAsImage = function (canvas, width, height, type, fileName) {
// save file type
const fileType = type;
if ($support.canvas && $support.dataURL) {
if (typeof canvas == "string") {
canvas = document.getElementById(canvas);
}
if (type === undefined) {
type = "png";
}
type = fixType(type);
if (/bmp/.test(type)) {
const data = getImageData(scaleCanvas(canvas, width, height));
const strData = genBitmapImage(data);
// use new parameter: fileType
saveFile(makeURI(strData, downloadMime), fileType, fileName);
} else {
const strData = getDataURL(canvas, type, width, height);
// use new parameter: fileType
saveFile(strData.replace(type, downloadMime), fileType, fileName);
}
}
};
const convertToImage = function (canvas, width, height, type) {
if ($support.canvas && $support.dataURL) {
if (typeof canvas == "string") {
canvas = document.getElementById(canvas);
}
if (type === undefined) {
type = "png";
}
type = fixType(type);
if (/bmp/.test(type)) {
const data = getImageData(scaleCanvas(canvas, width, height));
const strData = genBitmapImage(data);
return genImage(makeURI(strData, "image/bmp"));
} else {
const strData = getDataURL(canvas, type, width, height);
return genImage(strData);
}
}
};
return {
saveAsImage: saveAsImage,
saveAsPNG: function (canvas, width, height, fileName) {
return saveAsImage(canvas, width, height, "png", fileName);
},
saveAsJPEG: function (canvas, width, height, fileName) {
return saveAsImage(canvas, width, height, "jpeg", fileName);
},
saveAsGIF: function (canvas, width, height, fileName) {
return saveAsImage(canvas, width, height, "gif", fileName);
},
saveAsBMP: function (canvas, width, height, fileName) {
return saveAsImage(canvas, width, height, "bmp", fileName);
},
convertToImage: convertToImage,
convertToPNG: function (canvas, width, height) {
return convertToImage(canvas, width, height, "png");
},
convertToJPEG: function (canvas, width, height) {
return convertToImage(canvas, width, height, "jpeg");
},
convertToGIF: function (canvas, width, height) {
return convertToImage(canvas, width, height, "gif");
},
convertToBMP: function (canvas, width, height) {
return convertToImage(canvas, width, height, "bmp");
},
};
})();
// Export function, used in npm
export default Canvas2Image;
<!doctype html>
<html>
<meta charset="utf-8" />
<script src="canvas2image.js"></script>
<style>
.doc {
width: 604px;
margin: 0 auto;
}
canvas {
display: block;
border: 2px solid #888;
}
</style>
<body>
<div class="doc">
<canvas width="600" height="400" id="cvs"></canvas>
<div>
<p>
<button id="save">save</button> or <button id="convert">convert to</button> as:
<select id="sel">
<option value="png">png</option>
<option value="jpeg">jpeg</option>
<option value="bmp">bmp</option>
</select><br/>
width : <input type="number" value="300" id="imgW" /><br/>
height : <input type="number" value="200" id="imgH" />
</p>
</div>
<div id="imgs">
</div>
</div>
<script>
var canvas, ctx, bMouseIsDown = false, iLastX, iLastY,
$save, $imgs,
$convert, $imgW, $imgH,
$sel;
function init () {
canvas = document.getElementById('cvs');
ctx = canvas.getContext('2d');
$save = document.getElementById('save');
$convert = document.getElementById('convert');
$sel = document.getElementById('sel');
$imgs = document.getElementById('imgs');
$imgW = document.getElementById('imgW');
$imgH = document.getElementById('imgH');
bind();
draw();
}
function bind () {
canvas.onmousedown = function(e) {
bMouseIsDown = true;
iLastX = e.clientX - canvas.offsetLeft + (window.pageXOffset||document.body.scrollLeft||document.documentElement.scrollLeft);
iLastY = e.clientY - canvas.offsetTop + (window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop);
}
canvas.onmouseup = function() {
bMouseIsDown = false;
iLastX = -1;
iLastY = -1;
}
canvas.onmousemove = function(e) {
if (bMouseIsDown) {
var iX = e.clientX - canvas.offsetLeft + (window.pageXOffset||document.body.scrollLeft||document.documentElement.scrollLeft);
var iY = e.clientY - canvas.offsetTop + (window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop);
ctx.moveTo(iLastX, iLastY);
ctx.lineTo(iX, iY);
ctx.stroke();
iLastX = iX;
iLastY = iY;
}
};
$save.onclick = function (e) {
var type = $sel.value,
w = $imgW.value,
h = $imgH.value;
Canvas2Image.saveAsImage(canvas, w, h, type);
}
$convert.onclick = function (e) {
var type = $sel.value,
w = $imgW.value,
h = $imgH.value;
$imgs.appendChild(Canvas2Image.convertToImage(canvas, w, h, type))
}
}
function draw () {
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, 600, 400);
ctx.fillStyle = 'red';
ctx.fillRect(100, 100, 50, 50);
}
onload = init;
</script>
</body>
</html>
\ No newline at end of file
# Canvas2image #
a tool of saving or converting canvas to images
## Demo ##
[canvas2image](http://hongru.github.com/proj/canvas2image/index.html)
## Code ##
you can just use it like this
Canvas2Image.saveAsImage(canvasObj, width, height, type)
Canvas2Image.saveAsPNG(canvasObj, width, height)
Canvas2Image.saveAsJPEG(canvasObj, width, height)
Canvas2Image.saveAsGIF(canvasObj, width, height)
Canvas2Image.saveAsBMP(canvasObj, width, height)
Canvas2Image.convertToImage(canvasObj, width, height, type)
Canvas2Image.convertToPNG(canvasObj, width, height)
Canvas2Image.convertToJPEG(canvasObj, width, height)
Canvas2Image.convertToGIF(canvasObj, width, height)
Canvas2Image.convertToBMP(canvasObj, width, height)
## License
MIT
The MIT License (MIT)
Copyright (c) 2018 Chart.js Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<p align="center">
<img src="https://www.chartjs.org/media/logo-title.svg"><br/>
Simple yet flexible JavaScript charting for designers & developers
</p>
<p align="center">
<a href="https://www.chartjs.org/docs/latest/getting-started/installation.html"><img src="https://img.shields.io/github/release/chartjs/Chart.js.svg?style=flat-square&maxAge=600" alt="Downloads"></a>
<a href="https://travis-ci.org/chartjs/Chart.js"><img src="https://img.shields.io/travis/chartjs/Chart.js.svg?style=flat-square&maxAge=600" alt="Builds"></a>
<a href="https://coveralls.io/github/chartjs/Chart.js?branch=master"><img src="https://img.shields.io/coveralls/chartjs/Chart.js.svg?style=flat-square&maxAge=600" alt="Coverage"></a>
<a href="https://github.com/chartjs/awesome"><img src="https://awesome.re/badge-flat2.svg" alt="Awesome"></a>
<a href="https://chartjs-slack.herokuapp.com/"><img src="https://img.shields.io/badge/slack-chartjs-blue.svg?style=flat-square&maxAge=3600" alt="Slack"></a>
</p>
## Documentation
- [Introduction](https://www.chartjs.org/docs/latest/)
- [Getting Started](https://www.chartjs.org/docs/latest/getting-started/)
- [General](https://www.chartjs.org/docs/latest/general/)
- [Configuration](https://www.chartjs.org/docs/latest/configuration/)
- [Charts](https://www.chartjs.org/docs/latest/charts/)
- [Axes](https://www.chartjs.org/docs/latest/axes/)
- [Developers](https://www.chartjs.org/docs/latest/developers/)
- [Popular Extensions](https://github.com/chartjs/awesome)
- [Samples](https://www.chartjs.org/samples/)
## Contributing
Instructions on building and testing Chart.js can be found in [the documentation](https://github.com/chartjs/Chart.js/blob/master/docs/developers/contributing.md#building-and-testing). Before submitting an issue or a pull request, please take a moment to look over the [contributing guidelines](https://github.com/chartjs/Chart.js/blob/master/docs/developers/contributing.md) first. For support, please post questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/chartjs) with the `chartjs` tag.
## License
Chart.js is available under the [MIT license](https://opensource.org/licenses/MIT).
{
"name": "chart.js",
"description": "Simple HTML5 charts using the canvas element.",
"homepage": "https://www.chartjs.org",
"license": "MIT",
"version": "2.9.4",
"main": "./dist/Chart.js",
"ignore": [
".github",
".codeclimate.yml",
".gitignore",
".npmignore",
".travis.yml",
"scripts"
]
}
\ No newline at end of file
{
"name": "nnnick/chartjs",
"type": "library",
"description": "Simple HTML5 charts using the canvas element.",
"keywords": [
"chart",
"js"
],
"homepage": "https://www.chartjs.org/",
"license": "MIT",
"authors": [
{
"name": "NICK DOWNIE",
"email": "hello@nickdownie.com"
}
],
"require": {
"php": ">=5.3.3"
},
"minimum-stability": "stable",
"extra": {
"branch-alias": {
"release/2.0": "v2.0-dev"
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* DOM element rendering detection
* https://davidwalsh.name/detect-node-insertion
*/
@keyframes chartjs-render-animation {
from { opacity: 0.99; }
to { opacity: 1; }
}
.chartjs-render-monitor {
animation: chartjs-render-animation 0.001s;
}
/*
* DOM element resizing detection
* https://github.com/marcj/css-element-queries
*/
.chartjs-size-monitor,
.chartjs-size-monitor-expand,
.chartjs-size-monitor-shrink {
position: absolute;
direction: ltr;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
pointer-events: none;
visibility: hidden;