|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
body { |
|
font-family: helvetica; |
|
margin: 0; |
|
min-width: 100%; |
|
min-height: 100%; |
|
} |
|
|
|
.overlay { |
|
border: 3px dashed #fff; |
|
box-sizing: border-box; |
|
height: 100%; |
|
min-height: 500px; |
|
min-width: 960px; |
|
width: 100%; |
|
position: absolute; |
|
z-index: 100; |
|
} |
|
|
|
.example { |
|
z-index: 200; |
|
} |
|
|
|
</style> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<body> |
|
<svg class="overlay"> |
|
</svg> |
|
</body> |
|
<script src="xml.js"></script> |
|
<script> |
|
|
|
var svg = d3.select(".overlay"), |
|
width = +svg.style("width").replace("px", ""), |
|
height = +svg.style("height").replace("px", ""); |
|
|
|
var text = svg.append("text") |
|
.style("text-anchor", "middle") |
|
.style("font-size", "24px") |
|
.attr("x", width / 2) |
|
.attr("y", height / 2) |
|
.text("Drag and drop SVG files"); |
|
|
|
d3.select("body") |
|
.on("dragover", dragOver) |
|
.on("mouseleave", mouseleave) |
|
.on("drop", selectFile); |
|
|
|
function selectFile() { |
|
// Remove the visual cue that items are being drag-n-dropped. |
|
mouseleave(); |
|
|
|
text.remove(); |
|
|
|
var files = event.dataTransfer.files; |
|
var documents = []; // Array of promises which resolve to an XML Document. |
|
|
|
d3.event.stopPropagation(); |
|
d3.event.preventDefault(); |
|
|
|
for (var i = 0, file; file = files[i]; i++) { |
|
documents.push(svgDocument(file)); |
|
} |
|
|
|
// Wait for all files to be parsed from text into an XML Document. |
|
Promise.all(documents) |
|
.then((documents) => { |
|
window.focus(); |
|
|
|
let spritesheet, metadata; |
|
|
|
[spritesheet, data] = svgSpritesheet(documents); |
|
|
|
data = data.map((d, i) => { |
|
let datum = {}; |
|
Object.assign(datum, d); |
|
datum.name = files[i].name; |
|
return datum; |
|
}); |
|
|
|
ready(data, spritesheet); |
|
downloadText("spritesheet.svg", spritesheet); |
|
}); |
|
} |
|
|
|
// Make explicit to the user that the dragging operation will result in a copy. |
|
function dragOver() { |
|
// Produce a visual cue that items are being drag-n-dropped. |
|
svg |
|
.style("background-color", "rgba(150, 208, 150, 0.7)") |
|
.style("border", "3px dashed #000"); |
|
|
|
d3.event.stopPropagation(); |
|
d3.event.preventDefault(); |
|
d3.event.dataTransfer.dropEffect = 'copy'; |
|
} |
|
|
|
function mouseleave() { |
|
// Remove the visual cue that items are being drag-n-dropped. |
|
svg |
|
.style("background-color", null) |
|
.style("border", "3px dashed #fff"); |
|
} |
|
|
|
// Render each asset specified by it's unique name with a <use> tag, |
|
// referencing the spritesheet that is downloaded. |
|
function ready(data, spritesheet) { |
|
d3.selectAll(".assets").remove(); |
|
|
|
// SVG definitions. |
|
d3.select("body").append("svg") |
|
.html(spritesheet) |
|
.style("display", "none"); |
|
|
|
d3.selectAll(".assets").remove(); |
|
|
|
let assets = d3.select("body").append("div") |
|
.attr("class", "assets") |
|
.style("display", "flex") |
|
.style("flex-direction", "row") |
|
.style("align-items", "center") |
|
.style("flex-wrap", "wrap"); |
|
|
|
// Create and append a DIV the DOM for each asset in our dataset. |
|
let example = assets.selectAll(".example") |
|
.data(data) |
|
.enter().append("div") |
|
.attr("class", "example") |
|
.style("box-sizing", "border-box") |
|
.style("display", "flex") |
|
.style("flex-shrink", 0) |
|
.style("flex-direction", "column") |
|
.style("align-items", "center") |
|
.style("margin", "5px") |
|
.style("padding", "15px") |
|
.style("width", "145px") |
|
.style("font-family", "helvetica") |
|
.style("font-size", "14px") |
|
.style("background-color", (d) => { |
|
// Highlight possible problematic assets. |
|
if (d.fill || d.stroke) return "#fff8dc"; |
|
return null; |
|
}) |
|
.on("mouseover", function() { |
|
d3.select(this) |
|
.style("color", "#005F9E"); |
|
}) |
|
.on("mouseleave", function() { |
|
d3.select(this) |
|
.style("color", null) // Default color. |
|
}); |
|
|
|
// Create and append a SVG with a <use> tag to the asset DIV. |
|
let svg = example.append("svg") |
|
.attr("width", 32) |
|
.attr("height", 32) |
|
.attr("display", "inline-block") |
|
.attr("vertical-align", "text-top") |
|
.attr("fill", "currentColor") |
|
.append("svg:use") |
|
.attr("xlink:href", d => "#" + d.name.substring(0, d.name.indexOf(".svg"))); |
|
|
|
// Create and append a DIV as a child of each example which will show text. |
|
let label = example.append("div") |
|
.html(d => d.name) |
|
.style("width", "115px") |
|
.style("white-space", "nowrap") |
|
.style("overflow", "hidden") |
|
.style("text-overflow", "ellipsis") |
|
.style("text-align", "center") |
|
.attr("display", "inline-block"); |
|
} |
|
|
|
function downloadText(filename, text) { |
|
var element = document.createElement('a'); |
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); |
|
element.setAttribute('download', filename); |
|
|
|
element.style.display = 'none'; |
|
document.body.appendChild(element); |
|
|
|
element.click(); |
|
|
|
document.body.removeChild(element); |
|
} |
|
|
|
</script> |
TODO
Ensure drag and drop cleans up the state of the DOM and the overlay captures the drop.