我想将画布外部生成的图像拖动到画布中绘制一些线条和形状,然后移出画布。我使用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');
}
答案 0 :(得分:1)
以下是一种方法:
在画布上拖动img元素的副本,使其像素成为画布内容的一部分
在画布上涂抹一些线条
将img像素(带涂鸦)导出到新的img元素
演示: 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>