Skip to content

Instantly share code, notes, and snippets.

@thecomputergirl
Forked from nitaku/README.md
Last active March 12, 2017 01:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thecomputergirl/0b74d8e376a0188223319e906d213cb7 to your computer and use it in GitHub Desktop.
Save thecomputergirl/0b74d8e376a0188223319e906d213cb7 to your computer and use it in GitHub Desktop.
Freehand Doodles

A simple freehand drawing application, based on Bostock's Line Drawing gist and Matteo Abrate’s BlockFreehand Drawing gist. Adapted with Computergirl's DoodleDoo gist

Use your stylus, fingers or mouse to draw. The color of the line can be changed by interacting with the color palette, and the canvas can be cleared by clicking the trash in the upper-right corner of the UI.

The application uses two stacked SVG elements, one for the UI and one for the canvas. This is used to disable drawing when interacting with UI elements.

Unlike Bostock's example, this application maintains a DOM-independent object to store all the drawing's data (just look at the JavaScript console each time you complete a line).

There is also an option for opacity in the line path. Looking to add a button for this function.

Colors are from Colorbrewer's Dark2 palette.

#canvas {
background-image: url("https://raw.githubusercontent.com/thecomputergirl/doodledoo/master/images/103WrightStreet_500_sml90.png");
background-repeat: no-repeat;
background-size: 100%;
background-position: left top;
margin-left: 0px;
}
#ui {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
.swatch {
pointer-events: all;
fill-opacity:.2;
stroke-width: .5px;
stroke: black;
}
.swatch.active {
stroke-width: 2px;
stroke: black;
}
.swatch {
cursor: pointer;
}
.btn {
pointer-events: all;
font-family: FontAwesome;
fill: #333;
font-size: 32px;
text-anchor: middle;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.btn:hover {
fill: DeepPink ;
cursor: pointer;
}
.line {
fill: none;
stroke-linejoin: miter;
stroke-linecap: miter;
stroke-miterlimit:4;
stroke-dasharray:none;
stroke-dashoffset:3;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Freehand Doodles</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<link rel="stylesheet" href="index.css">
<style>
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<svg id="canvas" width="960px" height="500px"></svg>
<svg id="ui" width="960px" height="500px"></svg>
</body>
<script src="index.js"></script>
</html>
// Generated by CoffeeScript 1.4.0
(function() {
var SWATCH_D, stroke_width, stroke_opacity, active_color, active_stroke_opacity, active_line, active_stroke_width, canvas, drag, drawing_data, lines_layer, palette, redraw, render_line, swatches, trash_btn, ui, pen_btn, paint_btn;
SWATCH_D = 25;
render_line = d3.svg.line().x(function(d) {
return d[0];
}).y(function(d) {
return d[1];
}).interpolate('basis');
drawing_data = {
lines: [
{
color: "#1b9e77",
points: [[451, 448], [447, 447]]
}
]
};
active_line = null;
active_color = "#333333";
active_stroke_width = "2px";
active_stroke_opacity = "0.2";
canvas = d3.select('#canvas');
lines_layer = canvas.append('g');
ui = d3.select('#ui');
palette = ui.append('g').attr({
transform: "translate(" + (2 + SWATCH_D / 2) + "," + (2 + SWATCH_D / 2) + "," + (2 + SWATCH_D / 2) + "," + (2 + SWATCH_D / 2) + ")",
transform: "translate(800,430)"
});
swatches = palette.selectAll('swatch').data(["#333333", "#ffffff", "#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e", "#e6ab02", "#a6761d", "#666666"]);
trash_btn = ui.append('text').html('&#xf1f8;').attr({
"class": 'btn',
dy: '0.35em',
transform: 'translate(940,20)'
}).on('click', function() {
drawing_data.lines = [];
return redraw();
});
pen_btn = ui.append('text').html('&#xf040;').attr({
"class": 'btn',
dy: '0.35em',
transform: 'translate(940,80)'
}).on('click', function(e) {
active_stroke_width = "2px";
active_stroke_opacity = "0.9";
active_line.classed('active', false);
return d3.select(this).classed('active', true);
});
paint_btn = ui.append('text').html('&#xf1fc;').attr({
"class": 'btn',
dy: '0.35em',
transform: 'translate(940,140)'
}).on('click', function(f) {
active_stroke_width = "10px";
active_stroke_opacity = "0.2";
active_line.classed('active', false);
return d3.select(this).classed('active', true);
});
swatches.enter().append('circle').attr({
"class": 'swatch',
cx: function(d, i) {
return i * (SWATCH_D + 4) / 2;
},
cy: function(d, i) {
if (i % 2) {
return SWATCH_D;
} else {
return 0;
}
},
r: SWATCH_D / 2,
fill: function(d) {
return d;
}
}).on('click', function(d) {
active_color = d;
swatches.classed('active', false);
return d3.select(this).classed('active', true);
});
swatches.each(function(d) {
if (d === active_color) {
return d3.select(this).classed('active', true);
}
});
drag = d3.behavior.drag();
drag.on('dragstart', function() {
active_line = {
points: [],
color: active_color,
stroke_width : active_stroke_width
};
drawing_data.lines.push(active_line);
return redraw(active_line);
});
drag.on('drag', function() {
active_line.points.push(d3.mouse(this));
return redraw(active_line);
});
drag.on('dragend', function() {
if (active_line.points.length === 0) {
drawing_data.lines.pop();
}
active_line = null;
return console.log(drawing_data);
});
canvas.call(drag);
redraw = function(specific_line) {
var lines;
lines = lines_layer.selectAll('.line').data(drawing_data.lines);
lines.enter().append('path').attr({
"class": 'line',
stroke: function(d) {
return d.color;
}
}).each(function(d) {
return d.elem = d3.select(this);
});
if (specific_line != null) {
specific_line.elem.attr({
d: function(d) {
return render_line(d.points);
}
});
} else {
lines.attr({
d: function(d) {
return render_line(d.points);
}
});
}
return lines.exit().remove();
};
redraw();
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment