Styling Google Maps InfoWindow - css

I've been attempting to style my Google Maps InfoWindow, but the documentation is very limited on this topic. How do you style an InfoWindow?

Google wrote some code to assist with this. Here are some examples: Example using InfoBubble, Styled markers and Info Window Custom (using OverlayView).
The code in the links above take different routes to achieve similar results. The gist of it is that it is not easy to style InfoWindows directly, and it might be easier to use the additional InfoBubble class instead of InfoWindow, or to override GOverlay. Another option would be to modify the elements of the InfoWindow using javascript (or jQuery), like later ATOzTOA suggested.
Possibly the simplest of these examples is using InfoBubble instead of InfoWindow. InfoBubble is available by importing this file (which you should host yourself): http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobubble/src/infobubble.js
InfoBubble's Github project page.
InfoBubble is very stylable, compared to InfoWindow:
infoBubble = new InfoBubble({
map: map,
content: '<div class="mylabel">The label</div>',
position: new google.maps.LatLng(-32.0, 149.0),
shadowStyle: 1,
padding: 0,
backgroundColor: 'rgb(57,57,57)',
borderRadius: 5,
arrowSize: 10,
borderWidth: 1,
borderColor: '#2c2c2c',
disableAutoPan: true,
hideCloseButton: true,
arrowPosition: 30,
backgroundClassName: 'transparent',
arrowStyle: 2
});
infoBubble.open();
You can also call it with a given map and marker to open on:
infoBubble.open(map, marker);
As another example, the Info Window Custom example extends the GOverlay class from the Google Maps API and uses this as a base for creating a more flexible info window. It first creates the class:
/* An InfoBox is like an info window, but it displays
* under the marker, opens quicker, and has flexible styling.
* #param {GLatLng} latlng Point to place bar at
* #param {Map} map The map on which to display this InfoBox.
* #param {Object} opts Passes configuration options - content,
* offsetVertical, offsetHorizontal, className, height, width
*/
function InfoBox(opts) {
google.maps.OverlayView.call(this);
this.latlng_ = opts.latlng;
this.map_ = opts.map;
this.offsetVertical_ = -195;
this.offsetHorizontal_ = 0;
this.height_ = 165;
this.width_ = 266;
var me = this;
this.boundsChangedListener_ =
google.maps.event.addListener(this.map_, "bounds_changed", function() {
return me.panMap.apply(me);
});
// Once the properties of this OverlayView are initialized, set its map so
// that we can display it. This will trigger calls to panes_changed and
// draw.
this.setMap(this.map_);
}
after which it proceeds to override GOverlay:
InfoBox.prototype = new google.maps.OverlayView();
You should then override the methods you need: createElement, draw, remove and panMap. It gets rather involved, but in theory you are just drawing a div on the map yourself now, instead of using a normal Info Window.

You can modify the whole InfoWindow using jquery alone...
var popup = new google.maps.InfoWindow({
content:'<p id="hook">Hello World!</p>'
});
Here the <p> element will act as a hook into the actual InfoWindow. Once the domready fires, the element will become active and accessible using javascript/jquery, like $('#hook').parent().parent().parent().parent().
The below code just sets a 2 pixel border around the InfoWindow.
google.maps.event.addListener(popup, 'domready', function() {
var l = $('#hook').parent().parent().parent().siblings();
for (var i = 0; i < l.length; i++) {
if($(l[i]).css('z-index') == 'auto') {
$(l[i]).css('border-radius', '16px 16px 16px 16px');
$(l[i]).css('border', '2px solid red');
}
}
});
You can do anything like setting a new CSS class or just adding a new element.
Play around with the elements to get what you need...

I used the following code to apply some external CSS:
boxText = document.createElement("html");
boxText.innerHTML = "<head><link rel='stylesheet' href='style.css'/></head><body>[some html]<body>";
infowindow.setContent(boxText);
infowindow.open(map, marker);

google.maps.event.addListener(infowindow, 'domready', function() {
// Reference to the DIV that wraps the bottom of infowindow
var iwOuter = $('.gm-style-iw');
/* Since this div is in a position prior to .gm-div style-iw.
* We use jQuery and create a iwBackground variable,
* and took advantage of the existing reference .gm-style-iw for the previous div with .prev().
*/
var iwBackground = iwOuter.prev();
// Removes background shadow DIV
iwBackground.children(':nth-child(2)').css({'display' : 'none'});
// Removes white background DIV
iwBackground.children(':nth-child(4)').css({'display' : 'none'});
// Moves the infowindow 115px to the right.
iwOuter.parent().parent().css({left: '115px'});
// Moves the shadow of the arrow 76px to the left margin.
iwBackground.children(':nth-child(1)').attr('style', function(i,s){ return s + 'left: 76px !important;'});
// Moves the arrow 76px to the left margin.
iwBackground.children(':nth-child(3)').attr('style', function(i,s){ return s + 'left: 76px !important;'});
// Changes the desired tail shadow color.
iwBackground.children(':nth-child(3)').find('div').children().css({'box-shadow': 'rgba(72, 181, 233, 0.6) 0px 1px 6px', 'z-index' : '1'});
// Reference to the div that groups the close button elements.
var iwCloseBtn = iwOuter.next();
// Apply the desired effect to the close button
iwCloseBtn.css({opacity: '1', right: '38px', top: '3px', border: '7px solid #48b5e9', 'border-radius': '13px', 'box-shadow': '0 0 5px #3990B9'});
// If the content of infowindow not exceed the set maximum height, then the gradient is removed.
if($('.iw-content').height() < 140){
$('.iw-bottom-gradient').css({display: 'none'});
}
// The API automatically applies 0.7 opacity to the button after the mouseout event. This function reverses this event to the desired value.
iwCloseBtn.mouseout(function(){
$(this).css({opacity: '1'});
});
});
//CSS put in stylesheet
.gm-style-iw {
background-color: rgb(237, 28, 36);
border: 1px solid rgba(72, 181, 233, 0.6);
border-radius: 10px;
box-shadow: 0 1px 6px rgba(178, 178, 178, 0.6);
color: rgb(255, 255, 255) !important;
font-family: gothambook;
text-align: center;
top: 15px !important;
width: 150px !important;
}

I have design google map infowindow with image & some content as per below.
map_script (Just for infowindow html reference)
for (i = 0; i < locations.length; i++) {
var latlng = new google.maps.LatLng(locations[i][1], locations[i][2]);
marker = new google.maps.Marker({
position: latlng,
map: map,
icon: "<?php echo plugins_url( 'assets/img/map-pin.png', ELEMENTOR_ES__FILE__ ); ?>"
});
var property_img = locations[i][6],
title = locations[i][0],
price = locations[i][3],
bedrooms = locations[i][4],
type = locations[i][5],
listed_on = locations[i][7],
prop_url = locations[i][8];
content = "<div class='map_info_wrapper'><a href="+prop_url+"><div class='img_wrapper'><img src="+property_img+"></div>"+
"<div class='property_content_wrap'>"+
"<div class='property_title'>"+
"<span>"+title+"</span>"+
"</div>"+
"<div class='property_price'>"+
"<span>"+price+"</span>"+
"</div>"+
"<div class='property_bed_type'>"+
"<span>"+bedrooms+"</span>"+
"<ul><li>"+type+"</li></ul>"+
"</div>"+
"<div class='property_listed_date'>"+
"<span>Listed on "+listed_on+"</span>"+
"</div>"+
"</div></a></div>";
google.maps.event.addListener(marker, 'click', (function(marker, content, i) {
return function() {
infowindow.setContent(content);
infowindow.open(map, marker);
}
})(marker, content, i));
}
Most important thing is CSS
#propertymap .gm-style-iw{
box-shadow:none;
color:#515151;
font-family: "Georgia", "Open Sans", Sans-serif;
text-align: center;
width: 100% !important;
border-radius: 0;
left: 0 !important;
top: 20px !important;
}
#propertymap .gm-style > div > div > div > div > div > div > div {
background: none!important;
}
.gm-style > div > div > div > div > div > div > div:nth-child(2) {
box-shadow: none!important;
}
#propertymap .gm-style-iw > div > div{
background: #FFF!important;
}
#propertymap .gm-style-iw a{
text-decoration: none;
}
#propertymap .gm-style-iw > div{
width: 245px !important
}
#propertymap .gm-style-iw .img_wrapper {
height: 150px;
overflow: hidden;
width: 100%;
text-align: center;
margin: 0px auto;
}
#propertymap .gm-style-iw .img_wrapper > img {
width: 100%;
height:auto;
}
#propertymap .gm-style-iw .property_content_wrap {
padding: 0px 20px;
}
#propertymap .gm-style-iw .property_title{
min-height: auto;
}

Use the InfoBox plugin from the Google Maps Utility Library. It makes styling/managing map pop-ups much easier.
Note that you'll need to make sure it loads after the google maps API:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY&callback=initMap" async defer></script>
<script src="/js/infobox_packed.js" async defer></script>

Map InfoWindow supports html and css.
I usually create html string with css class. So I can attach any style I want to.
var contentString = '<div>Any Html here</div>';
marker.infowindow = new google.maps.InfoWindow({
content: contentString,
});
Here is the ref.

You could use a css class too.
$('#hook').parent().parent().parent().siblings().addClass("class_name");
Good day!

Related

Ending a svg path drawing in FabricJs using right mouse click

I am using fabric JS version 4.5.0 working on a draw application.
I want to use the right mouse click to end the brush drawing but cannot achieve this.
please take a look at this codepen snippet (credits to michaelsboost) I am doing something similar to it.
if (tool.toString().toLowerCase() === 'pencil') {
changeObjectSelection(false);
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas);
canvas.freeDrawingBrush.strokeLineCap = $('#brushStrokeCap').val(); // butt / round / square
canvas.freeDrawingBrush.strokeLineJoin = $('#brushStrokeLineJoin').val(); // bevel / round / miter
canvas.freeDrawingBrush.strokeMiterLimit = $('#brushMiter').val();
canvas.freeDrawingBrush.width = 1;
canvas.freeDrawingBrush.color = strokePickr.getColor().toRGBA().toString();
canvas.isDrawingMode = true;
}
what changes need to be added there to use left mouse click and right mouse click interchangebly to end a svg path drawing?
currently, if you select the pencil tool, clicked using your left mouse button it starts the drawing.
If you right clicked it opens a menu, select copy image, and move your mouse.
Undesired behaviour: try to left click, the whole drawing disappears.
Desired behaviour: right mouse click should end the drawing as a svg on canvas.
// Get a reference to the canvas element
var canvas = new fabric.Canvas('canvas');
canvas.isDrawingMode = true;
// Add a rectangle to the canvas
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'green',
width: 100,
height: 100
});
canvas.add(rect);
document.onclick = hideMenu;
document.oncontextmenu = rightClick;
function hideMenu() {
document.getElementById("contextMenu").style.display = "none"
}
function rightClick(e) {
e.preventDefault();
var menu = document.getElementById("contextMenu")
menu.style.display = 'block';
menu.style.left = e.pageX + "px";
menu.style.top = e.pageY + "px";
}
.context-menu {
position: absolute;
text-align: center;
background: lightgray;
border: 1px solid black;
}
.context-menu ul {
padding: 0px;
margin: 0px;
min-width: 150px;
list-style: none;
}
.context-menu ul li {
padding-bottom: 7px;
padding-top: 7px;
border: 1px solid black;
}
.context-menu ul li a {
text-decoration: none;
color: black;
}
.context-menu ul li:hover {
background: darkgray;
}
<canvas id="canvas" width="1920px" height="1080px"></canvas>
<div id="contextMenu" class="context-menu" style="display:none">
<ul>
<li onclick="canvas.isDrawingMode = true">Drawing mode true</li>
<li onclick="canvas.isDrawingMode = false">Drawing mode false</li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script>

Combining places search and kml layers with toggle on google maps api

I am attempting to create a map with multiple kml layers that can be toggled with the google places search, but have been unsuccessful. The purpose of this is to have the ability to search an address or intersection and determine the correct response apparatus for fire or medical calls for a dispatch center, with the search being biased toward the correct county. I have the base map with just one layer working here, but I've been unable to correctly integrate the kml layer toggle with the google places search. I had received some good input from geocodezip on using the geocode function here, but I wasn't able to bias it towards the correct location or include the predictive search completion. I also like the way that my original map will zoom and center on the searched address and would like to maintain that functionality. Admittedly, I am very much lacking in ability with this, and everything I have done has been to simply copy and modify working examples that others have posted, but I have not found any working examples that include both the google places search and kml layers with toggle. This is what I have so far. Any help in getting this to work would be very much appreciated.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
.controls {
margin-top: 10px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#pac-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 300px;
}
#pac-input:focus {
border-color: #4d90fe;
}
.pac-container {
font-family: Roboto;
}
#type-selector {
color: #fff;
background-color: #4d90fe;
padding: 5px 11px 0px 11px;
}
#type-selector label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
</style>
<title>Advanced Backup Map</title>
<style>
#target {
width: 345px;
}
</style>
<script>
var kml = {
a: {
name: "Fire Response Areas",
url: "https://drive.google.com/uc?export=download&id=0B2gbIV1dXlvDVDhVLXc2N1Y5ZEE"
},
b: {
name: "SD Counties",
url: "https://drive.google.com/uc?export=download&id=0B2gbIV1dXlvDRndwdEpKTjRBeTA"
},
c: {
name: "Counties in Surrounding States",
url: "https://drive.google.com/uc?export=download&id=0B2gbIV1dXlvDRlhLTm93S2Y3eDQ"
}
// keep adding more if ye like
};
// This example adds a search box to a map, using the Google Place Autocomplete
// feature. People can enter geographical searches. The search box will return a
// pick list containing a mix of places and predicted search terms.
function initAutocomplete() {
// lets define some vars to make things easier later
var options = {
center: new google.maps.LatLng(43.64837, -96.73737),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById('map'), options);
createTogglers();
// Append Class on Select
function highlight(box, listitem) {
var selected = 'selected';
var normal = 'normal';
document.getElementById(listitem).className = (box.checked ? selected : normal);
};
function startup() {
// for example, this toggles kml a on load and updates the menu selector
var checkit = document.getElementById('a');
checkit.checked = true;
toggleKML(checkit, 'a');
highlight(checkit, 'selector1');
};
// Create the search box and link it to the UI element.
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(43.38218, -97.29373),
new google.maps.LatLng(43.92451, -96.34532));
var input = document.getElementById('pac-input');
var searchBox = new google.maps.places.SearchBox(input, {
bounds: defaultBounds
});
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
// Bias the SearchBox results towards current map's viewport.
map.addListener('bounds_changed', function() {
searchBox.setBounds(map.getBounds());
});
var markers = [];
// [START region_getplaces]
// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
searchBox.addListener('places_changed', function() {
var places = searchBox.getPlaces();
if (places.length == 0) {
return;
}
// Clear out the old markers.
markers.forEach(function(marker) {
marker.setMap(null);
});
markers = [];
// For each place, get the icon, name and location.
var bounds = new google.maps.LatLngBounds();
places.forEach(function(place) {
var icon = {
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
// Create a marker for each place.
markers.push(new google.maps.Marker({
map: map,
icon: icon,
title: place.name,
position: place.geometry.location
}));
if (place.geometry.viewport) {
// Only geocodes have viewport.
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
});
map.fitBounds(bounds);
map.setZoom(16);
map.setCenter(center);
});
// [END region_getplaces]
// the important function... kml[id].xxxxx refers back to the top
function toggleKML(checked, id) {
if (checked) {
var layer = new google.maps.KmlLayer(kml[id].url, {
preserveViewport: true,
suppressInfoWindows: false
});
// store kml as obj
kml[id].obj = layer;
kml[id].obj.setMap(map);
}
else {
kml[id].obj.setMap(null);
delete kml[id].obj;
}
};
// create the controls dynamically because it's easier, really
function createTogglers() {
var html = "<form><ul>";
for (var prop in kml) {
html += "<li id=\"selector-" + prop + "\"><input type='checkbox' id='" + prop + "'" +
" onclick='highlight(this,\"selector-" + prop + "\"); toggleKML(this.checked, this.id)' \/>" +
kml[prop].name + "<\/li>";
}
document.getElementById("toggle_box").innerHTML = html;
};
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBhTQXonppCE2eVDQO5AHy11kMn-o27m_U&libraries=places&callback=initAutocomplete"
async defer></script>
</head>
<body>
<input id="pac-input" class="controls" type="text" placeholder="Search Box">
<div id="map"></div>
<div id="toggle_box" style="position: absolute; top: 10px; right: 10px; padding: 5px; background: #fff; z-index: 1; "></div>
</body>
</html>

Set animated html5 canvas as the background without interacting with other elements?

I got the canvas working, I'm having issues trying to position it.
Specifically I want to implement them to the same effect as:
html {
background: url(back.jpg) no-repeat center center fixed;
background-size: cover;
}
for static images. Basically no interaction with other elements, and positioned as low as possible with regards to the stacking context. Additionally, I'd like to have the canvas background as compartmentalized / as segmented as possible from the rest of the code.
By segmented, I mean something like this:
<body>
<div id="backgroundContainer">
<canvas id="myCanvas"></canvas>
</div>
<div id="everythingElseContainer">
....
</div>
<script src="canvasAnimation.js"></script>
</body>
or this:
<body>
<div id="container">
<canvas id="myCanvas"></canvas>
<div id="everythingElse">
....
</div>
</div>
<script src="canvasAnimation.js"></script>
</body>
to minimize the possibility of css conflicts.
var WIDTH;
var HEIGHT;
var canvas;
var con;
var g;
var pxs = new Array();
var rint = 60;
$(document).ready(function(){
WIDTH = window.innerWidth;
HEIGHT = window.innerHeight;
canvas = document.getElementById('canvas');
$(canvas).attr('width', WIDTH).attr('height',HEIGHT);
con = canvas.getContext('2d');
for(var i = 0; i < 100; i++) {
pxs[i] = new Circle();
pxs[i].reset();
}
setInterval(draw,rint);
});
function draw() {
con.clearRect(0,0,WIDTH,HEIGHT);
for(var i = 0; i < pxs.length; i++) {
pxs[i].fade();
pxs[i].move();
pxs[i].draw();
}
}
function Circle() {
this.s = {ttl:8000, xmax:5, ymax:2, rmax:10, rt:1, xdef:960, ydef:540, xdrift:4, ydrift: 4, random:true, blink:true};
this.reset = function() {
this.x = (this.s.random ? WIDTH*Math.random() : this.s.xdef);
this.y = (this.s.random ? HEIGHT*Math.random() : this.s.ydef);
this.r = ((this.s.rmax-1)*Math.random()) + 1;
this.dx = (Math.random()*this.s.xmax) * (Math.random() < .5 ? -1 : 1);
this.dy = (Math.random()*this.s.ymax) * (Math.random() < .5 ? -1 : 1);
this.hl = (this.s.ttl/rint)*(this.r/this.s.rmax);
this.rt = Math.random()*this.hl;
this.s.rt = Math.random()+1;
this.stop = Math.random()*.2+.4;
this.s.xdrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
this.s.ydrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
}
this.fade = function() {
this.rt += this.s.rt;
}
this.draw = function() {
if(this.s.blink && (this.rt <= 0 || this.rt >= this.hl)) this.s.rt = this.s.rt*-1;
else if(this.rt >= this.hl) this.reset();
var newo = 1-(this.rt/this.hl);
con.beginPath();
con.arc(this.x,this.y,this.r,0,Math.PI*2,true);
con.closePath();
var cr = this.r*newo;
g = con.createRadialGradient(this.x,this.y,0,this.x,this.y,(cr <= 0 ? 1 : cr));
g.addColorStop(0.0, 'rgba(255,255,255,'+newo+')');
g.addColorStop(this.stop, 'rgba(77,101,181,'+(newo*.6)+')');
g.addColorStop(1.0, 'rgba(77,101,181,0)');
con.fillStyle = g;
con.fill();
}
this.move = function() {
this.x += (this.rt/this.hl)*this.dx;
this.y += (this.rt/this.hl)*this.dy;
if(this.x > WIDTH || this.x < 0) this.dx *= -1;
if(this.y > HEIGHT || this.y < 0) this.dy *= -1;
}
this.getX = function() { return this.x; }
this.getY = function() { return this.y; }
}
html, body, div, button, canvas, .containr {
padding: 0;
border: none;
margin: 0;
}
html, body, .containr{
height: 100%;
width: 100%;
background: none;
}
html, body {
font-size: 13px;
text-decoration: none;
font-family: Verdana, Geneva, sans-serif !important;
}
button {
transition: all 0.24s ease;
}
h1 {
font-size: 4rem;
}
button {
font-size: 5.6rem;
}
#pixie {
position:fixed;
z-index: 0;
background: black;
}
.containr>div {
background: blue;
}
.containr {
overflow:hidden;
color: #ffffff;
z-index: 9;
font-size: 256%;
white-space: nowrap;
display: flex;
flex-flow: column nowrap;
justify-content: space-around;
align-items: center;
align-content: center;
}
.btnz {
margin-left: 2.4%;
margin-right: 2.4%;
background: #ffffff;
background: rgba(0, 0, 0, .36);
text-shadow: 1px 1px 3px #000;
padding: 2rem;
}
.btnz:hover {
background: #3cb0fd;
text-shadow: none;
text-decoration: none;
}
/* Outline Out */
.hvr {
display: inline-block;
vertical-align: middle;
-webkit-transform: translateZ(0);
transform: translateZ(0);
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-moz-osx-font-smoothing: grayscale;
position: relative;
}
.hvr:before {
content: '';
position: absolute;
border: #e1e1e1 solid 5px;
top: -4px;
right: -4px;
bottom: -4px;
left: -4px;
-webkit-transition-duration: 0.3s;
transition-duration: 0.3s;
-webkit-transition-property: top, right, bottom, left;
transition-property: top, right, bottom, left;
}
.hvr:hover:before, .hvr:focus:before, .hvr:active:before {
top: -18px;
right: -18px;
bottom: -18px;
left: -18px;
border: #ffffff solid 8px;
}
<!doctype html>
<html lang="en">
<head datetime="2015-10-31">
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="containr">
<canvas id="canvas"></canvas>
<div>
<h1>Main Title</h1>
</div>
<div>
<button class="btnz hvr">
Button Butt
</button>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="js.js"></script>
</body>
</html>
To move objects down in the visual order use the CSS styling z-index smaller numbers move the element down under other elements, higher numbers bring it up.See MDN z-index for more info.
To set the background of an element to a canvas use
element.style.background= "url(" + canvas.toDataURL() + ")";
To isolate of compartmentalize some code the easiest way is to wrap it in a anonymous function and call it. Everything inside it is isolated. Use 'use strict' directive to ensure you do not accidentally create global scoped variables.
A normal anonymous function does nothing and can not be used.
function(){ console.log(42); }; // does nothing
But if you wrap it in () and then add the function call tokens to the end ( ) you can call it like any function.
(function(){ console.log(42); })(); // send the meaning of life,
// the universe, and everything
// to the console.
The function below wraps up a and nothing can get access to a outside the anonymous function.
(function(){
var a = 1;
})();
But you can easily forget to put var in front of a variable making the variable visible to the entire page.
(function(){
var a = 1;
outThere = 2; // Oh no this is has been placed in
// global scope because it is missing
// the var token.
})();
To stop this use the 'use strict' directive.
(function(){
"use strict"; // this must be the very first line of the function
var a = 1;
outThere = 2; // this will cause the javascript to throw a
// ReferenceError: outThere is not defined
})();
It throws an error and stop the function from running but at least you will know that you have a leak.
Everything inside the anonymous function will manage itself. Deleting itself when not needed any more. Or remaining in memory if the Javascript engine holds an internal reference.
The next function starts up and calls its own function doSomething then exits and is deleted completely including the big array.
(function(){
var bigArray = new Array(100000000);
function doSomething(){
console.log("Whats up?");
}
doSomething();
})();
The next one will create a big array and hold that array in memory for 10 seconds (lifeTime). This is because the setTimeout has given the javascript engine an internal reference to doSomething. As long as that reference exists the bigArray will remain (because of closure). After the timeout the reference his no longer need and thus disposed causing all associated referances to go as well and thus disappear. All done via the magic of garbage collection.
Info on Clouser
Info on Garbage collection MDN is out of date but I am sure a quick search on StackOverflow will help.
(function(){
var bigArray = new Array(100000000);
function doSomething(){
console.log("Big Array has had its time.");
}
setTimeout(doSomething,10000);
})();
Attaching an object to items outside the anonymous function scope will expose data in that object to the global scope.
The next function adds a property to a DOM element. This is visible to the global scope and also means that the lifetime of the function will be as long as that element exists.
(function(){
function Info(){
... create info ..
}
var element = document.getElementById("thisOutsideWorld");
var importantPrivateInfo = new Info();
element.keepThis = importantPrivateInfo;
})();
But this does not apply to primitive types as they are copied not referenced. These are Numbers, Strings, Booleans , Undefined, Null...
So to set the background to a canvas via a compartmentalized function see the following function
(function(){
'use strict';
var myCanvas = document.createElement("canvas");
myCanvas .width = 1024;
myCanvas .height =1024;
var ctx = canvas.getContext("2d");
// toDo
// draw the stuff you want.
var el = document.getElementById("myElement");
if(el !== null){
el.style.background = "url("+canvas.toDataURL()+")";
}
// all done
})(); // once run it will delete the canvas and ctx and leave only the copied dataURL
You may think that this exposes the canvas. But it is safe as the canvas is converted to a string and strings are copied not referenced.
If you need to keep the canvas for some period then use a timer to create an internal reference to the anonymous function
The following function will create a canvas and update it every second for 100 seconds. After that it will be deleted and completely gone.
(function(){
'use strict';
var myCanvas = document.createElement("canvas");
myCanvas .width = 1024;
myCanvas .height =1024;
var lifeCounter = 0;
var ctx = canvas.getContext("2d");
// toDo
// draw the stuff you want.
var el = document.getElementById("myElement");
function update(){
// draw stuff on the canvas
if(el !== null){
el.style.background = "url("+canvas.toDataURL()+")";
}
lifeCounter += 1;
if(lifeCounter < 100){
setTimeout(update,1000);
}
}
update(); //start the updates
// all done
})();
Hope this helps.

Chrome and FF Display "margin-top" Differently

my google map works fine in firefox and IE. but when loading by chrome, the map will be in the top . and it also seem like all code functionality works fine
i found the
margin-top:-400px; /map position/
margin-left:-400px; /map position/
work find in firefox,but work in chrome is too top
part of my code as follows:
<style>
BODY {
font-family : Verdana,Arial,Helvetica,sans-serif;
color: #000000;
font-size : 13px ;
background-color:#8ba4d9;
}
#map_canvas {
width: 300px;
height: 300px;
box-shadow: 1px 5px 5px #666;
position:absolute;
left:50%;
top:50%;
margin-top:-400px; /*map position*/
margin-left:-400px; /*map position*/
}
</style>
<script type='text/javascript'>
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
</script>
<div id="map_canvas" align="center" style="width:65%; height:90% ; position: relative;"></div>
Try this script
google.load('visualization', '1', {'packages': ['geomap']});
google.setOnLoadCallback(drawMap);
function drawMap() {
var data = google.visualization.arrayToDataTable([
['Country', 'Popularity'],
['Germany', 200],
['United States', 300],
['Brazil', 400],
['Canada', 500],
['France', 600],
['RU', 700]
]);
var options = {};
options['dataMode'] = 'regions';
var container = document.getElementById('map_canvas');
var geomap = new google.visualization.GeoMap(container);
geomap.draw(data, options);
};
AND
have u added https://www.google.com/jsapi'> to your page (this script is important)

How to highlight div on click

I would like to highlight a div when it's clicked.
Heres the example: www.spidex.org
On this website if you hover any of the navigation buttons a div on the top of the page is highlighted.
You may use jQuery for achieving this.
get jQuery here.
now consider that you have a div that you want to highlight on mouseover called item.
do this by adding an overlay div.
div.overlay{
opacity:0;
background:#000;
width:100%;
height:100%;
position:absolute;
top:50px;left:0;
}
then use jquery
jQuery(document).ready(function($){
$('.item').mouseover(function(){
$('.overlay').css({opacity:0.3});
});
});
You can change the appearance of elements when hovered using the :hover pseudo-class.
For example
div:hover {
color: red;
}
Secondly, you can change the text color via using the color property and the background color using the background-color property.
Both are shown below:
div:hover {
color: black;
background-color: white;
}
In your given example, when you hover over the primary navigation items in the super-header, then the body dims. I agree with your analysis that this is managed with some cover div of the body.
One cross-browser approach (using jQuery in this example) you might consider would be the following:
EXAMPLE HTML:
<div class="header">
Some Link
</div>
<div class="body">
<div class="body-content">
[ CONTENT HTML ]
</div>
<div class="body-cover"></div>
</div>
EXAMPLE CSS:
.body {
position: relative; /* container needs position */
}
.body-cover {
position: absolute;
top: 0px;
left: 0px;
background-color: blue;
/*
you could use a sligtly transparent background here,
or tween your opacity in your javascript
*/
}
EXAMPLE JavaScript:
// on dom ready
jQuery(function ($) {
// closures
var $links = $('.header a');
var $body = $('.body');
var $content = $body.find('.body-content');
var $cover = $body.find('.body-cover');
var sCoverHiddenCssClassName = 'body-cover-hidden';
var sCoverTweeningCssClassName = 'body-cover-tweening';
var sCoverShowingCssClassName = 'body-cover-showing';
// closure methods
var fMouseOver = function () {
// check to see if hidden (not already tweening or showing)
if ($cover.hasClass(sCoverHiddenCssClassName)) {
// check content, may have changed.
$cover.css({
height: $content.outerHeight(),
width: $content.outerWidth()
});
// animate or tween cover (do this however you want)
$cover
.removeClass(sCoverHiddenCssClassName)
.addClass(sCoverTweeningCssClassName)
.fadeIn(function () {
// when completed, mark as showing/visible
$cover
.removeClass(sCoverTweeningCssClassName)
.addClass(sCoverShowingCssClassName);
});
}
};
var fMouseOut = function () {
// check to see if visible (not already tweening or hidden)
if ($cover.hasClass(sCoverShowingCssClassName)) {
// animate or tween cover (do this however you want)
$cover
.removeClass(sCoverShowingCssClassName)
.addClass(sCoverTweeningCssClassName)
.fadeOut(function () {
// when completed, mark as showing/visible
$cover
.removeClass(sCoverTweeningCssClassName)
.addClass(sCoverHiddenCssClassName);
});
}
};
var fClick = function (e) {
// prevent default if needed for anchors or submit buttons
// e.preventDefault();
if ($cover.hasClass(sCoverHiddenCssClassName)) {
fMouseOver();
}
else if ($cover.hasClass(sCoverShowingCssClassName)) {
fMouseOut();
}
};
// init interaction
$cover.hide().addClass(sCoverHiddenCssClassName);
$links.each(function () {
// wire links
jQuery(this)
.mouseover(fMouseOver)
.mouseout(fMouseOut);//
//.click(fClick); // use click event if desired
});
});
JQuery UI is also gives an good option to quickly highlight div .
https://jqueryui.com/effect/
$( "#divId" ).effect( "highlight", 500 );

Resources