d3.scaler = function() { var scale; var height = 255; var max; var min; var selection; var dispatch = d3.dispatch("update"); var editing; var drag = d3.behavior.drag() .on("drag", function(d,i) { if(editing) return false; var y = getY(i); if(!y && y !== 0) return; var dy = d3.event.dy; y += dy; if(y > max) y = max; if(y < min) y = min; //move things around setY(i, y); //sort & reorder the domain and range var domain = scale.domain(); var range = scale.range(); var zipped = d3.zip(domain, range); zipped.sort(function(a,b) { return a[0] - b[0]; }) domain = zipped.map(function(d) { return d[0] }) range = zipped.map(function(d) { return d[1] }) scaler.update(); }) var scaler = function(g) { selection = g; scaler._update(); } dispatch.on("update.internal", function() { scaler._update(); }); scaler._update = function() { selection.each(function() { var sel = d3.select(this); var domain = scale.domain(); var range = scale.range(); //background. TODO: use svg? var bg = sel.selectAll("div.background") .data([0]) bg.enter().append("div").classed("background",true) bg.style({ "margin-top": "16px", width: 10+"px", height: height+ "px", "background-color":"grey" }) bg.on("dblclick", function() { var domain = scale.domain(); var range = scale.range(); var y = d3.mouse(this)[1]; var i = d3.bisect(domain, y); domain.splice(i, 0, y); range.splice(i, 0, ""); scaler.update(); }); //handle things var handles = sel.selectAll("div.handle") .data(domain) var handlesEnter = handles.enter().append("div").classed("handle", true); handlesEnter.append("div").classed("line", true); //the input var inputs = handlesEnter.append("input").classed("ascii", true) .on("mouseup", function() { this.select(); d3.event.cancelBubble = true; }) .on("keyup", function(d,i) { setX(i, this.value); scaler.update(); }) .attr("maxlength", 1); //the number var numbers = handlesEnter.append("span.number") .classed("number", true) inputs.on("focus", function() { console.log("focus!") editing = true; }) inputs.on("blur", function() { console.log("blur!") editing = false; }) handlesEnter.call(drag) handles.style("top", function(d,i) { return getY(i) + "px"; }) handles.select(".number") .text(function(d,i) { return getY(i) }) handles.select(".ascii") .attr("value", function(d,i) { return getX(i); }) }) } scaler.scale = function(_) { if(!arguments.length) return scale; scale = _; max = d3.max(scale.domain()); min = d3.min(scale.domain()); return scaler; } function getY(i) { var domain = scale.domain(); return domain[i]; } function setY(i, v) { var domain = scale.domain(); domain[i] = v; } function getX(i) { var range = scale.range(); return range[i]; } function setX(i, v) { var range = scale.range(); range[i] = v; } d3.rebind(scaler, dispatch, "on", "update") return scaler; }