use click events rather than hit testing

This commit is contained in:
Geoff Schmidt
2012-08-10 20:17:32 -07:00
parent fec60a5ea9
commit efaa885a7b

View File

@@ -148,24 +148,12 @@ Template.d3Demo.right = function () {
return { group: "right" };
};
var hitTest = function (x, y, selector) {
var circles = Circles.find(selector).fetch();
for (var i = 0; i < circles.length; i++) {
var c = circles[i];
var dist2 = (x - c.x) * (x - c.x) + (y - c.y) * (y - c.y);
if (dist2 < c.r*c.r)
return c;
}
return null;
};
Template.circles.events = {
'click svg': function (evt, template) {
var circle = hitTest(evt.offsetX / 200, evt.offsetY / 200,
{group: this.group});
console.log("click " + (circle ? circle._id : "null"));
'click circle': function (evt, template) {
// XXX actually want to create a ReactiveVar on the template!
Session.set("selectedCircle:" + this.group, circle);
// (but how will it be preserved across migration?)
// (maybe template.get, template.set?? rather than form??)
Session.set("selectedCircle:" + this.group, evt.currentTarget.id);
},
'click .add': function () {
Circles.insert({x: Meteor.random(), y: Meteor.random(),
@@ -226,11 +214,53 @@ Template.circles.render = function () {
d3.select(self.node).append("rect");
self.handle = autorun(function () {
// XXX In an ideal world, we'd pass a cursor to .data(), and as
// long as we were within an autorun, the "right thing" would
// happen, meaning that d3 would process only the changed
// elements.
//
// You could model this as a getChanges() method on a cursor,
// which reactively returns the changes since you last called it
// (as an object with added, removed, moved, changed sections.)
// Except you should be able to have N per cursor.
//
// Actually, you could make a function Meteor.getChanges(cursor)
// that returns a changes function that has the above
// properties.
//
// Then, we'd need to reach inside d3's matching logic to make
// it detect a Meteor cursor and call getChanges ...
//
// XXX no, you need one getchanges per cursor per autorun. hmm.
// maybe a factory that memoizes them somehow? but, per autorun?
//
// Maybe:
// var stream = ChangeStream(cursor);
// autorun(function () { d3.select(...).stream(stream) ... }
// Streams are the factory described above. returns ChangeSets
//
// XXX what this doesn't answer is, what if you depend on other
// reactive values, eg Session.get("color")?
//
// XXX why can't we just do this stuff declaratively with
// Handlebars and an <svg> element? what does that imply about
// missing animation support in Spark?
//
// XXX make Session be a ReactiveDict (ReactiveMap?) and put the
// ReactiveDiff impl in packages/deps/tools.js. Keep the
// low-level deps machinery as it is (maybe add invalidation
// sequencing.) Rename Meteor.deps.Context =>
// InvalidationContext.
//
// XXX allow query selectors, sorts, to be lambdas?
var circle = d3.select(self.node).selectAll("circle")
.data(Circles.find({group: data.group}).fetch(),
function (d) { return d._id; });
circle.enter().append("circle")
.attr("id", function (d) {
return d._id;
})
.attr("cx", function (d) {
return d.x * 200;
})
@@ -265,6 +295,7 @@ Template.circles.render = function () {
.attr("r", 0)
.remove();
// XXX this doesn't animate as I'd hoped when you press Scram
var selectionId = Session.get("selectedCircle:" + data.group);
var s = selectionId && Circles.findOne(selectionId);
var rect = d3.select(self.node).select("rect");