I'm using Canvas to let my users "design" an add that later is transformed into an image to be displayed on my website. In this design, the users can add their logo. I'm using this function to add the logo to the canvas:
function canvasLogo(){
var x = 70;
var y = 70;
// var width = 500;
// var height = 500;
var imageObj = new Image();
imageObj.onload = function() {
var imageWidth = imageObj.width;
var imageHeight = imageObj.height;
if (imageHeight > imageWidth) {
imageWidth = (imageWidth / imageHeight) * 490;
imageHeight = 490;
} else {
imageHeight = (imageHeight / imageWidth) * 490;
imageWidth = 490;
}
x = x + (500 - imageWidth) / 2;
y = y + (500 - imageHeight) / 2;
roundedImage(70, 70, 500, 500, 30, 0, 0, 30);
global.kanvas.ctx.clip();
global.kanvas.ctx.fillStyle = "white";
global.kanvas.ctx.fillRect(70, 70, 500, 500);
global.kanvas.ctx.drawImage(imageObj, x, y, imageWidth, imageHeight);
console.log("Logo cargado");
};
imageObj.src = global.kanvas.logo;
}
And then the users add other things like text and colors and finally when they click the button to create the add I use:
function crearAnuncio(elm){
if($("#advanced-wizard").valid() && global.form.idMetodoPago > 0){
NProgress.start();
global.kanvas.size = "z";
setTimeout(function(){
render();
global.kanvas.ctx.scale(1*3,1*3);
setTimeout(function(){
kanv = document.getElementById(global.kanvas.canvasId);
var imgB = kanv.toDataURL("image/png");
var serialForm = $("#advanced-wizard").serialize();
var arguments = serialForm+"&file="+encodeURIComponent(imgB);
deliver(arguments);
console.log(global.request.response);
// Run paypal
if(global.form.idMetodoPago==1){
document.getElementById('paypal_process').submit();
} else {
global.request.response = '';
deliver_site(arguments, "success.php");
window.location.href="success.php?token="+global.request.response;
}
NProgress.done();
}, 550);
},150);
} else {
alert('Seleccione el método de pago ');
}
}
To transform the canvas into a png which is then displayed on my site.
The thing is that sometimes (haven't been able to replicate the error myself and the clients say it only happens "sometimes") their logo is not rendered in the final image (text and colors do). The space for the logo is just blank. The clients tell me that they could see their logo on the canvas before pressing the generate button.
It doesn't appear to be related to operative system or browser since the same computer sometimes creates the add alright and sometimes without the logo. I thought it was my server so I changed and upgraded the hosting and it still happened.
Any idea on what could be going wrong?
Related
I am trying to display multiple images on canvas. The most recently added image on canvas must be draggable. This is the HTML code.
<canvas id="panoramaCanvas" width=1500 height=1000></canvas>
I am using an object to keep the track of already added images. Each time I drag Image on canvas then this method gets called. storeData stores currently added image data.
var storeData = []; // Object
var panoramaImg = new Image();
var imgNumber = 0;
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
//
var url = e.dataTransfer.getData('text/plain');
// for img elements, url is the img src so
// create an Image Object & draw to canvas
if (url) {
panoramaImg.onload = function () {
panoramaCtx.globalAlpha = 0.4;
panoramaCtx.drawImage(panoramaImg, 0, 0, this.width, this.height, 0, 0, 500, 500);
panoramaCtx.globalAlpha = 1.0;
storeData.push({
imgData: panoramaImg,
imgNo: imgNumber + 1,
xPoint: 0,
yPoint: 0,
});
imgNumber = imgNumber + 1;
}
//img.width, img.height, 0, 0, rangeWidth.value, rangeHeight.value
panoramaImg.src = url;
// for img file(s), read the file & draw to canvas
} else {
handleFiles(e.dataTransfer.files);
}
}
On mouse event this method is called.
var canvasOffset1 = $("#panoramaCanvas").offset();
var offsetX1 = canvasOffset1.left;
var offsetY1 = canvasOffset1.top;
var canvasWidth = panoramaCanvas.width;
var canvasHeight = panoramaCanvas.height;
var isDragging = false;
function handleMouseDownEvent(e) {
canMouseX = parseInt(e.clientX - offsetX1);
canMouseY = parseInt(e.clientY - offsetY1);
// set the drag flag
isDragging = true;
}
function handleMouseUpEvent(e) {
canMouseX = parseInt(e.clientX - offsetX1);
canMouseY = parseInt(e.clientY - offsetY1);
// clear the drag flag
isDragging = false;
}
function handleMouseOutEvent(e) {
canMouseX = parseInt(e.clientX - offsetX1);
canMouseY = parseInt(e.clientY - offsetY1);
// user has left the canvas, so clear the drag flag
//isDragging=false;
}
function handleMouseMoveEvent(e) {
canMouseX = parseInt(e.clientX - offsetX1);
canMouseY = parseInt(e.clientY - offsetY1);
// if the drag flag is set, clear the canvas and draw the image
if (isDragging) {
panoramaCtx.clearRect(0, 0, canvasWidth, canvasHeight);
panoramaCtx.globalAlpha = 0.4;
if (storeData.length > 1)
{
for (var i = 0; i <= storeData.length - 2; i++) {
panoramaCtx.drawImage(storeData[i].imgData, storeData[i].xPoint, storeData[i].yPoint,
500, 500);
}
}
panoramaCtx.drawImage(panoramaImg, canMouseX - 1128 / 2, canMouseY - 120 / 2, 500, 500);
panoramaCtx.globalAlpha = 1.0;
storeData[imgNumber - 1].xPoint = canMouseX - 1128 / 2;
storeData[imgNumber - 1].yPoint = canMouseY - 120 / 2;
console.log(storeData);
}
}
When I add first image everything works fine with mouse events but when I add second image the image data first change change to image data of second image.
When I tried to change the position of second second image and image data of first image changes.
Where am I doing wrong while displaying image?
You are creating a single HTMLImageElement panoramaImg. The imgData property of all your storeData members are thus the same and only HTMLImageElement which points to the last dropped image.
Simply create a new Image() in your drop handler instead of reusing the same.
Below is my script which was working fine.
But right now my image url was static at bottom of the script,
But i want to make it dynamic using file upload button.
Means if i select a file from upload button, then it will preview both images.
Below is the line
img.src = "https://image.ibb.co/bGtv0z/Product_Two.jpg";
where my image was fixed. i want to get this URL from file upload button.
Please help me to make it dynamic.
var img = new Image(),
$canvas = $("<canvas>"),
canvas = $canvas[0],
context;
var removeBlanks = function(imgWidth, imgHeight) {
var imageData = context.getImageData(0, 0, imgWidth, imgHeight),
data = imageData.data,
getRBG = function(x, y) {
var offset = imgWidth * y + x;
return {
red: data[offset * 4],
green: data[offset * 4 + 1],
blue: data[offset * 4 + 2],
opacity: data[offset * 4 + 3]
};
},
isWhite = function(rgb) {
// many images contain noise, as the white is not a pure #fff white
return rgb.red > 242 && rgb.green > 240 && rgb.blue > 240;
},
scanY = function(fromTop) {
var offset = fromTop ? 1 : -1;
// loop through each row
for (var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {
// loop through each column
for (var x = 0; x < imgWidth; x++) {
var rgb = getRBG(x, y);
if (!isWhite(rgb)) {
return y;
}
}
}
return null; // all image is white
},
scanX = function(fromLeft) {
var offset = fromLeft ? 1 : -1;
// loop through each column
for (var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {
// loop through each row
for (var y = 0; y < imgHeight; y++) {
var rgb = getRBG(x, y);
if (!isWhite(rgb)) {
return x;
}
}
}
return null; // all image is white
};
var cropTop = scanY(true),
cropBottom = scanY(false),
cropLeft = scanX(true),
cropRight = scanX(false),
cropWidth = cropRight - cropLeft,
cropHeight = cropBottom - cropTop;
var $croppedCanvas = $("<canvas>").attr({
width: cropWidth,
height: cropHeight
});
// finally crop the guy
$croppedCanvas[0].getContext("2d").drawImage(canvas,
cropLeft, cropTop, cropWidth, cropHeight,
0, 0, cropWidth, cropHeight);
$("#oldimg").
append("<p>same image with white spaces cropped:</p>").
append($croppedCanvas);
console.log(cropTop, cropBottom, cropLeft, cropRight);
};
img.crossOrigin = "anonymous";
img.onload = function() {
$canvas.attr({
width: this.width,
height: this.height
});
context = canvas.getContext("2d");
if (context) {
context.drawImage(this, 0, 0);
$("#newimg").append("<p>original image:</p>").append($canvas);
removeBlanks(this.width, this.height);
} else {
alert('Get a real browser!');
}
};
// define here an image from your domain
img.src = "https://image.ibb.co/bGtv0z/Product_Two.jpg";
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<body style="background-color:#ddd">
<input type="file" src="">
<div id="oldimg"></div>
<div id="newimg"></div>
</body>
When you choose a file in file input it is only in temporary memory and not on a server. Thus you will be unable to display it.
In order to do to what you want, you can either add a form that uploads the file and after file upload you can display it or use a FileReader. But this question was already answered, so please before asking a question try to find the solution by your own first.
Here is an answer with FileReader
I want to have a canvas with a background image, and draw rectangles over the top. The rectangles are called hotSpots in my application. They get drawn to the canvas then quickly disappear. How can I make them stay?
appendSection() first appends a picture with appendPicture() which just appends a canvas to a div, then after that function has run, the canvas and context is made, then for every hotSpot, which there are 3 in this case, it will draw a rect, which it does, then they disappear.
function appendSection(theSection, list) {
list.append('<label class="heading">' + theSection.description + '</label><br/><hr><br/>');
if (theSection.picture) {
appendPicture(list, theSection);
var canvas = document.getElementById('assessmentImage');
var ctx=canvas.getContext("2d");
var img=new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0,canvas.width,canvas.height);
}
img.src = "data:image/jpeg;base64,"+ theSection.picture;
if(theSection.allHotSpots.length > 0) {
for( var x = 0; x < theSection.allHotSpots.length; x++) {
appendHotSpot(list, theSection.allHotSpots[x], theSection.thePicture, ctx);
}
}
}
appendSectionQuestions(theSection, list);
if (theSection.allSubSections) {
for (var x = 0; x < theSection.allSubSections.length; x++) {
var theSectionA = theSection.allSubSections[x];
appendSection(theSectionA, list);
}
}
}
function appendHotSpot(list, HotSpot, picture, ctx) {
var imageWidth = document.getElementById('assessmentImage' + platform).clientWidth;
var imageHeight = document.getElementById('assessmentImage' + platform).clientHeight;
var xScale = imageWidth / picture.xSize;
var yScale = imageHeight / picture.ySize;
HotSpot.topLeft = [Math.round(HotSpot.topLeft[0] * xScale), Math.round(HotSpot.topLeft[1] * yScale)];
HotSpot.bottomRight = [Math.round(HotSpot.bottomRight[0] * xScale), Math.round(HotSpot.bottomRight[1] * yScale)];
var rect = {x1: HotSpot.topLeft[0], y1: HotSpot.topLeft[1], x2: HotSpot.bottomRight[0], y2: HotSpot.bottomRight[1]};
ctx.fillStyle = "#FF0000";
ctx.fillRect(rect.x1, rect.y1, rect.x2, rect.y2);
//addRect("blue", rect);
}
function appendPicture(list, theSection) {
list.append('<div id="wrapper' + platform + '" style="width:100%; text-align:center">\
<canvas class="assessmentImageSmall" style="width:100%;" id="assessmentImage' + platform + '" align="middle" ></canvas>\
<!--<p style="color:#666;" id="imageInstruction">Tap image to enlarge.</p>-->\
</div>');
$("#wrapper").kendoTouch({
tap: function (e) {
switchImage();
}
});
}
It looks like your rects are being drawn and then the image (which loads asynchronously) is eventually loaded and then drawn on top of the rects--making them disappear.
Put the if(theSection.allHotSpots.length > 0 inside the onload so the image doesn't later clobber the rects.
The problem I have is that when the page is loaded sometimes it displays all the images, sometimes just 2 images and sometimes all. I don´t know why this is happening.
Any ideas?
$('#banners .box img').each(function(index){
var randval = (index+1)*100;
var _this = $(this)
setTimeout(function(){
_this.attr('id' , 'banner' + index);
to_canvas('banner' + index, 300, 223);
}, randval)
});
to_canvas function:
function to_canvas(im,w,h){
var canvas;
var imageBottom;
var im_w = w;
var im_h = h;
var imgData;
var pix;
var pixcount = 0;
var paintrow = 0;
var multiplyColor = [70, 116, 145];
var x_offset = Math.floor(($('#'+im).attr('width') - im_w)/2);
var y_offset = Math.floor(($('#'+im).attr('height') - im_h)/2);
imageBottom = document.getElementById(im);
canvas = document.createElement('canvas');
canvas.width = im_w;
canvas.height = im_h;
imageBottom.parentNode.insertBefore(canvas, imageBottom);
ctx = canvas.getContext('2d');
ctx.drawImage(imageBottom, -x_offset , -y_offset);
imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
pix = imgData.data;
for (var i = 0 ; i < pix.length; i += 4) {
if(pixcount > im_w - (im_h - paintrow) ){
pix[i ] = multiply(multiplyColor[0], pix[i ]);
pix[i+1] = multiply(multiplyColor[1], pix[i+1]);
pix[i+2] = multiply(multiplyColor[2], pix[i+2]);
}
if(pixcount < im_w-1){
pixcount++;
}else{
paintrow++;
pixcount = 0;
}
}
ctx.putImageData(imgData, 0, 0);
$('#'+im).remove();
}
function multiply(topValue, bottomValue){
return topValue * bottomValue / 255;
}
I'm using the canvas function to add a triangle with multiply effect (like Photoshop).
Make sure the images are loaded :
$('#banners .box img').each(function(index, elem){
var randval = (index+1)*100,
self = this,
img = new Image(); // create image object
img.onload = function() { // wait until it's loaded
setTimeout(function(){
self.id = 'banner' + index;
to_canvas('banner' + index, 300, 223);
}, randval)
}
img.src = elem.src; // set source to same as elem
});
Wrap it all in this code to make sure the images are loaded before you execute your script. When you initially load your page, it caches the images(stores them in temp memory), but not before all your elements are rendered. When you reload, it reads the images from the cache–which is much faster than refetching the images again from the server–and therefore the images load about the same time everything else does. This results in visible images.
Like I said, to get your page to work, make sure everything is loaded, then run your script.
$(window).load(function(){
...your scripts(you can exclude functions definitions from this scope)
}
I would like an image to move to the left if the mouse is to the left of the screen and to the right if the mouse to the right of the screen, using javascript, here is the code I have so far:
var dirx = 0;
var spdx = 35;
var imgLeftInt;
var imgTopInt;
var imgHeight;
var imgWidth;
var divWidth;
var divHeight;
var t;
var tempX;
var tempY;
So I'm pretty sure I'm not missing any variables...
function animBall(on) {
imgLeftInt = parseInt(document.images['logo'].style.left);
imgTopInt = parseInt(document.images['logo'].style.top);
imgHeight = parseInt(document.images['logo'].height);
imgWidth = parseInt(document.images['logo'].width);
divWidth = parseInt(document.images['container'].width);
if (tempX > 779){
dirx = 1;
}
else if(tempX < 767){
dirx = 2;
}
else {
spdx = 0;
}
So if tempX, which should be the x coordinate of the mouse location, is bigger than 779, which is the halfway point of the div tag, the image should go right. If it's less than that, it should go left, and otherwise, the speed should be zero, as in it should stay still.
if(dirx == 1){
goRight();
} else if(dirx == 2) {
goLeft();
}
}
function getMouseXY(e) {
tempX = e.clientX;
tempY = e.clientY;
}
I found hundreds of different ways to get the mouse location, but this was off W3C so I assume it works.
function goRight() {
document.images['logo'].style.left = imgLeftInt+spdx +"px";
if (imgLeftInt > (divWidth-imgWidth)){
dirx = 2;
spdx= 20;
}
}
function goLeft() {
document.images['logo'].style.left = (imgLeftInt-spdx) +"px";
if (imgLeftInt < 5){
dirx = 1;
spdx= 20;
}
}
</script>
So that's my whole script.
<div id="container" onmousemove="getMouseXY(event);" width="1546" height="423">
Start Animation Stop Animation <br />
<img src="http://qabila.tv/images/logo_old.png" style="position:absolute;left:10px;top:20px;" id="logo" />
</div>
I left the dependency on the mouse location to the very end so the animation script works fine (or at least worked, unless I broke something trying to get it to read the mouse location).
Any ideas what I'm doing wrong??
If it's any help, I've hosted the code here.
I went to your link and tried debugging your code. I get an error on line 21 because your document has no "container" image ("container" is a div).
At the start of your question, you said you wanted to know mouse position relative to center of "screen". For that, you'd probably want to use window.innerWidth instead of the width attribute that you set on your div.
Well that needed a whole load of work, anyway, I have done some of it for you and you can now see things partially working, but you will need to play with it on jsfiddle. Perhaps you can now open some specific questions regarding getting this to work.
<div id="container" width="1546" height="423"> <a id="start" href="#">Start Animation</a> <a id="stop" href="#">Stop Animation</a>
<br />
<img src="http://qabila.tv/images/logo_old.png" style="position:absolute;left:10px;top:20px;" id="logo" />
</div>
/*jslint sub: true, maxerr: 50, indent: 4, browser: true */
/*global */
(function () {
"use strict";
var start = document.getElementById("start"),
stop = document.getElementById("stop"),
container = document.getElementById("container"),
logo = document.getElementById("logo"),
dirx = 0,
spdx = 35,
imgLeftInt,
imgTopInt,
imgHeight,
imgWidth,
divWidth,
divHeight,
t,
tempX,
tempY;
function getMouseXY(e) {
tempX = e.clientX;
tempY = e.clientY;
}
function goRight() {
logo.style.left = imgLeftInt + spdx + "px";
if (imgLeftInt > (divWidth - imgWidth)) {
dirx = 2;
spdx = 20;
}
}
function goLeft() {
logo.style.left = (imgLeftInt - spdx) + "px";
if (imgLeftInt < 5) {
dirx = 1;
spdx = 20;
}
}
// attribute on unused
function animBall(on) {
imgLeftInt = parseInt(logo.style.left, 10);
imgTopInt = parseInt(logo.style.top, 10);
imgHeight = parseInt(logo.height, 10);
imgWidth = parseInt(logo.width, 10);
divWidth = parseInt(container.width, 10);
if (tempX > 779) {
dirx = 1;
} else if (tempX < 767) {
dirx = 2;
} else {
spdx = 0;
}
if (dirx === 1) {
goRight();
} else if (dirx === 2) {
goLeft();
}
}
function startAnim() {
t = setInterval(animBall, 80);
}
start.addEventListener("click", startAnim, false);
function stopAnim() {
clearInterval(t);
}
stop.addEventListener("click", stopAnim, false);
container.addEventListener("mousemove", getMouseXY, false);
}());
Why don't you usee the html5 canvas and gee.js
Here's the js fiddle result (it may take a while to load, but that's fault of jsfiddle, the script will load much faster once on your website): http://jsfiddle.net/wLCeE/7/embedded/result/
and here's the much simpler code to make it work:
var g = new GEE({
width: 500,
height: 423,
container: document.getElementById('canvas')
});
var img = new Image(); // Create new img element
img.onload = function () {
demo(g)
};
img.src = 'http://qabila.tv/images/logo_old.png'; // Set source path
function demo(g) {
var style = "left"
g.draw = function () {
if (g.mouseX > g.width / 2 && style == "left") styleRight()
else if (g.mouseX < g.width / 2 && style == "right") styleLeft()
}
function styleLeft() {
style = "left"
g.ctx.clearRect(0, 0, g.width, g.height)
g.ctx.drawImage(img, 0, 0)
}
function styleRight() {
style = "right"
g.ctx.clearRect(0, 0, g.width, g.height)
g.ctx.drawImage(img, g.width - img.width, 0)
}
}