1656833460
comic.js
Javascript library that acts as plugin for Raphael.js, D3.js, SVG.js or as lib for the HTML5 Canvas, providing functions for cartoon style drawing. Try it in the comic.js lab.
Provides either methods for drawing comic style shapes (cEllipse
, cLine
, cRect
, ...) or the magic
method for cartoonizing an already existing SVG. When using the magic
method or drawing on a canvas
no further libraries are required.
Cartoonized D3 examples: D3 Cartoonized!
Cartoon R widget built by Kent Russell using comic.js
: R Cartoonized!
using raphael.js, d3.js, svg.js and canvas: comic.js lab
using "magic": on images, on drawings
Chrome versions > 48.x need a polyfill for the missing pathSegList
API to make the magic
method of comic.js
work. This means you have to get pathseg.js
here and include it in your site via <script type="text/javascript" src="pathseg.js"></script>
.
Simply include comic.min.js
after including one of the supported libraries (Raphael.js, D3.js, SVG.js) - or none of them if you are using a HTML5 Canvas or just the magic
function for images. Then it can be used as follows, assuming that you have a container div
or canvas
with id paper
where needed:
The "magic" function universally goes:
// for images
COMIC.magic([ document.getElementById('img1'),
document.getElementById('img2') ]);
// for drawings
shapes.magic(); // where "shapes" is a drawing group created on "paper"
// via the lib of your choice (see examples below)
Drawing depending on the lib you use:
// Raphael.js
paper = Raphael("paper", width, height);
stuff = paper.set();
or
// D3.js
paper = d3.select("#paper").append('svg');
stuff = paper.append("g");
or
// SVG.js
paper = SVG('paper').size(width, height);
stuff = paper.group();
or
// canvas
paper = document.getElementById("paper");
ctx = paper.getContext("2d");
// IMPORTANT: here we bind comic.js to the canvas context
COMIC.ctx(ctx);
and then for the SVG libs (SVG.js, D3.js, Raphael.js):
// these are the default values if you do not call "init"
// NOTE: values have changed with beta5
COMIC.init({
ff: 8, // fuzz factor for line drawing: bigger -> fuzzier
ffc: 5, // fuzz factor for curve drawing: bigger -> fuzzier
fsteps: 5, // number of pixels per step: smaller -> fuzzier
msteps: 3, // min number of steps: bigger -> fuzzier
});
// lets draw!
stuff.cLine(x1, y1, x2, y2); // LINE from starting point to end point
stuff.cTrian(x1, y1, x2, y2, x3, y3); // TRIANGLE over three corner points
stuff.cRect(x1, y1, width, height, rh, rv); // RECTANGLE at upper left point (x1, y1) with
// width & height and with rounded (elliptic) corners
// with horizontal radius rh & vertical radius rv
stuff.cBezier2(x1, y1, cx, cy, x2, y2); // BEZIER (quadratic) curve with start point (x1, y1),
// control point (cx, cy) and end point (x2, y2)
stuff.cBezier3(x1, y1, cx1, cy1, cx2, cy2, x2, y2); // BEZIER (cubic) curve with start point
// (x1, y1), control points (cx1, cy1) & (cx2, cy2)
// and end point (x2, y2)
stuff.cCircle(x1, y1, r, start, end); // CIRCLE at center point (x1, y1) with radius r and drawn
// starting from 0 < start < 2*PI to 0 < end < 2*PI
stuff.cEllipse(x1, y1, rh, rv, rot, start, end); // ELLIPSE at center point with horizontal radius
// rh & vertical radius rv, rotation 0 < rot < 2*PI
// and drawn from 0 < start < 2*PI to 0 < end < 2*PI
// changing the look
stuff.attr({
"stroke":"#E0AE9F",
"stroke-width": 2,
"fill": "none"
});
Beyond this all depends on your choice of library - e.g. translation:
// Raphael.js
stuff.transform("t100,100r45");
// D3.js
stuff.attr({ "transform":"translate(30) rotate(45)" });
// SVG.js
stuff.transform({ x:100, y:100, rotation:45 });
For the HTML5 Canvas almost everything works identically. However to change the looks:
// changing the look
ctx.strokeStyle = "#FDD1BD";
ctx.lineWidth = 3;
ctx.globalCompositeOperation = 'destination-over';
While the drawing works exactly as above:
// lets draw!
stuff.cLine(x1, y1, x2, y2)
.cTrian(x1, y1, x2, y2, x3, y3)
.cRect(x1, y1, width, height);
All further things should work the default way of your chosen library. I have done little experiments though and errors are probable - please let me know if you encounter any.
Inspired by and based on Jonas Wagner's work which is based on this paper
Author: Balint42
Source Code: https://github.com/balint42/comic.js
License: MIT license
1656833460
comic.js
Javascript library that acts as plugin for Raphael.js, D3.js, SVG.js or as lib for the HTML5 Canvas, providing functions for cartoon style drawing. Try it in the comic.js lab.
Provides either methods for drawing comic style shapes (cEllipse
, cLine
, cRect
, ...) or the magic
method for cartoonizing an already existing SVG. When using the magic
method or drawing on a canvas
no further libraries are required.
Cartoonized D3 examples: D3 Cartoonized!
Cartoon R widget built by Kent Russell using comic.js
: R Cartoonized!
using raphael.js, d3.js, svg.js and canvas: comic.js lab
using "magic": on images, on drawings
Chrome versions > 48.x need a polyfill for the missing pathSegList
API to make the magic
method of comic.js
work. This means you have to get pathseg.js
here and include it in your site via <script type="text/javascript" src="pathseg.js"></script>
.
Simply include comic.min.js
after including one of the supported libraries (Raphael.js, D3.js, SVG.js) - or none of them if you are using a HTML5 Canvas or just the magic
function for images. Then it can be used as follows, assuming that you have a container div
or canvas
with id paper
where needed:
The "magic" function universally goes:
// for images
COMIC.magic([ document.getElementById('img1'),
document.getElementById('img2') ]);
// for drawings
shapes.magic(); // where "shapes" is a drawing group created on "paper"
// via the lib of your choice (see examples below)
Drawing depending on the lib you use:
// Raphael.js
paper = Raphael("paper", width, height);
stuff = paper.set();
or
// D3.js
paper = d3.select("#paper").append('svg');
stuff = paper.append("g");
or
// SVG.js
paper = SVG('paper').size(width, height);
stuff = paper.group();
or
// canvas
paper = document.getElementById("paper");
ctx = paper.getContext("2d");
// IMPORTANT: here we bind comic.js to the canvas context
COMIC.ctx(ctx);
and then for the SVG libs (SVG.js, D3.js, Raphael.js):
// these are the default values if you do not call "init"
// NOTE: values have changed with beta5
COMIC.init({
ff: 8, // fuzz factor for line drawing: bigger -> fuzzier
ffc: 5, // fuzz factor for curve drawing: bigger -> fuzzier
fsteps: 5, // number of pixels per step: smaller -> fuzzier
msteps: 3, // min number of steps: bigger -> fuzzier
});
// lets draw!
stuff.cLine(x1, y1, x2, y2); // LINE from starting point to end point
stuff.cTrian(x1, y1, x2, y2, x3, y3); // TRIANGLE over three corner points
stuff.cRect(x1, y1, width, height, rh, rv); // RECTANGLE at upper left point (x1, y1) with
// width & height and with rounded (elliptic) corners
// with horizontal radius rh & vertical radius rv
stuff.cBezier2(x1, y1, cx, cy, x2, y2); // BEZIER (quadratic) curve with start point (x1, y1),
// control point (cx, cy) and end point (x2, y2)
stuff.cBezier3(x1, y1, cx1, cy1, cx2, cy2, x2, y2); // BEZIER (cubic) curve with start point
// (x1, y1), control points (cx1, cy1) & (cx2, cy2)
// and end point (x2, y2)
stuff.cCircle(x1, y1, r, start, end); // CIRCLE at center point (x1, y1) with radius r and drawn
// starting from 0 < start < 2*PI to 0 < end < 2*PI
stuff.cEllipse(x1, y1, rh, rv, rot, start, end); // ELLIPSE at center point with horizontal radius
// rh & vertical radius rv, rotation 0 < rot < 2*PI
// and drawn from 0 < start < 2*PI to 0 < end < 2*PI
// changing the look
stuff.attr({
"stroke":"#E0AE9F",
"stroke-width": 2,
"fill": "none"
});
Beyond this all depends on your choice of library - e.g. translation:
// Raphael.js
stuff.transform("t100,100r45");
// D3.js
stuff.attr({ "transform":"translate(30) rotate(45)" });
// SVG.js
stuff.transform({ x:100, y:100, rotation:45 });
For the HTML5 Canvas almost everything works identically. However to change the looks:
// changing the look
ctx.strokeStyle = "#FDD1BD";
ctx.lineWidth = 3;
ctx.globalCompositeOperation = 'destination-over';
While the drawing works exactly as above:
// lets draw!
stuff.cLine(x1, y1, x2, y2)
.cTrian(x1, y1, x2, y2, x3, y3)
.cRect(x1, y1, width, height);
All further things should work the default way of your chosen library. I have done little experiments though and errors are probable - please let me know if you encounter any.
Inspired by and based on Jonas Wagner's work which is based on this paper
Author: Balint42
Source Code: https://github.com/balint42/comic.js
License: MIT license
1632537859
Not babashka. Node.js babashka!?
Ad-hoc CLJS scripting on Node.js.
Experimental. Please report issues here.
Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.
Additional goals and features are:
Nbb requires Node.js v12 or newer.
CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).
Install nbb
from NPM:
$ npm install nbb -g
Omit -g
for a local install.
Try out an expression:
$ nbb -e '(+ 1 2 3)'
6
And then install some other NPM libraries to use in the script. E.g.:
$ npm install csv-parse shelljs zx
Create a script which uses the NPM libraries:
(ns script
(:require ["csv-parse/lib/sync$default" :as csv-parse]
["fs" :as fs]
["path" :as path]
["shelljs$default" :as sh]
["term-size$default" :as term-size]
["zx$default" :as zx]
["zx$fs" :as zxfs]
[nbb.core :refer [*file*]]))
(prn (path/resolve "."))
(prn (term-size))
(println (count (str (fs/readFileSync *file*))))
(prn (sh/ls "."))
(prn (csv-parse "foo,bar"))
(prn (zxfs/existsSync *file*))
(zx/$ #js ["ls"])
Call the script:
$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs
Nbb has first class support for macros: you can define them right inside your .cljs
file, like you are used to from JVM Clojure. Consider the plet
macro to make working with promises more palatable:
(defmacro plet
[bindings & body]
(let [binding-pairs (reverse (partition 2 bindings))
body (cons 'do body)]
(reduce (fn [body [sym expr]]
(let [expr (list '.resolve 'js/Promise expr)]
(list '.then expr (list 'clojure.core/fn (vector sym)
body))))
body
binding-pairs)))
Using this macro we can look async code more like sync code. Consider this puppeteer example:
(-> (.launch puppeteer)
(.then (fn [browser]
(-> (.newPage browser)
(.then (fn [page]
(-> (.goto page "https://clojure.org")
(.then #(.screenshot page #js{:path "screenshot.png"}))
(.catch #(js/console.log %))
(.then #(.close browser)))))))))
Using plet
this becomes:
(plet [browser (.launch puppeteer)
page (.newPage browser)
_ (.goto page "https://clojure.org")
_ (-> (.screenshot page #js{:path "screenshot.png"})
(.catch #(js/console.log %)))]
(.close browser))
See the puppeteer example for the full code.
Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet
macro is similar to promesa.core/let
.
$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)' 0.17s user 0.02s system 109% cpu 0.168 total
The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx
this adds another 300ms or so, so for faster startup, either use a globally installed nbb
or use $(npm bin)/nbb script.cljs
to bypass npx
.
Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.
To load .cljs
files from local paths or dependencies, you can use the --classpath
argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs
relative to your current dir, then you can load it via (:require [foo.bar :as fb])
. Note that nbb
uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar
in the namespace name becomes foo_bar
in the directory name.
To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:
$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"
and then feed it to the --classpath
argument:
$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]
Currently nbb
only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar
files will be added later.
The name of the file that is currently being executed is available via nbb.core/*file*
or on the metadata of vars:
(ns foo
(:require [nbb.core :refer [*file*]]))
(prn *file*) ;; "/private/tmp/foo.cljs"
(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"
Nbb includes reagent.core
which will be lazily loaded when required. You can use this together with ink to create a TUI application:
$ npm install ink
ink-demo.cljs
:
(ns ink-demo
(:require ["ink" :refer [render Text]]
[reagent.core :as r]))
(defonce state (r/atom 0))
(doseq [n (range 1 11)]
(js/setTimeout #(swap! state inc) (* n 500)))
(defn hello []
[:> Text {:color "green"} "Hello, world! " @state])
(render (r/as-element [hello]))
Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core
namespace is included with the let
and do!
macros. An example:
(ns prom
(:require [promesa.core :as p]))
(defn sleep [ms]
(js/Promise.
(fn [resolve _]
(js/setTimeout resolve ms))))
(defn do-stuff
[]
(p/do!
(println "Doing stuff which takes a while")
(sleep 1000)
1))
(p/let [a (do-stuff)
b (inc a)
c (do-stuff)
d (+ b c)]
(prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3
Also see API docs.
Since nbb v0.0.75 applied-science/js-interop is available:
(ns example
(:require [applied-science.js-interop :as j]))
(def o (j/lit {:a 1 :b 2 :c {:d 1}}))
(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1
Most of this library is supported in nbb, except the following:
:syms
.-x
notation. In nbb, you must use keywords.See the example of what is currently supported.
See the examples directory for small examples.
Also check out these projects built with nbb:
See API documentation.
See this gist on how to convert an nbb script or project to shadow-cljs.
Prequisites:
To build:
bb release
Run bb tasks
for more project-related tasks.
Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb
License: EPL-1.0
#node #javascript
1561523460
This Matplotlib cheat sheet introduces you to the basics that you need to plot your data with Python and includes code samples.
Data visualization and storytelling with your data are essential skills that every data scientist needs to communicate insights gained from analyses effectively to any audience out there.
For most beginners, the first package that they use to get in touch with data visualization and storytelling is, naturally, Matplotlib: it is a Python 2D plotting library that enables users to make publication-quality figures. But, what might be even more convincing is the fact that other packages, such as Pandas, intend to build more plotting integration with Matplotlib as time goes on.
However, what might slow down beginners is the fact that this package is pretty extensive. There is so much that you can do with it and it might be hard to still keep a structure when you're learning how to work with Matplotlib.
DataCamp has created a Matplotlib cheat sheet for those who might already know how to use the package to their advantage to make beautiful plots in Python, but that still want to keep a one-page reference handy. Of course, for those who don't know how to work with Matplotlib, this might be the extra push be convinced and to finally get started with data visualization in Python.
You'll see that this cheat sheet presents you with the six basic steps that you can go through to make beautiful plots.
Check out the infographic by clicking on the button below:
With this handy reference, you'll familiarize yourself in no time with the basics of Matplotlib: you'll learn how you can prepare your data, create a new plot, use some basic plotting routines to your advantage, add customizations to your plots, and save, show and close the plots that you make.
What might have looked difficult before will definitely be more clear once you start using this cheat sheet! Use it in combination with the Matplotlib Gallery, the documentation.
Matplotlib
Matplotlib is a Python 2D plotting library which produces publication-quality figures in a variety of hardcopy formats and interactive environments across platforms.
>>> import numpy as np
>>> x = np.linspace(0, 10, 100)
>>> y = np.cos(x)
>>> z = np.sin(x)
>>> data = 2 * np.random.random((10, 10))
>>> data2 = 3 * np.random.random((10, 10))
>>> Y, X = np.mgrid[-3:3:100j, -3:3:100j]
>>> U = 1 X** 2 + Y
>>> V = 1 + X Y**2
>>> from matplotlib.cbook import get_sample_data
>>> img = np.load(get_sample_data('axes_grid/bivariate_normal.npy'))
>>> import matplotlib.pyplot as plt
>>> fig = plt.figure()
>>> fig2 = plt.figure(figsize=plt.figaspect(2.0))
>>> fig.add_axes()
>>> ax1 = fig.add_subplot(221) #row-col-num
>>> ax3 = fig.add_subplot(212)
>>> fig3, axes = plt.subplots(nrows=2,ncols=2)
>>> fig4, axes2 = plt.subplots(ncols=3)
>>> plt.savefig('foo.png') #Save figures
>>> plt.savefig('foo.png', transparent=True) #Save transparent figures
>>> plt.show()
>>> fig, ax = plt.subplots()
>>> lines = ax.plot(x,y) #Draw points with lines or markers connecting them
>>> ax.scatter(x,y) #Draw unconnected points, scaled or colored
>>> axes[0,0].bar([1,2,3],[3,4,5]) #Plot vertical rectangles (constant width)
>>> axes[1,0].barh([0.5,1,2.5],[0,1,2]) #Plot horiontal rectangles (constant height)
>>> axes[1,1].axhline(0.45) #Draw a horizontal line across axes
>>> axes[0,1].axvline(0.65) #Draw a vertical line across axes
>>> ax.fill(x,y,color='blue') #Draw filled polygons
>>> ax.fill_between(x,y,color='yellow') #Fill between y values and 0
>>> fig, ax = plt.subplots()
>>> im = ax.imshow(img, #Colormapped or RGB arrays
cmap= 'gist_earth',
interpolation= 'nearest',
vmin=-2,
vmax=2)
>>> axes2[0].pcolor(data2) #Pseudocolor plot of 2D array
>>> axes2[0].pcolormesh(data) #Pseudocolor plot of 2D array
>>> CS = plt.contour(Y,X,U) #Plot contours
>>> axes2[2].contourf(data1) #Plot filled contours
>>> axes2[2]= ax.clabel(CS) #Label a contour plot
>>> axes[0,1].arrow(0,0,0.5,0.5) #Add an arrow to the axes
>>> axes[1,1].quiver(y,z) #Plot a 2D field of arrows
>>> axes[0,1].streamplot(X,Y,U,V) #Plot a 2D field of arrows
>>> ax1.hist(y) #Plot a histogram
>>> ax3.boxplot(y) #Make a box and whisker plot
>>> ax3.violinplot(z) #Make a violin plot
y-axis
x-axis
The basic steps to creating plots with matplotlib are:
1 Prepare Data
2 Create Plot
3 Plot
4 Customized Plot
5 Save Plot
6 Show Plot
>>> import matplotlib.pyplot as plt
>>> x = [1,2,3,4] #Step 1
>>> y = [10,20,25,30]
>>> fig = plt.figure() #Step 2
>>> ax = fig.add_subplot(111) #Step 3
>>> ax.plot(x, y, color= 'lightblue', linewidth=3) #Step 3, 4
>>> ax.scatter([2,4,6],
[5,15,25],
color= 'darkgreen',
marker= '^' )
>>> ax.set_xlim(1, 6.5)
>>> plt.savefig('foo.png' ) #Step 5
>>> plt.show() #Step 6
>>> plt.cla() #Clear an axis
>>> plt.clf(). #Clear the entire figure
>>> plt.close(). #Close a window
>>> plt.plot(x, x, x, x**2, x, x** 3)
>>> ax.plot(x, y, alpha = 0.4)
>>> ax.plot(x, y, c= 'k')
>>> fig.colorbar(im, orientation= 'horizontal')
>>> im = ax.imshow(img,
cmap= 'seismic' )
>>> fig, ax = plt.subplots()
>>> ax.scatter(x,y,marker= ".")
>>> ax.plot(x,y,marker= "o")
>>> plt.plot(x,y,linewidth=4.0)
>>> plt.plot(x,y,ls= 'solid')
>>> plt.plot(x,y,ls= '--')
>>> plt.plot(x,y,'--' ,x**2,y**2,'-.' )
>>> plt.setp(lines,color= 'r',linewidth=4.0)
>>> ax.text(1,
-2.1,
'Example Graph',
style= 'italic' )
>>> ax.annotate("Sine",
xy=(8, 0),
xycoords= 'data',
xytext=(10.5, 0),
textcoords= 'data',
arrowprops=dict(arrowstyle= "->",
connectionstyle="arc3"),)
>>> plt.title(r '$sigma_i=15$', fontsize=20)
Limits & Autoscaling
>>> ax.margins(x=0.0,y=0.1) #Add padding to a plot
>>> ax.axis('equal') #Set the aspect ratio of the plot to 1
>>> ax.set(xlim=[0,10.5],ylim=[-1.5,1.5]) #Set limits for x-and y-axis
>>> ax.set_xlim(0,10.5) #Set limits for x-axis
Legends
>>> ax.set(title= 'An Example Axes', #Set a title and x-and y-axis labels
ylabel= 'Y-Axis',
xlabel= 'X-Axis')
>>> ax.legend(loc= 'best') #No overlapping plot elements
Ticks
>>> ax.xaxis.set(ticks=range(1,5), #Manually set x-ticks
ticklabels=[3,100, 12,"foo" ])
>>> ax.tick_params(axis= 'y', #Make y-ticks longer and go in and out
direction= 'inout',
length=10)
Subplot Spacing
>>> fig3.subplots_adjust(wspace=0.5, #Adjust the spacing between subplots
hspace=0.3,
left=0.125,
right=0.9,
top=0.9,
bottom=0.1)
>>> fig.tight_layout() #Fit subplot(s) in to the figure area
Axis Spines
>>> ax1.spines[ 'top'].set_visible(False) #Make the top axis line for a plot invisible
>>> ax1.spines['bottom' ].set_position(( 'outward',10)) #Move the bottom axis line outward
Have this Cheat Sheet at your fingertips
Original article source at https://www.datacamp.com
#matplotlib #cheatsheet #python
1627976163
Generates an image from a DOM node using HTML5 canvas and SVG.
Fork from dom-to-image with more maintainable code and some new features.
npm install --save html-to-image
/* ES6 */
import * as htmlToImage from 'html-to-image';
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from 'html-to-image';
/* ES5 */
var htmlToImage = require('html-to-image');
All the top level functions accept DOM node and rendering options, and return a promise fulfilled with corresponding dataURL:
Go with the following examples.
Get a PNG image base64-encoded data URL and display it right away:
var node = document.getElementById('my-node');
htmlToImage.toPng(node)
.then(function (dataUrl) {
var img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
})
.catch(function (error) {
console.error('oops, something went wrong!', error);
});
Get a PNG image base64-encoded data URL and download it (using download):
htmlToImage.toPng(document.getElementById('my-node'))
.then(function (dataUrl) {
download(dataUrl, 'my-node.png');
});
Get an SVG data URL, but filter out all the <i> elements:
function filter (node) {
return (node.tagName !== 'i');
}
htmlToImage.toSvg(document.getElementById('my-node'), { filter: filter })
.then(function (dataUrl) {
/* do something */
});
Save and download a compressed JPEG image:
htmlToImage.toJpeg(document.getElementById('my-node'), { quality: 0.95 })
.then(function (dataUrl) {
var link = document.createElement('a');
link.download = 'my-image-name.jpeg';
link.href = dataUrl;
link.click();
});
Get a PNG image blob and download it (using FileSaver):
htmlToImage.toBlob(document.getElementById('my-node'))
.then(function (blob) {
window.saveAs(blob, 'my-node.png');
});
Get a HTMLCanvasElement, and display it right away:
htmlToImage.toCanvas(document.getElementById('my-node'))
.then(function (canvas) {
document.body.appendChild(canvas);
});
Get the raw pixel data as a Uint8Array with every 4 array elements representing the RGBA data of a pixel:
var node = document.getElementById('my-node');
htmlToImage.toPixelData(node)
.then(function (pixels) {
for (var y = 0; y < node.scrollHeight; ++y) {
for (var x = 0; x < node.scrollWidth; ++x) {
pixelAtXYOffset = (4 * y * node.scrollHeight) + (4 * x);
/* pixelAtXY is a Uint8Array[4] containing RGBA values of the pixel at (x, y) in the range 0..255 */
pixelAtXY = pixels.slice(pixelAtXYOffset, pixelAtXYOffset + 4);
}
}
});
import React, { useCallback, useRef } from 'react';
import { toPng } from 'html-to-image';
const App: React.FC = () => {
const ref = useRef<HTMLDivElement>(null)
const onButtonClick = useCallback(() => {
if (ref.current === null) {
return
}
toPng(ref.current, { cacheBust: true, })
.then((dataUrl) => {
const link = document.createElement('a')
link.download = 'my-image-name.png'
link.href = dataUrl
link.click()
})
.catch((err) => {
console.log(err)
})
}, [ref])
return (
<>
<div ref={ref}>
{/* DOM nodes you want to convert to PNG */}
</div>
<button onClick={onButtonClick}>Click me</button>
</>
)
}
(domNode: HTMLElement) => boolean
A function taking DOM node as argument. Should return true if passed node should be included in the output. Excluding node means excluding it's children as well.
Not called on the root node.
A string value for the background color, any valid CSS color value.
Width and height in pixels to be applied to node before rendering.
Allows to scale the canva's size including the elements inside to a given width and height (in pixels).
An object whose properties to be copied to node's style before rendering. You might want to check this reference for JavaScript names of CSS properties.
A number between 0 and 1 indicating image quality (e.g. 0.92 => 92%) of the JPEG image.
Defaults to 1.0 (100%)
Set to true to append the current time as a query string to URL requests to enable cache busting.
Defaults to false
A data URL for a placeholder image that will be used when fetching an image fails.
Defaults to an empty string and will render empty areas for failed images.
The pixel ratio of the captured image. Default use the actual pixel ratio of the device. Set 1 to use as initial-scale 1 for the image.
The format required for font embedding. This is a useful optimisation when a webfont provider specifies several different formats for fonts in the CSS, for example:
@font-face {
name: 'proxima-nova';
src: url("...") format("woff2"), url("...") format("woff"), url("...") format("opentype");
}
Instead of embedding each format, all formats other than the one specified will be discarded. If this option is not specified then all formats will be downloaded and embedded.
When supplied, the library will skip the process of parsing and embedding webfont URLs in CSS, instead using this value. This is useful when combined with .getFontEmbedCss() to only perform the embedding process a single time across multiple calls to library functions.
const fontEmbedCss = await htmlToImage.getFontEmbedCss(element1);
html2Image.toSVG(element1, { fontEmbedCss });
html2Image.toSVG(element2, { fontEmbedCss });
Only standard lib is currently used, but make sure your browser supports:
It's tested on latest Chrome and Firefox (49 and 45 respectively at the time of writing), with Chrome performing significantly better on big DOM trees, possibly due to it's more performant SVG support, and the fact that it supports CSSStyleDeclaration.cssText property.
Internet Explorer is not (and will not be) supported, as it does not support SVG <foreignObject> tag.
Safari is not supported, as it uses a stricter security model on <foreignObject> tag. Suggested workaround is to use toSvg and render on the server.
There might some day exist (or maybe already exists?) a simple and standard way of exporting parts of the HTML to image (and then this script can only serve as an evidence of all the hoops I had to jump through in order to get such obvious thing done) but I haven't found one so far.
This library uses a feature of SVG that allows having arbitrary HTML content inside of the <foreignObject> tag. So, in order to render that DOM node for you, following steps are taken:
Pull requests and stars are highly welcome.
For bugs and feature requests, please create an issue.
Author: bubkoo
Download Link: Download The Source Code
Official Website: https://github.com/bubkoo/html-to-image
License: MIT
#Image #HTML5 #Canvas #SVG
1664456280
Signature Pad is a JavaScript library for drawing smooth signatures. It's HTML5 canvas based and uses variable width Bézier curve interpolation based on Smoother Signatures post by Square. It works in all modern desktop and mobile browsers and doesn't depend on any external libraries.
You can install the latest release using npm:
npm install --save signature_pad
or Yarn:
yarn add signature_pad
You can also add it directly to your page using <script>
tag:
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.0.0/dist/signature_pad.umd.min.js"></script>
You can select a different version at https://www.jsdelivr.com/package/npm/signature_pad.
This library is provided as UMD (Universal Module Definition) and ES6 module.
const canvas = document.querySelector("canvas");
const signaturePad = new SignaturePad(canvas);
// Returns signature image as data URL (see https://mdn.io/todataurl for the list of possible parameters)
signaturePad.toDataURL(); // save image as PNG
signaturePad.toDataURL("image/jpeg"); // save image as JPEG
signaturePad.toDataURL("image/jpeg", 0.5); // save image as JPEG with 0.5 image quality
signaturePad.toDataURL("image/svg+xml"); // save image as SVG
// Draws signature image from data URL (mostly uses https://mdn.io/drawImage under-the-hood)
// NOTE: This method does not populate internal data structure that represents drawn signature. Thus, after using #fromDataURL, #toData won't work properly.
signaturePad.fromDataURL("data:image/png;base64,iVBORw0K...");
// Draws signature image from data URL and alters it with the given options
signaturePad.fromDataURL("data:image/png;base64,iVBORw0K...", { ratio: 1, width: 400, height: 200, xOffset: 100, yOffset: 50 });
// Returns signature image as an array of point groups
const data = signaturePad.toData();
// Draws signature image from an array of point groups
signaturePad.fromData(data);
// Draws signature image from an array of point groups, without clearing your existing image (clear defaults to true if not provided)
signaturePad.fromData(data, { clear: false });
// Clears the canvas
signaturePad.clear();
// Returns true if canvas is empty, otherwise returns false
signaturePad.isEmpty();
// Unbinds all event handlers
signaturePad.off();
// Rebinds all event handlers
signaturePad.on();
dotSize
(float or function) Radius of a single dot.
minWidth
(float) Minimum width of a line. Defaults to 0.5
.
maxWidth
(float) Maximum width of a line. Defaults to 2.5
.
throttle
(integer) Draw the next point at most once per every x
milliseconds. Set it to 0
to turn off throttling. Defaults to 16
.
minDistance
(integer) Add the next point only if the previous one is farther than x
pixels. Defaults to 5
.
backgroundColor
(string) Color used to clear the background. Can be any color format accepted by context.fillStyle
. Defaults to "rgba(0,0,0,0)"
(transparent black). Use a non-transparent color e.g. "rgb(255,255,255)"
(opaque white) if you'd like to save signatures as JPEG images.
penColor
(string) Color used to draw the lines. Can be any color format accepted by context.fillStyle
. Defaults to "black"
.
velocityFilterWeight
(float) Weight used to modify new velocity based on the previous velocity. Defaults to 0.7
.
You can set options during initialization:
const signaturePad = new SignaturePad(canvas, {
minWidth: 5,
maxWidth: 10,
penColor: "rgb(66, 133, 244)"
});
or during runtime:
const signaturePad = new SignaturePad(canvas);
signaturePad.minWidth = 5;
signaturePad.maxWidth = 10;
signaturePad.penColor = "rgb(66, 133, 244)";
beginStroke
Triggered before stroke begins.
endStroke
Triggered after stroke ends.
beforeUpdateStroke
Triggered before stroke update.
afterUpdateStroke
Triggered after stroke update.
You can add listeners to events with .addEventListener
:
const signaturePad = new SignaturePad(canvas);
signaturePad.addEventListener("beginStroke", () => {
console.log("Signature started");
}, { once: true });
To correctly handle canvas on low and high DPI screens one has to take devicePixelRatio
into account and scale the canvas accordingly. This scaling is also necessary to properly display signatures loaded via SignaturePad#fromDataURL
. Here's an example how it can be done:
function resizeCanvas() {
const ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
canvas.getContext("2d").scale(ratio, ratio);
signaturePad.clear(); // otherwise isEmpty() might return incorrect value
}
window.addEventListener("resize", resizeCanvas);
resizeCanvas();
Instead of resize
event you can listen to screen orientation change, if you're using this library only on mobile devices. You can also throttle the resize
event - you can find some examples on this MDN page.
When you modify width or height of a canvas, it will be automatically cleared by the browser. SignaturePad doesn't know about it by itself, so you can call signaturePad.fromData(signaturePad.toData())
to reset the drawing, or signaturePad.clear()
to make sure that signaturePad.isEmpty()
returns correct value in this case.
This clearing of the canvas by the browser can be annoying, especially on mobile devices e.g. when screen orientation is changed. There are a few workarounds though, e.g. you can lock screen orientation, or read an image from the canvas before resizing it and write the image back after.
If you are not familiar with data URI scheme, you can read more about it on Wikipedia.
There are 2 ways you can handle data URI encoded images.
You could simply store it in your database as a string and display it in HTML like this:
<img src="data:image/png;base64,iVBORw0K..." />
but this way has many disadvantages - it's not easy to get image dimensions, you can't manipulate it e.g. to create a thumbnail and it also has some performance issues on mobile devices.
Thus, more common way is to decode it and store as a file. Here's an example in Ruby:
require "base64"
data_uri = "data:image/png;base64,iVBORw0K..."
encoded_image = data_uri.split(",")[1]
decoded_image = Base64.decode64(encoded_image)
File.open("signature.png", "wb") { |f| f.write(decoded_image) }
Here's an example in PHP:
$data_uri = "data:image/png;base64,iVBORw0K...";
$encoded_image = explode(",", $data_uri)[1];
$decoded_image = base64_decode($encoded_image);
file_put_contents("signature.png", $decoded_image);
Here's an example in C# for ASP.NET:
var dataUri = "data:image/png;base64,iVBORw0K...";
var encodedImage = dataUri.Split(',')[1];
var decodedImage = Convert.FromBase64String(encodedImage);
System.IO.File.WriteAllBytes("signature.png", decodedImage);
If you'd like to remove (trim) empty space around a signature, you can do it on the server side or the client side. On the server side you can use e.g. ImageMagic and its trim
option: convert -trim input.jpg output.jpg
. If you don't have access to the server, or just want to trim the image before submitting it to the server, you can do it on the client side as well. There are a few examples how to do it, e.g. here or here and there's also a tiny library trim-canvas that provides this functionality.
Demo: https://jsfiddle.net/szimek/d6a78gwq/
Demo works in desktop and mobile browsers. You can check out its source code for some tips on how to handle window resize and high DPI screens. You can also find more about the latter in HTML5 Rocks tutorial.
Author: Szimek
Source Code: https://github.com/szimek/signature_pad
License: MIT license