Please run the snippet and drag you mouse over the bar to make it red.
If you drag the mouse very slowly, you will fill it red, but if you move it fast, there will be white holes in it.
How to fix it? (the white holes)
I want to make a bar divided into 500 parts and if you hover it, it becomes red and being able to drag fast and fill it without holes.
Any help appreciated :)
$(function() {
var line = $("#line");
for ( var i = 0; i < 500; i++) {
line.append('<div class="tile" id="t'+(i+1)+'"></div>');
}
var tile = $(".tile");
tile.hover (
function() { //hover-in
$(this).css("background-color","red");
},
function() { //hover-out
}
);
});
#line{
height: 50px;
background-color: #000;
width: 500px;
}
.tile {
height: 50px;
float: left;
background-color: #ddd;
width: 1px;
}
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<div id="line"></div>
With your design one way would be to iterate over the first to your current hovered element and fill it, which would lead no spaces. That said you may want to consider using the HTML5 Canvas and drawing a rectangle from 0 to your mouse position, which will perform significantly faster.
$(function() {
var line = $("#line");
for ( var i = 0; i < 500; i++) {
line.append('<div class="tile" id="t'+(i+1)+'"></div>');
}
var tile = $(".tile");
tile.hover (
function() { //hover-in
var self = this;
$("#line").children().each(function(){
$(this).css("background-color","red");
if(this == self) return false;
});
},
function() { //hover-out
}
);
});
#line{
height: 50px;
background-color: #000;
width: 500px;
}
.tile {
height: 50px;
float: left;
background-color: #ddd;
width: 1px;
}
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<div id="line"></div>
Edit
Below is an example doing the same task but using the HTML 5 Canvas:
$("#line").mousemove(function(e){
var canvas = $(this)[0];
var ctx = canvas.getContext("2d");
var rect = canvas.getBoundingClientRect()
var x = e.clientX - rect.left;
ctx.fillStyle="red";
ctx.fillRect(0, 0, x, canvas.height);
});
#line{ background-color: #ddd; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="line" width=500 height=50 ></canvas>
This is another approach with nextUntil to select siblings..
$(function() {
var line = $("#line");
for ( var i = 0; i < 500; i++) {
line.append('<div class="tile" id="t'+(i+1)+'"></div>');
}
var tile = $(".tile");
line.on( 'mouseover', function(ev){
$('.tile').first().nextUntil( $('.tile').eq(ev.pageX) ).css("background-color","red");
});
line.on( 'mouseleave', function(ev){
$('.tile').css("background-color","#ddd");
});
});
#line{
height: 50px;
background-color: #000;
width: 500px;
}
.tile {
height: 50px;
float: left;
background-color: #ddd;
width: 1px;
}
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<div id="line"></div>
Another solution makes use of jQuery's mousemove method. This allows the bar to go both forward and backwards, simply following the cursors position.
This detects movement inside of the div, then I calculate the position of the cursor within the div as a percentage and apply it as the width of the red bar.
$( ".bar" ).mousemove(function( event ) {
var xCord = event.pageX;
xPercent = (xCord + $('.pct').width()) / $( document ).width() * 100;
$('.pct').width(xPercent+'%');
});
.bar{
background:'#999999';
width:50%;
height:50px;
}
.pct{
height:100%;
background:red;
width:0%;
}
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js">
</script>
<div class="bar" style="background:#999999">
<div class="pct"></div>
</div>
Related
The following code always shows the coordinates of the cursor below the cursor:
function showCoords(e) {
var x = event.clientX;
var y = event.clientY;
var coor = "(" + x + ", " + y + ")";
document.getElementById("box").innerHTML = coor;
var bx = document.getElementById("box");
bx.style.left = e.pageX - 50;
bx.style.top = e.pageY + 20;
}
function clearCoords() {
document.getElementById("box").innerHTML = "";
}
div.relative {
position: relative;
width: 400px;
height: 300px;
border: 1px solid black;
}
div.abs {
position: absolute;
top: 100px;
right: 50px;
width: 200px;
height: 100px;
background-color: yellow;
}
<body onmousemove="showCoords(event)">
<div class="relative">
<div class="abs" onmousemove="showCoords(event)" onmouseout="clearCoords()"></div>
</div>
<div id="box" style="width:100px; height:30px; position:absolute"></div>
</body>
I only want the coordinates to be visible when the mouse pointer is hovering over the yellow rectangle.
If I change <body onmousemove="showCoords(event)"> to <body>, the coordinates are never visible.
How do I get the coordinates be visible only when hovering over the yellow rectangle?
Move the onmousemove listener from the body to the element you want to listen on - div.abs in this case.
I'd recommend not using the onmousemove attribute, in favour of using an entirely javascript solution - just to keep javascript-y things together. Something like (untested)
var listenOn = document.querySelector(".abs");
listenOn.addEventListener("mousemove", ShowCoords);
In my web app, there is a draggable element.
I need to set the left position of this element when the element reaches a certain limit while dragging.
Using jQuery draggable widget, I have access to the position of the element:
function drag(e, ui) {
console.log(ui.position.left);
}
Let say my left attribute is setted to 1100px, I need to set it to 500px and this, without stopping the dragging.
I have three functions: dragStart, drag, and gradEnd.
Currently, I managed to get only one result: when setting ui.position.left = 500; on the drag function (using a condition), the left position is set to 500 but of course, the element is then stuck at 500px. The reason is that every time the drag function is triggered, the left position is setted to 500.
If the code runs only once the line ui.position.left = 500; the position left attribute is set to 500, but directly reset to 1100.
How can I set the left attribute once and for all?
$("#divId").draggable({
drag: drag,
})
function drag(e, ui) {
if (ui.position.top > 50) {
ui.position.left = 100;
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I am not sure how jQuery Draggable handles things under the hood, but even after setting ui.position.left = 100, it does not register in the event until after dragging has stopped - that is why I opted to check the actual CSS property of the element that is being targeted.
I have also provided an example (closure/functional based) which demonstrates how to handle this without having to check CSS..
First example:
$("#divId").draggable({
drag: drag
});
function drag(e, ui) {
if (ui.position.top > 50) {
$("#container").css('padding-left', '100px');
$(this).css('left', '0px');
}
if (ui.position.left < 0) {
ui.position.left = 0
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
width: 300px;
cursor: grab;
}
#container {
height: 100vh;
width: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="container">
<div id="divId">
Bubble
</div>
</div>
Second example, more of a 'closure based functional approach': does not require you to check CSS..
$("#divId").draggable({
drag: drag()
});
function drag(e, ui) {
let TRIGGER = false, TOP_THRESHOLD = 50, LEFT_POSITION = 100;
return function(e, ui) {
if (TRIGGER) {
ui.position.left = LEFT_POSITION;
} else if (ui.position.top > TOP_THRESHOLD) {
TRIGGER = true;
ui.position.left = LEFT_POSITION;
}
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I want to implement a draggable map containing certain elements.
--> See JSFiddle: https://jsfiddle.net/7ndx7s25/7/
By use of mousedown, mousemove and mouseup I achieved the dragging.
However I am facing problems:
When pressing the mouse button down and then moving outside the window I do not get a mouseup event. Reentering the window (having released the mouse button long ago) my map still thinks the button is down and misbehaves accordingly.
When there are objects on the map, I do not get mousemove events while moving through these objects. Therefore the map hangs and jumps as I enter and leave such an object.
While over such objects I still want to have a move mouse cursor. I could change the cursor style on each object (in the Fiddle I did this for Object 1 as an example), but this doesn't seem like a good way. Is there a more elegant solution?
You need e.g. mouseout to catch when leaving the canvas, though that event will also fire when the cursor move over the other elements.
One easy fix is to simply add a class to canvas, that set pointer-events: none on those.
With that class you can control the cursor as well, and avoid setting it with the script.
Stack snippet
updateInfo = function() {
document.getElementById('info').innerHTML =
'Position = ' + JSON.stringify(position) +
'<br />dragInfo = ' + JSON.stringify(dragInfo);
};
const canvas = document.getElementsByTagName('canvas')[0];
let position = { x: 0, y : 0 };
let dragInfo = null;
updateInfo();
canvas.addEventListener('mousedown', function(e) {
dragInfo = {
startEvent: {
x: e.clientX,
y: e.clientY,
},
startPosition: position
};
canvas.classList.add('dragging');
updateInfo();
});
canvas.addEventListener('mousemove', function(e) {
if (dragInfo === null) return;
position = {
x: dragInfo.startPosition.x - (e.clientX - dragInfo.startEvent.x),
y: dragInfo.startPosition.y - (e.clientY - dragInfo.startEvent.y)
};
updateInfo();
});
canvas.addEventListener('mouseup', function(e) {
dragInfo = null;
canvas.classList.remove('dragging');
updateInfo();
});
canvas.addEventListener('mouseout', function(e) {
dragInfo = null;
canvas.classList.remove('dragging');
updateInfo();
});
* {
user-select: none;
font-family: monospace;
}
canvas {
background: black;
border: 1px solid red;
}
.dragging {
cursor: move;
}
.obj {
position: absolute;
width: 50px;
height: 50px;
background: green;
color: white;
text-align: center;
line-height: 50px;
font-weight: bold;
}
.dragging ~ .obj {
pointer-events: none;
}
<div id="myMap-ish">
<canvas width="500" height="300"></canvas>
<div class="obj" style="left: 30px; top: 35px">1</div>
<div class="obj" style="left: 175px; top: 79px">2</div>
<div class="obj" style="left: 214px; top: 145px">3</div>
<div class="obj" style="left: 314px; top: 215px">4</div>
</div>
<div id="info"></div>
Another option could be to use mouseleave, on the outer wrapper, the myMap-ish element, which could be combined with the above added class to simply cursor handling.
The main difference between mouseout and mouseleave is that the latter won't fire when hovering children, as shown in below sample, so we don't need to toggle pointer-events as we did in the first sample.
Note, to simply use mouseleave in the first sample, on canvas, will have the same issue mouseout has, since the "other element" aren't children of the canvas.
Stack snippet
updateInfo = function() {
document.getElementById('info').innerHTML =
'Position = ' + JSON.stringify(position) +
'<br />dragInfo = ' + JSON.stringify(dragInfo);
};
const canvas = document.getElementById('myMap-ish');
let position = { x: 0, y : 0 };
let dragInfo = null;
updateInfo();
canvas.addEventListener('mousedown', function(e) {
dragInfo = {
startEvent: {
x: e.clientX,
y: e.clientY,
},
startPosition: position
};
canvas.style.cursor = 'move';
document.querySelectorAll('.obj')[0].style.cursor = 'move'; // TODO for all objects
updateInfo();
});
canvas.addEventListener('mousemove', function(e) {
if (dragInfo === null) return;
position = {
x: dragInfo.startPosition.x - (e.clientX - dragInfo.startEvent.x),
y: dragInfo.startPosition.y - (e.clientY - dragInfo.startEvent.y)
};
updateInfo();
});
canvas.addEventListener('mouseup', function(e) {
dragInfo = null;
canvas.style.cursor = 'default';
document.querySelectorAll('.obj')[0].style.cursor = 'default'; // TODO for all objects
updateInfo();
});
canvas.addEventListener('mouseleave', function(e) {
dragInfo = null;
canvas.style.cursor = 'default';
document.querySelectorAll('.obj')[0].style.cursor = 'default'; // TODO for all objects
updateInfo();
});
* {
user-select: none;
font-family: monospace;
}
canvas {
background: black;
border: 1px solid red;
}
.obj {
position: absolute;
width: 50px;
height: 50px;
background: green;
color: white;
text-align: center;
line-height: 50px;
font-weight: bold;
}
<div id="myMap-ish">
<canvas width="500" height="300"></canvas>
<div class="obj" style="left: 30px; top: 35px">1</div>
<div class="obj" style="left: 175px; top: 79px">2</div>
<div class="obj" style="left: 214px; top: 145px">3</div>
<div class="obj" style="left: 314px; top: 215px">4</div>
</div>
<div id="info"></div>
I need to use JS no JQuery plugins to make a simple tooltip like on the image below.
Click on ? image should open this tooltip and click again on the same image to close it.
I think that it's simple for someone with good JS knowledge but I can't do it anyway :(
This is something that I have tried I know it's not too much but I am simply stuck.
How to display it like on the image, how to hide it when it's open and how to add that little triangle in the corner?
myfiddle
<img id="info" src="http://www.craiglotter.co.za/wp-content/uploads/2009/12/craig_question_mark_icon1.png"/>
<div id="ttip">bla bla</div>
document.getElementById('info').addEventListener('click', function(){
// how to check if it's visible so I can close tooltip
document.getElementById('ttip').style.display="block";
});
#info{margin-left:100px;margin-top:50px;}
#ttip
{
width: 280px;
z-index: 15001;
top: 0px;
left: 0px;
display: none;
border-color: #666;
background-color: #fff;
color: #666;
position: relative;
border: 1px solid #666;
padding: 15px 9px 5px 9px;
text-align: left;
word-wrap: break-word;
overflow: hidden;
}
Clean up the css and this will basically do it:
<script>
function doTip(e){
var elem = e.toElement;
if(elem.getAttribute('data-tip-on') === 'false') {
elem.setAttribute('data-tip-on', 'true');
var rect = elem.getBoundingClientRect();
var tipId = Math.random().toString(36).substring(7);
elem.setAttribute('data-tip-id', tipId);
var tip = document.createElement("div");
tip.setAttribute('id', tipId);
tip.innerHTML = elem.getAttribute('data-tip');
tip.style.top = rect.bottom+ 10 + 'px';
tip.style.left = (rect.left-200) + 'px';
tip.setAttribute('class','tip-box');
document.body.appendChild(tip);
} else {
elem.setAttribute('data-tip-on', 'false');
var tip = document.getElementById(elem.getAttribute('data-tip-id'));
tip.parentNode.removeChild(tip);
}
}
function enableTips(){
var elems = document.getElementsByClassName('quick-tip');
for(var i = 0; i < elems.length; i++) {
elems[0].addEventListener("click", doTip, false);
}
}
window.onload = function(){
enableTips();
}
</script>
<style>
.quick-tip {
background: black;
color: #fff;
padding: 5px;
cursor: pointer;
height: 15px;
width: 15px;
text-align: center;
font-weight: 900;
margin-left: 350px;
}
.tip-box {
/* change dimensions to be whatever the background image is */
height: 50px;
width: 200px;
background: grey;
border: 1px solid black;
position: absolute;
}
</style>
<div class="quick-tip" data-tip="THIS IS THE TIP! change elements 'data-tip' to change." data-tip-on="false">?</div>
<script>enableTips(); //might be required for jsfiddle, especially with reloads.</script>
Edit: fixed formatting and a bug. jsfiddle: http://jsfiddle.net/u93a3/
Proof of concept:
The following markup in HTML: Create a div with class tooltip, add image and a div with class info with all text (can be multiple paragraphs if needed, scollbars is shown if necessary):
<div class='tooltip'>
<img src='craig_question_mark_icon1.png' alt='Help'/>
<div class='info'>
Some text to fill the box with.
</div>
</div>
The div.info is set to display:none in CSS.
When the page is loaded a pure javascript is running that draws an image of a triangle on a canvas-element, and then creates a div-element where the triangle is set as a background. Then, for every div.tooltip:
add a click-eventhandler to the image
replace the div.info with a div.info_container
add a clone of the triangle-div to div.info_container
add the original div.info to div.info_container
You can test it with this fiddle. It is tested successfully on FF25, Chrome31, IE10, Opera 12&18.
<!doctype html>
<html>
<head>
<script>
"use strict";
function click(event) {
var elem = this.parentNode.querySelector('div.info_container');
if (elem) elem.style.display = elem.style.display === 'block' ? 'none' : 'block';
}
function toolify() {
var idx,
len,
elem,
info,
text,
elements = document.querySelectorAll('div.tooltip'),
canvas,
imgurl,
pointer,
tipHeight = 20,
tipWidth = 20,
width = 200,
height = 100,
ctx;
// Create a canvas element where the triangle will be drawn
canvas = document.createElement('canvas');
canvas.width = tipHeight;
canvas.height = tipWidth;
ctx = canvas.getContext('2d');
ctx.strokeStyle = '#000'; // Border color
ctx.fillStyle = '#fff'; // background color
ctx.lineWidth = 1;
ctx.translate(-0.5,-0.5); // Move half pixel to make sharp lines
ctx.beginPath();
ctx.moveTo(1,canvas.height); // lower left corner
ctx.lineTo(canvas.width, 1); // upper right corner
ctx.lineTo(canvas.width,canvas.height); // lower right corner
ctx.fill(); // fill the background
ctx.stroke(); // stroke it with border
//fix bottom row
ctx.fillRect(0,canvas.height-0.5,canvas.width-1,canvas.height+2);
// Create a div element where the triangel will be set as background
pointer = document.createElement('div');
pointer.style.width = canvas.width + 'px';
pointer.style.height = canvas.height + 'px';
pointer.innerHTML = ' ' // non breaking space
pointer.style.backgroundImage = 'url(' + canvas.toDataURL() + ')';
pointer.style.position = 'absolute';
pointer.style.top = '2px';
pointer.style.right = '1px';
pointer.style.zIndex = '1'; // place it over the other elements
for (idx=0, len=elements.length; idx < len; ++idx) {
elem = elements[idx];
elem.querySelector('img').addEventListener('click',click);
text = elem.querySelector('div.info');
// Create a new div element, and place the text and pointer in it
info = document.createElement('div');
text.parentNode.replaceChild(info,text);
info.className = 'info_container';
info.appendChild(pointer.cloneNode());
info.appendChild(text);
//info.addEventListener('click',click);
}
}
window.addEventListener('load',toolify);
</script>
<style>
div.tooltip
{
position:relative;
display:inline-block;
width:300px;
text-align:right;
}
div.tooltip > div.info
{
display:none;
}
div.tooltip div.info_container
{
position:absolute;
right:20px;
width:200px;
height:100px;
display:none;
}
div.tooltip div.info
{
text-align:left;
position:absolute;
left:1px;
right:1px;
top:20px;
bottom:1px;
color:#000;
padding:5px;
overflow:auto;
border:1px solid #000;
}
</style>
</head>
<body>
<div class='tooltip'>
<img src='craig_question_mark_icon1.png' alt='Help'/>
<div class='info'>
Some text to fill the box with.
</div>
</div>
<div class='tooltip'>
<img src='craig_question_mark_icon1.png' alt='Help'/>
<div class='info'>
Some text to fill the box with.
Some text to fill the box with.
Some text to fill the box with.
Some text to fill the box with.
</div>
</div>
</body>
</html>
My code is below. I also have it at http://jsfiddle.net/S2JHa/
I do not understand why cursor changes to I-beam when I click and drag the mouse over my picture.
If I remove "some text" then it does not change. This happens in Chrome. FF is fine.
Please if you can tell how to fix that I would appreciate it.
Thanks!
<div id="window">
<div>some text</div>
<div id="sketch" class="box">
<div class="contents">
<canvas id="image-layer"></canvas>
</div>
</div>
</div>
CSS:
#window #sketch
{
padding: 1cm 0;
}
#window #sketch canvas
{
left: 0;
position: absolute;
top: 0;
}
#window #sketch .contents
{
cursor: crosshair;
position: relative;
}
div.box
{
background-color: #fff;
border: 1px solid black;
border-radius: 0.3cm;
cursor: move;
left: 0;
position: fixed;
top: 0;
}
JavaScript:
function image_onload(e) {
var image = e.target;
$("div.box").draggable({
cancel: "div.box div.contents",
containment: "document"
});
var x = $("#window #sketch");
// size to fit image
x.css("width", image.width);
x.css("height", image.height);
// center sketch inside parent window
x.css("left", ($(window).width() - x.width()) / 2);
var canvas = document.getElementById("image-layer");
canvas.height = image.height;
canvas.width = image.width;
var context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
}
function open(url) {
var image = new Image();
image.src = url;
image.onload = image_onload;
}
open("http://upload.wikimedia.org/wikipedia/commons/6/63/Wikipedia-logo.png");
If you don't want interactivity with the canvas you can cancel the onmousedown event like so:
canvas.onmousedown = function () {
return false;
}
Fr IE you will need:
canvas.onselectstart = function () {
return false;
}
See updated jsfiddle here: http://jsfiddle.net/S2JHa/11/