Last active
February 19, 2017 17:20
-
-
Save evanjmg/d458114897dcf0316f786d90ed8147d8 to your computer and use it in GitHub Desktop.
This file contains 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
var previousDraggedPosition = null, | |
selected = null; | |
// snap to grid is simply rounding to the nearest resolution of the square | |
function snapToGrid(p, r) { | |
return Math.round(p / r) * r; | |
} | |
// we'll use a resolution of 50 here | |
var cubeResolution = 50; | |
// randomly generate points, but make sure they snap to grid | |
var points = d3.range(10).map(() => { | |
return { | |
x: snapToGrid(Math.random() * 500, cubeResolution), | |
y: snapToGrid(Math.random() * 500, cubeResolution) | |
}; | |
}); | |
var itemContainer = view.selectAll("g").attr("class", "itemContainer") | |
// add group to view | |
.data(points).enter().append('g') | |
// and center the group in the middle | |
.attr("transform", () => 'translate(' + xScale(0) + ',' + yScale(0) + ')') | |
.append('g') | |
// make this entire group draggable - this is useful for adding text elements later | |
.call(d3.drag() | |
.on("start", dragstarted) | |
.on("drag", dragged) | |
.on("end", dragended)); | |
// add the square to each group | |
var item = itemContainer.append('rect').attr('class', 'table-graphic') | |
.attr('x', d => d.x) | |
.attr('y', d => d.y) | |
.attr('data-rotation', 0) | |
.attr('width', cubeResolution) | |
.attr('height', cubeResolution) | |
.attr('fill', 'blue') | |
.on('click', function() { | |
selected = this.parentNode; | |
}); | |
function dragged(d) { | |
selected = this; | |
// update the position of the rect (square) and snap to grid | |
var el = d3.select(this).select('.table-graphic').attr("x", (d) => snapToGrid(d3.event.x, cubeResolution)).attr("y", () => snapToGrid(d3.event.y, cubeResolution)) | |
// get center point and make sure rotation is correct on drag. | |
var center = getCenter(el.attr('x'), el.attr('y'), cubeResolution, cubeResolution); | |
el.attr('transform', () => { | |
return "rotate(" + el.attr('data-rotation') + "," + center.x + ',' + center.y + ")"; | |
}); | |
} | |
function dragended(d) { | |
d3.select(this).classed("dragging", false); | |
var newEl = d3.select(this).select('.table-graphic'); | |
var newPt = { | |
x: newEl.attr('x'), | |
y: newEl.attr('y') | |
}; | |
// save and update position for redraw | |
var pt = findAndUpdate(coorNum(previousDraggedPosition), coorNum(newPt)); | |
if (pt) { | |
previousDraggedPosition = pt | |
}; | |
} | |
function dragstarted(d) { | |
var el = d3.select(this); | |
// save previous drag point for collisions and redraws | |
savePreviousDragPoint(el); | |
// raise the z-index to the top and set class to dragging | |
el.raise().classed("dragging", true); | |
} | |
// helper to convert strings to integers | |
function coorNum(pt) { | |
return { | |
x: parseInt(pt.x, 10), | |
y: parseInt(pt.y, 10) | |
}; | |
} | |
function savePreviousDragPoint(el) { | |
var elBox = el.nodes()[0].getBBox(); | |
if (!el.nodes()[0].classList.contains('dragging')) { | |
previousDraggedPosition = { | |
x: elBox.x, | |
y: elBox.y | |
}; | |
} | |
} | |
// helper for drag recentering | |
function getCenter(x, y, w, h) { | |
return { | |
x: parseInt(x, 10) + parseInt(w, 10) / 2, | |
y: parseInt(y, 10) + parseInt(h) / 2 | |
} | |
}; | |
// add slider instead of mousewheel zoom to improve user experience | |
// have it start at min 50% and max out at 5x the amount. | |
// you'll also have to add slider.attr('value', d3.event.scale) in the zoom method to update slider | |
var slider = d3.select("body").append("input") | |
.datum({}) | |
.attr("type", "range") | |
.attr("value", 1) | |
.attr("min", zoom.scaleExtent()[0]) | |
.attr("max", zoom.scaleExtent()[1]) | |
.attr("step", (zoom.scaleExtent()[1] - zoom.scaleExtent()[0]) / 100) | |
.on("input", slided); | |
function slided(d) { | |
zoom.scaleTo(svg, d3.select(this).property("value")); | |
} | |
// disable zoom on mousewheel and double click | |
svg.call(zoom).on("wheel.zoom", null) | |
.on('dblclick.zoom', null); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment