Skip to content

Instantly share code, notes, and snippets.

@riston
Created September 6, 2015 15:38
Show Gist options
  • Save riston/aaaa08467aa19517175d to your computer and use it in GitHub Desktop.
Save riston/aaaa08467aa19517175d to your computer and use it in GitHub Desktop.
Reactive RXJS drawing example
var canvas = document.getElementById("container");
var ctx = canvas.getContext("2d");
// The line settings
ctx.lineWidth = 4;
ctx.lineJoin = ctx.lineCap = "round";
var intervalSource = Rx.Observable.interval(2 * 1000, Rx.Scheduler.requestAnimationFrame);
var pauser = new Rx.Subject();
var mouseMove = Rx.Observable.fromEvent(canvas, "mousemove");
var mouseDown = Rx.Observable.fromEvent(canvas, "mousedown");
var mouseUp = Rx.Observable.fromEvent(canvas, "mouseup");
var windowResize = Rx.Observable.fromEvent(window, "resize")
.throttleFirst(250 /* ms */);
var mousePath = mouseDown
.first()
.concat(mouseMove.takeUntil(mouseUp))
.repeat();
var snapToGrid = mousePath
.map(function (e) {
var gridWidth = 15;
var x = Math.round(e.x / gridWidth) * gridWidth;
var y = Math.round(e.y / gridWidth) * gridWidth;
return {
x: x,
y: y,
};
})
.distinctUntilChanged();
snapToGrid
.bufferWithCount(2, 1)
.subscribe(function (e) {
// console.log("N", e.x, e.y);
// newTick(e.y);
// var drawLine = function (p) {
// ctx.lineTo(p.x, p.y);
// ctx.stroke();
// };
// drawLine(e);
// drawCircle(e.x, e.y, 2, "#aaa");
});
mouseDown.subscribe(function (first) {
console.log("First Event", first);
ctx.beginPath();
ctx.moveTo(first.x, first.y);
// mouseMove.resume();
});
mouseUp.subscribe(function (last) {
console.log("Last event");
ctx.closePath();
// mouseMove.pause();
});
mousePath
.map(roundEventValues)
.distinctUntilChanged()
// .debounce(5)
// .bufferWithCount(2)
.subscribe(function (point) {
var drawEvent = function (e) {
var x = e.x;
var y = e.y;
drawCircle(x, y, 4);
};
var drawLine = function (p) {
ctx.lineTo(p.x, p.y);
ctx.stroke();
};
var drawQuadLine = function (a, b)
{
var midPoint = midPointBtw(a, b);
ctx.quadraticCurveTo(a.x, a.y, midPoint.x, midPoint.y);
ctx.stroke();
};
console.log("D", point);
// drawQuadLine(points[0], points[1]);
drawLine(point);
// drawLine(points[1]);
});
intervalSource.subscribe(function (e) {
console.log("Interval");
});
windowResize.subscribeOnNext(function (e) {
var size = getWindowSize();
console.log("Resize window", size);
canvas.setAttribute("height", size.height);
canvas.setAttribute("width", size.width);
});
function roundEventValues (e)
{
return {
x: ~~e.x,
y: ~~e.y,
};
}
function drawCircle(x, y, radius, defaultColor)
{
var hr = Math.floor(radius / 2);
var color = defaultColor || "#fff";
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x - hr, y - hr, radius, radius, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
function midPointBtw (p1, p2)
{
return {
x: p1.x + (p2.x - p1.x) / 2,
y: p1.y + (p2.y - p1.y) / 2
};
}
function getWindowSize ()
{
return {
width: window.innerWidth,
height: window.innerHeight,
};
}
function onLoad ()
{
var size = getWindowSize();
console.log("Window loaded", getWindowSize());
canvas.setAttribute("height", size.height);
canvas.setAttribute("width", size.width);
}
function main ()
{
console.log("Called main");
window.addEventListener("load", onLoad);
}
main();
// Drawing chart for the mouse movements
// var n = 40,
// random = d3.random.normal(0, 200),
// data = d3.range(n).map(random);
// var margin = {top: 20, right: 20, bottom: 20, left: 40},
// width = 400 - margin.left - margin.right,
// height = 200 - margin.top - margin.bottom;
// var x = d3.scale.linear()
// .domain([0, n - 1])
// .range([0, width]);
// var y = d3.scale.linear()
// .domain([0, 1000])
// .range([height, 0]);
// var line = d3.svg.line()
// .x(function(d, i) { return x(i); })
// .y(function(d, i) { return y(d); });
// var svg = d3.select(".x-axis").append("svg")
// .attr("width", width + margin.left + margin.right)
// .attr("height", height + margin.top + margin.bottom)
// .append("g")
// .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// svg.append("defs").append("clipPath")
// .attr("id", "clip")
// .append("rect")
// .attr("width", width)
// .attr("height", height);
// svg.append("g")
// .attr("class", "x axis")
// .attr("transform", "translate(0," + y(0) + ")")
// .call(d3.svg.axis().scale(x).orient("bottom"));
// svg.append("g")
// .attr("class", "y axis")
// .call(d3.svg.axis().scale(y).orient("left"));
// var path = svg.append("g")
// .attr("clip-path", "url(#clip)")
// .append("path")
// .datum(data)
// .attr("class", "line")
// .attr("d", line);
// // tick();
// function newTick (y) {
// // push a new data point onto the back
// data.push(y);
// // redraw the line, and slide it to the left
// path
// .attr("d", line)
// .attr("transform", "")
// .transition()
// .duration(500)
// .ease("linear")
// .attr("transform", "translate(" + x(-1) + ",0)");
// // .each("end", tick);
// // pop the old data point off the front
// data.shift();
// }
// function tick() {
// // push a new data point onto the back
// data.push(random());
// // redraw the line, and slide it to the left
// path
// .attr("d", line)
// .attr("transform", "")
// .transition()
// .duration(500)
// .ease("linear")
// .attr("transform", "translate(" + x(-1) + ",0)")
// .each("end", tick);
// // pop the old data point off the front
// data.shift();
// }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Drawing</title>
<link rel="stylesheet" type="text/css" href="./style.css">
</head>
<body>
<div>
<canvas id="container" width="600" height="600"></canvas>
</div>
<div class="x-axis"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/3.1.1/rx.all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="./app.js"></script>
</body>
</html>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
#container {
/* position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
*/
background-color: #adf;
/*width: 900px;*/
/*height: 900px;*/
}
canvas {
pointer: crosshair;
background: rgba(147,206,222,1);
background: linear-gradient(to right, rgba(147,206,222,1) 0%, rgba(117,189,209,1) 41%, rgba(73,165,191,1) 100%);
}
svg {
font: 10px sans-serif;
}
.line {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment