How to resolve d3js tree graph getting clipped - css

I am trying to create a collapsible tree graph in d3. Although there are many examples around the web, I am not expert in JS or d3 coming from java background, and couldn't find any that perfectly suited my needs and hence made this from different templates that I found across many blogs and gists.
The problem is the lower part of my graph getting clipped. If I increase the svg size, that just elongates the graph and it still gets clipped. I am posting the link to plunkr where I have put the code. Please scroll to the right in plunkr to see the graph.
Below is the javascript to render tree
var CollapsibleTree = function(elt) {
var m = [20, 120, 20, 120],
w = 1280 - m[1] - m[3],
h = 780 - m[0] - m[2],
i = 0,
root;
var tree = d3.layout.tree()
.size([w, h]);
var parentdiagonal = d3.svg.diagonal()
.projection(function(d) { return [d.x, -d.y]; });
var childdiagonal = d3.svg.diagonal()
.projection(function(d) { return [d.x, d.y]; });
var vis = d3.select(elt).append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate("+w/6+","+h/2+")"); // bidirectional-tree
var that = {
init: function(url) {
var that = this;
var json = {
"name":"A",
"elementType":"ACTION",
"elementSubType":"ACTION-A",
"isparent":false,
"parents":[
{
"name":"B",
"elementType":"RESOURCE",
"elementSubType":"RESOURCE-A",
"isparent":true
}
],
"children":[
{
"name":"C",
"elementType":"RESOURCE",
"elementSubType":"RESOURCE-C",
"isparent":false,
"children":[
{
"name":"D",
"elementType":"ACTION",
"elementSubType":"ACTION-A",
"isparent":false,
"children":[
{
"name":"E",
"elementType":"RESOURCE",
"elementSubType":"RESOURCE-A",
"isparent":false,
"children":[
{
"name":"F",
"elementType":"ACTION",
"elementSubType":"ACTION-C",
"isparent":false,
"children":[
{
"name":"G",
"elementType":"RESOURCE",
"elementSubType":"RESOURCE-C",
"isparent":false
}
]
}
]
}
]
}
]
}
]
};
root = json;
root.x = w / 2;
root.y = h / 2;
that.updateBoth(root);
},
updateBoth: function(source) {
var duration = d3.event && d3.event.altKey ? 5000 : 300;
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 0.5*h/4; });
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) {
if( that.isParent(d) ) {
return "translate(" + source.x + "," + -source.y + ")";
} else {
return "translate(" + source.x + "," + source.y + ")";
}
})
.on("click", function(d) { that.toggle(d); that.updateBoth(d); });
// Add images to node
nodeEnter.append("svg:image")
.attr("xlink:href", "img/file.png")
.attr("width", 35)
.attr("height", 35)
.attr("x",function(d) { return -20; }) // position the images
.attr("y",function(d) { return -20; });
nodeEnter.append("text")
// .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("x", function(d) {
return -10;
})
.attr("y", 20)
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.attr("text-anchor", function(d) {
return "middle";
})
.text(function(d) {
if (d.name.length > 10){
return d.name.substring(0,10)+d.name.substring(10,d.name.length);
}
else {
return d.name;
}
})
.style("fill", "black")
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.ease("linear")
.attr("transform", function(d) {
if( that.isParent(d) ) {
return "translate(" + d.x + "," + -d.y + ")";
} else {
return "translate(" + d.x + "," + d.y + ")";
}
});
nodeUpdate.select("text")
.style("fill-opacity", 1)
.attr("class", function(d){
if (d.status==="incomplete" || d.status === "failed"){
return "blink";
} else {
return "non-blink"
}
});
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
// .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.attr("transform", function(d) { // custom code to fix error in node exit
if (that.isParent(d)){
return "translate(" + source.x + "," + -source.y + ")"; // controls exit of parents
}
else{
return "translate(" + source.x + "," + source.y + ")"; // controls exit of children
}
})
.remove();
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = vis.selectAll("path.link")
.data(tree.links_parents(nodes).concat(tree.links(nodes)), function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("svg:path", "g")
.attr("class", "link")
.style("stroke", function(d) {
return "black";
})
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
if( that.isParent(d.target) ) {
return parentdiagonal({source: o, target: o});
} else {
return childdiagonal({source: o, target: o});
}
})
.transition()
.duration(duration)
.attr("d", function(d) {
if( that.isParent(d.target) ) {
return parentdiagonal(d);
} else {
// return parentdiagonal(d);
return childdiagonal(d);
}
})
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", function(d) {
if( that.isParent(d.target) ) {
return parentdiagonal(d);
} else {
return childdiagonal(d);
}
})
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
// return parentdiagonal({source: o, target: o});
if( that.isParent(d.target) ) {
return parentdiagonal({source: o, target: o});
} else {
return childdiagonal({source: o, target: o});
}
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x = d.x;
d.y = d.y;
});
},
isParent: function(node) {
if( node.parent && node.parent != root ) {
return this.isParent(node.parent);
} else
if( node.isparent ) {
return true;
} else {
return false;
}
},
// Toggle children or parents (one level).
toggle: function(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
if (d.parents) {
d._parents = d.parents;
d.parents = null;
} else {
d.parents = d._parents;
d._parents = null;
}
},
// Toggle successors or aancestors (multiple level)
toggleAll: function(d) {
if (d.children) {
d.children.forEach(that.toggleAll);
that.toggle(d);
}
if (d.parents) {
d.parents.forEach(that.toggleAll);
that.toggle(d);
}
}
}
return that;
}
and here are the css
body {
overflow: hidden;
margin: 0;
font-size: 14px;
font-family: "Helvetica Neue", Helvetica;
}
#chart, #header, #footer {
position: absolute;
top: 0;
}
#header, #footer {
z-index: 1;
display: block;
font-size: 36px;
font-weight: 300;
text-shadow: 0 1px 0 #fff;
}
#header.inverted, #footer.inverted {
color: #fff;
text-shadow: 0 1px 4px #000;
}
#header {
top: 80px;
left: 140px;
width: 1000px;
}
#footer {
top: 680px;
right: 140px;
text-align: right;
}
rect {
fill: none;
pointer-events: all;
}
pre {
font-size: 18px;
}
line {
stroke: #000;
stroke-width: 1.5px;
}
.string, .regexp {
color: #f39;
}
.keyword {
color: #00c;
}
.comment {
color: #777;
font-style: oblique;
}
.number {
color: #369;
}
.class, .special {
color: #1181B8;
}
a:link, a:visited {
color: #000;
text-decoration: none;
}
a:hover {
color: #666;
}
.hint {
position: absolute;
right: 0;
width: 1280px;
font-size: 12px;
color: #999;
}
.node circle {
cursor: pointer;
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font-size: 11px;
}
path.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
/*svg {
border: 1px;
border-style: solid;
border-color: black;
}*/
#foo {
border: 5px;
border-style: dashed;
border-color: black;
background-color: pink;
}
#categoryHierarchy{
margin: 5px;
height: 700px;
width: auto;
border: 2px;
border-style: solid;
border-color: #000;
overflow: scroll;
/*padding: 10px;*/
}
and html files
<body>
<div id="categoryHierarchy"></div>
<script type="text/javascript">
$(document).ready(function(event) {
var tree = CollapsibleTree("#categoryHierarchy");
tree.init('sample.json');
});
</script>
</body>

You could try reducing the distance between each of the 'nodes'.
E.g. line 98 try playing around with h - 'x', I've tried using 300.
nodes.forEach(function(d) { d.y = d.depth * 0.5*(h-300)/4; });

Related

D3 map not centering on page?

I'm having difficulty centering my D3 map on the webpage. The map is in a map class and within a div, but CSS won't appear to center it.
Any margins I apply to the class ".map", which the SVG is in, doesn't appear to work either. I'm not sure why I'm unable to apply any CSS to the map, but maybe I'm supposed to do something in the actual D3 code? Unsure. Thanks!
Here's my code:
<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.js'></script>
<meta charset='utf-8'>
<meta name="viewport" content='width=device-width, initial-scale=1.0'>
<title></title>
<style>
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 10px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 10px;
}
.active {
fill: rgba(149, 165, 166, 0.8);
}
body {
background: rgba(32, 32, 32, 1);
color: rgba(255, 255, 255, 0.8);
}
h1 {
font-family: Impact, Charcoal, sans-serif;
text-align: center;
}
h2 {
font-family: Impact, Charcoal, sans-serif;
text-align: center;
}
p {
font-family: "Arial Black", Gadget, sans-serif;
text-align: center;
}
#box {
border: 10px solid black;
margin: auto;
padding: 10px;
width: 75%;
border-radius: 10px;
}
.map {
margin-left: auto;
margin-right: auto;
}
</style>
<script>
function draw(geo_data) {
var margin = 0,
width = 2000 - margin,
height = 700 - margin;
var centered;
var svg = d3.select('#map')
.append('svg')
.attr('width', width + margin)
.attr('height', height + margin)
.append('g')
.attr('class', 'map');
var formatComma = d3.format(",")
var projection = d3.geoAlbersUsa();
var path = d3.geoPath().projection(projection);
var map = svg.selectAll('path')
.data(geo_data.features)
.enter()
.append('path')
.attr('d', path)
.attr('fill', 'rgba(105, 105, 105, 1)')
.attr('stroke', 'rgba(0, 0, 0, 1)')
.attr('stroke-width', 0.5)
.on('mouseover', function(d) {
d3.select(this).attr('fill', 'rgba(108, 122, 137, 0.5)')
})
.on('mouseout', function() {
if (d3.select(this).classed('clicked')) {
console.log('is clicked')
d3.select(this).attr('fill', 'rgba(105, 105, 105, 1)')
} else {
console.log('is not clicked')
d3.select(this).attr('fill', 'rgba(105, 105, 105, 1)')
}
})
// Calls click-to-zoom function defined below.
.on('click', clicked);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<p><font size='4rem'>" + d.city + ", " + d.state + "</p></font>" + "<p><font size='3rem'><strong>Guns Manufactured: </strong>" + formatComma(d.guns) + "</p>" +
"<p><strong>Top Manufacturer:</strong> " + d.manufacturer +
"</p></font>";
})
svg.call(tip);
// Click-to-zoom function adapted from Mike Bostock's code: https://bl.ocks.org/mbostock/2206590
function clicked(d) {
d3.select(this).attr('fill', 'rgba(108, 122, 137, 0.5)');
if (d3.select(this).classed('clicked')) {
d3.select(this).attr('clicked', false);
} else {
d3.select(this).attr('clicked', true);
}
var x, y, k;
if (d && centered !== d) {
var centroid = path.centroid(d);
x = centroid[0];
y = centroid[1];
k = 4;
centered = d;
} else {
x = width / 2;
y = height / 2;
k = 1;
centered = null;
}
map.selectAll('path')
.classed('active', centered && function(d) {
return d === centered;
});
map.transition()
.duration(1000)
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')scale(' + k + ')translate(' + -x + ',' + -y + ')')
.style('stroke-width', 1 / k + 'px');
// Transitions circles upon zoom.
svg.selectAll('circle')
.transition()
.duration(1000)
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')scale(' + k + ')translate(' + -x + ',' + -y + ')')
.style('stroke-width', 1 / k + 'px');
}
d3.csv('https://raw.githubusercontent.com/dieterholger/US-Gun-Manufacturing-Interactive/master/top100cities.csv', function(error, data) {
// Converts strings in csv to integers so they can be used.
data.forEach(function(d) {
return d.guns = +d.guns;
})
// This returns the max number of guns.
var guns = data.map(function(d) {
return d.guns;
});
var guns_extent = d3.extent(data, function(d) {
return d.guns;
});
var radius = d3.scaleSqrt()
.domain(guns_extent)
.range([2, 40]);
svg.append('g')
.attr('class', 'bubble')
.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d) {
return projection([d.lon, d.lat])[0];
})
.attr('cy', function(d) {
return projection([d.lon, d.lat])[1];
})
.attr('r', function(d) {
return radius(d.guns);
})
.attr('fill', 'rgba(248, 148, 6, 0.5)')
.attr('stroke', 'black')
.on('mouseover', function(d) {
tip.show(d);
return d3.select(this).attr('fill', 'rgba(248, 148, 6, 0.9)');
})
.on('mouseout', function(d) {
tip.hide(d);
return d3.select(this).attr('fill', 'rgba(248, 148, 6, 0.5)');
})
});
};
</script>
</head>
<body>
<div id='box'>
</div>
<div id='map'>
<h2>Hover your mouse to see data on the cities and click a state to zoom in.</h2>
</div>
<div id='box'>
</div>
<script>
d3.json('https://raw.githubusercontent.com/dieterholger/US-Gun-Manufacturing-Interactive/master/us_states.json', draw);
</script>
</body>
Enclose the map in another div, which has the same width as the box above it (75%). You may want to move the div style to a CSS class, if it works the way you want.
<div style="display:block; margin-left:auto; margin-right:auto; width:75%">
<div id="map">
...
</div>
</div>
UPDATE
I just found the real problem. Your css definition for map is for a class, not for an id. And... if you want to use auto margins, you need to define a width.
Change your css to match the following:
#map {
width: 75%;
margin-left: auto;
margin-right: auto;
}

Facebook/Twitter Style photos grid style layout [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
I'm trying to implement a facebook style photos grid layout. I'm using angularjs and bootstrap for this. I have come across certain plugins like angular-masonry which I think can be used for this. Following are some snapshots of what I'm actually trying to achieve following possible layouts:
Any idea how can this be achieved ? Is there any other plugin which can make life easy ?
All theses are your possibilities:
ngPhotoGrid
Seamless Responsive Photo Grid
freewall - Using jQuery
Bootstrap Responsive Image Gallery by mobirise
Gamma Gallery
Also read - An AngularJS directive for Masonry
ngPhotoGrid example :
//ngPhotoGrid.js
angular.module("ngPhotoGrid", [])
angular.module("ngPhotoGrid")
.filter("photoUrlSafe", [
"$sce", function($sce) {
return function(text) {
return $sce.trustAsResourceUrl(text);
};
}
])
.directive('endRepeat', function() {
return {
restrict: 'A',
require: "^ngPhotoGrid",
link: function(scope, element, attrs, gridController) {
if (scope.$last) {
gridController.notifyDOMReady(element)
}
}
};
})
.directive("ngPhotoGrid", ["$templateCache", function($templateCache){
$templateCache.put("photo_grid.html",
"<ul class='photo-grid-wrapper' ng-style = 'parentStyle'><li class='grid-cell' ng-repeat= 'image in loadedImages track by $index' ng-style = 'image.cellStyle' ng-click='cellClicked(image)' end-repeat='' ng-attr-data-src='{{image[defaultOptions.urlKey] | photoUrlSafe}}'><img class='grid-cell-image' ng-style = 'image.imageStyle' ng-src='{{image[defaultOptions.urlKey]}}' alt='#'/></li></ul>");
function linker(scope, element, attrs) {
scope.loadedImages = [];
scope.loadedTakenImages = [];
scope.takenImages = [];
// ###OPTIONS
scope.defaultOptions = {
urlKey : "original_url",
sortByKey : "nth",
onClicked : function() {},
onBuilded : function() {},
onDOMReady : function() {},
margin : 2,
maxLength : 5,
isSquare : false,
buildOnLoading : true
}
angular.extend(scope.defaultOptions, scope.gridOptions);
var IS_SQUARE = scope.defaultOptions.isSquare;
var GRID_WIDTH = element.prop('offsetWidth');
var MARGIN = scope.defaultOptions.margin;
if (!GRID_WIDTH) { // set the default width of parent
GRID_WIDTH = 250
}
scope.parentStyle = { width: GRID_WIDTH + "px", overflow: "hidden", position: "relative", margin: 0, padding: 0 }
if(IS_SQUARE) {
scope.parentStyle.height = GRID_WIDTH + "px";
}
var commonStyle = {
display: 'block',
overflow: 'hidden',
cssFloat: 'left',
cursor: 'pointer',
position: 'relative'
};
//callback handler
scope.cellClicked = function(image) {
scope.defaultOptions.onClicked(image);
}
/**
* choose images from the url source to build grid
* take maximum 7 images for best looking
*------------------------------------------------*/
scope.chooseImages = function(images) {
angular.forEach(images, function(image, index) {
var randNumber; //set the id and nth value for image if does not have
randNumber = randomNumber();
image.id = image.id || randNumber;
image[scope.defaultOptions.sortByKey] = image[scope.defaultOptions.sortByKey] || randNumber;
});
var sortedImages = images.sort(function(a, b) {
return a[scope.defaultOptions.sortByKey] - b[scope.defaultOptions.sortByKey]
})
return sortedImages.slice(0, scope.defaultOptions.maxLength)
}
randomNumber = function(max) {
max = max || 999;
return Math.floor(Math.random()*max);
}
scope.preloadImages = function(images) {
scope.takenImages = scope.chooseImages(images)
angular.forEach(scope.takenImages, function(image, index) {
var img;
img = new Image();
img.id = image.id ;
img[scope.defaultOptions.sortByKey] = image[scope.defaultOptions.sortByKey];
img.onload = function(loadedImage) {
scope.loadedTakenImages.push(loadedImage);
// store the original dimesion of image
image.naturalWidth = loadedImage.target.naturalWidth
image.naturalHeight = loadedImage.target.naturalHeight
// build the grid immediatly after the image was loaded
// building while images loading
if(scope.defaultOptions.buildOnLoading) {
scope.buildPhotoGrid();
setTimeout(function() {
scope.$apply()
}, 10)
}
if(scope.loadedTakenImages.length == scope.takenImages.length) {
//trigger build completed handler
scope.defaultOptions.onBuilded(element)
//grid also can be build after all image loaded
//all image would be shown correctly, loading time cause poor UX
if(!scope.defaultOptions.buildOnLoading) {
scope.buildPhotoGrid()
setTimeout(function() {
scope.$apply()
}, 15)
}
}
};
img.src = image[scope.defaultOptions.urlKey];
});
};
scope.buildPhotoGrid = function() {
var firstImage, imageStyle, smallCellHeight,
smallCellWidth, bigCellWidth, bigCellHeight, cellCount, is2First;
// get cell style & builded options
styles = scope.getCellStyles();
smallCellHeight = styles.options.smallCellHeight;
smallCellWidth = styles.options.smallCellWidth;
bigCellWidth = styles.options.bigCellWidth;
bigCellHeight = styles.options.bigCellHeight;
cellCount = styles.options.cellCount;
is2First = styles.options.is2First;
scope.loadedImages = []
angular.forEach(scope.takenImages, function(image, index) {
if (is2First) { //case the grid has 2 image big first
var bigCellStyle, smallCellStyle;
bigCellStyle = angular.copy(styles.big);
smallCellStyle = angular.copy(styles.small);
if (index == 0) {
bigCellStyle.top = "0";
image.cellStyle = bigCellStyle;
image.imageStyle = getImageStyle(bigCellWidth, bigCellHeight, image);
} else if (index == 1) {
bigCellStyle.top = bigCellHeight + MARGIN + "px";
image.cellStyle = bigCellStyle;
image.imageStyle = getImageStyle(bigCellWidth, bigCellHeight, image);
} else {
var margin, smallCellIndex;
// fix the last cell of 2 first was not fit the grid height
if(index == scope.takenImages.length - 1) {
smallCellStyle.height = smallCellHeight + MARGIN + "px"
}
smallCellIndex = index - 2;
margin = smallCellIndex == 0 ? 0 : MARGIN;
smallCellStyle.top = smallCellIndex * smallCellHeight + (margin * smallCellIndex) + "px";
image.cellStyle = smallCellStyle;
image.imageStyle = getImageStyle(smallCellWidth, smallCellHeight, image);
}
} else if (index == 0) { //big cell style
image.cellStyle = styles.big;
image.imageStyle = getImageStyle(bigCellWidth, bigCellHeight, image);
} else if (index != cellCount - 1 || cellCount == 2){ //small cells
image.cellStyle = styles.small;
image.imageStyle = getImageStyle(smallCellWidth, smallCellHeight, image);
} else { //last small cell style (remove redundant margin right or bottom)
image.imageStyle = getImageStyle(smallCellWidth, smallCellHeight, image);
image.cellStyle = styles.last;
}
})
scope.loadedImages = scope.takenImages;
}
function getImageStyle(cellWidth, cellHeight, image) {
var imageWidth, imageHeight, curImageWidth, curImageHeight, imgRatio, cellRatio;
cellWidth = Math.round(cellWidth);
cellHeight = Math.round(cellHeight);
imageWidth = image.naturalWidth;
imageHeight = image.naturalHeight;
imgRatio = imageWidth / imageHeight;
cellRatio = cellWidth / cellHeight;
// when the any image's dimension greater than cell's dimension
if(cellWidth > imageWidth || cellHeight > imageHeight) {
if (cellWidth >= imageWidth) {
return getSmallImagePortraitStyle(cellHeight, cellWidth, imgRatio);
} else {
return getSmallImageLandscapeStyle(cellHeight, cellWidth, imgRatio);
}
} else { // when the image smaller than the cell in both dimension
if(imgRatio >= 1) {
return getSmallImageLandscapeStyle(cellHeight, cellWidth, imgRatio);
} else {
return getSmallImagePortraitStyle(cellHeight, cellWidth, imgRatio);
}
}
}
function getSmallImageLandscapeStyle(cellHeight, cellWidth, imgRatio) {
var curImageWidth = cellWidth;
var curImageHeight = Math.round(curImageWidth / imgRatio);
if(curImageHeight >= cellHeight) {
var top = (-1) * Math.round((cellWidth / imgRatio - cellHeight) / 2);
if(curImageWidth < cellWidth) {
return { width: "100%", position: "relative", top: top + "px"}
} else {
return { maxWidth: "100%", position: "relative", top: top + "px"}
}
} else {
var left = (-1) * Math.round((cellHeight * imgRatio - cellWidth) / 2);
return { maxHeight: "100%", height: "100%", position: "relative", left: left + "px"}
}
}
function getSmallImagePortraitStyle(cellHeight, cellWidth, imgRatio) {
var curImageHeight = cellHeight;
var curImageWidth = Math.round(curImageHeight * imgRatio);
var top = (-1) * Math.round((cellWidth / imgRatio - cellHeight) / 2);
var left = (-1) * Math.round((cellHeight * imgRatio - cellWidth) / 2);
if(curImageWidth <= cellWidth) {
return { width: "100%", position: "relative", top: top + "px"}
} else {
return { maxHeight: "100%", height: "100%", position: "relative", left: left + "px"}
}
}
/**
* build cell style for grid
* #firstRatio : ratio of the first image in list
* #secondRatio : ratio of the second image in list
* #cellCount : total cells in grid
*------------------------------------------------*/
buildCellStyle = function (firstImage, secondImage, cellCount) {
var firstRatio, secondRatio, bigCellStyle, smallCellStyle, lastCellStyle,
WIDTH_RATE, bigCellWidth, bigCellHeight, smallCellHeight, smallCellWidth, is2First,
case2BigImage1, case2BigImage2;
firstRatio = firstImage.naturalWidth / firstImage.naturalHeight;
if (secondImage)
secondRatio = secondImage.naturalWidth / secondImage.naturalHeight;
else
secondRatio = 1.5 //fail all cases below
bigCellStyle = angular.copy(commonStyle);
smallCellStyle = angular.copy(commonStyle);
lastCellStyle = angular.copy(commonStyle);
WIDTH_RATE = getWidthRate(firstRatio, cellCount);
case2BigImage1 = firstRatio > 0.8 && firstRatio < 1.2 &&
secondRatio > 0.8 && secondRatio < 1.2
case2BigImage2 = firstRatio >= 2 && secondRatio >= 2
if(cellCount == 2) { //build style for grid has 2 images and first image has firstRatio > 1
if(firstRatio >= 1) {
bigCellStyle.marginBottom = MARGIN;
bigCellStyle.width = GRID_WIDTH;
bigCellStyle.height = GRID_WIDTH / 2;
smallCellStyle.width = GRID_WIDTH;
smallCellStyle.height = GRID_WIDTH / 2 - MARGIN;
} else {
var marginSize = MARGIN / cellCount;
bigCellStyle.marginRight = marginSize;
smallCellStyle.marginLeft = marginSize;
if(IS_SQUARE) {
bigCellWidth = Math.floor(GRID_WIDTH / 2) - MARGIN;
bigCellStyle.width = bigCellWidth;
bigCellStyle.height = GRID_WIDTH;
smallCellWidth = Math.floor(GRID_WIDTH / 2) - MARGIN;
smallCellStyle.width = smallCellWidth;
smallCellStyle.height = GRID_WIDTH;
} else {
bigCellWidth = Math.floor(GRID_WIDTH * WIDTH_RATE) - MARGIN;
bigCellStyle.width = bigCellWidth;
bigCellStyle.height = bigCellWidth;
smallCellWidth = GRID_WIDTH - bigCellWidth - MARGIN;
smallCellHeight = bigCellWidth;
smallCellStyle.width = smallCellWidth;
smallCellStyle.height = smallCellHeight;
}
}
}
// add style for first column contain 2 big images, only support for grid has more than 5 cells
//NOTE: need check when 2 first were same size!!!
else if (cellCount >= 5 && (case2BigImage1 || case2BigImage2)) {
var GRID_HEIGHT;
WIDTH_RATE = case2BigImage1 ? 1/2 : 2/3;
scope.parentStyle.position = "relative";
bigCellStyle.cssFloat = smallCellStyle.cssFloat = lastCellStyle.cssFloat = null;
bigCellStyle.position = smallCellStyle.position = lastCellStyle.position = "absolute";
//determine the height of the big cell
//height == width / 2 if the grid in case2BigImage1
if(case2BigImage1) {
bigCellHeight = GRID_WIDTH / 2;
} else {
bigCellHeight = WIDTH_RATE * GRID_WIDTH / firstRatio;
}
GRID_HEIGHT = bigCellHeight * 2 + MARGIN; //margin bottom the first big image
scope.parentStyle.height = GRID_HEIGHT + "px";
bigCellStyle.width = GRID_WIDTH * WIDTH_RATE - MARGIN;
bigCellStyle.height = bigCellHeight;
bigCellStyle.left = 0;
smallCellStyle.width = GRID_WIDTH - bigCellStyle.width - MARGIN;
smallCellStyle.height = Math.floor((GRID_HEIGHT / (cellCount - 2))) - MARGIN;
smallCellStyle.right = 0;
is2First = true; //flag this style is has 2 big image style
lastCellStyle.height = smallCellStyle.height + MARGIN;
} else if(firstRatio >= 1) { //build style for grid more than 2 images and first image has firstRatio > 1
bigCellStyle.marginBottom = MARGIN;
smallCellStyle.marginRight = MARGIN;
var smallCellCount = cellCount - 1;
if (IS_SQUARE) {
bigCellStyle.height = GRID_WIDTH * 2 / 3;
bigCellStyle.width = GRID_WIDTH;
smallCellStyle.height = GRID_WIDTH * 1 / 3 - MARGIN;
} else {
bigCellStyle.width = GRID_WIDTH ;
bigCellStyle.height = GRID_WIDTH * 2 / 3;
}
smallCellStyle.width = ( GRID_WIDTH - smallCellCount * MARGIN ) / smallCellCount;
// determine the height of smallCell below
if (IS_SQUARE) {
smallCellStyle.height = GRID_WIDTH - bigCellStyle.height - MARGIN;
} else if (firstRatio > 1.3 && firstRatio < 1.5) { // 4:3 < firstRatio < 5:3
smallCellStyle.height = smallCellStyle.width / firstRatio;
} else if (firstRatio > 1.5) {
smallCellStyle.height = smallCellStyle.width / 1.5;
} else {
smallCellStyle.height = smallCellStyle.width;
}
lastCellStyle.height = smallCellStyle.height;
lastCellStyle.width = smallCellStyle.width;
} else { //build style for grid more than 2 images and first image has firstRatio <= 1
bigCellStyle.marginRight = MARGIN;
smallCellStyle.marginBottom = MARGIN;
if (IS_SQUARE) {
bigCellHeight = GRID_WIDTH;
bigCellWidth = GRID_WIDTH * WIDTH_RATE;
} else {
bigCellWidth = Math.floor(GRID_WIDTH * WIDTH_RATE);
bigCellHeight = bigCellWidth / firstRatio;
}
bigCellStyle.width = bigCellWidth;
bigCellStyle.height = bigCellHeight;
smallCellCount = cellCount - 1;
smallCellWidth = GRID_WIDTH - bigCellWidth - MARGIN;
smallCellHeight = bigCellHeight / smallCellCount - MARGIN
smallCellStyle.width = GRID_WIDTH - bigCellWidth - MARGIN;
smallCellStyle.height = smallCellHeight;
lastCellStyle.width = smallCellWidth;
lastCellStyle.height = smallCellHeight;
}
return {
big: bigCellStyle,
small: smallCellStyle,
last: lastCellStyle,
options: {
firstRatio: firstRatio,
// keep these value because ng style need add measured suffix
smallCellWidth: smallCellStyle.width,
smallCellHeight: smallCellStyle.height,
bigCellWidth: bigCellStyle.width,
bigCellHeight: bigCellStyle.height,
cellCount: cellCount,
is2First: is2First
} //keep these values to style cell image after building style for cell link
}
}
getWidthRate = function(firstRatio, cellCount) {
if (cellCount == 2) { //build style for 2 images
if(firstRatio > 1) {
return 2/3;
} else {
return 1/2;
}
} else if(firstRatio > 1) { //build style for >= 3 images, first image has firstRatio > 1
return 1
} else { //build style for >= 3 images, first image has firstRatio < 1
return 2/3
}
}
scope.getCellStyles = function() {
var firstImage, secondImage, cellCount, buildedStyle;
firstImage = scope.takenImages[0];
secondImage = scope.takenImages[1];
cellCount = scope.takenImages.length;
if (cellCount == 1) { //build style for only one image
//#todo need implement!
} else { //build style for >=2 images
buildedStyle = buildCellStyle(firstImage, secondImage, cellCount);
}
// remove margin right of last small cell in the bottom
if(buildedStyle.small.marginRight) {
buildedStyle.last.marginRight = 0;
buildedStyle.last.width = buildedStyle.small.width + MARGIN;
}
// remove margin bottom of last small cell in the right
if(buildedStyle.small.marginBottom) {
buildedStyle.last.marginBottom = 0;
buildedStyle.last.height = buildedStyle.small.height + MARGIN;
}
// add suffix px for margin and size for ng-style working
var attrs = ["width", "height", "marginRight", "marginLeft", "marginBottom", "left", "right"];
angular.forEach(attrs, function(attr, index) {
if(buildedStyle.big[attr]) {
buildedStyle.big[attr] += "px";
}
if(buildedStyle.small[attr]) {
buildedStyle.small[attr] += "px";
}
if(buildedStyle.last[attr]) {
buildedStyle.last[attr] += "px";
}
})
return buildedStyle;
}
//trigger build grid
scope.$watch("images", function(images) {
if(images && images.length > 0) {
scope.preloadImages(images);
}
})
}
return {
restrict: "A",
templateUrl: "photo_grid.html",
scope: {
images: "=",
gridOptions: "="
},
controller: ["$scope", "$element", function($scope, $element) {
this.notifyDOMReady = function() {
$scope.defaultOptions.onDOMReady($element)
}
}],
link: linker
}
}])
angular.module("ngApp", ["ngPhotoGrid"])
angular.module("ngApp").controller("indexCtrl", ["$scope", function($scope){
//show loading mark while grid is building
$scope.isBuildingGrid = true;
// production test
img1 = {original_url: "http://lorempixel.com/1366/768"};
img2 = {original_url: "http://lorempixel.com/316/316"};
img3 = {original_url: "http://lorempixel.com/400/200"};
img4 = {original_url: "http://lorempixel.com/600/1000"};
img5 = {original_url: "http://lorempixel.com/600/800"};
img6 = {original_url: "http://lorempixel.com/800/600"};
img7 = {original_url: "http://lorempixel.com/800/800"};
img8 = {original_url: "http://lorempixel.com/900/1000"};
// // local dev
// img1 = {original_url: "images/1366x768.jpg"};
// img2 = {original_url: "images/316x316.jpg"};
// img3 = {original_url: "images/600x1000.jpg"};
// img4 = {original_url: "images/900x1000.jpg"};
// img5 = {original_url: "images/600x800.jpg"};
// img6 = {original_url: "images/800x600.jpg"};
// img7 = {original_url: "images/800x800.jpg"};
// img8 = {original_url: "images/900x1000.jpg"};
var sources = [img1, img2, img3, img4, img5, img6, img7, img8]
var sources2big = [{original_url: "http://lorempixel.com/316/316", nth: 1}, {original_url: "http://lorempixel.com/800/800", nth: 2}, img3, img4, img5, img6]
$scope.rand = function(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
$scope.clickHandler = function(image) {
alert(JSON.stringify(image))
}
$scope.buildCompletedHandler = function() {
console.log ("built completed!")
$scope.isBuildingGrid = false;
}
getSelectedSeeds = function() {
var photoNumbers = $scope.rand(2, 7)
var seeds = []
var arr = []
while(arr.length < photoNumbers){
var randomnumber = $scope.rand(1, 8);
var found = false;
for(var i = 0; i < arr.length; i++){
if(arr[i] == randomnumber ){
found = true;
break;
}
}
if(!found) {
arr[arr.length] = randomnumber;
seeds.push(sources[randomnumber])
}
}
return seeds;
}
$scope.images = getSelectedSeeds();
$scope.images2big = sources2big.slice(0, 7);
/**
* Options definitions
*----------------------*/
$scope.gridOptions = {
urlKey : "original_url",
sortKey : "nth",
onClicked : function(image) {
alert(JSON.stringify(image))
},
onBuilded : function() {
console.log ("built completed!")
$scope.isBuildingGrid = false;
},
margin : 2,
maxLength : 5
}
/**
* Options definitions for square example
*----------------------------------------*/
$scope.gridOptionsSquare = {
urlKey : "original_url",
sortKey : "nth",
onClicked : function(image) {
alert(JSON.stringify(image))
},
onBuilded : function() {
console.log ("built completed!")
$scope.isBuildingGrid = false;
},
margin : 2,
isSquare : true,
maxLength : 4
}
$scope.squareGridGroup = [];
angular.forEach([1,2,3,4,5,6], function() {
$scope.squareGridGroup.push(angular.copy(getSelectedSeeds()))
})
}])
/**
* All these styles are not a part of angular module.
*/
.center {
text-align: center;
}
.small {
font-size:12px;
font-weight: normal;
margin-left: 10px;
}
.wrapper {
text-align: center;
}
.content {
width: 400px;
margin: 0 auto;
}
.feed-item{
overflow: hidden;
}
.feed-photos {
position: relative;
min-height: 100px;
}
.feed-photos.loading::after {
content: "";
height: 100%;
width: 100%;
background: rgba(0,0,0,.6) url("loader.gif") center center no-repeat;
left:0;
top:0;
position: absolute;
}
.feed-photos.loading .grid-cell-image{
width: 100%;
}
/**
* It's the part of module
* used to style the border of grid
* included this style if you want to border the grid cell
*/
.grid-cell:after {
content: '';
position: absolute;
border: 1px solid rgba(0, 0, 0, 0.2); /*change this color if you want*/
top: 0;
right: 0;
bottom: 0;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
<style>
body { text-align: center; }
.links a { padding: 0 5px ;}
.active { color: red;}
</style>
</head>
<body ng-app='ngApp'>
<div class='wrapper' ng-controller="indexCtrl">
<div class="header">
<h1>ngPhotoGrid Example - 2 bigs first</h1>
</div>
<div class='content'>
<div class="feed-item">
<div ng-photo-grid = ""
images = "images2big"
grid-options = "gridOptions"
ng-class = "{'loading': isBuildingGrid}"
class = "feed-photos">
</div>
</div>
<p class='small'><i>click on image or turn on firebug to see the callback.</i></p>
</div>
<div class='footer'>
<p>source on github</p>
</div>
</div>
There is an easier way to do this by using pure css: column-count and column-width.
Here's a fiddle (https://jsfiddle.net/3z73obt0/1/)
And here's the code:
#wrapper {
-moz-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
-moz-column-gap: 10px;
-webkit-column-gap: 10px;
column-gap: 10px;
}
#wrapper > div:nth-child(n+2) {
margin-top:10px;
}
#wrapper > div:nth-child(1) {
height: 150px;
width:100%;
background-color:#8ebce5;
}
#wrapper > div:nth-child(2) {
height: 150px;
width:100%;
background-color:#3a2313;
}
#wrapper > div:nth-child(3) {
height: 100px;
width:100%;
background-color:peru;
}
#wrapper > div:nth-child(4) {
height: 100px;
width:100%;
background-color:#BB3579;
}
#wrapper > div:nth-child(5) {
height: 100px;
width:100%;
background-color:#EAC243;
}
<div id="wrapper">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
If you would still prefer using a library, I would suggest having a look at the isotope library to achieve this. (http://isotope.metafizzy.co/).
Here's a codepen of a nice masonry layout made with isotope: http://codepen.io/desandro/pen/mIkhq
Have you tried ngPhotoGrid? https://github.com/jerryc-nguyen/ng-photo-grid
A simple compact photo grid like Facebook in AngularJS with no dependencies.
From looking at its Examples it looks like what you are looking for.

Custom cursor not supported in Edge?

if(!CSS.supports('cursor', 'url(cursor.png), pointer')) {
var myCursor = document.createElement('img');
myCursor.src = 'cursor.png';
myCursor.style.position = 'absolute';
document.body.appendChild(myCursor);
document.addEventListener('mousemove', function(e) {
myCursor.style.left = e.pageX+'px';
myCursor.style.top = e.pageY+'px';
}, false);
}
body{
padding:0;
margin:0;
background-color: #19321D;
color: #53CC66;
line-height: 1.5;
font-family: FreeMono, monospace;
cursor: url(cursor.png), pointer;
}
a{
text-decoration: none;
color: #53CC66;
}
ul{
text-decoration: none;
list-style-type: none;
}
#header{
text-align: center;
border-bottom: 3px solid #53CC66;
margin-bottom: 100px;
width: 90%;
margin-left: auto;
margin-right: auto;
margin-top: 25px;
line-height: 1;
}
h1, h2, h3{
color: #53CC66;
font-family: FreeMono, monospace;
font-size: 15px;
}
a{
cursor: url(cursor.png), pointer;
}
a:hover {
cursor: url(cursor.png), pointer;
color: #19321D;
}
li:hover{
background-color:#53CC66;
color: #19321D;
}
li:hover a{
color: #19321D;
}
<html>
<head>
<title>Getrate|Command promph </title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="styles15.css" type="text/css" />
</head>
<body>
<div id="wrapper">
<div id="header">
<h1>DAVID SECRET INDUSTRIES UNVERIFIED SYSTEM</h1>
<h2>COPYRIGHT 2015 - 2050 ALL RIGHT RESERVED</h2>
<h3>- SERVER #1 -</h3>
</div>
<ul>
<li>[CONZOLE] > -TOP SECRET- . PAGE //stripslash 1.3.8.9.84.113.21.73</li>
<li>[CONZOLE] > -TOP SECRET- . PAGE //stripslash 1.4.8.9.84.113.21.74</li>
<li>[CONZOLE] > -TOP SECRET- . PAGE //stripslash 1.5.8.9.84.113.21.75</li>
<li>[CONZOLE] > -TOP SECRET- . PAGE //stripslash 1.6.8.9.84.113.21.76</li>
<li>[CONZOLE] > -TOP SECRET- . PAGE //stripslash 1.7.8.9.84.113.21.77</li>
</ul>
</div>
</body>
<script src="wow.js"></script>
</html>
I just thought, is there any possible way, to make custom cursor, that works on microsoft edge? On my website, i used this:
body{ cursor: url(cursor.png), pointer;}
but in microsoft edge, it is not working...
Any ideas how to solve this?/Is there any other way?
So.... after small recode, my website looks like this, see the fiddle and try, it is not working yet...
This property is not supported yet : http://caniuse.com/#search=cursor
This property is now supported : caniuse.com:cursor:url()
As Charaf mentioned: the property isn't yet supported in Edge. If your project requires a solution, you can sort of mimic the behavior with JavaScript.
JavaScript:
if(!CSS.supports('cursor', 'url(cursor.png), pointer')) {
var myCursor = document.createElement('img');
myCursor.src = 'cursor.png';
myCursor.style.position = 'absolute';
document.body.appendChild(myCursor);
document.addEventListener('mousemove', function(e) {
myCursor.style.left = e.pageX+'px';
myCursor.style.top = e.pageY+'px';
}, false);
}
I made a library called CursorJS for you. You can check it out here. If you scroll to the bottom of the JavaScript code, you can find initializing code:
/* Enable lib with cursor image src */
CursorJS.enable('http://files.softicons.com/download/toolbar-icons/plastic-mini-icons-by-deleket/png/32x32/Cursor-01.png');
CursorJS.addEl(document.querySelector('.myElement1'));
CursorJS.addEl(document.querySelector('.myElement3'));
In your case just do the following:
/* Enable lib with cursor image src */
CursorJS.enable('./cursor.png');
CursorJS.addEl(document.body);
Customization
CursorJS has a mouseOffset variable. It repesents difference of mouse position and position of image. For example, if I set it to
mouseOffset: {
x: 50,
y: 50
},
The mouse will be 50px off. The reason why I made this variable is that custom mouse was kind of "blinking", try to set it to {x:1,y:1} ;)
Live example
var CursorJS = {
img: new Image(),
els: [],
mouseOffset: {
x: 5,
y: 5
},
addedImg: false,
checkForIE: function() {
return (/MSIE/i.test(navigator.userAgent)
|| /rv:11.0/i.test(navigator.userAgent));
},
setDisplay: function() {
this.img.style.display =
this.els.indexOf(true) > -1 ? null : 'none';
},
getMouseCoords: function(e) {
var mx = 0, my = 0;
if (this.checkForIE())
mx = event.clientX + document.body.scrollLeft,
my = event.clientY + document.body.scrollTop;
else
mx = e.pageX,my = e.pageY;
if (mx < 0) mx = 0;
if (my < 0) my = 0;
return [mx, my];
},
mouseOver: function(e, id) {
this.els[id] = true;
this.setDisplay();
var coords = this.getMouseCoords(e);
this.img.style.left =
(coords[0]+this.mouseOffset.x) + 'px';
this.img.style.top =
(coords[1]+this.mouseOffset.y) + 'px';
},
mouseOut: function(e, id) {
this.els[id] = false;
this.setDisplay();
},
mouseMove: function(e) {
var coords = this.getMouseCoords(e);
this.img.style.left =
(coords[0]+this.mouseOffset.x) + 'px';
this.img.style.top =
(coords[1]+this.mouseOffset.y) + 'px';
},
addEvent: function(el, name, func, bool) {
if (el == null || typeof name != 'string'
|| typeof func != 'function'
|| typeof bool != 'boolean')
return;
if (el.addEventListener)
el.addEventListener(name, func, false);
else if (el.attachEvent)
el.attachEvent('on' + name, func);
else
el['on' + name] = func;
},
addEl: function(el) {
var evts = ['over','out','move'],
id = this.els.length;
this.els.push(false);
this.el = el;
this.addEvent(el, 'mouseover', function(e) {
this.mouseOver(e, id) }.bind(this), false);
this.addEvent(el, 'mouseout', function(e) {
this.mouseOut(e, id) }.bind(this), false);
this.addEvent(el, 'mousemove', function(e) {
this.mouseMove(e) }.bind(this), false);
if (typeof el['style'] != 'undefined')
el.style.cursor = 'none';
},
enable: function(src) {
this.img.src = src;
this.img.style.display = 'none';
this.img.style.position = 'absolute';
this.img.style.cursor = 'none';
this.addEvent(this.img, 'mousemove', function(e) {
this.mouseMove(e) }.bind(this), false);
if (!this.addedImg)
document.body.appendChild(this.img),
this.addedImg = true;
}
}
/*** INITIALIZE ***/
CursorJS.enable('http://files.softicons.com/download/toolbar-icons/plastic-mini-icons-by-deleket/png/32x32/Cursor-01.png');
CursorJS.addEl(document.querySelector('.myElement1'));
CursorJS.addEl(document.querySelector('.myElement3'));
.myElement1, .myElement2, .myElement3 {
width: 150px;
height: 150px;
border: 1px solid gray;
display: inline-block;
}
<div class="myElement1">added</div>
<div class="myElement2">not added</div>
<div class="myElement3">added</div>
Hope that worked! Have a nice day :)

Mobile Safari Crashing with background-position css

I have the following code which crashes in mobile safari, works in all other browsers. I have a checkbox that is using jquery plugin for displaying a nicer image when it is checked. The issue seems to be in the background-position attribute support in Safari-mobile but I don't know how to fix it.
<input type="checkbox" id="terms" data-bind="checked: termsOfUseAccepted" >
<label for="terms" class="" data-bind="text:TermsLabel"></label>
<div class="chk-overview ">
<h2 >Continue</h2>
</div>
Following Javascript is used
$(function () {
var isTouch = false;
try { isTouch = "ontouchstart" in window; } catch (e) { }
var $activeTip = null;
if (isTouch) {
document.ontouchstart = function () {
if ($activeTip) {
$activeTip.data("close").call($activeTip);
$activeTip = null;
}
};
}
function courseViewModel() {
var self = this;
self.termsOfUseAccepted = ko.observable(false);
self.TermsLabel = ko.observable('I understand');
self.continueDisplay = ko.computed({
read: function() {
return self.termsOfUseAccepted();
},
owner: this,
deferEvaluation: true
});
};
var viewModel = new courseViewModel();
ko.applyBindings(viewModel);
});
(function($) {
$.fn.hoverIntent = function(f, g) {
var cfg = {sensitivity: 7,interval: 100,timeout: 0};
cfg = $.extend(cfg, g ? {over: f,out: g} : f);
var cX, cY, pX, pY;
var track = function(ev) {
cX = ev.pageX;
cY = ev.pageY
};
var compare = function(ev, ob) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
if ((Math.abs(pX - cX) + Math.abs(pY - cY)) < cfg.sensitivity) {
$(ob).unbind("mousemove", track);
ob.hoverIntent_s = 1;
return cfg.over.apply(ob, [ev])
} else {
pX = cX;
pY = cY;
ob.hoverIntent_t = setTimeout(function() {
compare(ev, ob)
}, cfg.interval)
}
};
var delay = function(ev, ob) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
ob.hoverIntent_s = 0;
return cfg.out.apply(ob, [ev])
};
var handleHover = function(e) {
var ev = jQuery.extend({}, e);
var ob = this;
if (ob.hoverIntent_t) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t)
}
if (e.type == "mouseenter") {
pX = ev.pageX;
pY = ev.pageY;
$(ob).bind("mousemove", track);
if (ob.hoverIntent_s != 1) {
ob.hoverIntent_t = setTimeout(function() {
compare(ev, ob)
}, cfg.interval)
}
} else {
$(ob).unbind("mousemove", track);
if (ob.hoverIntent_s == 1) {
ob.hoverIntent_t = setTimeout(function() {
delay(ev, ob)
}, cfg.timeout)
}
}
};
return this.bind('mouseenter', handleHover).bind('mouseleave', handleHover)
}
})(jQuery);
(function($) {
jQuery.fn.customInput = function () {
$(this).each(function (i) {
if ($(this).is('[type=checkbox],[type=radio]')) {
var input = $(this);
if (input.data('customInput') === 'done') {
return true;
}
else {
input.data('customInput', 'done');
}
// get the associated label using the input's id
var label = $('label[for=' + input.attr('id') + ']');
//get type, for classname suffix
var inputType = (input.is('[type=checkbox]')) ? 'checkbox' : 'radio';
// wrap the input + label in a div
$('<div class="custom-' + inputType + '"></div>').insertBefore(input).append(input, label);
// find all inputs in this set using the shared name attribute
var allInputs = $('input[name=' + input.attr('name') + ']');
// necessary for browsers that don't support the :hover pseudo class on labels
label.hover(
function () {
$(this).addClass('hover');
if (inputType == 'checkbox' && input.is(':checked')) {
$(this).addClass('checkedHover');
}
},
function () { $(this).removeClass('hover checkedHover'); }
);
//bind custom event, trigger it, bind click,focus,blur events
input.bind('updateState', function () {
if (input.is(':checked')) {
if (input.is(':radio')) {
allInputs.each(function () {
$('label[for=' + $(this).attr('id') + ']').removeClass('checked');
});
};
label.addClass('checked');
}
else { label.removeClass('checked checkedHover checkedFocus'); }
})
.trigger('updateState')
.click(function () {
if (input.is(':checked')) {
if (input.is(':radio')) {
allInputs.each(function () {
$('label[for=' + $(this).attr('id') + ']').removeClass('checked');
});
};
label.addClass('checked');
}
else { label.removeClass('checked checkedHover checkedFocus'); }
})
.focus(function () {
label.addClass('focus');
if (inputType == 'checkbox' && input.is(':checked')) {
$(this).addClass('checkedFocus');
}
})
.blur(function () { label.removeClass('focus checkedFocus'); });
}
});
};
})(jQuery);
$.fn.smartHover = function (configObject) {
if (isTouch) {
$(this)
.bind("hold", function () {
$activeTip = $(this);
$(this).data("held", true);
})
.bind("hold", configObject.over)
.bind("click", function (e) {
var wasHeld = $(this).data("held");
$(this).data("held", false);
if (wasHeld) {
e.preventDefault();
return false;
}
})
.data("close", configObject.out);
} else {
$(this).hoverIntent(configObject);
}
};
$('input').customInput();
And here is the css
.chk-overview h2 { font: 24px "StoneSansITCW01-SemiBol 735693",sans-serif; margin-bottom: 20px;padding: 0 }
.custom-checkbox label {
background: transparent url(http://aonhewittnavigators.com/AonExchange/media/Image-Gallery/SiteImages/checkbox.png) no-repeat;
outline: 0;
background-position: 0 0;
}
.custom-checkbox label {
cursor: pointer;
display: block;
height: 19px;
outline: 0;
position: relative;
width: 21px;
z-index: 1;
}
.custom-checkbox label.checked {
background-position: 0 bottom;
padding: 0;
}
.custom-checkbox input {
left: 1px;
margin: 0;
outline: 0;
position: absolute;
top: 5px;
z-index: 0;
height: 0;
}
Try removing the height: 0 on the checkbox style. I have seen it crash when the height or width attribute is set on the checkbox input.

Javascript or CSS hover not working in Safari and Chrome

I have a problem with a script for a image gallery. The problem seems to only occur on Safari and Chrome, but if I refresh the page I get it to work correctly - weird!
Correct function:
The gallery has a top bar, which if you hover over it, it will display a caption. Below sits the main image. At the bottom there is another bar that is a reversal of the top bar. When you hover over it, it will display thumbnails of the gallery.
The problem:
In Safari and Chrome, the thumbnail holder will not display. In fact, it doesn't even show it as an active item (or a rollover). But oddly enough, if you manually refresh the page it begins to work correctly for the rest of the time you view the page. Once you have left the page and return the same error occurs again and you have to go through the same process.
Here's one of the pages to look at:
link text
Here's the CSS:
#ThumbsGutter {
background: url(../Images/1x1.gif);
background: url(/Images/1x1.gif);
height: 105px;
left: 0px;
position: absolute;
top: 0px;
width: 754px;
z-index: 2;
}
#ThumbsHolder {
display: none;
}
#ThumbsTable {
left: 1px;
}
#Thumbs {
background-color: #000;
width: 703px;
}
#Thumbs ul {
list-style: none;
margin: 0;
padding: 0;
}
#Thumbs ul li {
display: inline;
}
.Thumbs ul li a {
border-right: 1px solid #fff;
border-top: 1px solid #fff;
float: left;
left: 1px;
}
.Thumbs ul li a img {
filter: alpha(opacity=50);
height: 104px;
opacity: .5;
width: 140px;
}
.Thumbs ul li a img.Hot {
filter: alpha(opacity=100);
opacity: 1;
}
Here is the javascript:
//Variables
var globalPath = "";
var imgMain;
var gutter;
var holder;
var thumbs;
var loadingImage;
var holderState;
var imgCount;
var imgLoaded;
var captionHolder;
var captionState = 0;
var captionHideTimer;
var captionHideTime = 500;
var thumbsHideTimer;
var thumbsHideTime = 500;
$(document).ready(function() {
//Load Variables
imgMain = $("#MainImage");
captionHolder = $("#CaptionHolder");
gutter = $("#ThumbsGutter");
holder = $("#ThumbsHolder");
thumbs = $("#Thumbs");
loadingImage = $("#LoadingImageHolder");
//Position Loading Image
loadingImage.centerOnObject(imgMain);
//Caption Tab Event Handlers
$("#CaptionTab").mouseover(function() {
clearCaptionHideTimer();
showCaption();
}).mouseout(function() {
setCaptionHideTimer();
});
//Caption Holder Event Handlers
captionHolder.mouseenter(function() {
clearCaptionHideTimer();
}).mouseleave(function() {
setCaptionHideTimer();
});
//Position Gutter
if (jQuery.browser.safari) {
gutter.css("left", imgMain.position().left + "px").css("top", ((imgMain.offset().top + imgMain.height()) - 89) + "px");
} else {
gutter.css("left", imgMain.position().left + "px").css("top", ((imgMain.offset().top + imgMain.height()) - 105) + "px");
}
//gutter.css("left", imgMain.position().left + "px").css("top", ((imgMain.offset().top + imgMain.height()) - 105) + "px");
//gutter.css("left", imgMain.offset().left + "px").css("top", ((imgMain.offset().top + imgMain.height()) - gutter.height()) + "px");
//Thumb Tab Event Handlers
$("#ThumbTab").mouseover(function() {
clearThumbsHideTimer();
showThumbs();
}).mouseout(function() {
setThumbsHideTimer();
});
//Gutter Event Handlers
gutter.mouseenter(function() {
//showThumbs();
clearThumbsHideTimer();
}).mouseleave(function() {
//hideThumbs();
setThumbsHideTimer();
});
//Next/Prev Button Event Handlers
$("#btnPrev").mouseover(function() {
$(this).attr("src", globalPath + "/Images/GalleryLeftButtonHot.jpg");
}).mouseout(function() {
$(this).attr("src", globalPath + "/Images/GalleryLeftButton.jpg");
});
$("#btnNext").mouseover(function() {
$(this).attr("src", globalPath + "/Images/GalleryRightButtonHot.jpg");
}).mouseout(function() {
$(this).attr("src", globalPath + "/Images/GalleryRightButton.jpg");
});
//Load Gallery
//loadGallery(1);
});
function loadGallery(galleryID) {
//Hide Holder
holderState = 0;
holder.css("display", "none");
//Hide Empty Gallery Text
$("#EmptyGalleryText").css("display", "none");
//Show Loading Message
$("#LoadingGalleryOverlay").css("display", "inline").centerOnObject(imgMain);
$("#LoadingGalleryText").css("display", "inline").centerOnObject(imgMain);
//Load Thumbs
thumbs.load(globalPath + "/GetGallery.aspx", { GID: galleryID }, function() {
$("#TitleHolder").html($("#TitleContainer").html());
$("#DescriptionHolder").html($("#DescriptionContainer").html());
imgCount = $("#Thumbs img").length;
imgLoaded = 0;
if (imgCount == 0) {
$("#LoadingGalleryText").css("display", "none");
$("#EmptyGalleryText").css("display", "inline").centerOnObject(imgMain);
} else {
$("#Thumbs img").load(function() {
imgLoaded++;
if (imgLoaded == imgCount) {
holder.css("display", "inline");
//Carousel Thumbs
thumbs.jCarouselLite({
btnNext: "#btnNext",
btnPrev: "#btnPrev",
mouseWheel: true,
scroll: 1,
visible: 5
});
//Small Image Event Handlers
$("#Thumbs img").each(function(i) {
$(this).mouseover(function() {
$(this).addClass("Hot");
}).mouseout(function() {
$(this).removeClass("Hot");
}).click(function() {
//Load Big Image
setImage($(this));
});
});
holder.css("display", "none");
//Load First Image
var img = new Image();
img.onload = function() {
imgMain.attr("src", img.src);
setCaption($("#Image1").attr("alt"));
//Hide Loading Message
$("#LoadingGalleryText").css("display", "none");
$("#LoadingGalleryOverlay").css("display", "none");
}
img.src = $("#Image1").attr("bigimg");
}
});
}
});
}
function showCaption() {
if (captionState == 0) {
$("#CaptionTab").attr("src", globalPath + "/Images/CaptionTabHot.jpg");
captionHolder.css("display", "inline").css("left", imgMain.position().left + "px").css("top", imgMain.position().top + "px").css("width", imgMain.width() + "px").effect("slide", { "direction": "up" }, 500, function() {
captionState = 1;
});
}
}
function hideCaption() {
if (captionState == 1) {
captionHolder.toggle("slide", { "direction": "up" }, 500, function() {
$("#CaptionTab").attr("src", globalPath + "/Images/CaptionTab.jpg");
captionState = 0;
});
}
}
function setCaptionHideTimer() {
captionHideTimer = window.setTimeout(hideCaption,captionHideTime);
}
function clearCaptionHideTimer() {
if(captionHideTimer) {
window.clearTimeout(captionHideTimer);
captionHideTimer = null;
}
}
function showThumbs() {
if (holderState == 0) {
$("#ThumbTab").attr("src", globalPath + "/Images/ThumbTabHot.jpg");
holder.effect("slide", { "direction": "down" }, 500, function() {
holderState = 1;
});
}
}
function hideThumbs() {
if (holderState == 1) {
if (jQuery.browser.safari) {
holder.css("display", "none");
$("#ThumbTab").attr("src", globalPath + "/Images/ThumbTab.jpg");
holderState = 0;
} else {
holder.toggle("slide", { "direction": "down" }, 500, function() {
$("#ThumbTab").attr("src", globalPath + "/Images/ThumbTab.jpg");
holderState = 0;
});
}
}
}
function setThumbsHideTimer() {
thumbsHideTimer = window.setTimeout(hideThumbs,thumbsHideTime);
}
function clearThumbsHideTimer() {
if(thumbsHideTimer) {
window.clearTimeout(thumbsHideTimer);
thumbsHideTimer = null;
}
}
function setImage(image) {
//Show Loading Image
loadingImage.css("display", "inline");
var img = new Image();
img.onload = function() {
//imgMain.css("background","url(" + img.src + ")").css("display","none").fadeIn(250);
imgMain.attr("src", img.src).css("display", "none").fadeIn(250);
setCaption(image.attr("alt"));
//Hide Loading Image
loadingImage.css("display", "none");
};
img.src = image.attr("bigimg");
}
function setCaption(caption) {
$("#CaptionText").html(caption);
//alert($("#CaptionText").html());
/*
if (caption.length > 0) {
$("#CaptionText")
.css("display", "inline")
.css("left", imgMain.position().left + "px")
.css("top", imgMain.position().top + "px")
.css("width", imgMain.width() + "px")
.html(caption);
$("#CaptionOverlay").css("display", "inline")
.css("height", $("#CaptionText").height() + 36 + "px")
.css("left", imgMain.position().left + "px")
.css("top", imgMain.position().top + "px")
.css("width", imgMain.width() + "px");
} else {
$("#CaptionText").css("display", "none");
$("#CaptionOverlay").css("display", "none");
}
*/
}
Please if anyone could help, it would be greatly appreciated!
Thanks in advance.
Justin
I'm using Chrome 4.1.249.1064 and the top bar works perfect, I see the caption without refreshing the page.
The same in Firefox 3.6.3, all works perfect
Same with Safari 4.0.3, all works perfect

Resources