Skip to content

Instantly share code, notes, and snippets.

@Nowalon
Created September 2, 2013 08:55
Show Gist options
  • Save Nowalon/6410729 to your computer and use it in GitHub Desktop.
Save Nowalon/6410729 to your computer and use it in GitHub Desktop.
SVG board with image manipulation - resize / rotate / move / remove etc.
Display the source blob
Display the rendered blob
Raw
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svg="http://www.w3.org/2000/svg"
id="canvas"
name="Demo Board"
onload="loaded()"
xml:space="preserve"
preserveAspectRatio="xMinYMin meet"
width="1280"
height="768"
>
<script type="text/javascript"><![CDATA[
var SVG = "http://www.w3.org/2000/svg";
var XLINK = "http://www.w3.org/1999/xlink";
var hotspot = "rgba(0,200,200,0.3)";
var svgWidth, svgHeight, boardName;
var trashZoneStart, trashZoneEnd = {};
var trashEmptyImgData = "data:image/png;base64,iVBORw0KG ...";
var trashActiveImgData = "data:image/png;base64,iVBORw0KGgoAAA ...";
var imgUrl1 = "data:image/jpeg;base64,iVBORw0KGgoAAA ...",
imgUrl2 = "data:image/jpeg;base64,iVBORw0KGgoAAA ...",
imgUrl3 = "data:image/jpeg;base64,iVBORw0KGgoAAA ...",
imgUrl4 = "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUg ...";
var currentTransform = null;
function loaded() {
// change onloadFunc to point to your real onload function that you
// want called when the page is truly ready
var onloadFunc = doload;
if (top.svgweb != undefined) {
top.svgweb.addOnLoad(onloadFunc, true, window);
} else {
onloadFunc();
}
// var objboardName = top.document.getElementById('boardName');
// var boardName = document.getElementById("canvas").getAttribute("name");
// if (objboardName && boardName) {
// objboardName.innerHTML = boardName; ///innerText
// }
var objElement = top.document.getElementById('__svg__random___0__object');
if (objElement)
{
// Extend object tag object's methods
objElement.SVGloadImage = loadImage;
objElement.SVGchancheBackground = chancheBackground;
}
svgWidth = document.getElementById("background-rect").width.baseVal.value;
svgHeight = document.getElementById("background-rect").height.baseVal.value;
document.getElementById("canvas").setAttribute("viewBox","0 0 " + svgWidth + " " + svgHeight);
var trashIconImg = document.getElementById("trash-img");
var trashIcon = document.getElementById("trash-rect");
trashIcon.setAttribute('x', svgWidth - 80);
trashIconImg.setAttributeNS(XLINK, "xlink:href", trashEmptyImgData);
trashIconImg.setAttribute('x', svgWidth - 80);
trashIconImg.style.visibility = "hidden";
trashIconImg.style.zIndex = 9999;
trashZoneStart = getOffsetRect(trashIconImg);
trashZoneEnd.top = getOffsetRect(trashIconImg).top + trashIconImg.height.baseVal.value;
trashZoneEnd.left = getOffsetRect(trashIconImg).left + trashIconImg.width.baseVal.value;
}
function doload() {
var images;
// Load a few images; some extra stuff here to make
// testing from file:// URLs easier -- it will load
// standard wallpapers on OSX or Vista.
try {
if (document.location.toString().indexOf("http") != -1) {
// images = [ "http://farm6.staticflickr.com/5205/5275927837_a46569a11a.jpg",
// "http://farm5.staticflickr.com/4132/5216680729_df5afcda77.jpg",
// "http://farm4.staticflickr.com/3589/3458525324_b86e0ff76b.jpg",
// "http://farm5.staticflickr.com/4029/5196957300_4babe45b82.jpg" ];
images = [ imgUrl1,
imgUrl2,
imgUrl3,
imgUrl4 ];
} else if (document.location.toString().toLowerCase().indexOf("users") != -1) {
images = ["file:///Library/Desktop Pictures/Nature/Flowing Rock.jpg",
"file:///Library/Desktop Pictures/Nature/Stones.jpg",
"file:///Library/Desktop Pictures/Plants/Lotus.jpg",
"file:///Library/Desktop Pictures/Plants/Dandelion.jpg" ];
} else {
images = ["file:///c:/Windows/Web/Wallpaper/Landscapes/img9.jpg",
"file:///c:/Windows/Web/Wallpaper/Landscapes/img7.jpg",
"file:///c:/Windows/Web/Wallpaper/Landscapes/img11.jpg",
"file:///c:/Windows/Web/Wallpaper/Landscapes/img10.jpg"];
}
} catch (e) {
images = [ imgUrl1,
imgUrl2,
imgUrl3,
imgUrl4 ];
}
// Load the images in the background, and only add them once they're
// loaded (and, presumably, cached by the browser)
for (var k = 0; k < images.length; k++) {
loadImage(k, images[k]);
}
document.getElementById("canvas").addEventListener("mousemove", onMouseMove, false);
document.getElementById("canvas").addEventListener("mouseup", onMouseUp, false);
document.getElementById("background-rect").addEventListener("mousemove", onMouseMove, false);
document.getElementById("background-rect").addEventListener("mouseup", onMouseUp, false);
document.getElementById("canvas").addEventListener("touchstart", onTouch, false);
document.getElementById("canvas").addEventListener("touchmove", onTouch, false);
document.getElementById("canvas").addEventListener("touchend", onTouch, false);
document.getElementById("background-rect").addEventListener("touchstart", onTouch, false);
document.getElementById("background-rect").addEventListener("touchmove", onTouch, false);
document.getElementById("background-rect").addEventListener("touchend", onTouch, false);
}
function loadImage(k, url) {
var img = new Image();
img.onload = function() {
var imgDm = {};
imgDm.width = this.width;
imgDm.height = this.height;
var g = addImage(url, 1, this.width, this.height);
g.style.opacity = 1;
g.vTranslate = [100 + Math.random() * 300 + (k%3) * 250,
100 + Math.random() * 300 + (k/3) * 280];
// var c = 0.25 + (Math.random() * .25);
var c = 0.5 + (Math.random() * .5);
//console.log('C: ', c);
g.vScale = c; // 0.25; // 0.001;
g.vRotate = (Math.random() * 40) - 20;
setupTransform(g.id);
rampOpacityUp(g);
}
img.src = url;
}
// convenience function to set X, Y, width, and height attributes
function svgSetXYWH(el, x, y, w, h) {
el.setAttribute("x", x);
el.setAttribute("y", y);
el.setAttribute("width", w);
el.setAttribute("height", h);
}
// create a new clickable rect [x,y,w,h] with the givenfill/stroke
// with the given handler on mouse down
function newClickableRect(id, x, y, w, h, fill, stroke, handler) {
var p = document.createElementNS(SVG, "rect");
p.setAttribute("id", id);
svgSetXYWH(p, x, y, w, h);
p.setAttribute("rx", 30);
p.setAttribute("ry", 30);
p.setAttribute("fill", fill);
//p.setAttribute("stroke", stroke);
//p.setAttribute("stroke-width", 10);
p.addEventListener("mousedown", handler, false);
p.addEventListener("touchstart", onTouch, false)
p.addEventListener("touchmove", onTouch, false);
p.addEventListener("touchend", onTouch, false);
return p;
}
// create all the elements for the given image URL.
// this includes the toplevel group, the image itself,
// and the clickable hotspots used for rotating the image.
var nextImageId = 0;
function addImage(url, initOpacity, imgWidth, imgHeight) {
//var imgw = 1000;
//var imgh = 700;
// var imgw = 800;
// var imgh = 600;
var imgw = imgWidth;
var imgh = imgHeight;
var id = nextImageId++;
var s = "image" + id;
var g = document.createElementNS(SVG, "g");
g.setAttribute("id", s);
g.setAttribute("class", "board-image");
g.addEventListener("mouseover", onEnterImage, false);
g.addEventListener("mouseout", onExitImage, false);
// g.addEventListener("mousedown", function(evt) { startTransform(evt, "c", "move"); evt.preventDefault(); }, false);
g.addEventListener("mousedown", function(evt) { startTransform(evt, "c", "move"); document.getElementById("canvas").addEventListener("mousemove", onMouseMove, false); evt.preventDefault(); }, false);
g.addEventListener("touchstart", onTouch, false);
g.addEventListener("touchmove", onTouch, false);
g.addEventListener("touchend", onTouch, false);
if (initOpacity != null)
g.style.opacity = initOpacity;
var image = document.createElementNS(SVG, "image");
image.setAttribute("id", s+"-img");
svgSetXYWH(image, -imgw/2, -imgh/2, imgw, imgh);
image.setAttribute("preserveAspectRatio", "xMinYMin slice");
image.setAttributeNS(XLINK, "xlink:href", url);
g.appendChild(image);
var rect = document.createElementNS(SVG, "rect");
rect.setAttribute("id", s+"-border");
svgSetXYWH(rect, -imgw/2, -imgh/2, imgw, imgh);
rect.setAttribute("stroke", "black");
// rect.setAttribute("rx", "10");
// rect.setAttribute("ry", "10");
// rect.setAttribute("stroke-width", "20");
rect.setAttribute("stroke-width", "1");
rect.setAttribute("fill", "none");
g.appendChild(rect);
var g2 = document.createElementNS(SVG, "g");
g2.setAttribute("id", s+"-overlay");
g2.setAttribute("class", "image-overlay");
g2.setAttribute("style", "visibility: hidden");
// var rsz = 200;
var rsz = 80;
g2.appendChild(newClickableRect(s+"-tl", -imgw/2, -imgh/2, rsz, rsz,
hotspot, "rgba(100,100,100,0.5)",
function (evt) { return startTransform(evt, 'tl', 'rotate'); }));
g2.appendChild(newClickableRect(s+"-tr", imgw/2-rsz, -imgh/2, rsz, rsz,
hotspot, "rgba(100,100,100,0.5)",
function (evt) { return startTransform(evt, 'tr', 'rotate'); }));
g2.appendChild(newClickableRect(s+"-br", imgw/2-rsz, imgh/2-rsz, rsz, rsz,
hotspot, "rgba(100,100,100,0.5)",
function (evt) { return startTransform(evt, 'br', 'rotate'); }));
g2.appendChild(newClickableRect(s+"-bl", -imgw/2, imgh/2-rsz, rsz, rsz,
hotspot, "rgba(100,100,100,0.5)",
function (evt) { return startTransform(evt, 'bl', 'rotate'); }));
/*
g2.appendChild(newClickableRect(s+"-c", -rsz/2, -rsz/2, rsz, rsz,
hotspot, "rgba(100,100,100,0.5)",
function (evt) { return startTransform(evt, 'c', 'scale'); }));
*/
g.appendChild(g2);
document.getElementById("canvas").appendChild(g);
return g;
}
function bringToFront(s) {
var el = document.getElementById(s);
el.parentNode.removeChild(el);
document.getElementById("canvas").appendChild(el);
}
// take the transforms saved on the element and turn them into
// svg transform syntax
function setupTransform(s) {
var g = document.getElementById(s);
if (g && g !== null){
var g2 = document.getElementById(s + "-overlay");
g.setAttribute("transform", "translate(" + g.vTranslate[0] + "," + g.vTranslate[1] + ") " +
"scale(" + g.vScale + "," + g.vScale + ") " +
"rotate(" + g.vRotate + ") ");
}
}
function baseName(ev) {
var id = ev.target.getAttribute("id");
return id.substr(0, id.indexOf("-"));
}
function onEnterImage(ev) {
var e = baseName(ev);
if (!e)
return;
document.getElementById(e + '-overlay').style.visibility = "visible";
ev.preventDefault();
}
function onExitImage(ev) {
var e = baseName(ev);
if (!e)
return;
document.getElementById(e + '-overlay').style.visibility = "hidden";
ev.preventDefault();
}
function startTransform(ev, corner, what) {
// ignore if something else is already going on
if (currentTransform != null)
return;
var e = baseName(ev);
if (!e)
return;
bringToFront(e);
var g = document.getElementById(e);
currentTransform = { what: what, el: e, corner: corner, g: g,
s: g.vScale, r: g.vRotate, t: g.vTranslate,
x: ev.clientX, y: ev.clientY };
rampOpacityDown(currentTransform.g);
}
function onMouseUp(ev) {
if (currentTransform){
rampOpacityUp(currentTransform.g);
}
currentTransform = null;
document.getElementById("trash-img").style.visibility = "hidden";
document.getElementById("trash-img").setAttributeNS(XLINK, "xlink:href", trashEmptyImgData);
ev.preventDefault();
}
function onMouseMove(ev) {
if (!("currentTransform" in window) ||
currentTransform == null)
return;
var ex = ev.clientX;
var ey = ev.clientY;
var pos = currentTransform.g.vTranslate;
if (currentTransform.what == "rotate") {
var r2d = 360.0 / (2.0 * Math.PI);
var lastAngle = Math.atan2(currentTransform.y - pos[1],
currentTransform.x - pos[0]) * r2d;
var curAngle = Math.atan2(ey - pos[1],
ex - pos[0]) * r2d;
currentTransform.g.vRotate += (curAngle - lastAngle);
var lastLen = Math.sqrt(Math.pow(currentTransform.y - pos[1], 2) +
Math.pow(currentTransform.x - pos[0], 2));
var curLen = Math.sqrt(Math.pow(ey - pos[1], 2) +
Math.pow(ex - pos[0], 2));
currentTransform.g.vScale = currentTransform.g.vScale * (curLen / lastLen);
} else if (currentTransform.what == "move") {
var xd = ev.clientX - currentTransform.x;
var yd = ev.clientY - currentTransform.y;
currentTransform.g.vTranslate = [ pos[0] + xd, pos[1] + yd ];
bringTrashToFront();
var trashEl = document.getElementById("trash-img");
var trashElGr = document.getElementById("trash-image-g");
trashEl.style.visibility = "visible";
var trSx = trashZoneStart.left;
var trSy = trashZoneStart.top;
var trEx = trashZoneEnd.left;
var trEy = trashZoneEnd.top;
if ((trSx < ex) && ( ex < trEx) && ( trSy < ey ) && ( ey < trEy)) {
trashEl.setAttributeNS(XLINK, "xlink:href", trashActiveImgData);
trashEl.setAttribute("width", 85);
trashEl.setAttribute("height", 85);
trashElGr.setAttribute("class", "trash-image-g-active");
} else {
trashEl.setAttributeNS(XLINK, "xlink:href", trashEmptyImgData);
trashEl.setAttribute("width", 80);
trashEl.setAttribute("height", 80);
trashElGr.setAttribute("class", "trash-image-g-nonactive");
}
} else {}
currentTransform.x = ex;
currentTransform.y = ey;
setupTransform(currentTransform.el);
ev.preventDefault();
}
function rampOpacityDown(g) {
g.style.opacity = 1.0;
var rampFunc = function () {
var o = parseFloat(g.style.opacity) - 0.05;
g.style.opacity = o;
if (o > 0.7)
setTimeout(rampFunc, 10);
}
rampFunc();
}
function rampOpacityUp(g) {
g.style.opacity = 0.7;
var rampFunc = function () {
var o = parseFloat(g.style.opacity) + 0.05;
g.style.opacity = o;
if (o < 1.0)
setTimeout(rampFunc, 10);
}
rampFunc();
}
function chancheBackground(url){
var bgImg = document.getElementById("background-img");
bgImg.setAttributeNS(XLINK, "xlink:href", url);
}
function bringTrashToFront() {
var el = document.getElementById('trash-image-g');
el.parentNode.removeChild(el);
document.getElementById("canvas").appendChild(el);
el.addEventListener("mouseup", trashMouseUp, false);
}
function getOffsetRect(elem) {
// (1)
var box = elem.getBoundingClientRect();
// (2)
var body = document.getElementById("canvas");
var docElem = document.documentElement;
// (3)
var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
// (4)
var clientTop = docElem.clientTop || body.clientTop || 0;
var clientLeft = docElem.clientLeft || body.clientLeft || 0;
// (5)
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return { top: Math.round(top), left: Math.round(left) }
}
/// cross-browsers getElementsByClassName method
if(!document.getElementsByClassName) {      
    document.getElementsByClassName = function (class_name) {
        var elements = document.body.getElementsByTagName("*"),
            length   = elements.length,
            out = [], i;
        for (i = 0; i < length; i += 1) {
            if (elements[i].className.indexOf(class_name) !== -1) {
                out.push(elements[i]);
            }       
        }        
        return out;
    };
}
function trashMouseUp(){
if (currentTransform && currentTransform.g){
deleteImageGroup(currentTransform.g);
}
}
function deleteImageGroup(imgGr){
var svgNS = "http://www.w3.org/2000/svg";
imgGr.removeEventListener('mousemove', onMouseMove);
document.getElementById("canvas").removeEventListener("mousemove", onMouseMove);
imgGr.removeEventListener('mousedown', function(evt) { startTransform(evt, "c", "move"); evt.preventDefault(); });
if (imgGr && imgGr.parentNode){
var imgGrId = imgGr.getAttribute("id");
var image = document.getElementById(imgGrId + '-img');
var rect = document.getElementById(imgGrId + '-border');
var overlay = document.getElementById(imgGrId + '-overlay');
var a = document.createElementNS(svgNS, "animateTransform");
a.setAttributeNS(null, "attributeName", "transform");
a.setAttributeNS(null, "attributeType", "XML");
a.setAttributeNS(null, "type", "scale");
a.setAttributeNS(null, "dur", "0.5s");
a.setAttributeNS(null, "from", "1");
a.setAttributeNS(null, "to", "0");
a.setAttributeNS(null, "fill", "freeze");
var b = document.createElementNS(svgNS, "animateTransform");
b.setAttributeNS(null, "attributeName", "transform");
b.setAttributeNS(null, "attributeType", "XML");
b.setAttributeNS(null, "type", "scale");
b.setAttributeNS(null, "dur", "0.5s");
b.setAttributeNS(null, "from", "1");
b.setAttributeNS(null, "to", "0");
b.setAttributeNS(null, "fill", "freeze");
var c = document.createElementNS(svgNS, "animateTransform");
c.setAttributeNS(null, "attributeName", "transform");
c.setAttributeNS(null, "attributeType", "XML");
c.setAttributeNS(null, "type", "scale");
c.setAttributeNS(null, "dur", "0.5s");
c.setAttributeNS(null, "from", "1");
c.setAttributeNS(null, "to", "0");
c.setAttributeNS(null, "fill", "freeze");
if (!image.getElementsByTagName('animateTransform').length){
image.appendChild(a);
a.beginElement();
}
if (!rect.getElementsByTagName('animateTransform').length){
rect.appendChild(b);
b.beginElement();
}
if (!overlay.getElementsByTagName('animateTransform').length){
overlay.appendChild(c);
c.beginElement();
}
setTimeout(function(imgGrId){
document.getElementById("canvas").addEventListener("mousemove", onMouseMove, false);
imgGr.parentNode.removeChild(imgGr);
}, 500);
}
}
function deleteAllBoardImages(){
var imgGrs = document.getElementsByClassName('board-image');
while(imgGrs[0]) {
imgGrs[0].parentNode.removeChild(imgGrs[0]);
}
document.getElementById("background-img").setAttributeNS(XLINK, "xlink:href", '/wp-content/themes/superspark-v1-02/images/vision-board/vision-golden-logo-text-bg.jpg');
}
function getSVG(){
return document.getElementById("canvas");
}
var timeout;
function onTouch(evt) {
evt.preventDefault();
if (evt.touches.length > 1 || (evt.type == "touchend" && evt.touches.length > 0)){
return;
}
var e = baseName(evt);
if (!e)
return;
document.getElementById(e + '-overlay').style.visibility = "visible";
var newEvt = document.createEvent("MouseEvents");
var type = null;
var touch = null;
switch (evt.type) {
case "touchstart": type = "mousedown"; touch = evt.changedTouches[0];break;
case "touchmove": type = "mousemove"; touch = evt.changedTouches[0]; break;
case "touchend": type = "mouseup"; touch = evt.changedTouches[0]; break;
}
// newEvt.initMouseEvent(type, true, true, evt.originalTarget.ownerDocument.defaultView, 0,
newEvt.initMouseEvent(type, true, true, evt.target.ownerDocument.defaultView, 0,
touch.screenX, touch.screenY, touch.clientX, touch.clientY,
evt.ctrlKey, evt.altKey, evt.shirtKey, evt.metaKey, 0, null);
// evt.originalTarget.dispatchEvent(newEvt);
evt.target.dispatchEvent(newEvt);
if (evt.type == 'touchend') {
setTimeout(function(){
document.getElementById(e + '-overlay').style.visibility = "hidden";
}, 2000);
if (document.getElementById("trash-image-g").getAttribute("class") == "trash-image-g-active"){
if (evt.target){
deleteImageGroup(evt.target.parentNode);
document.getElementById("trash-image-g").setAttribute("class", "trash-image-g-nonactive");
}
}
}
}
function testElem(str){
var str = str || "test info";
var newDiv = document.createElementNS(SVG, "text");
newDiv.id = "testBlock";
newDiv.setAttribute('x', 0);
newDiv.setAttribute('y', 10);
newDiv.setAttribute('width', 300);
newDiv.setAttribute('height', 20);
newDiv.setAttribute('font-size', 14);
newDiv.setAttribute('fill', 'red');
newDiv.style = "position:absolute; height: 20px; width: 100px; color: red; top: 0; left: 0";
var newContent = document.createTextNode(str);
if (!document.getElementById("testBlock")){
document.getElementById("canvas").appendChild(newDiv);
testBlock = newDiv;
testBlock.appendChild(newContent);
} else {
testBlock = document.getElementById("testBlock");
testBlock.parentNode.removeChild(testBlock);
// document.getElementById("canvas").appendChild(newDiv);
testBlock.replaceChild(newContent);
}
// testBlock.innerHTML = str;
}
]]></script>
<g xmlns="http://www.w3.org/2000/svg" id="background-image-g" style="opacity: 1.0;" viewBox="0 0 100% 100%">
<image id="background-img" x="0" y="0" width="100%" height="100%" preserveAspectRatio="xMinYMin slice" xlink:href="/wp-content/themes/superspark-v1-02/images/vision-board/board-wooden-bg.jpg" xmlns:xlink="http://www.w3.org/1999/xlink" />
<rect id="background-rect" x="0%" y="0%" width="100%" height="100%" fill="none" />
</g>
<g xmlns="http://www.w3.org/2000/svg" id="trash-image-g" style="opacity: 1.0;">
<image id="trash-img" x="90%" y="0" width="80" height="80" preserveAspectRatio="xMinYMin slice" xlink:href="" xmlns:xlink="http://www.w3.org/1999/xlink"/>
<rect id="trash-rect" x="1180" y="0%" width="80" height="80" fill="none" />
</g>
</svg>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment