Canvas blocks area hover - javascript

I imitated for tag area hover through js. But when place canvas ON image, hover gets blocked. But when I place it under the image, canvas content isn't visible.
I create the js function for the every area and when initializing the page, I place canvas on the image.
var hdc;
// shorthand func
function byId(e){return document.getElementById(e);}
// takes a string that contains coords eg - "227,307,261,309, 339,354, 328,371, 240,331"
// draws a line from each co-ord pair to the next - assumes starting point needs to be repeated as ending point.
function drawPoly(coOrdStr)
{
var mCoords = coOrdStr.split(',');
var i, n;
n = mCoords.length;
hdc.beginPath();
hdc.moveTo(mCoords[0], mCoords[1]);
for (i=2; i<n; i+=2)
{
hdc.lineTo(mCoords[i], mCoords[i+1]);
}
hdc.lineTo(mCoords[0], mCoords[1]);
hdc.stroke();
}
function drawRect(coOrdStr)
{
var mCoords = coOrdStr.split(',');
var top, left, bot, right;
left = mCoords[0];
top = mCoords[1];
right = mCoords[2];
bot = mCoords[3];
hdc.fillRect(left,top,right-left,bot-top);
}
function myHover(element)
{
var hoveredElement = element;
var coordStr = element.getAttribute('coords');
var areaType = element.getAttribute('shape');
switch (areaType)
{
case 'polygon':
case 'poly':
drawPoly(coordStr);
break;
case 'rect':
drawRect(coordStr);
break;
}
}
function myLeave()
{
var canvas = byId('myCanvas');
hdc.clearRect(0, 0, canvas.width, canvas.height);
}
function myInit()
{
// get the target image
var img = byId('main');
var x,y, w,h;
// get it's position and width+height
x = img.offsetLeft;
y = img.offsetTop;
w = img.clientWidth;
h = img.clientHeight;
//alert(x + " " + y + " " + w + " " + h);
// move the canvas, so it's contained by the same parent as the image
var imgParent = img.parentNode;
var can = byId('myCanvas');
imgParent.appendChild(can);
// place the canvas in front of the image
can.style.zIndex = -1;
// position it over the image
can.style.left = x+'px';
can.style.top = y+'px';
// make same size as the image
can.setAttribute('width', w+'px');
can.setAttribute('height', h+'px');
// get it's context
hdc = can.getContext('2d');
// set the 'default' values for the colour/width of fill/stroke operations
hdc.fillStyle = 'red';
hdc.strokeStyle = 'red';
hdc.lineWidth = 4;
}
#back_1 {
background-color: #cecece;
height: 720px;
margin: 0px auto;
text-align: center;
}
#main {
width: 700px;
high: 700px;
line-height: 0;
border: none;
}
#bolshevism {
height: 300px;
background-color: #b30106;
}
.text_1 {
width: 1320px;
padding-top: 70px;
margin: 0px auto;
text-align: left;
}
.head {
font: bold 40px Ubuntu-B;
}
.line {
width: 500px;
padding-top: 10px;
padding-bottom: 10px;
}
.descriprion{
font: 20px Ubuntu-B;
}
.text_2 {
width: 1320px;
padding-top: 70px;
margin: 0px auto;
text-align: right;
}
.authoritarian {
color: #ffffff;
}
#myCanvas {
position: absolute;
}
<body onload="myInit()">
<canvas id='myCanvas'></canvas>
<div id="back_1">
<img src="http://i.imgur.com/XQ5KueE.png" id="main" usemap="#map"ismap>
<div>
<map name="map">
<area href="#bolshevism_1" onmouseover='myHover(this);' onmouseout='myLeave();' shape="rect" coords="59,55,105,128" alt="Bolshevism">
</map>
</div>
</div>
<div id="bolshevism" class="authoritarian">
<div class="text_1">
<a id="bolshevism_1"><p class="head">BOLSHEVISM</p></a>
<p class="descriprion">Bolshevism is the term used to describe the beliefs and practices of the Bolsheviks, the members of a political movement in Russia during the early 20th century. Bolsheviks were a faction of the Marxist Russian Social Democratic Labour Party (RSDLP) which split apart from the Menshevik faction at the Second Party Congress in 1903. The RSDLP was a revolutionary socialist political party formed in 1898 in Minsk in Belarus to unite the various revolutionary organisations of the Russian Empire into one party.</p>
</div>
</div>
</body>

Just add pointer-events:none;
var hdc;
// shorthand func
function byId(e){return document.getElementById(e);}
// takes a string that contains coords eg - "227,307,261,309, 339,354, 328,371, 240,331"
// draws a line from each co-ord pair to the next - assumes starting point needs to be repeated as ending point.
function drawPoly(coOrdStr)
{
var mCoords = coOrdStr.split(',');
var i, n;
n = mCoords.length;
hdc.beginPath();
hdc.moveTo(mCoords[0], mCoords[1]);
for (i=2; i<n; i+=2)
{
hdc.lineTo(mCoords[i], mCoords[i+1]);
}
hdc.lineTo(mCoords[0], mCoords[1]);
hdc.stroke();
}
function drawRect(coOrdStr)
{
var mCoords = coOrdStr.split(',');
var top, left, bot, right;
left = mCoords[0];
top = mCoords[1];
right = mCoords[2];
bot = mCoords[3];
hdc.fillRect(left,top,right-left,bot-top);
}
function myHover(element)
{
var hoveredElement = element;
var coordStr = element.getAttribute('coords');
var areaType = element.getAttribute('shape');
switch (areaType)
{
case 'polygon':
case 'poly':
drawPoly(coordStr);
break;
case 'rect':
drawRect(coordStr);
break;
}
}
function myLeave()
{
var canvas = byId('myCanvas');
hdc.clearRect(0, 0, canvas.width, canvas.height);
}
function myInit()
{
// get the target image
var img = byId('main');
var x,y, w,h;
// get it's position and width+height
x = img.offsetLeft;
y = img.offsetTop;
w = img.clientWidth;
h = img.clientHeight;
//alert(x + " " + y + " " + w + " " + h);
// move the canvas, so it's contained by the same parent as the image
var imgParent = img.parentNode;
var can = byId('myCanvas');
imgParent.appendChild(can);
// place the canvas in front of the image
can.style.zIndex = -1;
// position it over the image
can.style.left = x+'px';
can.style.top = y+'px';
// make same size as the image
can.setAttribute('width', w+'px');
can.setAttribute('height', h+'px');
// get it's context
hdc = can.getContext('2d');
// set the 'default' values for the colour/width of fill/stroke operations
hdc.fillStyle = 'red';
hdc.strokeStyle = 'red';
hdc.lineWidth = 4;
}
#back_1 {
background-color: #cecece;
height: 720px;
margin: 0px auto;
text-align: center;
}
#main {
width: 700px;
high: 700px;
line-height: 0;
border: none;
}
#bolshevism {
height: 300px;
background-color: #b30106;
}
.text_1 {
width: 1320px;
padding-top: 70px;
margin: 0px auto;
text-align: left;
}
.head {
font: bold 40px Ubuntu-B;
}
.line {
width: 500px;
padding-top: 10px;
padding-bottom: 10px;
}
.descriprion{
font: 20px Ubuntu-B;
}
.text_2 {
width: 1320px;
padding-top: 70px;
margin: 0px auto;
text-align: right;
}
.authoritarian {
color: #ffffff;
}
#myCanvas {
position:absolute;
pointer-events:none;
}
<body onload="myInit()">
<canvas id='myCanvas'></canvas>
<div id="back_1">
<img src="http://i.imgur.com/XQ5KueE.png" id="main" usemap="#map"ismap>
<div>
<map name="map">
<area href="#bolshevism_1" onmouseover='myHover(this);' onmouseout='myLeave();' shape="rect" coords="59,55,105,128" alt="Bolshevism">
</map>
</div>
</div>
<div id="bolshevism" class="authoritarian">
<div class="text_1">
<a id="bolshevism_1"><p class="head">BOLSHEVISM</p></a>
<p class="descriprion">Bolshevism is the term used to describe the beliefs and practices of the Bolsheviks, the members of a political movement in Russia during the early 20th century. Bolsheviks were a faction of the Marxist Russian Social Democratic Labour Party (RSDLP) which split apart from the Menshevik faction at the Second Party Congress in 1903. The RSDLP was a revolutionary socialist political party formed in 1898 in Minsk in Belarus to unite the various revolutionary organisations of the Russian Empire into one party.</p>
</div>
</div>
</body>

Related

Adjacent div's children needs to be level vertically

There are 3 Vertical divs, as shown in the picture. There are some child divs inside each div that are shown by blue rectangles. I need the children divs to be level vertically. How can I do it?
As they said, in pure css/html is not possible if they are in separated containers.
Using javascript you can first create the 'base' element (in this case, the inner divs of the center column), save its coord and then create the side ones and pos them with the saved coords.
This is a rough example, but can give the idea
for (let i = 1; i < 10; i++) {
//Create the center column element first, from where to get the Y pos
let elem2 = document.createElement('div');
elem2.style.width = 'calc(100% - 10px)';
elem2.style.height = '50px';
elem2.style.margin = '5px';
elem2.style.background = 'lightblue';
document.querySelector('.col2').append(elem2);
let coords = elem2.getBoundingClientRect(); //Getting coords data
//creating first column elem
let elem1 = document.createElement('div');
elem1.style.position = 'absolute';
elem1.style.top = coords.top + 'px'; //use de y pos from above
elem1.style.width = 'calc(100% - 10px)';
elem1.style.height = '25px';
elem1.style.margin = '0 5px';
elem1.style.background = 'pink';
document.querySelector('.col1').append(elem1);
//creating third column elem
let elem3 = document.createElement('div');
elem3.style.position = 'absolute';
elem3.style.top = coords.top + 'px'; //use de y pos from above
elem3.style.width = 'calc(100% - 10px)';
elem3.style.height = '25px';
elem3.style.margin = '0 5px';
elem3.style.background = 'lightgreen';
document.querySelector('.col3').append(elem3);
}
body,
html {
margin: 0;
padding: 0;
background: lightyellow
}
.container {
display: flex;
}
.col1 {
position: relative;
width: 75px;
border: 2px solid red
}
.col2 {
position: relative;
flex-grow: 1;
border: 2px solid blue
}
.col3 {
position: relative;
width: 150px;
border: 2px solid green
}
<div class="container">
<div class="col1">
</div>
<div class="col2">
</div>
<div class="col3">
</div>
</div>

Div with sprite-animation doesn't change properly during window.resize event

I am trying to imitate 3d-model rotation with a sprite sheet. I found a perfect example on Codepen, but it was not responsive.
What I tried to do is to write divs, containers and spritesize (in script) in vw, and then it is being checked in the window.resize event. It does work, but unfortunately not DURING window resize.
I put my snippet and three pictures in the post —
I opened website and everything is perfect - image
I started to change the size of my browser window and as you can see something is wrong - image
Now I tried to "rotate" the "model" with resized window and all is fine again - image
var spriteslider = document.createElement('div');
var clientWidth = document.getElementById('spritetarget').clientWidth;
document.body.appendChild(spriteslider);
spriteslider.slider = document.getElementById('spriteslider');
spriteslider.sprite = document.getElementById('spritetarget');
spriteslider.spritesize = clientWidth;
spriteslider.spritecount = 20;
spriteslider.pixelsperincrement = 5;
spriteslider.multiplier = spriteslider.lastmultiplier = 0;
Draggable.create(spriteslider, {
type: 'x',
trigger: spriteslider.slider,
bounds: {
minX: 0,
maxX: 0,
minY: 0,
maxY: 0
},
edgeResistance: 0,
cursor: 'e-resize',
onDrag: function() {
if (this.isDragging) {
var t = this.target;
t.multiplier = Math.floor(this.x / t.pixelsperincrement) + t.lastmultiplier;
// TweenLite.set(t.sprite, { backgroundPosition: (-t.multiplier * t.spritesize) + "px 0"});
TweenLite.set(t.sprite, {
backgroundPosition: (-t.multiplier * t.spritesize) + "px 0"
});
}
},
onDragEnd: function() {
var t = this.target;
t.lastmultiplier = t.multiplier % t.spritecount;
}
});
window.addEventListener('resize', function(event) {
var clientWidth = document.getElementById('spritetarget').clientWidth;
spriteslider.spritesize = clientWidth;
TweenLite.set(t.sprite, {
backgroundPosition: (-t.multiplier * t.spritesize) + "px 0"
});
}, true);
body {
text-align: center;
font: normal 12px sans-serif;
background: #000000;
color: #91E600;
}
.spriteslider {
margin: 20px auto;
padding: 60px;
width: 20vw;
height: 20vw;
background: #FCFEFC;
border-radius: 5px;
}
#spritetarget {
width: 20vw;
height: 20vw;
background-size: cover;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/29123/heart.png);
/* horizontal spritesheet - image from http://preloaders.net */
background-repeat: repeat-x;
}
<div class='spriteslider' id='spriteslider'>
<div id='spritetarget'></div>
</div>
<p>Drag the box left/right to control the sprite's position.</p>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/utils/Draggable.min.js'></script>
The issue is because you're referencing t in the window.resize event handler, yet that variable has been defined in a different scope, and is not accessible from that location.
To fix this issue you can replace t in that function with the spriteslider variable, as that's what t is expected to contain. Try this:
var spriteslider = document.createElement('div');
var clientWidth = document.getElementById('spritetarget').clientWidth;
document.body.appendChild(spriteslider);
spriteslider.slider = document.getElementById('spriteslider');
spriteslider.sprite = document.getElementById('spritetarget');
spriteslider.spritesize = clientWidth;
spriteslider.spritecount = 20;
spriteslider.pixelsperincrement = 5;
spriteslider.multiplier = spriteslider.lastmultiplier = 0;
Draggable.create(spriteslider, {
type: 'x',
trigger: spriteslider.slider,
bounds: {
minX: 0,
maxX: 0,
minY: 0,
maxY: 0
},
edgeResistance: 0,
cursor: 'e-resize',
onDrag: function() {
if (this.isDragging) {
var t = this.target;
t.multiplier = Math.floor(this.x / t.pixelsperincrement) + t.lastmultiplier;
TweenLite.set(t.sprite, {
backgroundPosition: (-t.multiplier * t.spritesize) + "px 0"
});
}
},
onDragEnd: function() {
var t = this.target;
t.lastmultiplier = t.multiplier % t.spritecount;
}
});
window.addEventListener('resize', function(event) {
var clientWidth = document.getElementById('spritetarget').clientWidth;
spriteslider.spritesize = clientWidth;
TweenLite.set(spriteslider.sprite, {
backgroundPosition: (-spriteslider.multiplier * spriteslider.spritesize) + "px 0"
});
}, true);
body {
text-align: center;
font: normal 12px sans-serif;
background: #000000;
color: #91E600;
}
.spriteslider {
margin: 20px auto;
padding: 60px;
width: 20vw;
height: 20vw;
background: #FCFEFC;
border-radius: 5px;
}
#spritetarget {
width: 20vw;
height: 20vw;
background-size: cover;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/29123/heart.png);
/* horizontal spritesheet - image from http://preloaders.net */
background-repeat: repeat-x;
}
<div class='spriteslider' id='spriteslider'>
<div id='spritetarget'></div>
</div>
<p>Drag the box left/right to control the sprite's position.</p>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/utils/Draggable.min.js'></script>

jQuery hover is too slow

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>

How to simulate rays emerging from an image/div to another image/div using HTML and CSS

I want to build a page to show a blown-up version of an image.
I have the smaller image and the bigger image built out. I am not sure how to build the in between portion that looks like rays coming out of the smaller image.
HTML
<div class="flex">
<div class="exp" tabindex="0">
<img class="image" src="http://via.placeholder.com/50x50">
</div>
<div class="big-image">
<img class="image" src="http://via.placeholder.com/350x550">
</div>
</div>
CSS
.exp {
margin: 5px;
width: 100px;
height: 100px;
background-color: #ded3c0;
border-radius: 100%;
line-height: 80px;
align-items: center;
display: flex;
justify-content: center;
}
.exp .image {
width: 50px;
height: 50px;
}
.big-image {
border: 1px solid #000;
padding: 20px;
border-radius: 19px;
}
.flex {
display: flex;
align-items: center;
justify-content: space-around;
}
Any pointers on how to do this is helpful.
Here is jsfiddle https://jsfiddle.net/npkeq7ut/
If you need only lines you can achieve this with JS and skew transform:
let topLine = document.getElementById('top-line');
let bottomLine = document.getElementById('bottom-line');
function updateLines()
{
let b = document.getElementById('b').getBoundingClientRect();
let a = document.getElementById('a').getBoundingClientRect();
let left = a.right;
let width = b.left - a.right;
let tHeight = a.top - b.top;
let tTop = tHeight / 2 + b.top;
let tAngle = Math.atan(tHeight / width) * 180 / Math.PI;
let bHeight = b.bottom - a.bottom;
let bTop = bHeight / 2 + a.bottom - bottomLine.offsetHeight;
let bAngle = Math.atan(bHeight / width) * 180 / Math.PI;
topLine.style.top = tTop + "px";
topLine.style.left = left + "px";
topLine.style.width = width + "px";
topLine.style.transform = "skewY("+(-tAngle)+"deg)";
bottomLine.style.top = bTop + "px";
bottomLine.style.left = left + "px";
bottomLine.style.width = width + "px";
bottomLine.style.transform = "skewY("+(bAngle)+"deg)";
}
updateLines();
Fiddle: https://jsfiddle.net/JacobDesight/f40yeuqe/2/
#EDIT
If you want trapeze with background then here is example using canvas: https://jsfiddle.net/JacobDesight/f40yeuqe/3/
This could be a starting point for you.
Code by thecodeplayer.
http://thecodeplayer.com/walkthrough/magnifying-glass-for-images-using-jquery-and-css3
$(document).ready(function() {
var native_width = 0;
var native_height = 0;
//Now the mousemove function
$(".magnify").mousemove(function(e) {
//When the user hovers on the image, the script will first calculate
//the native dimensions if they don't exist. Only after the native dimensions
//are available, the script will show the zoomed version.
if (!native_width && !native_height) {
//This will create a new image object with the same image as that in .small
//We cannot directly get the dimensions from .small because of the
//width specified to 200px in the html. To get the actual dimensions we have
//created this image object.
var image_object = new Image();
image_object.src = $(".small").attr("src");
//This code is wrapped in the .load function which is important.
//width and height of the object would return 0 if accessed before
//the image gets loaded.
native_width = image_object.width;
native_height = image_object.height;
} else {
//x/y coordinates of the mouse
//This is the position of .magnify with respect to the document.
var magnify_offset = $(this).offset();
//We will deduct the positions of .magnify from the mouse positions with
//respect to the document to get the mouse positions with respect to the
//container(.magnify)
var mx = e.pageX - magnify_offset.left;
var my = e.pageY - magnify_offset.top;
//Finally the code to fade out the glass if the mouse is outside the container
if (mx < $(this).width() && my < $(this).height() && mx > 0 && my > 0) {
$(".large").fadeIn(100);
} else {
$(".large").fadeOut(100);
}
if ($(".large").is(":visible")) {
//The background position of .large will be changed according to the position
//of the mouse over the .small image. So we will get the ratio of the pixel
//under the mouse pointer with respect to the image and use that to position the
//large image inside the magnifying glass
var rx = Math.round(mx / $(".small").width() * native_width - $(".large").width() / 2) * -1;
var ry = Math.round(my / $(".small").height() * native_height - $(".large").height() / 2) * -1;
var bgp = rx + "px " + ry + "px";
//Time to move the magnifying glass with the mouse
var px = mx - $(".large").width() / 2;
var py = my - $(".large").height() / 2;
//Now the glass moves with the mouse
//The logic is to deduct half of the glass's width and height from the
//mouse coordinates to place it with its center at the mouse coordinates
//If you hover on the image now, you should see the magnifying glass in action
$(".large").css({
left: px,
top: py,
backgroundPosition: bgp
});
}
}
})
})
/*Some CSS*/
* {
margin: 0;
padding: 0;
}
.magnify {
width: 200px;
margin: 50px auto;
position: relative;
}
/*Lets create the magnifying glass*/
.large {
width: 175px;
height: 175px;
position: absolute;
border-radius: 100%;
/*Multiple box shadows to achieve the glass effect*/
box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25);
/*Lets load up the large image first*/
background: url('http://thecodeplayer.com/uploads/media/iphone.jpg') no-repeat;
/*hide the glass by default*/
display: none;
}
/*To solve overlap bug at the edges during magnification*/
.small {
display: block;
}
<!-- Lets make a simple image magnifier -->
<div class="magnify">
<!-- This is the magnifying glass which will contain the original/large version -->
<div class="large"></div>
<!-- This is the small image -->
<img class="small" src="http://thecodeplayer.com/uploads/media/iphone.jpg" width="200"/>
</div>
<!-- Lets load up prefixfree to handle CSS3 vendor prefixes -->
<script src="http://thecodeplayer.com/uploads/js/prefixfree.js" type="text/javascript"></script>
<!-- You can download it from http://leaverou.github.com/prefixfree/ -->
<!-- Time for jquery action -->
<script src="http://thecodeplayer.com/uploads/js/jquery-1.7.1.min.js" type="text/javascript"></script>

How to make this tooltip like this with pure javascript

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>

Categories