I am using a JS code which originally was written for individual PNG images, but I am converting to using a Sprite Image.
The code originally pulled an image for one part of the code and shrank when the thumbnail was called. What would be the best way to make the same affect now that it's calling a Sprite Class?
//<![CDATA[
var awards2 = {
start : function(){
if(location.href.match(/\/topic\/\d+\/?/)){
for(var a=0;a<t_award2.users.length;a++){
awards2.present(a);
}
}
},
present : function(a){
var award2 = t_award2.users[a];
if($("."+award2[0]+"-awards2").size() == 0){
$("a.member[href="+main_url+"profile/"+award2[0]+"/]").parent().parent().next().find("dl.user_info dd.spacer").before('<dt>'+t_award2.name+':</dt><dd class="'+award2[0]+'-awards2"><div onmouseover="awards2.tooltip.open(event,'+a+');" onmouseout="awards2.tooltip.bye('+a+');" id="'+a+'-award2" class="'+award2[2]+'" alt="'+award2[1]+'" width="'+t_award2.thumbnail[0]+'px" height="'+t_award2.thumbnail[1]+'px" /></dd>');
} else {
$("."+award2[0]+"-awards2").append('<div onmouseover="awards2.tooltip.open(event,'+a+');" onmouseout="awards2.tooltip.bye('+a+');" id="'+a+'-award2" class="'+award2[2]+'" alt="'+award2[1]+'" width="'+t_award2.thumbnail[0]+'px" height="'+t_award2.thumbnail[1]+'px" />');
}
},
tooltip : {
current : 0,
open : function(event,a){
var award2 = t_award2.users[a];
var pos = awards2.mouse.locate(event);
awards2.tooltip.coords = [pos[0],pos[1]];
if($("#"+a+"-tooltip").size() == 0)$("body").append('<div id="'+a+'-tooltip" style="position:absolute;max-width:500px;"><table><thead><tr><th colspan="2">'+award2[1]+'</th></tr></thead><tbody><tr><td><div class="'+award2[2]+'" alt="'+award2[1]+'" /></td><td>'+award2[3]+'<hr /><strong>Received:</strong> '+award2[4]+'</td></tr></tbody></table></div>');
var elem = document.getElementById(a+"-tooltip");
elem.style.left = pos[0]+10+"px";
elem.style.top = pos[1]+10+"px";
awards2.tooltip.current = a;
document.onmousemove = awards2.tooltip.update;
},
update : function(event){
var pos = awards2.mouse.locate(event);
var elem = document.getElementById(awards2.tooltip.current+"-tooltip");
if(elem !== null){
elem.style.left = pos[0]+10+"px";
elem.style.top = pos[1]+10+"px";
} else {
document.onmousemove = null;
}
},
bye : function(a){
switch(t_award2.closeFunction){
case "slide":$("#"+a+"-tooltip").slideToggle("fast",function(){$(this).remove();});break;
case "fade": $("#"+a+"-tooltip").fadeOut("fast",function(){$(this).remove();});break;
default: $("#"+a+"-tooltip").remove();break;
}
}
},
mouse : {
locate : function(event){
e = event || window.event;
coords = [0,0]
if (e.pageX || e.pageY) {
coords = [e.pageX,e.pageY];
}
else {
var de = document.documentElement;
var b = document.body;
coords = [e.clientX + (de.scrollLeft || b.scrollLeft) - (de.clientLeft || 0),e.clientY + (de.scrollTop || b.scrollTop) - (de.clientTop || 0)];
}
return coords;
}
}
}
awards2.start();
//]]>
.exampleclass
{ display: inline-block; background: url(‘sprite.png') no-repeat; overflow: hidden; text-indent: -9999px; text-align: left; }
.exampleclass { background-position: -2px -3491px; width: 50px; height: 50px; }
<script type="text/javascript">
//<![CDATA[
var t_award2 = {
name : “Award”,
thumbnail : [20,20],
closeFunction : "fade",
users : [
[user ID,”Name”,”exampleclass”,”Message”,”Date”],
[user ID,”Name”,”exampleclass”,”Message”,”Date”]
]
}
//]]>
</script>
I read somewhere I'd need something like background-size but I know nothing about how to implement that. Currently when this code runs, the thumbnail loads as the regular size which is too big.
Thanks in advance :)
A couple of weeks ago I looked into creating responsive sprites as well and, while there is a lot of good information out there, none of it ended up working for what I wanted. Here are two of the best examples in my opinion, though both aren't without their drawbacks.
The second link talks about background size but it ends up being tricky depending on whether or not your sprites are all the same size.
http://tobyj.net/responsive-sprites/
http://blog.brianjohnsondesign.com/responsive-background-image-sprites-css-tutorial/
Related
OK so I've tried one thing from a different question and it worked, but not the way I wanted it to. it didn't work the way I wanted it to! You literally had to click when two objects were touching so it would alert you, if somebody can figure out a way to detect if two elements are touching without having to click that would be a life saver! So I hope you people who read this request please respond if you know how. this is the code below. so one object is moving and i want it to make it stop when the object hits the player (i am making a game) the movement is by px.... i want it to keep testing if one object hits the player, and if it does i want it to stop everything.
var boxes = document.querySelectorAll('.box');
boxes.forEach(function (el) {
if (el.addEventListener) {
el.addEventListener('click', clickHandler);
} else {
el.attachEvent('onclick', clickHandler);
}
})
var detectOverlap = (function () {
function getPositions(elem) {
var pos = elem.getBoundingClientRect();
return [[pos.left, pos.right], [pos.top, pos.bottom]];
}
function comparePositions(p1, p2) {
var r1, r2;
if (p1[0] < p2[0]) {
r1 = p1;
r2 = p2;
} else {
r1 = p2;
r2 = p1;
}
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function (a, b) {
var pos1 = getPositions(a),
pos2 = getPositions(b);
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
};
})();
function clickHandler(e) {
var elem = e.target,
elems = document.querySelectorAll('.box'),
elemList = Array.prototype.slice.call(elems),
within = elemList.indexOf(elem),
touching = [];
if (within !== -1) {
elemList.splice(within, 1);
}
for (var i = 0; i < elemList.length; i++) {
if (detectOverlap(elem, elemList[i])) {
touching.push(elemList[i].id);
}
}
if (touching.length) {
console.log(elem.id + ' touches ' + touching.join(' and ') + '.');
alert(elem.id + ' touches ' + touching.join(' and ') + '.');
} else {
console.log(elem.id + ' touches nothing.');
alert(elem.id + ' touches nothing.');
}
}
this is my video game right now (please do not copy)
<!DOCTYPE html>
/
<html>
<form id="player" class="box">
</form>
<button type="button" class="up" onclick="moveup()">^</button>
<button type="button" class="down" onclick="movedown()">v
</button>
<style src="style.css">
#player {
width: 300px;
height: 100px;
background-color: blue;
display: inline-block;
position: relative;
bottom: -250px;
left: 200px;
}
.up {
position: relative;
bottom: -400px;
}
.down {
position: relative;
bottom: -420px;
}
body {
background-color: black;
}
#car {
width: 300px;
height: 100px;
background-color: red;
display: inline-block;
position: relative;
bottom: -250px;
left: 600px;
}
</style>
<form id="car" class="box"></form>
<script>
imgObj = document.getElementById('player');
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
function moveup() {
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
imgObj.style.bottom = parseInt(imgObj.style.bottom) + 70 + 'px';
}
function movedown() {
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
imgObj.style.bottom = parseInt(imgObj.style.bottom) + -120 + 'px';
}
myMove();
function myMove() {
var elem = document.getElementById("car");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 1000) {
clearInterval(id);
myMove();
} else {
pos++;
elem.style.left = pos + "px";
elem.style.left = pos + "px";
}
}
}
/* please do not copy; this is it so far i want the red box when it hits the player(blue box) to stop everything that is happening */
/* made by Jsscripter; car game */
</script>
</html>
Intersection observer. API was largely developed because of news feeds and infinite scrolling. Goal was to solve when something comes into view, load content. Also is a great fit for a game.
The Intersection Observer API lets code register a callback function
that is executed whenever an element they wish to monitor enters or
exits another element (or the viewport), or when the amount by which
the two intersect changes by a requested amount. This way, sites no
longer need to do anything on the main thread to watch for this kind
of element intersection, and the browser is free to optimize the
management of intersections as it sees fit.
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
All major browsers except safari support the API. For backwards compatibility and Safari support can use the polyfill from W3C found here. Check out this example from MDN:
var callback = function(entries, observer) {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// target element:
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
});
};
var options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0
}
var observer = new IntersectionObserver(callback, options);
var target = document.querySelector('#listItem');
observer.observe(target);
See this in action here: https://codepen.io/anon/pen/OqpeMV
I am working on a project where I have a slideshow with images as follows:
img {
width:100vw;
height:100vh;
object-fit:cover;
}
This makes the images fullscreen and behave like background-size:cover, so they fill out the whole viewport on any screen size without distortion.
I would like to tag certain points with text tooltips on these images. For this purpose I have found Tim Severien's Taggd, which works great on responsive images, but in my case the object-fit:cover; property makes the tagged positions inaccurate.
I have tried everything from CSS hacks to improving Tim's code, but I am out of ideas. If you have any solution or workaround in mind please share.
Thank you!
well i actually wanted to do the same thing.
here is what i've done.
maybe it will help someone in the future.
it would be great if this feature could be integrated in taggd.
function buildTags()
{
// be aware that image.clientWidth and image.clientHeight are available when image is loaded
var croppedWidth = false;
var expectedWidth = 0;
var croppedWidthHalf = 0;
var imageWidth = 0;
var croppedHeight = false;
var expectedHeight = 0;
var croppedHeightHalf = 0;
var imageHeight = 0;
var naturalRatio = image.naturalWidth/image.naturalHeight;
var coverRatio = image.clientWidth/image.clientHeight;
if(Math.abs(naturalRatio - coverRatio) < 0.01)
{
// the image is not cropped, nothing to do
}
else
{
if(naturalRatio > coverRatio)
{
// width is cropped
croppedWidth = true;
expectedWidth = image.clientHeight * naturalRatio;
croppedWidthHalf = (expectedWidth - image.clientWidth)/2;
imageWidth = image.clientWidth;
}
else
{
// height is cropped
croppedHeight = true;
expectedHeight = image.clientWidth / naturalRatio;
croppedHeightHalf = (expectedHeight - image.clientHeight)/2;
imageHeight = image.clientHeight;
}
}
function calcy(y)
{
if(croppedHeight)
{
var positiony = y * expectedHeight;
if(positiony > croppedHeightHalf)
return (positiony - croppedHeightHalf)/imageHeight;
else // tag is outside the picture because cropped
return 0; // TODO : handle that case nicely
}
else
return y;
}
function calcx(x)
{
if(croppedWidth)
{
var positionx = x * expectedWidth;
if(positionx > croppedWidthHalf)
return (positionx - croppedWidthHalf)/imageWidth;
else // tag is outside the picture because cropped
return 0; // TODO : handle that case nicely
}
else
return x;
}
var tags = [
Taggd.Tag.createFromObject({
position: { x: calcx(0.74), y: calcy(0.56) },
text: 'some tag',
}),
Taggd.Tag.createFromObject({
position: { x: calcx(0.9), y: calcy(0.29) },
text: 'some other tag',
}),
....
];
var taggd = new Taggd(image, options, tags);
}
$(window).bind("load", function() {buildTags();});
Is not possible. Think if the user has a tablet with 1024x768 resolution, when the user change view from horizontal to vertical the image can fill the space but you will loose part of the image, loose img quality, etc.
The best way for cross devices is to use big pictures and add in css
img {
height: auto;
width: 100%;
display: block;
}
And fill image background with a color;
For some reason, the lines I'm trying to draw aren't appearing. The output from the console.log statement are as follow:
(39,259) (0,375)
(39,-157) (0,-249)
(39,-233) (0,1458)
(0,-157) (39,718)
(0,1198) (39,1337)
(39,-84) (0,164)
(39,-140) (0,496)
(39,-157) (0,-249)
(39,-11) (0,378)
(39,-157) (0,378)
(39,-233) (0,1300)
By logging the ctxt, I have confirmed that is not an issue. The styling for the canvases are as follows:
width: 35px;
height:1879px;
left: 415px;
position: absolute;
margin-top: 4.4%;
I've done a test with drawing a rectangle and that seemed to work.
for (var a = 0; a < arrows.length; a++) {
var ctxt,
ctxtX = 0,
tgtX = 0;
tgtGroup = groups[arrows[a].getAttribute('data-gID') - 1],
categoryTxt = tgtGroup.parentNode.firstChild.innerHTML,
arrowCatTxt = arrows[a].parentNode.parentNode.firstChild.innerHTML;
if(categoryTxt == 'Engineering' && arrowCatTxt == 'Administration') {
ctxt = canvases[0].getContext("2d");
tgtX = canvases[0].offsetWidth;
} else if(categoryTxt == 'Engineering' && arrowCatTxt == 'Fabrication') {
ctxt = canvases[1].getContext("2d");
tgtX = canvases[0].offsetWidth;
} else if(categoryTxt == 'Administration' && arrowCatTxt == 'Engineering') {
ctxt = canvases[0].getContext("2d");
ctxtX = canvases[0].offsetWidth;
} else {
ctxt = canvases[1].getContext("2d");
ctxtX = canvases[1].offsetWidth;
}
console.log('('+ctxtX +','+ (arrows[a].offsetTop - canvases[0].offsetTop) + ') (' + tgtX + ',' + (tgtGroup.offsetTop - canvases[0].offsetTop) + ')');
ctxt.beginPath();
ctxt.strokeStyle = "#000";
ctxt.lineWidth = 10;
ctxt.moveTo(ctxtX, Math.abs(arrows[a].offsetTop - canvases[0].offsetTop));
ctxt.lineTo(tgtX, Math.abs(tgtGroup.offsetTop - canvases[0].offsetTop));
ctxt.stroke();
}
Thank you for your help!
The canvas element requires width and height attributes directly, not only in the css: <canvas id="thing" width="200px" height="200px">No support.</canvas>
Your canvas is a bit small, make it a lot bigger and try again.
Also try removing your code, and draw just a single diagonal line from {10,10} to {width-10, height-10} and make sure that works first.
If you have multiple canvases, make sure the id's are different and that you're using different variables for the contexts. Also, inspect the elements and make sure they're not overlapping.
Good luck!
I want to use the 'mouse's drag' to drag a background's position around, inside a box.
The CSS:
.filmmakers #map {
width : 920px;
height : 500px;
margin-top : 50px;
margin-left : 38px;
border : 1px solid rgb(0, 0, 0);
cursor : move;
overflow : hidden;
background-image : url('WorldMap.png');
background-repeat : no-repeat;
}
The html:
<div id = "map" src = "WorldMap.png" onmousedown = "MouseMove(this)"> </div>
The Javascript:
function MouseMove (e) {
var x = e.clientX;
var y = e.clientY;
e.style.backgroundPositionX = x + 'px';
e.style.backgroundPositionY = y + 'px';
e.style.cursor = "move";
}
Nothing happens, no errors, no warnings, nothing... I have tried lots of things: an absolutely positioned image inside a div (you can guess why that didn't work), A draggable div inside a div with a background image, a table with drag and drop, and finally I tried this:
function MouseMove () {
e.style.backgroundPositionX = 10 + 'px';
e.style.backgroundPositionY = 10 + 'px';
e.style.cursor = "move";
}
This works, but its not relative to the mouse's position, pageX and pageY don't work either.
A live demo: http://jsfiddle.net/VRvUB/224/
P.S: whatever your idea is, please don't write it in JQuery
From your question I understood you needed help implementing the actual "dragging" behavior. I guess not. Anyway, here's the results of my efforts: http://jsfiddle.net/joplomacedo/VRvUB/236/
The drag only happens when the mouse button, and.. well, it behaves as I think you might want it to. Just see the fiddle if you haven't =)
Here's the code for those who want to see it here:
var AttachDragTo = (function () {
var _AttachDragTo = function (el) {
this.el = el;
this.mouse_is_down = false;
this.init();
};
_AttachDragTo.prototype = {
onMousemove: function (e) {
if ( !this.mouse_is_down ) return;
var tg = e.target,
x = e.clientX,
y = e.clientY;
tg.style.backgroundPositionX = x - this.origin_x + this.origin_bg_pos_x + 'px';
tg.style.backgroundPositionY = y - this.origin_y + this.origin_bg_pos_y + 'px';
},
onMousedown: function(e) {
this.mouse_is_down = true;
this.origin_x = e.clientX;
this.origin_y = e.clientY;
},
onMouseup: function(e) {
var tg = e.target,
styles = getComputedStyle(tg);
this.mouse_is_down = false;
this.origin_bg_pos_x = parseInt(styles.getPropertyValue('background-position-x'), 10);
this.origin_bg_pos_y = parseInt(styles.getPropertyValue('background-position-y'), 10);
},
init: function () {
var styles = getComputedStyle(this.el);
this.origin_bg_pos_x = parseInt(styles.getPropertyValue('background-position-x'), 10);
this.origin_bg_pos_y = parseInt(styles.getPropertyValue('background-position-y'), 10);
//attach events
this.el.addEventListener('mousedown', this.onMousedown.bind(this), false);
this.el.addEventListener('mouseup', this.onMouseup.bind(this), false);
this.el.addEventListener('mousemove', this.onMousemove.bind(this), false);
}
};
return function ( el ) {
new _AttachDragTo(el);
};
})();
/*** IMPLEMENTATION ***/
//1. Get your element.
var map = document.getElementById('map');
//2. Attach the drag.
AttachDragTo(map);
This isn't working because you are passing the element "map" to your MouseMove function, and using it as both an event object and an element. You can fix this painlessly by using JavaScript to assign your event handler rather than HTML attributes:
<div id="map"></div>
And in your JavaScript:
document.getElementById('map').onmousemove = function (e) {
// the first parameter (e) is automatically assigned an event object
var x = e.clientX;
var y = e.clientY;
// The context of this is the "map" element
this.style.backgroundPositionX = x + 'px';
this.style.backgroundPositionY = y + 'px';
}
http://jsfiddle.net/VRvUB/229/
The downside of this approach is that the backgroundPositionX and backgroundPositionY style properties are not supported in all browsers.
You mention "an absolutely positioned image inside a div" which is probably the more compatible solution for this. To make this setup work, you need to set the position of the outer element to relative, which makes absolute child elements use its bounds as zero.
<div id="map">
<img src="" alt="">
</div>
CSS:
#map {
position:relative;
overflow:hidden;
}
#map img {
position:absolute;
left:0;
top:0;
}
Here it is applied to your code: http://jsfiddle.net/VRvUB/232/
This works 100%
Vanilla Javascript
document.getElementById('image').onmousemove = function (e) {
var x = e.clientX;
var y = e.clientY;
this.style.backgroundPositionX = -x + 'px';
this.style.backgroundPositionY = -y + 'px';
this.style.backgroundImage = 'url(https://i.ibb.co/vhL5kH2/image-14.png)';
}
document.getElementById('image').onmouseleave = function (e) {
this.style.backgroundPositionX = 0 + 'px';
this.style.backgroundPositionY = 0 + 'px';
this.style.backgroundImage = 'url(https://i.ibb.co/Ph9MCB2/template.png)';
}
.container {
max-width: 670px;
height: 377px;
}
#image {
max-width: 670px;
height: 377px;
cursor: crosshair;
overflow: hidden;
background-image: url('https://i.ibb.co/Ph9MCB2/template.png');
background-repeat: no-repeat;
}
<div class="container">
<div id="image">
</div>
</div>
I have an HTML file with this:
<div id="container"></div>
and I have a stylesheet with a CSS3 animation defined:
.image {
position: absolute;
-webkit-animation-name: image-create;
-webkit-animation-duration: 1s;
}
#-webkit-keyframes image-create {
from {
width: 0px;
height: 0px;
}
to {
width: 500px;
height: 500px;
}
}
This should make an image grow from 0x0 to 500x500.
In my Javascript file I have the following:
var findAnimation = function(name) {
for (var i in document.styleSheets) {
var styleSheet = document.styleSheets[i];
for (var j in styleSheet.cssRules) {
var rule = styleSheet.cssRules[j];
if (rule.type === 7 && rule.name == name) {
return rule;
}
}
}
return null;
}
var addImage = function(x, y, src) {
var image = new Image();
image.src = src;
image.className = "image";
image.style.width = "500px";
image.style.height = "500px";
image.style.left = x;
image.style.top = y;
image.onload = function() {
document.getElementById("container").appendChild(image);
var animation = findAnimation("image-create");
for (var i in animation.cssRules) {
var rule = animation.cssRules[i];
if (rule.keyText == "0%") {
rule.style.top = y;
rule.style.left = x;
}
if (rule.keyText == "100%") {
rule.style.top = 0;
rule.style.left = 0;
}
}
}
}
addImage(100, 100, "http://i.imgur.com/KGfgH.jpg");
When addImage() is called, I'm trying to create an image at the coordinates (x, y). The animation should make it grow while also move from the location where the image was created (x, y) to the top left corner (0, 0).
Instead, Chrome just crashes to the "Aw, snap" page. Does anyone know why this is the case?
EDIT: Here is an example. This crashes for me if I visit it: http://jsfiddle.net/LVpWS/10/
In this one I commented out some lines and it does not crash: http://jsfiddle.net/LVpWS/21/
EDIT2: It works if I switch back to Chrome 20.
I've isolated the error:
The page crashes (Aw, snap) when a new property is added to a WebKitCSSKeyframeRule instance.
The bug can be reproduced in Chrome 21.0.1180.57 using the following code: http://jsfiddle.net/LVpWS/68/
<style id="sheet">
#-webkit-keyframes test {
from {}
}</style><script>
var keyFramesRule = document.getElementById('sheet').sheet.cssRules[0];
var keyFrameRule = keyFramesRule[0];
keyFrameRule.style.top = 0;</script>
This crash does not happen when the property already exists in the rule. Replace from {} with from{top:1px;} to check that: http://jsfiddle.net/LVpWS/69/.