Last active
December 18, 2015 20:49
-
-
Save voyce/5842759 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<title>D3 and Knockout</title> | |
<script src="knockout-2.2.1.js"></script> | |
<script src="lib/d3.v2.js"></script> | |
<link rel="stylesheet" href="src/nv.d3.css" type="text/css"/> | |
<script> | |
var nrects = 1; | |
function Rect() { | |
var self = this; | |
self.x = ko.observable(0); | |
self.y = ko.observable(0); | |
self.w = ko.observable(100); | |
self.h = ko.observable(100); | |
self.name = ko.observable("rect" + nrects++); | |
self.rect = ko.computed(function(){ | |
// In our case it doesn't matter we return; this function just needs to be | |
// something that reads the values of the properties we're interested in | |
return {x:self.x(), y:self.y(), w:self.w(), h:self.h()}; | |
}); | |
}; | |
function ViewModel() { | |
var self = this; | |
self.rects = ko.observableArray([]); | |
self.addRect = function () { | |
self.rects.push(new Rect(self)); | |
}; | |
}; | |
var drag = d3.behavior.drag() | |
.origin(Object) | |
.on("drag", function (d) { | |
// Update the view model | |
d.x(parseInt(d.x()) + d3.event.dx); | |
d.y(parseInt(d.y()) + d3.event.dy); | |
}); | |
window.onload = function() { | |
var vm = new ViewModel(); | |
ko.applyBindings(vm); | |
function update(data) { | |
// Join elements with data | |
var rects = d3.select("#svg") | |
.selectAll("rect") | |
.data(data, function (d) { return d.name(); }); | |
// Create new elements by transitioning them in | |
rects.enter() | |
.append("rect") | |
.attr("id", function (d) { return d.name(); }) | |
.attr("opacity", 0.0) | |
.transition() | |
.duration(1000) | |
.attr("opacity", 0.5); | |
// Update existing ones by setting their x, y, etc | |
rects.attr("x", function (d) { return d.x(); }) | |
.attr("y", function (d) { return d.y(); }) | |
.attr("width", function (d) { return d.w(); }) | |
.attr("height", function (d) { return d.h(); }) | |
.call(drag); | |
rects.exit().remove(); | |
} | |
var subs = []; // for keeping track of subscriptions | |
// Listen for changes to the view model data... | |
vm.rects.subscribe(function (newValue) { | |
update(newValue); | |
// Dispose any existing subscriptions | |
ko.utils.arrayForEach(subs, function (sub) { sub.dispose(); }); | |
// And create new ones... | |
ko.utils.arrayForEach(newValue, function (item) { | |
subs.push(item.rect.subscribe(function () { | |
update(newValue); | |
})); | |
}); | |
}); | |
// Add one to get us started | |
vm.rects.push(new Rect()); | |
}; | |
</script> | |
</head> | |
<body> | |
<div> | |
<button data-bind="click:addRect">Add</button> | |
<div data-bind="foreach: rects"> | |
x:<input data-bind="value: x" size="6"/> | |
y:<input data-bind="value: y" size="6"/> | |
w:<input data-bind="value: w" size="6"/> | |
h:<input data-bind="value: h" size="6"/> | |
<br/> | |
</div> | |
</div> | |
<svg id="svg" width="500px" height="500px"/> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A quick example of combining Knockout-driven data with D3. More info here: http://www.voyce.com/index.php/2013/06/23/dynamic-d3-with-knockout-js/