Skip to content

Instantly share code, notes, and snippets.

@dsaffo
Forked from nitaku/README.md
Last active October 15, 2020 19:22
Show Gist options
  • Save dsaffo/432feae93ee2af995a427ad459afd454 to your computer and use it in GitHub Desktop.
Save dsaffo/432feae93ee2af995a427ad459afd454 to your computer and use it in GitHub Desktop.
Freehand drawing adapted with VisConnect

VisConnect Drawing

This VisConnect example is adapted from this block. The only changes are adding the PeerJS and VisConnect script tags, adding the collaboration attribute to the HTML body, and replacing d3.drag with vc.drag.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Freehand drawing</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://unpkg.com/peerjs@1.0.4/dist/peerjs.min.js"></script>
<script src="https://unpkg.com/visconnect@latest/visconnect-bundle.js"></script>
</head>
<style>
#canvas {
/*background: oldlace;*/
}
#ui {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
.swatch {
pointer-events: all;
}
.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: black;
cursor: pointer;
}
.line {
fill: none;
stroke-width: 2px;
stroke-linejoin: round;
stroke-linecap: round;
}
</style>
<body collaboration="live">
<svg id="canvas" width="960px" height="500px"></svg>
<svg id="ui" width="960px" height="500px"></svg>
<script src="index.js"></script>
</body>
</html>
(function () {
var SWATCH_D, active_color, active_line, canvas, drag, drawing_data, lines_layer, palette, redraw, render_line,
swatches, trash_btn, ui;
SWATCH_D = 22;
render_line = d3.line().x((d) => d[0]).y((d) => d[1]).curve(d3.curveBasis);
drawing_data = {
lines: []
};
active_line = {};
active_color = {};
const default_color = '#333333';
let active_local_color = default_color;
canvas = d3.select('#canvas');
lines_layer = canvas.append('g');
ui = d3.select('#ui');
palette = ui.append('g').attr('transform', "translate(" + (4 + SWATCH_D / 2) + "," + (4 + SWATCH_D / 2) + ")");
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')
.attr("dy", '0.35em')
.attr("transform", 'translate(940,20)')
.on('click', function () {
drawing_data.lines = [];
return redraw();
});
const swatchEnter = swatches.enter().append('circle');
swatchEnter
.attr("class", 'swatch')
.attr('cx', function (d, i) {
return i * (SWATCH_D + 4) / 2;
})
.attr('cy', function (d, i) {
if (i % 2) {
return SWATCH_D;
} else {
return 0;
}
})
.attr('r', SWATCH_D / 2)
.attr('fill', d => d)
.on('click', function (d) {
active_color[d3.event.collaboratorId] = d;
if (d3.event.isLocalEvent) {
active_local_color = d;
palette.selectAll('.swatch').classed('active', false);
return d3.select(this).classed('active', true);
}
});
swatchEnter.each(function (d) {
if (d === active_local_color) {
return d3.select(this).classed('active', true);
}
});
drag = vc.drag(); // = d3.drag();
var rafRequest = 0;
drag.on('start', function () {
active_line[d3.event.sourceEvent.collaboratorId] = {
points: [],
color: active_color[d3.event.sourceEvent.collaboratorId] || default_color
};
drawing_data.lines.push(active_line[d3.event.sourceEvent.collaboratorId]);
redraw();
});
drag.on('drag', function () {
if (active_line[d3.event.sourceEvent.collaboratorId]) {
active_line[d3.event.sourceEvent.collaboratorId].points.push(d3.mouse(this));
if(!rafRequest) {
rafRequest = requestAnimationFrame(redraw.bind(this));
}
}
});
drag.on('end', function () {
if (active_line[d3.event.sourceEvent.collaboratorId] &&
active_line[d3.event.sourceEvent.collaboratorId].points.length === 0) {
drawing_data.lines.pop();
}
active_line[d3.event.sourceEvent.collaboratorId] = null;
});
canvas.call(drag);
redraw = function () {
rafRequest = 0;
const lines = lines_layer.selectAll('.line').data(drawing_data.lines);
const enter = lines.enter();
enter.append('path')
.attr("class", 'line')
.attr('stroke', function (d) {
return d.color;
}).each(function (d) {
return d.elem = d3.select(this);
});
lines.attr('d', function (d) {
return render_line(d.points);
});
lines.exit().remove();
};
redraw();
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment