Last active
May 22, 2019 14:02
-
-
Save profexorgeek/05c882de8414166ad02b6cd3198d9c62 to your computer and use it in GitHub Desktop.
Single page web application that allows quick and easy mapping of spritesheet textures
This file contains hidden or 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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>Texture Mapping Helper</title> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |
<style> | |
html, body, div, img { | |
margin:0; | |
padding:0; | |
font-family: Arial, Helvetica, sans-serif; | |
font-size: 10pt; | |
color: #444; | |
} | |
h1, h2, h3, h4, h5, h6 { | |
font-size: 12pt; | |
} | |
div#imagediv { | |
min-width: 100px; | |
min-height: 100px; | |
display: inline-block; | |
background: slategrey; | |
} | |
div.rect { | |
outline:1px dashed yellow; | |
outline-offset: -1px; | |
z-index: 999; | |
} | |
div.rect:hover { | |
outline:1px dashed red; | |
} | |
div.controls { | |
padding:8px; | |
} | |
div#output { | |
border: 1px dashed slategray; | |
margin:10px; | |
min-height: 10px; | |
} | |
p.instructions { | |
font-size:9pt; | |
font-style:italic; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<div id="imagediv"></div> | |
<div class="controls"> | |
<h1>Texture Mapping Helper</h1> | |
<p class="instructions">Drag and drop an image on the box above. Click and drag to create texture rectangles. Click an existing rectangle to delete it. Change the snapping below.</p> | |
<p><label for="snapincrement">Snap To: </label><input id="snapincrement" type="text" size="2" value="32"/>px</p> | |
<h2>Output</h2> | |
<div id="output"></div> | |
</div> | |
</div> | |
<script type="text/javascript"> | |
var imageLoaded = false; | |
var rects = []; | |
var currentRect = null; | |
var dropZone = document.getElementById('imagediv'); | |
var snapIncrement = document.getElementById('snapincrement'); | |
var output = document.getElementById('output'); | |
var gridImg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkQ1Rjk3NTkwN0M0MTExRTlBRDdEQUY1OTFBMDU2Q0VFIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkQ1Rjk3NTkxN0M0MTExRTlBRDdEQUY1OTFBMDU2Q0VFIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RDVGOTc1OEU3QzQxMTFFOUFEN0RBRjU5MUEwNTZDRUUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RDVGOTc1OEY3QzQxMTFFOUFEN0RBRjU5MUEwNTZDRUUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6ZiAjnAAACH0lEQVR42uzdQW7aQBSAYWdsqMUCKRsS9QrkKu0JeuzkChVZZBMFpKj2TB16AT+pxlh8/4IVTIb3JUaKbHP34+evqqrqp9dqXHXdVJFyeyrH9fjnR9fv+y70/OvZf355HB6bf9Pvnx9GvuyuWcUGtPko79/GPz+6ftm95d/b6dafbv9pfxgMUmj6+o99TX9/SAYxbwAAABAAAAIAQAAACAAAAbidmrpuQv+h7bo/oR+wapoy7fqrtNj9133nL8AhCIAAABAAAAIAQAAACAAAAQCgC9Tk9tRvPsa/YNXEzq/vuq6acv3cHvMmLXT/aZubclyHzn8vwfPrq+D59dH1S7vg/Q/DdwjyGQBAAAAIAAABACAAAAQAgADcRq4PmHP/rg9wCAJgBAAACAAAAQAgAAAEAIAAAFhKJXLr9Cus6fuu7N7Gv2AVPL07t8fSridaf5h+Pt++Pn1/X+L+0+7z62qC0P33U/QNbFLo/Prw+ufNj38LV7X/cn9a/CFo/O++zwABACAAAAQAgAAAEAAAAIwAwE3n+oA59+/6AIcgAEYAAIAAABAAAAIAQAAACAAAXSbfHzDn/n1/wMz79/0BPgMAGAEAAAIAQAAACAAAAQAgADeT6wPm3L/rAxyCABgBAAACAEAAAAgAAAEAoAsC5JfHtD8YxOWrn17754fz3dMjBnXfxYS3uRwDt38Pr7/7LPenCdefbP/D9IfHvwIMANUw7ym/L+NBAAAAAElFTkSuQmCC"; | |
dropZone.addEventListener('dragover', function (e) { | |
e.stopPropagation(); | |
e.preventDefault(); | |
e.dataTransfer.dropEffect = "copy"; | |
console.log("File has been dragged over drop zone."); | |
}); | |
dropZone.addEventListener('drop', function (e) { | |
e.stopPropagation(); | |
e.preventDefault(); | |
console.log("File has been dropped in drop zone."); | |
var files = e.dataTransfer.files; | |
for(var i = 0, file; file = files[i]; i++) { | |
if(file.type.match(/image.*/)) { | |
var reader = new FileReader(); | |
reader.onload = function (e2) { | |
var img = document.createElement('img'); | |
img.src = e2.target.result; | |
dropZone.appendChild(img); | |
imageLoaded = true; | |
applyBackground(); | |
console.log("Adding image...") | |
} | |
console.log("Reading image file..."); | |
reader.readAsDataURL(file); | |
} | |
} | |
}); | |
dropZone.addEventListener('mousedown', function (e) { | |
if(imageLoaded) { | |
e.stopPropagation(); | |
e.preventDefault(); | |
var x = e.clientX + document.documentElement.scrollLeft; | |
var y = e.clientY + document.documentElement.scrollTop; | |
currentRect = createRect(x, y); | |
} | |
}); | |
dropZone.addEventListener('mousemove', function (e) { | |
if(imageLoaded && currentRect != null) { | |
var rectLeft = parseInt(currentRect.style.left); | |
var rectTop = parseInt(currentRect.style.top) | |
var x = e.clientX + document.documentElement.scrollLeft; | |
var y = e.clientY + document.documentElement.scrollTop; | |
updateRect(currentRect, rectLeft, rectTop, x, y); | |
} | |
}); | |
dropZone.addEventListener('mouseup', function (e) { | |
if(imageLoaded && currentRect != null) { | |
currentRect = null; | |
renderRectangleList(); | |
} | |
}); | |
function getOffset() { | |
return { | |
x: dropZone.offsetLeft - dropZone.scrollLeft + dropZone.clientLeft, | |
y: dropZone.offsetTop - dropZone.scrollTop + dropZone.clientTop | |
}; | |
} | |
function getSnap() { | |
return parseInt(snapIncrement.value); | |
} | |
function updateRect(rect, left, top, right, bottom) { | |
var snap = getSnap(); | |
var offset = getOffset(); | |
left = Math.floor(left / snap) * snap + offset.x; | |
top = Math.floor(top / snap) * snap + offset.y; | |
right = Math.round(right / snap) * snap + offset.x; | |
bottom = Math.round(bottom / snap) * snap + offset.y; | |
width = Math.max(right - left, snap); | |
height = Math.max(bottom - top, snap); | |
console.log('Updating rect to: ' + left + ',' + top + ',' + width + ',' + height); | |
rect.style.position = 'absolute'; | |
rect.style.top = top + 'px'; | |
rect.style.left = left + 'px'; | |
rect.style.width = width + 'px'; | |
rect.style.height = height + 'px'; | |
} | |
function createRect(x, y) { | |
var snap = getSnap(); | |
var rect = document.createElement('div'); | |
rect.classList.add('rect'); | |
updateRect(rect, x, y, x + snap, y + snap); | |
dropZone.insertBefore(rect, dropZone.firstChild); | |
rects.push(rect); | |
console.log('Created rect at ' + x + ', ' + y); | |
rect.addEventListener('mousedown', function (e) { | |
e.stopPropagation(); | |
e.preventDefault(); | |
dropZone.removeChild(rect); | |
var index = rects.indexOf(rect); | |
rects.splice(index, 1,); | |
renderRectangleList(); | |
}); | |
return rect; | |
} | |
function renderRectangleList() { | |
var rectList = ""; | |
for(var i = 0; i < rects.length; i++) { | |
var x = parseInt(rects[i].style.left) - dropZone.offsetLeft; | |
var y = parseInt(rects[i].style.top) - dropZone.offsetTop; | |
var width = parseInt(rects[i].style.width); | |
var height = parseInt(rects[i].style.height); | |
rectList += 'new Rectangle(' + x + ',' + y + ',' + width + ',' + height + '),<br />'; | |
} | |
output.innerHTML = rectList; | |
} | |
function applyBackground() { | |
dropZone.style.background = 'url("' + gridImg + '")'; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment