Why is my precision web layout imprecise? - javascript

I am having a problem modifying HTML with Javascript. An example can be found here: https://jsfiddle.net/02mwyvyo/
My goal is to move a specific element down the page. I am trying to do this by inserting a spacer div before the target element. The spacer div's style attributes are style="display: inline-block; width=1px; height=100px;".
Here is the code I am using:
function describeDOMRect(rect) {
return "{ top: " + rect.top + ", left: " + rect.left + ", bottom: " + rect.bottom + ", right: " + rect.right + " }"
}
function addVerticalSpacer() {
var div = document.getElementsByClassName("target-div")[0]
var bounds = div.getBoundingClientRect()
console.log("old bounds: " + describeDOMRect(bounds))
var spacerHeight = 100
var newTop = bounds.top + spacerHeight
var spacer = document.createElement("div")
spacer.className = "spacer"
spacer.setAttribute("style", "display: inline-block; width: 1px; height: " + spacerHeight + "px;")
div.parentNode.insertBefore(spacer, div)
bounds = div.getBoundingClientRect()
console.log("new bounds: " + describeDOMRect(bounds))
}
And here are the CSS properties applied to div:
div {
border: none;
border-width: 0;
padding: 0;
margin: 0;
}
When I run the code above, this is what I see in the console:
old bounds: { top: 26, left: 8, bottom: 26, right: 729 }
new bounds: { top: 112, left: 8, bottom: 112, right: 729 }
Notice the old top position is 26, so I expect the new top to be 126, but it is 112.
Why is this happening? What can I do to correct it?

You are actually inserting the spacer div between Some text and Some more text. Since it is an inline-block it is appended at the end of the first line.

Related

element not appends in body on window onload

I have been created the function which detects the screen zoom-in or zoom-out function. I am trying if window zoom == 100 or is in normal size the notification will remove else it append instantly.
In my code, it's working perfectly but it not working on window load, for showing the demo and result I have to click ctrl+ or ctrl-.
I am trying as window load it auto decide and append if window zoom, not 100 or normal.
Please help me with how I fix this?
function informationbar(percentage, zoomstatus) {
$("body").append('<div id="informationbar" style="top: 0px;"><img src="#" style="width: 14px; height: 14px; float: right; border: 0; margin-right: 5px" />You are using the window screen on ' + percentage + '% ' + zoomstatus + ' resolution, might some options are not visible properly on this current resolution please fit the screen on 100% as this our highly recommendation.</div>');
}
$(window).resize(function() {
var browserZoomLevel = Math.round(window.devicePixelRatio * 100);
if (browserZoomLevel !== '100') {
if (browserZoomLevel > "100") {
var status = "ZoomIn";
} else {
var status = "ZoomOut";
}
informationbar(browserZoomLevel, status);
} else {
$("div#informationbar").remove();
}
});
var browserZoomLevel = Math.round(window.devicePixelRatio * 100);
if (browserZoomLevel == '100') {
$("div#informationbar").remove();
} else {
if (browserZoomLevel > "100") {
var status = "ZoomIn";
} else {
var status = "ZoomOut";
}
informationbar(browserZoomLevel, status);
}
#informationbar {
position: fixed;
left: 0;
width: 100 %;
text - indent: 5 px;
padding: 5 px 0;
background - color: lightyellow;
border - bottom: 1 px solid black;
font: bold 12 px Verdana;
}
* html# informationbar {
/*IE6 hack*/
position: absolute;
width: expression(document.compatMode=="CSS1Compat" ? document.documentElement.clientWidth + "px": body.clientWidth + "px");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You seem to be using !== to compare numbers and strings, e.g. browserZoomLeveL !== '100' where browserZoomLevel = Math.round(...).
That will always give false, since the a string isn't a number, and === is strict about types. You should replace === '100' with just === 100.

How to insert a faceless square of a person into an image?

The user forwards an image and receives a response through a json on that image, one of the answers is as follows:
"faceRectangle": {
"top": 187,
"left": 458,
"width": 186,
"height": 186
},
The big question is:
Through the information shown above, how do I insert a square in each
top and left with the javascript?
MY CODE [CSS]
.teste {
border-radius: 0px 0px 0px 0px;
-moz-border-radius: 0px 0px 0px 0px;
-webkit-border-radius: 0px 0px 0px 0px;
border: 5px solid #efff0d;
}
MY CODE [HTML]
<div class="col s12 m12 l6 xl6 center-align">
<div class="container-image-uploaded">
<div id="teste"></div>
<img id="sourceImagem" class="responsive-img sourceImagem">
</div>
</div>
MY CODE [JAVASCRIPT]
document.getElementById('teste').innerHTML.style.width += obj[o].faceRectangle.width + "px";
document.getElementById('teste').innerHTML.style.height += obj[o].faceRectangle.height + "px";
document.getElementById('teste').innerHTML.style.top += obj[o].faceRectangle.top + "px";
document.getElementById('teste').innerHTML.style.left += obj[o].faceRectangle.left + "px";
I would prefer to use appendChild because then you can create your new dom elements in memory and add it with this method.
.innerHtml is also working but then you're more working with strings.
Please have a look at the demo below or this fiddle.
Vue.js is not really needed in this example but with it's easier to work component based. If you don't know Vue then just have a look at the add method that's called by the mousedown eventhandler markImage.
As O'Kane mentioned in the comments, you need to be careful with your string concatenation. I'm using back-tick syntax / template string for the strings in my demo so you can easily insert your values into the string. e.g.
var style = `
left: ${pos.x}px;
top: ${pos.y}px;`
The same is also possible with single quotes but that's harder to write. e.g.
var style = 'left: ' + pos.x + 'px; top: ' + pos.y + 'px;'
Note: Babel is required to work with template strings. With-out it browser support is limited see here
In the demo I've created two variants:
SVG rectangles (less css required to make it work)
DIVs like your code (requires more css)
I think both variants are working and OK. I would probably use SVG because it's easier to create and also exporting later is no problem. e.g. if you like to save it as a new image.
A note to the css
The following zero-space width character is needed to have the div react on the size specified. Probably setting min-width would also work.
.image-marker-png:after {
content: '\200b';
}
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
const svgOutput = {
mounted () {
this.svg = this.$el.querySelector('svg')
let img = document.createElementNS('http://www.w3.org/2000/svg', 'image')
img.setAttribute('x', 0)
img.setAttribute('y', 0)
img.setAttribute('width', '100%')
img.setAttribute('height', '100%')
img.setAttribute('href', 'https://unsplash.it/300')
console.log(img)
this.svg.appendChild(img)
// setInterval(this.add, 50)
this.image = this.svg.querySelector('image')
this.image.addEventListener('mousedown', this.markImage)
},
beforeDestroy() {
// clean listeners
this.image.removeEventListener('mousedown', this.markImage)
},
template: `
<div>
<svg width="300px" height="300px" xmlns="http://www.w3.org/2000/svg"></svg>
<button #click="add">add random</button>
<button #click="add($event, {x: 20, y: 40}, {width: 50, height: 100})">
add "x20,y40,w50,h100"
</button>
</div>
`,
methods: {
add (evt, pos, dimension, color) {
let rectangle = document.createElementNS("http://www.w3.org/2000/svg", 'rect')
let containerSize = this.svg.getBoundingClientRect();
dimension = dimension || {}
pos = pos || {}
let sizeX = dimension.width || 50;
let sizeY = dimension.height || 50;
let x = pos.x || (Math.random()*(containerSize.width) - sizeX)
let y = pos.y || (Math.random()*(containerSize.height) - sizeY)
// some limiting
if (x > containerSize.width) {
x = containerSize.width - sizeX + 1
}
if (x < 0) {
x = 1
}
if (y > containerSize.height) {
y = containerSize.height - sizeY + 1
}
if (y < 0) {
y = 1
}
rectangle.setAttribute('class', 'image-marker')
rectangle.setAttribute('width', sizeX)
rectangle.setAttribute('height', sizeY)
rectangle.setAttribute('x', x)
rectangle.setAttribute('y', y)
rectangle.setAttribute('fill', color || getRandomColor())
rectangle.setAttribute('stroke', 'black')
this.svg.appendChild(rectangle)
},
markImage (evt) {
console.log('clicked svg', evt)
this.add(evt, {x: evt.offsetX, y: evt.offsetY}, {width: 20, height: 20})
}
}
}
const imgOutput = {
beforeDestroy() {
// clean listeners
this.container.removeEventListener('mousedown', this.markImage)
},
mounted() {
this.container = this.$el
this.container.addEventListener('mousedown', this.markImage)
},
template: `
<div class="image-container">
<img src="https://unsplash.it/300"/>
</div>
`,
methods: {
add (evt, pos, dimension, color) {
let marker = document.createElement('div')
marker.setAttribute('class', 'image-marker-png')
marker.setAttribute('style', `
left: ${pos.x}px;
top: ${pos.y}px;
width: ${dimension.width}px;
height: ${dimension.height}px;
background-color: ${color || getRandomColor()}`)
console.log('add marker', marker)
this.container.appendChild(marker)
},
markImage (evt) {
console.log('clicked image', evt)
this.add(evt, {x: evt.offsetX, y: evt.offsetY}, {width: 20, height: 20})
}
}
}
console.log(imgOutput)
new Vue({
components: {
svgOutput,
imgOutput
},
el: '#app'
})
.image-marker:hover {
stroke-width: 1px;
stroke: yellow;
}
.image-container {
position: relative;
display: inline-block;
overflow: hidden;
}
.image-marker-png {
position: absolute;
z-index: +1;
}
.image-marker-png:hover{
border: 1px solid yellow;
}
.image-marker-png:after {
content: '\200b';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<svg-output></svg-output>
<img-output></img-output>
</div>

Adding incremental relative position to dynamically created divs

I am trying to create this shape using dynamically created divs. I have this code already in place:
var bgImg = ['ScreenShot.png', 'stars.jpg', 'ScreenShot.png', 'stars_1230_600x450.jpg'];
for (var i = 0, n = 12; i < n; i++) {
var port = document.createElement('div');
document.body.appendChild(port);
port.style.backgroundImage = "url('" + bgImg[3] + "')";
I would like to create this image: https://flic.kr/p/mSJm6G
which will eventually hold images from the array. (one image per slot on the grid.)
I have tried below, which only does not work, it doesn't do what i want, which is to add that amount each time a new div is created. I want a new object to raise by 40px each time it is created.
$(port).css('top','+=40n');
I think that i will have to create three divs/scripts,, one for each row, so that i can get the divs to align properly. the master css will set the divs with a negative margin-top so they can cascade properly.
for reference, my css looks like this:
div {
height: 190px;
width:230px;
background: red;
position: relative;
background: #ef4c4d;
background-position: center;
float: left;
margin: 8px;
top: 30px;
left: 10px;
}
div:before {
content: '';
position: absolute;
bottom: 0; right: 0;
border-bottom: 60px solid #0d1036;
border-left: 60px solid transparent;
width: 0;
}
div:after {
content: '';
position: absolute;
top: 0; left: 0;
border-top: 60px solid #0d1036;
border-right:60px solid transparent;
width: 0;
}
I think that i need to pull the integer from an array, but really not sure.
Some things I notice in your code:
for (var i = 0, n = 12; i < n; i++) {
var port = document.createElement('div');
document.body.appendChild(port);
// <- end "}" of for loop is missing here
port.style.backgroundImage = "url('" + bgImg[3] + "')"; // <- will just be applied on the last created div
I guess you want something like this:
for (var i = 0, n = 12; i < n; i++) {
var port = document.createElement('div');
port.style.backgroundImage = "url('" + bgImg[3] + "')";
document.body.appendChild(port);
}
To update the "top" property, you can use this code with jQuery:
for (var i = 0, n = 12; i < n; i++) {
var port = $('<div></div>');
port.css("background-image", "url('" + bgImg[3] + "')");
port.css("top": 40 * i + "px"); // <- set "top" +40px for each div
$("body").append(port);
}

Dynamically added div with length = 0?

so I am trying to check if I already added the a div with the same id and if I did, I chage its color to red. But for some reason my divs have a length of 0 and the if clause is never true.
I've been doing some research and this is very often due to a float, but I don't have one. I am just positionting my divs absolutely and appending them to the body.
Please have a look, any help I will be grateful for!
Thanks.
<body>
<style>
#box {
background: url('a.gif') no-repeat;
width: 50px;
height: 30px;
position: absolute;
top:210px;
left: 0;
}
#grid {
background: url('grid.gif') no-repeat;
width: 423px;
height: 240px;
margin-left: 4px;
}
#stand {
background: black;
width: 4px;
height: 240px;
margin-left: 23px;
}
#hstand {
/*horizontal stand for the carrier*/
width: 423px;
margin-left: 27px;
height: 4px;
background: black;
}
</style>
<script>
$(function() {
$('#box').click(function(e) {
var i = 0;
while (i < 50) { //specifying the cycles for the box' movement
var hstandWidth = $("#hstand").width() + 27; //getting the current x-coordinates
//array to randomly select x-coordinates from
var items = Array(hstandWidth - (50) * 1, hstandWidth - (50) * 2, hstandWidth - (50) * 3, hstandWidth - (50) * 4, hstandWidth - (50) * 5, hstandWidth - (50) * 6, hstandWidth - (50) * 7, hstandWidth - (50) * 8);
//variable with the x-coordinates, which are randomly fetched from the array
var moveLeft = items[Math.floor(Math.random() * items.length)];
//array to randomly select y-coordinates from
var items2 = Array(30, 30 * 2, 30 * 3, 30 * 4, 30 * 5, 30 * 6, 30 * 7);
//variable with the y-coordinates, which are randomly fetched from the array
var moveTop = items2[Math.floor(Math.random() * items2.length)];
// y-achs movement
$(this).animate({
"top": "" + moveTop + "px"
}, 80);
// x-achs movement with the callback function which should add the colored div to every position the box has been
// create closure to capture moveTop and moveLeft values for later callback
// use different named variables xmoveTop and xmoveLeft to distinguish the
// closure variable from the outer for loop variable
(function(obj, xmoveTop, xmoveLeft) {
$(obj).animate({
"left": "" + xmoveLeft + "px"
}, 80, function() {
if ($("#" + xmoveLeft + xmoveTop + "").length > 0) {
$("#" + xmoveLeft + xmoveTop + "").css("background", "red");
} else {
$("<div style='position: absolute; top: " + xmoveTop + "px; left: " + xmoveLeft + "px; background: blue; width: 50px; height: 30px;' id='" + xmoveTop + xmoveLeft + "'></div>").appendTo("body");
console.log($("#" + xmoveLeft + xmoveTop + "").length);
}
});
})(this, moveTop, moveLeft);
//get the box to the initial position
$(this).animate({
"left": "0px"
}, 80);
$(this).animate({
"top": "210px"
}, 80);
//mark cycle passed
i++;
}
});
});
</script>
</head>
<body>
<div id="box"></div>
<div id="stand">
<div id="grid"></div>
</div>
<div id="hstand"></div>
</body>
You create your div with id="xmoveTop + xmoveLeft" but you search for it with id="xmoveLeft + xmoveTop".
So change this line :
if ($("#" + xmoveLeft + xmoveTop + "").length > 0) {
$("#" + xmoveLeft + xmoveTop + "").css("background", "red");
To :
if ($("#" + xmoveTop + xmoveLeft + "").length > 0) {
$("#" + xmoveTop + xmoveLeft + "").css("background", "red");
You search for
"#"+xmoveLeft + xmoveTop +""
but you create the id with
" id='"+ xmoveTop + xmoveLeft +"'"
Since they are created as strings you do not use the sum but concatenated strings..
Wrap them in parenthesis, so you get the actual sum ..
"#"+ (xmoveLeft + xmoveTop) +"" and id='"+ (xmoveTop + xmoveLeft) +"'

Improve my Draggable DIV

Can anyone can help me to improve this draggable DIV? In the first drag/drop, all runs perfect. But when I try to drag for the 2nd time, the position bugs.
CSS
#coordenadas {
position: fixed;
bottom: 0px;
right: 0px;
background: rgb(224, 224, 224);
}
#clicado {
position: fixed;
bottom: 20px;
right: 0px;
background: rgb(224, 224, 224);
}
#janela {
position: absolute;
height: 100px;
width: 100px;
background: rgb(224, 224, 224);
}
JavaScript
var clicado = false;
var inicioX;
var inicioY;
var finalX;
var finalY;
document.onmousemove = function mostrarInfo(event) {
if (clicado == true) {
finalX = event.clientX;
finalY = event.clientY;
pontoX = finalX - inicioX;
pontoY = finalY - inicioY;
document.getElementById('janela').style.top = pontoY + "px";
document.getElementById('janela').style.left = pontoX + "px";
document.getElementById('coordenadas').innerHTML = "X: " + pontoX + " | ";
document.getElementById('coordenadas').innerHTML += "Y: " + pontoY;
}
}
function segurar(event) {
clicado = true;
document.getElementById('clicado').innerHTML = "Mouse: Segurando";
inicioX = event.clientX;
inicioY = event.clientY;
}
function soltar() {
clicado = false;
document.getElementById('clicado').innerHTML = "Mouse: Solto";
}
HTML
<div id="janela" onmousedown="segurar(event);" onmouseup="soltar();"></div>
<span id="coordenadas"></span>
<span id="clicado"></span>
The problem is how you're calculating the new position of your <div>. In your code, you are taking your mouse position and subtracting the initial position. This is OK for the first time around, because your initial position is top: 0; left: 0. But once you start moving it the second time it becomes more obvious. You're setting the position to the distance between your start position and your end position.
Change your mostrarInfo like this:
document.onmousemove = function mostrarInfo(event) {
if (clicado == true) {
pontoX = event.clientX;
pontoY = event.clientY;
document.getElementById('janela').style.top = pontoY + "px";
document.getElementById('janela').style.left = pontoX + "px";
document.getElementById('coordenadas').innerHTML = "X: " + pontoX + " | ";
document.getElementById('coordenadas').innerHTML += "Y: " + pontoY;
}
}
See this JSFiddle.
It is still not perfect, because it's trying to set the top-left corner of the <div> to your mouse position, but it is still better than your other one. To make it more exact, I suggest using something like JQuery instead. (Or else you'd need to figure out where in the <div> the click is happening, find the distance between that point and the top-left corner, and adjust your pontoX and pontoY accordingly.)
You need to subtract the current position of the div to your offset since the mousedown event gives you global coordinates.
function segurar(event) {
clicado = true;
document.getElementById('clicado').innerHTML = "Mouse: Segurando";
inicioX = event.clientX - document.getElementById('janela').offsetLeft;
inicioY = event.clientY - document.getElementById('janela').offsetTop;
}
here's my jsfiddle

Categories