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);
Related
I'm building a program where you can insert copied HTML from your Webbrowser into the program and then edit it by using a contenteditable div tag, but the copied HTML overflows the div and doesn't apply the style in relative to my div but to the whole screen, is there a way to prevent that?
document.getElementById("HTMLMD").contentEditable = html;
#container-HTMLMD {
overflow: auto;
background-color: white;
height: 100vh;
width: 50%;
}
#HTMLMD {
padding: 5px;
}
<div id="container-HTMLMD">
<div id="HTMLMD" spellcheck="false"></div>
</div>
Result (the top bar should only take half of the width as the other elements):
Solution:
I inspected the html contents and saw that the overflowing items were items with position: absolute and position: fixed, I fixed the problem by first setting #HTMLMD { position: relative } which fixed the problem for the items with position: absolute, then I wrote the JS script:
let children = inner.getElementsByTagName("*");
children.forEach((e) => {
if (e.style.position === "fixed") e.style.position = "absolute";
});
which sets all items with position: fixed to position: absolute, which is definitly not an optimal solution but it works in my case.
I am trying to make a JavaScript game and I need a CSS object with an animation to move in place of an object I originally made using JavaScript. Basically, what I want to happen is have my "sword" CSS object move with my player object when I have it Unsheathed. I have been looking for a while and they only give me a result as to were it will be when the page is loaded. I need the sword to always be moving with the player. If my code is needed, tell me, and I will provide it. If you have any questions, feel free to ask. I am pretty new so go easy on the terrible JavaScript that may be provided.
PLEASE USE AN EXAMPLE RELATED TO MY CODE!
if you don't I probably wont understand what is going on....
Thank You in Advance
Focusing the the following element of your example I am only going to address CSS here...
....
<div class="player"></div>
<div id="swordl"></div>
<div id="swordr"></div>
....
To move #swordl and #swordr along with .player you can take advantage of a feature of the CSS position attribute.
When a containing element has CSS position: relative; children of that element with the CSS position: absolute; are positioned with reference to the top-left corner of the parent.
In the following example #player would be the parent, and #swordl and #swordr would be the children...
....
<div id="player">
<div id="swordl"></div>
<div id="swordr"></div>
</div>
....
/* CSS */
#player {
position: relative;
}
#swordl, #swordr {
position: absolute;
}
#swordl {
left: 4px;
top: 2px;
}
#swordr {
left: 12px;
top: 2px;
}
Note the change of class to id in 'player'
Now, whenever you animate the position of #player the two #swords will maintain their position relative to the top-left corner of their containing parent element: you will not have to animate the position of #swords explicitly.
Hope that helps. ;)
CSS position # MDN
You can use the transistion. I have included a couple examples. One example is just JavaScript, the other is not just JavaScript.
//Get Element By Id of 'movingdiv'
var div = document.getElementById('movingdiv');
//Create the timeout (not required)
setTimeout(function() {
//Change the style.top to 50%, You can also do this in px
div.style.top = '50%';
//Change the style.top to 50%, You can also do this in px
div.style.left = '50%';
//Add the transform so it can be centered in the viewport
div.style.transform = 'translate(-50%,-50%)';
//Add the timeout below in milliseconds.
}, 1000)
#movingdiv {
width: 100px;
height: 100px;
background: black;
position: absolute;
top: 10px;
left: 10px;
transition: all 2s;
}
<div id='movingdiv'></div>
//Create a div
var div = document.createElement('div');
//Give the div some style. IMPORTANT: notice the transition
div.style = 'width: 100px; height: 100px; background: black; position: absolute; top: 10px; left: 10px; transition: all 2s;';
//Append the div to the body
document.body.appendChild(div);
//Create a timeout for the div to move
setTimeout(function() {
//Change the style.top to 50%, You can also do this in px
div.style.top = '50%';
//Change the style.top to 50%, You can also do this in px
div.style.left = '50%';
//Add the transform so it can be centered in the viewport
div.style.transform = 'translate(-50%,-50%)';
//Add the timeout below in milliseconds.
}, 1000)
I use images created on the fly to maintain the aspect ratio of boxes with a fixed height. Image sources are set as data-urls provided from a canvas with a given width and height, the images are then attached to divs which can contain any content, have any height, and still maintain a fixed aspect ratio.
This works well, however, on slower phones with less memory the large number of data-urls on the page can start to be a little bit of a drag. Some of the ratios can't be reduced below a certain point resulting in relatively large canvases.
Is there any way to set the ratio of an img element without setting its source? Is there any way to set the source to a format that is an truly empty image with only a width and height?
EDIT: The snippet below throws an error - iframe restrictions, probably having to do with making images. You can see an error free version over at this CodePen.
const wrapper = document.querySelector(".wrapper");
function addRatioBox(width, height = 1) {
const cvs = document.createElement("canvas");
const img = new Image(width, height);
const box = document.createElement("div");
cvs.width = width;
cvs.height = height;
img.src = cvs.toDataURL("image/png");
box.appendChild(img);
box.className = "ratioBox";
wrapper.appendChild(box);
}
addRatioBox(1);
addRatioBox(4, 3);
addRatioBox(16, 9);
addRatioBox(2, 1);
.ratioBox {
background: orange;
display: inline-block;
height: 100%;
margin-right: 10px;
}
.ratioBox img {
height: 100%;
width: auto;
display: block;
}
/* just a whole bunch of stuff to make things prettier from here on down */
.wrapper {
background: #556;
padding: 10px;
position: absolute;
height: 20%;
top: 50%;
left: 50%;
white-space: nowrap;
transform: translate(-50%, -50%);
}
body {
background: #334;
}
.ratioBox:last-of-type {
margin-right: 0;
}
<div class="wrapper"></div>
WolfPack!
I want to highlight any element I hover over just like the Chrome Dev Tools does it.
Picture of Chrome Dev Tools
Notice how the entire element is drenched in a blue tint? This is not as simple as adding a background color or linear-gradient because the insides of input elements are still white.
I've tried using the different filter methods like hue rotate, contrast w/brightness, and even THIS MONSTER, but nothing seems to work.
The closest I've been is just a nice looking box-shadow around the elements for highlighting.
Javascript: element.classList.add('anotherClass')
CSS: box-shadow: 0 0 5px #3fd290, 0 0 10px #36A9F7, 0 0 15px #36A9F7, 0 0 20px #36A9F7 !important;
Help me make my dreams come true
If anyone cares what I did to solve it, here is my code (thanks to the help of Roope):
onMouseEnter:
highlightElement(event){
const hoverableElements = document.querySelectorAll('[data-attr]');
for(let elm of hoverableElements){
const styles = elm.getBoundingClientRect()
if(event.currentTarget.textContent === elm.dataset.dataAttr) {
let div = document.createElement('div');
div.className = 'anotherClass';
div.style.position = 'absolute';
div.style.content = '';
div.style.height = `${styles.height}px`;
div.style.width = `${styles.width}px`;
div.style.top = `${styles.top}px`;
div.style.right = `${styles.right}px`;
div.style.bottom = `${styles.bottom}px`;
div.style.left = `${styles.left}px`;
div.style.background = '#05f';
div.style.opacity = '0.25';
document.body.appendChild(div);
}
}
}
onMouseLeave:
onLeave(event){
const anotherClass = document.getElementsByClassName("anotherClass");
for (let elm of anotherClass) {
document.body.removeChild(elm)
}
}
After looping through the querySelectorAll (to get the desired elements), I used element.getBoundingClientRect() to get the exact height, width, top, right, bottom, left of the element.. That way, the new div created will take the exact size and location of the element.
CSS didn't quite cut it because other stylesheets would override/mess the styling up.
If all you want is the blue transparent highlight, just add a pseudo element over the hovered element. Positioning may of course be absolute of fixed for the element as well.
.element {
float: left;
position: relative;
width: 100px;
height: 100px;
margin: 10px;
border: 1px solid #000;
text-align: center;
line-height: 100px;
}
.element:hover::after {
position: absolute;
display: block;
content: '';
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #05f;
opacity: 0.25;
}
.tall {
height: 200px;
}
<div class="element">Element</div>
<div class="element tall">Element</div>
<div class="element">Element</div>
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);
}