├── dev ├── style.css └── index.html ├── .gitignore ├── d3_handwriting.gif ├── src ├── app.coffee ├── handwritten │ └── write.coffee └── dev │ └── dev.coffee ├── .gitattributes ├── example.html ├── bower.json ├── package.json ├── gulpfile.js ├── handwritten.min.js ├── graph.json ├── README.md ├── app.js └── handwritten.dev.js /dev/style.css: -------------------------------------------------------------------------------- 1 | svg path{ 2 | fill: none; 3 | stroke-width: 3; 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | bower_components 6 | 7 | -------------------------------------------------------------------------------- /d3_handwriting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxArturo/d3_handwriting/HEAD/d3_handwriting.gif -------------------------------------------------------------------------------- /src/app.coffee: -------------------------------------------------------------------------------- 1 | Handwritten = window.Handwritten or {} 2 | window.Handwritten = Handwritten 3 | 4 | # general settings 5 | Handwritten.dev = 6 | enabled: true 7 | mountPoint: null 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files you want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.md text 7 | 8 | # Declare files that will always have CRLF line endings on checkout. 9 | 10 | # Denote all files that are truly binary and should not be modified. 11 | *.png binary 12 | *.jpg binary 13 | *.gif binary 14 | -------------------------------------------------------------------------------- /example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Dev environment for handwritten.js

13 | 14 | -------------------------------------------------------------------------------- /dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Dev environment for handwritten.js

13 | 14 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js_handwriting", 3 | "version": "1.0.0", 4 | "homepage": "https://github.com/maxArturo/d3_handwriting", 5 | "authors": [ 6 | "Max Alcala " 7 | ], 8 | "description": "Handwritten svg, with d3.js", 9 | "main": "js/handwritten.js", 10 | "moduleType": [], 11 | "keywords": [ 12 | "handwritten", 13 | "d3" 14 | ], 15 | "license": "MIT", 16 | "private": true, 17 | "ignore": [ 18 | "**/.*", 19 | "node_modules", 20 | "bower_components", 21 | "test", 22 | "tests" 23 | ], 24 | "dependencies": { 25 | "d3": "~3.5.6", 26 | "dat-gui": "dataarts/dat.gui#~0.5.1", 27 | "lodash": "~3.10.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js_handwriting", 3 | "version": "1.0.0", 4 | "description": "Handwritten SVG glyps, using d3.js", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/maxArturo/d3_handwriting.git" 12 | }, 13 | "keywords": [ 14 | "d3.js", 15 | "handwriting" 16 | ], 17 | "author": "Max Alcala (@maxArturoAS)", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/maxArturo/d3_handwriting/issues" 21 | }, 22 | "homepage": "https://github.com/maxArturo/d3_handwriting#readme", 23 | "devDependencies": { 24 | "coffee": "^1.2.0", 25 | "gulp": "^3.9.0", 26 | "gulp-coffee": "^2.3.1", 27 | "gulp-concat": "^2.6.0", 28 | "gulp-if": "^2.0.0", 29 | "gulp-rename": "^1.2.2", 30 | "gulp-sourcemaps": "^1.6.0", 31 | "gulp-uglify": "^1.4.1", 32 | "gulp-util": "^3.0.6", 33 | "yargs": "^3.26.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | argv = require('yargs').argv, 3 | coffee = require('gulp-coffee'), 4 | sourcemaps = require('gulp-sourcemaps'), 5 | concat = require('gulp-concat'), 6 | rename = require('gulp-rename'), 7 | uglify = require('gulp-uglify'), 8 | gutil = require('gulp-util'), 9 | gulpif = require('gulp-if'); 10 | 11 | var prodFiles = ['src/app.coffee', 'src/handwritten/*.coffee']; 12 | var devFiles = prodFiles.concat(['src/dev/dev.coffee']); 13 | 14 | var compile = function(){ 15 | gulp.src(argv.production ? prodFiles : devFiles) 16 | .pipe(sourcemaps.init()) 17 | .pipe(coffee({bare: true}).on('error', gutil.log)) 18 | .pipe(concat('handwritten.dev.js')) 19 | .pipe(sourcemaps.write()) 20 | .pipe(gulpif(argv.production, rename('handwritten.min.js'))) 21 | .pipe(gulpif(argv.production, uglify())) 22 | .pipe(gulp.dest('.')); 23 | } 24 | 25 | gulp.task('build', compile(prodFiles)); 26 | 27 | gulp.task('watch', function(){ 28 | gulp.watch('src/**/*.coffee', ['build']) 29 | }); 30 | 31 | gulp.task('default', ['build', 'watch']); 32 | -------------------------------------------------------------------------------- /handwritten.min.js: -------------------------------------------------------------------------------- 1 | var Handwritten;Handwritten=window.Handwritten||{},window.Handwritten=Handwritten,Handwritten.dev={enabled:!0,mountPoint:null};var hasProp={}.hasOwnProperty;Handwritten.writing=function(){var t,n,r,e,a,i,o,u,l,h,c;return e=function(t){return t.each(function(t,n){var e,a,o,l,h,c;e=d3.select(this),e.selectAll("path").remove(),h=[];for(a in t)hasProp.call(t,a)&&(c=t[a],o=u(c),h.push(function(){var t,n,a;for(a=[],t=0,n=o.length;n>t;t++)l=o[t],a.push(e.append("path").attr("d",i(l)).attr("stroke",r));return a}()));return h})},i=d3.svg.line().x(function(t){return t.x}).y(function(t){return t.y}).interpolate("basis"),o={top:20,right:20,bottom:20,left:20},c=900-o.left-o.right,a=500-o.bottom-o.top,h=5,l=100,t=0,r="#000000",e.width=function(t){return arguments.length?(c=t,e):c},e.height=function(t){return arguments.length?(a=t,e):a},e.variability=function(t){return arguments.length?(h=t,e):h},e.transform=function(t){return arguments.length?(l=t,e):l},e.baseline=function(n){return arguments.length?(t=n,e):t},e.color=function(t){return arguments.length?(r=t,e):r},u=function(t){var r,e,a,i;for(i=_.cloneDeep(t),r=0,e=i.length;e>r;r++)a=i[r],a=a.map(n);return i},n=function(n){return n.x=(n.x+Math.random()*h-h/2)*(l/100),n.y=(n.y+Math.random()*h-h/2)*(l/100)+t,n},e}; -------------------------------------------------------------------------------- /graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | [ 4 | { 5 | "x": 65.00141906738281, 6 | "y": 179.5014190673828 7 | }, 8 | { 9 | "x": 123.50141906738281, 10 | "y": 89.50141906738281 11 | }, 12 | { 13 | "x": 140.5014190673828, 14 | "y": 66.00141906738281 15 | }, 16 | { 17 | "x": 150.5014190673828, 18 | "y": 70.50141906738281 19 | }, 20 | { 21 | "x": 177.0014190673828, 22 | "y": 115.5014190673828 23 | }, 24 | { 25 | "x": 183.0014190673828, 26 | "y": 178.0014190673828 27 | } 28 | ], 29 | [ 30 | { 31 | "x": 100.00283813476562, 32 | "y": 123.00283813476562 33 | }, 34 | { 35 | "x": 165.00283813476562, 36 | "y": 126.00283813476562 37 | }, 38 | { 39 | "x": 172.00283813476562, 40 | "y": 120.00283813476562 41 | } 42 | ] 43 | ], 44 | "B": [ 45 | [ 46 | { 47 | "x": 223.00283813476565, 48 | "y": 182.00283813476562 49 | }, 50 | { 51 | "x": 189.00283813476562, 52 | "y": 49.00284194946289 53 | }, 54 | { 55 | "x": 255.00283813476562, 56 | "y": 35.00284194946289 57 | }, 58 | { 59 | "x": 327.0028381347656, 60 | "y": 72.00283813476562 61 | }, 62 | { 63 | "x": 266.0028381347656, 64 | "y": 101.00283813476562 65 | }, 66 | { 67 | "x": 205.00283813476562, 68 | "y": 104.00283813476562 69 | }, 70 | { 71 | "x": 323.0028381347656, 72 | "y": 133.00283813476562 73 | }, 74 | { 75 | "x": 304.0028381347656, 76 | "y": 182.00283813476562 77 | }, 78 | { 79 | "x": 253.00283813476562, 80 | "y": 182.00283813476562 81 | }, 82 | { 83 | "x": 230.00283813476562, 84 | "y": 172.00283813476562 85 | } 86 | ] 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /src/handwritten/write.coffee: -------------------------------------------------------------------------------- 1 | Handwritten.writing = -> 2 | 3 | draw = (selection) -> 4 | selection.each( (d, i) -> 5 | element = d3.select(@) 6 | element.selectAll('path').remove() 7 | 8 | for own letter, values of d 9 | letterPaths = randomize(values) 10 | for path in letterPaths 11 | element.append('path') 12 | .attr('d', lineFunction(path)) 13 | .attr('stroke', color) 14 | ) 15 | 16 | lineFunction = d3.svg.line() 17 | .x((d) -> 18 | d.x 19 | ).y((d) -> 20 | d.y 21 | ).interpolate('basis') 22 | 23 | margin =( 24 | top: 20 25 | right: 20 26 | bottom: 20 27 | left: 20) 28 | 29 | width = 900 - margin.left - margin.right 30 | height = 500 - margin.bottom - margin.top 31 | variability = 5 32 | transform = 100 33 | baseline = 0 34 | color = '#000000' 35 | 36 | # accessor functions 37 | draw.width = (value) -> 38 | return width unless arguments.length 39 | width = value 40 | draw 41 | 42 | draw.height = (value) -> 43 | return height unless arguments.length 44 | height = value 45 | draw 46 | 47 | draw.variability = (value) -> 48 | return variability unless arguments.length 49 | variability = value 50 | draw 51 | 52 | draw.transform = (value) -> 53 | return transform unless arguments.length 54 | transform = value 55 | draw 56 | 57 | draw.baseline = (value) -> 58 | return baseline unless arguments.length 59 | baseline = value 60 | draw 61 | 62 | draw.color = (value) -> 63 | return color unless arguments.length 64 | color = value 65 | draw 66 | 67 | randomize = (letterPaths) -> 68 | paths = _.cloneDeep(letterPaths) 69 | for path in paths 70 | path = path.map(coerce) 71 | paths 72 | 73 | coerce = (d) -> 74 | d.x = (d.x + Math.random() * variability - variability / 2) * 75 | (transform / 100) 76 | d.y = (d.y + Math.random() * variability - variability / 2) * 77 | (transform / 100) + baseline; 78 | d 79 | 80 | # return main update function 81 | draw 82 | -------------------------------------------------------------------------------- /src/dev/dev.coffee: -------------------------------------------------------------------------------- 1 | if Handwritten.dev.enabled 2 | d3.json('../graph.json', (error, letters) -> 3 | Handwritten.dev.mountPoint = d3.select('body').append('svg') 4 | .attr('width', Handwritten.writing().width()) 5 | .attr('height', Handwritten.writing().height()) 6 | .datum(letters) 7 | .on("click", Handwritten.dev.addCoordinates); 8 | 9 | Handwritten.dev.gui = new dat.GUI() 10 | Handwritten.dev.params = (-> 11 | @.variability = 5 12 | @.transform = 100 13 | @.baseline = 0 14 | @.color = '#000000' 15 | @ 16 | ).bind(@) 17 | 18 | Handwritten.dev.input = new Handwritten.dev.params() 19 | 20 | (-> 21 | drawing = Handwritten.writing() 22 | mountPoint = Handwritten.dev.mountPoint 23 | Handwritten.dev.gui_controller = ( 24 | variability: Handwritten.dev.gui.add(Handwritten.dev.input, 25 | 'variability', 0, 100).onChange( 26 | -> 27 | drawing.variability(Handwritten.dev.input.variability) 28 | drawing(mountPoint)) 29 | transform: Handwritten.dev.gui.add(Handwritten.dev.input, 'transform', 0, 200).onChange( 30 | -> 31 | drawing.transform(Handwritten.dev.input.transform) 32 | drawing(mountPoint)) 33 | baseline: Handwritten.dev.gui.add(Handwritten.dev.input, 'baseline', 0, 100).onChange( 34 | -> 35 | drawing.baseline(Handwritten.dev.input.baseline) 36 | drawing(mountPoint)) 37 | color: Handwritten.dev.gui.add(Handwritten.dev.input, 'color').onChange( 38 | (value) -> 39 | drawing.color(Handwritten.dev.input.color) 40 | drawing(mountPoint)) 41 | ) 42 | )() 43 | ) 44 | 45 | Handwritten.dev.addCoordinates =( -> 46 | coordinates = d3.mouse(@) 47 | if !@data.newLetter 48 | @data.newLetter = [[]] 49 | 50 | @data.newLetter[0].push( 51 | x: coordinates[0] / Handwritten.writing().transform() * 100, 52 | y: coordinates[1] / Handwritten.writing().transform() * 100 53 | ) 54 | Handwritten.writing().draw(Handwritten.dev.mountPoint) 55 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## D3 Handwriting type generator 2 | 3 | Have you ever noticed those [types](http://www.google.com/fonts/specimen/Rock+Salt) that make you think like they are handwritten, only to find same-letter multiples together and have the illusion completely shattered? 4 | 5 | With static types, there are simply no satisfactory replacements for a handwritten type. I find that completely upending, and to scratch that itch I've turned to D3 for a more 'proper' implementation of an actual 'handwritten' typeset - one that changes upon rendering. 6 | 7 | ![](https://raw.githubusercontent.com/maxArturo/d3_handwriting/master/d3_handwriting.gif) 8 | 9 | D3 takes care of generating SVG lines for the glyphs, whose coordinates are randomized runtime and interpolated using [basis interpolation](https://en.wikipedia.org/wiki/B-spline) to achieve that good ol' scrawl feel. It also (almost) guarantees that every rendering will be unique - just like every scribble is. 10 | 11 | 12 | It is worthwhile to note that this is completely preposterous to use as an actual typeface, as it would require JavaScript upon any given display (say, your birthday card). However, this does lend itself to more meaningful applications, such as rendering and then transferring to static media (PDF, say) multiple times over. 13 | 14 | I am looking for a proper glyph implementation - one that can be projected and transformed. My current process (painting a glyph with my mouse on the SVG element and saving the coordinates) is not close to optimal, but it works for now. If anyone knows of a better standard way (taking a standard Unicode implementation and parsing out to a SVG:line) do let me know. 15 | 16 | ### Development 17 | After `git clone`, run `npm install` and `bower install` to add the dev dependencies. Then `gulp` will translate the CoffeeScript and watch for any changes. 18 | 19 | Without the `--production` option, a dev version of `handwritten.js` is built, which includes default `
`s for the glyphs to draw on, along with dat.GUI to play with variables. There is a handy `index.html` file under the dev folder where you can experiment with your changes - serve the entire repo folder with your [favorite server](https://gist.github.com/willurd/5720255) and browse to see your changes. 20 | 21 | ### Build release 22 | Run `gulp --production` to generate an uglified, minifed version ready for release. 23 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /* global d3, $, dat */ 2 | 'use strict'; 3 | 4 | var margin = { 5 | top: 20, 6 | right: 20, 7 | bottom: 20, 8 | left: 20 9 | }, 10 | width = 900 - margin.left - margin.right, 11 | height = 500 - margin.bottom - margin.top, 12 | lineData; 13 | 14 | var svg = d3.select('body').append('svg') 15 | .attr('width', width) 16 | .attr('height', height) 17 | .on("click", addCoordinates); 18 | 19 | // gui stuff 20 | var params = function() { 21 | this.variability = 5; 22 | this.transform = 100; 23 | this.baseline = 0; 24 | this.color = '#000000'; 25 | }; 26 | var input = new params(); 27 | var gui = new dat.GUI({ 28 | height: 5 * 32 - 1 29 | }); 30 | 31 | var controller = { 32 | variability: gui.add(input, 'variability', 0, 100) 33 | .onChange(function() { 34 | update(); 35 | }), 36 | 37 | transform: gui.add(input, 'transform', 0, 200) 38 | .onChange(function() { 39 | update(); 40 | }), 41 | baseline: gui.add(input, 'baseline', 0, 100) 42 | .onChange(function() { 43 | update(); 44 | }), 45 | color: gui.addColor(input, 'color') 46 | .onChange(function(value) { 47 | svg.selectAll('path').attr('stroke', value); 48 | }), 49 | }; 50 | 51 | var lineFunction = d3.svg.line() 52 | .x(function(d) { 53 | return d.x; 54 | }) 55 | .y(function(d) { 56 | return d.y; 57 | }) 58 | .interpolate('basis'); 59 | 60 | d3.json('graph.json', function(error, letters) { 61 | lineData = letters; 62 | update(); 63 | }); 64 | 65 | function update() { 66 | svg.selectAll('path').remove(); 67 | 68 | //for each letter 69 | for (var letter in lineData) { 70 | if (lineData.hasOwnProperty(letter)) { 71 | var letterPaths = transform(lineData[letter]); 72 | 73 | for (var i = letterPaths.length - 1; i >= 0; i--) { 74 | svg.append('path') 75 | .attr('d', lineFunction(letterPaths[i])) 76 | .attr('stroke', input.color); 77 | } 78 | } 79 | } 80 | } 81 | 82 | function addCoordinates() { 83 | var coordinates = d3.mouse(this); 84 | if (!lineData.newLetter) { 85 | lineData.newLetter = [ 86 | [] 87 | ]; 88 | } 89 | 90 | lineData.newLetter[0].push({ 91 | x: coordinates[0] / input.transform * 100, 92 | y: coordinates[1] / input.transform * 100 93 | }); 94 | update(); 95 | } 96 | 97 | function transform(letterPaths) { 98 | var paths = _.cloneDeep(letterPaths); 99 | for (var i = paths.length - 1; i >= 0; i--) { 100 | paths[i].map(coerce); 101 | } 102 | return paths; 103 | } 104 | 105 | // randomizes the points 106 | function coerce(d) { 107 | d.x = (d.x + Math.random() * input.variability - input.variability / 2) * 108 | (input.transform / 100); 109 | d.y = (d.y + Math.random() * input.variability - input.variability / 2) * 110 | (input.transform / 100) + input.baseline; 111 | return d; 112 | } 113 | -------------------------------------------------------------------------------- /handwritten.dev.js: -------------------------------------------------------------------------------- 1 | var Handwritten; 2 | 3 | Handwritten = window.Handwritten || {}; 4 | 5 | window.Handwritten = Handwritten; 6 | 7 | Handwritten.dev = { 8 | enabled: true, 9 | mountPoint: null 10 | }; 11 | 12 | var hasProp = {}.hasOwnProperty; 13 | 14 | Handwritten.writing = function() { 15 | var baseline, coerce, color, draw, height, lineFunction, margin, randomize, transform, variability, width; 16 | draw = function(selection) { 17 | return selection.each(function(d, i) { 18 | var element, letter, letterPaths, path, results, values; 19 | element = d3.select(this); 20 | element.selectAll('path').remove(); 21 | results = []; 22 | for (letter in d) { 23 | if (!hasProp.call(d, letter)) continue; 24 | values = d[letter]; 25 | letterPaths = randomize(values); 26 | results.push((function() { 27 | var j, len, results1; 28 | results1 = []; 29 | for (j = 0, len = letterPaths.length; j < len; j++) { 30 | path = letterPaths[j]; 31 | results1.push(element.append('path').attr('d', lineFunction(path)).attr('stroke', color)); 32 | } 33 | return results1; 34 | })()); 35 | } 36 | return results; 37 | }); 38 | }; 39 | lineFunction = d3.svg.line().x(function(d) { 40 | return d.x; 41 | }).y(function(d) { 42 | return d.y; 43 | }).interpolate('basis'); 44 | margin = { 45 | top: 20, 46 | right: 20, 47 | bottom: 20, 48 | left: 20 49 | }; 50 | width = 900 - margin.left - margin.right; 51 | height = 500 - margin.bottom - margin.top; 52 | variability = 5; 53 | transform = 100; 54 | baseline = 0; 55 | color = '#000000'; 56 | draw.width = function(value) { 57 | if (!arguments.length) { 58 | return width; 59 | } 60 | width = value; 61 | return draw; 62 | }; 63 | draw.height = function(value) { 64 | if (!arguments.length) { 65 | return height; 66 | } 67 | height = value; 68 | return draw; 69 | }; 70 | draw.variability = function(value) { 71 | if (!arguments.length) { 72 | return variability; 73 | } 74 | variability = value; 75 | return draw; 76 | }; 77 | draw.transform = function(value) { 78 | if (!arguments.length) { 79 | return transform; 80 | } 81 | transform = value; 82 | return draw; 83 | }; 84 | draw.baseline = function(value) { 85 | if (!arguments.length) { 86 | return baseline; 87 | } 88 | baseline = value; 89 | return draw; 90 | }; 91 | draw.color = function(value) { 92 | if (!arguments.length) { 93 | return color; 94 | } 95 | color = value; 96 | return draw; 97 | }; 98 | randomize = function(letterPaths) { 99 | var j, len, path, paths; 100 | paths = _.cloneDeep(letterPaths); 101 | for (j = 0, len = paths.length; j < len; j++) { 102 | path = paths[j]; 103 | path = path.map(coerce); 104 | } 105 | return paths; 106 | }; 107 | coerce = function(d) { 108 | d.x = (d.x + Math.random() * variability - variability / 2) * (transform / 100); 109 | d.y = (d.y + Math.random() * variability - variability / 2) * (transform / 100) + baseline; 110 | return d; 111 | }; 112 | return draw; 113 | }; 114 | 115 | if (Handwritten.dev.enabled) { 116 | d3.json('../graph.json', function(error, letters) { 117 | Handwritten.dev.mountPoint = d3.select('body').append('svg').attr('width', Handwritten.writing().width()).attr('height', Handwritten.writing().height()).datum(letters).on("click", Handwritten.dev.addCoordinates); 118 | Handwritten.dev.gui = new dat.GUI(); 119 | Handwritten.dev.params = (function() { 120 | this.variability = 5; 121 | this.transform = 100; 122 | this.baseline = 0; 123 | this.color = '#000000'; 124 | return this; 125 | }).bind(this); 126 | Handwritten.dev.input = new Handwritten.dev.params(); 127 | return (function() { 128 | var drawing, mountPoint; 129 | drawing = Handwritten.writing(); 130 | mountPoint = Handwritten.dev.mountPoint; 131 | return Handwritten.dev.gui_controller = { 132 | variability: Handwritten.dev.gui.add(Handwritten.dev.input, 'variability', 0, 100).onChange(function() { 133 | drawing.variability(Handwritten.dev.input.variability); 134 | return drawing(mountPoint); 135 | }), 136 | transform: Handwritten.dev.gui.add(Handwritten.dev.input, 'transform', 0, 200).onChange(function() { 137 | drawing.transform(Handwritten.dev.input.transform); 138 | return drawing(mountPoint); 139 | }), 140 | baseline: Handwritten.dev.gui.add(Handwritten.dev.input, 'baseline', 0, 100).onChange(function() { 141 | drawing.baseline(Handwritten.dev.input.baseline); 142 | return drawing(mountPoint); 143 | }), 144 | color: Handwritten.dev.gui.add(Handwritten.dev.input, 'color').onChange(function(value) { 145 | drawing.color(Handwritten.dev.input.color); 146 | return drawing(mountPoint); 147 | }) 148 | }; 149 | })(); 150 | }); 151 | Handwritten.dev.addCoordinates = (function() { 152 | var coordinates; 153 | coordinates = d3.mouse(this); 154 | if (!this.data.newLetter) { 155 | this.data.newLetter = [[]]; 156 | } 157 | this.data.newLetter[0].push({ 158 | x: coordinates[0] / Handwritten.writing().transform() * 100, 159 | y: coordinates[1] / Handwritten.writing().transform() * 100 160 | }); 161 | return Handwritten.writing().draw(Handwritten.dev.mountPoint); 162 | }); 163 | } 164 | 165 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFwcC5jb2ZmZWUiLCJ3cml0ZS5jb2ZmZWUiLCJkZXYuY29mZmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQUE7O0FBQUEsV0FBQSxHQUFjLE1BQU0sQ0FBQyxXQUFQLElBQXNCOztBQUNwQyxNQUFNLENBQUMsV0FBUCxHQUFxQjs7QUFHckIsV0FBVyxDQUFDLEdBQVosR0FDRTtFQUFBLE9BQUEsRUFBUyxJQUFUO0VBQ0EsVUFBQSxFQUFZLElBRFo7OztBQ0xGLElBQUE7O0FBQUEsV0FBVyxDQUFDLE9BQVosR0FBc0IsU0FBQTtBQUVwQixNQUFBO0VBQUEsSUFBQSxHQUFPLFNBQUMsU0FBRDtXQUNMLFNBQVMsQ0FBQyxJQUFWLENBQWdCLFNBQUMsQ0FBRCxFQUFJLENBQUo7QUFDZCxVQUFBO01BQUEsT0FBQSxHQUFVLEVBQUUsQ0FBQyxNQUFILENBQVUsSUFBVjtNQUNWLE9BQU8sQ0FBQyxTQUFSLENBQWtCLE1BQWxCLENBQXlCLENBQUMsTUFBMUIsQ0FBQTtBQUVBO1dBQUEsV0FBQTs7O1FBQ0UsV0FBQSxHQUFjLFNBQUEsQ0FBVSxNQUFWOzs7QUFDZDtlQUFBLDZDQUFBOzswQkFDRSxPQUFPLENBQUMsTUFBUixDQUFlLE1BQWYsQ0FDRSxDQUFDLElBREgsQ0FDUSxHQURSLEVBQ2EsWUFBQSxDQUFhLElBQWIsQ0FEYixDQUVFLENBQUMsSUFGSCxDQUVRLFFBRlIsRUFFa0IsS0FGbEI7QUFERjs7O0FBRkY7O0lBSmMsQ0FBaEI7RUFESztFQWFQLFlBQUEsR0FBZSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQVAsQ0FBQSxDQUNiLENBQUMsQ0FEWSxDQUNWLFNBQUMsQ0FBRDtXQUNELENBQUMsQ0FBQztFQURELENBRFUsQ0FHWixDQUFDLENBSFcsQ0FHVCxTQUFDLENBQUQ7V0FDRixDQUFDLENBQUM7RUFEQSxDQUhTLENBS1osQ0FBQyxXQUxXLENBS0MsT0FMRDtFQU9mLE1BQUEsR0FDRTtJQUFBLEdBQUEsRUFBSyxFQUFMO0lBQ0EsS0FBQSxF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RDtNQUNBLENBQUEsRUFBRyxXQUFZLENBQUEsQ0FBQSxDQUFaLEdBQWlCLFdBQVcsQ0FBQyxPQUFaLENBQUEsQ0FBcUIsQ0FBQyxTQUF0QixDQUFBLENBQWpCLEdBQXFELEdBRHhEO0tBREY7V0FJQSxXQUFXLENBQUMsT0FBWixDQUFBLENBQXFCLENBQUMsSUFBdEIsQ0FBMkIsV0FBVyxDQUFDLEdBQUcsQ0FBQyxVQUEzQztFQVRnQyxDQUFGLEVBNUNsQyIsImZpbGUiOiJoYW5kd3JpdHRlbi5kZXYuanMiLCJzb3VyY2VzQ29udGVudCI6WyJIYW5kd3JpdHRlbiA9IHdpbmRvdy5IYW5kd3JpdHRlbiBvciB7fVxud2luZG93LkhhbmR3cml0dGVuID0gSGFuZHdyaXR0ZW5cblxuIyBnZW5lcmFsIHNldHRpbmdzXG5IYW5kd3JpdHRlbi5kZXYgPVxuICBlbmFibGVkOiB0cnVlXG4gIG1vdW50UG9pbnQ6IG51bGxcbiIsIkhhbmR3cml0dGVuLndyaXRpbmcgPSAtPlxuXG4gIGRyYXcgPSAoc2VsZWN0aW9uKSAtPlxuICAgIHNlbGVjdGlvbi5lYWNoKCAoZCwgaSkgLT5cbiAgICAgIGVsZW1lbnQgPSBkMy5zZWxlY3QoQClcbiAgICAgIGVsZW1lbnQuc2VsZWN0QWxsKCdwYXRoJykucmVtb3ZlKClcblxuICAgICAgZm9yIG93biBsZXR0ZXIsIHZhbHVlcyBvZiBkXG4gICAgICAgIGxldHRlclBhdGhzID0gcmFuZG9taXplKHZhbHVlcylcbiAgICAgICAgZm9yIHBhdGggaW4gbGV0dGVyUGF0aHNcbiAgICAgICAgICBlbGVtZW50LmFwcGVuZCgncGF0aCcpXG4gICAgICAgICAgICAuYXR0cignZCcsIGxpbmVGdW5jdGlvbihwYXRoKSlcbiAgICAgICAgICAgIC5hdHRyKCdzdHJva2UnLCBjb2xvcilcbiAgICApXG5cbiAgbGluZUZ1bmN0aW9uID0gZDMuc3ZnLmxpbmUoKVxuICAgIC54KChkKSAtPlxuICAgICAgZC54XG4gICAgKS55KChkKSAtPlxuICAgICAgZC55XG4gICAgKS5pbnRlcnBvbGF0ZSgnYmFzaXMnKVxuXG4gIG1hcmdpbiA9KFxuICAgIHRvcDogMjBcbiAgICByaWdodDogMjBcbiAgICBib3R0b206IDIwXG4gICAgbGVmdDogMjApXG5cbiAgd2lkdGggPSA5MDAgLSBtYXJnaW4ubGVmdCAtIG1hcmdpbi5yaWdodFxuICBoZWlnaHQgPSA1MDAgLSBtYXJnaW4uYm90dG9tIC0gbWFyZ2luLnRvcFxuICB2YXJpYWJpbGl0eSA9IDVcbiAgdHJhbnNmb3JtID0gMTAwXG4gIGJhc2VsaW5lID0gMFxuICBjb2xvciA9ICcjMDAwMDAwJ1xuXG4gICMgYWNjZXNzb3IgZnVuY3Rpb25zXG4gIGRyYXcud2lkdGggPSAodmFsdWUpIC0+XG4gICAgcmV0dXJuIHdpZHRoIHVubGVzcyBhcmd1bWVudHMubGVuZ3RoXG4gICAgd2lkdGggPSB2YWx1ZVxuICAgIGRyYXdcblxuICBkcmF3LmhlaWdodCA9ICh2YWx1ZSkgLT5cbiAgICByZXR1cm4gaGVpZ2h0IHVubGVzcyBhcmd1bWVudHMubGVuZ3RoXG4gICAgaGVpZ2h0ID0gdmFsdWVcbiAgICBkcmF3XG5cbiAgZHJhdy52YXJpYWJpbGl0eSA9ICh2YWx1ZSkgLT5cbiAgICByZXR1cm4gdmFyaWFiaWxpdHkgdW5sZXNzIGFyZ3VtZW50cy5sZW5ndGhcbiAgICB2YXJpYWJpbGl0eSA9IHZhbHVlXG4gICAgZHJhd1xuXG4gIGRyYXcudHJhbnNmb3JtID0gKHZhbHVlKSAtPlxuICAgIHJldHVybiB0cmFuc2Zvcm0gdW5sZXNzIGFyZ3VtZW50cy5sZW5ndGhcbiAgICB0cmFuc2Zvcm0gPSB2YWx1ZVxuICAgIGRyYXdcblxuICBkcmF3LmJhc2VsaW5lID0gKHZhbHVlKSAtPlxuICAgIHJldHVybiBiYXNlbGluZSB1bmxlc3MgYXJndW1lbnRzLmxlbmd0aFxuICAgIGJhc2VsaW5lID0gdmFsdWVcbiAgICBkcmF3XG5cbiAgZHJhdy5jb2xvciA9ICh2YWx1ZSkgLT5cbiAgICByZXR1cm4gY29sb3IgdW5sZXNzIGFyZ3VtZW50cy5sZW5ndGhcbiAgICBjb2xvciA9IHZhbHVlXG4gICAgZHJhd1xuXG4gIHJhbmRvbWl6ZSA9IChsZXR0ZXJQYXRocykgLT5cbiAgICBwYXRocyA9IF8uY2xvbmVEZWVwKGxldHRlclBhdGhzKVxuICAgIGZvciBwYXRoIGluIHBhdGhzXG4gICAgICBwYXRoID0gcGF0aC5tYXAoY29lcmNlKVxuICAgIHBhdGhzXG5cbiAgY29lcmNlID0gKGQpIC0+XG4gICAgZC54ID0gKGQueCArIE1hdGgucmFuZG9tKCkgKiB2YXJpYWJpbGl0eSAtIHZhcmlhYmlsaXR5IC8gMikgKlxuICAgICAgKHRyYW5zZm9ybSAvIDEwMClcbiAgICBkLnkgPSAoZC55ICsgTWF0aC5yYW5kb20oKSAqIHZhcmlhYmlsaXR5IC0gdmFyaWFiaWxpdHkgLyAyKSAqXG4gICAgICAodHJhbnNmb3JtIC8gMTAwKSArIGJhc2VsaW5lO1xuICAgIGRcblxuICAjIHJldHVybiBtYWluIHVwZGF0ZSBmdW5jdGlvblxuICBkcmF3XG4iLCJpZiBIYW5kd3JpdHRlbi5kZXYuZW5hYmxlZFxuICBkMy5qc29uKCcuLi9ncmFwaC5qc29uJywgKGVycm9yLCBsZXR0ZXJzKSAtPlxuICAgIEhhbmR3cml0dGVuLmRldi5tb3VudFBvaW50ID0gZDMuc2VsZWN0KCdib2R5JykuYXBwZW5kKCdzdmcnKVxuICAgICAgLmF0dHIoJ3dpZHRoJywgSGFuZHdyaXR0ZW4ud3JpdGluZygpLndpZHRoKCkpXG4gICAgICAuYXR0cignaGVpZ2h0JywgSGFuZHdyaXR0ZW4ud3JpdGluZygpLmhlaWdodCgpKVxuICAgICAgLmRhdHVtKGxldHRlcnMpXG4gICAgICAub24oXCJjbGlja1wiLCBIYW5kd3JpdHRlbi5kZXYuYWRkQ29vcmRpbmF0ZXMpO1xuXG4gICAgSGFuZHdyaXR0ZW4uZGV2Lmd1aSA9IG5ldyBkYXQuR1VJKClcbiAgICBIYW5kd3JpdHRlbi5kZXYucGFyYW1zID0gKC0+XG4gICAgICBALnZhcmlhYmlsaXR5ID0gNVxuICAgICAgQC50cmFuc2Zvcm0gPSAxMDBcbiAgICAgIEAuYmFzZWxpbmUgPSAwXG4gICAgICBALmNvbG9yID0gJyMwMDAwMDAnXG4gICAgICBAXG4gICAgKS5iaW5kKEApXG5cbiAgICBIYW5kd3JpdHRlbi5kZXYuaW5wdXQgPSBuZXcgSGFuZHdyaXR0ZW4uZGV2LnBhcmFtcygpXG5cbiAgICAoLT5cbiAgICAgIGRyYXdpbmcgPSBIYW5kd3JpdHRlbi53cml0aW5nKClcbiAgICAgIG1vdW50UG9pbnQgPSBIYW5kd3JpdHRlbi5kZXYubW91bnRQb2ludFxuICAgICAgSGFuZHdyaXR0ZW4uZGV2Lmd1aV9jb250cm9sbGVyID0gKFxuICAgICAgICB2YXJpYWJpbGl0eTogSGFuZHdyaXR0ZW4uZGV2Lmd1aS5hZGQoSGFuZHdyaXR0ZW4uZGV2LmlucHV0LFxuICAgICAgICAgICd2YXJpYWJpbGl0eScsIDAsIDEwMCkub25DaGFuZ2UoXG4gICAgICAgICAgLT5cbiAgICAgICAgICAgIGRyYXdpbmcudmFyaWFiaWxpdHkoSGFuZHdyaXR0ZW4uZGV2LmlucHV0LnZhcmlhYmlsaXR5KVxuICAgICAgICAgICAgZHJhd2luZyhtb3VudFBvaW50KSlcbiAgICAgICAgdHJhbnNmb3JtOiBIYW5kd3JpdHRlbi5kZXYuZ3VpLmFkZChIYW5kd3JpdHRlbi5kZXYuaW5wdXQsICd0cmFuc2Zvcm0nLCAwLCAyMDApLm9uQ2hhbmdlKFxuICAgICAgICAgIC0+XG4gICAgICAgICAgICBkcmF3aW5nLnRyYW5zZm9ybShIYW5kd3JpdHRlbi5kZXYuaW5wdXQudHJhbnNmb3JtKVxuICAgICAgICAgICAgZHJhd2luZyhtb3VudFBvaW50KSlcbiAgICAgICAgYmFzZWxpbmU6IEhhbmR3cml0dGVuLmRldi5ndWkuYWRkKEhhbmR3cml0dGVuLmRldi5pbnB1dCwgJ2Jhc2VsaW5lJywgMCwgMTAwKS5vbkNoYW5nZShcbiAgICAgICAgICAtPlxuICAgICAgICAgICAgZHJhd2luZy5iYXNlbGluZShIYW5kd3JpdHRlbi5kZXYuaW5wdXQuYmFzZWxpbmUpXG4gICAgICAgICAgICBkcmF3aW5nKG1vdW50UG9pbnQpKVxuICAgICAgICBjb2xvcjogSGFuZHdyaXR0ZW4uZGV2Lmd1aS5hZGQoSGFuZHdyaXR0ZW4uZGV2LmlucHV0LCAnY29sb3InKS5vbkNoYW5nZShcbiAgICAgICAgICAodmFsdWUpIC0+XG4gICAgICAgICAgICBkcmF3aW5nLmNvbG9yKEhhbmR3cml0dGVuLmRldi5pbnB1dC5jb2xvcilcbiAgICAgICAgICAgIGRyYXdpbmcobW91bnRQb2ludCkpXG4gICAgICAgIClcbiAgICApKClcbiAgKVxuXG4gIEhhbmR3cml0dGVuLmRldi5hZGRDb29yZGluYXRlcyA9KCAtPlxuICAgIGNvb3JkaW5hdGVzID0gZDMubW91c2UoQClcbiAgICBpZiAhQGRhdGEubmV3TGV0dGVyXG4gICAgICBAZGF0YS5uZXdMZXR0ZXIgPSBbW11dXG5cbiAgICBAZGF0YS5uZXdMZXR0ZXJbMF0ucHVzaChcbiAgICAgIHg6IGNvb3JkaW5hdGVzWzBdIC8gSGFuZHdyaXR0ZW4ud3JpdGluZygpLnRyYW5zZm9ybSgpICogMTAwLFxuICAgICAgeTogY29vcmRpbmF0ZXNbMV0gLyBIYW5kd3JpdHRlbi53cml0aW5nKCkudHJhbnNmb3JtKCkgKiAxMDBcbiAgICApXG4gICAgSGFuZHdyaXR0ZW4ud3JpdGluZygpLmRyYXcoSGFuZHdyaXR0ZW4uZGV2Lm1vdW50UG9pbnQpXG4gICkiXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0= 166 | --------------------------------------------------------------------------------