将图像拖放到画布中

时间:2014-10-27 06:51:12

标签: javascript html5 canvas

我想将画布外部生成的图像拖动到画布中绘制一些线条和形状,然后移出画布。我使用touchstart / touchmove函数来跟踪被拖动的图像但是当我将它们移动到画布上时,我可以将它们放在画布上并且绘制不会影响任何图像。下面是分别生成图像和创建绘画画布的脚本。

图像脚本代码。

var zIndexCount = 1;
var moving = {};
var imgData = [[620, 166, 2.9, 0.570], [606, 134, 10.4, 0.403], [633, 103, 45.9, 0.396], [618, 110, 
-46.5, 0.576], [618, 40, -69.3, 0.550], [694, 84, 18.7, 0.642], [688, 46, 32.2, 0.363], [614, 114, 64.6, 0.437], [627, 59, 63.3, 0.288], [690, 127, 22.2, 0.352]];

function touchHandler(e) {
if (e.type === "touchstart") {
    for (var i = 0; i < e.touches.length; i++) {
        // for each "movable" touch event:
        if (e.touches[i].target.className == "movable") {
            var id = e.touches[i].identifier;

            // record initial data in the "moving" hash
            moving[id] = {
                identifier : id,
                target : e.touches[i].target,
                mouse : {
                    x : e.touches[i].clientX,
                    y : e.touches[i].clientY
                },
                position : {
                    x : e.touches[i].target.xfmTX,
                    y : e.touches[i].target.xfmTY
                },
                rotation : e.touches[i].target.xfmR,
                scale : e.touches[i].target.xfmS
            };
        }
    }
    if (e.touches[i - 1].target.className === "movable") {

        // move to the front
        moving[id].target.style.zIndex = ++zIndexCount;
        imgId = moving[id].target.id;
        action = "frnt";
        // imgX = e.touches[i - 1].target.xfmTX;
        // imgY = e.touches[i - 1].target.xfmTY;
        // handleSend();

        // reset rotate/scale mode to off
        moving[id].rotateScaleMode = false;
        //***
        updateTransform(moving[id].target);
        //***
    }
    //}
} else if (e.type === "touchmove") {
    // if there are two touches and both are on the *same* element, we're in rotate/scale mode
    if (e.touches.length == 2 && e.touches[0].target == e.touches[1].target) {
        var idA = e.touches[0].identifier, idB = e.touches[1].identifier;

        // if we've previously recorded initial rotate/scale mode data:
        if (moving[idA].rotateScaleMode && moving[idB].rotateScaleMode) {
            // calculate translation, rotation, and scale
            moving[idA].target.xfmTX = ((moving[idA].positionCenter.x - moving[idA].mouseCenter.x) + ((e.touches[0].clientX + e.touches[1].clientX) / 2));
            moving[idA].target.xfmTY = ((moving[idA].positionCenter.y - moving[idA].mouseCenter.y) + ((e.touches[0].clientY + e.touches[1].clientY) / 2));
            moving[idA].target.xfmR = moving[idA].rotation + e.rotation;
            moving[idA].target.xfmS = moving[idA].scale * e.scale;

            action = "move";
            imgId = moving[idA].target.id;
            imgX = moving[idA].target.xfmTX;
            imgY = moving[idA].target.xfmTY;

            updateTransform(moving[idA].target);
        } else {
            // set rotate/scale mode to on
            moving[idA].rotateScaleMode = moving[idB].rotateScaleMode = true;
            // record initial rotate/scale mode data
            moving[idA].mouseCenter = moving[idB].mouseCenter = {
                x : (e.touches[0].clientX + e.touches[1].clientX) / 2,
                y : (e.touches[0].clientY + e.touches[1].clientY) / 2,
            }
            moving[idA].positionCenter = moving[idB].positionCenter = {
                x : moving[idA].target.xfmTX,
                y : moving[idA].target.xfmTY
            }
            action = "move";
            imgId = moving[idA].target.id;
            imgX = moving[idA].target.xfmTX;
            imgY = moving[idA].target.xfmTY;
            updateTransform(moving[idA].target);
        }
    } else {
        // if it's a touch device
        if ("ontouchstart" in window) {
            for (var i = 0; i < e.touches.length; i++) {
                // var i = e.touches.length - 1;
                var id = e.touches[i].identifier;

                // for each touch event:
                if (moving[id]) {
                    // reset rotate/scale mode to off
                    moving[id].rotateScaleMode = false;
                    // calculate translation, leave rotation and scale alone
                    moving[id].target.xfmTX = ((moving[id].position.x - moving[id].mouse.x) + e.touches[i].clientX);
                    moving[id].target.xfmTY = ((moving[id].position.y - moving[id].mouse.y) + e.touches[i].clientY);
                    imgX = moving[id].target.xfmTX;
                    imgY = moving[id].target.xfmTY;
                    action = "move";

                    updateTransform(moving[id].target);
                    doubleMove = false;
                }
            }
        } else {
            var i = e.touches.length - 1;
            var id = e.touches[i].identifier;

            // for each touch event:
            if (moving[id]) {
                // reset rotate/scale mode to off
                moving[id].rotateScaleMode = false;
                // calculate translation, leave rotation and scale alone
                moving[id].target.xfmTX = ((moving[id].position.x - moving[id].mouse.x) + e.touches[i].clientX);
                moving[id].target.xfmTY = ((moving[id].position.y - moving[id].mouse.y) + e.touches[i].clientY);
                imgX = moving[id].target.xfmTX;
                imgY = moving[id].target.xfmTY;
                action = "move";
                updateTransform(moving[id].target);
            }
        }
    }
} else if (e.type == "touchend" || e.type == "touchcancel") {
    // clear each from the "moving" hash
    for (var i = 0; i < e.touches.length; i++)
        delete moving[e.touches[i].identifier];
}
e.preventDefault();
}


function updateTransform(element) {
element.style['-webkit-transform'] = 'translate(' + element.xfmTX + 'px,' + element.xfmTY + 'px) ' + 'scale(' + element.xfmS + ') ' + 'rotate(' + element.xfmR + 'deg)';
action = (action === undefined) ? "trafo" : action;
imgId = element.id;
imgX = (imgX === undefined) ? element.xfmTX.toString() : imgX;
imgY = (imgY === undefined) ? element.xfmTY.toString() : imgY;
scale = element.xfmS;
rotate = element.xfmR;
handleSend();
}

function jsonFlickrApi(data)
{
if (isLocal) {
    var loc = getLocalURI();
    data = JSON.parse(data);
}
for (var i = 0; i < data.photos.photo.length; i++) {
    var p = data.photos.photo[i], img = document.createElement("img");
    if (isLocal == true) {
        img.src = loc + p.name;
    } else {
        img.src = 'img/' +  i + '.jpg';
    }
    img.id = "img" + [i];
    img.className = "movable";
    img.xfmTX = imgData[i][0];
    img.xfmTY = imgData[i][1];
    img.xfmR = imgData[i][2];
    img.xfmS = imgData[i][3];
    img.setAttribute("style", "position: absolute; top: 0px; left: 0px;");
    document.body.appendChild(img);
    updateTransform(img);
}
}

function init() {
// touch event listeners
document.addEventListener("touchstart", touchHandler, false);
document.addEventListener("touchmove", touchHandler, false);
document.addEventListener("touchend", touchHandler, false);
document.addEventListener("touchcancel", touchHandler, false);

// get the 10 latest "interesting images" from Flickr
var flickrApiCall = document.createElement("script");
document.body.appendChild(flickrApiCall);

// set the isLocal variable to boolean true or false
isLocal = getParameterByName("local") == "true";
if (isLocal) {
    jsonFlickrApi(getLocalJSON());

} else {
    flickrApiCall.src = 'https://api.flickr.com/services/rest/?method=flickr.interestingness.getList&api_key=856affa07586845de6fcbfb82520aa3e&per_page=' + 10 + '&format=json';
}
}

function log(message) {
console.log(message);
}

// added by Chad to perform local images
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

function getLocalJSON() {
return '{"photos":{"photo":[{"name":"1.jpg"},{"name":"2.jpg"},{"name":"3.jpg"},{"name":"4.jpg"},{"name":"5.jpg"},{"name":"6.jpg"},{"name":"7.jpg"},{"name":"8.jpg"},{"name":"9.jpg"},{"name":"10.jpg"}]}}';
}

 function getLocalURI() {
// construct the local image location
var localURI = new URI(document.URL || location.href);
localURI = localURI.toString();
localURI = localURI.substring(0, localURI.lastIndexOf("/") + 1) + "localimages/";
return localURI;
}

paintbar脚本代码。

var canvasWidth = '500';
var canvasHeight = '400';
var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var black = "#000000";
var purple = "#B424F0";
var green = "#97F024";
var yellow = "#F0DA24";
var orange = "#F06C24";
var white = "#ffffff";
var red = "#F02437";
var blue = "#2459F0";
var lightblue = "#24F0E4";
var curColor = black;
var clickColor = new Array();

var sizesmall = 1;
var sizenormal = 3;
var sizelarge = 10;
var sizehuge = 20;
var curSize = sizenormal;
var clickSize = new Array();

var mode = "free";
var prevMode = "free";
var prevColor = "#000000";
var prevSize = 3;

var colorName = "black";
var sizeName = "normal";

var name = '';

$(function(){
if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i)) || (navigator.userAgent.match(/iPad/i))) {
    $('#customWidget').hide();
}
 $('.colorpicker_submit').live('click',function(){
     var colorPicked = $('#selColor').val();
     curColor = colorPicked;
     prevColor = colorPicked;
 });

 $('#green').click(function(){
     curColor = green;
     prevColor = green;
     colorName = "green";
     updateMode();
 });

  $('#yellow').click(function(){
     curColor = yellow;
     prevColor = yellow;
     colorName = "yellow";
     updateMode();
 });

  $('#orange').click(function(){
     curColor = orange;
     prevColor = orange;
     colorName = "orange";
     updateMode();
 });

  $('#purple').click(function(){
     curColor = purple;
     prevColor = purple;
     colorName = "purple";
     updateMode();
 });

  $('#lightblue').click(function(){
     curColor = lightblue;
     prevColor = lightblue;
     colorName = "lightblue";
     updateMode();
 });

  $('#black').click(function(){
     curColor = black;
     prevColor = black;
     colorName = "black";
     updateMode();
 });

 //red
  $('#red').click(function(){
     curColor = red;
     prevColor = red;
     colorName = "red";
     updateMode();
 });

  $('#blue').click(function(){
     curColor = blue;
     prevColor = blue;
     colorName = "blue";
     updateMode();
 });

 //white
  $('#white').click(function(){
     curColor = "#ffffff";
     prevColor = "#ffffff";
 });


 //eraser
  $('#eraser').click(function(){
     curColor = "#ffffff";
     prevColor = "#ffffff";
     mode="free";
     prevMode="free";

     $('.nav li').find('a').removeClass('active');
     $('.nav li').filter('[id=eraser]').find('a').addClass('active');
     $('.nav li').filter('[id='+sizeName+']').find('a').addClass('active');
  });

 //size=============
 //small
 $('#small').click(function(){
     curSize = sizesmall;
     prevSize = sizesmall;
     sizeName = "normal";
     updateMode();
 });
 //normal
 $('#normal').click(function(){
     curSize = sizenormal;
     prevSize = sizenormal;
     sizeName = "normal";
     updateMode();
 });
 //large
 $('#large').click(function(){
     curSize = sizelarge;
     prevSize = sizelarge;
     sizeName = "large";
     updateMode();
 });
 //huge
 $('#huge').click(function(){
     curSize = sizehuge;
     prevSize = sizehuge;
     sizeName = "huge";
     updateMode();
 });

$('#elipse').click(function(){
    mode="elipse";
    prevMode="elipse";
    updateMode();
});

$('#rectangle').click(function(){
    mode="rectangle";
    prevMode="rectangle";
    updateMode();
});

$('#straight').click(function(){
    mode="straight";
    prevMode="straight";
    updateMode();
});

$('#free').click(function(){
    curColor = prevColor;
    //prevColor = black;
    mode="free";
    prevMode="free";
    updateMode();
});

$('.chatLink').click(function(){
    $('.chatBox').toggle();
    $('#msg').focus();
});

function updateMode(){
    if(curColor=="#ffffff"){
        curColor = black;
        prevColor = black;
    }
    $('#mode').html(mode);

    $('.nav li').find('a').removeClass('active');
    $('.nav li').filter('[id='+mode+']').find('a').addClass('active');
    $('.nav li').filter('[id='+sizeName+']').find('a').addClass('active');
    $('.nav li:eq(0)').find('.sub li').filter('[id='+colorName+']').find('a').addClass('active');
}

//====================================

// This demo depends on the canvas element
if(!('getContext' in document.createElement('canvas'))){
    alert('Sorry, it looks like your browser does not support canvas!');
    return false;
}

// The URL of your web server (the port is set in app.js)
//var url = 'http://192.168.0.113:8080';

var doc = $(document),
    win = $(window),
    canvas = $('#paper'),
    ctx = canvas[0].getContext('2d');

    $('#paper').attr('width','500');
    $('#paper').attr('height','400');

    var tmp_canvas = document.createElement('canvas');
    var tmp_ctx = tmp_canvas.getContext('2d');
    tmp_canvas.id = 'tmp_canvas';

    tmp_canvas.width = canvasWidth;
    tmp_canvas.height = canvasHeight;

    var sketch = document.querySelector('#sketch');
    sketch.appendChild(tmp_canvas); 

// Generate an unique ID
var id = Math.round($.now()*Math.random());

// A flag for drawing activity
var drawing = false;

var clients = {};
var cursors = {};



var prev = {};

canvas.on('mousedown',function(e){
    e.preventDefault();
    drawing = true;

    mode = prevMode;
    curColor = prevColor;
    curSize = prevSize;

    prev.x = e.pageX;
    prev.y = e.pageY;

});

//doc.('mouseup mouseleave',function(){
doc.bind('mouseup mouseleave', function(){  

    drawing = false;

    ctx.drawImage(tmp_canvas, 0, 0);
    //tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
});

var lastEmit = $.now();

doc.on('mousemove',function(e){
    if($.now() - lastEmit > 30){
        lastEmit = $.now();
    }


    if(drawing){
        e.preventDefault();
        drawLine(prev.x, prev.y, e.pageX, e.pageY,curColor,curSize,mode,id);
        if(mode=="free"){
            prev.x = e.pageX;
            prev.y = e.pageY;
        }
    }
});


if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i)) || (navigator.userAgent.match(/iPad/i))) {
    canvas.on('touchstart',function(e){
        e.preventDefault();
        var orig = e.originalEvent;
        drawing = true;  
        prev.x = orig.targetTouches[0].pageX;  
        prev.y = orig.targetTouches[0].pageY;
    });

    doc.bind('touchend touchcancel',function(e){
        drawing = false;
        ctx.drawImage(tmp_canvas, 0, 0);
    });

    var lastEmit = $.now();
    doc.on('touchmove',function(e){
        //e.preventDefault();
        var orig = e.originalEvent;  
        ex = orig.targetTouches[0].pageX;  
        ey = orig.targetTouches[0].pageY;
        if($.now() - lastEmit > 30){
            lastEmit = $.now();
        }

        // Draw a line for the current user's movement, as it is
        // not received in the socket.on('moving') event above

        if(drawing){
            drawLine(prev.x, prev.y, ex, ey, curColor, curSize, mode);
            if(mode=="free"){
                prev.x = ex;
                prev.y = ey;
            }
        }
    });
}

// Remove inactive clients after 10 seconds of inactivity
setInterval(function(){

    for(ident in clients){
        if($.now() - clients[ident].updated > 200){
            cursors[ident].remove();
            delete clients[ident];
            delete cursors[ident];
        }
    }

},350);


function drawLine(clickX, clickY, tox, toy,curColor,curSize,mode,dataId){
tmp_ctx.beginPath();
tmp_ctx.lineCap = "round";
tmp_ctx.lineJoin = "round"; 
tmp_ctx.fillStyle = "solid";
tmp_ctx.strokeStyle = curColor;
tmp_ctx.lineWidth = curSize;

//free line
if(mode=="free"){
    tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
    tmp_ctx.moveTo(clickX, clickY);
    tmp_ctx.lineTo(tox, toy);
    //tmp_ctx.closePath();
    tmp_ctx.stroke();
    ctx.drawImage(tmp_canvas, 0, 0);
}

//straight line
else if(mode=="straight"){
    tmp_ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    tmp_ctx.moveTo(clickX, clickY);
    tmp_ctx.lineTo(tox, toy);
    tmp_ctx.closePath();
    tmp_ctx.stroke();
}

//rectangle
else if(mode=="rectangle"){
    tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
    var x = Math.min(tox, clickX);
    var y = Math.min(toy, clickY);
    var width = Math.abs(tox - clickX);
    var height = Math.abs(toy - clickY);
    tmp_ctx.strokeRect(x, y, width, height);
}

//ellipse
else if(mode=="elipse"){
    tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
    var x = Math.min(tox, clickX);
    var y = Math.min(toy, clickY);
    var w = Math.abs(tox - clickX);
    var h = Math.abs(toy - clickY);
}
drawEllipse(tmp_ctx, x, y, w, h);

}

function drawEllipse(ctx, x, y, w, h) {
var kappa = .5522848,
ox = (w / 2) * kappa, // control point offset horizontal
oy = (h / 2) * kappa, // control point offset vertical
xe = x + w,           // x-end
ye = y + h,           // y-end
xm = x + w / 2,       // x-middle
ym = y + h / 2;       // y-middle

ctx.beginPath();
ctx.moveTo(x, ym);
ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
ctx.closePath();
ctx.stroke();
}
$('#clearCanvas').click(function(){
tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
ctx.clearRect(0, 0, canvasWidth, canvasHeight); // Fill in the canvas with white

ctx.drawImage(tmp_canvas, 0, 0);

curColor = black;
prevColor = black;
updateMode();


});
//=============================
});

//chat ========================
//=============================
$(".btnSend").click(function(e) {
e.preventDefault();
if($("textarea#msg").val()!=""){
    $("p#data_recieved").append("<br /><b>" + name + '</b>: ' + $("textarea#msg").val());
    divx = document.getElementById('msgLog');
    divx.scrollTop = divx.scrollHeight;
}
$("textarea#msg").val('');
});






function keyEnter(e){
if ( e.keyCode == 13 ){ 
e.preventDefault();
if($("textarea#msg").val()!=""){
    $("p#data_recieved").append("<br /><b>" + name + '</b>: ' + $("textarea#msg").val());
    divx = document.getElementById('msgLog');
    divx.scrollTop = divx.scrollHeight;
}
$("textarea#msg").val('');  
}
}

function closePalette(){
$('.sub').removeClass('open');
}

1 个答案:

答案 0 :(得分:1)

以下是一种方法:

  • 在画布上拖动img元素的副本,使其像素成为画布内容的一部分

  • 在画布上涂抹一些线条

  • 将img像素(带涂鸦)导出到新的img元素

enter image description here

演示: http://jsfiddle.net/m1erickson/83o87v32/

以下是一种方法概述:

  • 将jQuery的拖放功能添加到图像源工具箱中的每个img元素。

  • 使用:context.drawImage

  • 将图像像素绘制到画布像素上
  • 在包含图像的画布像素上进行涂鸦。

  • 从画布中将图像像素加上涂鸦像素导出到新的img元素。

示例带注释的代码:

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.min.js"></script>
<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    #exportedImgs{border:1px solid green; padding:15px; width:300px; height:70px;}
    #toolbar{
      width:350px;
      height:35px;
      border:solid 1px blue;
    }
</style>
<script>
$(function(){

    // get references to the canvas and its context
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    // get the offset position of the canvas
    var $canvas=$("#canvas");
    var Offset=$canvas.offset();
    var offsetX=Offset.left;
    var offsetY=Offset.top;

    var x,y,width,height;

    // select all .tool's
    var $tools=$(".tool");


    // make all .tool's draggable
    $tools.draggable({
            helper:'clone',
    });


    // assign each .tool its index in $tools
    $tools.each(function(index,element){
        $(this).data("toolsIndex",index);
    });


    // make the canvas a dropzone
    $canvas.droppable({
        drop:dragDrop,
    });


    // handle a drop into the canvas
    function dragDrop(e,ui){

        // get the drop point (be sure to adjust for border)
        x=parseInt(ui.offset.left-offsetX)-1;
        y=parseInt(ui.offset.top-offsetY);
        width=ui.helper[0].width;
        height=ui.helper[0].height;

        // get the drop payload (here the payload is the $tools index)
        var theIndex=ui.draggable.data("toolsIndex");

        // drawImage at the drop point using the dropped image 
        // This will make the img a permanent part of the canvas content
        ctx.drawImage($tools[theIndex],x,y,width,height);

    }


    // Just testing: Scribble some lines over the dropped img pixels
    // In your app you can scribble any way you desire
    $('#scribble').click(function(){
        ctx.beginPath();
        ctx.moveTo(x-20,y-20);
        ctx.lineTo(x+10,y+height+5);
        ctx.lineTo(x+20,y-20);
        ctx.lineTo(x+width,y+height+5);
        ctx.stroke();
        console.log('scribble',x,y,width,height);
    });

    // export the img pixels plus the scribble pixels
    // (1) Draw the desired pixels onto a temporary canvas
    // (2) Create a new img element from the temp canvas's dataURL
    // (3) Append that new img to the #exportedImgs div
    $('#export').click(function(){
        var tempCanvas=document.createElement('canvas');
        var tempCtx=tempCanvas.getContext('2d');
        tempCanvas.width=width;
        tempCanvas.height=height;
        tempCtx.drawImage(canvas,x,y,width,height,0,0,width,height);
        var img=new Image();
        img.onload=function(){
            $('#exportedImgs').append(img);
        };
        img.src=tempCanvas.toDataURL();
    });

}); // end $(function(){});
</script>
</head>
<body>
    <p>Drag from blue toolbar onto red canvas<br>Then press the action buttons below</p>
    <div id="toolbar">
        <img class="tool" width=32 height=32 src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg" crossOrigin='anonymous'>
        <img class="tool" width=32 height=32 src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-2.jpg" crossOrigin='anonymous'>
        <img class="tool" width=32 height=32 src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg" crossOrigin='anonymous'>
        <img class="tool" width=32 height=32 src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-4.jpg" crossOrigin='anonymous'>
    </div><br>
    <canvas id="canvas" width=350 height=150></canvas><br>
    <button id=scribble>Simulate drawing on canvas</button>
    <button id=export>Export to img element</button>
    <p>Exported images will be put in this green Div</p>
    <div id=exportedImgs>
    </div>
</body>
</html>