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;cZoom/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