Merging multiple canvas in a single DIV together - JQuery - javascript

I have a method that creates different layers of canvas within single divs based on data. Sometimes a div will contain more than one canvas within it. These canvas contain an image which is usually a PNG. What I am trying to do is take every canvas within a single div and render as one single canvas so that every div would contain combined canvases if they had more than one within it.
Here is what I am doing:
// Loop through each div that contains canvas and combine them
$(".ifp_container_printing").each(function(index, element) {
var primaryCanvas = $(this).closest('canvas');
var thisOne = $(this);
thisOne.find('canvas').each(function(index, element) {//<!-- grab the canvas for this parent div
var childCanvas = $(this).get();
childCanvas = childCanvas.getContext("2d");
primaryCanvas.drawImage(childCanvas, 0, 0);
});
});
The issue here is when I get to the childCanvas.getCo... it tells me its undefined.
Suggestions or thoughts?
UPDATE:
Here is the example of the div layout I would be grabbing from:
<div class="ifp_container_printing ifp_container_printing_15" style="width:100%;" id="ifp_container_printing_15">
<div class="kineticjs-content" role="presentation" style="position: relative; display: inline-block; width: 1665px; height: 1871px;">
<canvas width="3330" height="3742" style="padding: 0px; margin: 0px; border: 0px; position: absolute; top: 0px; left: 0px; width: 1665px; height: 1871px; background: transparent;"></canvas>
<canvas width="3330" height="3742" style="padding: 0px; margin: 0px; border: 0px; position: absolute; top: 0px; left: 0px; width: 1665px; height: 1871px; background: transparent;"></canvas>
</div>
</div>

Your problem is the wrong usage of closest method. It traverses up to the tree, check the API.
You may rewrite your code like this. This code will draw all canvases in a div on the first canvas in that div.
$(".ifp_container_printing").each(function() {
var allCanvases = $(this).find('canvas');
var primaryCanvas = allCanvases[0];
var primaryContext = primaryCanvas.getContext('2d');
for (var i = 1, len = allCanvases.length; i < len; i++) {
// iterate through all canvases except the first
primaryContext.drawImage(allCanvases[i], 0, 0);
}
});

Related

Centre Lottie SVG to a Header element

I have an animation from Lottiefiles (in JSON format), which is then converted into an animated SVG document by the Lottie framwork. However, I can't seem to position the SVG document with the header tag. I'd like it to be beside the text.
I tried to search existing threads for similar things, but none of these worked, except for one (sort of). This included adding the SVG into a div, inside the header itself. However, when I tried this, the SVG document is fixed in place, so while it worked for shorter text (less than 6 characters), if the text was longer, the SVG would appear underneath, instead of moving to the end of the text.
I also have to manually assign the style to the SVG file through Javascript in a timeout, because the SVG document doesn't exist initially.
This is the actual header code (in PugJS).
h1(class="channel-header" style="margin-bottom: 36px; width: 96px; margin: auto;") #{channel}
if premium
div(id="bodyanim" class="badge baseline")
Here is the SASS for the header and inner div tag:
.badge
display: inline-flex
align-self: center
height: 70%
.badge svg, .badge img
height: 1em
width: 1em
fill: currentColor
z-index: -1
position: absolute
left: 0
top: 0
.badge.baseline svg, .badge img
top: .125em
position: relative
.channel-header
margin: 0 0 16px 0
padding: 0
line-height: 1
font-weight: normal
position: relative
height: 45px
And here's the JS setting the SVG object, and setting its CSS after a timeout.
var animData = {
wrapper: document.getElementById('bodyanim'),
animType: 'svg',
loop: true,
prerender: true,
autoplay: true,
path: '/anims/4768-trophy.json'
};
var anim = bodymovin.loadAnimation(animData);
setTimeout(function () {
var svg = animData.wrapper.getElementsByTagName("svg")[0];
svg.style.position = "absolute";
svg.style.left = "0";
svg.style.top = "0";
svg.style.zIndex = -1;
svg.style.marginLeft = "65%";
}, 100);
When I run the site with this code, the header works for any text shorter than 7 characters, but if there's more, the header tries to "push" itself above the SVG document, and the SVG remains in position behind it instead of moving along with the text.
You can see an example of this on this site (you can either edit the endpoint, i.e. /channel/anythinghere or edit the tag client-side):
http://themadgamers.co.uk:3000/channel/ItsMike
Why do you set a fixed width for your h1?
h1(class="channel-header" style="margin-bottom: 36px; width: 96px; margin: auto;")
If you remove the 96px width restriction, longer strings no longer push the trophy below the user names.
As for the manual need to style the SVG via JavaScript...
setTimeout(function () {
var svg = animData.wrapper.getElementsByTagName("svg")[0];
svg.style.position = "absolute";
svg.style.left = "0";
svg.style.top = "0";
svg.style.zIndex = -1;
svg.style.marginLeft = "65%";
}, 100);
Consider adding a new class to your CSS.
.mySvg {
position: absolute;
left: 0;
top: 0;
z-index: -1;
margin-left: 65%;
}
Then you should be able to simplify the JavaScript to:
setTimeout(function () {
var svg = animData.wrapper.getElementsByTagName("svg")[0];
svg.className = "mySvg";
}, 100);

How to get coordinates of element from top of element to container?

I am trying to get the coordinates of the box on the image. The coordinates should be based on the image itself and not on the screen size. I am currently using getBoundingClientRect(). How do I retrieve the coordinates based on the image, the box is on, rather than the window size?
CODE that I've tried:
var rect = div[index].getBoundingClientRect();
I found this post on SO : How to get xy coordinates of child element from parent element in jquery? but it was 7 years ago...
You would use the difference between the elements position and its containers position. I've used getBoundingClientRect and returned a new DomRect like you were trying but be cautions as there is no support for Internet Expolorer, Edge or Safari at the moment.
const getBoundingClientRect_RelativeToParent = element => {
const domRect = element.getBoundingClientRect(),
parentDomRect = element.parentElement.getBoundingClientRect()
return new DOMRect(domRect.left - parentDomRect.left, domRect.top - parentDomRect.top, domRect.width, domRect.height)
}
console.log(getBoundingClientRect_RelativeToParent(document.querySelector(".child")))
.parent {
width: 500px;
height: 300px;
margin-left: 200px;
margin-top: 200px;
padding-left: 30px;
padding-top: 30px;
background: green;
}
.child {
width: 100px;
height: 50px;
background: red
}
body {
background: blue
}
<div class="parent">
<div class="child">
</div>
</div>

Unable to make individual divs in class draggable using jQuery .each loop

Problem Overview:
I am creating circular div elements to serve as location markers on a map. My code reads the total number of rows from a database table and executes a loop to create that number of div elements, assigning each a div id using data returned from the database. Each div element is appended to a single div class (marker_mother). All of this works perfectly, resulting in a row of circular div elements on the page.
The next step is to make each individual div element draggable. I am using the .each() jQuery method to loop through all div elements in the class (marker_mother) and set them to draggable using the Draggable interaction from the jQuery UI. I have been using the following Stack Overflow Q&A as a reference: jQuery to loop through elements with the same class. However, all my attempts result in the class being set to draggable and not the individual divs. This means that all divs respond as a unified whole when dragged.
Code:
var total_units = "";
$(document).ready(function() {
// Triggers PHP script to return number of table rows from DB
$('#get_rows').click(function() {
$.get('get_coords.php', function(data) {
total_units = data;
console.log(data);
});
});
// Posts row number to DB and returns query data (eg. id and colour)
// Uses returned data in construction of circular div elements
$('#create_divs').click(function() {
for (i = 0; i < total_units; i++) {
$.ajax({
type: 'POST',
url: 'get_row.php',
dataType: 'html',
data: {
row: i
},
success: function(response) {
var jsonData = JSON.parse(response);
jQuery('<div/>', {
id: jsonData.id,
css: {
"position": "relative",
"top": "200",
"left": "100",
"border-radius": "50%",
"width": "100px",
"height": "100px",
"background": "jsonData.colour",
"font-size": "20px",
"text-align": "center",
"line-height": "100px",
"cursor": "move",
"z-index": "100"
},
href: 'http://127.0.0.1/' + jsonData.id + '.html',
text: jsonData.id
}).appendTo('.marker_mother');
console.log(response);
}
});
}
});
// Assigns top&left positions of dragged div to variables
// Code to store coords in db will be added later
var coordinates = function(element) {
element = $(element);
var top = element.position().top;
var left = element.position().left;
}
// Loops through divs and makes each draggable
$('.marker_mother').each(function(index, item) {
$(item).draggable({
start: function() {
coordinates(item);
},
stop: function() {
coordinates(item);
}
});
});
});
/* CSS to define characteristics for the marker div class */
.marker_mother {
position: relative;
top: 0;
left: 0;
border-radius: 50%;
width: 50px;
height: 50px;
font-size: 10px;
text-align: center;
color: black;
line-height: 50px;
cursor: move;
z-index: 100;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
As mentioned in the overview, I have tried multiple implementations of the .each() function to make the divs draggable (including referring to the DOM object and $(this)). All attempts result in the class (marker_mother) being set to draggable and not the individual divs. I feel there must be something simple I am missing here.
Any ideas or suggestions would be greatly appreciated.
Edit:
HTML markup for the created divs end up looking as follows:
<div class="marker_mother ui-draggable ui-draggable-handle"> == $0
<div id="0001" href="http://127.0.0.1/0001.html" style="position: relative; border-radius: 50%; width: 100px; height: 100px; background: lime; font-size: 20px; text-align: center; line-height: 100px; cursor: move; z-index: 100;">0001</div>
<div id="0002" href="http://127.0.0.1/0002.html" style="position: relative; border-radius: 50%; width: 100px; height: 100px; background: lime; font-size: 20px; text-align: center; line-height: 100px; cursor: move; z-index: 100;">0002</div>
<div id="0003" href="http://127.0.0.1/0003.html" style="position: relative; border-radius: 50%; width: 100px; height: 100px; background: lime; font-size: 20px; text-align: center; line-height: 100px; cursor: move; z-index: 100;">0003</div>
</div>
Solution:
haydenwagner provided the solution in an answer below.
$('.marker_mother div').each(function(index, item) {
To me it looks like you are affecting the marker_mother element instead of its children (the divs that you appended).
Try changing this code:
$('.marker_mother').each(function(index, item) {
to this:
$('.marker_mother div').each(function(index, item) {
so that the elements that you are making draggable in the each function are the divs inside the .marker_mother element.
If this works then you can add a '.marker' or '.'marker-draggable' class to these divs so that your selection can be more explicit (with the code above, all divs inside the '.marker_mother' will become draggable). This may not be necessary if you are only appending draggable elements to the '.marker_mother' element.
The issue is that you looping through all elements with the class marker_mother instead of the children. But in this case you don't need the $.each() loop here.
Just tweak your selector and draggable can handle the rest:
// Assigns top&left positions of dragged div to variables
// Code to store coords in db will be added later
var coordinates = function(element) {
var top = element.position().top;
var left = element.position().left;
}
// Loops through divs and makes each draggable
$('.marker_mother div').draggable({
start: function() {
coordinates($(this));
},
stop: function() {
coordinates($(this));
}
});
Example

Chrome Extension: inserting elements to page using NodeList data

I'm new to creating chrome extensions and what I want to do is to insert elements in specific locations on a page by using a element's class name. I know when I do a
document.getElementsByClassName("List-Item");
It gives me a NodeList. What I want to do is get this list and overlay information on each item on the list with my meta-data. But trying to loop through the node list won't work i.e
var div = document.createElement('div');
div.style.cssText = 'padding: 5px; position: absolute; color: white; left: 0px; top: 0px; background: green; height: 50px; width: 50px; z-index: 9999';
div.innerHTML = 'Chrome Plugin Success!';
var foo = document.getElementsByClassName("List-Item");
for(var i = 0; i < foo.length; i++) {
document.getElementsByClassName("card-content")[i].appendChild(div);
}
Can some one point me in the right way please?

How to add a div over another div with JavaScript?

First, I have this:
Now, what I want to do is, to make "zoom" of some nodes. Once I double click on some of the nodes, I want to see the whole node on the page:
Now, because every time I zoom a node - I see the same thing (a big circle), I want to make this: once I double-click on a node - only a new div to be added which will have the circle and it will overlap its container. I am working with Raphael, so the circle should be drawn with Raphael.
How should I do this with JavaScript? (adding new div with the circle which will overlap the container, and drawing the circle with Raphael, which shouldn't be hard, but the creation of the div is the part where I am stuck)
What I did so far is:
zoomDiv = document.createElement('div');
zoomDiv.id = 'graph-zoom';
zoomDiv.style.position = 'absolute';
zoomDiv.style.zIndex = 2000;
this.container.appendChild(zoomDiv);
When I go to the HTML, I can see that the div is added to the container:
But it is too low. I don't know if this is the problem why I can't see the empty div so far or is it something else?
This example demonstrates the creation of a div in javascript, how to append and remove it to and from the document.body, the use of CSS position: absolute; and CSS z-index to place elements on top of one another.
CSS
#parent {
position: absolute;
top: 0px;
left: 0px;
height: 100px;
width: 300px;
z-index: 0;
background-color: yellow;
}
#child {
position: absolute;
top: 0px;
left: 0px;
height: 100px;
width: 300px;
z-index: 1;
background-color: green;
}
HTML
<div id="parent">
<button id="open">Open</button>
</div>
Javascript
var parent = document.getElementById("parent");
var open = document.getElementById("open");
function addChild() {
var div = document.createElement("div");
var close = document.createElement("button");
div.id = "child";
close.id = "close";
close.textContent = "Close";
close.addEventListener("click", function closeSelf() {
document.body.removeChild(div);
}, false);
div.appendChild(close);
document.body.appendChild(div);
}
open.addEventListener("click", addChild, false);
On jsfiddle
Creation is easy:
var new_div = document.createElement("div");
Insertion is little more difficult:
var your_raphael_container_parent = your_raphael_container.parentNode;
if (your_raphael_container.nextSibling) {
your_raphael_container_parent.insertBefore(new_div, your_raphael_container.nextSibling);
}
else {
your_raphael_container_parent.appendChild(new_div);
}

Categories