├── FileSaver ├── FileSaver.js ├── LICENSE.md ├── README.md ├── bower.json ├── demo │ ├── demo.css │ ├── demo.js │ ├── demo.min.js │ └── index.xhtml └── package.json ├── LICENSE ├── README.md ├── canvg ├── MIT-LICENSE.txt ├── StackBlur.js ├── canvg.js └── rgbcolor.js ├── circularplot.js ├── d3 ├── d3-tip.js └── d3.min.js ├── examples ├── circulardemo.html ├── circularsample.js ├── combodemo.html ├── data.js ├── data.simple.js ├── lineardemo.html ├── lineardemo.js └── tracks.css ├── linearbrush.js ├── linearplot.js └── prototypes ├── islandplot.html ├── islandplot.js ├── lineartrack.js └── sample.js /FileSaver/FileSaver.js: -------------------------------------------------------------------------------- 1 | /* FileSaver.js 2 | * A saveAs() FileSaver implementation. 3 | * 2013-10-21 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * License: X11/MIT 7 | * See LICENSE.md 8 | */ 9 | 10 | /*global self */ 11 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 12 | plusplus: true */ 13 | 14 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 15 | 16 | var saveAs = saveAs 17 | || (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) 18 | || (function(view) { 19 | "use strict"; 20 | var 21 | doc = view.document 22 | // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet 23 | , get_URL = function() { 24 | return view.URL || view.webkitURL || view; 25 | } 26 | , URL = view.URL || view.webkitURL || view 27 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 28 | , can_use_save_link = !view.externalHost && "download" in save_link 29 | , click = function(node) { 30 | var event = doc.createEvent("MouseEvents"); 31 | event.initMouseEvent( 32 | "click", true, false, view, 0, 0, 0, 0, 0 33 | , false, false, false, false, 0, null 34 | ); 35 | node.dispatchEvent(event); 36 | } 37 | , webkit_req_fs = view.webkitRequestFileSystem 38 | , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem 39 | , throw_outside = function (ex) { 40 | (view.setImmediate || view.setTimeout)(function() { 41 | throw ex; 42 | }, 0); 43 | } 44 | , force_saveable_type = "application/octet-stream" 45 | , fs_min_size = 0 46 | , deletion_queue = [] 47 | , process_deletion_queue = function() { 48 | var i = deletion_queue.length; 49 | while (i--) { 50 | var file = deletion_queue[i]; 51 | if (typeof file === "string") { // file is an object URL 52 | URL.revokeObjectURL(file); 53 | } else { // file is a File 54 | file.remove(); 55 | } 56 | } 57 | deletion_queue.length = 0; // clear queue 58 | } 59 | , dispatch = function(filesaver, event_types, event) { 60 | event_types = [].concat(event_types); 61 | var i = event_types.length; 62 | while (i--) { 63 | var listener = filesaver["on" + event_types[i]]; 64 | if (typeof listener === "function") { 65 | try { 66 | listener.call(filesaver, event || filesaver); 67 | } catch (ex) { 68 | throw_outside(ex); 69 | } 70 | } 71 | } 72 | } 73 | , FileSaver = function(blob, name) { 74 | // First try a.download, then web filesystem, then object URLs 75 | var 76 | filesaver = this 77 | , type = blob.type 78 | , blob_changed = false 79 | , object_url 80 | , target_view 81 | , get_object_url = function() { 82 | var object_url = get_URL().createObjectURL(blob); 83 | deletion_queue.push(object_url); 84 | return object_url; 85 | } 86 | , dispatch_all = function() { 87 | dispatch(filesaver, "writestart progress write writeend".split(" ")); 88 | } 89 | // on any filesys errors revert to saving with object URLs 90 | , fs_error = function() { 91 | // don't create more object URLs than needed 92 | if (blob_changed || !object_url) { 93 | object_url = get_object_url(blob); 94 | } 95 | if (target_view) { 96 | target_view.location.href = object_url; 97 | } else { 98 | window.open(object_url, "_blank"); 99 | } 100 | filesaver.readyState = filesaver.DONE; 101 | dispatch_all(); 102 | } 103 | , abortable = function(func) { 104 | return function() { 105 | if (filesaver.readyState !== filesaver.DONE) { 106 | return func.apply(this, arguments); 107 | } 108 | }; 109 | } 110 | , create_if_not_found = {create: true, exclusive: false} 111 | , slice 112 | ; 113 | filesaver.readyState = filesaver.INIT; 114 | if (!name) { 115 | name = "download"; 116 | } 117 | if (can_use_save_link) { 118 | object_url = get_object_url(blob); 119 | // FF for Android has a nasty garbage collection mechanism 120 | // that turns all objects that are not pure javascript into 'deadObject' 121 | // this means `doc` and `save_link` are unusable and need to be recreated 122 | // `view` is usable though: 123 | doc = view.document; 124 | save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); 125 | save_link.href = object_url; 126 | save_link.download = name; 127 | var event = doc.createEvent("MouseEvents"); 128 | event.initMouseEvent( 129 | "click", true, false, view, 0, 0, 0, 0, 0 130 | , false, false, false, false, 0, null 131 | ); 132 | save_link.dispatchEvent(event); 133 | filesaver.readyState = filesaver.DONE; 134 | dispatch_all(); 135 | return; 136 | } 137 | // Object and web filesystem URLs have a problem saving in Google Chrome when 138 | // viewed in a tab, so I force save with application/octet-stream 139 | // http://code.google.com/p/chromium/issues/detail?id=91158 140 | if (view.chrome && type && type !== force_saveable_type) { 141 | slice = blob.slice || blob.webkitSlice; 142 | blob = slice.call(blob, 0, blob.size, force_saveable_type); 143 | blob_changed = true; 144 | } 145 | // Since I can't be sure that the guessed media type will trigger a download 146 | // in WebKit, I append .download to the filename. 147 | // https://bugs.webkit.org/show_bug.cgi?id=65440 148 | if (webkit_req_fs && name !== "download") { 149 | name += ".download"; 150 | } 151 | if (type === force_saveable_type || webkit_req_fs) { 152 | target_view = view; 153 | } 154 | if (!req_fs) { 155 | fs_error(); 156 | return; 157 | } 158 | fs_min_size += blob.size; 159 | req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { 160 | fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { 161 | var save = function() { 162 | dir.getFile(name, create_if_not_found, abortable(function(file) { 163 | file.createWriter(abortable(function(writer) { 164 | writer.onwriteend = function(event) { 165 | target_view.location.href = file.toURL(); 166 | deletion_queue.push(file); 167 | filesaver.readyState = filesaver.DONE; 168 | dispatch(filesaver, "writeend", event); 169 | }; 170 | writer.onerror = function() { 171 | var error = writer.error; 172 | if (error.code !== error.ABORT_ERR) { 173 | fs_error(); 174 | } 175 | }; 176 | "writestart progress write abort".split(" ").forEach(function(event) { 177 | writer["on" + event] = filesaver["on" + event]; 178 | }); 179 | writer.write(blob); 180 | filesaver.abort = function() { 181 | writer.abort(); 182 | filesaver.readyState = filesaver.DONE; 183 | }; 184 | filesaver.readyState = filesaver.WRITING; 185 | }), fs_error); 186 | }), fs_error); 187 | }; 188 | dir.getFile(name, {create: false}, abortable(function(file) { 189 | // delete file if it already exists 190 | file.remove(); 191 | save(); 192 | }), abortable(function(ex) { 193 | if (ex.code === ex.NOT_FOUND_ERR) { 194 | save(); 195 | } else { 196 | fs_error(); 197 | } 198 | })); 199 | }), fs_error); 200 | }), fs_error); 201 | } 202 | , FS_proto = FileSaver.prototype 203 | , saveAs = function(blob, name) { 204 | return new FileSaver(blob, name); 205 | } 206 | ; 207 | FS_proto.abort = function() { 208 | var filesaver = this; 209 | filesaver.readyState = filesaver.DONE; 210 | dispatch(filesaver, "abort"); 211 | }; 212 | FS_proto.readyState = FS_proto.INIT = 0; 213 | FS_proto.WRITING = 1; 214 | FS_proto.DONE = 2; 215 | 216 | FS_proto.error = 217 | FS_proto.onwritestart = 218 | FS_proto.onprogress = 219 | FS_proto.onwrite = 220 | FS_proto.onabort = 221 | FS_proto.onerror = 222 | FS_proto.onwriteend = 223 | null; 224 | 225 | view.addEventListener("unload", process_deletion_queue, false); 226 | return saveAs; 227 | }(this.self || this.window || this.content)); 228 | // `self` is undefined in Firefox for Android content script context 229 | // while `this` is nsIContentFrameMessageManager 230 | // with an attribute `content` that corresponds to the window 231 | 232 | if (typeof module !== 'undefined') module.exports = saveAs; 233 | -------------------------------------------------------------------------------- /FileSaver/LICENSE.md: -------------------------------------------------------------------------------- 1 | This software is licensed under the MIT/X11 license. 2 | 3 | MIT/X11 license 4 | --------------- 5 | 6 | Copyright © 2011 [Eli Grey][1]. 7 | 8 | Permission is hereby granted, free of charge, to any person 9 | obtaining a copy of this software and associated documentation 10 | files (the "Software"), to deal in the Software without 11 | restriction, including without limitation the rights to use, 12 | copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the 14 | Software is furnished to do so, subject to the following 15 | conditions: 16 | 17 | The above copyright notice and this permission notice shall be 18 | included in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | OTHER DEALINGS IN THE SOFTWARE. 28 | 29 | 30 | [1]: http://eligrey.com -------------------------------------------------------------------------------- /FileSaver/README.md: -------------------------------------------------------------------------------- 1 | FileSaver.js 2 | ============ 3 | 4 | FileSaver.js implements the HTML5 W3C `saveAs()` [FileSaver][1] interface in browsers that do 5 | not natively support it. There is a [FileSaver.js demo][2] that demonstrates saving 6 | various media types. 7 | 8 | FileSaver.js is the solution to saving files on the client-side, and is perfect for 9 | webapps that need to generate files, or for saving sensitive information that shouldn't be 10 | sent to an external server. 11 | 12 | Looking for `canvas.toBlob()` for saving canvases? Check out 13 | [canvas-toBlob.js](https://github.com/eligrey/canvas-toBlob.js) for a cross-browser implementation. 14 | 15 | Supported Browsers 16 | ------------------ 17 | 18 | | Browser | Constructs as | Filenames | Max Blob Size | Dependencies | 19 | | -------------- | ------------- | ------------ | ------------- | ------------ | 20 | | Firefox 20+ | Blob | Yes | 800MiB | None | 21 | | Firefox ≤ 19 | data: URI | No | n/a | [Blob.js](https://github.com/eligrey/Blob.js) | 22 | | Chrome | Blob | Yes | 345MiB | None | 23 | | Chrome for Android | Blob | Yes | ? | None | 24 | | IE 10+ | Blob | Yes | 600MiB | None | 25 | | Opera Next | Blob | Yes | ? | None | 26 | | Opera < 15 | data: URI | No | n/a | [Blob.js](https://github.com/eligrey/Blob.js) | 27 | | Safari 6.1+ | Blob | No | ? | None | 28 | | Safari < 6 | data: URI | No | n/a | [Blob.js](https://github.com/eligrey/Blob.js) | 29 | 30 | Feature detection is possible: 31 | 32 | try { var isFileSaverSupported = !!new Blob(); } catch(e){} 33 | 34 | Syntax 35 | ------ 36 | 37 | FileSaver saveAs(in Blob data, in DOMString filename) 38 | 39 | Examples 40 | -------- 41 | 42 | ### Saving text 43 | 44 | var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"}); 45 | saveAs(blob, "hello world.txt"); 46 | 47 | The standard W3C File API [`Blob`][3] interface is not available in all browsers. 48 | [Blob.js][4] is a cross-browser `Blob` implementation that solves this. 49 | 50 | ### Saving a canvas 51 | 52 | var canvas = document.getElementById("my-canvas"), ctx = canvas.getContext("2d"); 53 | // draw to canvas... 54 | canvas.toBlob(function(blob) { 55 | saveAs(blob, "pretty image.png"); 56 | }); 57 | 58 | Note: The standard HTML5 `canvas.toBlob()` method is not available in all browsers. 59 | [canvas-toBlob.js][5] is a cross-browser `canvas.toBlob()` that polyfills this. 60 | 61 | ### Aborting a save 62 | 63 | var filesaver = saveAs(blob, "whatever"); 64 | cancel_button.addEventListener("click", function() { 65 | if (filesaver.abort) { 66 | filesaver.abort(); 67 | } 68 | }, false); 69 | 70 | This isn't that useful unless you're saving very large files (e.g. generated video). 71 | 72 | ![Tracking image](https://in.getclicky.com/212712ns.gif) 73 | 74 | [1]: http://www.w3.org/TR/file-writer-api/#the-filesaver-interface 75 | [2]: http://eligrey.com/demos/FileSaver.js/ 76 | [3]: https://developer.mozilla.org/en-US/docs/DOM/Blob 77 | [4]: https://github.com/eligrey/Blob.js 78 | [5]: https://github.com/eligrey/canvas-toBlob.js 79 | -------------------------------------------------------------------------------- /FileSaver/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FileSaver", 3 | "version": "1.0.0", 4 | "main": "./FileSaver.js", 5 | "dependencies": { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /FileSaver/demo/demo.css: -------------------------------------------------------------------------------- 1 | html { 2 | background-color: #DDD; 3 | } 4 | body { 5 | width: 900px; 6 | margin: 0 auto; 7 | font-family: Verdana, Helvetica, Arial, sans-serif; 8 | box-shadow: 0 0 5px #000; 9 | box-shadow: 0 0 10px 2px rgba(0, 0, 0, .5); 10 | padding: 7px 25px 70px; 11 | background-color: #FFF; 12 | } 13 | h1, h2, h3, h4, h5, h6 { 14 | font-family: Georgia, "Times New Roman", serif; 15 | } 16 | h2, form { 17 | text-align: center; 18 | } 19 | form { 20 | margin-top: 5px; 21 | } 22 | .input { 23 | width: 500px; 24 | height: 300px; 25 | margin: 0 auto; 26 | display: block; 27 | } 28 | section { 29 | margin-top: 40px; 30 | } 31 | dt { 32 | font-weight: bold; 33 | font-size: larger; 34 | } 35 | #canvas { 36 | cursor: crosshair; 37 | } 38 | #canvas, #html { 39 | border: 1px solid black; 40 | } 41 | .filename { 42 | text-align: right; 43 | } 44 | #html { 45 | box-sizing: border-box; 46 | ms-box-sizing: border-box; 47 | webkit-box-sizing: border-box; 48 | moz-box-sizing: border-box; 49 | overflow: auto; 50 | padding: 1em; 51 | } 52 | dt:target { 53 | background-color: Highlight; 54 | color: HighlightText; 55 | } 56 | -------------------------------------------------------------------------------- /FileSaver/demo/demo.js: -------------------------------------------------------------------------------- 1 | /* FileSaver.js demo script 2 | * 2012-01-23 3 | * 4 | * By Eli Grey, http://eligrey.com 5 | * License: X11/MIT 6 | * See LICENSE.md 7 | */ 8 | 9 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/demo/demo.js */ 10 | 11 | (function(view) { 12 | "use strict"; 13 | // The canvas drawing portion of the demo is based off the demo at 14 | // http://www.williammalone.com/articles/create-html5-canvas-javascript-drawing-app/ 15 | var 16 | document = view.document 17 | , $ = function(id) { 18 | return document.getElementById(id); 19 | } 20 | , session = view.sessionStorage 21 | // only get URL when necessary in case Blob.js hasn't defined it yet 22 | , get_blob = function() { 23 | return view.Blob; 24 | } 25 | 26 | , canvas = $("canvas") 27 | , canvas_options_form = $("canvas-options") 28 | , canvas_filename = $("canvas-filename") 29 | , canvas_clear_button = $("canvas-clear") 30 | 31 | , text = $("text") 32 | , text_options_form = $("text-options") 33 | , text_filename = $("text-filename") 34 | 35 | , html = $("html") 36 | , html_options_form = $("html-options") 37 | , html_filename = $("html-filename") 38 | 39 | , ctx = canvas.getContext("2d") 40 | , drawing = false 41 | , x_points = session.x_points || [] 42 | , y_points = session.y_points || [] 43 | , drag_points = session.drag_points || [] 44 | , add_point = function(x, y, dragging) { 45 | x_points.push(x); 46 | y_points.push(y); 47 | drag_points.push(dragging); 48 | } 49 | , draw = function(){ 50 | canvas.width = canvas.width; 51 | ctx.lineWidth = 6; 52 | ctx.lineJoin = "round"; 53 | ctx.strokeStyle = "#000000"; 54 | var 55 | i = 0 56 | , len = x_points.length 57 | ; 58 | for(; i < len; i++) { 59 | ctx.beginPath(); 60 | if (i && drag_points[i]) { 61 | ctx.moveTo(x_points[i-1], y_points[i-1]); 62 | } else { 63 | ctx.moveTo(x_points[i]-1, y_points[i]); 64 | } 65 | ctx.lineTo(x_points[i], y_points[i]); 66 | ctx.closePath(); 67 | ctx.stroke(); 68 | } 69 | } 70 | , stop_drawing = function() { 71 | drawing = false; 72 | } 73 | 74 | // Title guesser and document creator available at https://gist.github.com/1059648 75 | , guess_title = function(doc) { 76 | var 77 | h = "h6 h5 h4 h3 h2 h1".split(" ") 78 | , i = h.length 79 | , headers 80 | , header_text 81 | ; 82 | while (i--) { 83 | headers = doc.getElementsByTagName(h[i]); 84 | for (var j = 0, len = headers.length; j < len; j++) { 85 | header_text = headers[j].textContent.trim(); 86 | if (header_text) { 87 | return header_text; 88 | } 89 | } 90 | } 91 | } 92 | , doc_impl = document.implementation 93 | , create_html_doc = function(html) { 94 | var 95 | dt = doc_impl.createDocumentType('html', null, null) 96 | , doc = doc_impl.createDocument("http://www.w3.org/1999/xhtml", "html", dt) 97 | , doc_el = doc.documentElement 98 | , head = doc_el.appendChild(doc.createElement("head")) 99 | , charset_meta = head.appendChild(doc.createElement("meta")) 100 | , title = head.appendChild(doc.createElement("title")) 101 | , body = doc_el.appendChild(doc.createElement("body")) 102 | , i = 0 103 | , len = html.childNodes.length 104 | ; 105 | charset_meta.setAttribute("charset", html.ownerDocument.characterSet); 106 | for (; i < len; i++) { 107 | body.appendChild(doc.importNode(html.childNodes.item(i), true)); 108 | } 109 | var title_text = guess_title(doc); 110 | if (title_text) { 111 | title.appendChild(doc.createTextNode(title_text)); 112 | } 113 | return doc; 114 | } 115 | ; 116 | canvas.width = 500; 117 | canvas.height = 300; 118 | 119 | if (typeof x_points === "string") { 120 | x_points = JSON.parse(x_points); 121 | } if (typeof y_points === "string") { 122 | y_points = JSON.parse(y_points); 123 | } if (typeof drag_points === "string") { 124 | drag_points = JSON.parse(drag_points); 125 | } if (session.canvas_filename) { 126 | canvas_filename.value = session.canvas_filename; 127 | } if (session.text) { 128 | text.value = session.text; 129 | } if (session.text_filename) { 130 | text_filename.value = session.text_filename; 131 | } if (session.html) { 132 | html.innerHTML = session.html; 133 | } if (session.html_filename) { 134 | html_filename.value = session.html_filename; 135 | } 136 | 137 | drawing = true; 138 | draw(); 139 | drawing = false; 140 | 141 | canvas_clear_button.addEventListener("click", function() { 142 | canvas.width = canvas.width; 143 | x_points.length = 144 | y_points.length = 145 | drag_points.length = 146 | 0; 147 | }, false); 148 | canvas.addEventListener("mousedown", function(event) { 149 | event.preventDefault(); 150 | drawing = true; 151 | add_point(event.pageX - canvas.offsetLeft, event.pageY - canvas.offsetTop, false); 152 | draw(); 153 | }, false); 154 | canvas.addEventListener("mousemove", function(event) { 155 | if (drawing) { 156 | add_point(event.pageX - canvas.offsetLeft, event.pageY - canvas.offsetTop, true); 157 | draw(); 158 | } 159 | }, false); 160 | canvas.addEventListener("mouseup", stop_drawing, false); 161 | canvas.addEventListener("mouseout", stop_drawing, false); 162 | 163 | canvas_options_form.addEventListener("submit", function(event) { 164 | event.preventDefault(); 165 | canvas.toBlob(function(blob) { 166 | saveAs( 167 | blob 168 | , (canvas_filename.value || canvas_filename.placeholder) + ".png" 169 | ); 170 | }, "image/png"); 171 | }, false); 172 | 173 | text_options_form.addEventListener("submit", function(event) { 174 | event.preventDefault(); 175 | var BB = get_blob(); 176 | saveAs( 177 | new BB( 178 | [text.value || text.placeholder] 179 | , {type: "text/plain;charset=" + document.characterSet} 180 | ) 181 | , (text_filename.value || text_filename.placeholder) + ".txt" 182 | ); 183 | }, false); 184 | 185 | html_options_form.addEventListener("submit", function(event) { 186 | event.preventDefault(); 187 | var 188 | BB = get_blob() 189 | , xml_serializer = new XMLSerializer 190 | , doc = create_html_doc(html) 191 | ; 192 | saveAs( 193 | new BB( 194 | [xml_serializer.serializeToString(doc)] 195 | , {type: "application/xhtml+xml;charset=" + document.characterSet} 196 | ) 197 | , (html_filename.value || html_filename.placeholder) + ".xhtml" 198 | ); 199 | }, false); 200 | 201 | view.addEventListener("unload", function() { 202 | session.x_points = JSON.stringify(x_points); 203 | session.y_points = JSON.stringify(y_points); 204 | session.drag_points = JSON.stringify(drag_points); 205 | session.canvas_filename = canvas_filename.value; 206 | 207 | session.text = text.value; 208 | session.text_filename = text_filename.value; 209 | 210 | session.html = html.innerHTML; 211 | session.html_filename = html_filename.value; 212 | }, false); 213 | }(self)); 214 | -------------------------------------------------------------------------------- /FileSaver/demo/demo.min.js: -------------------------------------------------------------------------------- 1 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/demo/demo.js */ 2 | (function(n){"use strict";var s=n.document,g=function(A){return s.getElementById(A)},b=n.sessionStorage,x=function(){return n.Blob},f=g("canvas"),r=g("canvas-options"),y=g("canvas-filename"),p=g("canvas-clear"),q=g("text"),t=g("text-options"),h=g("text-filename"),m=g("html"),e=g("html-options"),i=g("html-filename"),u=f.getContext("2d"),z=false,a=b.x_points||[],o=b.y_points||[],d=b.drag_points||[],j=function(A,C,B){a.push(A);o.push(C);d.push(B)},l=function(){f.width=f.width;u.lineWidth=6;u.lineJoin="round";u.strokeStyle="#000000";var B=0,A=a.length;for(;B 2 | 3 | 4 | 5 | FileSaver.js demo 6 | 7 | 8 | 9 |

FileSaver.js demo

10 |

11 | The following examples demonstrate how it is possible to generate and save any type of data right in the browser using the W3C saveAs() FileSaver interface, without contacting any servers. 12 |

13 |
14 |

Saving an image

15 | 16 |
17 | 18 | 19 | 20 |
21 |
22 |
23 |

Saving text

24 |