Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jqtruong/18c97f765223652dab3edf050a38d78b to your computer and use it in GitHub Desktop.
Save jqtruong/18c97f765223652dab3edf050a38d78b to your computer and use it in GitHub Desktop.
Custom Animated Google Maps Markers
<link href='//fonts.googleapis.com/css?family=Raleway:600,900,400|Roboto:300,700' rel='stylesheet'>
<div id="map"></div>
<div class="header">
<h1>Map Marker</h1>
<ul class="animations">
<li><a href="#" id="drop">Drop</a>
<li><a href="#" id="wobble">Wobble</a>
<li><a href="#" id="bounce">Bounce</a>
</ul>
<div class='list-label'>--- animations ---</div>
<div class='tags'>CSS | Google Maps | <a href="http://dynamicsjs.com/">dynamics.js</a></div>
</div>
CustomMarker.prototype = new google.maps.OverlayView();
function CustomMarker(opts) {
this.setValues(opts);
}
CustomMarker.prototype.draw = function() {
var self = this;
var div = this.div;
if (!div) {
div = this.div = $('' +
'<div>' +
'<div class="shadow"></div>' +
'<div class="pulse"></div>' +
'<div class="pin-wrap">' +
'<div class="pin"></div>' +
'</div>' +
'</div>' +
'')[0];
this.pinWrap = this.div.getElementsByClassName('pin-wrap');
this.pin = this.div.getElementsByClassName('pin');
this.pinShadow = this.div.getElementsByClassName('shadow');
div.style.position = 'absolute';
div.style.cursor = 'pointer';
var panes = this.getPanes();
panes.overlayImage.appendChild(div);
google.maps.event.addDomListener(div, "click", function(event) {
google.maps.event.trigger(self, "click", event);
});
}
var point = this.getProjection().fromLatLngToDivPixel(this.position);
if (point) {
div.style.left = point.x + 'px';
div.style.top = point.y + 'px';
}
};
CustomMarker.prototype.animateDrop = function() {
dynamics.stop(this.pinWrap);
dynamics.css(this.pinWrap, {
'transform': 'scaleY(2) translateY(-'+$('#map').outerHeight()+'px)',
'opacity': '1',
});
dynamics.animate(this.pinWrap, {
translateY: 0,
scaleY: 1.0,
}, {
type: dynamics.gravity,
duration: 1800,
});
dynamics.stop(this.pin);
dynamics.css(this.pin, {
'transform': 'none',
});
dynamics.animate(this.pin, {
scaleY: 0.8
}, {
type: dynamics.bounce,
duration: 1800,
bounciness: 600,
})
dynamics.stop(this.pinShadow);
dynamics.css(this.pinShadow, {
'transform': 'scale(0,0)',
});
dynamics.animate(this.pinShadow, {
scale: 1,
}, {
type: dynamics.gravity,
duration: 1800,
});
}
CustomMarker.prototype.animateBounce = function() {
dynamics.stop(this.pinWrap);
dynamics.css(this.pinWrap, {
'transform': 'none',
});
dynamics.animate(this.pinWrap, {
translateY: -30
}, {
type: dynamics.forceWithGravity,
bounciness: 0,
duration: 500,
delay: 150,
});
dynamics.stop(this.pin);
dynamics.css(this.pin, {
'transform': 'none',
});
dynamics.animate(this.pin, {
scaleY: 0.8
}, {
type: dynamics.bounce,
duration: 800,
bounciness: 0,
});
dynamics.animate(this.pin, {
scaleY: 0.8
}, {
type: dynamics.bounce,
duration: 800,
bounciness: 600,
delay: 650,
});
dynamics.stop(this.pinShadow);
dynamics.css(this.pinShadow, {
'transform': 'none',
});
dynamics.animate(this.pinShadow, {
scale: 0.6,
}, {
type: dynamics.forceWithGravity,
bounciness: 0,
duration: 500,
delay: 150,
});
}
CustomMarker.prototype.animateWobble = function() {
dynamics.stop(this.pinWrap);
dynamics.css(this.pinWrap, {
'transform': 'none',
});
dynamics.animate(this.pinWrap, {
rotateZ: -45,
}, {
type: dynamics.bounce,
duration: 1800,
});
dynamics.stop(this.pin);
dynamics.css(this.pin, {
'transform': 'none',
});
dynamics.animate(this.pin, {
scaleX: 0.8
}, {
type: dynamics.bounce,
duration: 800,
bounciness: 1800,
});
}
$(function() {
var pos = new google.maps.LatLng(42.9837, -81.2497);
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 14,
center: pos,
disableDefaultUI: true,
});
var marker = new CustomMarker({
position: pos,
map: map,
});
google.maps.event.addListener(marker, 'click', function(e) {
marker.animateWobble();
});
$('#drop').on('click', function(e) {
marker.animateDrop();
});
$('#wobble').on('click', function(e) {
marker.animateWobble();
});
$('#bounce').on('click', function(e) {
marker.animateBounce();
})
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//maps.google.com/maps/api/js"></script>
<script src="//github.com/michaelvillar/dynamics.js/releases/download/0.0.8/dynamics.min.js"></script>
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
}
// Thanks to: https://www.antimath.info/css/sass-sqrt-function/
// Using sqrt to get the size of the map pin. You could do this manually,
// if your pin is a different shape.
@function sqrt($r) {
$x0: 1;
$x1: $x0;
@for $i from 1 through 10 {
$x1: $x0 - ($x0 * $x0 - abs($r)) / (2 * $x0);
$x0: $x1;
}
@return $x1;
}
$pinWidth: 100px;
$pinHeightFactor: ((1 + sqrt(2))/2);
$pinHeight: $pinHeightFactor * $pinWidth;
$pinColor: #f93c11;
$shadowOpacity: .5;
$shadow-size: 50px;
$pulseSize: 100px;
.pin-wrap {
position: absolute;
width: $pinWidth;
height: $pinWidth;
margin-top: -$pinHeight;
margin-left: -$pinWidth/2;
transform-origin: 50% ($pinHeightFactor * 100%) 0;
}
.pin {
position: absolute;
top: 50%;
left: 50%;
width: $pinWidth;
height: $pinWidth;
margin-top: -$pinWidth/2;
margin-left: -$pinWidth/2;
transform-origin: 50% ($pinHeightFactor * 100%) 0;
}
.pin::after {
position: absolute;
display: block;
box-sizing: border-box;
width: $pinWidth;
height: $pinWidth;
content: '';
transform: rotateZ(-45deg);
border: 20px solid $pinColor;
border-radius: 50% 50% 50% 50%;
}
.pin::before {
position: absolute;
display: block;
box-sizing: border-box;
width: $pinWidth;
height: $pinWidth;
content: '';
transform: rotateZ(-45deg);
border: 18px solid darken($pinColor, 10%);
border-radius: 50% 50% 50% 0;
;
}
.shadow {
position: absolute;
}
.shadow::after {
position: absolute;
left: -100px - $shadow-size/2;
display: block;
width: $shadow-size;
height: $shadow-size;
margin-top: -$shadow-size/2;
content: '';
transform: rotateX(55deg);
border-radius: 50%;
box-shadow: rgba(0, 0, 0, $shadowOpacity) 100px 0 20px;
}
.pulse {
position: absolute;
margin-top: -$pulseSize/2;
margin-left: -$pulseSize/2;
transform: rotateX(55deg);
}
.pulse::after {
display: block;
width: $pulseSize;
height: $pulseSize;
content: '';
animation: pulsate 1s ease-out;
animation-delay: 1.1s;
animation-iteration-count: infinite;
opacity: 0;
border-radius: 50%;
box-shadow: 0 0 1px 2px rgba(0, 0, 0, $shadowOpacity);
box-shadow: 0 0 6px 3px rgba($pinColor, 1.0);
}
@keyframes pulsate {
0% {
transform: scale(.1, .1);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2, 1.2);
opacity: 0;
}
}
.header {
font-family: Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 2em;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 10px 0;
text-align: center;
color: $pinColor;
background: rgba(white, .75);
}
h1 {
font-family: Raleway, 'Century Gothic', CenturyGothic, AppleGothic, sans-serif;
font-weight: 900;
font-size: 32px;
margin-bottom: 10px;
border-bottom: 2px dashed $pinColor;
display: inline-block;
}
.tags {
font-weight: 300;
}
.list-label {
font-family: Raleway, 'Century Gothic', CenturyGothic, AppleGothic, sans-serif;
font-weight: 400;
}
.header li {
display: inline-block;
}
.tags a{
color: $pinColor;
}
$buttonHeight: 44px;
.animations a {
line-height: $buttonHeight - 2px;
display: block;
box-sizing: border-box;
height: $buttonHeight;
margin: 0 5px;
padding: 0 10px;
text-decoration: none;
color: $pinColor;
border: 2px solid $pinColor;
border-radius: ($buttonHeight / 2);
transition: background-color 0.3s, color 0.3s;
}
.animations a:hover {
color: white;
background: $pinColor;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment