Custom Drag & Drop not working perfectly - javascript

I want to drag a div and drop anywhere in its parent div . For dragging I use css style
draggable="true"
and for drop, I use 'mousemove' event X and Y values and use this values for div top and left .The code I used is
$(".drop").mousedown(function () {
$(this).mousemove(function (e) {
var k = e.clientX ;
var f = e.clientY;
$(".drop").text(k+ ", " + f);
$(".drop").css("top",f);
$(".drop").css("left",k);
});
}).mouseup(function () {
$(this).unbind('mousemove');
}).mouseout(function () {
$(this).unbind('mousemove');
});
.drop{
position: absolute;
left: 300;
top: 200; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
}
.gridPart{
padding: 20px;
background-color: #FFF;
border-radius: 5px;
margin: auto;
margin: 20px;
padding-right: 0px;
padding-bottom: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gridpart">
<div class="drop" draggable="true" ></div>
<div>
Now it's drag & drop if I drag with increasing left value. But if I drag with decreasing left value it's not dropping. And how I stop the drag if it reach the end of the main div(GridPart)?

I have fixed your code. All you did is quite good but you should have to use the mousemove event with $(document) element and not with the div. Since when you drag backwards, mouse movement is going out of the div and so its no longer dragging.
Also, as you used custom dragging, you don't need to use draggable="true".
$(".drop").mousedown(function () {
$(document).mousemove(function (e) {
var k = e.clientX;
var f = e.clientY;
$(".drop").text(k+ ", " + f);
$(".drop").css("top", f + 'px');
$(".drop").css("left", k + 'px');
});
});
$(document).mouseup(function () {
$(document).unbind('mousemove');
});
.drop{
position: absolute;
left: 300;
top: 200; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
}
.gridPart{
padding: 20px;
background-color: #FFF;
border-radius: 5px;
margin: auto;
margin: 20px;
padding-right: 0px;
padding-bottom: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gridpart">
<div class="drop" ></div>
<div>

Simply use the JQueryUi Draggable:
https://jqueryui.com/draggable/
UPDATE: sample code here:
http://embed.plnkr.co/5W3ACU/

I think what i have discerned from your question you are trying to do, is limit dragging to within the .gridpart div.
The key was moving the drag detection to the container div, and then moving the drag component based on the mousedown position
JSFIDDLE
JS
$(".gridpart").mousedown(function () {
var containerDims = $(this)[0].getBoundingClientRect();
var dropEl = $(this).find('.drop');
// measure the size of the drop element
var dropDims = dropEl[0].getBoundingClientRect()
$(this).mousemove(function (e) {
// position the element centered under the cursor
var k = e.clientX - dropDims.width / 2;
var f = e.clientY - dropDims.height / 2;
if( k >= 0 && k <= containerDims.width - dropDims.width){
dropEl.css("left",k);
}
if(f >= 0 && f <= containerDims.height - dropDims.height){
dropEl.css("top", f);
}
dropEl.text(k + ', ' + f);
});
}).mouseup(function () {
$(this).unbind('mousemove');
});
CSS
.drop{
position: absolute;
left: 0;
top: 20px;
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
/* prevent 'shadow' drag preventing mouseup firing */
-webkit-user-drag: none;
-khtml-user-drag: none;
-moz-user-drag: none;
-o-user-drag: none;
user-drag: none;
}
.gridpart{ /* correct camelcase typo */
background-color: #F00;
border-radius: 5px;
margin: 20px;
padding-right: 0px;
position: relative;
height: 58px;
}
HTML
<div class="gridpart">
<div class="drop" draggable="true">0, 0</div>
<div>

Related

Problems with moving a div by cursor if I move it too fast

to specify my question I wrote an standalone example of my problem. I want to precisely move a div inside a wrapping container (only in x-direction), like a trackbar. The wrapping div should specify the space for the slider.
My script works, if I slowly move the cursor. But if I move the cursor too fast I kind of loose the slider div somewhere inside the container. Especially in the right and left corner.
How can I improve the code to have a stable solution, without the need of librarys? I know that there is a kind of simple solution with jQuery, but I would be very happy if we could find a way in plain javascript.
var x_mouse_position;
var x_offset;
var isDown = false;
var new_slider_left_position;
var container = document.getElementById("container");
var slider = document.getElementById("slider");
slider.addEventListener('mousedown', function (e) {
isDown = true;
x_offset = slider.offsetLeft - e.clientX;
}, true);
document.addEventListener('mouseup', function () {
isDown = false;
}, true);
document.addEventListener('mousemove', function (event) {
if (isDown) {
x_mouse_position = event.clientX;
new_slider_left_position = x_mouse_position + x_offset;
if (new_slider_left_position >= 0 && new_slider_left_position <= container.offsetWidth - slider.offsetWidth) {
slider.style.left = new_slider_left_position + 'px';
}
}
}, true);
html,
body {
height: 100%;
width: 100%;
}
body {
background-color: antiquewhite;
display: flex;
justify-content: center;
align-items: center;
}
#container {
position: relative;
width: 400px;
height: 30px;
background-color: cornflowerblue;
border-radius: 5px;
overflow: hidden;
}
#slider {
position: absolute;
top: 0;
left: 0;
box-sizing: border-box;
border: 1px solid black;
width: 50px;
height: 100%;
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.2);
cursor: move;
}
<div id="container">
<div id="slider"></div>
</div>

Compounding Value within an object used to slide dot across the page incrementally

I am unable to get a variable to function properly as the translateX value within my object. I am wanting to make the dot scroll across the page each time the next button is clicked. My code is only able to move it back and forth for the first step.
I am new to the animation API, and I have already made this work with CSS transitions but I am trying to get a good handle on the API.
html:
<div class="progress__container">
<div class="progress__bar">
<div id="progress__fill" class="step1"></div>
<div class="circ" id="circ__1"></div>
<div class="circ" id="circ__2"></div>
<div class="circ" id="circ__3"></div>
<div class="circ" id="circ__4"></div>
<div id="progress__dot" class="prog__1"></div>
</div>
<div class="backBar"></div>
<div class="flexrow">
<span class="stepName">Account</span>
<span class="stepName">Frequency</span>
<span class="stepName">Amount</span>
<span class="stepName">Taxes</span>
</div>
<div class="button__container">
<button class="buttonStep" id="back">Back</button>
<button class="buttonStep is-active" id="next">Next</button>
</div>
</div>
js:
// give a starting value for the transformation
var startVal = 0;
// define the keyframes
var moveDot = [
{ transform: `translateX(${startVal}px)`},
{ transform: `translateX(${startVal + 190}px)`}
];
// definte the timing
var dotTiming = {
duration: 400,
fill: "forwards",
easing: 'ease-in',
}
// make the animation happen
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
// pause the animation until called
movingDot.pause();
// on click fire the animation
document.getElementById('next').addEventListener('click', function() {
movingDot.playbackRate = 1;
if (startVal <= 380) {
movingDot.play();
startVal += 190;
}
});
document.getElementById('back').addEventListener('click', function() {
movingDot.playbackRate = -1;
if (startVal >= 0) {
movingDot.play();
startVal -= 190;
}
});
css:
#progress__fill {
height:2px;
position: absolute;
top: 7px;
left: 0;
background-color: darkred;
}
#progress__dot {
background-color: darkred;
color: #fff;
border-radius: 50%;
height: 8px;
width: 8px;
position: absolute;
text-align:center;
line-height: 8px;
padding: 6px;
top: 0;
font-size: 12px;
}
/* Static Bar Elements */
.progress__container {
width: 600px;
margin: 20px auto;
position: relative;
}
.backBar {
height:2px;
width:96%;
position: absolute;
top: 7px;
left: 2%;
background-color: lightgrey;
}
.progress__bar {
z-index: 100;
position: relative;
width: 96%;
margin: 0 auto;
}
.circ {
background-color: #fff;
border: 2px solid lightgrey;
border-radius: 50%;
height: 12px;
width: 12px;
display: inline-block;
}
#circ__2, #circ__3 {
margin-left: 30%
}
#circ__4 {
float: right;
}
.passed {
background-color: darkred;
border: 2px solid darkred;
}
.hide {
visibility: hidden
}
.flexrow {
display: flex;
flex-direction: row;
justify-content: space-between;
}
/* Buttons */
.buttonStep {
background: grey;
color: #fff;
padding: 10px 25px;
border-radius: 10px;
font-size: 16px;
}
#back {
float: left;
}
#next {
float: right;
}
.is-active {
background: darkred;
}
The way I have it set up, I expect for the translateX values to increment or decrement depending on the click event listeners which would make the circle slide across the page. What is actually happening is that only the first step works. it will not go past the first stop point. If I log moveDot in the console it gives me the values that I am expecting, but it will only start/stop at 0 and 190. the back button functions the same way. link to fiddle
It is animated from and to the same place every time. Move the definition of moveDot into the event listener:
// give a starting value for the transformation
var startVal = 0;
// definte the timing
var dotTiming = {
duration: 400,
fill: "forwards",
easing: 'ease-in',
}
// on click fire the animation
document.getElementById('next').addEventListener('click', function() {
if (startVal > 380){return;}
// define the keyframes
var moveDot = [{transform: `translateX(${startVal}px)`},
{transform: `translateX(${startVal + 190}px)`}];
// make the animation happen
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
movingDot.playbackRate = 1;
movingDot.play();
startVal += 190;
});
document.getElementById('back').addEventListener('click', function() {
movingDot.playbackRate = -1;
if (startVal >= 0) {
movingDot.play();
startVal -= 190;
}
});

prevent click on hyperlink while dragging/holding

I have item div elements with anchor elements as children. The size of the anchor children stretches the parent item element.
I've made the item elements draggable with the library interact.js. The items get draggable when they are hold 300ms or longer. The problem is, that the anchor link of the item child get fired when the drag is released.
How can I prevent the child from firing the hyperlink when the parent element is held/dragged?
Here is a small example of the problem
let items = document.getElementsByClassName("item");
// add class .draggable to each item
for(var i = 0; i < items.length; i++)
{
items[i].classList.add("draggable");
}
// target elements with the "draggable" class
interact('.draggable').draggable({
autoScroll: true,
hold: 300,
// call this function on every dragmove event
onmove: dragMoveListener,
// call this function on every dragend event
onend: function (event) {
var target = event.target;
target.style.webkitTransform =
target.style.transform =
'translate(0px, 0px)';
target.setAttribute('data-x', 0);
target.setAttribute('data-y', 0);
}
});
// this function is calles on every dragmove event
function dragMoveListener (event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// update the posiion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
};
interact('.dropzone').dropzone({
ondropactivate: function (event) {
event.target.classList.add('drop-active');
},
ondragenter: function (event) {
var draggableElement = event.relatedTarget,
dropzoneElement = event.target;
// feedback the possibility of a drop
dropzoneElement.classList.add('drop-target');
draggableElement.classList.add('can-drop');
},
ondragleave: function (event) {
// remove the drop feedback style
event.target.classList.remove('drop-target');
event.relatedTarget.classList.remove('can-drop');
},
ondrop: function (event) {
//delete Bookmark here!
event.relatedTarget.classList.add('drop-ok');
},
ondropdeactivate: function (event) {
// remove active dropzone feedback
event.target.classList.remove('drop-active');
event.target.classList.remove('drop-target');
}
});
body {
background-color: #EDEFF3;
padding: 40px 48px;
}
.item {
display: inline-block;
margin: 8px;
background-color: RGBA(255, 255, 255, 1);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
border-radius: 10px;
z-index: 999;
}
.item a {
position: relative;
display: inline-block;
border-radius: 10px;
line-height: 40px;
padding: 0 32px 0 48px;
font-weight: 400;
text-decoration: none;
font-size: 13px;
color: black;
font-size: 14px;
}
.item a .dott {
position: absolute;
top: 12px;
left: 20px;
height: 16px;
width: 16px;
background-color: tomato;
border-radius: 100%;
}
.item.can-drop a {
text-decoration: line-through;
}
.item.drop-ok {
display: none;
}
.category {
display: flex;
flex-wrap: wrap;
position: relative;
align-items: flex-start;
background-color: RGBA(127, 135, 147, 0.2);
margin: 16px;
padding: 8px;
}
.dropzone {
height: 20%;
width: 100%;
position: fixed;
bottom: 0;
left: 0;
background-color: tomato;
opacity: 0;
}
.dropzone.drop-active {
opacity: 1;
}
.dropzone.drop-target {
background-color: #F15B52;
}
<script src="https://cdn.jsdelivr.net/npm/interactjs#1.3.4/dist/interact.min.js"></script>
<div class="category">
<div class="item">
<span class="dott"></span>bookmark
</div>
<div class="item">
<a href="https://www.google.com/">
<span class="dott"></span>
bookmark</a>
</div>
<div class="item">
<span class="dott"></span>bookmark
</div>
<div class="item">
<span class="dott"></span>bookmark
</div>
<div class="item">
<span class="dott"></span>bookmark
</div>
</div>
<div class="dropzone"></div>
Here is my current state at Codepen:
https://codepen.io/iamrbn/pen/pKGPMz
Perhaps not the most elegant solution but it works. My first attempt failed but I think I have something that works now. I created a flag system to keep track of events. Note that I added onstart to the draggable instance. I had to add a 300ms timeout to match the time of the hold. It seems onstart fired immediately on mousedown despite the 300ms hold. I'm not sure how that part of your library works ;)
Anyway, wait 300ms and then set a flag of drag. Note that the variable is global for reference. Check your project variable scope before implementing this. You might want to create a public object instead to keep the global from mixing things up.
I add a click event listener to each link. When the click fired, check the hold flag status. If it is a drag, prevent the event. Otherwise, proceed to register a click. Note: I tried adding this flag evaluator code to the onend method within the draggable instance but onend turns out to be a mouseup event which fires before click. Therefore, the evaluation needs to happen with a click event. The best way to do that within the scope is with adding a click event to each link.
Whew! Gosh, that took probably an hour. Let me know if it works :)
let items = document.getElementsByClassName("item");
// add class .draggable to each item
for (var i = 0; i < items.length; i++) {
items[i].classList.add("draggable");
items[i].children[0].addEventListener('click',function(e){
if(drag){
drag = false;
e.preventDefault()
}
});
}
var drag = false;
// target elements with the "draggable" class
interact('.draggable').draggable({
autoScroll: true,
hold: 300,
// call this function on every dragmove event
onstart: function(){
setTimeout(function(){
drag = true;
},300);
},
onmove: dragMoveListener,
// call this function on every dragend event
onend: function(event) {
var target = event.target;
target.style.webkitTransform =
target.style.transform =
'translate(0px, 0px)';
target.setAttribute('data-x', 0);
target.setAttribute('data-y', 0);
}
});
// this function is calles on every dragmove event
function dragMoveListener(event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// update the posiion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
};
interact('.dropzone').dropzone({
ondropactivate: function(event) {
event.target.classList.add('drop-active');
},
ondragenter: function(event) {
var draggableElement = event.relatedTarget,
dropzoneElement = event.target;
// feedback the possibility of a drop
dropzoneElement.classList.add('drop-target');
draggableElement.classList.add('can-drop');
},
ondragleave: function(event) {
// remove the drop feedback style
event.target.classList.remove('drop-target');
event.relatedTarget.classList.remove('can-drop');
},
ondrop: function(event) {
//delete Bookmark here!
event.relatedTarget.classList.add('drop-ok');
},
ondropdeactivate: function(event) {
// remove active dropzone feedback
event.target.classList.remove('drop-active');
event.target.classList.remove('drop-target');
}
});
body {
background-color: #EDEFF3;
padding: 40px 48px;
}
.item {
display: inline-block;
margin: 8px;
background-color: RGBA(255, 255, 255, 1);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
border-radius: 10px;
z-index: 999;
}
.item a {
position: relative;
display: inline-block;
border-radius: 10px;
line-height: 40px;
padding: 0 32px 0 48px;
font-weight: 400;
text-decoration: none;
font-size: 13px;
color: black;
font-size: 14px;
}
.item a .dott {
position: absolute;
top: 12px;
left: 20px;
height: 16px;
width: 16px;
background-color: tomato;
border-radius: 100%;
}
.item.can-drop a {
text-decoration: line-through;
}
.item.drop-ok {
display: none;
}
.category {
display: flex;
flex-wrap: wrap;
position: relative;
align-items: flex-start;
background-color: RGBA(127, 135, 147, 0.2);
margin: 16px;
padding: 8px;
}
.dropzone {
height: 20%;
width: 100%;
position: fixed;
bottom: 0;
left: 0;
background-color: tomato;
opacity: 0;
}
.dropzone.drop-active {
opacity: 1;
}
.dropzone.drop-target {
background-color: #F15B52;
}
<script src="https://cdn.jsdelivr.net/npm/interactjs#1.3.4/dist/interact.min.js"></script>
<div class="category">
<div class="item">
<span class="dott"></span>bookmark
</div>
<div class="item">
<a href="https://www.google.com/">
<span class="dott"></span> bookmark
</a>
</div>
<div class="item">
<span class="dott"></span>bookmark
</div>
<div class="item">
<span class="dott"></span>bookmark
</div>
<div class="item">
<span class="dott"></span>bookmark
</div>
</div>
<div class="dropzone"></div>

Can I undo or delete some javascript code after running it

I am 3th year at college and for web design class we are manually drawing canvas elements. Which is very boring for me so I tried to make some 2D paint where I can do it by mouse where on the other end it writes code by itself.
I managed to do this much even tho is not "much" but now I am wondering is there a way to undo some script to remove it from the code? One way would be to append new canvas and do moves by one less but is there something to delete existing ones but not to recreate new ones over and over again?
In this example down below (try by full screen), when I add new lines I add new moves to the array and when I finish at the starting point I can draw new element. But every time I add new line I re create or draw lines over existing ones and new lines so it shows as one element where I could fill style and so on.
By doing that you will see that the adding lines over existing ones create a little darker bolder line, and because of that I would like to know if there is some way to delete or undo those lines and add whole new ones without puting em over existing ones.
$(document).ready(function(){
var mainCanvas = $('#mainCanvas')[0].getContext('2d');
var coordsCanvas = $('#coordsCanvas')[0].getContext('2d');
var moves = [];
$('#newCoords').click(function(){
var mainCanvasWidth = $('#mainCanvas').width();
$(this).parent().prepend('<input class="input-class" id="x-n0" placeholder="X number of blocks"><input class="input-class" id="y-n0" placeholder="Y number of blocks"> <span class="notes">Note: canvas full width is: '+Math.floor(mainCanvasWidth)+'px. </span><button id="saveCoords">Save</button>')
$(this).remove();
});
$(document).on('click','#saveCoords',function(){
var x = $(this).siblings('input#x-n0').val(),
y = $(this).siblings('input#y-n0').val(),
mainCanvasWidth = $('#mainCanvas').width(),
mainCanvasHeight = $('#mainCanvas').height(),
xWidthPx = Math.floor(mainCanvasWidth/x),
yHeightPx = Math.floor(mainCanvasHeight/y);
$('#coordsCanvas, #mainCanvas').attr('width', Math.floor(xWidthPx*x));
$('#coordsCanvas, #mainCanvas').attr('height', Math.floor(yHeightPx*y));
var marginLeftRight = 'calc(50% - '+Math.floor(xWidthPx*x)/2+'px)';
$('#coordsCanvas, #mainCanvas').css({'width':Math.floor(xWidthPx*x)+'px','height':Math.floor(yHeightPx*y)+'px','left': marginLeftRight, 'top':'10vh'});
for(var i=0; i<x-1; i++){
coordsCanvas.beginPath();
coordsCanvas.moveTo(Math.floor(xWidthPx+(xWidthPx*i)), 0);
coordsCanvas.lineTo(Math.floor(xWidthPx+(xWidthPx*i)), Math.floor(yHeightPx*y));
coordsCanvas.stroke();
coordsCanvas.closePath();
}
for(var i=0; i<y-1; i++){
coordsCanvas.beginPath();
coordsCanvas.moveTo(0 ,Math.floor(yHeightPx+(yHeightPx*i))+1);
coordsCanvas.lineTo(Math.floor(xWidthPx*x), Math.floor(yHeightPx+(yHeightPx*i))+1);
coordsCanvas.stroke();
coordsCanvas.closePath();
}
$(this).parent().html('<label for="#mouse-position"><input type="checkbox" id="mouse-position">Show mouse position</label><span class="notes">X = '+Math.floor(xWidthPx)+'px; Y = '+Math.floor(yHeightPx)+'px;</span><div class="tools"><button id="line">Lines</button></div>');
});
$(document).on( "change", "#mouse-position", function() {
if($('input[id="mouse-position"]:checked').length === 1){
$('#mouse-coords').css('display','block');
}else{
$('#mouse-coords').css('display','none');
}
});
$(document).on( "click", "#line", function() {
$(this).css('background','silver');
$('#mainCanvas').css({'cursor':'url(./pen.png) 0 24, auto'});
});
$(document).on( "click", "#mainCanvas", function(e) {
var cursor = $('#mainCanvas').css('cursor');
var strokeStyle = $('#strokestyle').val();
if(~cursor.indexOf('pen.png')){
var posX = $(this).position().left,
posY = $(this).position().top;
if(moves[0]==='beginPath'){
if(Object.keys(moves[1])[0]==='moveTo'){
var len = moves.length-1,
nowpos = Math.floor((e.pageX - posX)) + ',' + Math.floor((e.pageY - posY)),
renderDrawing = [];
renderDrawing.push({'func': 'beginPath', init: function(){ mainCanvas.beginPath(); }});
if(moves[len]!=="stroke" || moves[len]!=="closePath"){
for(var ee=1; ee<moves.length; ee++){
if(Object.keys(moves[ee])[0]==="moveTo"){
var mtp = moves[ee]['moveTo'],
pos = mtp.split(',');
renderDrawing.push({func: 'moveTo', val: pos, init: function(){
mainCanvas.moveTo(this.val[0], this.val[1]);
}});
}else if(Object.keys(moves[ee])[0]==="lineTo"){
var mtp = moves[ee]['lineTo'],
pos = mtp.split(',');
renderDrawing.push({func: 'lineTo', val: pos, init: function(){
mainCanvas.lineTo(this.val[0], this.val[1]);
}});
}
}
var nowX = Math.floor((e.pageX - posX));
var nowY = Math.floor((e.pageY - posY));
var nowXY = nowX + ',' + nowY;
moves.push({'lineTo':nowXY});
renderDrawing.push(
{func: 'lineTo', val: nowXY, init: function(){
mainCanvas.lineTo(this.val.split(',')[0], this.val.split(',')[1]);
}},
{func: 'stroke', init: function(){ mainCanvas.stroke(); }},
{func: 'closePath', init: function(){ mainCanvas.closePath(); }});
for(var q=0; q<renderDrawing.length; q++){
if(renderDrawing[q]['func']!=="beginPath" && renderDrawing[q]['func']!=="closePath" && renderDrawing[q]['func']!=="stroke"){
renderDrawing[q].init();
}else renderDrawing[q].init();
}
console.log(moves);
if(Object.keys(moves[len])[0]==="lineTo" && nowpos===moves[1]['moveTo']){
moves = [];
}
}
}
}else{
mainCanvas.beginPath();
mainCanvas.moveTo(Math.floor(e.pageX - posX) , Math.floor(e.pageY - posY));
moves.push('beginPath',{'moveTo':Math.floor((e.pageX - posX)) + ',' + Math.floor((e.pageY - posY))});
console.log(moves);
}
}
});
$(document).on('mousemove', "#mainCanvas", function(e){
var parentOffset = $('#mainCanvas').offset();
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
$('#mouse-coords').css({
left: e.pageX + 20,
top: e.pageY
}).text( "X: " + Math.floor(relX) + ", Y: " + Math.floor(relY) );
});
});
* {
margin: 0;
padding: 0;
list-style: none;
text-decoration: none;
box-sizing: border-box;
}
body {
overflow: hidden;
font-size: 100%;
}
.container {
width: 100vw;
height: 100vh;
padding-right: 5vw;
padding-left: 5vw;
padding-top: 10vh;
padding-bottom: 5vh;
overflow: hidden;
position: relative;
}
canvas {
width: 90vw;
height: 85vh;
border: 1px solid #000;
float: left;
}
.toolsBar {
width: calc(100% - 10vw);
position: absolute;
top: 5px;
left: 5vw;
border: 1px solid #000;
height: calc(10vh - 10px);
overflow: hidden;
overflow-y: auto;
}
button {
color: #fff;
background: skyblue;
border: 0;
border-radius: 5px;
margin: 5px;
padding: 15px;
cursor: pointer;
float: left;
}
.input-class {
border-radius: 5px;
margin: 5px;
padding: 15px;
float: left;
border: 1px solid #e0e0e0;
outline: none;
}
.notes {
display: inline-block;
height: 60px;
text-align: center;
float: left;
color: red;
line-height: 60px;
}
#mouse-coords {
position: absolute;
display: none;
background: #000;
padding: 2px;
color: #fff;
}
label[for="#mouse-position"] {
display: inline-block;
height: 60px;
text-align: center;
line-height: 60px;
font-size: 1.2rem;
float: left;
padding: 5px;
}
label>input {
height: 1.2rem;
width: 1.2rem;
}
.coordsCanvas {
position: absolute;
z-index: 100;
}
#mainCanvas {
background: rgba(255,255,255,.5);
position: absolute;
z-index: 200;
}
.tools {
width: auto;
overflow: hidden;
overflow-y: auto;
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="toolsBar">
<button id="newCoords">X & Y</button>
</div>
<div id="mouse-coords"></div>
<canvas class="coordsCanvas" id="coordsCanvas"></canvas>
<canvas id="mainCanvas"></canvas>
</div>

Position bottom element of top parent element

I am making this simple tooltip where I want to position the tooltip bottom at the top of the parent element. I want to do this by getting the height of the tooltip element and set this number negative to the top positioning.
The problem is that at the time that I hover the element, the tooltip height is 0, according to console.log();
$('.tooltip').hover(function() {
var content = $(this).data('tip-content');
var element = $(this).find('.tip-content');
if(element.length == 0 ) {
var html = $('<p class="tip-content">' + content + '</p>');
var height = html.height();
console.log(height);
html.css('top', - height);
$(this).prepend(html);
} else {
element.remove();
}
});
.element {
height: 50px;
width: 50px;
margin: 50px auto;
background: #000;
}
.tooltip {
position: relative;
}
.tooltip .tip-content {
width: 180px;
margin-left: -98px;
padding: 10px 5px;
position: absolute;
left: 50%;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background: #294a72;
font-size: 0.75em;
color: #fff;
text-align: center;
}
.tooltip .tip-content:after {
top: 100%;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-top-color: #294a72;
border-width: 5px;
margin-left: -5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="element tooltip" data-tip-content="This is a test content">
</div>
At the time you're checking the height, the element has not yet been added to the DOM, and therefore can have no height. You simply need to switch the order of your statements. jQuery can and will change the CSS of the element even after it has been added.
var html = $('<p class="tip-content">' + content + '</p>');
$(this).prepend(html); //This line must go before the next
var height = html.height();
console.log(height);
However, you're still missing some pieces. height() does not include either margin or padding. To get padding, you can use outerHeight(), but margin you'll have to either read from the CSS or use a hard-coded value. Even worse, your arrow is using a pseudo-element, which *cannot* be read by DOM traversal, so your best bet there is to just hardcode it, sadly.
A better height calculation might look like:
var ARROW_HEIGHT = 5;
html.outerHeight() + parseInt(html.css('marginBottom'), 10) + ARROW_HEIGHT;
I think you have to prepend the HTML, and then get the height and reposition the element. Right now, you are getting the height of a variable, not an HTML element.
You just need to get height of 'tooltip' instead of 'tip-content'.
$('.tooltip').hover(function() {
var content = $(this).data('tip-content');
var element = $(this).find('.tip-content');
if(element.length == 0 ) {
var html = $('<p class="tip-content">' + content + '</p>');
// Get height of parent element
var height = $(this).height();
console.log(height);
html.css('top', - height);
$(this).prepend(html);
} else {
element.remove();
}
});
.element {
height: 50px;
width: 50px;
margin: 50px auto;
background: #000;
}
.tooltip {
position: relative;
}
.tooltip .tip-content {
width: 180px;
margin-left: -98px;
padding: 10px 5px;
position: absolute;
left: 50%;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background: #294a72;
font-size: 0.75em;
color: #fff;
text-align: center;
}
.tooltip .tip-content:after {
top: 100%;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-top-color: #294a72;
border-width: 5px;
margin-left: -5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="element tooltip" data-tip-content="This is a test content">
</div>
For html object gets a height automatically, you need first put in DOM. That the reason for you get height = 0. You need first append your object and then get the height.
See my example: https://jsfiddle.net/bwun82q4/
$('.tooltip').hover(function() {
var content = $(this).data('tip-content');
var element = $(this).find('.tip-content');
if(element.length == 0 ) {
var html = $('<p class="tip-content">' + content + '</p>');
var height = html.height();
console.log(height);
html.css('top', - height);
$(this).prepend(html);
$(this).find("p").css("top",- $(this).find("p").height());
} else {
element.remove();
}});

Categories

Resources