Separating HTML elements into columns with proper spacing (JQuery and CSS) - javascript

I am trying to make a Windows 8 like interface for my webpage. I have created articles that act as tiles and have a random generator that makes the tile small or large. I am trying to make these look like they are in columns depending on the width of the screen. When I change the screen width the tiles do not seem to be properly spaced which is driving me nuts. I am new to css and jquery so I am still learning and always open to learning new ways to do things. I would really appreciate some help on this column and spacing issue.
NOTE: My tiles usually have pictures and after I changed the code just to show up as color tiles. Now they are not always showing but I will fix that issue.
For example: each column should have a width of one double box or two single box's. And depending on the screen width...if bigger the more columns will display and the smaller the less amount of columns it will display.
Here is my current code:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="http://code.jquery.com/jquery-2.1.0.min.js" type="text/javascript"></script>
<script src="Script/jquery.lorem.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function ()
{
var colors = ["#2672ec", "#00a300", "#97009f", "#094db5", "#da532c", "#af1a3f", "#613cbc", "#008ad2"];
var doubleBoxFlag = [true, false, false, false, false, false];
var pictures = ["Images/1.jpg", "Images/2.jpg", "Images/3.jpg", "Images/4.jpg", "Images/5.jpg", "Images/6.jpg", "Images/7.jpg", "Images/8.jpg", "Images/9.jpg", "Images/10.jpg", "Images/11.jpg"];
var defaultClass = '.box';
for (var i = 0; i < Math.floor((Math.random() * 64) + 34) ; i++)
{
var rand = Math.floor(Math.random() * pictures.length);
var boxRand = Math.floor(Math.random() * doubleBoxFlag.length);
var currentClass = defaultClass + i;
var currentClassJ = 'box' + i;
//For picture tiles:
//$("#Interface").append("<article class=" + currentClassJ + " " + "style='background-image: url(" + pictures[rand] + ")" + "'><span>" + i + "</span>");
//For Color Tiles:
$("#Interface").append("<article class=" + currentClassJ + " " + "style='background-color:" + colors[rand] + "'><span>" + i + "</span>");
if (doubleBoxFlag[boxRand]) {
$(currentClass).css("width", "374px");
$(currentClass).css("padding-right", "20px");
}
else
$(currentClass).css("width", "187px");
$(currentClass).css("height", "187px");
$("article").css("float", "left");
$("article").css("margin", "11px");
$("span").css("display", "block");
$("span").css("padding-top", "167px");
$("span").css("padding-left", "12px");
}
//if (screen.width <= 480)
// $("#Interface").css("width", "470px");
//if (screen.width >= 1000 && screen.width <= 1799)
// $("#Interface").css("width", "470px");
//if (screen.width >= 1800)
// $("#Interface").css("width", "470px");
// This line below should be adding the random word to each of the articles
$('span').lorem({ type: 'words', amount: '1', ptags: false });
});
</script>
</head>
<body background = "Images/bg.png">
<div id="Interface"></div>
</body>
</html>

Now that I understand your problem, I propose to you start using css media queries. Basicaly for three reasons:
It's one way to solve your problem (duh)
This scripty resising and calculations will run slower when it comes to the real world.
It's much more clear and painless.
Make a css file with all rules that you want at determined screen size, then do this again for as many screen sizes you want to match. Remeber you can use all css tricks available to one determined screen size to achieve the look & feel that you want, because rules aplied under a media query will not mess with your css in other screen sizes.
After all, organize all the stylesheets in a single files and wrap them inside a proper media query.
Give it a try, you'll love it.
And yes, it's supported in at least the three earlier versions of IE, I guess.

Related

Javascript: preload next image

not very big on JS.
I currently have a script I use to load/change background images every xxx seconds.
What I would like is to display an image and preload the next one so it displays seamlessly (ie: no jittering or slow loads).
Here is my current script, can this be adapted to achieve such a result?
<!-- Background Image Changer inpired by: https://stackoverflow.com/a/7265145 -->
var images = ['images/image01.jpg',
'images/image02.jpg',
'images/image03.jpg',
'images/image04.jpg',
'images/image05.jpg',
'images/image06.jpg',
'images/image07.jpg',
'images/image08.jpg',
'images/image09.jpg',
'images/image10.jpg',
'images/image11.jpg',
'images/image12.jpg',
'images/image13.jpg',
'images/image14.jpg',
'images/image15.jpg',
'images/image16.jpg',];
var numSeconds = 30;
var curImage = 0;
function switchImage()
{
curImage = (curImage + 1) % images.length
document.body.style.backgroundImage = 'url(' + images[curImage] + ')'
}
window.setInterval(switchImage, numSeconds * 1000);
NOTES: There are 50 images in my script. I've only used fake named placeholders for clarity.
EDIT: To be clear, I only want one image displayed and the next (one) image to be preloaded. It's running on a RPi 3b so not much memory is available.
I want to add a different answer here. There are a few options you can use to improve your web page performance. Using <link> with preconnect and preload rel value can helps you to load resources before using them:
Use preconnect keyword for the rel attribute to tell the browsers that the user is likely to need resources from this origin and therefore it can improve the user experience by preemptively initiating a connection to that origin.
<link rel="preconnect" href="<your-images-base-url">
Use preload keyword for the rel attribute to declare fetch requests in the HTML's , specifying resources that your page will need very soon. This ensures they are available earlier and are less likely to block the page's render, improving performance. Taken from https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload
Create preload link:
const preloadLink = document.createElement('link');
document.head.appendChild(preloadLink);
preloadLink.rel = 'preload';
preloadLink.as = 'image';
function preloadNextImage(href) {
preloadLink.href = href;
}
function switchImage()
{
curImage = (curImage + 1) % images.length
document.body.style.backgroundImage = 'url(' + images[curImage] + ')';
preloadNextImage(/* <next-image-url> */)
}
You could just load the next image when displaying the current one using the JavaScript Image object. When switchImages runs again then the image will be already in the browsers cache. Also, the cached images are stored in a new array, so the cache "generator" will be ran only once. With this snippet you will need enough delay between iterations, so the next image will have enough time to be downloaded from the sever.
var images = ['images/image01.jpg',
'images/image02.jpg',
'images/image03.jpg',
'images/image04.jpg',
'images/image05.jpg',
'images/image06.jpg',
'images/image07.jpg',
'images/image08.jpg',
'images/image09.jpg',
'images/image10.jpg',
'images/image11.jpg',
'images/image12.jpg',
'images/image13.jpg',
'images/image14.jpg',
'images/image15.jpg',
'images/image16.jpg',];
var numSeconds = 2;
var curImage = 0;
var cache = [];
function switchImage()
{
curImage = (curImage + 1) % images.length;
document.body.style.backgroundImage = 'url(' + images[curImage] + ')';
if(images[curImage + 1] && !cache[curImage + 1]) {
cache[curImage + 1] = new Image();
cache[curImage + 1].src = images[curImage + 1];
}
}
window.setInterval(switchImage, numSeconds * 1000);

Morphing with Velocity.js doesnt work

Hej,
i have this plunker: http://plnkr.co/edit/bKzi6rU3lIXT4Nz2wkR8?p=info
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="stilovi/main.css">
<title>Testing</title>
</head>
<body>
<div id="avengers"></div>
</body>
<script src="snap.svg-min.js"></script>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://rawgit.com/julianshapiro/velocity/master/velocity.min.js"></script>
<script>
function fetchXML(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function(evt) {
//Do not explicitly handle errors, those should be
//visible via console output in the browser.
if (xhr.readyState === 4) {
callback(xhr.responseXML);
}
};
xhr.send(null);
};
/*var list = ["test3.svg","test.2svg"];*/
//fetch the document
fetchXML("test3.svg", function(newSVGDoc) {
//import it into the current DOM
var n = document.importNode(newSVGDoc.documentElement, true);
document.getElementById("avengers").appendChild(n);
var ironman = document.getElementsByTagName("polygon");
var ironmanlist = Array.prototype.slice.call(ironman);
/*alert(ironmanlist.length);*/
ironmanlist.forEach(function(elem, i) {
/*for (var index = 0; index < elem.points.length; ++index){
//2.test case morphing each point (not working)//
console.log(elem.points[index]);
$.Velocity(elem.points[index],{x:100,y:100},{duration:Math.floor(Math.random() * (3000 - 1000 + 1)) + 1000}, "ease-in-out");
//3.test case morphing each point in another way (not working)//
/*$(elem.points[index])
.velocity({x:100,y:100},{duration:Math.floor(Math.random() * (3000 - 1000 + 1)) + 1000}, "ease-in-out");
console.log(elem.points[index]);
}*/
//1. working test case (translation)//
console.log(elem.points[0].x);
$.Velocity(elem, {
translateX: -300
}, {
duration: Math.floor(Math.random() * (3000 - 1000 + 1)) + 1000
}, "ease-in-out");
//$.Velocity(elem,{rotateZ:"45deg"},{duration:Math.floor(Math.random() * (3000 - 1000 + 1)) + 1000}, "ease-in-out");
console.log(elem.points[0].x);
//End of 1. working test case//
});
console.log(ironmanlist);
});
</script>
</html>
With my code, and some examples. What I want to do is morph each polygon from one SVG image, into another polygon from another SVG image. The translation works, but I'm not sure how to do a morph.
Can anyone help, or check the code and tell me what I am doing wrong?
There are a lot of polygons, and I need it to be fast so i went with velocity.js for this.
I was also thinking of maybe moving it all to three.js, and maybe convert it to a format that would be best to use with three.js. But if it is a possibilty to use it as svg and keep a great performance i would do so.
As far as I'm aware, velocity.js doesn't support this as (taken from their website):
In general, Velocity can animate any property that takes a single numeric value.
As SVG paths usually (always?) consist of multiple values, morphing is way beyond their current scope.
However, I can highly recommend Snap for morphing SVG paths.

Detect which canvas rectangle is clicked

I have a canvas in html:
<canvas id="canvas" width="450" height="450"></canvas>
That I made nine equally sized squares in. I would like to see what square I have clicked as an alert function. How would I do that?
Full Code is here: https://jsfiddle.net/ckd6g1ac/1/
Sorry, I do not have any code relevant to my problem in the JSFiddle, but I have no clue on how to start writing it.
Thanks!
This is your onclick function:
$("#canvas").click(function(e) {
var yNames = ['upper', 'middle', 'lower'],
xNames = ['left', 'middle', 'right'];
alert(('The '
+ yNames[Math.floor((e.offsetY * 3) / canvas.height)] + '-'
+ xNames[Math.floor((e.offsetX * 3) / canvas.width)] + ' box was clicked.')
.replace('middle-middle', 'middle'));
});
Also you had a semantic error in your loop: it should be i<9 instead of 1<9.
offsetX and offsetY were used because these measure the offset from the element itself, which means that it doesn’t matter where the canvas is on the page.
Working JSFiddle.

Constrain jquery draggable to stay only on the path of a circle

So Im trying to make something where the user is able to drag planets along their orbits and it will continuously update the other planets. Ideally I would like this to work with ellipses too.
So far I can drag an image node with jquery and check/change the coordinates, but i cannot update the position reliably while the user is dragging the object. I know there is an axis and a rectangle containment for draggable but this doesn't really help me.
I have a site for calculating planetary orbits http://www.stjarnhimlen.se/comp/ppcomp.html and a formula i think should help me if i can figure out how to constrain the draggable object with coordinate checks Calculating point on a circle's circumference from angle in C#?
But it seems like there should be an easier way to have a user drag a sphere along a circular track while it updates coords for other spheres
here's what i have so far. It's not much
http://jsfiddle.net/b3247uc2/2/
Html
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
Js
var $newPosX = 100,
$newPosY = 100;
//create image node
var x = document.createElement("IMG");
x.src = "http://upload.wikimedia.org/wikipedia/commons/a/a4/Sol_de_Mayo_Bandera_Argentina.png";
x.width = 100;
x.height = 100;
x.id = "sun";
x.hspace = 100;
x.vspace = 100;
document.body.appendChild(x);
//coords
var text = document.createTextNode($newPosX + " " + $newPosY);
document.body.appendChild(text);
//make sun draggable and update coords
$("#sun").draggable({
drag: function (event, ui) {
$newPosX = $(this).offset().left;
$newPosY = $(this).offset().top;
}
});
//0 millisecond update for displayed coords
setInterval(check, 0);
function check() {
//tries to constrain movement, doesn't work well
/*
if ($newPosX > 300) {
$("#sun").offset({
left: 200
});
}
*/
text.nodeValue = ($newPosX + " " + $newPosY);
}
Edit:
I found this and am trying to modify it to suit my purposes but have so far not had luck.
http://jsfiddle.net/7Asn6/
Ok so i got it to drag
http://jsfiddle.net/7Asn6/103/
This is pretty close to what I want but can be moved without being clicked on directly
http://jsfiddle.net/7Asn6/104/
Ok final edit on this question. This one seems to work well and have fixed my problems. I would still very much like to hear peoples implementation ideas or ideas to make it work smoother.
http://jsfiddle.net/7Asn6/106/

SVG Click Handling Inconsistent With Displayed Location

I am building a web based, world domination game. The backbone of the game is a three level zoomable map of thirty-eight territories.
I built the map with SVG paths. The global view has a widescreen aspect ratio. When displaying the map on a square screen, for the sake of aesthetics, the entire SVG must be centered vertically using an animation tag. I've gotten the centering to work perfectly, the part I don't understand comes in when I click to zoom the map. It seems as though for the purposes of clicking, the map is a few (about 25) pixels above where it is displayed. For example, if I were to click on the grey background slightly above Russia, it would zoom me to the Asian continent. It seems more interesting to me when I consider the fact that I use transforms on every path for territorial and continental zoom levels, and the same problem does not occur.
The HTML looks as such:
<div class="test1" width="100%" height="100%">
<div id="renderedSprites"></div>
<div id="background"></div>
<div id="continentFilter" class="filter"></div>
<div id="territoryFilter" class="filter"></div>
<svg
preserveAspectRatio="xMinYMin meet"
class="territoryImage"
id="continentalSVG"></svg>
<svg
preserveAspectRatio="xMinYMin meet"
class="territoryImage"
id="territorialSVG"></svg>
<%= render partial: "images" %>
</div>
The images partial contains the global SVG, which is too long to show but follows this format:
<svg
preserveAspectRatio="xMinYMin meet"
class="territoryImage"
id="globalSVG">
<g>
<path
class="continentName"
id="territoryName"
d="..."
inkscape:connector-curvature="0" />
</g>
37 More paths and animations...
</svg>
The zooming JS is simple and pretty much irrelevant. I just clone the paths for the desired piece of the map into the proper SVG for that level. I then display that SVG at a higher z-index and put a filter or set of filters in between displayed levels. Here it is though, anyways (sorry it's so packed and disgusting):
var zoomLevel = ["global","globe"];
//renderObject("encampment",zoomLevel);
//renderObject("fort",zoomLevel);
$(".territoryImage").click( function(e) {
if ($(document.elementFromPoint(e.pageX,e.pageY)).is("path") == true) {
if (zoomLevel[0] == "global") {
var continent = $(".".concat($(document.elementFromPoint(e.pageX,e.pageY)).attr("class")))
for (i = 0; i < continent.length; i++) {
$("#continentalSVG").append($(continent[i]).parent().clone())
}
var box = $("#continentalSVG")[0].getBoundingClientRect()
var newScaleFactor
if (box.width/$(window).width() > box.height/$(window).height()) {
newScaleFactor = ($("#background").width()*parseFloat($("#continentalSVG").children("g").attr("transform").split(")")[0].replace("scale(","")))/box.width*0.95;
console.log(newScaleFactor);
}
else {
newScaleFactor = ($("#background").height()*parseFloat($("#continentalSVG").children("g").attr("transform").split(")")[0].replace("scale(","")))/box.height*0.95;
console.log(newScaleFactor);
}
$("#continentalSVG").children("g").attr("transform","scale(" + newScaleFactor + ")");
var scaledBox = $("#continentalSVG").offset();
scaledBox.top = ((scaledBox.top - $("#background").offset().top)/newScaleFactor) - (($("#background").height()/2) - ($("#continentalSVG")[0].getBoundingClientRect().height/2))
scaledBox.left = ((scaledBox.left - $("#background").offset().left)/newScaleFactor) - (($("#background").width()/2) - ($("#continentalSVG")[0].getBoundingClientRect().width/2))
$("#continentalSVG").children("g").attr("transform", $("#continentalSVG").children("g").attr("transform") + " translate(" + -1*scaledBox.left + ", " + -1*scaledBox.top + ")")
$("#continentalSVG").css("z-index","2");
$("#continentFilter").css("display","inline");
zoomLevel = ["continental",$("#continentalSVG").children("g").attr("class")];
//renderObject("encampment",zoomLevel);
//renderObject("fort",zoomLevel);
}
else if (zoomLevel[0] == "continental") {
var territory = "#" + document.elementFromPoint(e.pageX,e.pageY).id;
$("#territorialSVG").append($(territory).parent().clone())
var box = $("#territorialSVG")[0].getBoundingClientRect();
var newScaleFactor
if (box.width/$(window).width() > box.height/$(window).height()) {
newScaleFactor = ($("#background").width()*parseFloat($("#territorialSVG").children("g").attr("transform").split(")")[0].replace("scale(","")))/box.width*0.95;
}
else {
newScaleFactor = ($("#background").height()*parseFloat($("#territorialSVG").children("g").attr("transform").split(")")[0].replace("scale(","")))/box.height*0.95;
}
$("#territorialSVG").children("g").attr("transform","scale(" + newScaleFactor + ")");
var scaledBox = $("#territorialSVG").offset()
//console.log(scaledBox)
scaledBox.top = ((scaledBox.top - $("#background").offset().top)/newScaleFactor) - ($("#background").height() - ($("#territorialSVG")[0].getBoundingClientRect().height))/(newScaleFactor*2)
scaledBox.left = ((scaledBox.left - $("#background").offset().left)/newScaleFactor) - ($("#background").width() - ($("#territorialSVG")[0].getBoundingClientRect().width))/(newScaleFactor*2)
//console.log(($("#background").width() - ($("#territorialSVG")[0].getBoundingClientRect().width))/(newScaleFactor*2))
$("#territorialSVG").children("g").attr("transform", $("#territorialSVG").children("g").attr("transform") + " translate(" + -1*scaledBox.left + ", " + -1*scaledBox.top + ")")
$("#territorialSVG").css("z-index","4");
$("#territoryFilter").css("display","inline");
zoomLevel = ["territorial",territory, zoomLevel[1]];
//renderObject("encampment",zoomLevel);
//renderObject("fort",zoomLevel);
}
}
else {
if (zoomLevel[0] == "continental") {
$("#continentalSVG").children().remove();
$("#continentFilter").css("display","none");
$("#continentalSVG").css("z-index","-1");
zoomLevel = ["global","globe"];
//renderObject("encampment",zoomLevel);
//renderObject("fort",zoomLevel);
}
else if (zoomLevel[0] == "territorial") {
$("#territorialSVG").children().remove();
$("#territoryFilter").css("display","none");
$("#territorialSVG").css("z-index","-1");
$("#continentalSVG").css("z-index","2");
zoomLevel = ["continental", zoomLevel[2]];
//renderObject("encampment",zoomLevel);
//renderObject("fort",zoomLevel);
}
}
});
Here is the relevant part:
function setOriginalZoom() {
//this first part scales all the SVG's as well as the background, the filters, and a div I use for sprites
$(".territoryImage").attr("viewBox", "0 0 " + $(window).width()*0.95 + " " + $(window).height()*0.95);
$(".territoryImage").attr("width", $(".territoryImage").attr("viewBox").split(" ")[2]);
$(".territoryImage").attr("height", $(".territoryImage").attr("viewBox").split(" ")[3]);
$("#background").css("width", $(".territoryImage").width())
$("#renderedSprites").css("height", $(".territoryImage").height())
$("#renderedSprites").css("width", $(".territoryImage").width())
$("#background").css("height", $(".territoryImage").height())
$(".filter").css("width", $(".territoryImage").width())
$(".filter").css("height", $(".territoryImage").height())
$("g").attr("transform", "scale(" + $(".territoryImage").attr("viewBox").split(" ")[2]/3508 + ")")
//this part vertically centers the global SVG. The part that seems to trip things up.
$("#globalSVG").children("g").attr("transform", $("#globalSVG").children("g").attr("transform") + " translate(0 " + (($("#background").height()/2) - ($("#globalSVG")[0].getBoundingClientRect().height/2) + ($("#globalSVG").offset().top - $("#background").offset().top))/(($(".territoryImage").attr("viewBox").split(" ")[2]/3508)*2) + ")")
}
I call this function on page load, and it centers all of the displayed elments. It also scales the SVG's for the global view. The last bit I commented out, was written to vertically center the map.
It has occurred to me that the way I listen for clicks on the map may be responsible for the bug. This piece of code, included in the zooming section above, is what i'm talking about:
$(".territoryImage").click( function(e) {
if ($(document.elementFromPoint(e.pageX,e.pageY)).is("path") == true) {
I wrote it that way because the simpler way,
$("path").click( function() {...});
would fire whenever someone clicks on the SVG. For whatever reason that solution registered the path as being the defined size of the SVG (in terms of height and width attributes which I set to a percent of the window size), while the other implementation only fired when a filled part of the path was clicked.
Now if anyone can figure this out, I would really appreciate it. If you have any questions, really please ask I'll respond asap.
Thanks,
-Alex

Categories

Resources