|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
body { |
|
position: relative; |
|
width: 960px; |
|
height: 500px; |
|
} |
|
|
|
#background { |
|
width: 960px; |
|
height: 500px; |
|
background: url(mosque.jpg); |
|
} |
|
|
|
svg { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
} |
|
|
|
.line { |
|
stroke: #000; |
|
stroke-opacity: .5; |
|
stroke-width: 1px; |
|
stroke-linecap: square; |
|
} |
|
|
|
.handle { |
|
fill: none; |
|
pointer-events: all; |
|
stroke: #fff; |
|
stroke-width: 2px; |
|
cursor: move; |
|
} |
|
|
|
#buttons { |
|
position: absolute; |
|
top: 20px; |
|
left: 20px; |
|
z-index: 2; |
|
} |
|
|
|
button { |
|
display: block; |
|
width: 10em; |
|
} |
|
|
|
button:focus { |
|
outline: none; |
|
} |
|
|
|
</style> |
|
<div id="background"></div> |
|
<div id="buttons"> |
|
<button data-targets="[[492,329],[542,330],[569,434],[424,424]]">Floor</button> |
|
<button data-targets="[[-28,287],[74,288],[72,413],[-31,404]]">Near Wall</button> |
|
<button data-targets="[[-194,282],[-95,282],[-100,354],[-200,365]]">Far Wall</button> |
|
<button data-targets="[[0,0],[400,0],[400,400],[0,400]]">Reset</button> |
|
</div> |
|
<script src="//d3js.org/d3.v3.min.js"></script> |
|
<script src="numeric-solve.min.js"></script> |
|
<script> |
|
|
|
var margin = {top: 50, right: 280, bottom: 50, left: 280}, |
|
width = 960 - margin.left - margin.right, |
|
height = 500 - margin.top - margin.bottom; |
|
|
|
var transform = ["", "-webkit-", "-moz-", "-ms-", "-o-"].reduce(function(p, v) { return v + "transform" in document.body.style ? v : p; }) + "transform"; |
|
|
|
var sourcePoints = [[0, 0], [width, 0], [width, height], [0, height]], |
|
targetPoints = [[0, 0], [width, 0], [width, height], [0, height]]; |
|
|
|
d3.select("body").selectAll("svg") |
|
.data(["transform", "flat"]) |
|
.enter().append("svg") |
|
.attr("id", function(d) { return d; }) |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom) |
|
.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
var svgTransform = d3.select("#transform") |
|
.style(transform + "-origin", margin.left + "px " + margin.top + "px 0"); |
|
|
|
var svgFlat = d3.select("#flat"); |
|
|
|
svgTransform.select("g").append("image") |
|
.attr("xlink:href", "sailboat.png") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
svgTransform.select("g").selectAll(".line--x") |
|
.data(d3.range(0, width + 1, 40)) |
|
.enter().append("line") |
|
.attr("class", "line line--x") |
|
.attr("x1", function(d) { return d; }) |
|
.attr("x2", function(d) { return d; }) |
|
.attr("y1", 0) |
|
.attr("y2", height); |
|
|
|
svgTransform.select("g").selectAll(".line--y") |
|
.data(d3.range(0, height + 1, 40)) |
|
.enter().append("line") |
|
.attr("class", "line line--y") |
|
.attr("x1", 0) |
|
.attr("x2", width) |
|
.attr("y1", function(d) { return d; }) |
|
.attr("y2", function(d) { return d; }); |
|
|
|
var handle = svgFlat.select("g").selectAll(".handle") |
|
.data(targetPoints) |
|
.enter().append("circle") |
|
.attr("class", "handle") |
|
.attr("transform", function(d) { return "translate(" + d + ")"; }) |
|
.attr("r", 7) |
|
.call(d3.behavior.drag() |
|
.origin(function(d) { return {x: d[0], y: d[1]}; }) |
|
.on("drag", dragged)); |
|
|
|
d3.selectAll("button") |
|
.datum(function(d) { return JSON.parse(this.getAttribute("data-targets")); }) |
|
.on("click", clicked) |
|
.call(transformed); |
|
|
|
function clicked(d) { |
|
d3.transition() |
|
.duration(750) |
|
.tween("points", function() { |
|
var i = d3.interpolate(targetPoints, d); |
|
return function(t) { |
|
handle.data(targetPoints = i(t)).attr("transform", function(d) { return "translate(" + d + ")"; }); |
|
transformed(); |
|
}; |
|
}); |
|
} |
|
|
|
function dragged(d) { |
|
d3.select(this).attr("transform", "translate(" + (d[0] = d3.event.x) + "," + (d[1] = d3.event.y) + ")"); |
|
transformed(); |
|
} |
|
|
|
function transformed() { |
|
for (var a = [], b = [], i = 0, n = sourcePoints.length; i < n; ++i) { |
|
var s = sourcePoints[i], t = targetPoints[i]; |
|
a.push([s[0], s[1], 1, 0, 0, 0, -s[0] * t[0], -s[1] * t[0]]), b.push(t[0]); |
|
a.push([0, 0, 0, s[0], s[1], 1, -s[0] * t[1], -s[1] * t[1]]), b.push(t[1]); |
|
} |
|
|
|
var X = solve(a, b, true), matrix = [ |
|
X[0], X[3], 0, X[6], |
|
X[1], X[4], 0, X[7], |
|
0, 0, 1, 0, |
|
X[2], X[5], 0, 1 |
|
].map(function(x) { |
|
return d3.round(x, 6); |
|
}); |
|
|
|
svgTransform.style(transform, "matrix3d(" + matrix + ")"); |
|
} |
|
|
|
</script> |
AMAZING!!!!
What would be the necessary changes to make the whole Sailboat svg dragabble?
(Not just by corners, but also from center just to reposition)
Also, is it possible to layer another transparent PNG on top of the sailboat (for example to mimic wall shadows?)
Then you can have:
This c layer would have to be designed in photoshop similar to how tshirt mock up generators create wrinkles.
Thanks!!