diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a7daefb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+**/*.css.map
+node_modules
+.sass-cache
+**/.DS_Store
\ No newline at end of file
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..840c2a6
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,71 @@
+module.exports = function(grunt) {
+
+ // 1. All configuration goes here
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+
+ concat: {
+ js: {
+ src: ['src/js/*.js'],
+ dest: 'dist/pinpoint.js'
+ }
+
+ },
+
+ uglify: {
+ build: {
+ src: 'dist/pinpoint.js',
+ dest: 'dist/pinpoint.min.js'
+ }
+ },
+
+ sass: {
+ dist: {
+ files: {
+ 'dist/pinpoint.css': 'src/scss/main.scss'
+ }
+ },
+ dist_min: {
+ options: {
+ style: 'compressed',
+ sourcemap: 'none'
+ },
+ files: {
+ 'dist/pinpoint.min.css': 'src/scss/main.scss'
+ }
+ }
+ },
+
+ watch: {
+ options: {
+ livereload: true,
+ },
+ scripts: {
+ files: ['src/js/*'],
+ tasks: ['concat', 'uglify'],
+ options: {
+ spawn: false,
+ },
+ },
+ css: {
+ files: ['src/scss/*'],
+ tasks: ['sass'],
+ options: {
+ spawn: false,
+ }
+ }
+ }
+
+ });
+
+ // 3. Where we tell Grunt we plan to use this plug-in.
+ grunt.loadNpmTasks('grunt-contrib-concat');
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+ grunt.loadNpmTasks('grunt-contrib-watch');
+ grunt.loadNpmTasks('grunt-contrib-sass');
+
+
+ // 4. Where we tell Grunt what to do when we type "grunt" into the terminal.
+ grunt.registerTask('default', ['concat','uglify','sass']);
+
+};
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..288c453
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Dow Jones
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..9cc8f1c
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,151 @@
+# Pinpoint
+
+A JavaScript library for creating beautifully simple maps in seconds. Developed at The Wall Street Journal.
+
+- [Example on WSJ.com](http://www.wsj.com/articles/mass-grave-of-boko-haram-victims-discovered-1426867025)
+- [Blog post](http://ejb.github.io/2015/03/21/pinpoint-maps-at-wsj.html)
+
+## Features
+
+- Map settings are stored in a simple JSON format and can be generated using [Pinpoint Editor](https://github.com/dowjones/pinpoint-editor).
+- Fully responsive with touch-friendly "click-to-activate" behaviour.
+- Powered by the awesome [Leaflet.js](http://leafletjs.com).
+
+## Quickstart
+
+Include `pinpoint.js` and `pinpoint.css` on your page.
+
+In terms of HTML, just a single div is needed:
+
+```html
+
+```
+
+Then in your JavaScript file:
+
+```js
+var options = {
+ "element": ".map-container",
+ "aspect-ratio": "wide",
+ "dek": "",
+ "hed": "The U.K.",
+ "lat": 51.5049378,
+ "lon": -0.0870377,
+ "minimap": false,
+ "zoom": 4,
+ "markers": [
+ {
+ "lat": 51.5049378,
+ "lon": -0.0870377,
+ "text": "London"
+ }
+ ]
+};
+var map = new Pinpoint( options );
+```
+
+
+### Options
+
+Pinpoint accepts a JavaScript object for configuration.
+
+option | type | default | description
+------------------- | -------- | ------------------------------------------ | ------------------
+element | string | "#map-el" | CSS selector for map parent element.
+aspect-ratio | string | (required) | The shape of the map: "wide" (3x2), "square" (1x1), or "tall" (5x6)
+lat | number | (required) | Latitude for map centre.
+lon | number | (required) | Longitude for map centre.
+markers | array | (required) | Array of markers/icons on map (see below for details).
+zoom | number | (required) | Initial zoom level of map.
+hed | string | (blank) | Headline for map (optional).
+dek | string | (blank) | Dek for map (optional).
+note | string | (blank) | Note to go below map (optional).
+minimap | boolean | false | Set to `true` to enables zoomed-out smaller map in corner.
+minimap-zoom-offset | number | -5 | Zoom level of minimap relative to main map zoom. Should always be below 0.
+basemap | string | "http://{s}.tile.osm.org/{z}/{x}/{y}.png" | Leaflet tile layer [URL template](http://leafletjs.com/reference.html#url-template) (optional)
+basemapCredit | string | "Leaflet | © OpenStreetMap contributors" | Credit for tilelayer. Goes at bottom, below note. (optional)
+creation | boolean | false | Set to `true tot enables "creation mode" for use in admin tool.
+dragend | function | undefined | Anonymous function called on Leaflet `dragend` event (ie. when dragging/panning map).
+zoomend | function | undefined | Anonymous function called on Leaflet `zoomend` event (ie. when zooming).
+markerdragend | function | undefined | Anonymous function called on Leaflet marker `dragend` event (ie. when dragging a marker around the map). Only works when `creation` is true.
+
+
+### Marker options
+
+Markers are stored as an array of objects.
+
+option | type | default | description
+--------------- | ------ | ---------- | ------------------
+lat | number | (required) | Latitude of point.
+lon | number | (required) | Longitude of point.
+text | string | (blank) | Text for marker callout.
+icon | string | "square" | Marker icon style: "circle", "square" or "none".
+label | string | "callout" | Marker label style: "callout" or "plain".
+label-direction | string | "north" | Marker label direction. Available directions varies between label styles.
+
+### Example configuration JSON
+
+```json
+{
+ "aspect-ratio": "wide",
+ "dek": "",
+ "hed": "The U.K.",
+ "lat": 51.5049378,
+ "lon": -0.0870377,
+ "minimap": false,
+ "minimap-zoom-offset": -5,
+ "zoom": 4,
+ "markers": [
+ {
+ "icon": "circle",
+ "label": "plain",
+ "label-direction": "north",
+ "lat": 51.5049378,
+ "lon": -0.0870377,
+ "text": "London"
+ },
+ {
+ "icon": "circle",
+ "label": "plain",
+ "label-direction": "north",
+ "lat": 53.4779669,
+ "lon": -2.0613722,
+ "text": "Manchester"
+ }
+ ]
+}
+```
+
+### Public methods
+
+- `.remove()`: Reset map container to empty element.
+
+## Compiling dist folder
+
+You must have [npm](https://www.npmjs.com) and [grunt](http://gruntjs.com) installed.
+
+- `npm install`
+- `grunt`
+
+Note that the images in `src/img` are not auto-compiled - if they're changed, the SVG code will need to be copied into `pinpoint.js`.
+
+## Customising styles
+
+The look of the map and its markers is mostly controlled with CSS/SASS. These files can be found in `src/scss`:
+
+- **main:** Head and deck, scale line style
+- **overlay:** "Zoom/pan" icon
+- **markers:** Square, circle and plain/invisible marker styles
+- **marker-label-callout:** Callout label with north and south styles
+- **marker-label-plain:** Plain label with N, NE, E, SE, S, SW, W and NW styles
+- **geojson:** Styles for geojson objects
+
+To change the map's basemap/tilelayer, use the `basemap` configuration variable. See above for more details.
+
+## Changelog
+
+v1.0.0
+
+- Initial release
+
+
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..abb6a74
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,23 @@
+{
+ "name": "pinpoint-library",
+ "version": "1.0.0",
+ "authors": [
+ "ejb "
+ ],
+ "license": "MIT",
+ "main": [
+ "dist/pinpoint.js",
+ "dist/pinpoint.css"
+ ],
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ],
+ "description": "A JavaScript library for creating beautifully simple maps in seconds.",
+ "moduleType": [
+ "globals"
+ ]
+}
diff --git a/dist/pinpoint.css b/dist/pinpoint.css
new file mode 100644
index 0000000..cf2e359
--- /dev/null
+++ b/dist/pinpoint.css
@@ -0,0 +1,257 @@
+/*
+ Pinpoint v1.0.0
+*/
+.pinpoint-hed, .pinpoint-dek, .map-outer, .pinpoint-source, .pinpoint-note {
+ font-family: 'Whitney Ssm', sans-serif; }
+
+.map-inner {
+ width: 100%; }
+
+.map-outer {
+ position: relative; }
+
+.map-cover {
+ position: absolute;
+ top: 0; }
+
+.map-outer.inactive .map-cover {
+ content: '';
+ width: 100%;
+ z-index: 10000000;
+ cursor: pointer;
+ /* background: red;
+ opacity: 0.5; */ }
+
+.map-inner .leaflet-control-zoom {
+ -webkit-transition: opacity 0.5s;
+ transition: opacity 0.5s; }
+
+.map-outer.inactive .leaflet-control-zoom {
+ opacity: 0; }
+
+.pinpoint-hed, .pinpoint-dek {
+ margin: 0;
+ padding: 0; }
+
+.pinpoint-hed {
+ font-size: 16px;
+ padding-bottom: 5px;
+ margin: 0;
+ font-weight: 600; }
+
+.pinpoint-dek {
+ font-size: 16px;
+ margin: 0 0 10px 0;
+ padding: 0;
+ color: #666;
+ font-weight: 400; }
+
+.pinpoint-topline {
+ border-top: 1px solid #dadada;
+ padding-top: 7px; }
+
+.pinpoint-source, .pinpoint-note {
+ margin-top: 4px;
+ font-size: 12px;
+ color: #666; }
+ .pinpoint-source a:link, .pinpoint-source a:visited, .pinpoint-note a:link, .pinpoint-note a:visited {
+ text-decoration: none;
+ color: inherit; }
+ .pinpoint-source a:hover, .pinpoint-note a:hover {
+ text-decoration: underline; }
+
+.pinpoint-note {
+ margin-bottom: 0; }
+
+.leaflet-control-scale-line {
+ border: 0 !important;
+ background: none !important;
+ padding: 2px 0 !important;
+ font-weight: bold;
+ color: black;
+ text-shadow: 0 0 5px white; }
+
+.leaflet-control-scale-line:first-child {
+ border-bottom: 5px solid black !important; }
+
+.leaflet-control-scale-line:last-child {
+ border-top: 5px solid black !important;
+ margin-top: 4px !important; }
+
+.leaflet-control-minimap {
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
+ pointer-events: none; }
+
+.leaflet-control-minimap .leaflet-zoom-hide > g:first-child:after {
+ content: 'xxxx';
+ display: block; }
+
+/* markers */
+.marker-circle {
+ stroke: none;
+ fill: black;
+ fill-opacity: 1; }
+
+.marker-icon {
+ width: 20px;
+ height: 20px;
+ background: black;
+ margin-left: 10px; }
+
+.marker-icon-circle {
+ border-radius: 1000px; }
+
+.marker-icon-none {
+ opacity: 0; }
+
+.marker-label-plain {
+ margin-top: -28px !important;
+ margin-left: 100% !important; }
+ .marker-label-plain .marker-inner {
+ display: inline-block;
+ white-space: nowrap;
+ height: auto !important;
+ position: relative;
+ line-height: initial;
+ font-family: 'Whitney Ssm', sans-serif;
+ color: black;
+ font-weight: 600;
+ font-size: 14px; }
+
+.marker-label-plain.northeast {
+ margin-top: -25px !important; }
+ .marker-label-plain.northeast .marker-inner {
+ margin-left: 10px !important; }
+
+.marker-label-plain.east {
+ margin-top: -10px !important; }
+ .marker-label-plain.east .marker-inner {
+ margin-left: 10px !important; }
+
+.marker-label-plain.southeast {
+ margin-top: 8px !important; }
+ .marker-label-plain.southeast .marker-inner {
+ margin-left: 10px !important; }
+
+.marker-label-plain.south {
+ margin-top: 5px !important; }
+
+.marker-label-plain.southwest {
+ margin-top: 8px !important; }
+ .marker-label-plain.southwest .marker-inner {
+ margin-right: 25px !important;
+ position: absolute;
+ right: 0; }
+
+.marker-label-plain.west {
+ margin-top: -10px !important; }
+ .marker-label-plain.west .marker-inner {
+ margin-right: 25px !important;
+ position: absolute;
+ right: 0; }
+
+.marker-label-plain.northwest {
+ margin-top: -25px !important; }
+ .marker-label-plain.northwest .marker-inner {
+ margin-right: 25px !important;
+ position: absolute;
+ right: 0; }
+
+.marker-label-callout {
+ margin-top: -50px !important;
+ margin-left: -50% !important; }
+ .marker-label-callout .marker-inner {
+ display: inline-block;
+ white-space: nowrap;
+ height: auto !important;
+ position: relative;
+ line-height: initial;
+ font-family: 'Whitney Ssm', sans-serif;
+ background: black;
+ color: white;
+ font-weight: 500;
+ font-size: 14px;
+ padding: 6px;
+ margin-top: -6px; }
+ .marker-label-callout .marker-inner:after {
+ content: "";
+ top: 100%;
+ left: 50%;
+ height: 22px;
+ width: 2px;
+ background: black;
+ position: absolute;
+ pointer-events: none;
+ margin-left: -1px; }
+
+.marker-label-callout.south .marker-inner {
+ margin-top: 72px; }
+ .marker-label-callout.south .marker-inner:after {
+ top: 0;
+ border-color: transparent;
+ border-bottom-color: #000000;
+ margin-top: -20px; }
+
+/* overlay icon */
+.image-interactive-icon {
+ opacity: 0;
+ -webkit-transition: opacity 0.5s;
+ transition: opacity 0.5s;
+ cursor: pointer;
+ display: none; }
+
+.map-outer.inactive .image-interactive-icon {
+ display: block;
+ top: 10px;
+ left: 10px;
+ position: absolute;
+ border-radius: 4px;
+ background-size: 50px 50px;
+ background-color: white;
+ z-index: 999;
+ opacity: 1;
+ font-size: 10px;
+ font-weight: 600;
+ padding: 8px 10px;
+ box-shadow: 0 0 3px #777; }
+ .map-outer.inactive .image-interactive-icon > svg {
+ vertical-align: middle;
+ display: inline-block;
+ margin-right: 8px; }
+ .map-outer.inactive .image-interactive-icon .image-interactive-icon-text {
+ vertical-align: middle; }
+ .map-outer.inactive .image-interactive-icon.image-interactive-icon-hover {
+ display: none;
+ background-color: #007ec5;
+ color: white; }
+
+.map-outer.inactive:hover .image-interactive-icon {
+ display: none; }
+ .map-outer.inactive:hover .image-interactive-icon.image-interactive-icon-hover {
+ display: block; }
+
+.pinpoint-geojson, .pinpoint-geojson.dashed, .pinpoint-geojson.dashed-clockwise, .pinpoint-geojson.dashed-anticlockwise {
+ stroke: #777;
+ stroke-width: 3;
+ stroke-opacity: 1;
+ fill-opacity: 0; }
+
+.pinpoint-geojson.dashed, .pinpoint-geojson.dashed-clockwise, .pinpoint-geojson.dashed-anticlockwise {
+ stroke-dasharray: 6 6; }
+
+.pinpoint-geojson.dashed-clockwise, .pinpoint-geojson.dashed-anticlockwise {
+ animation: dash 100s linear infinite reverse;
+ -webkit-animation: dash 100s linear infinite reverse; }
+
+.pinpoint-geojson.dashed-anticlockwise {
+ animation: dash 100s linear infinite;
+ -webkit-animation: dash 100s linear infinite; }
+
+@-webkit-keyframes dash {
+ to {
+ stroke-dashoffset: 600; } }
+@keyframes dash {
+ to {
+ stroke-dashoffset: 600; } }
+
+/*# sourceMappingURL=pinpoint.css.map */
diff --git a/dist/pinpoint.js b/dist/pinpoint.js
new file mode 100644
index 0000000..f5a5c57
--- /dev/null
+++ b/dist/pinpoint.js
@@ -0,0 +1,324 @@
+/*
+ Pinpoint v1.0.0
+*/
+
+function Pinpoint(opts){
+ 'use strict';
+
+ var that = this;
+ this.opts = opts;
+ this.opts.el = this.opts.el || '#map-el';
+ this.$el = $(this.opts.el);
+ this.opts.basemap = opts.basemap || 'http://{s}.tile.osm.org/{z}/{x}/{y}.png';
+ this.opts.basemapCredit = opts.basemapCredit || 'Leaflet | © OpenStreetMap contributors';
+
+ this.addElements();
+ this.fillText();
+ this.setAspectRatio();
+ this.setupMap();
+ this.calcBounds();
+
+ this.disableInteraction();
+
+ if (this.opts.creation) {
+ this.enableInteraction();
+ this.map.remove();
+ this.map.setMaxBounds( null );
+ this.setupMap({nozoomlimits: true});
+
+ }
+
+ this.$el.find('.map-outer').click( this.enableInteraction.bind(that) );
+
+ if (opts.minimap) {
+ this.addMinimap();
+ }
+
+ for (var i = 0; i < opts.markers.length; i++) {
+ this.addMarker(opts.markers[i], i);
+ }
+
+ console.log(opts);
+ if (opts.geojson) {
+ this.addGeoJSON(opts.geojson);
+ }
+
+ if (typeof Iframe !== 'undefined') {
+ var fm = Iframe.init();
+ }
+ if ($(window).smartresize) {
+ $(window).smartresize( this.onWindowResize.bind(that) );
+ }
+}
+
+Pinpoint.prototype.addElements = function(){
+
+ var pointer = ' ';
+ var html = '
'+
+ '
'+
+ ''+
+ '
'+
+ '
'+pointer+'Zoom/Pan '+
+ '
'+pointer.replace('#697379','white')+'Zoom/Pan '+
+ '
'+
+ '
'+
+ '
'+
+ ' '+this.opts.basemapCredit+'
';
+ this.$el.html( html );
+}
+
+Pinpoint.prototype.setAspectRatio = function(){
+
+ var aspectRatios = {
+ "tall": 1.2,
+ "square": 1,
+ "wide": (2/3)
+ };
+
+ var aspectRatio = aspectRatios[this.opts['aspect-ratio']];
+ var newHeight = this.$el.find('.map-inner').width() * aspectRatio;
+ this.$el.find('.map-inner, .map-cover').height( newHeight );
+
+ if (this.map) {
+ this.map.invalidateSize();
+ }
+
+}
+
+Pinpoint.prototype.onWindowResize = function(){
+ this.setAspectRatio();
+ $(window).trigger('resize');
+ // this.map.setView([this.opts.lat, this.opts.lon]);
+}
+
+Pinpoint.prototype.setupMap = function(mapopts){
+
+ var opts = this.opts;
+
+ var maxZoom = opts.zoom +1;
+ var minZoom = opts.zoom -1;
+ if (mapopts && mapopts.nozoomlimits) {
+ maxZoom = 20;
+ minZoom = 1;
+ }
+
+ var mapOptions = {
+ scrollWheelZoom: true,
+ keyboard: false,
+ maxZoom: maxZoom,
+ minZoom: minZoom,
+ attributionControl: false
+ };
+
+ var mapEl = this.$el.find('.map-inner')[0];
+ this.map = L.map(mapEl, mapOptions)
+ .setView([opts.lat, opts.lon], opts.zoom);
+ L.control.scale({ position: 'topright' }).addTo(this.map); // scale bar
+ // put miles on top of km
+ var $scaleParent = this.$el.find('.leaflet-control-scale.leaflet-control');
+ $scaleParent.find('.leaflet-control-scale-line').eq(0).detach().appendTo($scaleParent);
+
+ L.tileLayer(this.opts.basemap).addTo(this.map);
+
+ if (opts.dragend) {
+ this.map.on('dragend',opts.dragend);
+ }
+ if (opts.zoomend) {
+ this.map.on('zoomend',opts.zoomend);
+ }
+
+}
+
+Pinpoint.prototype.addMarker = function(mopts, index){
+ this.markers = this.markers || [];
+ mopts.icon = mopts.icon || 'circle';
+ // set the icon type
+ var squareIcon = L.divIcon({
+ className: 'marker-icon marker-icon-'+mopts.icon
+ });
+ var icon = L.marker(
+ [mopts.lat, mopts.lon],
+ {
+ icon: squareIcon,
+ draggable: this.opts.creation,
+ title: index
+ }
+ ).addTo(this.map);
+ mopts.label = mopts.label || 'plain';
+ var labelDir = mopts["label-direction"] || 'north';
+ if (mopts.label === 'callout') {
+ var textBox = L.divIcon({
+ className: 'marker-label-callout '+labelDir,
+ html: ''+mopts.text+'
'
+ });
+ } else if (mopts.label === 'plain') {
+ var textBox = L.divIcon({
+ className: 'marker-label-plain '+labelDir,
+ html: ''+mopts.text+'
'
+ });
+ }
+ var text = L.marker(
+ [mopts.lat, mopts.lon],
+ {
+ icon: textBox
+ }
+ ).addTo(this.map);
+
+ // you can set .my-div-icon styles in CSS
+
+ // L.marker([50.505, 30.57]).addTo(map);
+
+ var $mi = this.$el.find('.marker-inner').eq(-1);
+ $mi.css( 'margin-left', -$mi.outerWidth()/2 );
+ setTimeout((function(){
+ $mi.css( 'margin-left', -$mi.outerWidth()/2 );
+ }).bind(this),100);
+
+ if (this.opts.markerdragend) {
+ icon.on('dragend', this.opts.markerdragend);
+ }
+
+ this.markers.push({
+ icon: icon,
+ text: text
+ });
+}
+
+Pinpoint.prototype.addMinimap = function(){
+ var minitiles = L.tileLayer(
+ this.opts.basemap, {
+ attribution: ''
+ });
+
+ var miniMap = new L.Control.MiniMap(minitiles, {
+ zoomLevelOffset: this.opts['minimap-zoom-offset'] || -5,
+ width: 100,
+ height: 100,
+ aimingRectOptions: {
+ color: 'black',
+ weight: 1,
+ opacity: 1,
+ fillColor: '#999',
+ fillOpacity: 0
+ }
+ }).addTo(this.map);
+
+ // Disable drag and zoom handlers.
+ miniMap._miniMap.dragging.disable();
+ miniMap._miniMap.touchZoom.disable();
+ miniMap._miniMap.doubleClickZoom.disable();
+ miniMap._miniMap.scrollWheelZoom.disable();
+
+ // Disable tap handler, if present.
+ if (miniMap._miniMap.tap) miniMap._miniMap.tap.disable();
+
+
+}
+
+Pinpoint.prototype.calcBounds = function(){
+ var that = this;
+
+ var bounds = calcNewMaxBounds(this.map);
+ this.map.setMaxBounds( bounds );
+
+ function calcNewMaxBounds(map){
+ // add an extra 30% margin to bounds
+ var boundScaleFactor = 1/3;
+
+ var current = map.getBounds();
+ var hori = Math.abs( current._southWest.lng - current._northEast.lng ) * boundScaleFactor;
+ var vert = Math.abs( current._southWest.lat - current._northEast.lat ) * boundScaleFactor;
+ var southWest = {
+ lat: current._southWest.lat - vert,
+ lng: current._southWest.lng - hori
+ }
+ var northEast = {
+ lat: current._northEast.lat + vert,
+ lng: current._northEast.lng + hori
+ }
+ return L.latLngBounds(southWest, northEast);
+
+ }
+}
+
+Pinpoint.prototype.fillText = function(){
+ if (this.opts.hed && (this.opts.hed.length > 0)) {
+ this.$el.find('.pinpoint-hed').text( this.opts.hed );
+ } else {
+ this.$el.find('.pinpoint-hed').hide();
+ }
+ if (this.opts.dek && (this.opts.dek.length > 0)) {
+ this.$el.find('.pinpoint-dek').text( this.opts.dek );
+ } else {
+ this.$el.find('.pinpoint-dek').hide();
+ }
+ if (this.opts.note && (this.opts.note.length > 0)) {
+ this.$el.find('.pinpoint-note').html( this.opts.note );
+ } else {
+ this.$el.find('.pinpoint-note').hide();
+ }
+ this.$el.find('.pinpoint-hed:visible(), .pinpoint-dek:visible()').eq(0).addClass('pinpoint-topline');
+}
+
+Pinpoint.prototype.disableInteraction = function(){
+ var map = this.map;
+ this.$el.find('.map-outer').addClass('inactive');
+ // map.dragging.disable();
+ // map.touchZoom.disable();
+ // map.doubleClickZoom.disable();
+ // // map.scrollWheelZoom.disable();
+ // map.boxZoom.disable();
+ // map.keyboard.disable();
+ return this;
+}
+
+Pinpoint.prototype.enableInteraction = function(){
+ var map = this.map;
+ this.$el.find('.map-outer').removeClass('inactive');
+ // map.dragging.enable();
+ // map.touchZoom.enable();
+ // map.doubleClickZoom.enable();
+ // // map.scrollWheelZoom.enable();
+ // map.boxZoom.enable();
+ // map.keyboard.enable();
+ return this;
+}
+
+Pinpoint.prototype.remove = function(){
+ this.map.remove();
+ this.$el.empty();
+}
+
+Pinpoint.prototype.addGeoJSON = function(geojson){
+ var map = this.map;
+ var features = geojson.features;
+ console.log(features);
+ for (var i = 0; i < features.length; i++) {
+ if (features[i].geometry && features[i].geometry) {
+ if (features[i].properties && features[i].properties.pinpointStyle) {
+ var styleName = features[i].properties.pinpointStyle;
+ } else {
+ var styleName = '';
+ }
+ var type = features[i].geometry.type;
+ if ( isOneOf( type, ["LineString", "MultiLineString", "Polygon", "MultiPolygon"]) ) {
+ L.geoJson(features[i].geometry, {
+ style: {
+ className: 'pinpoint-geojson '+styleName
+ }
+ }).addTo(map);
+
+ }
+ }
+ }
+
+ function isOneOf( needle, haystack ){
+ for (var i = 0; i < haystack.length; i++) {
+ if (haystack[i] === needle) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
diff --git a/dist/pinpoint.min.css b/dist/pinpoint.min.css
new file mode 100644
index 0000000..3c4e057
--- /dev/null
+++ b/dist/pinpoint.min.css
@@ -0,0 +1,2 @@
+.pinpoint-hed,.pinpoint-dek,.map-outer,.pinpoint-source,.pinpoint-note{font-family:'Whitney Ssm', sans-serif}.map-inner{width:100%}.map-outer{position:relative}.map-cover{position:absolute;top:0}.map-outer.inactive .map-cover{content:'';width:100%;z-index:10000000;cursor:pointer}.map-inner .leaflet-control-zoom{-webkit-transition:opacity 0.5s;transition:opacity 0.5s}.map-outer.inactive .leaflet-control-zoom{opacity:0}.pinpoint-hed,.pinpoint-dek{margin:0;padding:0}.pinpoint-hed{font-size:16px;padding-bottom:5px;margin:0;font-weight:600}.pinpoint-dek{font-size:16px;margin:0 0 10px 0;padding:0;color:#666;font-weight:400}.pinpoint-topline{border-top:1px solid #dadada;padding-top:7px}.pinpoint-source,.pinpoint-note{margin-top:4px;font-size:12px;color:#666}.pinpoint-source a:link,.pinpoint-source a:visited,.pinpoint-note a:link,.pinpoint-note a:visited{text-decoration:none;color:inherit}.pinpoint-source a:hover,.pinpoint-note a:hover{text-decoration:underline}.pinpoint-note{margin-bottom:0}.leaflet-control-scale-line{border:0 !important;background:none !important;padding:2px 0 !important;font-weight:bold;color:black;text-shadow:0 0 5px white}.leaflet-control-scale-line:first-child{border-bottom:5px solid black !important}.leaflet-control-scale-line:last-child{border-top:5px solid black !important;margin-top:4px !important}.leaflet-control-minimap{box-shadow:0 0 8px rgba(0,0,0,0.5);pointer-events:none}.leaflet-control-minimap .leaflet-zoom-hide>g:first-child:after{content:'xxxx';display:block}.marker-circle{stroke:none;fill:black;fill-opacity:1}.marker-icon{width:20px;height:20px;background:black;margin-left:10px}.marker-icon-circle{border-radius:1000px}.marker-icon-none{opacity:0}.marker-label-plain{margin-top:-28px !important;margin-left:100% !important}.marker-label-plain .marker-inner{display:inline-block;white-space:nowrap;height:auto !important;position:relative;line-height:initial;font-family:'Whitney Ssm', sans-serif;color:black;font-weight:600;font-size:14px}.marker-label-plain.northeast{margin-top:-25px !important}.marker-label-plain.northeast .marker-inner{margin-left:10px !important}.marker-label-plain.east{margin-top:-10px !important}.marker-label-plain.east .marker-inner{margin-left:10px !important}.marker-label-plain.southeast{margin-top:8px !important}.marker-label-plain.southeast .marker-inner{margin-left:10px !important}.marker-label-plain.south{margin-top:5px !important}.marker-label-plain.southwest{margin-top:8px !important}.marker-label-plain.southwest .marker-inner{margin-right:25px !important;position:absolute;right:0}.marker-label-plain.west{margin-top:-10px !important}.marker-label-plain.west .marker-inner{margin-right:25px !important;position:absolute;right:0}.marker-label-plain.northwest{margin-top:-25px !important}.marker-label-plain.northwest .marker-inner{margin-right:25px !important;position:absolute;right:0}.marker-label-callout{margin-top:-50px !important;margin-left:-50% !important}.marker-label-callout .marker-inner{display:inline-block;white-space:nowrap;height:auto !important;position:relative;line-height:initial;font-family:'Whitney Ssm', sans-serif;background:black;color:white;font-weight:500;font-size:14px;padding:6px;margin-top:-6px}.marker-label-callout .marker-inner:after{content:"";top:100%;left:50%;height:22px;width:2px;background:black;position:absolute;pointer-events:none;margin-left:-1px}.marker-label-callout.south .marker-inner{margin-top:72px}.marker-label-callout.south .marker-inner:after{top:0;border-color:transparent;border-bottom-color:#000000;margin-top:-20px}.image-interactive-icon{opacity:0;-webkit-transition:opacity 0.5s;transition:opacity 0.5s;cursor:pointer;display:none}.map-outer.inactive .image-interactive-icon{display:block;top:10px;left:10px;position:absolute;border-radius:4px;background-size:50px 50px;background-color:white;z-index:999;opacity:1;font-size:10px;font-weight:600;padding:8px 10px;box-shadow:0 0 3px #777}.map-outer.inactive .image-interactive-icon>svg{vertical-align:middle;display:inline-block;margin-right:8px}.map-outer.inactive .image-interactive-icon .image-interactive-icon-text{vertical-align:middle}.map-outer.inactive .image-interactive-icon.image-interactive-icon-hover{display:none;background-color:#007ec5;color:white}.map-outer.inactive:hover .image-interactive-icon{display:none}.map-outer.inactive:hover .image-interactive-icon.image-interactive-icon-hover{display:block}.pinpoint-geojson,.pinpoint-geojson.dashed,.pinpoint-geojson.dashed-clockwise,.pinpoint-geojson.dashed-anticlockwise{stroke:#777;stroke-width:3;stroke-opacity:1;fill-opacity:0}.pinpoint-geojson.dashed,.pinpoint-geojson.dashed-clockwise,.pinpoint-geojson.dashed-anticlockwise{stroke-dasharray:6 6}.pinpoint-geojson.dashed-clockwise,.pinpoint-geojson.dashed-anticlockwise{animation:dash 100s linear infinite reverse;-webkit-animation:dash 100s linear infinite reverse}.pinpoint-geojson.dashed-anticlockwise{animation:dash 100s linear infinite;-webkit-animation:dash 100s linear infinite}@-webkit-keyframes dash{to{stroke-dashoffset:600}}@keyframes dash{to{stroke-dashoffset:600}}
+/*# sourceMappingURL=pinpoint.min.css.map */
diff --git a/dist/pinpoint.min.js b/dist/pinpoint.min.js
new file mode 100644
index 0000000..bb1310d
--- /dev/null
+++ b/dist/pinpoint.min.js
@@ -0,0 +1 @@
+function Pinpoint(a){"use strict";var b=this;this.opts=a,this.opts.el=this.opts.el||"#map-el",this.$el=$(this.opts.el),this.opts.basemap=a.basemap||"http://{s}.tile.osm.org/{z}/{x}/{y}.png",this.opts.basemapCredit=a.basemapCredit||'Leaflet | © OpenStreetMap contributors',this.addElements(),this.fillText(),this.setAspectRatio(),this.setupMap(),this.calcBounds(),this.disableInteraction(),this.opts.creation&&(this.enableInteraction(),this.map.remove(),this.map.setMaxBounds(null),this.setupMap({nozoomlimits:!0})),this.$el.find(".map-outer").click(this.enableInteraction.bind(b)),a.minimap&&this.addMinimap();for(var c=0;c
'+a+'Zoom/Pan '+a.replace("#697379","white")+'Zoom/Pan
'+this.opts.basemapCredit+"
";this.$el.html(b)},Pinpoint.prototype.setAspectRatio=function(){var a={tall:1.2,square:1,wide:2/3},b=a[this.opts["aspect-ratio"]],c=this.$el.find(".map-inner").width()*b;this.$el.find(".map-inner, .map-cover").height(c),this.map&&this.map.invalidateSize()},Pinpoint.prototype.onWindowResize=function(){this.setAspectRatio(),$(window).trigger("resize")},Pinpoint.prototype.setupMap=function(a){var b=this.opts,c=b.zoom+1,d=b.zoom-1;a&&a.nozoomlimits&&(c=20,d=1);var e={scrollWheelZoom:!0,keyboard:!1,maxZoom:c,minZoom:d,attributionControl:!1},f=this.$el.find(".map-inner")[0];this.map=L.map(f,e).setView([b.lat,b.lon],b.zoom),L.control.scale({position:"topright"}).addTo(this.map);var g=this.$el.find(".leaflet-control-scale.leaflet-control");g.find(".leaflet-control-scale-line").eq(0).detach().appendTo(g),L.tileLayer(this.opts.basemap).addTo(this.map),b.dragend&&this.map.on("dragend",b.dragend),b.zoomend&&this.map.on("zoomend",b.zoomend)},Pinpoint.prototype.addMarker=function(a,b){this.markers=this.markers||[],a.icon=a.icon||"circle";var c=L.divIcon({className:"marker-icon marker-icon-"+a.icon}),d=L.marker([a.lat,a.lon],{icon:c,draggable:this.opts.creation,title:b}).addTo(this.map);a.label=a.label||"plain";var e=a["label-direction"]||"north";if("callout"===a.label)var f=L.divIcon({className:"marker-label-callout "+e,html:''+a.text+"
"});else if("plain"===a.label)var f=L.divIcon({className:"marker-label-plain "+e,html:''+a.text+"
"});var g=L.marker([a.lat,a.lon],{icon:f}).addTo(this.map),h=this.$el.find(".marker-inner").eq(-1);h.css("margin-left",-h.outerWidth()/2),setTimeout(function(){h.css("margin-left",-h.outerWidth()/2)}.bind(this),100),this.opts.markerdragend&&d.on("dragend",this.opts.markerdragend),this.markers.push({icon:d,text:g})},Pinpoint.prototype.addMinimap=function(){var a=L.tileLayer(this.opts.basemap,{attribution:""}),b=new L.Control.MiniMap(a,{zoomLevelOffset:this.opts["minimap-zoom-offset"]||-5,width:100,height:100,aimingRectOptions:{color:"black",weight:1,opacity:1,fillColor:"#999",fillOpacity:0}}).addTo(this.map);b._miniMap.dragging.disable(),b._miniMap.touchZoom.disable(),b._miniMap.doubleClickZoom.disable(),b._miniMap.scrollWheelZoom.disable(),b._miniMap.tap&&b._miniMap.tap.disable()},Pinpoint.prototype.calcBounds=function(){function a(a){var b=1/3,c=a.getBounds(),d=Math.abs(c._southWest.lng-c._northEast.lng)*b,e=Math.abs(c._southWest.lat-c._northEast.lat)*b,f={lat:c._southWest.lat-e,lng:c._southWest.lng-d},g={lat:c._northEast.lat+e,lng:c._northEast.lng+d};return L.latLngBounds(f,g)}var b=a(this.map);this.map.setMaxBounds(b)},Pinpoint.prototype.fillText=function(){this.opts.hed&&this.opts.hed.length>0?this.$el.find(".pinpoint-hed").text(this.opts.hed):this.$el.find(".pinpoint-hed").hide(),this.opts.dek&&this.opts.dek.length>0?this.$el.find(".pinpoint-dek").text(this.opts.dek):this.$el.find(".pinpoint-dek").hide(),this.opts.note&&this.opts.note.length>0?this.$el.find(".pinpoint-note").html(this.opts.note):this.$el.find(".pinpoint-note").hide(),this.$el.find(".pinpoint-hed:visible(), .pinpoint-dek:visible()").eq(0).addClass("pinpoint-topline")},Pinpoint.prototype.disableInteraction=function(){this.map;return this.$el.find(".map-outer").addClass("inactive"),this},Pinpoint.prototype.enableInteraction=function(){this.map;return this.$el.find(".map-outer").removeClass("inactive"),this},Pinpoint.prototype.remove=function(){this.map.remove(),this.$el.empty()},Pinpoint.prototype.addGeoJSON=function(a){function b(a,b){for(var c=0;c
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/index.htm b/example/index.htm
new file mode 100644
index 0000000..1a4f320
--- /dev/null
+++ b/example/index.htm
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..db948d9
--- /dev/null
+++ b/package.json
@@ -0,0 +1,9 @@
+{
+ "devDependencies": {
+ "grunt": "~0.4.1",
+ "grunt-contrib-concat": "~0.3.0",
+ "grunt-contrib-uglify": "~0.2.7",
+ "grunt-contrib-watch": "~0.5.3",
+ "grunt-contrib-sass": "~0.6.0"
+ }
+}
diff --git a/src/img/pointer-highlight.svg b/src/img/pointer-highlight.svg
new file mode 100644
index 0000000..286e046
--- /dev/null
+++ b/src/img/pointer-highlight.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
diff --git a/src/img/pointer.svg b/src/img/pointer.svg
new file mode 100644
index 0000000..20f9aac
--- /dev/null
+++ b/src/img/pointer.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
diff --git a/src/js/pinpoint.js b/src/js/pinpoint.js
new file mode 100644
index 0000000..f5a5c57
--- /dev/null
+++ b/src/js/pinpoint.js
@@ -0,0 +1,324 @@
+/*
+ Pinpoint v1.0.0
+*/
+
+function Pinpoint(opts){
+ 'use strict';
+
+ var that = this;
+ this.opts = opts;
+ this.opts.el = this.opts.el || '#map-el';
+ this.$el = $(this.opts.el);
+ this.opts.basemap = opts.basemap || 'http://{s}.tile.osm.org/{z}/{x}/{y}.png';
+ this.opts.basemapCredit = opts.basemapCredit || 'Leaflet | © OpenStreetMap contributors';
+
+ this.addElements();
+ this.fillText();
+ this.setAspectRatio();
+ this.setupMap();
+ this.calcBounds();
+
+ this.disableInteraction();
+
+ if (this.opts.creation) {
+ this.enableInteraction();
+ this.map.remove();
+ this.map.setMaxBounds( null );
+ this.setupMap({nozoomlimits: true});
+
+ }
+
+ this.$el.find('.map-outer').click( this.enableInteraction.bind(that) );
+
+ if (opts.minimap) {
+ this.addMinimap();
+ }
+
+ for (var i = 0; i < opts.markers.length; i++) {
+ this.addMarker(opts.markers[i], i);
+ }
+
+ console.log(opts);
+ if (opts.geojson) {
+ this.addGeoJSON(opts.geojson);
+ }
+
+ if (typeof Iframe !== 'undefined') {
+ var fm = Iframe.init();
+ }
+ if ($(window).smartresize) {
+ $(window).smartresize( this.onWindowResize.bind(that) );
+ }
+}
+
+Pinpoint.prototype.addElements = function(){
+
+ var pointer = ' ';
+ var html = '
'+
+ '
'+
+ ''+
+ '
'+
+ '
'+pointer+'Zoom/Pan '+
+ '
'+pointer.replace('#697379','white')+'Zoom/Pan '+
+ '
'+
+ '
'+
+ '
'+
+ ' '+this.opts.basemapCredit+'
';
+ this.$el.html( html );
+}
+
+Pinpoint.prototype.setAspectRatio = function(){
+
+ var aspectRatios = {
+ "tall": 1.2,
+ "square": 1,
+ "wide": (2/3)
+ };
+
+ var aspectRatio = aspectRatios[this.opts['aspect-ratio']];
+ var newHeight = this.$el.find('.map-inner').width() * aspectRatio;
+ this.$el.find('.map-inner, .map-cover').height( newHeight );
+
+ if (this.map) {
+ this.map.invalidateSize();
+ }
+
+}
+
+Pinpoint.prototype.onWindowResize = function(){
+ this.setAspectRatio();
+ $(window).trigger('resize');
+ // this.map.setView([this.opts.lat, this.opts.lon]);
+}
+
+Pinpoint.prototype.setupMap = function(mapopts){
+
+ var opts = this.opts;
+
+ var maxZoom = opts.zoom +1;
+ var minZoom = opts.zoom -1;
+ if (mapopts && mapopts.nozoomlimits) {
+ maxZoom = 20;
+ minZoom = 1;
+ }
+
+ var mapOptions = {
+ scrollWheelZoom: true,
+ keyboard: false,
+ maxZoom: maxZoom,
+ minZoom: minZoom,
+ attributionControl: false
+ };
+
+ var mapEl = this.$el.find('.map-inner')[0];
+ this.map = L.map(mapEl, mapOptions)
+ .setView([opts.lat, opts.lon], opts.zoom);
+ L.control.scale({ position: 'topright' }).addTo(this.map); // scale bar
+ // put miles on top of km
+ var $scaleParent = this.$el.find('.leaflet-control-scale.leaflet-control');
+ $scaleParent.find('.leaflet-control-scale-line').eq(0).detach().appendTo($scaleParent);
+
+ L.tileLayer(this.opts.basemap).addTo(this.map);
+
+ if (opts.dragend) {
+ this.map.on('dragend',opts.dragend);
+ }
+ if (opts.zoomend) {
+ this.map.on('zoomend',opts.zoomend);
+ }
+
+}
+
+Pinpoint.prototype.addMarker = function(mopts, index){
+ this.markers = this.markers || [];
+ mopts.icon = mopts.icon || 'circle';
+ // set the icon type
+ var squareIcon = L.divIcon({
+ className: 'marker-icon marker-icon-'+mopts.icon
+ });
+ var icon = L.marker(
+ [mopts.lat, mopts.lon],
+ {
+ icon: squareIcon,
+ draggable: this.opts.creation,
+ title: index
+ }
+ ).addTo(this.map);
+ mopts.label = mopts.label || 'plain';
+ var labelDir = mopts["label-direction"] || 'north';
+ if (mopts.label === 'callout') {
+ var textBox = L.divIcon({
+ className: 'marker-label-callout '+labelDir,
+ html: ''+mopts.text+'
'
+ });
+ } else if (mopts.label === 'plain') {
+ var textBox = L.divIcon({
+ className: 'marker-label-plain '+labelDir,
+ html: ''+mopts.text+'
'
+ });
+ }
+ var text = L.marker(
+ [mopts.lat, mopts.lon],
+ {
+ icon: textBox
+ }
+ ).addTo(this.map);
+
+ // you can set .my-div-icon styles in CSS
+
+ // L.marker([50.505, 30.57]).addTo(map);
+
+ var $mi = this.$el.find('.marker-inner').eq(-1);
+ $mi.css( 'margin-left', -$mi.outerWidth()/2 );
+ setTimeout((function(){
+ $mi.css( 'margin-left', -$mi.outerWidth()/2 );
+ }).bind(this),100);
+
+ if (this.opts.markerdragend) {
+ icon.on('dragend', this.opts.markerdragend);
+ }
+
+ this.markers.push({
+ icon: icon,
+ text: text
+ });
+}
+
+Pinpoint.prototype.addMinimap = function(){
+ var minitiles = L.tileLayer(
+ this.opts.basemap, {
+ attribution: ''
+ });
+
+ var miniMap = new L.Control.MiniMap(minitiles, {
+ zoomLevelOffset: this.opts['minimap-zoom-offset'] || -5,
+ width: 100,
+ height: 100,
+ aimingRectOptions: {
+ color: 'black',
+ weight: 1,
+ opacity: 1,
+ fillColor: '#999',
+ fillOpacity: 0
+ }
+ }).addTo(this.map);
+
+ // Disable drag and zoom handlers.
+ miniMap._miniMap.dragging.disable();
+ miniMap._miniMap.touchZoom.disable();
+ miniMap._miniMap.doubleClickZoom.disable();
+ miniMap._miniMap.scrollWheelZoom.disable();
+
+ // Disable tap handler, if present.
+ if (miniMap._miniMap.tap) miniMap._miniMap.tap.disable();
+
+
+}
+
+Pinpoint.prototype.calcBounds = function(){
+ var that = this;
+
+ var bounds = calcNewMaxBounds(this.map);
+ this.map.setMaxBounds( bounds );
+
+ function calcNewMaxBounds(map){
+ // add an extra 30% margin to bounds
+ var boundScaleFactor = 1/3;
+
+ var current = map.getBounds();
+ var hori = Math.abs( current._southWest.lng - current._northEast.lng ) * boundScaleFactor;
+ var vert = Math.abs( current._southWest.lat - current._northEast.lat ) * boundScaleFactor;
+ var southWest = {
+ lat: current._southWest.lat - vert,
+ lng: current._southWest.lng - hori
+ }
+ var northEast = {
+ lat: current._northEast.lat + vert,
+ lng: current._northEast.lng + hori
+ }
+ return L.latLngBounds(southWest, northEast);
+
+ }
+}
+
+Pinpoint.prototype.fillText = function(){
+ if (this.opts.hed && (this.opts.hed.length > 0)) {
+ this.$el.find('.pinpoint-hed').text( this.opts.hed );
+ } else {
+ this.$el.find('.pinpoint-hed').hide();
+ }
+ if (this.opts.dek && (this.opts.dek.length > 0)) {
+ this.$el.find('.pinpoint-dek').text( this.opts.dek );
+ } else {
+ this.$el.find('.pinpoint-dek').hide();
+ }
+ if (this.opts.note && (this.opts.note.length > 0)) {
+ this.$el.find('.pinpoint-note').html( this.opts.note );
+ } else {
+ this.$el.find('.pinpoint-note').hide();
+ }
+ this.$el.find('.pinpoint-hed:visible(), .pinpoint-dek:visible()').eq(0).addClass('pinpoint-topline');
+}
+
+Pinpoint.prototype.disableInteraction = function(){
+ var map = this.map;
+ this.$el.find('.map-outer').addClass('inactive');
+ // map.dragging.disable();
+ // map.touchZoom.disable();
+ // map.doubleClickZoom.disable();
+ // // map.scrollWheelZoom.disable();
+ // map.boxZoom.disable();
+ // map.keyboard.disable();
+ return this;
+}
+
+Pinpoint.prototype.enableInteraction = function(){
+ var map = this.map;
+ this.$el.find('.map-outer').removeClass('inactive');
+ // map.dragging.enable();
+ // map.touchZoom.enable();
+ // map.doubleClickZoom.enable();
+ // // map.scrollWheelZoom.enable();
+ // map.boxZoom.enable();
+ // map.keyboard.enable();
+ return this;
+}
+
+Pinpoint.prototype.remove = function(){
+ this.map.remove();
+ this.$el.empty();
+}
+
+Pinpoint.prototype.addGeoJSON = function(geojson){
+ var map = this.map;
+ var features = geojson.features;
+ console.log(features);
+ for (var i = 0; i < features.length; i++) {
+ if (features[i].geometry && features[i].geometry) {
+ if (features[i].properties && features[i].properties.pinpointStyle) {
+ var styleName = features[i].properties.pinpointStyle;
+ } else {
+ var styleName = '';
+ }
+ var type = features[i].geometry.type;
+ if ( isOneOf( type, ["LineString", "MultiLineString", "Polygon", "MultiPolygon"]) ) {
+ L.geoJson(features[i].geometry, {
+ style: {
+ className: 'pinpoint-geojson '+styleName
+ }
+ }).addTo(map);
+
+ }
+ }
+ }
+
+ function isOneOf( needle, haystack ){
+ for (var i = 0; i < haystack.length; i++) {
+ if (haystack[i] === needle) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
diff --git a/src/scss/geojson.scss b/src/scss/geojson.scss
new file mode 100644
index 0000000..292889e
--- /dev/null
+++ b/src/scss/geojson.scss
@@ -0,0 +1,35 @@
+.pinpoint-geojson {
+ stroke: #777;
+ stroke-width: 3;
+ stroke-opacity: 1;
+ fill-opacity: 0;
+}
+
+.pinpoint-geojson.dashed {
+ @extend .pinpoint-geojson;
+ stroke-dasharray: 6 6;
+}
+
+.pinpoint-geojson.dashed-clockwise {
+ @extend .pinpoint-geojson.dashed;
+ animation: dash 100s linear infinite reverse;
+ -webkit-animation: dash 100s linear infinite reverse;
+}
+
+.pinpoint-geojson.dashed-anticlockwise {
+ @extend .pinpoint-geojson.dashed-clockwise;
+ animation: dash 100s linear infinite;
+ -webkit-animation: dash 100s linear infinite;
+}
+
+@-webkit-keyframes dash {
+ to {
+ stroke-dashoffset: 600;
+ }
+}
+
+@keyframes dash {
+ to {
+ stroke-dashoffset: 600;
+ }
+}
diff --git a/src/scss/main.scss b/src/scss/main.scss
new file mode 100644
index 0000000..a0e988b
--- /dev/null
+++ b/src/scss/main.scss
@@ -0,0 +1,103 @@
+/*
+ Pinpoint v1.0.0
+*/
+
+.pinpoint-hed, .pinpoint-dek, .map-outer, .pinpoint-source, .pinpoint-note {
+ font-family: 'Whitney Ssm', sans-serif;
+}
+
+.map-inner {
+ width: 100%;
+}
+.map-outer {
+ position: relative;
+}
+.map-cover {
+ position: absolute;
+ top: 0;
+}
+.map-outer.inactive .map-cover {
+ content: '';
+ width: 100%;
+ z-index: 10000000;
+ cursor: pointer;
+/* background: red;
+ opacity: 0.5; */
+ }
+.map-inner .leaflet-control-zoom {
+ -webkit-transition: opacity 0.5s;
+ transition: opacity 0.5s;
+}
+.map-outer.inactive .leaflet-control-zoom {
+ opacity: 0;
+}
+
+.pinpoint-hed, .pinpoint-dek {
+ margin: 0;
+ padding: 0;
+}
+
+.pinpoint-hed {
+ font-size: 16px;
+ padding-bottom: 5px;
+ margin: 0;
+ font-weight: 600;
+}
+
+.pinpoint-dek {
+ font-size: 16px;
+ margin: 0 0 10px 0;
+ padding: 0;
+ color: #666;
+ font-weight: 400;
+}
+
+.pinpoint-topline {
+ border-top: 1px solid #dadada;
+ padding-top: 7px;
+}
+
+.pinpoint-source, .pinpoint-note {
+ margin-top: 4px;
+ font-size: 12px;
+ color: #666;
+ a:link, a:visited {
+ text-decoration: none;
+ color: inherit;
+ }
+ a:hover {
+ text-decoration: underline;
+ }
+}
+
+.pinpoint-note {
+ margin-bottom: 0;
+}
+
+.leaflet-control-scale-line {
+ border: 0 !important;
+ background: none !important;
+ padding: 2px 0 !important;
+ font-weight: bold;
+ color: black;
+ text-shadow: 0 0 5px white;
+}
+.leaflet-control-scale-line:first-child {
+ border-bottom: 5px solid black !important;
+}
+.leaflet-control-scale-line:last-child {
+ border-top: 5px solid black !important;
+ margin-top: 4px !important;
+}
+.leaflet-control-minimap {
+ box-shadow: 0 0 8px rgba(0,0,0,0.5);
+ pointer-events: none;
+}
+.leaflet-control-minimap .leaflet-zoom-hide > g:first-child:after {
+ content: 'xxxx';
+ display: block;
+}
+
+@import 'markers';
+@import 'overlay';
+@import 'geojson';
diff --git a/src/scss/marker-label-callout.scss b/src/scss/marker-label-callout.scss
new file mode 100644
index 0000000..843aa44
--- /dev/null
+++ b/src/scss/marker-label-callout.scss
@@ -0,0 +1,45 @@
+
+
+
+
+.marker-label-callout {
+ margin-top: -50px !important;
+ margin-left: -50% !important;
+ .marker-inner {
+ @include marker-inner;
+ font-family: 'Whitney Ssm', sans-serif;
+ background: black;
+ color: white;
+ font-weight: 500;
+ font-size: 14px;
+ padding: 6px;
+ margin-top: -6px;
+ &:after {
+ content: "";
+ top: 100%;
+ left: 50%;
+ height: 22px;
+ width: 2px;
+ background: black;
+ position: absolute;
+ pointer-events: none;
+ margin-left: -1px;
+ }
+ }
+}
+
+.marker-label-callout.north {
+ // default
+}
+
+.marker-label-callout.south {
+ .marker-inner {
+ margin-top: 72px;
+ &:after {
+ top: 0;
+ border-color: rgba(0, 0, 0, 0);
+ border-bottom-color: #000000;
+ margin-top: -20px;
+ }
+ }
+}
diff --git a/src/scss/marker-label-plain.scss b/src/scss/marker-label-plain.scss
new file mode 100644
index 0000000..7013a18
--- /dev/null
+++ b/src/scss/marker-label-plain.scss
@@ -0,0 +1,70 @@
+
+.marker-label-plain {
+ margin-top: -28px !important;
+ margin-left: 100% !important;
+ .marker-inner {
+ @include marker-inner;
+ font-family: 'Whitney Ssm', sans-serif;
+ color: black;
+ font-weight: 600;
+ font-size: 14px;
+ }
+}
+
+.marker-label-plain.north {
+ // same as default
+}
+
+.marker-label-plain.northeast {
+ margin-top: -25px !important;
+ .marker-inner {
+ margin-left: 10px !important;
+ }
+}
+
+.marker-label-plain.east {
+ margin-top: -10px !important;
+ .marker-inner {
+ margin-left: 10px !important;
+ }
+}
+
+.marker-label-plain.southeast {
+ margin-top: 8px !important;
+ .marker-inner {
+ margin-left: 10px !important;
+ }
+}
+
+
+.marker-label-plain.south {
+ margin-top: 5px !important;
+}
+
+.marker-label-plain.southwest {
+ margin-top: 8px !important;
+ .marker-inner {
+ margin-right: 25px !important;
+ position: absolute;
+ right: 0;
+ }
+}
+
+.marker-label-plain.west {
+ margin-top: -10px !important;
+ .marker-inner {
+ margin-right: 25px !important;
+ position: absolute;
+ right: 0;
+ }
+}
+
+.marker-label-plain.northwest {
+ margin-top: -25px !important;
+ .marker-inner {
+ margin-right: 25px !important;
+ position: absolute;
+ right: 0;
+ }
+}
+
diff --git a/src/scss/markers.scss b/src/scss/markers.scss
new file mode 100644
index 0000000..e5a4bd8
--- /dev/null
+++ b/src/scss/markers.scss
@@ -0,0 +1,34 @@
+
+/* markers */
+.marker-circle {
+ stroke: none;
+ fill: black;
+ fill-opacity: 1;
+}
+.marker-icon{
+ width: 20px;
+ height: 20px;
+ background: black;
+ margin-left: 10px;
+}
+.marker-icon-square {
+ // default
+}
+.marker-icon-circle {
+ border-radius: 1000px;
+}
+.marker-icon-none {
+ opacity: 0;
+}
+
+@mixin marker-inner {
+ display: inline-block;
+ white-space: nowrap;
+ height: auto !important;
+ position: relative;
+ line-height: initial;
+}
+
+@import 'marker-label-plain';
+@import 'marker-label-callout';
+
diff --git a/src/scss/overlay.scss b/src/scss/overlay.scss
new file mode 100644
index 0000000..3b2082d
--- /dev/null
+++ b/src/scss/overlay.scss
@@ -0,0 +1,49 @@
+
+/* overlay icon */
+.image-interactive-icon {
+ opacity: 0;
+ -webkit-transition: opacity 0.5s;
+ transition: opacity 0.5s;
+ cursor: pointer;
+ display: none;
+}
+
+.map-outer.inactive .image-interactive-icon {
+ display: block;
+ top: 10px;
+ left: 10px;
+ position: absolute;
+ border-radius: 4px;
+ background-size: 50px 50px;
+ background-color: white;
+ z-index: 999;
+ opacity: 1;
+ font-size: 10px;
+ font-weight: 600;
+ padding: 8px 10px;
+ box-shadow: 0 0 3px #777;
+ > svg {
+ vertical-align: middle;
+ display: inline-block;
+ margin-right: 8px;
+ }
+ .image-interactive-icon-text {
+ vertical-align: middle;
+ }
+ &.image-interactive-icon-hover {
+ display: none;
+ background-color: #007ec5;
+ color: white;
+ }
+
+}
+
+
+.map-outer.inactive:hover {
+ .image-interactive-icon {
+ display: none;
+ &.image-interactive-icon-hover {
+ display: block;
+ }
+ }
+}
\ No newline at end of file