I have been trying to make this work since the beginning of this week but couldn't figure it out. I have two elements in my HTML file. They are on the same vertical lane, element1 is moving 60ems to the left horizontally with each button click. I have to compare the positions of these two elements and detect whether element1 has passed the element2 with an if/else statement. When it passes I want to move the element1 to its initial position and start over. But if statement never shoots, it always jumps to else statement.
I have tried comparing following properties:
$('#elemet1').position();
$('#elemet1').position().left;
$('#elemet1').offset();
$('#elemet1').offsetLeft;
$('#elemet1').css("position");
$('#elemet1').css("left");
$('#elemet1').css("margin");
$('#elemet1').left;
I tried to compare the positions like below:
$(function () {
$("button").click(function () {
var position1 = $('#element1').css("left");
var position2 = $('#element2').css("left");
if (position1 <= position2) {
$("#element1").animate({left:'+=240em'}, 600);
}
else {
$("#element1").animate({left:'-=60em'}, 600);
}
});
});
If you can give me an answer or direct me to another post I will appreciate it. Thank you in advance.
EDIT: The style I use is below:
.element2 {
position: relative;
width: 60em;
height: 40em;
bottom: 8em;
background: rgba(242, 210, 139, 0.6);
border-radius: 1.2em;
z-index: 1;
overflow: hidden;
#element1 {
position: absolute;
margin-left: 180em;
width: 60em;
height: 40em;
z-index: 1;
}
And I should have mentioned this at the beginning: element1 is inside element2:
<div class="element2">
<img id="element1" src="image/bg1.png" />
</div>
This will give you the current position of an element:
$('#element').position().left;
If you need position relative to the document (instead of relative to a parent element) you can use:
$('#element').offset().left;
You should just be able to compare the return values of these for the different elements directly. Here's some sample code that works for me, note there is no need to parse since they always return pixel values.
var pos = Math.max($(w).scrollTop(), 38),
top = $(ballon).position().top,
dist = Math.abs(pos-top),
time = dist > 1000 ? 2000 : dist / 0.15;
if (pos + $(w).height() >= pHeight) {
pos = pHeight - bHeight - gHeight;
$(ballon).animate({'top': pos}, time, 'easeInOutSine');
}
else if (dist > 150 || pos < 100) {
$(ballon).animate({'top': pos}, time, 'easeInOutBack');
}
Related
const rightSide = document.querySelector("#rightSide");
let scrollPercentage = () => {
let h = document.documentElement;
let st = h.scrollTop || document.body.scrollTop;
let sh = h.scrollHeight || document.body.scrollHeight;
let percent = st / (sh - h.clientHeight) * 100;
console.log(percent);
}
rightSide.onscroll = scrollPercentage;
.right-side {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 90%;
width: 90%;
background-color: #eee;
overflow-y: scroll;
}
.top-page {
width: 100%;
height: 100%;
background-color: red;
}
.bot-page {
width: 100%;
height: 100%;
background-color: yellow;
}
<div class="right-side" id="rightSide">
<div id="top-page" class="top-page"></div>
<div id="bot-page" class="bot-page"></div>
</div>
I'm making a website and I want to get the scroll percentage of a div. I've used Tyler Pott's video on YouTube https://youtu.be/-FJSedZAers and he does that to the whole page (using the body). And this is my code:
const rightSide = document.querySelector("#rightSide")
let scrollPercentage = () => {
let h = document.documentElement;
let st = h.scrollTop || document.body.scrollTop;
let sh = h.scrollHeight || document.body.scrollHeight;
let percent = st / (sh - h.clientHeight) * 100;
console.log(percent);
}
rightSide.onscroll = scrollPercentage;
When I run this, the console just outputs "NaN" which is to be expected. I am not sure what I should do in order to transfer that code onto the divs. I've tried to use things like
const topPage = document.querySelector("#top-page");
And then add topPage instead of the body in document.body.scrollTop etc. but that obviously doesn't work.
This is sort of what the HTML looks like, and the top page has a width and height of the rightSide div and the bottom page has the same width but a minimum height of the rightSide div.
<div class="right-side" id="rightSide">
<div id="top-page" class="top-page"></div>
<div id="bot-page" class="bot-page"></div>
</div>
Coming back to this I knew that I had to understand the values assigned to the variables in order to make the equation simpler.
So, a quick search for documentElement led me to this answer:
"documentElement returns the Element that is the root element of the document (for example, the element for HTML documents)"
Then, I realised that maybe that is the issue and it was. I assigned rightSide to h and that's all that was needed.
let h = rightSide;
Not sure if this is fully correct, sometimes at the end of the scroll you can get 100.05 or more, but I didn't need the precise number. Hope this helps.
What I'm trying to do (which I've been able to accomplish, but with poor performances) is to apply a sort of grid over the canvas, in order to be able to take inputs from the user about the origin point position. Once the input is received, the "draw" coordinates are provided via keyboard.
What I've managed to do in these days, was to calculate the width and height of the canvas, then divide it by the area of a standard 20x20 square (speaking in px). In this way I can loop on the result and create n squares, that I will render in display flex inside the grid element. Then this grid element is applied "over" the canvas.
Everything works, but there's a lot of divs going around, and if the user choses to shrink the div to let's say 10x10, then, that would have a great impact over the performances... So I'm trying to find out a lighter way to do this...
I've thought about using HR elements inside two divs that would be applied over the canvas. One div displays elements in column, and another in row. In this way I should obtain the grid, but what about the snap? How could I detect the intersection on the two HR elements and use that exact spot as position?
The reason of why I cannot directly draw the grid on the canvas is because this should remain as 'pure' as possible. Containing only the final draw of the user.
Here's the 'non optimized' code:
I'm using Angular 5 as framework.
<div class="draw-zone" #drawZone>
<div class="grid" #grid [ngClass]="{'activated': activateDrawZones}">
<div *ngFor="let block of gridBlocks" class="grid-block" [ngClass]="{'show': showGrid, 'ten-x-ten': blockSize === 10, 'twe-x-twe': blockSize === 20, 'thr-x-thr': blockSize === 30, 'fou-x-fou': blockSize === 40}"
#gridBlock (click)="draw($event, gridBlock)"></div>
</div>
<canvas #canvas [height]="canvasSize.y" [width]="canvasSize.x"></canvas>
</div>
The scss:
.draw-zone{
flex-grow: 2;
height: 100%;
position: relative;
canvas{
z-index: 10;
}
.grid{
top: 0;
left: 0;
z-index: 11;
width: 100%;
display: flex;
flex-wrap: wrap;
overflow: hidden;
position: absolute;
margin-left: -.1rem;
border-radius: .5rem;
align-content: stretch;
border: 1px solid transparent;
&.activated{
border-color: #3f51b5;
}
.grid-block{
opacity: 0;
border-right: 1px solid #3f51b5;
border-bottom: 1px solid #3f51b5;
&.show{
opacity: .1;
}
&:hover{
opacity: 1;
border-radius: 50%;
background-color: #3f51b5;
transform: scale(1.2);
}
&.ten-x-ten{
width: 10px;
height: 10px;
}
&.twe-x-twe{
width: 20px;
height: 20px;
}
&.thr-x-thr{
width: 30px;
height: 30px;
}
&.fou-x-fou{
width: 40px;
height: 40px;
}
}
}
And the component method to cal:
private calculateGrid() {
this.activateDrawZones = false;
this.canvasSize.x = this._drawZone.nativeElement.clientWidth;
this.canvasSize.y = this._drawZone.nativeElement.clientHeight;
const blocksCount = (this.canvasSize.x * this.canvasSize.y) / (this.blockSize * this.blockSize);
this.gridBlocks = [];
for (let i = 0; i < blocksCount; i++) {
this.gridBlocks.push({ size: this.blockSize });
}
this.activateDrawZones = true;
}
And the method that actually draws:
public draw(e: MouseEvent, block: HTMLDivElement, returnOnFail?: boolean) {
const x = block.offsetLeft + (this.blockSize / 2);
const y = block.offsetTop + (this.blockSize / 2);
if (this.firstClick) {
this.ctx.beginPath();
this.ctx.moveTo(x, y);
this.setCrosshair(x, y);
this.firstClick = false;
this.addPathToDrawSequence(x, y);
return;
}
if (this.isNotOnTheSameAxisAsTheLastInsert(x, y)) {
if (returnOnFail) { return; }
this.toggleDrawDirection();
this.draw(e, block, true);
return;
}
this.ctx.lineTo(x, y);
this.ctx.stroke();
this.setCrosshair(x, y);
this.addPathToDrawSequence(x, y);
}
As you can see, I'm applying the '.grid' element over the canvas element. The grid element contains all the blocks that are displayed in flex mode. As you can see the grid container has a display:flex and flex-wrap: wrap properties. In this way, when the user clicks over a block, I can guess the x, y coordinates by getting its position, relative to the parent. Which has the same dimensions as the canvas. Once that I have the x,y coords, i can draw on the canvas.
Yes, creating a multiplicity of DOM elements and trying to dynamically position and size them with javascript will not be particularly performant. I don't think hr elements will solve this problem for you.
First, have you considered drawing your grid directly onto the canvas?
Another option is to have a background image with the grid on it layered behind the canvas. This will automatically resize just as performantly as any other aspect of your webpage.
Now for the 'snapping' part. It looks like you've already figured out how to draw what you need on the canvas once you get the grid information you're looking for. What you need is a method to get which grid a user clicked on. I'm guessing that is why you overlaid all those divs...
Instead, canvas natively tracks mouse clicks. Using some techniques laid out here should be able to get you the grid interaction information you're looking for.
Edit: A method to generate and find grids:
var height = 100;
var width = 200;
var horizontal_grids = 8;
var vertical_grids = 4;
function bounding_grid_1d(length, grids, x) {
var divisions = [];
var grid_width = length / grids;
for ( i = 0; i <= grids; i++ ) {
if (x || x == 0) {
if (i*grid_width > x) {
divisions.push((i-1)*grid_width);
divisions.push(i*grid_width);
break;
}
else if (i*grid_width == x) {
divisions.push(i*grid_width);
break;
}
}
else {
divisions.push(i*grid_width);
}
}
return divisions;
}
console.log("Get all the x and y grid line locations");
console.log(bounding_grid_1d(width, horizontal_grids));
console.log(bounding_grid_1d(height, vertical_grids));
console.log("Get the x and y grid line locations that surround the coordinates (60,30)");
console.log(bounding_grid_1d(width, horizontal_grids, 60));
console.log(bounding_grid_1d(height, vertical_grids, 30));
I am working on a project trying to make something resembling an etch-a-sketch. I have a 780x780px square, and I am trying to get a 16x16 grid, using a series of smaller square divs.
It is on this grid that I have the hover effect. I keep getting a 15x17 grid of square divs because the last square of the row won't fit. I have margins set to 1px and padding set to 0 so I figured that to fit 16 squares on a 780px wide row, it would require me to take into account the margins (15 1px margins) and from there I could divide (780-15) by 16, the number of squares I want.
That isn't working, and the next step of this project is to have a button where the user could input any number of squares for the row/column and have either a larger or smaller squared grid STILL ON the 780x780 square. Does anyone have any ideas? I'm pretty stumped.
$(document).ready(function() {
var original = 16;
for (var y = 0; y < original * original; y++) {
$(".squares").width((780 - 15) / original);
$(".squares").height((780 - 17) / original);
$("<div class='squares'></div>").appendTo('#main');
}
$('.squares').hover(
function() {
$(this).addClass('hover');
}
)
});
function gridq() {
$('.squares').removeClass('hover');
$('div').remove('.squares');
var newgrid = prompt("How many squares on each side?");
var widthscreen = 192;
if (newgrid > 0) {
for (var x = 0; x < newgrid * newgrid; x++) {
$(".squares").width(widthscreen / newgrid);
$(".squares").height(widthscreen / newgrid);
$("<div class='squares'></div>").appendTo('#main');
}
$('.squares').hover(
function() {
$(this).addClass('hover');
}
)
}
}
#main {
height: 780px;
width: 780px;
background-color: antiquewhite;
position: relative;
}
.squares {
margin: 1px;
padding: 0;
background-color: aquamarine;
display: inline-block;
float: left;
}
.hover {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id=main>
</div>
<button onclick="gridq()">Go Again!</button>
Try this snippet? Grid initialisation is set in the grid() function and then called later when necessary. The width is set dynamically to the 16th square's right side.and the remaining squares fill out as necessary.
var wide = (780 - 15) / 16,
tall = (780 - 17) / 16; // set the square dimensions. this can be incorporated into the grid() function with 16 replaced by 'original'
function grid(x, y) {
var original = x,
y = y;
$("#main").empty(); // empty and restart
$("#main").width(wide * (original + 1));
for (var i = 0; i < original * y; i++) {
$("<div class='squares'></div>").appendTo('#main');
}
var square = $(".squares");
square.width(wide);
square.height(tall);
var side = square.eq(original - 1).position().left + square.width() + 2; // tighten the #main width
$("#main").width(side);
$('.squares').hover(
function() {
$(this).addClass('hover');
}
)
}
grid(16, 16); // starting dimension
function gridq() {
$('.squares').removeClass('hover');
$('div').remove('.squares');
var newgrid = prompt("How many squares on each side?");
var widthscreen = 192;
if (newgrid > 0) {
grid(newgrid, newgrid);
}
}
#main {
background-color: antiquewhite;
position: relative;
}
.squares {
margin: 1px;
padding: 0;
background-color: aquamarine;
display: inline-block;
float: left;
}
.hover {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id='main'>
</div>
<button onclick="gridq()">Go Again!</button>
just got beat to it...ill post this as it answers the question slightly differently and I feel is a little cleaner. Also I added in a width and a height prompt.
see the codepen here
As a side note...its good practice to make the names of your variables make sense. Also I find that breaking down your code problems into smaller more manageable chunks makes it seem less overwhelming...one step at a time :)
Enjoy and good luck!
$(document).ready(function() {
//declare the variables at the top of your functions...it enables us to change them later
var columnWidthCount = 16;
var columnHeightCount = 16;
function makeBoxes() {
//boxcount lets us set how many times we want the for loop to run...when we change the columns/rows later this variable will be updated
var boxCount = columnWidthCount * columnHeightCount;
//
for (var i = 0; i < boxCount; i++) { //loop through each box
//any code you place in here will execute each time we loop around
$("<div class='squares'></div>").appendTo('#main');
}
//we only want to declare this once so we place it after the loop
$(".squares").width((780 / columnWidthCount) - 2);
$(".squares").height((780 / columnHeightCount) - 2);
$('.squares').hover(
function() {
$(this).addClass('hover');
}
);
}
//fire the initial function
makeBoxes();
// fire function after click
$('button').on("click", function() {
$('div').remove('.squares');
var squaresHigh = prompt("How many squares high? (must be a number)");
var squaresWide = prompt("How many squares wide? (must be a number)");
//prompt returns a string...use parseInt to turn that number string into an integer
columnWidthCount = parseInt(squaresWide);
columnHeightCount = parseInt(squaresHigh);
makeBoxes();
});
});
#main {
height: 780px;
width: 780px;
background-color: antiquewhite;
position: relative;
font-size:0;
white-space:nowrap;
}
.squares {
margin: 1px;
padding: 0;
background-color: aquamarine;
display: inline-block;
float: left;
}
.hover {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id=main>
</div>
<button>Go Again!</button>
Right now I currently have a slider and two images on my Google ad
input class="gwd-input-13xh" type="range" min="0" max="50" value="25" id="slider" oninput="getInput(this.value, this.max)">
.img_1 {
position: absolute;
width: 180px;
height: 130px;
left: 62px;
top: 1px;
-webkit-filter: blur(5px);
opacity: .8;
}
.img_2 {
position: absolute;
width: 180px;
height: 130px;
left: 62px;
top: 1px;
-webkit-filter: blur(5px);
opacity: .8;
}
This slider, if moved right of slider value(higher 25) should remove blur and set opacity to 1. If moved left of slider value(lower 25) then vice versa occurs. Here is the current code I have to do this:
function getInput(value, max) {
var img_1 = document.getElementById("img_1");
var img_2 = document.getElementById("img_2");
var sliderPercentage = (value / max).toFixed(2);
img_1.style.opacity = 1 - sliderPercentage
setBlur(img_1, (10 * sliderPercentage).toFixed(2));
img_2.style.opacity = sliderPercentage;
setBlur(img_2, 10 - (10 * sliderPercentage).toFixed(2));
}
function setBlur(ele, value) {
if (ele.style.hasOwnProperty('filter')) {
ele.setAttribute("style", "-webkit-filter:blur(" + value + "px)")
}
}
This code works flawlessly. However, for whatever reason, the opacity will not change. IDK if it is because the opacity is set in stone when working within GWD. If you console.log(img_1.style.opacity = 1 - sliderPercentage) you will see the math on the code works.. it just isn't adjusting the opacity.
Any suggestions and ideas would greatly be appreciated. It also should be noted, when I do NOT run the setBlur function then the setOpacity function works. It just does not work when I am running setBlur.
Not familiar with GWD either, but I assume the problem is you are re-assigning the whole style attribute, so later alteration overrides the former. Replacing ele.setAttribute("style", "...") with
ele.style["-webkit-filter"] = "blur(" + value + "px)";
should fix your issue.
I'm not familiar with GWD but I tried it (with some minor changes):
$("#slider").change(function(){
var img_1 = document.getElementById("img_1");
var img_2 = document.getElementById("img_2");
var sliderPercentage = ($(this).val() / $(this).attr('max')).toFixed(2);
img_1.style.opacity = 1 - sliderPercentage
setBlur(img_1, (10 * sliderPercentage).toFixed(2));
img_2.style.opacity = sliderPercentage;
setBlur(img_2, 10 - (10 * sliderPercentage).toFixed(2));
});
function setBlur(ele, value) {
if (ele.style.hasOwnProperty('filter')) {
ele.setAttribute("style", "-webkit-filter:blur(" + value + "px)")
}
}
and I think it behaves as expected.
Please check full solution at:
https://jsfiddle.net/1eumfwoh/
The webpage I'm trying to create has a bidirectional sliding animation on it. However the animation is only partially working. To be more precise, the animation slides up, but it only slides down partway. Here's my JavaScript:
function showLayer() {
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.top);
if (layerPosition > 315) {
hiddenLayer.style.top = (layerPosition - 5) + "px";
setTimeout("showLayer()", 20);
}
}
function hideLayer() {
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.top);
if (layerPosition <= 315) {
hiddenLayer.style.top = (layerPosition + 5) + "px";
setTimeout("hideLayer()", 20);
}
}
Notice on the fourth line of the hideLayer function, I have the condition set to <= 315, this is due to the fact that setting it equal to 315 causes the element to move only a few pixels in either direction after clicking the trigger element. Here's the HTML elements I have dedicated to the animation:
<div id="mainbutton" onclick="showLayer('mainmenu'); hideLayer('mainmenu')"></div>
<div id="mainmenu" style="position: absolute; top: 690px; left: 9px;"
onclick="showLayer('mainmenu')"> </div>
And here are the styles for them:
div#mainmenu { width: 600px; height: 350px; border-style: solid; background-color:
rgb(0, 0, 0) ; border-width: 3px; border-top-right-radius: 7px; border-top-left-
radius: 7px; }
div#mainbutton { position: absolute; top: 674px; left: 12px; width: 28px; height:
28px; border-style: solid; border-color: rgb(255, 255, 255); border-width: 1px; border-
radius: 4px; }
And the fiddle : http://jsfiddle.net/JAtLA/
I had to put some of the styles inline with the HTML because the animation wouldn't work any other way. At first I thought the problem had solely lain in the if conditional of the hideLayer function. But after tweaking it I'm not so sure now.
I don't know if it's what you want but here is my answer :
There is a problem of logic in your code. You wrote
if(layerPosition<=315){
hiddenLayer.style.top = (layerPosition + 5) + "px";}
It means that if the top is 315 or less, the top will increase until it arrives to 316. But in the first function, you say it to stop at 315. So the function hideLayer will just get it moving from 1 pixel.
The solution is to tell him <400 instead of <=315 (or something higher than 400).
Here is a modified fiddle : http://jsfiddle.net/7egr7/2/
It looks like "hideLayer" will stop if (layerPosition <= 315). Is that really what you want? It happens after 1 iteration.
Note that the y axis goes down the screen (i.e. zero is at the top).
Clicking the button will call showLayer, and then hideLayer.
If the menu is open (i.e. layerPosition > 315), showLayer will not do anything (i guess that is what you intend), and hideLayer will make the menu go up by 5 (from 315 to 320).
On the next iteration of hideLayer (layerPosition <= 315) will be false, so it will not do anything.
Try this:
var open = false;
function showLayer() {
if (open)
return;
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.top);
if (layerPosition > 315) {
hiddenLayer.style.top = (layerPosition - 5) + "px";
setTimeout("showLayer()", 20);
}
else {
open = true;
}
}
function hideLayer() {
if (!open)
return;
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.top);
if (layerPosition <= 685) {
hiddenLayer.style.top = (layerPosition + 5) + "px";
setTimeout("hideLayer()", 20);
}
else {
open = false;
}
}
In the html, I would like to check if the thing is open or closed before doing anything.
<div id="mainbutton" onclick="if (!open) { showLayer('mainmenu'); } else { hideLayer('mainmenu'); }">
but layerPosition <= 685 is the only change that really matters.