Who knows about canvas and new Image() ? | Sololearn: Learn to code for FREE!
New course! Every coder should learn Generative AI!
Try a free lesson
0

Who knows about canvas and new Image() ?

Hey people, I try to get this running: https://code.sololearn.com/WOp31WwyIOoe/# but it's buggy. It works properly only if you resize the window and not onLoad. Why?? Please, help me out. Thank you, Claude

1st Nov 2020, 2:05 AM
Claude Dumont
Claude Dumont - avatar
12 Answers
+ 1
In your updated code, I see broken image links when I run it. I see "Failed to load resource: net::ERR_INVALID_URL" in the JavaScript console but I'm not sure why the data URL is invalid. The base 64 encoding looks fine but I didn't test it anywhere outside of your page. toDataURL won't work well if canvas might be considered "tainted" ( https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image#:~:text=As%20soon%20as%20you%20draw,an%20exception%20to%20be%20thrown. ). It might be worth experimenting with loading the image through a hidden img element in the page instead of using the Image class to see if loading the image that way makes a difference. I adjusted to use the background-image but removed the code after you copied from it.
1st Nov 2020, 11:37 PM
Josh Greig
Josh Greig - avatar
+ 2
Your script never adds the newly created canvas elements to the document model. Don't you want to append them to corresponding div class="pattern" elements to make them visible? Your div class="pattern" elements have 0 width and 0 height which will make them impossible to see until that's fixed. You might want to set those dimensions in CSS if adding the canvas to each of them doesn't fix it. Your browser's inspect and developer tools can help you see the dimensions to troubleshoot them. Drawing images on a canvas adds some complexity around things like cross origin policy and inefficiencies around needing to convert to data URL's. Have you considered using CSS properties like background-image, background-position, background-size directly on your div class="pattern" elements to crop off the desired sections of images on each div? A background image won't introduce any CORS concern, should be more efficient, and simpler unless I'm missing something.
1st Nov 2020, 7:10 AM
Josh Greig
Josh Greig - avatar
0
window.addEventListener('load', function () { let clWidth = document.getElementById('bg').clientWidth; let clHeight = document.getElementById('bg').clientHeight; const RDS = 20; // Cuts const pW = (clWidth / RDS); const pH = (clHeight / RDS); var elements = document.getElementById('cuts'); var j; var k; for (k = 0; k < RDS; k++) { for (j = 0; j < RDS; j++) { elements.innerHTML += '<div class="pattern"> </div><div class="pback"> </div>'; } elements.innerHTML += '<br />'; } var element = elements.getElementsByClassName('pattern'); var elBack = elements.getElementsByClassName('pback'); var i; var l; var count = 0; for (l = 0; l < RDS; l++) { for (i = 0; i < RDS; i++) { var current = element[count]; var currBack = elBack[count]; current.style.width = pW + 'px'; current.style.height = pH + 'px'; currBack.style.width = pW + 'px'; currBack.style.height = pH + 'px'; var elementX = current.offsetLeft * (-1); var elementY = pH * (-1) * l; var elementXY = elementX + 'px' + ' ' + elementY + 'px'; var elBackX = pW * i; var elBackY = pH * l; current.style.backgroundImage = 'url(https://picsum.photos/1920/1080?random=1)'; current.style.backgroundPosition = elementXY; current.style.backgroundRepeat = 'no-repeat'; currBack.style.backgroundImage = 'url(https://picsum.photos/1920/1080?random=2)'; currBack.style.backgroundPosition = elementXY; currBack.style.backgroundRepeat = 'no-repeat'; currBack.style.left = elBackX + 'px'; currBack.style.top = elBackY + 'px'; count += 1; } } }, false)
1st Nov 2020, 5:33 PM
Claude Dumont
Claude Dumont - avatar
0
Thank you for your answer. I think what you mean is this (below)? That's working but it's really ressource heavy. Therefore I tried to "cut" the image into pieces and show it on elements. But I got lost somewhere and don't know if what I'm trying to do is possible...
1st Nov 2020, 5:37 PM
Claude Dumont
Claude Dumont - avatar
0
What do you mean by "resource heavy"? Was the animation choppy or slow? I'm not sure why it would be any slower than this canvas approach. I'm sure what you're doing is possible but you need to fix the problems I mentioned earlier. You need to add the canvas to a document element for it to be visible and the div must be greater than 0 by 0 in size. I'm not sure why but some of the image requests get weird responses when I check the browser dev tools network feature. It might be related CORS or something else. I edited your code to load the images by adding them directly to the document, draw from img elements, and was able to draw them on the canvas and make the results visible. Regardless of why I'm seeing some of the requests to https://i.picsum.photos/id/232/1920/1080.jpg?hmac=9ep4R7HwKsrH1LbkZqyycvWWmRb2bvayRFCUHTa_NJc fail, there is a workaround like I mentioned in this paragraph. I don't see any huge roadblocks that will prevent your approach with the canvas from working.
1st Nov 2020, 6:24 PM
Josh Greig
Josh Greig - avatar
0
window.addEventListener('load', function () { let clWidth = document.getElementById('bg').clientWidth; let clHeight = document.getElementById('bg').clientHeight; console.log('Width:', clWidth, ' Height:', clHeight); const RDS = 10; // Cuts const pW = (clWidth / RDS); const pH = (clHeight / RDS); console.log('pW:', pW, ' pH:', pH); var elements = document.getElementById('cuts'); var j; var k; var i = 0; for (k = 0; k < RDS; k++) { for (j = 0; j < RDS; j++) { elements.innerHTML += '<div id="image' + i + '" class="pattern"></div>'; i += 1; } elements.innerHTML += '<br />'; } var image = new Image(); image.setAttribute('crossOrigin', 'anonymous'); var timestamp = new Date().getTime(); image.src = 'https://picsum.photos/1920/1080?random=1' + '?' + timestamp; image.onload = cutImageUp(); function cutImageUp() { var imagePieces = []; var i = 0; for (var x = 0; x < RDS; ++x) { for (var y = 0; y < RDS; ++y) { console.log('i:' + i); var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); canvas.style.width = pW + 'px'; canvas.style.height = pH + 'px'; context.drawImage(image, x * pW, y * pH, pW, pH, x * i, y, pW, pH); imagePieces.push(canvas.toDataURL()); var element = document.getElementById('image' + i); element.insertAdjacentHTML('beforeend', '<img src=' + imagePieces[i] + '/>'); element.src = '<img src=' + imagePieces[i] + '/>'; element.style.width = pW + 'px'; element.style.height = pH + 'px'; console.log(element.id + ': ' + element.innerHTML); i += 1; } } } console.log('image sliced'); }, false)
1st Nov 2020, 7:27 PM
Claude Dumont
Claude Dumont - avatar
0
Something is happening but still not working. Please see code below.
1st Nov 2020, 7:28 PM
Claude Dumont
Claude Dumont - avatar
0
Thank you so much for your help. It looks great :-) What is this for in your code: var wPercent = 100 * RDS * scale; var hPercent = 100 * RDS * scale; What do you think about my approach on: https://chi.lu/pattern That was my first try and I couldn't get rid of the remaining space below the animation. Is it that you tried to achieve with wPercent? I will try to make your code work for double sided animation and also load new images after both images were shown.
2nd Nov 2020, 5:04 PM
Claude Dumont
Claude Dumont - avatar
0
That code regarding "scale" is to scale the image as large as possible without cropping or stretching the image. The wPercent, hPercent and a couple other references to scale make that work. Setting background-repeat: no-repeat was important to prevent the image from repeating in more available space. You could move some of the repeated inline styles such as background-repeat from JavaScript to CSS. I left it there to make it clearer to you what new CSS properties were getting applied. Aside from background-position and background-size, the other CSS properties could be moved. https://chi.lu/pattern looks pretty good. Some more polish would be to have the slider respond appropriately to resize events in the browser. Right now, resizing the browser leads to cropped content or needless empty space. You could fix that by listening for the window's resize event and updating the clWidth and clHeight whenever they should change.
2nd Nov 2020, 7:36 PM
Josh Greig
Josh Greig - avatar
0
Ok, but wPercent and hPercent is never used in the code after assigning values to them. Your idea to bring in a scale is great! I updated your (the) code with an Event Listener to 'resize' and moved the background-repeat to CSS. Seems to work :-) https://code.sololearn.com/WOp31WwyIOoe/#html Do you have an idea how I could improve it to always display full-screen even if the image is not entirely displayed? So to remove the body and '#bg' below the animation?
2nd Nov 2020, 11:07 PM
Claude Dumont
Claude Dumont - avatar
0
I updated the code. For me the one-side animation is working good enough now. Could you help me getting it to work for both sides. I already tried it but am doing something wrong. I guess I don't really understand the "appendChild" you used...
6th Nov 2020, 4:26 AM
Claude Dumont
Claude Dumont - avatar
0
All done :-) Check it out (https://code.sololearn.com/WOp31WwyIOoe/#html) and thank you for valuable help.
6th Nov 2020, 11:09 PM
Claude Dumont
Claude Dumont - avatar