I am creating a learning module for an education company where i create 25 animal sprites (canvas with an image in it) and put them in a farm (div with a background image). I then reorder their z-index according to their location on the background, so that closer sprites will be on top of farther ones (both the background DIV and the sprites are position:absolute;).
This is the function that rearranges the sprites:
Array.prototype.sortIndices = function (func) {
var i = j = this.length,
that = this;
while (i--) {
this[i] = { k: i, v: this[i] };
}
this.sort(function (a, b) {
return func ? func.call(that, a.v, b.v) :
a.v < b.v ? -1 : a.v > b.v ? 1 : 0;
});
while (j--) {
this[j] = this[j].k;
}
}
function rearrangeSprites() {
var zSprites = new Array();
for (var i = 0; i < sprites.length; i++) {
var a = $('#sprite_'+i).css('bottom');
a = a.substr(0, a.length - 2);
zSprites[i] = { b : -a*1 };
}
zSprites.sortIndices(function(a,b) { return a.b - b.b; });
for (var i = 0; i < zSprites.length; i++) {
spriteObjects[zSprites[i]].style.zIndex = (1001 + i) + '';
}
}
It works great in IE and Firefox, but Chrome doesn't respect the z-index order.
any ideas?
Response to answers:
justspamjustin: Tried negative z-indices, as the article seemed to note, at some point. also tried reordering the objects, using this code:
$('.sprite').detach();
for (var i = 0; i < zSprites.length; i++) {
$('#Stage_udi_meadow').append(spriteObjects[zSprites[i]]);
spriteObjects[zSprites[i]].style.zIndex = (i + 1000) + '';
}
nada!
Francis: it would be quite a thing to replace the canvases with, say... DIVs, as a lot of code is built around the canvas features. I also need it to be canvases, because i am using transparency, PNG shadows and doing hit tests for the drag, which will not work with a simple DIV, so I will save this delicious option for last.
apsillers: CSS (as requested):
for the sprites:
element.style {
width: 60.674351585014406px;
height: 60.674351585014406px;
left: 204.55043227665706px;
top: 22.550432276657062px;
cursor: pointer;
z-index: 1003;
}
.sprite {
background-repeat: no-repeat;
margin: 0px;
padding: 0px;
overflow: hidden;
position: absolute;
z-index: 140;
}
.EDGE-122375087, .EDGE-122375087 * {
-webkit-transform: translateX(0px);
}
for the background:
element.style {
position: absolute;
margin: 0px;
left: 0px;
top: 177px;
width: 566px;
height: 347px;
right: auto;
bottom: auto;
background-size: 100%;
background-image: url(http://localhost:9090/cet_html5/publish/images/udi_meadow.png);
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
opacity: 1;
background-position: 0px 0px;
background-repeat: no-repeat no-repeat;
}
#Stage_udi_meadow {
}
.EDGE-122375087, .EDGE-122375087 * {
-webkit-transform: translateX(0px);
}
user agent stylesheetdiv {
display: block;
}
Inherited from body
Style Attribute {
cursor: auto;
}
Sometimes z-index can be a bit tricky. This article from the W3 may be of some help. But that spec may be a bit confusing. If I can't get z-index to work, then I make sure that my elements in the DOM are ordered properly. Generally elements lower in the DOM, have a higher visibility preference. So under some conditions, this might be true:
<div style="z-index:9999">I'm on bottom</div>
<div>I'm on top</div>
Try reordering the elements in the DOM.
Related
Using a code snippet I found online https://codepen.io/mattyfours/pen/LNgOWx
I made slight modifications and now, although the scroll/fixed functionality works, my 'fixed' side jumps when scrolling. I added 'background-size: contain' onto the fixed side which only works when scrolling has commenced However, on page load/ when no scrolling has occurred the image remains at its full-size meaning once scrolling begins the image goes from full width to 'contained' and created a jump.
Github:
https://github.com/tavimba/fixed-scroll
The issue can be seen in about.html
javascript:
var window_height;
var header_height;
var doc_height;
var posTop_sticky1;
var posBottom_sticky1;
var posTop_s2;
var posBottom_s2;
$(document).ready(function() {
getValues();
});
$(window).scroll(function(event) {
var scroll = $(window).scrollTop();
if (scroll < posTop_sticky1) {
$('.sticky').removeClass('fixy');
$('.sticky').removeClass('bottom');
}
if (scroll > posTop_sticky1) {
$('.sticky').removeClass('fixy');
$('.sticky').removeClass('bottom');
$('#sticky1 .sticky').addClass('fixy');
}
if (scroll > posBottom_sticky1) {
$('.sticky').removeClass('fixy');
$('.sticky').removeClass('bottom');
$('#sticky1 .sticky').addClass('bottom');
$('.bottom').css({
'max-height': window_height + 'px'
});
}
if (scroll > posTop_s2 && scroll < posBottom_s2) {
$('.sticky').removeClass('fixy');
$('.sticky').removeClass('bottom');
$('#s2 .sticky').addClass('fixy');
}
});
function getValues() {
window_height = $(window).height();
doc_height = $(document).height();
header_height = $('header').height();
//get heights first
var height_sticky1 = $('#sticky1').height();
var height_s2 = $('#s2').height();
//get top position second
posTop_sticky1 = header_height;
posTop_s2 = posTop_sticky1 + height_sticky1;
//get bottom position 3rd
posBottom_sticky1 = posTop_s2 - header_height;
posBottom_s2 = doc_height;
}
var rtime;
var timeout = false;
var delta = 200;
$(window).resize(function() {
rtime = new Date();
if (timeout === false) {
timeout = true;
setTimeout(resizeend, delta);
}
});
function resizeend() {
if (new Date() - rtime < delta) {
setTimeout(resizeend, delta);
} else {
timeout = false;
getValues();
}
}
CSS:
section {
width: 100%;
min-height: 100%;
float: left;
position: relative;
}
header {
width: 100%;
height: 5vw;
background-color: black;
float: left;
}
.sticky {
height: 100%;
width: 60%;
float: left;
position: absolute;
}
.sticky.fixy {
position: fixed;
top: 0;
left: 0;
}
.sticky.bottom {
position: absolute;
bottom: 0;
}
.green {
background-image: url(../imgs/front%20view.jpg);
background-size: cover;
}
.stickyBg {
background-image: url(../imgs/bonnets.jpg);
background-size: cover;
}
.scrolling {
float: right;
width: 50%;
padding: 20px;
h5 {
margin-left: 135px;
}
p {
margin-left: 135px;
font-size: 1em;
line-height: 1.5;
}
}
The jump is caused by change of position from absolute to fixed in combination with 100% height.
Besides, the above code has the following flaws:
Max-height assignment looks inconsistent.
JS assumes exactly two sections in HTML: #section1 and #s2. The third section won't work.
Window resize is handled incorrectly. The half-page-scroll logic consists of the two steps: CalculateVars and AdjustDOMElementPositions. For the smooth look these two actions have to be done in 3 cases: onDocumentLoad, onResize and onScroll.
Global vars.
Looks like, it needs some refactoring to get work ;)
<section class="js-half-page-scroll-section"><!-- Get rid of id -->
...
</section>
function halfPageScroll() {
let scrollTop, windowHeight, headerHeight; // and some other common vars
// Calculate vars
scrollTop = $(window).scrollTop();
//...
let repositionSection = function($section) {
let sectionHeight; // and some other vars related to current section
// Some logic
}
$('.js-half-page-scroll-section').each((i, el) => repositionSection($(el)));
}
$(document).ready(halfPageScroll);
$(window).scroll(halfPageScroll);
$(window).resize(halfPageScroll); // TODO: add some debounce wrapper with timeouts
I have the following code on codesandbox: https://codesandbox.io/s/highlighter-cv2kv?file=/src/index.js
I have a bunch of spans for every word in a phrase. I want to be able to create highlights based on a start and end time (every span has those details in dataset). Highlights need to be laid above the corresponding spans.
So far I've been able to highlight the start and stop word but I need to highlight every word between that interval.
Current state:
Desired state:
Any ideas on how can I do this in the most efficient way?
Using dataset and querySelectorAll
Working Demo
for (let range of ranges) {
parent.querySelectorAll('.will-play').forEach (span => {
if (span.dataset.start < range.start || span.dataset.end > range.end) {
return;
}
let highLightParent = document.createElement("div");
let highlight = document.createElement("div");
let pos = getPos(parent, span);
highlight.style.cssText = `position: absolute; top: ${pos.top}px; left: ${pos.left}px; width: ${span.offsetWidth}px; height: ${span.offsetHeight}px; background-color: yellow; opacity: 0.5; z-index: 1`;
highLightParent.appendChild(highlight);
parent.appendChild(highLightParent);
});
}
i have an i idea for you less js more css, with that you only need to toggle the class playing and will highlight the words:
body {
font-family: sans-serif;
}
.will-play {
position: inherit;
z-index: 1;
position: relative;
}
.will-play.playing::after {
z-index: 200;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: yellow;
opacity: 0.5;
content: "";
}
I forgot the JS :
let ranges = { start: "80.9", end: "87.48" };
let spans = [...document.querySelectorAll("span.will-play")];
spans.map((item) => {
if(item.dataset.start>=ranges.start && item.dataset.end<=ranges.end){
item.classList.add('playing')
}
});
I am learning JS and have created a carousel with a caption underneath.
How do I get the Prev/Next buttons to affect the caption as well as the image? I've tried combining the if statements in several ways but have failed miserably.
Relevant HTML:
<span id="prev" class="arrow">❮</span>
<div class="karussell" id="karussell">
<img class="karu" name="esislaid">
</div>
<span id="next" class="arrow">❯</span>
<div class="caption">
<h3 id="esikiri"></h3>
</div>
JS:
var p = 0;
var s = 0;
var esileht = [];
var aeg = 5000;
var kiri = [];
//Image List
esileht[0] = 'img/tooted/raamat/graafvanalinn2016.jpg';
esileht[1] = 'img/tooted/kaart/kaart_taskus_esipool.jpg';
esileht[2] = 'img/tooted/kaart/graafkaart_esikylg.jpg';
//Captions
kiri[0] = 'Raamat "Tallinn. Graafiline vanalinn"';
kiri[1] = 'Tallinna vanalinna graafiline kaart (suur formaat)';
kiri[2] = 'Tallinna vanalinna graafiline kaart (väike formaat)';
// Left and Right arrows
//Eelmine
function eelmine(){
if (p === 0){
p = esileht.length;
}
p = p - 1;
return esileht[p];
}
//Jargmine
function jargmine(){
p = p + 1;
p = p % esileht.length;
return esileht[p];
}
document.getElementById('prev').addEventListener('click', function (e){
document.querySelector('#karussell img').src = eelmine();
}
);
document.getElementById('next').addEventListener('click', function (e) {
document.querySelector('#karussell img').src = jargmine();
}
);
//Change Image
function changePilt (){
document.esislaid.src = esileht[p];
if(p < esileht.length -1){
p++;
} else {
p = 0;
}
setTimeout("changePilt()", aeg);
}
//Change Caption
function changeKiri(){
document.getElementById('esikiri').innerHTML = kiri[s];
if(s < kiri.length - 1){
s++;
}
else {
s = 0;
}
setTimeout('changeKiri()', aeg);
}
document.body.onload = function(){
changePilt();
changeKiri();
};
CSS, just in case:
.karussell {
position: relative;
width: 100%;
max-height: 600px;
overflow: hidden;
}
.arrow {
cursor: pointer;
position: absolute;
top: 40%;
width: auto;
color: #00A7E0;
padding: 16px;
font-weight: bold;
font-size: 18px;
border-radius: 3px;
transition: 0.6s ease;
}
#next {
right: 0;
}
#prev {
left: 0;
}
.arrow:hover {
background-color: rgba(0,0,0,0.8);
}
.caption {
text-align: center;
color: #00A7E0;
padding: 2px 16px;
}
.karu {
max-width: 75%;
animation-name: fade;
animation-duration: 2s;
}
#keyframes fade {
from {opacity: 0.4}
to {opacity: 1}
}
#media (max-width:767px){.karu{max-width: 95%;}}
I made a fiddle to try to illustrate (had to paste the js into the html tab to gt it to work for some reason): Fiddle
Really you just need to use the .innerHTML() feature and do exactly what you already have. Either create a eelmine2() function (or something like that) and call it again, grabbing the content from kiri[] or instead just return the p and use it in two places:
document.getElementById('prev').addEventListener('click', function (e){
document.querySelector('#karussell img').src = eelmine();
document.querySelector('#esikiri').innerHTML = eelmine2();
});
function eelmine2(){
if (p === 0){
p = kiri.length;
}
p = p - 1;
return kiri[p];
}
or
document.getElementById('prev').addEventListener('click', function (e){
var change = eelmine();
document.querySelector('#karussell img').src = esileht[change];
document.querySelector('#esikiri').innerHTML = kiri[change];
});
function eelmine(){
if (p === 0){
p = kiri.length;
}
p = p - 1;
return p;
}
This assumes your code is using the same global vars inside public functions that you have set up in your Fiddle. You should fix that to have variables passed into the functions before going live with all of this, but I'm not addressing that any further here.
I want to create some divs and place the around the body. That means left , right, up and down. I create a div every time a client connect via socket. and here is the code
var parent = document.getElementById("#parent-div")
socket.on("isConnected", function(data) {
// Receive the 'data' and check if 'isConnected' is true
if(data.isConnected == true) {
parent.innerHTML += "<div class='new-div'></div>"
}
});
and here is the style of the div :
.ZE {
position: fixed;
width: 400px;
height: 100px;
background-color: #73AD81;
overflow: hidden;
border-radius: 20px 60px;
border: 2px solid #965D31;
}
how can i do that ?
Your code will work as you have it once you've made a few adjustments.
jsFiddle Demo
First, you have a number symbol (#) you don't need in your getElementById():
Should be:
var parent = document.getElementById("parent-div");
Next, create classes for the locations you want to place them in:
.ZE.left {
top: 50%;
transform: translateY(-50%);
}
.ZE.right {
right: 0;
top: 50%;
transform: translateY(-50%);
}
.ZE.up {
left: 50%;
transform: translateX(-50%);
}
.ZE.down {
left: 50%;
transform: translateX(-50%);
bottom: 0;
}
Up to you how you place them. Above is just one way to place them left/right/top/bottom and may not be the best way at that but I've based it on your existing code.
Lastly you'll want to add those classes, incrementally, or otherwise in your callback function:
// for demo purposes
var data = {
isConnected: true
},
classes = ['left', 'right', 'up', 'down'];
//socket.on("isConnected", function(data) {
// Receive the 'data' and check if 'isConnected' is true
// loop for demo purposes
for (var i = 0; i < 4; i++) {
if(data.isConnected === true) {
parent.innerHTML += "<div class='ZE " + classes[i] + "'></div>"
}
}
//});
var newDiv = document.createElement("div");
var parentDiv = document.getElementById("div_to_place_within");
parentDiv.appendChild(newDiv);
newDiv.id = "some_id";
newDiv.className = "some classnames";
createElement & appendChild
I'm new to JavaScript but moving over from ActionScript, so I'm using a lot of AS3 logic and not sure what's possible and not.
I have a series of 5 dots for an image slider nav. The dots are just CSS styled dots, so I'm trying to make it so I can control the colors using element.style.backgroundColor.
Here's my script:
function btnFeatured(thisBtn) {
btnFeatured_reset();
for (i = 1; i <= 5; i++) {
if (thisBtn === document.getElementById("dotFeat" + i)) {
document.getElementById("dotFeat" + i).style.backgroundColor = "#ffae00";
}
}
}
function btnFeatured_reset() {
for (i = 1; i <= 5; i++) {
document.getElementById("dotFeat" + i).style.backgroundColor = "#969696";
}
}
Seems to work just fine, but when I click the dot, it turns orange (ffae00) and then immediately turns back to gray (969696).
And just in case, here's the style I'm using for the dots:
#featured-nav a {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: #969696;
border-bottom: none;
margin: 0 14px;
}
#featured-nav a:hover {
background-color: #ffae00;
border-bottom: none;
}
And my html:
Change the HTML to
test
test
test
test
test
and the JS:
function btnFeatured(thisBtn) {
for (i = 1; i <= 5; i++) {
var state = parseInt(thisBtn.id.slice(-1),10) == i,
elem = document.getElementById("dotFeat" + i);
elem.style.backgroundColor = (state ? "#ffae00" : "#969696");
}
return false;
}
FIDDLE
Even better would be to not use inline JS, but proper event handlers.