;(function(d3){ var ENTER = 13; var Z = 1; var ZOOM = 1; var card_collection = window.card_collection = []; function Card(){ var my = { x: 0, y: 0, text: null, id: +(new Date()) + Math.random() }; function wrap(attr){ return function(val){ if(val === void 0){ return my[attr]; } my[attr] = val; return api; }; } var api = { x: wrap("x"), y: wrap("y"), text: wrap("text"), id: wrap("id") }; return api; } Card.create = function(){ var card = Card().x(d3.event.x).y(d3.event.y); card._editable = 1; card_collection.push(card); render(); var div = d3.selectAll(".card").filter(function(d){ return d === card; }).node(); Card.click.call(div, card); }; Card.click = function(d, i){ d._editable = true; render(); d3.select(this).select(".text").node().focus(); d3.event.stopPropagation(); }; Card.keyup = function(d, i){ if(d3.event.shiftKey && d3.event.keyCode === ENTER){ Card.save(d, i); } }; Card.save = function(d, i){ if(d._editable){ return; } console.log("saved!"); this.blur(); var text = d3.select(this); d.text(this.innerHTML); d._editable = false; render(); }; Card.zoom = function(){ var regex = { scale: /scale\(([\d\.]*)\)/, mtx: /matrix\(([\d\.]*), /, }; var old_zoom = ( root.style("transform") || root.style("-webkit-transform") || ""); d3.entries(regex).map(function(regex, key){ var match = old_zoom.match(regex.value); if(match !== null){ old_zoom = +match[1]; } }); if(!old_zoom === null){ old_zoom = 1; } ZOOM = Math.max(0.01, old_zoom + d3.event.wheelDelta / 1000); root.call(xb_scale(ZOOM)); }; Card.drag = d3.behavior.drag() .origin(function(){ var that = d3.select(this); return { x: parseInt(that.style("left")), y: parseInt(that.style("top")) } }) .on("drag", function(d, i){ if(editable(d)){return;} d.x(d3.event.x) .y(d3.event.y); d3.select(this) .style("left", d3.event.x + "px") .style("top", d3.event.y + "px") .style("z-index", Z++); }); function attr(att){ return function(d){ return d[att]; }; } attr.px = function(att){ var func = attr(att); return function(d, i){ return func(d, i) + "px"; }; }; function xb_scale(amount){ var val = "scale(" + amount + ")"; return function(selection){ selection .transition() .style("transform", val) .style("-webkit-transform", val) }; } // initialize the frame var root = d3.select("body") .on("mousewheel", Card.zoom) .selectAll("#root") .data([1]); root.enter().append("div") .attr("id", "root") .on("dblclick", Card.create) .call(xb_scale(ZOOM)); function editable(d, i){ return d._editable; } function render(){ var card = root.selectAll(".card") .data(card_collection), card_init = card.enter() .append("div") .attr("class", "card") .call(Card.drag) .style("left", function(d){ return d.x()+"px"; }) .style("top", function(d){ return d.y()+"px"; }) .on("dblclick", Card.click); card_init.append("div") .classed("text", 1) .on("keydown", Card.keyup) .on("blur", function(d, i){ d._editable = false; Card.save.call(this, d,i); }); card.select(".text") .attr("contenteditable", editable) .each(function(d, i){ this.innerHTML = d.text(); }); card .style("left", attr.px("x")) .style("top", attr.px("y")); } render(); }).call(this, d3);