├── web ├── CNAME ├── icon.png ├── favicon.ico ├── img │ ├── fork.png │ ├── logo.png │ ├── star.png │ ├── zoom.png │ ├── zoomm.png │ ├── zoomp.png │ ├── console.png │ ├── console-g.png │ ├── console-r.png │ ├── download.png │ ├── pin-black.png │ ├── pin-orange.png │ ├── pin-white.png │ └── pin-black-small.png ├── about.html ├── js │ ├── main.js │ └── jhere-custom.js ├── css │ ├── normalize.scss │ └── main.scss └── index.html ├── docs ├── shot.png └── docco.new.jst ├── src ├── examples │ ├── resources │ │ └── balloon.png │ ├── example.geocode.html │ ├── example.forceLanguage.html │ ├── example.compatibility.html │ ├── example.citySearch.html │ ├── example.dommarkers.html │ ├── example.autoinit.html │ ├── example.customize.html │ ├── example.route.html │ ├── example.shapes.html │ ├── example.getters.html │ ├── example.markers.html │ ├── example.types.html │ ├── example.tire.html │ └── example.basic.html ├── extensions │ ├── customize.js │ ├── autoinit.js │ ├── clustering.js │ ├── geocode.js │ ├── citySearch.js │ ├── domMarkers.js │ ├── customTypes.js │ ├── shapes.js │ ├── route.js │ └── markers.js ├── zepto.adapter.js └── tire.adapter.js ├── .gitignore ├── bower.json ├── test ├── lib │ ├── injectors.js │ ├── jasmine-1.3.1 │ │ ├── MIT.LICENSE │ │ └── jasmine.css │ ├── 3rd-party │ │ └── console-runner.js │ └── mocks.js └── SpecRunner.html ├── dist ├── extensions │ ├── customize.min.js │ ├── autoinit.min.js │ ├── geocode.min.js │ ├── clustering.min.js │ ├── domMarkers.min.js │ ├── citySearch.min.js │ ├── customTypes.min.js │ ├── shapes.min.js │ ├── route.min.js │ └── markers.min.js ├── zepto.adapter.min.js ├── tire.adapter.min.js └── jhere.min.js ├── .jshintrc ├── package.json ├── jhere.jquery.json ├── MIT-LICENSE.txt ├── Makefile ├── README.md └── EXTENSIONS.md /web/CNAME: -------------------------------------------------------------------------------- 1 | jhere.net 2 | -------------------------------------------------------------------------------- /web/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/icon.png -------------------------------------------------------------------------------- /docs/shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/docs/shot.png -------------------------------------------------------------------------------- /web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/favicon.ico -------------------------------------------------------------------------------- /web/img/fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/fork.png -------------------------------------------------------------------------------- /web/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/logo.png -------------------------------------------------------------------------------- /web/img/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/star.png -------------------------------------------------------------------------------- /web/img/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/zoom.png -------------------------------------------------------------------------------- /web/img/zoomm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/zoomm.png -------------------------------------------------------------------------------- /web/img/zoomp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/zoomp.png -------------------------------------------------------------------------------- /web/img/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/console.png -------------------------------------------------------------------------------- /web/img/console-g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/console-g.png -------------------------------------------------------------------------------- /web/img/console-r.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/console-r.png -------------------------------------------------------------------------------- /web/img/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/download.png -------------------------------------------------------------------------------- /web/img/pin-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/pin-black.png -------------------------------------------------------------------------------- /web/img/pin-orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/pin-orange.png -------------------------------------------------------------------------------- /web/img/pin-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/pin-white.png -------------------------------------------------------------------------------- /web/img/pin-black-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/web/img/pin-black-small.png -------------------------------------------------------------------------------- /src/examples/resources/balloon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmarcon/jhere/HEAD/src/examples/resources/balloon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | docs/*.html 4 | docs/*.css 5 | jhere.sublime* 6 | test/lib/jhere.js 7 | .sass-cache -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jhere", 3 | "version": "0.9.0", 4 | "main": "src/jhere.js", 5 | "ignore": [ 6 | "**/.*", 7 | "node_modules", 8 | "components" 9 | ], 10 | "dependencies": { 11 | "jquery": "2.0.0" 12 | } 13 | } -------------------------------------------------------------------------------- /test/lib/injectors.js: -------------------------------------------------------------------------------- 1 | P._injectNS = function(nokia){ 2 | _nokia = nokia; 3 | _ns = nokia.maps; 4 | _ns_map = _ns.map; 5 | }; 6 | P._injectJSLALoader = function(loader){ 7 | _JSLALoader = loader; 8 | P._JSLALoader = loader; 9 | }; -------------------------------------------------------------------------------- /dist/extensions/customize.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function n(n){t=t||nokia.maps;var r=this.map;e.each(n,function(n,i){if(n==="bubble"){var s=r.getComponentById("InfoBubbles")||r.addComponent(new t.map.component.InfoBubbles);s.options.set(i)}else e.error(n+" unsupported")})}var t;e.jHERE.extend("customize",n)})(jQuery); -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "globals": { 4 | "jQuery": true, 5 | "nokia": true, 6 | "Zepto": true, 7 | "tire": true 8 | }, 9 | 10 | "browser": true, 11 | 12 | "curly": true, 13 | "eqeqeq": true, 14 | "forin": true, 15 | "indent": 4, 16 | "multistr": true, 17 | "noarg": true, 18 | "node": true, 19 | "noempty": true, 20 | "strict": false, 21 | "trailing": true, 22 | "undef": true, 23 | "unused": true, 24 | "white": false 25 | } -------------------------------------------------------------------------------- /dist/extensions/autoinit.min.js: -------------------------------------------------------------------------------- 1 | (function(e,t){e(t).on("load",function(){var t=e("#map, .map"),n={};if(t.length===0)return;t.each(function(t,r){var i=e(r);n.center=i.data("center"),n.zoom=i.data("zoom"),n.type=i.data("type"),n.center.match(/[\-+]?\d+(?:\.\d+)?,\s?[\-+]?\d+(?:\.\d+)?/)?(n.center=n.center.split(",").map(function(e){return parseFloat(e)}),i.jHERE(n)):(e.jHERE.geocode||e.error("Geocode extension is required to resolve an address to a location."),e.jHERE.geocode(n.center,function(e){n.center=e,i.jHERE(n)},function(){e.error("Geocoding error")}))})})})(jQuery,window); -------------------------------------------------------------------------------- /dist/extensions/geocode.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function n(e){return typeof e=="function"}function r(r,i,s,o){var u=e.Deferred();return i=n(i)?i:e.noop,s=n(s)?s:e.noop,t._JSLALoader.load().is.done(function(){function t(e,t){var n=e.location;n=o?e.location.address:e.location.position,t==="OK"?(u.resolve(n),i(n)):(u.reject(),s())}var e=nokia.places.search.manager;o?e.reverseGeoCode({latitude:r.latitude||r[0],longitude:r.longitude||r[1],onComplete:t}):e.geoCode({searchTerm:r,onComplete:t})}),u}var t=e.jHERE;t.geocode=function(e,t,n){return r(e,t,n)},t.reverseGeocode=function(e,t,n){return r(e,t,n,!0)}})(jQuery); -------------------------------------------------------------------------------- /dist/extensions/clustering.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function o(e,n){return i||(i=new t.clustering.ClusterProvider(e,{eps:n.eps||16,minPts:1,dataPoints:[]})),i}var t,n,r,i,s={};s.is=!1,s.load=function(){return s.is&&s.is.state().match(/pending|resolved/)?this:(s.is=e.Deferred(),nokia.Features.load({clustering:"auto"},function(){s.is.resolve()}),this)},n=function(n,r){var i,u=this;t=t||nokia.maps,s.load().is.done(function(){r=r||{},i=o(u.map,r),e.isArray(n)||(n=[n]),i.addAll(n),i.cluster()})},r=function(e,n){var r,i=this;t=t||nokia.maps,s.load().is.done(function(){r=o(i.map,n),r.clean()})},e.jHERE.extend("cluster",n),e.jHERE.extend("nocluster",r)})(jQuery); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jHERE", 3 | "version": "0.9.0", 4 | "description": "Maps made simple.", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "docs" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/mmarcon/jhere.git" 15 | }, 16 | "keywords": [ 17 | "maps", 18 | "nokia", 19 | "maps", 20 | "jquery" 21 | ], 22 | "author": "Massimiliano Marcon (@mmarcon)", 23 | "license": "MIT", 24 | "devDependencies": { 25 | "uglify-js": "1.3.4", 26 | "jshint": "0.9.1", 27 | "phantom-jasmine": "0.1.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /dist/extensions/domMarkers.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function i(i,s,u){var a,f=this.map;t||(t=e("
").prependTo(f.getUIContainer())),a=e(s),a.each(function(r,s){var a;a=e(s),a.css("position","absolute"),a.data("anchor",u.anchor),u.anchor||(u.anchor={x:a.width()/2,y:a.height()/2}),u=e.extend({},n.marker,u),a.data("position",i),a.data("updatePosition",o),f.addListener("mapviewchange",function(){o.call(a,null,f)}),t.append(a)}),f.addListener("mapviewchange",function(){r||(r=!!a.trigger("maploaded"))})}function s(t,n){var r=e(n),i=r.data();i.updatePosition&&i.updatePosition.call(r,t,this.map)}function o(t,n){var r,i=e(this),s=i.data();t=t||s.position,r=n.geoToPixel({latitude:t.latitude||t[0],longitude:t.longitude||t[1]}),i.data("position",t),i.css("left",r.x-s.anchor.x+"px"),i.css("top",r.y-s.anchor.y+"px")}var t,n,r=!1;n={anchor:{x:0,y:0}},e.jHERE.extend("dommarker",i),e.jHERE.extend("dommarkerupdate",s)})(jQuery); -------------------------------------------------------------------------------- /dist/zepto.adapter.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function t(){e.each(this.queue,function(e,t){typeof t=="function"&&t.call(null)})}e.error=function(e){throw new Error(e)},e.Deferred=function(){if(!(this instanceof e.Deferred))return new e.Deferred;this.queue=[],this._state="pending"};var n=e.Deferred.prototype,r,i,s;n.resolve=function(){this._state="resolved",t.call(this)},n.state=function(){return this._state},n.done=function(e){if(this._state==="pending"){this.queue.push(e);return}e.call(null)},r=function(){this.store={},this.counter=0},i=r.prototype,i.data=function(e,t,n){if(!n)return this.store[e.__data]&&this.store[e.__data][t];e.__data||(e.__data="cache"+this.counter++),this.store[e.__data]=this.store[e.__data]||{},this.store[e.__data][t]=n},i.removeData=function(e,t){if(t){this.store[e.__data][t]=null;return}this.store[e.__data]=null},s=new r,e.data=function(){return s.data.apply(s,arguments)},e.removeData=function(){return s.removeData.apply(s,arguments)},window.jQuery=e})(Zepto); -------------------------------------------------------------------------------- /dist/extensions/citySearch.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function r(e){return e.match(/^\s*$/)}function i(e){return typeof e=="string"}function s(e){return typeof e=="function"}function o(e,t){if(r(e.query))return t.resolve([]);nokia.places.search.manager.findPlaces({searchTerm:e.query,useGeoLocation:e.useGeoLocation,onComplete:function(n,r){if(r!=="OK")return t.reject();var i=u(n,e),s=[];i.forEach(function(e){var n=e.position;n.onComplete=function(r,o){o==="OK"?s.push(a(r)):(delete n.onComplete,s.push(e)),s.length===i.length&&t.resolve(s)},nokia.places.search.manager.reverseGeoCode(n)})}})}function u(e,n){return e.results.items.filter(function(e){return e.category.categoryId===t}).slice(0,n.resultsLimit)}function a(e){return e.location}function f(e){if(!e||i(e))e={query:e};var t={};for(var r in n)n.hasOwnProperty(r)&&(t[r]=e[r]||n[r]);return t}var t="city-town-village",n={query:"",resultsLimit:10,useGeoLocation:!0};e.jHERE.searchCities=function(t,n,r){var i=e.Deferred(),u=i.promise();return n=s(n)?n:e.noop,r=s(r)?r:e.noop,e.jHERE._JSLALoader.load().is.done(function(){o(f(t),i)}),e.when(u).then(function(e){n(e)},function(e){r(e)}),u}})(jQuery); -------------------------------------------------------------------------------- /jhere.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jhere", 3 | "title": "jHERE - Maps Made easy", 4 | "description": "Maps are cool, but map APIs are complicated. jHERE solves this problem by offering a simple but powerful map API in the form of a jQuery (or Zepto.JS) plugin.", 5 | "keywords": [ 6 | "here", 7 | "maps", 8 | "location", 9 | "heatmaps", 10 | "kml" 11 | ], 12 | "version": "0.9.0", 13 | "author": { 14 | "name": "Massimiliano Marcon", 15 | "url": "http://marcon.me", 16 | "email": "max@jhere.net" 17 | }, 18 | "maintainers": [ 19 | { 20 | "name": "Massimiliano Marcon", 21 | "email": "max@jhere.net", 22 | "url": "http://marcon.me" 23 | } 24 | ], 25 | "licenses": [ 26 | { 27 | "type": "MIT", 28 | "url": "https://github.com/mmarcon/jhere/blob/master/LICENSE.txt" 29 | } 30 | ], 31 | "bugs": "https://github.com/mmarcon/jhere/issues", 32 | "homepage": "http://jhere.net", 33 | "docs": "http://jhere.net/docs.html", 34 | "download": "https://github.com/mmarcon/jhere/archive/master.zip", 35 | "dependencies": { 36 | "jquery": ">=1.8" 37 | } 38 | } -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Massimiliano Marcon, http://marcon.me 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /test/lib/jasmine-1.3.1/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2011 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /dist/extensions/customTypes.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function n(e,n){t=t||nokia.maps;var i=this.map,s,o={map:i.NORMAL,satellite:i.SATELLITE,smart:i.SMARTMAP,terrain:i.TERRAIN,pt:i.SMART_PT,community:i.NORMAL_COMMUNITY,satcommunity:i.SATELLITE_COMMUNITY,traffic:i.TRAFFIC};s=n&&r(e,n),s?this.mtype="custom":(this.mtype=e in o?e:"map",s=o[this.mtype]),i.set("baseMapType",s)}function r(e,n){if(!n)return!1;var r=o(e,n),u=1 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 33 | 34 | -------------------------------------------------------------------------------- /src/examples/example.forceLanguage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 36 | 37 | -------------------------------------------------------------------------------- /src/examples/example.compatibility.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 15 | 16 | 17 | 18 |
19 | 23 | 24 | 25 | 26 | 38 | 39 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: dist test 2 | 3 | PLUGIN = jhere 4 | TESTED_CODE = test/lib/jhere.js 5 | INJECTORS = $(shell cat test/lib/injectors.js | tr -d ' ') 6 | RUNNER = test/SpecRunner.html 7 | 8 | deps: 9 | @npm install 10 | 11 | dist: hint plugin zepto tire extensions summary 12 | 13 | plugin: 14 | @./node_modules/.bin/uglifyjs -nc -o dist/$(PLUGIN).min.js src/$(PLUGIN).js 15 | 16 | zepto: 17 | @./node_modules/.bin/uglifyjs -nc -o dist/zepto.adapter.min.js src/zepto.adapter.js 18 | 19 | tire: 20 | @./node_modules/.bin/uglifyjs -nc -o dist/tire.adapter.min.js src/tire.adapter.js 21 | 22 | extensions: 23 | @./build-scripts/build-extensions.sh 24 | 25 | summary: 26 | @ls -nhl dist | grep -v ^d | awk '{print $$9,$$5}' | tail -n +2; \ 27 | ls -nhl dist/extensions | grep -v ^d | awk '{print $$9,$$5}' | tail -n +2 28 | 29 | hint: 30 | @./node_modules/.bin/jshint ./src 31 | 32 | doc: 33 | @docco -t docs/docco.new.jst -o docs src/$(PLUGIN).js;mv docs/$(PLUGIN).html web/docs.html; 34 | 35 | website: doc 36 | @./build-scripts/update-website.sh "$(COMMENT)" 37 | 38 | test: deps 39 | @sed 's/\/\*\*\*_\*\*\*\//$(INJECTORS)/g' src/$(PLUGIN).js > $(TESTED_CODE); \ 40 | command -v phantomjs >/dev/null 2>&1 || { echo >&2 "PhantomJS not installed. Run the tests from the browser."; exit 0; }; \ 41 | ./node_modules/.bin/phantom-jasmine $(RUNNER) 42 | -------------------------------------------------------------------------------- /dist/extensions/shapes.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function f(e){return e instanceof Array?{latitude:e[0],longitude:e[1]}:e}function l(e){return e?(e.pen=e.pen||{},e.brush=e.brush||{},e.pen.strokeColor=e.pen.strokeColor||e.stroke||"#111",e.stroke="solid",e.pen.lineWidth=e.pen.lineWidth||e.thickness||1,e.brush.color=e.brush.color||e.fill,e):e}function c(e,n){e.objects.add(new t.map.Circle(f(n.center),n.radius||1e3,n.style))}function h(e,n){var r=new t.geo.BoundingBox(f(n.topLeft),f(n.bottomRight),!1);e.objects.add(new t.map.Rectangle(r,n.style))}function p(n,r){r.points=e.map(r.points,function(e){return f(e)}),n.objects.add(new t.map.Polyline(r.points,r.style))}function d(n,r){r.points=e.map(r.points,function(e){return f(e)}),n.objects.add(new t.map.Polygon(r.points,r.style))}var t,n,r,i,s,o,u,a;n=function(n,r){t=t||nokia.maps,a||(a=new t.map.Container,this.map.objects.add(a)),r.style=l(r.style);switch(n){case"circle":c(a,r);break;case"rectangle":h(a,r);break;case"polyline":p(a,r);break;case"polygon":d(a,r);break;default:e.error(n+" not supported")}},r=function(){a&&a.objects&&a.objects.clear()},i=function(e){n.call(this,"circle",e)},s=function(e){n.call(this,"rectangle",e)},o=function(e){n.call(this,"polyline",e)},u=function(e){n.call(this,"polygon",e)},e.jHERE.extend("shape",n),e.jHERE.extend("clearShapes",r),e.jHERE.extend("circle",i),e.jHERE.extend("rectangle",s),e.jHERE.extend("polyline",o),e.jHERE.extend("polygon",u)})(jQuery); -------------------------------------------------------------------------------- /src/examples/example.citySearch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Example for the City Search extension 6 | 7 | 8 | 9 | 10 |

Results for ''

11 | 14 | 15 | 16 | 17 | 18 | 43 | 44 | -------------------------------------------------------------------------------- /dist/extensions/route.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function o(e){return e instanceof Array?{latitude:e[0],longitude:e[1]}:e}var t,n,r,i,s={type:"shortest",transportMode:"car",options:"",trafficMode:"default",width:4,color:"#ff6347",marker:{text:"#",textColor:"#fff"},zoomTo:!0};i=function(n,i,u,a){var f,l,c,h;t=t||nokia.maps,n=o(n),i=o(i),u instanceof Array?a=e.extend({},s,a):(a=e.extend({},s,u),u=[]),c=function(n,i,s){var o,u,f,l={},c;s==="finished"?(o=n.getRoutes(),f=o[0],u=new t.map.Polyline(f&&f.shape,{pen:new t.util.Pen({lineWidth:a.width,strokeColor:a.color})}),r||(r=new t.map.Container,this.map.objects.add(r)),r.objects.add(u),e.each(f.waypoints,e.proxy(function(t,n){var r=e.extend({},a.marker);a.marker.text==="#"&&(r.text=t+1),this.marker(n.originalPosition,r)},this)),a.zoomTo&&this.map.zoomTo(r.getBoundingBox(),!1,"default"),l.time=f.summary.travelTime,l.length=f.summary.distance,l.waypoints=f.waypoints,l.legs=f.legs,typeof a.onroute=="function"&&a.onroute.call(this.element,l),c=e.Event("jhere.route",{route:l,target:this.element}),e(this.element).trigger(c)):s==="failed"&&e.error("Failed to calculate route")},f=new t.routing.Manager,f.addObserver("state",e.proxy(c,this)),l=new t.routing.WaypointParameterList,l.addCoordinate(n),e.each(u,function(e,t){l.addCoordinate(o(t))}),l.addCoordinate(i),h={transportModes:[a.transportMode],type:a.type,options:a.options,trafficMode:a.trafficMode},f.calculateRoute(l,[h])},n=function(){r&&r.objects&&r.objects.clear()},e.jHERE.extend("route",i),e.jHERE.extend("clearRoutes",n)})(jQuery); -------------------------------------------------------------------------------- /dist/extensions/markers.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function m(e){var t=e.target,n=t[e.type];y(n)&&n.call(this.element,g(e,t.coordinate))}function g(t,n){return e.Event(t.type,{originalEvent:t,geo:{latitude:n.latitude,longitude:n.longitude},target:t.target})}function y(e){return typeof e=="function"}var t,n,r,i,s,o={text:"",textColor:"#333333",fill:"#ff6347",stroke:"#333333",shape:"balloon",icon:undefined,group:"_"},u=e.proxy,a="mouse",f="click",l="drag",c="touch",h="start",p="end",d="move",v=[f,"dbl"+f,a+"up",a+"down",a+d,a+"over",a+"out",a+"enter",a+"leave","longpress",l+h,l,l+p,"resize",c+h,c+p,c+d];n=function(n,r){var i={},s=u(m,this),a=this._mc,f="Marker",l,c;this.groups=this.groups||{},c=this.groups,t=t||nokia.maps,e.each(v,function(e,t){i[t]=[s,!1,null]}),r=e.extend({},o,r),r.textPen=r.textPen||{strokeColor:r.textColor},r.pen=r.pen||{strokeColor:r.stroke},r.brush=r.brush||{color:r.fill},r.eventListener=i,r.icon||(f="Standard"+f),l=new t.map[f](n,r),c[r.group]=c[r.group]||[],c[r.group].visible=c[r.group].length===0?!0:c[r.group].visible,c[r.group].push(l),c[r.group].visible&&a.objects.add(l)},i=function(t,n){var r=this._mc,i=r.objects,s;this.groups=this.groups||{},s=this.groups,t=t instanceof Array?t:[t],e.each(t,function(e,t){n?i.addAll(s[t]||[]):i.removeAll(s[t]||[]),s[t].visible=!!n})},r=function(){this._mc.objects.clear(),this.groups={}},s=function(e){if(this._mc.objects.getLength()>1){var t=this._mc.getBoundingBox();this.map.zoomTo(t,e||!1)}},e.jHERE.extend("marker",n),e.jHERE.extend("markergroups",i),e.jHERE.extend("nomarkers",r),e.jHERE.extend("zoomToMarkers",s)})(jQuery); -------------------------------------------------------------------------------- /src/examples/example.dommarkers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 | 35 | 36 | 53 | 54 | -------------------------------------------------------------------------------- /src/examples/example.autoinit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | HTML5 boilerplate—all you really need… 7 | 31 | 32 | 33 | 34 |

Centered with coordinates

35 |
36 |

Centered with geocoding of address

37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /dist/tire.adapter.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function t(){e.each(this.queue,function(e,t){typeof t=="function"&&t.call(null)})}function u(e){return e._zid||(e._zid=o++)}e.error=function(e){throw new Error(e)},e.Deferred=function(){if(!(this instanceof e.Deferred))return new e.Deferred;this.queue=[],this._state="pending"};var n=e.Deferred.prototype,r,i,s;n.resolve=function(){this._state="resolved",t.call(this)},n.state=function(){return this._state},n.done=function(e){if(this._state==="pending"){this.queue.push(e);return}e.call(null)},r=function(){this.store={},this.counter=0},i=r.prototype,i.data=function(e,t,n){if(!n)return this.store[e.__data]&&this.store[e.__data][t];e.__data||(e.__data="cache"+this.counter++),this.store[e.__data]=this.store[e.__data]||{},this.store[e.__data][t]=n},i.removeData=function(e,t){if(t){this.store[e.__data][t]=null;return}this.store[e.__data]=null},s=new r,e.data=function(){return s.data.apply(s,arguments)},e.removeData=function(){return s.removeData.apply(s,arguments)};var o=1;e.proxy=function(t,n){if(e.isFunction(t)){var r=function(){return t.apply(n,arguments)};return r._zid=u(t),r}if(typeof n=="string")return e.proxy(t[n],t);throw new TypeError("expected function")},e.inArray=function(e,t,n){return[].indexOf.call(t,e,n)},e.Event=function(t,n){typeof t!="string"&&(n=t,t=n.type);var r=document.createEvent((t.match(/click|mouse/)?"Mouse":"")+"Events"),i=!0;return n&&(e.each(n,function(e,t,n,s){s=e==="bubbles"?i=!!t:r[e]=t}),r.xdata=n,r.initEvent(t,i,!0,null,null,null,null,null,null,null,null,null,null,null,null),r.isDefaultPrevented=function(){return this.defaultPrevented}),r},e.fn._trigger=e.fn.trigger,e.fn.trigger=function(){if(!arguments[0].xdata)return e.fn._trigger.apply(this,arguments);e.fn._trigger.call(this,arguments[0].type,arguments[0].xdata)},window.jQuery=e})(tire); -------------------------------------------------------------------------------- /src/examples/example.customize.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 44 | 45 | -------------------------------------------------------------------------------- /src/examples/example.route.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 34 | 35 | 36 | 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 58 | 59 | -------------------------------------------------------------------------------- /src/extensions/customize.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Massimiliano Marcon, http://marcon.me 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ;(function($){ 24 | var _ns; 25 | 26 | //### Customize particular aspects of the map 27 | //`$('.selector').jHERE('customize', options)` 28 | // 29 | //Supported options are currently the following: 30 | // 31 | //
{
32 |     //  bubble: {
33 |     //    backgroundColor: '#ffffff',
34 |     //    color: '#111111',
35 |     //    autoClose: false /*Should bubbles be autoclosed when a new one is open?*/
36 |     //  }
37 |     //}
38 | function customize(options){ 39 | _ns = _ns || nokia.maps; 40 | var map = this.map; 41 | $.each(options, function(k, v){ 42 | if(k === 'bubble') { 43 | var bubbles = map.getComponentById('InfoBubbles') || 44 | map.addComponent(new _ns.map.component.InfoBubbles()); 45 | bubbles.options.set(v); 46 | } else { 47 | $.error(k + ' unsupported'); 48 | } 49 | }); 50 | } 51 | 52 | $.jHERE.extend('customize', customize); 53 | }(jQuery)); -------------------------------------------------------------------------------- /test/SpecRunner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Spec Runner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/extensions/autoinit.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Massimiliano Marcon, http://marcon.me 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ;(function($, w){ 24 | 25 | //## Auto-init extension 26 | // 27 | //When this extension is included a map is automatically initialized on a 28 | //container with `id` or `class` `map`. 29 | //Options are passed via data attributes as follows: 30 | // 31 | //`
` 32 | $(w).on('load', function(){ 33 | var target = $('#map, .map'), options = {}; 34 | if(target.length === 0) { 35 | return; 36 | } 37 | target.each(function(i, t){ 38 | var target = $(t); 39 | options.center = target.data('center'); 40 | options.zoom = target.data('zoom'); 41 | options.type = target.data('type'); 42 | /*if it is something like 52.49,13.37*/ 43 | if(options.center.match(/[\-+]?\d+(?:\.\d+)?,\s?[\-+]?\d+(?:\.\d+)?/)) { 44 | options.center = options.center.split(',').map(function(v){return parseFloat(v);}); 45 | target.jHERE(options); 46 | } else { 47 | if(!$.jHERE.geocode){ 48 | /*Uhmm... missing geocode dependency*/ 49 | $.error('Geocode extension is required to resolve an address to a location.'); 50 | } 51 | $.jHERE.geocode(options.center, function(center){ 52 | options.center = center; 53 | target.jHERE(options); 54 | }, function(){ 55 | $.error('Geocoding error'); 56 | }); 57 | } 58 | }); 59 | }); 60 | })(jQuery, window); -------------------------------------------------------------------------------- /src/extensions/clustering.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Massimiliano Marcon, http://marcon.me 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ;(function($){ 24 | var _ns, clusterFn, noClusterFn, _cluster; 25 | 26 | var _JSLALoader = {}; 27 | _JSLALoader.is = false; 28 | _JSLALoader.load = function(){ 29 | if(_JSLALoader.is && _JSLALoader.is.state().match(/pending|resolved/)) { 30 | /*JSLA loading is already in progress*/ 31 | return this; 32 | } 33 | _JSLALoader.is = $.Deferred(); 34 | nokia.Features.load({clustering: 'auto'}, function(){_JSLALoader.is.resolve();}); 35 | return this; 36 | }; 37 | 38 | function getCluster(map, options){ 39 | if(!_cluster) { 40 | _cluster = new _ns.clustering.ClusterProvider(map, { 41 | eps: options.eps || 16, 42 | minPts: 1, 43 | dataPoints: [] 44 | }); 45 | } 46 | return _cluster; 47 | } 48 | 49 | clusterFn = function(data, options) { 50 | var cluster, self = this; 51 | _ns = _ns || nokia.maps; 52 | _JSLALoader.load().is.done(function(){ 53 | options = options || {}; 54 | cluster = getCluster(self.map, options); 55 | if(!$.isArray(data)) { 56 | data = [data]; 57 | } 58 | cluster.addAll(data); 59 | cluster.cluster(); 60 | }); 61 | }; 62 | 63 | noClusterFn = function(data, options) { 64 | var cluster, self = this; 65 | _ns = _ns || nokia.maps; 66 | _JSLALoader.load().is.done(function(){ 67 | cluster = getCluster(self.map, options); 68 | cluster.clean(); 69 | }); 70 | }; 71 | 72 | $.jHERE.extend('cluster', clusterFn); 73 | $.jHERE.extend('nocluster', noClusterFn); 74 | }(jQuery)); -------------------------------------------------------------------------------- /src/examples/example.shapes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 29 | 30 | 31 | 32 |
Clear all shapes
33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 70 | 71 | -------------------------------------------------------------------------------- /src/examples/example.getters.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 44 | 45 | 46 | 47 | 53 |
54 | 55 | 56 | 57 | 58 | 92 | 93 | -------------------------------------------------------------------------------- /src/examples/example.markers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 49 | 50 | 51 | 52 |
53 | 61 | 62 | 63 | 64 | 65 | 66 | 92 | 93 | -------------------------------------------------------------------------------- /src/zepto.adapter.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Massimiliano Marcon, http://marcon.me 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ;(function($){ 24 | $.error = function(msg){ 25 | throw new Error(msg); 26 | }; 27 | /*MINIMAL implementation of $.Deferred*/ 28 | /*This only implements the method required by jHERE*/ 29 | /*So do not use it for real "promises" purpose*/ 30 | $.Deferred = function(){ 31 | if(!(this instanceof $.Deferred)) { 32 | return new $.Deferred(); 33 | } 34 | this.queue = []; 35 | this._state = 'pending'; 36 | }; 37 | 38 | function callCallbacks(){ 39 | $.each(this.queue, function(i, fn){ 40 | if(typeof fn === 'function') { 41 | fn.call(null); 42 | } 43 | }); 44 | } 45 | 46 | var D = $.Deferred.prototype, Data, P, d; 47 | D.resolve = function(){ 48 | this._state = 'resolved'; 49 | callCallbacks.call(this); 50 | }; 51 | D.state = function(){ 52 | return this._state; 53 | }; 54 | D.done = function(callback){ 55 | if(this._state === 'pending') { 56 | this.queue.push(callback); 57 | return; 58 | } 59 | callback.call(null); 60 | }; 61 | 62 | Data = function(){ 63 | this.store = {}; 64 | this.counter = 0; 65 | }; 66 | P = Data.prototype; 67 | P.data = function(element, key, object){ 68 | if(!object) { 69 | //getter 70 | return this.store[element.__data] && this.store[element.__data][key]; 71 | } 72 | if(!element.__data) { 73 | element.__data = 'cache' + this.counter++; 74 | } 75 | this.store[element.__data] = this.store[element.__data] || {}; 76 | this.store[element.__data][key] = object; 77 | }; 78 | P.removeData = function(element, key){ 79 | if(key) { 80 | this.store[element.__data][key] = null; 81 | return; 82 | } 83 | this.store[element.__data] = null; 84 | }; 85 | 86 | d = new Data(); 87 | $.data = function(){ 88 | return d.data.apply(d, arguments); 89 | }; 90 | $.removeData = function(){ 91 | return d.removeData.apply(d, arguments); 92 | }; 93 | 94 | //Export Zepto as jQuery so there is no need 95 | //to check for it in the plugin. 96 | window.jQuery = $; 97 | }(Zepto)); -------------------------------------------------------------------------------- /test/lib/3rd-party/console-runner.js: -------------------------------------------------------------------------------- 1 | /** 2 | Jasmine Reporter that outputs test results to the browser console. 3 | Useful for running in a headless environment such as PhantomJs, ZombieJs etc. 4 | 5 | Usage: 6 | // From your html file that loads jasmine: 7 | jasmine.getEnv().addReporter(new jasmine.ConsoleReporter()); 8 | jasmine.getEnv().execute(); 9 | */ 10 | 11 | (function(jasmine, console) { 12 | if (!jasmine) { 13 | throw "jasmine library isn't loaded!"; 14 | } 15 | 16 | var ANSI = {} 17 | ANSI.color_map = { 18 | "green" : 32, 19 | "red" : 31 20 | } 21 | 22 | ANSI.colorize_text = function(text, color) { 23 | var color_code = this.color_map[color]; 24 | return "\033[" + color_code + "m" + text + "\033[0m"; 25 | } 26 | 27 | var ConsoleReporter = function() { 28 | if (!console || !console.log) { throw "console isn't present!"; } 29 | this.status = this.statuses.stopped; 30 | }; 31 | 32 | var proto = ConsoleReporter.prototype; 33 | proto.statuses = { 34 | stopped : "stopped", 35 | running : "running", 36 | fail : "fail", 37 | success : "success" 38 | }; 39 | 40 | proto.reportRunnerStarting = function(runner) { 41 | this.status = this.statuses.running; 42 | this.start_time = (new Date()).getTime(); 43 | this.executed_specs = 0; 44 | this.passed_specs = 0; 45 | this.log("Starting..."); 46 | }; 47 | 48 | proto.reportRunnerResults = function(runner) { 49 | var failed = this.executed_specs - this.passed_specs; 50 | var spec_str = this.executed_specs + (this.executed_specs === 1 ? " spec, " : " specs, "); 51 | var fail_str = failed + (failed === 1 ? " failure in " : " failures in "); 52 | var color = (failed > 0)? "red" : "green"; 53 | var dur = (new Date()).getTime() - this.start_time; 54 | 55 | this.log(""); 56 | this.log("Finished"); 57 | this.log("-----------------"); 58 | this.log(spec_str + fail_str + (dur/1000) + "s.", color); 59 | 60 | this.status = (failed > 0)? this.statuses.fail : this.statuses.success; 61 | 62 | /* Print something that signals that testing is over so that headless browsers 63 | like PhantomJs know when to terminate. */ 64 | this.log(""); 65 | this.log("ConsoleReporter finished"); 66 | }; 67 | 68 | 69 | proto.reportSpecStarting = function(spec) { 70 | this.executed_specs++; 71 | }; 72 | 73 | proto.reportSpecResults = function(spec) { 74 | if (spec.results().passed()) { 75 | this.passed_specs++; 76 | return; 77 | } 78 | 79 | var resultText = spec.suite.description + " : " + spec.description; 80 | this.log(resultText, "red"); 81 | 82 | var items = spec.results().getItems() 83 | for (var i = 0; i < items.length; i++) { 84 | var trace = items[i].trace.stack || items[i].trace; 85 | this.log(trace, "red"); 86 | } 87 | }; 88 | 89 | proto.reportSuiteResults = function(suite) { 90 | if (!suite.parentSuite) { return; } 91 | var results = suite.results(); 92 | var failed = results.totalCount - results.passedCount; 93 | var color = (failed > 0)? "red" : "green"; 94 | this.log(suite.description + ": " + results.passedCount + " of " + results.totalCount + " passed.", color); 95 | }; 96 | 97 | proto.log = function(str, color) { 98 | var text = (color != undefined)? ANSI.colorize_text(str, color) : str; 99 | console.log(text) 100 | }; 101 | 102 | jasmine.ConsoleReporter = ConsoleReporter; 103 | })(jasmine, console); 104 | 105 | -------------------------------------------------------------------------------- /src/examples/example.types.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 32 | 33 | 34 | 35 |
36 |
37 | 47 | 48 | 53 | 54 | 55 | 56 |
57 | 58 | 59 | 60 | 111 | 112 | -------------------------------------------------------------------------------- /src/extensions/geocode.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Massimiliano Marcon, http://marcon.me 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ;(function($){ 24 | var P = $.jHERE; 25 | 26 | function isFunction(fn) { 27 | return typeof fn === 'function'; 28 | } 29 | 30 | function geocode(query, success, error, reverse) { 31 | var deferred = $.Deferred(); 32 | success = isFunction(success) ? success : $.noop; 33 | error = isFunction(error) ? error : $.noop; 34 | P._JSLALoader.load().is.done(function(){ 35 | var searchManager = nokia.places.search.manager; 36 | function geocodeCallback(data, status) { 37 | var location = data.location; 38 | location = reverse ? data.location.address : data.location.position; 39 | if(status === 'OK') { 40 | deferred.resolve(location); 41 | success(location); 42 | } else { 43 | deferred.reject(); 44 | error(); 45 | } 46 | } 47 | if (reverse) { 48 | searchManager.reverseGeoCode({ 49 | latitude: query.latitude || query[0], 50 | longitude: query.longitude || query[1], 51 | onComplete: geocodeCallback 52 | }); 53 | } else { 54 | searchManager.geoCode({ 55 | searchTerm: query, 56 | onComplete: geocodeCallback 57 | }); 58 | } 59 | }); 60 | return deferred; 61 | } 62 | 63 | 64 | //### Geocode 65 | //`$.JHERE.geocode('Berlin, Germany', function(position){}, function(){/*error*/});` 66 | //jHERE exposes the possibility of geocoding an address 67 | //into (latitude, longitude). This call is asynchronous 68 | //and supports a `success` and a `error` callback. 69 | //When jHERE is used with jQuery a $.Deferred object is also returned 70 | //and can be used instead of callbacks. For Zepto.JS a Deferred is also returned, 71 | //however note that it is a custom implementation that only supports the `done` method. 72 | P.geocode = function(query, success, error) { 73 | return geocode(query, success, error); 74 | }; 75 | 76 | //### Reverse Geocode 77 | //`$.JHERE.reverseGeocode({latitude: 52.5, longitude: 13.3}, function(address){}, function(){/*error*/});` 78 | //jHERE exposes the possibility of reverse geocoding a position 79 | //into an address. This call is asynchronous 80 | //and supports a `success` and a `error` callback. 81 | //When jHERE is used with jQuery a $.Deferred object is also returned 82 | //and can be used instead of callbacks. For Zepto.JS a Deferred is also returned, 83 | //however note that it is a custom implementation that only supports the `done` method. 84 | P.reverseGeocode = function(query, success, error) { 85 | return geocode(query, success, error, true); 86 | }; 87 | 88 | }(jQuery)); -------------------------------------------------------------------------------- /src/extensions/citySearch.js: -------------------------------------------------------------------------------- 1 | ;(function($) { 2 | 3 | var cityCategoryId = 'city-town-village'; 4 | 5 | var defaultOptions = { 6 | query: '', 7 | resultsLimit: 10, 8 | useGeoLocation: true 9 | }; 10 | 11 | function isEmpty(string) { 12 | return string.match(/^\s*$/); 13 | } 14 | 15 | function isString(obj) { 16 | return typeof obj === 'string'; 17 | } 18 | 19 | function isFunction(fn) { 20 | return typeof fn === 'function'; 21 | } 22 | 23 | function searchCities(opts, deferred) { 24 | 25 | if (isEmpty(opts.query)) { 26 | return deferred.resolve([]); 27 | } 28 | 29 | nokia.places.search.manager.findPlaces({ 30 | searchTerm: opts.query, 31 | useGeoLocation: opts.useGeoLocation, 32 | onComplete: function(findResult, status) { 33 | if (status !== 'OK') { 34 | return deferred.reject(); 35 | } 36 | 37 | var cities = filterCities(findResult, opts); 38 | var formattedCities = []; 39 | 40 | cities.forEach(function(city) { 41 | var geocodeQuery = city.position; 42 | geocodeQuery.onComplete = function(geocodedCity, status) { 43 | if (status === 'OK') { 44 | formattedCities.push(formatCity(geocodedCity)); 45 | } else { 46 | delete geocodeQuery.onComplete; 47 | formattedCities.push(city); 48 | } 49 | 50 | if (formattedCities.length === cities.length) { 51 | deferred.resolve(formattedCities); 52 | } 53 | }; 54 | nokia.places.search.manager.reverseGeoCode(geocodeQuery); 55 | }); 56 | } 57 | }); 58 | 59 | } 60 | 61 | function filterCities(findResult, opts) { 62 | return findResult.results.items 63 | .filter(function(e) { return e.category.categoryId === cityCategoryId; }) 64 | .slice(0, opts.resultsLimit); 65 | } 66 | 67 | function formatCity(geocodedCity) { 68 | return geocodedCity.location; 69 | } 70 | 71 | function parseOpts(givenOpts) { 72 | if (!givenOpts || isString(givenOpts)) { 73 | givenOpts = { 74 | query: givenOpts 75 | }; 76 | } 77 | 78 | var opts = {}; 79 | for (var opt in defaultOptions) { 80 | if (defaultOptions.hasOwnProperty(opt)) { 81 | opts[opt] = givenOpts[opt] || defaultOptions[opt]; 82 | } 83 | } 84 | return opts; 85 | } 86 | 87 | // ### City Search 88 | // Searches for cities that matches the given query. 89 | // Ex.: `$.JHERE.searchCity(query, function(cities){}, function(){error});` 90 | // Where `query` can be: 91 | // * A **String** 92 | // * An **Object** with the following fields: 93 | // * *query*: criteria 94 | // * *resultsLimit*: limit of results to be returned 95 | // * *useGeoLocation*: use current user location to aid on the search 96 | 97 | // The function returns a jQuery promise object or call the success 98 | // callback with all the cities matching the criteria. In the case where 99 | // the geocoder fails for a specific city, only its position will be returned 100 | // without the city address details. 101 | $.jHERE.searchCities = function(opts, success, error) { 102 | var deferred = $.Deferred(); 103 | var promise = deferred.promise(); 104 | 105 | success = isFunction(success) ? success : $.noop; 106 | error = isFunction(error) ? error : $.noop; 107 | 108 | $.jHERE._JSLALoader.load().is.done(function() { 109 | 110 | searchCities(parseOpts(opts), deferred); 111 | 112 | }); 113 | 114 | $.when(promise).then( 115 | function(v) { 116 | success(v); 117 | }, 118 | function(e) { 119 | error(e); 120 | } 121 | ); 122 | 123 | return promise; 124 | }; 125 | 126 | }(jQuery)); 127 | -------------------------------------------------------------------------------- /docs/docco.new.jst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jHERE - Maps Made Easy 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 |

jHERE

39 |

Maps made easy.

40 | 44 |
45 | 52 |
53 | 54 |
55 |
56 |

Documentation

57 |
58 |
59 | <% for (var i=0, l=sections.length; i 60 | <% var section = sections[i]; %> 61 |
62 | <%= section.docsHtml %> 63 |
64 | <% } %> 65 |
66 |
67 | 68 | 69 | 79 | 80 | 81 | 82 | 83 | 84 | 85 |
86 | 93 | 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #jHERE 2 | 3 | Maps are cool, but map APIs are complicated. jHERE solves this problem by offering a simple but powerful map API in the form of a jQuery (or Zepto.JS) plugin. 4 | 5 | With jHERE, you can easily add interactive maps to your website. In only 4KB, you get a powerful map API, highly customizable markers, event handling and info bubbles. Bonus features are KML support and data visualization via heatmaps. 6 | 7 | ![Screenshot](https://raw.github.com/mmarcon/jhere/master/docs/shot.png) 8 | 9 | ## Add jHERE to your pages 10 | 11 | Adding jHERE to a web page or web application is very easy. jHERE supports both jQuery as well as Zepto.JS, so first of all include one of these libraries. 12 | 13 | 14 | 15 | or 16 | 17 | 18 | 19 | In case you are using [Zepto](http://zeptojs.com/), you will need to include the Zepto adapter, that includes a couple of little things that are not implemented in Zepto and I used in my plugin (`$.Deferred` and `$.data`). 20 | 21 | 24 | 25 | In case you are using [Tire](http://tirejs.github.io/), then include the Tire adapter (adds `$.Deferred`, `$.data`, `$.proxy`, `$.inArray` and `$.Event` to Tire): 26 | 27 | 30 | 31 | Finally include the plugin. 32 | 33 | 34 | 35 | And done. Execute your code on window load. 36 | 37 | 46 | 47 | That's it. All the documentation is available at [jhere.net/docs.html](http://jhere.net/docs.html). 48 | 49 | ## Extensions 50 | 51 | Please refer to [EXTENSIONS.md](https://github.com/mmarcon/jhere/blob/master/EXTENSIONS.md) for information about the extensions for jHERE. 52 | 53 | ### Playground 54 | Because [@thingsinjars](http://twitter.com/thingsinjars) is awesome **jHERE** has [a playground](http://bin.jhere.net), where you can go and experiment with the API, make cool maps, save the result as a Gist and share it with the world. 55 | 56 | ## Contribute 57 | 58 | Feel free to submit pull requests and report the issues you may find when using the plugin. 59 | 60 | ### Code Style 61 | 62 | I am not a code style super-geek, but here are the things I like and I don't like: 63 | 64 | 1. **☼ Like:** semicolons at the end of the line. 65 | 2. **☁ Don't like:** tabs, use **4** spaces instead. Not 1, not 2, **4**. 66 | 3. **☼ Like:** single quotes for strings. 67 | 4. **☁ Don't like:** trailing whitespaces, messed up indentation. 68 | 5. **☼ Like:** meaningful variable names. Don't steal the job to the minificator. Also I want to keep the size of the plugin small, so do facilitate the minificator's job by caching long namespaces and functions that are invoked often. 69 | 6. **☁ Don't like:** globals. 70 | 7. **☼ Like:** well documented API. If you add functionalities, take the time to write the documentation using `//` comments directly in the source code. Docco will do the rest. 71 | 72 | #### Comments 73 | 74 | I normally like single line comments, i.e. 75 | 76 | //My comment goes here 77 | 78 | However I am using [Docco](http://jashkenas.github.com/docco/) to automatically generate documentation for the API, so `//` is reserved for documentation, as single line comments are parsed by the tool. Anything that developers using the plugin should not see in the API docs will have to be commented with `/* */`. 79 | 80 | #### Before submitting a pull request 81 | 82 | If you changed anything in jhere.js before pushing please run a 83 | 84 | make test 85 | 86 | If something fails, please fix the problem. 87 | 88 | If you changed anything else (e.g. extensions, adapters) please run 89 | 90 | make dist 91 | 92 | before submitting the pull request. 93 | 94 | ## Supporters 95 | 96 | jHERE is kindly supported by: 97 | 98 | ![BrowserStack logo](https://dgzoq9b5asjg1.cloudfront.net/production/images/layout/logo-header.png?1441983233) 99 | 100 | [**BrowserStack**](https://www.browserstack.com): Live, Web-Based Browser Testing on all desktop and mobile browsers. I use BrowserStack to make sure jHERE runs on all the supported browsers. 101 | 102 | ![Digital Ocean logo](https://dl.dropboxusercontent.com/u/234787/DO_Logo_Vertical_Blue-75e0d68b.png) 103 | 104 | [**Digital Ocean**](https://www.digitalocean.com/): Simple Cloud Hosting, 105 | Built for Developers. Soon jhere.net and the [playground](http://bin.jhere.net) will be hosted on Digital Ocean. 106 | -------------------------------------------------------------------------------- /dist/jhere.min.js: -------------------------------------------------------------------------------- 1 | (function(e,t,n){function x(t,n){this.element=t,this.options=e.extend({},i,n),this.init()}function T(){var e=this.map||{};return{center:e.center,zoom:e.zoomLevel,bbox:e.getViewBounds&&e.getViewBounds(),type:this.mtype}}function N(e,t){var n=new u.kml.Manager;n.addObserver("state",c(function(e){e.state==="finished"&&t.call(this,e)},this)),n.parseKML(e)}function C(t){var n=t.target,r=this.map.pixelToGeo(t.displayX,t.displayY);if(n!==this.map)return;t.type="map"+t.type,e(this.element).trigger(L(t,r))}function k(e){var t=e.target,n=t[e.type];A(n)&&n.call(this.element,L(e,t.coordinate))}function L(t,n){return e.Event(t.type,{originalEvent:t,geo:{latitude:n.latitude,longitude:n.longitude},target:t.target})}function A(e){return typeof e=="function"}function O(){return!!e().on}var r="jHERE",i,s,o,u,a,f,l,c=e.proxy,h,p="mouse",d="click",v="drag",m="touch",g="start",y="end",b="move",w="appId",E="authenticationToken",S=[d,"dbl"+d,p+"up",p+"down",p+b,p+"over",p+"out",p+"enter",p+"leave","longpress",v+g,v,v+y,"resize",m+g,m+y,m+b];i={appId:"69Dgg78qt4obQKxVbRA8",authToken:"Nz7ilIB_v1CRwPXxgPdvuA",zoom:12,center:[52.49,13.37],enable:["behavior","zoombar","scalebar","typeselector"],type:"map",marker:{text:"",textColor:"#333333",fill:"#ff6347",stroke:"#333333",shape:"balloon",icon:undefined},bubble:{content:"",closable:!0,onclose:e.noop},heatmap:{max:20,opacity:.8,coarseness:2}},e[r]=h={},s=x.prototype,h.defaultCredentials=function(e,t){l={id:e,token:t},f.load().is.done(function(){o.Settings.set(w,e),o.Settings.set(E,t)})},s.init=function(){f.load().is.done(c(this.makemap,this))},s.makemap=function(){var t=this,n=t.options,i=a.component,s=[],f=c(C,t),h={};i.Positioning=u.positioning.component.Positioning,l=l||{id:n.appId,token:n.authToken},o.Settings.set(w,l.id),o.Settings.set(E,l.token),e.data(t.element,r,!0),e.each(i,c(function(n,r){n=n.toLowerCase();if(~e.inArray(n,t.options.enable))return A(r)&&s.push(new r)||e.error("invalid: "+n)},t)),t.map=new a.Display(t.element,{zoomLevel:n.zoom,center:n.center,components:s}),t.type(n.type),t._mc=new a.Container,t.map.objects.add(t._mc),e.each(S,function(e,t){h[t]=[f,!1,null]}),t.map.addListeners(h)},s.center=function(e){this.map.setCenter(e)},s.zoom=function(e){this.map.set("zoomLevel",e)},s.type=function(e){var t=this.map,n={map:t.NORMAL,satellite:t.SATELLITE,smart:t.SMARTMAP,terrain:t.TERRAIN,pt:t.SMART_PT,community:t.NORMAL_COMMUNITY,satcommunity:t.SATELLITE_COMMUNITY,traffic:t.TRAFFIC};e in n?(this.mtype=e,e=n[e]):(this.mtype="map",e=n.map),t.set("baseMapType",e)},s.marker=function(t,n){var r={},s=c(k,this),o=this._mc,u="Marker";e.each(S,function(e,t){r[t]=[s,!1,null]}),n=e.extend({},i.marker,n),n.textPen=n.textPen||{strokeColor:n.textColor},n.pen=n.pen||{strokeColor:n.stroke},n.brush=n.brush||{color:n.fill},n.eventListener=r,n.icon||(u="Standard"+u),o.objects.add(new a[u](t,n))},s.nomarkers=function(){this._mc.objects.clear()},s.bubble=function(t,n){var r,s=this.map;n=e.extend({},i.bubble,n),n.content.jquery&&(n.content.css("white-space","normal"),n.content=e("
").append(n.content.clone()).html()),r=s.getComponentById("InfoBubbles")||s.addComponent(new a.component.InfoBubbles),r.openBubble(n.content,{latitude:t.latitude||t[0],longitude:t.longitude||t[1]},n.onclose,!n.closable)},s.nobubbles=function(){var e;return(e=this.map.getComponentById("InfoBubbles"))&&e.closeAll()},s.kml=function(e,t,n){A(t)&&(n=t,t=!1),N.call(this,e,c(function(e){var r=this.map,i=new u.kml.component.KMLResultSet(e.kmlDocument,r);i.addObserver("state",c(function(e){var i,s;e.state==="finished"&&(t&&(i=e.container.objects.get(0),s=i.getBoundingBox(),s&&r.zoomTo(s)),A(n)&&n.call(this,e))},this)),r.objects.add(i.create())},this))},s.heatmap=function(t,n,r){var s;n=n||"value",n.match(/^density|value$/)||(n="value"),r=r||{},r.type=n,r=e.extend({},i.heatmap,r),s=new u.heatmap.Overlay(r),s.addData(t),this.map.overlays.add(s)},s.originalMap=function(e){e.call(this.element,this.map,u)},s.destroy=function(){this.map.destroy(),e.removeData(this.element),e(this.element).empty()},f={},f.is=!1,f.load=function(){var t,r,i;return f.is&&f.is.state().match(/pending|resolved/)?this:(f.is=e.Deferred(),i=function(){o=nokia,u=o.maps,o.Features.load({map:"auto",ui:"auto",search:"auto",routing:"auto",positioning:"auto",behavior:"auto",kml:"auto",heatmap:"auto"},function(){a=u.map,f.is.resolve()})},t=n.getElementsByTagName("head")[0],r=n.createElement("script"),r.src="http://js.api.here.com/se/2.5.4/jsl.js",r.type="text/javascript",r.charset="utf-8",r.onreadystatechange=function(){r.readyState.match(/loaded|complete/)&&i()},r.onload=i,t.appendChild(r),this)},h._JSLALoader=f,h.extend=function(e,t){typeof e=="string"&&A(t)&&(s[e]=t)},e.fn[r]=function(t){var n=arguments,i="plg_"+r,s;return O()||e.error(r+" requires Zepto or jQuery >= 1.7"),!t&&(s=e.data(this[0],i))?T.call(s):this.each(function(){var o;s=e.data(this,i),s?(typeof t!="string"&&e.error(r+" already initialized, expected method."),o=t,n=Array.prototype.slice.call(n,1),A(s[o])||e.error(r+": "+o+" does not exist"),f.load().is.done(function(){s[o].apply(s,n)})):(s=new x(this,t),e.data(this,i,s))})}})(jQuery,window,document); -------------------------------------------------------------------------------- /src/extensions/domMarkers.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 Simon Madine http://thingsinjars.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | //DOM Markers 25 | //=== 26 | // 27 | //Use any DOM element as a marker attached to the map instead of the 28 | // built-in Marker class. Any change in map position, zoom or size 29 | // will trigger an event to keep the DOM marker positions in sync. 30 | // 31 | //## Usage: 32 | // 33 | //`$('.selector').jHERE('dommarker', [52.46, 13.31], '.markerSelector'); 34 | // 35 | //The marker position can be updated using: 36 | //`$('.selector').jHERE('dommarkerupdate', [52.6, 13.3], '.markerSelector'); 37 | ;(function($) { 38 | 39 | var domMarkerContainer, defaults, mapLoaded = false; 40 | 41 | defaults = { 42 | anchor: { 43 | x: 0, 44 | y: 0 45 | } 46 | }; 47 | 48 | //### Use DOM elements as markers instead of the built-in Marker class 49 | // 50 | //`$('.selector').jHERE('dommarker', positionObject, domElement, markerOptions);` 51 | // 52 | // 53 | //`positionObject` can be an object of type 54 | // 55 | //`{latitude: -43, longitude: 55}` 56 | // 57 | //or an array 58 | // 59 | //`[-43, 55]` 60 | // 61 | //`domElement` is the element to be used as a marker 62 | // The element will be moved from its original DOM location into the map's own UI layer. 63 | // 64 | //`markerOptions` can be an object of type 65 | //
{
 66 | 	//  anchor: {x: 12, y: 18} //an element 24x36 would result centered
 67 | 	//}
68 | // 69 | // Note: This does not take the same event listeners as the standard jHERE marker type. 70 | // Because this is a plain DOM element, events can be added the normal way. 71 | // 72 | // Update the position of the marker on the map with 73 | // $('.markerSelector') 74 | //markerOptions are **optional**. 75 | function dommarker(position, domElement, markerOptions) { 76 | var $domElements, map = this.map; 77 | if (!domMarkerContainer) { 78 | domMarkerContainer = $('
').prependTo(map.getUIContainer()); 79 | } 80 | 81 | $domElements = $(domElement); 82 | $domElements.each(function(i, domElement) { 83 | var $domElement; 84 | $domElement = $(domElement); 85 | $domElement.css('position', 'absolute'); 86 | // $domElement.css('pointerEvents', 'none'); 87 | $domElement.data('anchor', markerOptions.anchor); 88 | 89 | if (!markerOptions.anchor) { 90 | markerOptions.anchor = { 91 | x: $domElement.width() / 2, 92 | y: $domElement.height() / 2 93 | }; 94 | 95 | } 96 | 97 | markerOptions = $.extend({}, defaults.marker, markerOptions); 98 | 99 | $domElement.data('position', position); 100 | 101 | $domElement.data('updatePosition', updatePosition); 102 | 103 | map.addListener('mapviewchange', function() { 104 | updatePosition.call($domElement, null, map); 105 | }); 106 | domMarkerContainer.append($domElement); 107 | }); 108 | map.addListener('mapviewchange', function() { 109 | if (!mapLoaded) { 110 | mapLoaded = !!$domElements.trigger('maploaded'); 111 | } 112 | }); 113 | 114 | } 115 | 116 | function domMarkerUpdate(position, domElement) { 117 | var $domElement = $(domElement), 118 | data = $domElement.data(); 119 | 120 | if (data.updatePosition) { 121 | data.updatePosition.call($domElement, position, this.map); 122 | } 123 | } 124 | 125 | function updatePosition(position, map) { 126 | var px, $this = $(this), 127 | data = $this.data(); 128 | 129 | position = position || data.position; 130 | 131 | px = map.geoToPixel({ 132 | latitude: position.latitude || position[0], 133 | longitude: position.longitude || position[1] 134 | }); 135 | $this.data('position', position); 136 | $this.css('left', px.x - data.anchor.x + 'px'); 137 | $this.css('top', px.y - data.anchor.y + 'px'); 138 | } 139 | 140 | $.jHERE.extend('dommarker', dommarker); 141 | $.jHERE.extend('dommarkerupdate', domMarkerUpdate); 142 | }(jQuery)); -------------------------------------------------------------------------------- /src/extensions/customTypes.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 Simon Madine http://thingsinjars.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ;(function($){ 24 | var _ns; 25 | //### Set the map type 26 | //`$('.selector').jHERE('type', mapType);` 27 | // 28 | //`mapType` is a string: 29 | // 30 | // 1. `'map'`: the normal map type. This is the *default*. 31 | // 2. `'smart'`: a map with most of the colors grayed out. Useful for data visualization. 32 | // 3. `'pt'`: a smart map where the tiles also contain the **public transport lines**. 33 | // 4. `'satellite'`: satellite view. 34 | // 5. `'terrain'`: terrain view. 35 | // 6. `'community'`: HERE Maps community layer. 36 | // 7. `'satcommunity'`: HERE Maps community layer with satellite imagery. 37 | // 8. `'traffic'`: traffic layer. 38 | function customType(type, options){ 39 | _ns = _ns || nokia.maps; 40 | var map = this.map, 41 | newType, 42 | types = { 43 | map: map.NORMAL, 44 | satellite: map.SATELLITE, 45 | smart: map.SMARTMAP, 46 | terrain: map.TERRAIN, 47 | pt: map.SMART_PT, 48 | community: map.NORMAL_COMMUNITY, 49 | satcommunity: map.SATELLITE_COMMUNITY, 50 | traffic: map.TRAFFIC 51 | }; 52 | 53 | newType = options && createBaseMapType(type, options); 54 | if(newType) { 55 | this.mtype='custom'; 56 | } else { 57 | this.mtype = type in types ? type : 'map'; 58 | newType = types[this.mtype]; 59 | } 60 | map.set('baseMapType', newType); 61 | } 62 | 63 | function createBaseMapType(scheme, options) { 64 | if(!options) { 65 | return false; 66 | } 67 | var type = getType(scheme, options), 68 | size = 1 2 | 3 | 4 | 5 | jHERE - Maps Made Easy 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 |

jHERE

39 |

Maps made easy.

40 | 44 |
45 | 52 |
53 | 54 |
55 |
56 | Massimiliano Marcon 57 |

58 | I am a software engineer, web dev and JavaScript geek. I work with many other 59 | clever people on HERE, in Berlin. Coding is my job as well as my favourite hobby. You can find almost everything I work on by looking at my Github profile or my blog. 60 |

61 |

62 | If you want to leave some feedback about jHERE, feel free to just email me at 63 | . Any feedback is good, really. And if you want to contribute, just fork the project and submit a pull request. 64 |

65 |

66 | Note that even though I work for Nokia on HERE, jHERE is a project that I developed in my personal time and it is not related to or supported by Nokia or HERE in any way. 67 |

68 |
69 |
70 | 71 | 81 | 82 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |
94 | 101 | 102 | -------------------------------------------------------------------------------- /src/extensions/shapes.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Massimiliano Marcon, http://marcon.me 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ;(function($){ 24 | var _ns, shape, clearShapes, circle, rectangle, polyline, polygon, shapeContainer; 25 | 26 | function normalize(position){ 27 | return position instanceof Array ? {latitude: position[0], longitude: position[1]} : position; 28 | } 29 | 30 | function mapProperties(style){ 31 | if(!style) { 32 | return style; 33 | } 34 | style.pen = style.pen || {}; 35 | style.brush = style.brush || {}; 36 | style.pen.strokeColor = style.pen.strokeColor || style.stroke || '#111'; 37 | /* 38 | I don't see why this should influence at all since it's not part of the pen 39 | object, but whatever, this fixes it: 40 | */ 41 | style.stroke = 'solid'; 42 | style.pen.lineWidth = style.pen.lineWidth || style.thickness || 1; 43 | style.brush.color = style.brush.color || style.fill; 44 | return style; 45 | } 46 | 47 | /* 48 | Shapes: 49 | - nokia.maps.map.Circle => center (Coordinate object), radius in meters, properties 50 | - nokia.maps.map.Rectangle => bounds (BoundingBox object = {topLeft, bottomRight} ), properties 51 | - nokia.maps.map.PolyLine => array of points, properties 52 | - nokia.maps.map.Polygon => array of points, properties 53 | */ 54 | 55 | function makeCircle(container, options) { 56 | container.objects.add(new _ns.map.Circle(normalize(options.center), options.radius || 1000, options.style)); 57 | } 58 | 59 | function makeRectangle(container, options) { 60 | var bb = new _ns.geo.BoundingBox(normalize(options.topLeft), normalize(options.bottomRight), false); 61 | container.objects.add(new _ns.map.Rectangle(bb, options.style)); 62 | } 63 | 64 | function makePolyline(container, options) { 65 | options.points = $.map(options.points, function(p){ 66 | return normalize(p); 67 | }); 68 | container.objects.add(new _ns.map.Polyline(options.points, options.style)); 69 | } 70 | 71 | function makePolygon(container, options) { 72 | options.points = $.map(options.points, function(p){ 73 | return normalize(p); 74 | }); 75 | container.objects.add(new _ns.map.Polygon(options.points, options.style)); 76 | } 77 | 78 | //### Draw shapes on the map 79 | //`$('.selector').jHERE('shape', 'circle', {center: position, radius: integer, style: object});` 80 | //`$('.selector').jHERE('shape', 'rectangle' {topLeft: position, bottomRight: position, style: object});` 81 | //`$('.selector').jHERE('shape', 'polyline', {points: array, style: object}));` 82 | //`$('.selector').jHERE('shape', 'polygon', {points: array, style: object});` 83 | // 84 | //`style` is always an object that defines the way the shape looks. Can be specified as 85 | //in the JSLA API (pen, brush, see [here](http://developer.here.com/apiexplorer/index.html#examples/js/shapes/map-with-shapes/)) 86 | //or in a simpler way as follows: 87 | //
{
 88 |     //  stroke: "#CC0000FF", //RGBA
 89 |     //  fill: "#000000AA", //RGBA
 90 |     //  thickness: 1 //px
 91 |     //}
92 | shape = function(shape, options){ 93 | _ns = _ns || nokia.maps; 94 | if(!shapeContainer) { 95 | shapeContainer = new _ns.map.Container(); 96 | this.map.objects.add(shapeContainer); 97 | } 98 | options.style = mapProperties(options.style); 99 | switch(shape) { 100 | case 'circle': 101 | makeCircle(shapeContainer, options); 102 | break; 103 | case 'rectangle': 104 | makeRectangle(shapeContainer, options); 105 | break; 106 | case 'polyline': 107 | makePolyline(shapeContainer, options); 108 | break; 109 | case 'polygon': 110 | makePolygon(shapeContainer, options); 111 | break; 112 | default: 113 | $.error(shape + ' not supported'); 114 | } 115 | }; 116 | 117 | //###Clear all shapes from the map 118 | clearShapes = function() { 119 | if (shapeContainer && shapeContainer.objects) { 120 | shapeContainer.objects.clear(); 121 | } 122 | }; 123 | 124 | circle = function(options){ 125 | shape.call(this, 'circle', options); 126 | }; 127 | 128 | rectangle = function(options){ 129 | shape.call(this, 'rectangle', options); 130 | }; 131 | 132 | polyline = function(options){ 133 | shape.call(this, 'polyline', options); 134 | }; 135 | 136 | polygon = function(options){ 137 | shape.call(this, 'polygon', options); 138 | }; 139 | 140 | $.jHERE.extend('shape', shape); 141 | $.jHERE.extend('clearShapes', clearShapes); 142 | $.jHERE.extend('circle', circle); 143 | $.jHERE.extend('rectangle', rectangle); 144 | $.jHERE.extend('polyline', polyline); 145 | $.jHERE.extend('polygon', polygon); 146 | }(jQuery)); 147 | -------------------------------------------------------------------------------- /test/lib/jasmine-1.3.1/jasmine.css: -------------------------------------------------------------------------------- 1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } 2 | 3 | #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } 4 | #HTMLReporter a { text-decoration: none; } 5 | #HTMLReporter a:hover { text-decoration: underline; } 6 | #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; } 7 | #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; } 8 | #HTMLReporter #jasmine_content { position: fixed; right: 100%; } 9 | #HTMLReporter .version { color: #aaaaaa; } 10 | #HTMLReporter .banner { margin-top: 14px; } 11 | #HTMLReporter .duration { color: #aaaaaa; float: right; } 12 | #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; } 13 | #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } 14 | #HTMLReporter .symbolSummary li.passed { font-size: 14px; } 15 | #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; } 16 | #HTMLReporter .symbolSummary li.failed { line-height: 9px; } 17 | #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } 18 | #HTMLReporter .symbolSummary li.skipped { font-size: 14px; } 19 | #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; } 20 | #HTMLReporter .symbolSummary li.pending { line-height: 11px; } 21 | #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; } 22 | #HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } 23 | #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 24 | #HTMLReporter .runningAlert { background-color: #666666; } 25 | #HTMLReporter .skippedAlert { background-color: #aaaaaa; } 26 | #HTMLReporter .skippedAlert:first-child { background-color: #333333; } 27 | #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; } 28 | #HTMLReporter .passingAlert { background-color: #a6b779; } 29 | #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; } 30 | #HTMLReporter .failingAlert { background-color: #cf867e; } 31 | #HTMLReporter .failingAlert:first-child { background-color: #b03911; } 32 | #HTMLReporter .results { margin-top: 14px; } 33 | #HTMLReporter #details { display: none; } 34 | #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; } 35 | #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } 36 | #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } 37 | #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } 38 | #HTMLReporter.showDetails .summary { display: none; } 39 | #HTMLReporter.showDetails #details { display: block; } 40 | #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } 41 | #HTMLReporter .summary { margin-top: 14px; } 42 | #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; } 43 | #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; } 44 | #HTMLReporter .summary .specSummary.failed a { color: #b03911; } 45 | #HTMLReporter .description + .suite { margin-top: 0; } 46 | #HTMLReporter .suite { margin-top: 14px; } 47 | #HTMLReporter .suite a { color: #333333; } 48 | #HTMLReporter #details .specDetail { margin-bottom: 28px; } 49 | #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; } 50 | #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; } 51 | #HTMLReporter .resultMessage span.result { display: block; } 52 | #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } 53 | 54 | #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ } 55 | #TrivialReporter a:visited, #TrivialReporter a { color: #303; } 56 | #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; } 57 | #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; } 58 | #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; } 59 | #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; } 60 | #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; } 61 | #TrivialReporter .runner.running { background-color: yellow; } 62 | #TrivialReporter .options { text-align: right; font-size: .8em; } 63 | #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; } 64 | #TrivialReporter .suite .suite { margin: 5px; } 65 | #TrivialReporter .suite.passed { background-color: #dfd; } 66 | #TrivialReporter .suite.failed { background-color: #fdd; } 67 | #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; } 68 | #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; } 69 | #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; } 70 | #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; } 71 | #TrivialReporter .spec.skipped { background-color: #bbb; } 72 | #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; } 73 | #TrivialReporter .passed { background-color: #cfc; display: none; } 74 | #TrivialReporter .failed { background-color: #fbb; } 75 | #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; } 76 | #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; } 77 | #TrivialReporter .resultMessage .mismatch { color: black; } 78 | #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; } 79 | #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; } 80 | #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; } 81 | #TrivialReporter #jasmine_content { position: fixed; right: 100%; } 82 | #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; } 83 | -------------------------------------------------------------------------------- /src/extensions/route.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Massimiliano Marcon, http://marcon.me 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ; 24 | (function($) { 25 | var _ns, clearRoutes, routeContainer, route, _default = { 26 | type: 'shortest', 27 | transportMode: 'car', 28 | options: '', 29 | trafficMode: 'default', 30 | width: 4, 31 | color: '#ff6347', 32 | marker: { 33 | text: '#', 34 | textColor: '#fff' 35 | }, 36 | zoomTo: true 37 | }; 38 | 39 | function normalize(position) { 40 | return position instanceof Array ? { latitude: position[0], longitude: position[1] } : position; 41 | } 42 | 43 | //### Calculate the route between 2 points 44 | //`$('.selector').jHERE('route', from, to, routeOptions);` 45 | // 46 | //`from` and `to` can be objects of type 47 | // 48 | //`{latitude: -43, longitude: 55}` 49 | // 50 | //or an array 51 | // 52 | //`[-43, 55]` 53 | // 54 | //`routeOptions` is optional and can be an object of type 55 | //
{
 56 |     //  marker: {},
 57 |     //  type: 'shortest', //can be shortest, fastest, fastestNow, directDrive, scenic
 58 |     //  transportMode: 'car', //can be car, pedestrian, publicTransport, truck
 59 |     //  options: '', //can be avoidTollroad, avoidMotorway, avoidBoatFerry,
 60 |     //               //avoidRailFerry, avoidPublicTransport, avoidTunnel,
 61 |     //               //avoidDirtRoad, avoidPark, preferHOVLane, avoidStairs
 62 |     //  trafficMode: 'default', //can be enabled, disabled, default
 63 |     //  width: 4, //width in px of the route drawn on the map
 64 |     //  color: '#ff6347', //color of the route drawn on the map,
 65 |     //  onroute: function(route){} //optional callbacks that gets the list of maneuvers with some
 66 |     //                             //basic info, plus total time (seconds) and length (meters)
 67 |     //}
68 | // 69 | //Once route is calculated a jhere.route event is also triggered. 70 | // 71 | //`marker` is an object containing the same options used for 72 | //`$('.selector').jHERE('marker')`. Options apply to both start and destionation markers. 73 | route = function(from, to, via, options) { 74 | var router, wp, done, cleanOptions; 75 | _ns = _ns || nokia.maps; 76 | from = normalize(from); 77 | to = normalize(to); 78 | 79 | //in this case options is the options object, like expected 80 | if (via instanceof Array) { 81 | options = $.extend({}, _default, options); 82 | } 83 | //in this case via is the options object, probably older implementation of plugin 84 | else { 85 | options = $.extend({}, _default, via); 86 | via = []; 87 | } 88 | /*Call me with the correct context!*/ 89 | done = function(router, key, status) { 90 | var routes, poly, r, info = {}, evt; 91 | if (status === 'finished') { 92 | routes = router.getRoutes(); 93 | r = routes[0]; 94 | /*We want to customize the way a routeContainer is shown*/ 95 | /*So we have to make a polyline first*/ 96 | poly = new _ns.map.Polyline(r && r.shape, { 97 | pen: new _ns.util.Pen({ 98 | lineWidth: options.width, 99 | strokeColor: options.color 100 | }) 101 | }); 102 | if (!routeContainer) { 103 | routeContainer = new _ns.map.Container(); 104 | this.map.objects.add(routeContainer); 105 | } 106 | routeContainer.objects.add(poly); 107 | /*And add the markers next. For markers we use the corresponding jHERE method for now.*/ 108 | $.each(r.waypoints, $.proxy(function(i, w) { 109 | var o = $.extend({}, options.marker); 110 | if (options.marker.text === '#') { 111 | o.text = i + 1; 112 | } 113 | this.marker(w.originalPosition, o); 114 | }, this)); 115 | /*Zoom map to bounds of route*/ 116 | if (options.zoomTo) { 117 | this.map.zoomTo(routeContainer.getBoundingBox(), false, "default"); 118 | } 119 | /*Now let's look into the route infos*/ 120 | info.time = r.summary.travelTime; 121 | info.length = r.summary.distance; 122 | info.waypoints = r.waypoints; 123 | info.legs = r.legs; 124 | 125 | /*Fire callback if present*/ 126 | if (typeof options.onroute === 'function') { 127 | options.onroute.call(this.element, info); 128 | } 129 | /*And trigger event (jQuery only)*/ 130 | evt = $.Event('jhere.route', { 131 | route: info, 132 | target: this.element 133 | }); 134 | $(this.element).trigger(evt); 135 | } else if (status === 'failed') { 136 | $.error('Failed to calculate route'); 137 | } 138 | }; 139 | 140 | router = new _ns.routing.Manager(); 141 | router.addObserver('state', $.proxy(done, this)); 142 | 143 | wp = new _ns.routing.WaypointParameterList(); 144 | wp.addCoordinate(from); 145 | $.each(via, function(i, item) { 146 | wp.addCoordinate(normalize(item)); 147 | }); 148 | wp.addCoordinate(to); 149 | 150 | /*Fix for insanity*/ 151 | cleanOptions = { 152 | transportModes: [options.transportMode], 153 | type: options.type, 154 | options: options.options, 155 | trafficMode: options.trafficMode 156 | }; 157 | 158 | router.calculateRoute(wp, [cleanOptions]); 159 | }; 160 | 161 | //###Clear all routes from the map 162 | clearRoutes = function() { 163 | if (routeContainer && routeContainer.objects) { 164 | routeContainer.objects.clear(); 165 | } 166 | }; 167 | 168 | $.jHERE.extend('route', route); 169 | $.jHERE.extend('clearRoutes', clearRoutes); 170 | }(jQuery)); 171 | -------------------------------------------------------------------------------- /web/js/main.js: -------------------------------------------------------------------------------- 1 | /*global $:true, alert:true, _gaq*/ 2 | var heatMapData=[{value:4899,latitude:52.53026126658807,longitude:13.385298362512387},{value:3299,latitude:52.530712612721196,longitude:13.385059833526611},{value:36,latitude:52.530215905734,longitude:13.38543057664563},{value:680,latitude:52.5308704376221,longitude:13.3849096298218},{value:289,latitude:52.530234520737004,longitude:13.385648693847036},{value:27,latitude:52.53048853756028,longitude:13.385252371995787},{value:38,latitude:52.53006362614138,longitude:13.385473500409793},{value:89,latitude:52.530244890211264, 3 | longitude:13.385788119172863},{value:6,latitude:52.53025398343701,longitude:13.38576000453459},{value:164,latitude:52.529855659002,longitude:13.38426841720272},{value:687,latitude:52.529975,longitude:13.383993},{value:1347,latitude:52.52956594243049,longitude:13.384504666194712},{value:34,latitude:52.530347321620944,longitude:13.385677040788089},{value:184,latitude:52.530878,longitude:13.384904},{value:172,latitude:52.52976864794835,longitude:13.384791244138654},{value:479,latitude:52.53080398695847, 4 | longitude:13.38707685470581},{value:128,latitude:52.5309,longitude:13.3847},{value:17,latitude:52.5299699698133,longitude:13.3851313311731},{value:18,latitude:52.5309,longitude:13.3849},{value:3,latitude:52.530006959735175,longitude:13.385183469129728},{value:169,latitude:52.52960574844206,longitude:13.384814799655908},{value:308,latitude:52.53043419709394,longitude:13.385883058015915},{value:71,latitude:52.530757,longitude:13.384383},{value:716,latitude:52.530305,longitude:13.38347432},{value:7, 5 | latitude:52.530581520484056,longitude:13.386184774537549},{value:3,latitude:52.5307651756088,longitude:13.384771001626588},{value:297,latitude:52.53071931758466,longitude:13.383554065723375},{value:687,latitude:52.53054291720474,longitude:13.383557796478271},{value:13,latitude:52.530131948860614,longitude:13.386342364840072},{value:5,latitude:52.53,longitude:13.3851},{value:68,latitude:52.530712612721196,longitude:13.384780883789062},{value:21,latitude:52.530497,longitude:13.385122349999998},{value:210, 6 | latitude:52.529994665670216,longitude:13.38409423828125},{value:5,latitude:52.53097347967182,longitude:13.3848509841156},{value:220,latitude:52.529782,longitude:13.38395},{value:212,latitude:52.530654,longitude:13.383659},{value:56,latitude:52.5308170648083,longitude:13.383900201050393},{value:88,latitude:52.530654962765965,longitude:13.383485390706522},{value:19,latitude:52.530841,longitude:13.384908},{value:7,latitude:52.5309619680536,longitude:13.3848052751398},{value:376,latitude:52.529297467355825, 7 | longitude:13.384428562870935},{value:824,latitude:52.529055867792856,longitude:13.385228922324478},{value:25,latitude:52.53073893510019,longitude:13.38375270869002},{value:157,latitude:52.53011214871808,longitude:13.38357925415039},{value:44,latitude:52.530441122208984,longitude:13.386257713051902},{value:32,latitude:52.52943155096217,longitude:13.384827986540591},{value:235,latitude:52.530798030550265,longitude:13.383918592731648},{value:211,latitude:52.529138,longitude:13.384971},{value:41,latitude:52.53110073535684, 8 | longitude:13.386037485323744},{value:28,latitude:52.529808973752715,longitude:13.383999001205726}]; 9 | 10 | function makeSimple(selector) { 11 | $(selector).jHERE({ 12 | enable: ['behavior'], 13 | center: [40.664167, -73.838611], 14 | zoom: 8 15 | }); 16 | } 17 | 18 | function makeSatellite(selector) { 19 | $(selector).jHERE({ 20 | enable: ['behavior', 'contextmenu'], 21 | center: [41.77, -87.51], 22 | zoom: 8, 23 | type: 'satellite' 24 | }); 25 | } 26 | 27 | function makeMarker(selector) { 28 | $(selector).jHERE({ 29 | enable: ['behavior'], 30 | center: [52.500556, 13.398889], 31 | zoom: 8, 32 | type: 'terrain' 33 | }).jHERE('marker', [52.500556, 13.338889], { 34 | icon: 'img/pin-black.png', 35 | anchor: {x: 12, y: 32}, 36 | click: function(){alert('Hallo from Berlin!');} 37 | }); 38 | } 39 | 40 | function makeBubble(selector) { 41 | $(selector).jHERE({ 42 | enable: ['behavior'], 43 | center: [52.400556, 13.5889], 44 | zoom: 8 45 | }).jHERE('bubble', [52.500556, 13.398889], {closable: false, content: 'Hallo!'}); 46 | } 47 | 48 | function makeKML(selector) { 49 | $(selector).jHERE({ 50 | enable: false 51 | }).jHERE('kml', 'js/berlin.kml', true); 52 | } 53 | 54 | function makeHeatmap(selector) { 55 | $(selector).jHERE({ 56 | enable: false, 57 | center: [52.53, 13.384], 58 | zoom: 15 59 | }).jHERE('heatmap', heatMapData /*defined elsewhere*/, 'density'); 60 | } 61 | 62 | function makeGecode(selector) { 63 | var s = $(selector).css('background', '#fff'), 64 | address = 'Invalidenstrasse, 116, 10115, Berlin, Germany'; 65 | s.append('
' + address + ' is located at:
'); 66 | $.jHERE.geocode(address, function(location){ 67 | s.append('
' + location.latitude + ',' + location.longitude + '
'); 68 | }); 69 | } 70 | 71 | function makeRoute(selector) { 72 | $(selector).jHERE({ 73 | enable: [], 74 | center: [52.56, 13.18], 75 | zoom: 9, 76 | type: 'smart' 77 | }) 78 | .jHERE('route', [52.711, 13.011], [52.514, 13.453], {color: '#333', marker: { 79 | fill: '#86c440', 80 | text: '#' 81 | }}); 82 | } 83 | 84 | function makeShapes(selector) { 85 | $(selector).jHERE({ 86 | enable: [], 87 | center: [52.5, 13.4], 88 | zoom: 11, 89 | type: 'smart' 90 | }) 91 | .jHERE('polygon', {points: [[52.521, 13.372], 92 | [52.516, 13.370], [52.506, 13.373], [52.501, 13.377], [52.498, 13.390], [52.499, 13.419], [52.501, 13.444], 93 | [52.502, 13.447], [52.518, 13.454], [52.527, 13.448], [52.532, 13.442], [52.536, 13.433], [52.539, 13.423], 94 | [52.541, 13.413], [52.538, 13.396], [52.534, 13.388], [52.532, 13.389], [52.529, 13.380], [52.526, 13.368]], 95 | style:{ 96 | fill: '#ff6347AA', 97 | thickness: 1, 98 | stroke: '#111' 99 | } 100 | }); 101 | } 102 | 103 | $(function(){ 104 | $('.email').attr('href', 'mailto:max@jhere.net').text('max@jhere.net'); 105 | $('a').on('click', function(e){ 106 | if(!_gaq) { 107 | return true; 108 | } 109 | var url = $(this).attr("href"); 110 | if (e.currentTarget.host != window.location.host) { 111 | e.preventDefault(); 112 | try { 113 | _gaq.push(['_trackEvent', 'Outbound Links', e.currentTarget.host, url, 0]); 114 | setTimeout('document.location = "' + url + '"', 100); 115 | } catch(err){ 116 | document.location = url; 117 | } 118 | } 119 | }); 120 | }); 121 | 122 | $(window).on('load', function(){ 123 | $.jHERE.defaultCredentials('69Dgg78qt4obQKxVbRA8', 'Nz7ilIB_v1CRwPXxgPdvuA'); 124 | 125 | var $map = $('#map').jHERE({ 126 | enable: [], 127 | zoom: 12, 128 | center: {latitude: 40.7324, longitude: -74.0132}, 129 | type: 'pt' 130 | }); 131 | 132 | $(document).on('click', '.controls li', function(){ 133 | var zoom = $map.jHERE().zoom; 134 | if($(this).hasClass('plus')) { 135 | return $map.jHERE('zoom', zoom + 1); 136 | } 137 | $map.jHERE('zoom', zoom - 1); 138 | }); 139 | 140 | $('header.home, header.page').append('
'); 141 | 142 | makeSimple('.simple'); 143 | makeSatellite('.satellite'); 144 | makeMarker('.marker'); 145 | makeBubble('.bubble'); 146 | makeKML('.kml'); 147 | makeHeatmap('.heatmap'); 148 | 149 | makeGecode('.geocoding'); 150 | makeRoute('.routing'); 151 | makeShapes('.shapes'); 152 | }); -------------------------------------------------------------------------------- /EXTENSIONS.md: -------------------------------------------------------------------------------- 1 | #jHERE Extensions 2 | 3 | Extensions extend the behavior of jHERE. A minified version of each extension is available in the `dist/extensions` folder. 4 | 5 | **Note** that to improve performance the plugin and the needed extensions should be combined in a single file. **Luckily for you this is now automated! Keep reading…** 6 | 7 | ##jHERE Custom Builder 8 | 9 | With [jHERE Custom Builder](http://custom.jhere.net/) you can build a custom version of jHERE that contains only what you need, all concatenated together in a single file, minified and ready for production. 10 | 11 | ##Available extensions 12 | 13 | ###autoinit extension 14 | 15 | When this extension is included a map is automatically initialized on ~~the first~~ each container with `id` or `class` `map`. Options are passed via data attributes as follows: 16 | 17 |
22 |
23 | 24 | If `data-center` is an address, e.g. *Largo da Matriz de Nossa Senhora do Ó, 203, São Paulo, SP, Brazil*, the address will be geocoded in the attempt of obtaining the geographical coordinates where to center the map. 25 | 26 | This extension packaged together with the plugin enables *HTML developers* to insert a map in their pages without having to write a single line of JavaScript. 27 | 28 | ###routing extension 29 | 30 | When this extension is included it is possible to add routes to the map by simply doing the following: 31 | 32 | `$('.selector').jHERE('route', from, to, via, routeOptions);` 33 | 34 | `from` and `to` can be objects of type 35 | 36 | `{latitude: -43, longitude: 55}` 37 | 38 | or an array 39 | 40 | `[-43, 55]` 41 | 42 | `via` is optional and can be an array of coordinates of type 43 | 44 | `[[-43, 55], [52.33, 13.08]]` 45 | 46 | or 47 | 48 | `[{latitude: 52.33812, longitude: 13.08835}]` 49 | 50 | `routeOptions` is optional and can be an object of type 51 | 52 | { 53 | marker: {}, 54 | type: 'shortest', //can be shortest, fastest, fastestNow, directDrive, scenic 55 | transportMode: 'car', //can be car, pedestrian, publicTransport, truck 56 | options: '', //can be avoidTollroad, avoidMotorway, avoidBoatFerry, 57 | //avoidRailFerry, avoidPublicTransport, avoidTunnel, 58 | //avoidDirtRoad, avoidPark, preferHOVLane, avoidStairs 59 | trafficMode: 'default', //can be enabled, disabled, default 60 | width: 4, //width in px of the route drawn on the map 61 | color: '#ff6347', //color of the route drawn on the map 62 | zoomTo: false, //will disable zooming to bounds of calculated route 63 | onroute: function(route){} //optional callbacks that gets the list of maneuvers with some 64 | //basic info, plus total time (seconds) and length (meters) 65 | } 66 | 67 | `marker` is an object containing the same options used for 68 | `$('.selector').jHERE('marker')`. Options apply to both start and destionation markers. 69 | 70 | For jQuery a `jhere.route` event is also triggered, which can be caught with `on` on the map element. With Zepto the call to `trigger` seems to be ignored. 71 | 72 | **DEMO:** a demo of the routing extension is available [here](http://bin.jhere.net/4134408). 73 | 74 | ### geocode extension 75 | 76 | By including this extension it is possible to do very easily geocoding and reverse geocoding operations. 77 | 78 | #### Geocode 79 | 80 | $.jHERE.geocode('Berlin, Germany', 81 | function(position){ 82 | //Do stuff with position 83 | }, 84 | function(){/*error*/}); 85 | 86 | jHERE exposes the possibility of geocoding an address 87 | into (latitude, longitude). This call is asynchronous 88 | and supports a `success` and a `error` callback. 89 | When jHERE is used with jQuery a $.Deferred object is also returned 90 | and can be used instead of callbacks. For Zepto.JS a Deferred is also returned, 91 | however note that it is a custom implementation that only supports the `done` method. 92 | 93 | #### Reverse Geocode 94 | 95 | $.jHERE.reverseGeocode({latitude: 52.5, longitude: 13.3}, 96 | function(address){ 97 | //Do stuff with address 98 | }, 99 | function(){/*error*/}); 100 | 101 | jHERE exposes the possibility of reverse geocoding a position 102 | into an address. This call is asynchronous 103 | and supports a `success` and a `error` callback. 104 | When jHERE is used with jQuery a $.Deferred object is also returned 105 | and can be used instead of callbacks. For Zepto.JS a Deferred is also returned, 106 | however note that it is a custom implementation that only supports the `done` method. 107 | 108 | ### shapes extension 109 | 110 | With the shapes extension it is possible to draw circles, rectangles, polylines and polygons on the map canvas. 111 | 112 | The syntax is the following: 113 | 114 | $('.selector').jHERE('shape', 'circle', {center: position, radius: integer, style: object}); 115 | /*or*/ $('.selector').jHERE('circle', {center: position, radius: integer, style: object}); 116 | 117 | $('.selector').jHERE('shape', 'rectangle' {topLeft: position, bottomRight: position, style: object}); 118 | /*or*/ $('.selector').jHERE('rectangle' {topLeft: position, bottomRight: position, style: object}); 119 | 120 | $('.selector').jHERE('shape', 'polyline', {points: array, style: object})); 121 | /*or*/ $('.selector').jHERE('polyline', {points: array, style: object})); 122 | 123 | $('.selector').jHERE('shape', 'polygon', {points: array, style: object}); 124 | /*or*/ $('.selector').jHERE('polygon', {points: array, style: object}); 125 | 126 | `style` is always an object that defines the way the shape looks. Can be specified as in the JSLA API (pen, brush, see [here](http://developer.here.com/apiexplorer/index.html#examples/js/shapes/map-with-shapes/)) or in a simpler way as follows: 127 | 128 | { 129 | stroke: "#CC0000FF", //RGBA 130 | fill: "#000000AA", //RGBA 131 | thickness: 1 //px 132 | } 133 | 134 | ### markers extension 135 | 136 | Extends the marker-related functionalities of the jHERE core by adding support for group of markers. 137 | 138 | It adds support for the `group` option for a marker. Groups can be then hidden or shown with a call to 139 | 140 | $('.selector').jHERE(['group0', 'group1'], true); 141 | 142 | First parameter is a group name (`String`) or an `Array` of group names. Second parameter is a `boolean`, for visible (`true`) or not visible (`false`). 143 | 144 | This extansion is useful when it is necessary to categorize (i.e. group) markers and enable the capability of showing/hiding certain categories of markers. 145 | 146 | //Stupid example: show all Burger Kings and hide all the Mc Donalds 147 | $('.map').jHERE('markergroups', 'b-king', true).jHERE('markergroups', 'mc-donald', false); 148 | 149 | ### clustering extension 150 | 151 | Exposes markers clustering for better data visualuzation. When your maps get crowded with markers, this is the extension for you. 152 | 153 | var data = [ 154 | { 155 | "name":"Name of the place", 156 | "longitude": 20.17920, 157 | "latitude": 59.96930 158 | } 159 | //,many other points here 160 | ]; 161 | 162 | $('#map').jHERE('cluster', data); 163 | 164 | To get rid of the clusters: 165 | 166 | $('#map').jHERE('nocluster', data); 167 | 168 | ### customize extension 169 | 170 | Allows to customize particular aspects of the map. 171 | 172 | $('.selector').jHERE('customize', options); 173 | 174 | Supported options are currently the following: 175 | 176 | { 177 | bubble: { 178 | backgroundColor: '#ffffff', 179 | color: '#111111', 180 | autoClose: false /*Should bubbles be autoclosed when a new one is open?*/ 181 | } 182 | } -------------------------------------------------------------------------------- /src/extensions/markers.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Massimiliano Marcon, http://marcon.me 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | ;(function($){ 24 | var _ns, marker, nomarkers, 25 | markergroups, zoomToMarkers, 26 | _defaults = { 27 | text: '', 28 | textColor: '#333333', 29 | fill: '#ff6347', 30 | stroke: '#333333', 31 | shape: 'balloon', 32 | icon: undefined, 33 | group: '_' 34 | }, bind = $.proxy, 35 | /*Map and marker supported events*/ 36 | mouse = 'mouse', click = 'click', drag = 'drag', touch = 'touch', start = 'start', end = 'end', move = 'move', 37 | supportedEvents = [ 38 | click, 39 | 'dbl' + click, 40 | mouse + 'up', 41 | mouse + 'down', 42 | mouse + move, 43 | mouse + 'over', 44 | mouse + 'out', 45 | mouse + 'enter', 46 | mouse + 'leave', 47 | 'longpress', 48 | drag + start, 49 | drag, 50 | drag + end, 51 | 'resize', 52 | touch + start, 53 | touch + end, 54 | touch + move 55 | ]; 56 | 57 | //### Add markers to the map 58 | //`$('.selector').jHERE('marker', positionObject, markerOptions);` 59 | // 60 | //`positionObject` can be an object of type 61 | // 62 | //`{latitude: -43, longitude: 55}` 63 | // 64 | //or an array 65 | // 66 | //`[-43, 55]` 67 | // 68 | //`markerOptions` can be an object of type 69 | //
{
 70 |     //  text: '!',
 71 |     //  textColor: '#333333',
 72 |     //  fill: '#ff6347',
 73 |     //  stroke: '#333333',
 74 |     //  icon: 'urlToIcon',
 75 |     //  anchor: {x: 12, y: 18} //an icon 24x36 would result centered
 76 |     //  click: function(event){/*this is the element, event.geo contains the coordinates*/},
 77 |     //  dblclick: function(event){/*this is the element, event.geo contains the coordinates*/},
 78 |     //  mousemove: function(event){/*this is the element, event.geo contains the coordinates*/},
 79 |     //  mouseover: function(event){/*this is the element, event.geo contains the coordinates*/},
 80 |     //  mouseout: function(event){/*this is the element, event.geo contains the coordinates*/},
 81 |     //  mouseenter: function(event){/*this is the element, event.geo contains the coordinates*/},
 82 |     //  mouseleave: function(event){/*this is the element, event.geo contains the coordinates*/},
 83 |     //  longpress: function(event){/*this is the element, event.geo contains the coordinates*/},
 84 |     //  group: 'restaurants'
 85 |     //}
86 | //All parameters are **optional**. 87 | marker = function(position, markerOptions) { 88 | var markerListeners = {}, 89 | centralizedHandler = bind(triggerEvent, this), 90 | mc = this._mc, 91 | MarkerConstructor = 'Marker', 92 | marker, groups; 93 | this.groups = this.groups || {}; 94 | groups = this.groups; 95 | _ns = _ns || nokia.maps; 96 | $.each(supportedEvents, function(i, v){ 97 | markerListeners[v] = [centralizedHandler, false, null]; 98 | }); 99 | 100 | markerOptions = $.extend({}, _defaults, markerOptions); 101 | /*Normalize settings*/ 102 | markerOptions.textPen = markerOptions.textPen || {strokeColor: markerOptions.textColor}; 103 | markerOptions.pen = markerOptions.pen || {strokeColor: markerOptions.stroke}; 104 | markerOptions.brush = markerOptions.brush || {color: markerOptions.fill}; 105 | markerOptions.eventListener = markerListeners; 106 | 107 | if (!markerOptions.icon) { 108 | MarkerConstructor = 'Standard' + MarkerConstructor; 109 | } 110 | 111 | marker = new _ns.map[MarkerConstructor](position, markerOptions); 112 | groups[markerOptions.group] = groups[markerOptions.group] || []; 113 | /* 114 | If the group has just been created, make it visible, 115 | if not leave the visibility as it is 116 | */ 117 | groups[markerOptions.group].visible = groups[markerOptions.group].length === 0 ? true : groups[markerOptions.group].visible; 118 | groups[markerOptions.group].push(marker); 119 | 120 | /*Only add the marker to the map when its group is visible*/ 121 | if(groups[markerOptions.group].visible) { 122 | mc.objects.add(marker); 123 | } 124 | }; 125 | 126 | //### Show/hides group of markers 127 | //`$('.selector').jHERE(['group0', 'group1'], true);` 128 | // 129 | //First parameter is a group name (String) or an Array of 130 | //group names. 131 | //Second parameter is a boolean, for visible (`true`) or not visible (`false`). 132 | markergroups = function(targetgroups, visible) { 133 | var mc = this._mc, objs = mc.objects, groups; 134 | this.groups = this.groups || {}; 135 | groups = this.groups; 136 | targetgroups = (targetgroups instanceof Array ? targetgroups : [targetgroups]); 137 | $.each(targetgroups, function(i, g){ 138 | if(visible) { 139 | objs.addAll(groups[g] || []); 140 | } 141 | else { 142 | objs.removeAll(groups[g] || []); 143 | } 144 | groups[g].visible = !!visible; 145 | }); 146 | }; 147 | 148 | //### Remove all the markers from the map 149 | //`$('.selector').jHERE('nomarkers');` 150 | nomarkers = function(){ 151 | this._mc.objects.clear(); 152 | this.groups = {}; 153 | }; 154 | 155 | //### ZoomToMarkers extent on the map 156 | //`$('.selector').jHERE('zoomToMarkers', keepCenter);` 157 | // 158 | //`keepCenter` is a boolean whether the center should be kept, defaults to false 159 | zoomToMarkers = function(keepCenter){ 160 | if(this._mc.objects.getLength() > 1) { 161 | var bbox = this._mc.getBoundingBox(); 162 | this.map.zoomTo(bbox, keepCenter || false); 163 | } 164 | }; 165 | 166 | /* 167 | Following is copy-pasted from jhere.js, but I can't 168 | see another way of doing this without exposing this stuff that 169 | is supposed to be private 170 | */ 171 | 172 | function triggerEvent(event) { 173 | var target = event.target, handler = target[event.type]; 174 | if (isFunction(handler)) { 175 | /* 176 | When the event listener is called then 177 | the context is the DOM element containing the map. 178 | */ 179 | handler.call(this.element, makeGeoEvent(event, target.coordinate)); 180 | } 181 | } 182 | 183 | /* 184 | ********************************************* 185 | ********************************************* 186 | */ 187 | 188 | function makeGeoEvent(event, position) { 189 | return $.Event(event.type, { 190 | originalEvent: event, 191 | geo: { 192 | latitude: position.latitude, 193 | longitude: position.longitude 194 | }, 195 | target: event.target 196 | }); 197 | } 198 | 199 | function isFunction(fn) { 200 | return typeof fn === 'function'; 201 | } 202 | 203 | $.jHERE.extend('marker', marker); 204 | $.jHERE.extend('markergroups', markergroups); 205 | $.jHERE.extend('nomarkers', nomarkers); 206 | $.jHERE.extend('zoomToMarkers', zoomToMarkers); 207 | }(jQuery)); -------------------------------------------------------------------------------- /src/examples/example.tire.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 277 | 296 | 297 | -------------------------------------------------------------------------------- /src/examples/example.basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 boilerplate—all you really need… 6 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 278 | 301 | 302 | -------------------------------------------------------------------------------- /web/css/normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v2.1.0 | MIT License | git.io/normalize */ 2 | 3 | /* ========================================================================== 4 | HTML5 display definitions 5 | ========================================================================== */ 6 | 7 | /** 8 | * Correct `block` display not defined in IE 8/9. 9 | */ 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | main, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | 26 | /** 27 | * Correct `inline-block` display not defined in IE 8/9. 28 | */ 29 | 30 | audio, 31 | canvas, 32 | video { 33 | display: inline-block; 34 | } 35 | 36 | /** 37 | * Prevent modern browsers from displaying `audio` without controls. 38 | * Remove excess height in iOS 5 devices. 39 | */ 40 | 41 | audio:not([controls]) { 42 | display: none; 43 | height: 0; 44 | } 45 | 46 | /** 47 | * Address styling not present in IE 8/9. 48 | */ 49 | 50 | [hidden] { 51 | display: none; 52 | } 53 | 54 | /* ========================================================================== 55 | Base 56 | ========================================================================== */ 57 | 58 | /** 59 | * 1. Set default font family to sans-serif. 60 | * 2. Prevent iOS text size adjust after orientation change, without disabling 61 | * user zoom. 62 | */ 63 | 64 | html { 65 | font-family: sans-serif; /* 1 */ 66 | -webkit-text-size-adjust: 100%; /* 2 */ 67 | -ms-text-size-adjust: 100%; /* 2 */ 68 | } 69 | 70 | /** 71 | * Remove default margin. 72 | */ 73 | 74 | body { 75 | margin: 0; 76 | } 77 | 78 | /* ========================================================================== 79 | Links 80 | ========================================================================== */ 81 | 82 | /** 83 | * Address `outline` inconsistency between Chrome and other browsers. 84 | */ 85 | 86 | a:focus { 87 | outline: thin dotted; 88 | } 89 | 90 | /** 91 | * Improve readability when focused and also mouse hovered in all browsers. 92 | */ 93 | 94 | a:active, 95 | a:hover { 96 | outline: 0; 97 | } 98 | 99 | /* ========================================================================== 100 | Typography 101 | ========================================================================== */ 102 | 103 | /** 104 | * Address variable `h1` font-size and margin within `section` and `article` 105 | * contexts in Firefox 4+, Safari 5, and Chrome. 106 | */ 107 | 108 | h1 { 109 | font-size: 2em; 110 | margin: 0.67em 0; 111 | } 112 | 113 | /** 114 | * Address styling not present in IE 8/9, Safari 5, and Chrome. 115 | */ 116 | 117 | abbr[title] { 118 | border-bottom: 1px dotted; 119 | } 120 | 121 | /** 122 | * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 123 | */ 124 | 125 | b, 126 | strong { 127 | font-weight: bold; 128 | } 129 | 130 | /** 131 | * Address styling not present in Safari 5 and Chrome. 132 | */ 133 | 134 | dfn { 135 | font-style: italic; 136 | } 137 | 138 | /** 139 | * Address differences between Firefox and other browsers. 140 | */ 141 | 142 | hr { 143 | -moz-box-sizing: content-box; 144 | box-sizing: content-box; 145 | height: 0; 146 | } 147 | 148 | /** 149 | * Address styling not present in IE 8/9. 150 | */ 151 | 152 | mark { 153 | background: #ff0; 154 | color: #000; 155 | } 156 | 157 | /** 158 | * Correct font family set oddly in Safari 5 and Chrome. 159 | */ 160 | 161 | code, 162 | kbd, 163 | pre, 164 | samp { 165 | font-family: monospace, serif; 166 | font-size: 1em; 167 | } 168 | 169 | /** 170 | * Improve readability of pre-formatted text in all browsers. 171 | */ 172 | 173 | pre { 174 | white-space: pre-wrap; 175 | } 176 | 177 | /** 178 | * Set consistent quote types. 179 | */ 180 | 181 | q { 182 | quotes: "\201C" "\201D" "\2018" "\2019"; 183 | } 184 | 185 | /** 186 | * Address inconsistent and variable font size in all browsers. 187 | */ 188 | 189 | small { 190 | font-size: 80%; 191 | } 192 | 193 | /** 194 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 195 | */ 196 | 197 | sub, 198 | sup { 199 | font-size: 75%; 200 | line-height: 0; 201 | position: relative; 202 | vertical-align: baseline; 203 | } 204 | 205 | sup { 206 | top: -0.5em; 207 | } 208 | 209 | sub { 210 | bottom: -0.25em; 211 | } 212 | 213 | /* ========================================================================== 214 | Embedded content 215 | ========================================================================== */ 216 | 217 | /** 218 | * Remove border when inside `a` element in IE 8/9. 219 | */ 220 | 221 | img { 222 | border: 0; 223 | } 224 | 225 | /** 226 | * Correct overflow displayed oddly in IE 9. 227 | */ 228 | 229 | svg:not(:root) { 230 | overflow: hidden; 231 | } 232 | 233 | /* ========================================================================== 234 | Figures 235 | ========================================================================== */ 236 | 237 | /** 238 | * Address margin not present in IE 8/9 and Safari 5. 239 | */ 240 | 241 | figure { 242 | margin: 0; 243 | } 244 | 245 | /* ========================================================================== 246 | Forms 247 | ========================================================================== */ 248 | 249 | /** 250 | * Define consistent border, margin, and padding. 251 | */ 252 | 253 | fieldset { 254 | border: 1px solid #c0c0c0; 255 | margin: 0 2px; 256 | padding: 0.35em 0.625em 0.75em; 257 | } 258 | 259 | /** 260 | * 1. Correct `color` not being inherited in IE 8/9. 261 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 262 | */ 263 | 264 | legend { 265 | border: 0; /* 1 */ 266 | padding: 0; /* 2 */ 267 | } 268 | 269 | /** 270 | * 1. Correct font family not being inherited in all browsers. 271 | * 2. Correct font size not being inherited in all browsers. 272 | * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. 273 | */ 274 | 275 | button, 276 | input, 277 | select, 278 | textarea { 279 | font-family: inherit; /* 1 */ 280 | font-size: 100%; /* 2 */ 281 | margin: 0; /* 3 */ 282 | } 283 | 284 | /** 285 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 286 | * the UA stylesheet. 287 | */ 288 | 289 | button, 290 | input { 291 | line-height: normal; 292 | } 293 | 294 | /** 295 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 296 | * All other form control elements do not inherit `text-transform` values. 297 | * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. 298 | * Correct `select` style inheritance in Firefox 4+ and Opera. 299 | */ 300 | 301 | button, 302 | select { 303 | text-transform: none; 304 | } 305 | 306 | /** 307 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 308 | * and `video` controls. 309 | * 2. Correct inability to style clickable `input` types in iOS. 310 | * 3. Improve usability and consistency of cursor style between image-type 311 | * `input` and others. 312 | */ 313 | 314 | button, 315 | html input[type="button"], /* 1 */ 316 | input[type="reset"], 317 | input[type="submit"] { 318 | -webkit-appearance: button; /* 2 */ 319 | cursor: pointer; /* 3 */ 320 | } 321 | 322 | /** 323 | * Re-set default cursor for disabled elements. 324 | */ 325 | 326 | button[disabled], 327 | html input[disabled] { 328 | cursor: default; 329 | } 330 | 331 | /** 332 | * 1. Address box sizing set to `content-box` in IE 8/9. 333 | * 2. Remove excess padding in IE 8/9. 334 | */ 335 | 336 | input[type="checkbox"], 337 | input[type="radio"] { 338 | box-sizing: border-box; /* 1 */ 339 | padding: 0; /* 2 */ 340 | } 341 | 342 | /** 343 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 344 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome 345 | * (include `-moz` to future-proof). 346 | */ 347 | 348 | input[type="search"] { 349 | -webkit-appearance: textfield; /* 1 */ 350 | -moz-box-sizing: content-box; 351 | -webkit-box-sizing: content-box; /* 2 */ 352 | box-sizing: content-box; 353 | } 354 | 355 | /** 356 | * Remove inner padding and search cancel button in Safari 5 and Chrome 357 | * on OS X. 358 | */ 359 | 360 | input[type="search"]::-webkit-search-cancel-button, 361 | input[type="search"]::-webkit-search-decoration { 362 | -webkit-appearance: none; 363 | } 364 | 365 | /** 366 | * Remove inner padding and border in Firefox 4+. 367 | */ 368 | 369 | button::-moz-focus-inner, 370 | input::-moz-focus-inner { 371 | border: 0; 372 | padding: 0; 373 | } 374 | 375 | /** 376 | * 1. Remove default vertical scrollbar in IE 8/9. 377 | * 2. Improve readability and alignment in all browsers. 378 | */ 379 | 380 | textarea { 381 | overflow: auto; /* 1 */ 382 | vertical-align: top; /* 2 */ 383 | } 384 | 385 | /* ========================================================================== 386 | Tables 387 | ========================================================================== */ 388 | 389 | /** 390 | * Remove most spacing between table cells. 391 | */ 392 | 393 | table { 394 | border-collapse: collapse; 395 | border-spacing: 0; 396 | } 397 | -------------------------------------------------------------------------------- /web/js/jhere-custom.js: -------------------------------------------------------------------------------- 1 | (function(e,t,n){function x(t,n){this.element=t,this.options=e.extend({},i,n),this.init()}function T(){var e=this.map||{};return{center:e.center,zoom:e.zoomLevel,bbox:e.getViewBounds&&e.getViewBounds(),type:this.mtype}}function N(e,t){var n=new u.kml.Manager;n.addObserver("state",c(function(e){e.state==="finished"&&t.call(this,e)},this)),n.parseKML(e)}function C(t){var n=t.target,r=this.map.pixelToGeo(t.displayX,t.displayY);if(n!==this.map)return;t.type="map"+t.type,e(this.element).trigger(L(t,r))}function k(e){var t=e.target,n=t[e.type];A(n)&&n.call(this.element,L(e,t.coordinate))}function L(t,n){return e.Event(t.type,{originalEvent:t,geo:{latitude:n.latitude,longitude:n.longitude},target:t.target})}function A(e){return typeof e=="function"}function O(){return!!e().on}var r="jHERE",i,s,o,u,a,f,l,c=e.proxy,h,p="mouse",d="click",v="drag",m="touch",g="start",y="end",b="move",w="appId",E="authenticationToken",S=[d,"dbl"+d,p+"up",p+"down",p+b,p+"over",p+"out",p+"enter",p+"leave","longpress",v+g,v,v+y,"resize",m+g,m+y,m+b];i={appId:"69Dgg78qt4obQKxVbRA8",authToken:"Nz7ilIB_v1CRwPXxgPdvuA",zoom:12,center:[52.49,13.37],enable:["behavior","zoombar","scalebar","typeselector"],type:"map",marker:{text:"",textColor:"#333333",fill:"#ff6347",stroke:"#333333",shape:"balloon",icon:undefined},bubble:{content:"",closable:!0,onclose:e.noop},heatmap:{max:20,opacity:.8,coarseness:2}},e[r]=h={},s=x.prototype,h.defaultCredentials=function(e,t){l={id:e,token:t},f.load().is.done(function(){o.Settings.set(w,e),o.Settings.set(E,t)})},s.init=function(){f.load().is.done(c(this.makemap,this))},s.makemap=function(){var t=this,n=t.options,i=a.component,s=[],f=c(C,t),h={};i.Positioning=u.positioning.component.Positioning,l=l||{id:n.appId,token:n.authToken},o.Settings.set(w,l.id),o.Settings.set(E,l.token),e.data(t.element,r,!0),e.each(i,c(function(n,r){n=n.toLowerCase();if(~e.inArray(n,t.options.enable))return A(r)&&s.push(new r)||e.error("invalid: "+n)},t)),t.map=new a.Display(t.element,{zoomLevel:n.zoom,center:n.center,components:s}),t.type(n.type),t._mc=new a.Container,t.map.objects.add(t._mc),e.each(S,function(e,t){h[t]=[f,!1,null]}),t.map.addListeners(h)},s.center=function(e){this.map.setCenter(e)},s.zoom=function(e){this.map.set("zoomLevel",e)},s.type=function(e){var t=this.map,n={map:t.NORMAL,satellite:t.SATELLITE,smart:t.SMARTMAP,terrain:t.TERRAIN,pt:t.SMART_PT,community:t.NORMAL_COMMUNITY,satcommunity:t.SATELLITE_COMMUNITY,traffic:t.TRAFFIC};e in n?(this.mtype=e,e=n[e]):(this.mtype="map",e=n.map),t.set("baseMapType",e)},s.marker=function(t,n){var r={},s=c(k,this),o=this._mc,u="Marker";e.each(S,function(e,t){r[t]=[s,!1,null]}),n=e.extend({},i.marker,n),n.textPen=n.textPen||{strokeColor:n.textColor},n.pen=n.pen||{strokeColor:n.stroke},n.brush=n.brush||{color:n.fill},n.eventListener=r,n.icon||(u="Standard"+u),o.objects.add(new a[u](t,n))},s.nomarkers=function(){this._mc.objects.clear()},s.bubble=function(t,n){var r,s=this.map;n=e.extend({},i.bubble,n),n.content.jquery&&(n.content.css("white-space","normal"),n.content=e("
").append(n.content.clone()).html()),r=s.getComponentById("InfoBubbles")||s.addComponent(new a.component.InfoBubbles),r.openBubble(n.content,{latitude:t.latitude||t[0],longitude:t.longitude||t[1]},n.onclose,!n.closable)},s.nobubbles=function(){var e;return(e=this.map.getComponentById("InfoBubbles"))&&e.closeAll()},s.kml=function(e,t,n){A(t)&&(n=t,t=!1),N.call(this,e,c(function(e){var r=this.map,i=new u.kml.component.KMLResultSet(e.kmlDocument,r);i.addObserver("state",c(function(e){var i,s;e.state==="finished"&&(t&&(i=e.container.objects.get(0),s=i.getBoundingBox(),s&&r.zoomTo(s)),A(n)&&n.call(this,e))},this)),r.objects.add(i.create())},this))},s.heatmap=function(t,n,r){var s;n=n||"value",n.match(/^density|value$/)||(n="value"),r=r||{},r.type=n,r=e.extend({},i.heatmap,r),s=new u.heatmap.Overlay(r),s.addData(t),this.map.overlays.add(s)},s.originalMap=function(e){e.call(this.element,this.map,u)},s.destroy=function(){this.map.destroy(),e.removeData(this.element),e(this.element).empty()},f={},f.is=!1,f.load=function(){var t,r,i;return f.is&&f.is.state().match(/pending|resolved/)?this:(f.is=e.Deferred(),i=function(){o=nokia,u=o.maps,o.Features.load({map:"auto",ui:"auto",search:"auto",routing:"auto",positioning:"auto",behavior:"auto",kml:"auto",heatmap:"auto"},function(){a=u.map,f.is.resolve()})},t=n.getElementsByTagName("head")[0],r=n.createElement("script"),r.src="http://api.maps.nokia.com/2.2.4/jsl.js",r.type="text/javascript",r.charset="utf-8",r.onreadystatechange=function(){r.readyState.match(/loaded|complete/)&&i()},r.onload=i,t.appendChild(r),this)},h._JSLALoader=f,h.extend=function(e,t){typeof e=="string"&&A(t)&&(s[e]=t)},e.fn[r]=function(t){var n=arguments,i="plg_"+r,s;return O()||e.error(r+" requires Zepto or jQuery >= 1.7"),!t&&(s=e.data(this[0],i))?T.call(s):this.each(function(){var o;s=e.data(this,i),s?(typeof t!="string"&&e.error(r+" already initialized, expected method."),o=t,n=Array.prototype.slice.call(n,1),A(s[o])||e.error(r+": "+o+" does not exist"),f.load().is.done(function(){s[o].apply(s,n)})):(s=new x(this,t),e.data(this,i,s))})}})(jQuery,window,document);(function(e){function n(e){return typeof e=="function"}function r(r,i,s,o){var u=e.Deferred();return i=n(i)?i:e.noop,s=n(s)?s:e.noop,t._JSLALoader.load().is.done(function(){function t(e,t){var n=e.location;n=o?e.location.address:e.location.position,t==="OK"?(u.resolve(n),i(n)):(u.reject(),s())}var e=nokia.places.search.manager;o?e.reverseGeoCode({latitude:r.latitude||r[0],longitude:r.longitude||r[1],onComplete:t}):e.geoCode({searchTerm:r,onComplete:t})}),u}var t=e.jHERE;t.geocode=function(e,t,n){return r(e,t,n)},t.reverseGeocode=function(e,t,n){return r(e,t,n,!0)}})(jQuery);(function(e){function i(e){return e instanceof Array?{latitude:e[0],longitude:e[1]}:e}var t,n,r={type:"shortest",transportMode:"car",options:"",trafficMode:"default",width:4,color:"#ff6347",marker:{text:"#",textColor:"#fff"}};n=function(n,s,o){var u,a,f,l;t=t||nokia.maps,n=i(n),s=i(s),o=e.extend({},r,o),f=function(n,r,i){var s,u,a,f,l,c={},h;i==="finished"?(s=n.getRoutes(),f=s[0],a=new t.map.Polyline(f&&f.shape,{pen:new t.util.Pen({lineWidth:o.width,strokeColor:o.color})}),u=new t.map.Container,u.objects.add(a),e.each(f.waypoints,e.proxy(function(t,n){var r=e.extend({},o.marker);o.marker.text==="#"&&(r.text=t+1),this.marker(n.originalPosition,r)},this)),this.map.objects.add(u),l=f.legs&&f.legs.length&&f.legs[0],c.time=l.travelTime,c.length=l.length,c.maneuvers=e.map(l.maneuvers,function(e){return{street:e.streetName,length:e.length,route:e.routeName}}),typeof o.onroute=="function"&&o.onroute.call(this.element,c),h=e.Event("jhere.route",{route:c,target:this.element}),e(this.element).trigger(h)):i==="failed"&&e.error("Failed to calcolate route")},u=new t.routing.Manager,u.addObserver("state",e.proxy(f,this)),a=new t.routing.WaypointParameterList,a.addCoordinate(n),a.addCoordinate(s),l={transportModes:[o.transportMode],type:o.type,options:o.options,trafficMode:o.trafficMode},u.calculateRoute(a,[l])},e.jHERE.extend("route",n)})(jQuery);(function(e){function a(e){return e instanceof Array?{latitude:e[0],longitude:e[1]}:e}function f(e){return e?(e.pen=e.pen||{},e.brush=e.brush||{},e.pen.strokeColor=e.pen.strokeColor||e.stroke||"#111",e.stroke="solid",e.pen.lineWidth=e.pen.lineWidth||e.thickness||1,e.brush.color=e.brush.color||e.fill,e):e}function l(e,n){e.objects.add(new t.map.Circle(a(n.center),n.radius||1e3,n.style))}function c(e,n){var r=new t.geo.BoundingBox(a(n.topLeft),a(n.bottomRight),!1);e.objects.add(new t.map.Rectangle(r,n.style))}function h(n,r){r.points=e.map(r.points,function(e){return a(e)}),n.objects.add(new t.map.Polyline(r.points,r.style))}function p(n,r){r.points=e.map(r.points,function(e){return a(e)}),n.objects.add(new t.map.Polygon(r.points,r.style))}var t,n,r,i,s,o,u;n=function(n,r){t=t||nokia.maps,u||(u=new t.map.Container,this.map.objects.add(u)),r.style=f(r.style);switch(n){case"circle":l(u,r);break;case"rectangle":c(u,r);break;case"polyline":h(u,r);break;case"polygon":p(u,r);break;default:e.error(n+" not supported")}},r=function(e){n.call(this,"circle",e)},i=function(e){n.call(this,"rectangle",e)},s=function(e){n.call(this,"polyline",e)},o=function(e){n.call(this,"polygon",e)},e.jHERE.extend("shape",n),e.jHERE.extend("circle",r),e.jHERE.extend("rectangle",i),e.jHERE.extend("polyline",s),e.jHERE.extend("polygon",o)})(jQuery);(function(e){function v(e){var t=e.target,n=t[e.type];g(n)&&n.call(this.element,m(e,t.coordinate))}function m(t,n){return e.Event(t.type,{originalEvent:t,geo:{latitude:n.latitude,longitude:n.longitude},target:t.target})}function g(e){return typeof e=="function"}var t,n,r,i,s={text:"",textColor:"#333333",fill:"#ff6347",stroke:"#333333",shape:"balloon",icon:undefined,group:"_"},o=e.proxy,u="mouse",a="click",f="drag",l="touch",c="start",h="end",p="move",d=[a,"dbl"+a,u+"up",u+"down",u+p,u+"over",u+"out",u+"enter",u+"leave","longpress",f+c,f,f+h,"resize",l+c,l+h,l+p];n=function(n,r){var i={},u=o(v,this),a=this._mc,f="Marker",l,c;this.groups=this.groups||{},c=this.groups,t=t||nokia.maps,e.each(d,function(e,t){i[t]=[u,!1,null]}),r=e.extend({},s,r),r.textPen=r.textPen||{strokeColor:r.textColor},r.pen=r.pen||{strokeColor:r.stroke},r.brush=r.brush||{color:r.fill},r.eventListener=i,r.icon||(f="Standard"+f),l=new t.map[f](n,r),c[r.group]=c[r.group]||[],c[r.group].visible=c[r.group].length===0?!0:c[r.group].visible,c[r.group].push(l),c[r.group].visible&&a.objects.add(l)},i=function(t,n){var r=this._mc,i=r.objects,s;this.groups=this.groups||{},s=this.groups,t=t instanceof Array?t:[t],e.each(t,function(e,t){n?i.addAll(s[t]||[]):i.removeAll(s[t]||[]),s[t].visible=!!n})},r=function(){this._mc.objects.clear(),this.groups={}},e.jHERE.extend("marker",n),e.jHERE.extend("markergroups",i),e.jHERE.extend("nomarkers",r)})(jQuery); -------------------------------------------------------------------------------- /test/lib/mocks.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Massimiliano Marcon 3 | 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | * subject to the following conditions: 9 | 10 | * The above copyright notice and this permission notice shall be included 11 | * in all copies or substantial portions of the Software. 12 | 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 15 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 16 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 17 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 18 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | */ 20 | 21 | /*global jasmine:true, 22 | $:true*/ 23 | var resetMocks, spy, nokia = {}, SPIES = {}, _JSLALoader; 24 | 25 | (function(){ 26 | 27 | var _spy = function(name) { 28 | return jasmine.createSpy(name); 29 | }; 30 | 31 | var _resetMocks = function(){ 32 | var map; 33 | 34 | _JSLALoader = {}; 35 | 36 | //Mock the promise-based loaded 37 | _JSLALoader.load = function(){ 38 | return { 39 | is: { 40 | done: function(fn) { 41 | fn(); 42 | } 43 | } 44 | }; 45 | }; 46 | 47 | //JSLA 48 | nokia.Settings = { 49 | set: spy('nokia.Settings.set') 50 | }; 51 | 52 | nokia.maps = { 53 | util: { 54 | ApplicationContext: { 55 | set: function(){ 56 | console.log('ApplicationContext.set is deprecated'); 57 | spy('ApplicationContext.set')(); 58 | } 59 | } 60 | } 61 | }; 62 | nokia.maps.positioning = { 63 | component: { 64 | Positioning: spy('Positioning') 65 | } 66 | }; 67 | SPIES.component_infobubbles_openbubble = spy('[component] open info bubble'); 68 | SPIES.component_infobubbles_closeall = spy('[component] closeall info bubbles'); 69 | map = nokia.maps.map = { 70 | component: { 71 | Behavior: spy('[component] Behavior'), 72 | zoom: {}, 73 | InfoBubbles: function(){ 74 | this.openBubble = function(){ 75 | SPIES.component_infobubbles_openbubble.apply(this, arguments); 76 | }; 77 | this.closeAll = function(){ 78 | SPIES.component_infobubbles_closeall.apply(this, arguments); 79 | }; 80 | } 81 | } 82 | }; 83 | 84 | SPIES.container_objects_add = spy('[container] add to objects'); 85 | SPIES.container_objects_clear = spy('[container] clear to objects'); 86 | SPIES.container_objects_get = spy('[container] get object'); 87 | SPIES.container_objects_getbbox = spy('[container] get bbox'); 88 | 89 | map.Container = function(){ 90 | this.objects = { 91 | add: function(){ SPIES.container_objects_add.apply(this, arguments); }, 92 | clear: function(){ SPIES.container_objects_clear.apply(this, arguments); }, 93 | get: function(){ 94 | SPIES.container_objects_get.apply(this, arguments); 95 | return { 96 | getBoundingBox: function(){ 97 | SPIES.container_objects_getbbox.apply(this, arguments); 98 | return 'bbox'; 99 | } 100 | }; 101 | } 102 | }; 103 | }; 104 | 105 | SPIES.display_objects_add = spy('[map] add to objects'); 106 | SPIES.display_overlays_add = spy('[map] add to overlays'); 107 | SPIES.display_set = spy('[map] set property'); 108 | SPIES.display_addListeners = spy('[map] add add listeners'); 109 | SPIES.display_destroy = spy('[map] destroy'); 110 | SPIES.display_setCenter = spy('[map] setCenter'); 111 | SPIES.display_getComponentById = spy('[map] getComponentById'); 112 | SPIES.display_addComponent = spy('[map] addComponent'); 113 | SPIES.display_zoomTo = spy('[map] zoomTo'); 114 | 115 | SPIES.args = { 116 | map_normal: {t:1}, 117 | map_satellite: {t:2}, 118 | map_smart: {t:3}, 119 | map_terrain: {t:4}, 120 | map_smartpt: {t:5}, 121 | map_normalcommunity: {t:6}, 122 | map_satellitecommunity: {t:7}, 123 | map_traffic: {t:8} 124 | }; 125 | 126 | map.Display = function(){ 127 | this.objects = { 128 | add: function(){ SPIES.display_objects_add.apply(this, arguments); } 129 | }; 130 | this.set = function(){ SPIES.display_set.apply(this, arguments); }; 131 | this.addListeners = function(){ SPIES.display_addListeners.apply(this, arguments); }; 132 | this.destroy = function(){ SPIES.display_destroy.apply(this, arguments); }; 133 | this.center = {}; 134 | this.setCenter = function(center){ 135 | this.center = center; 136 | SPIES.display_setCenter.apply(this, arguments); 137 | }; 138 | this.addComponent = function(component){ 139 | SPIES.display_addComponent.apply(this, arguments); 140 | return component; 141 | }; 142 | this.zoomTo = function(zoom){ 143 | this.zoomLevel = zoom; 144 | SPIES.display_zoomTo.apply(this, arguments); 145 | }; 146 | this.overlays = { 147 | add: function(){ SPIES.display_overlays_add.apply(this, arguments); } 148 | }; 149 | 150 | this.NORMAL = SPIES.args.map_normal; 151 | this.SATELLITE = SPIES.args.map_satellite; 152 | this.SMARTMAP = SPIES.args.map_smart; 153 | this.TERRAIN = SPIES.args.map_terrain; 154 | this.SMART_PT = SPIES.args.map_smartpt; 155 | this.NORMAL_COMMUNITY = SPIES.args.map_normalcommunity; 156 | this.SATELLITE_COMMUNITY = SPIES.args.map_satellitecommunity; 157 | this.TRAFFIC = SPIES.args.map_traffic; 158 | }; 159 | 160 | map.Display.prototype.getComponentById = function(){ SPIES.display_getComponentById.apply(this, arguments); }; 161 | 162 | map.Marker = function(){}; 163 | map.StandardMarker = function(){}; 164 | 165 | nokia.maps.kml = {}; 166 | nokia.maps.kml.component = {}; 167 | 168 | SPIES.kmlmgr_addObserver = spy('[kml manager] addObserver'); 169 | SPIES.kmlmgr_parseKML = spy('[kml manager] parseKML'); 170 | 171 | nokia.maps.kml.Manager = function(){ 172 | this.observers = {}; 173 | this.addObserver = function(event, callback){ 174 | //Need to trigger the event somehow 175 | this.observers[event] = callback; 176 | SPIES.kmlmgr_addObserver.apply(this, arguments); 177 | }; 178 | this.parseKML = function(){ 179 | //Trigger callback immediately 180 | if(typeof this.observers.state === 'function') { 181 | this.observers.state(this); 182 | } 183 | SPIES.kmlmgr_parseKML.apply(this, arguments); 184 | }; 185 | this.state = 'finished'; //No need to have other states for mocking purposes 186 | this.kmlDocument = 'mockeddocument'; 187 | }; 188 | 189 | SPIES.kmlresultset_addObserver = spy('[kml resultset] addObserver'); 190 | SPIES.kmlresultset_create = spy('[kml resultset] create'); 191 | 192 | nokia.maps.kml.component.KMLResultSet = function(){ 193 | this.observers = {}; 194 | this.addObserver = function(event, callback){ 195 | //Need to trigger the event somehow 196 | this.observers[event] = callback; 197 | SPIES.kmlresultset_addObserver.apply(this, arguments); 198 | }; 199 | this.create = function() { 200 | if(typeof this.observers.state === 'function') { 201 | this.observers.state(this); 202 | } 203 | SPIES.kmlresultset_create.apply(this, arguments); 204 | }; 205 | this.state = 'finished'; //No need to have other states for mocking purposes 206 | this.container = new map.Container(); 207 | }; 208 | 209 | nokia.maps.heatmap = {}; 210 | 211 | SPIES.heatmap_addData = spy('[heatmap] addData'); 212 | 213 | nokia.maps.heatmap.Overlay = function(){ 214 | this.addData = function(){ SPIES.heatmap_addData.apply(this, arguments); }; 215 | }; 216 | 217 | $.jHERE._injectNS(nokia); 218 | $.jHERE._injectJSLALoader(_JSLALoader); 219 | }; 220 | 221 | 222 | resetMocks = _resetMocks; 223 | spy = _spy; 224 | })(); -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jHERE - Maps Made Easy 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 |

jHERE

39 |

Maps made easy.

40 | 44 |
45 | 52 |
53 | 54 |
55 |
56 |

57 | Maps are cool, but map APIs are complicated. jHERE solves this problem 58 | by offering a simple but powerful map API in the form of a jQuery (or Zepto.JS, or Tire) plugin. 59 |

60 | 61 |

62 | With jHERE, you can easily add interactive maps to your website. In only 5KB (2KB Gzipped), you get a powerful map API, highly customizable markers, event handling and info bubbles. Bonus features are KML support and data visualization via heatmaps. 63 |

64 |

65 | jHERE is built on top of the awesome and very solid HERE Maps API. For advanced users, the native 66 | API is exposed by jHERE, thus offering unlimited possibilities of customization. 67 |

68 |
69 |
70 | 71 |
72 |
73 |

Examples

74 |
75 |
76 |

77 | The examples below give an overview of what jHERE can do. 78 | Experiment with jHERE in the playground: the code is so simple that it needs no explanation. 79 |

80 |
81 |
82 |
    83 |
  • 84 | Simple Map 85 | 86 |
  • 87 |
  • 88 | Satellite 89 | 90 |
  • 91 |
  • 92 | Marker 93 | 94 |
  • 95 |
  • 96 | Bubble 97 | 98 |
  • 99 |
  • 100 | KML 101 | 102 |
  • 103 |
  • 104 | Heatmap 105 | 106 |
  • 107 |
108 |
109 |
110 | 111 |
112 |
113 |

Extensions

114 |
115 |
116 |

117 | In order to keep jHERE as small as possible, the plugin contains only a subset of all 118 | the functionalities that are available via the HERE Maps API. 119 |

120 |

121 | Everything else is available via extensions. A few of them are already available on Github. 122 |

123 |

124 | Geocoding, routing, shapes are just a few examples 125 | of what can be done with extensions. 126 |

127 |

128 | It is possible to create a custom build of jHERE that includes all the official extensions you need minified and concatenated in a single file. 129 |

130 |
131 |
132 |
    133 |
  • 134 | Geocoding 135 | 136 |
  • 137 |
  • 138 | Routing 139 | 140 |
  • 141 |
  • 142 | Shapes 143 | 144 |
  • 145 |
146 |
147 |
148 | 149 | 164 | 165 | 170 | 171 | 172 | 173 | 174 | 175 | 176 |
177 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /web/css/main.scss: -------------------------------------------------------------------------------- 1 | @import "normalize"; 2 | 3 | $background: #333; 4 | $jherereddish: rgba(255, 99, 71, 0.8); 5 | $jherereddishold: #FF7F50; //#ff6347 6 | 7 | $navbackground: #222; 8 | $lightgreen: #9fd067; 9 | $darkgreen: #86c440; 10 | 11 | 12 | //Utilities 13 | $default-prefixes: webkit moz ms o; 14 | 15 | @mixin breakpoint($point) { 16 | @if $point == small-480 { 17 | @media (max-device-width: 480px) { @content; } 18 | } 19 | } 20 | 21 | @mixin prefix($property, $value, $prefixes: $default-prefixes) { 22 | @each $prefix in $prefixes { 23 | -#{$prefix}-#{$property}: #{$value}; 24 | } 25 | #{$property}: #{$value}; 26 | } 27 | 28 | @mixin transition($property: all, $delay: 1s, $timing: linear) { 29 | $value: $property $delay $timing; 30 | // use default prefixes 31 | @include prefix('transition', $value); 32 | } 33 | 34 | // h2 { 35 | // text-shadow: 1px 1px 0 transparentize(#111, .6); 36 | // text-transform: capitalize; 37 | // @include breakpoint(small-480) { 38 | // text-align: center; 39 | // } 40 | // } 41 | 42 | html { 43 | font-size: 62.5%; 44 | } 45 | 46 | body { 47 | background: #fff; 48 | font-family: 'Titillium Web', sans-serif; 49 | font-weight: 400; 50 | } 51 | 52 | #map { 53 | position: absolute; 54 | top: 0; 55 | right: 0; 56 | bottom: -3rem; 57 | left: 0; 58 | } 59 | 60 | header { 61 | 62 | .overlay { 63 | position: absolute; 64 | top: 0; 65 | right: 0; 66 | bottom: 0; 67 | left: 0; 68 | background: #000; 69 | opacity: 0.65; 70 | z-index: 10; 71 | } 72 | 73 | position: relative; 74 | height: 40rem; 75 | margin: 0; 76 | overflow: hidden; 77 | 78 | // &.page { 79 | // height: 40rem; 80 | // } 81 | 82 | nav { 83 | background: $navbackground; 84 | background: transparentize($navbackground, .1); 85 | text-align: center; 86 | position: fixed; 87 | top: 0; 88 | left: 0; 89 | right: 0; 90 | z-index: 100; 91 | 92 | ul { 93 | margin: 0; 94 | padding: 0; 95 | 96 | li { 97 | font-family: 'Oswald', sans-serif; 98 | color: #fff; 99 | display: inline-block; 100 | font-size: 3rem; 101 | margin: 0 1rem; 102 | 103 | a:link, a:visited { 104 | padding: .8rem; 105 | text-align: center; 106 | color: #fff; 107 | text-transform: uppercase; 108 | text-decoration: none; 109 | display: inline-block; 110 | } 111 | 112 | a:hover, a:active { 113 | color: $lightgreen; 114 | } 115 | } 116 | } 117 | } 118 | 119 | .title { 120 | position: absolute; 121 | top: 20%; 122 | left: 0; 123 | right: 0; 124 | text-align: center; 125 | z-index: 11; 126 | // background: transparent url(../img/logo.png) no-repeat 50% 100%; 127 | padding-bottom: 8rem; 128 | 129 | h1 { 130 | font-family: 'Oswald', sans-serif; 131 | font-size: 11rem; 132 | line-height: 1.2; 133 | margin: 0; 134 | padding: 0; 135 | color: #fff; 136 | font-weight: normal; 137 | } 138 | 139 | h2 { 140 | font-family: 'Syncopate', sans-serif; 141 | font-size: 2.2rem; 142 | text-transform: uppercase; 143 | color: #fff; 144 | font-weight: normal; 145 | } 146 | 147 | .get { 148 | text-align: center; 149 | 150 | a:link, a:visited { 151 | background-color: $lightgreen; 152 | border-radius: 4px; 153 | display: inline-block; 154 | color: #fff; 155 | padding: 1.5rem; 156 | text-decoration: none; 157 | text-transform: uppercase; 158 | font-size: 1.6rem; 159 | text-align: center; 160 | width: 14rem; 161 | margin: 2rem; 162 | border-right: 4.8rem solid $darkgreen; 163 | overflow: visible; 164 | position: relative; 165 | @include transition(background-color, .3s, linear); 166 | 167 | span { 168 | position: absolute; 169 | right: -4.8rem; 170 | top: 0; 171 | bottom:0; 172 | width: 4.8rem; 173 | } 174 | 175 | &.download span { 176 | background: transparent url(../img/download.png) no-repeat 50%; 177 | } 178 | 179 | &.fork span { 180 | background: transparent url(../img/fork.png) no-repeat 50%; 181 | } 182 | 183 | &.star span { 184 | background: transparent url(../img/star.png) no-repeat 50%; 185 | } 186 | 187 | } 188 | 189 | a:hover, a:active { 190 | background-color: $darkgreen; 191 | } 192 | } 193 | } 194 | 195 | .controls { 196 | width: 3.2rem; 197 | height: 7.4rem; 198 | position: absolute; 199 | top: 50%; 200 | margin-top: -3.7rem; 201 | right: 1.5rem; 202 | margin: 0; 203 | padding: 0; 204 | z-index: 11; 205 | 206 | li { 207 | cursor: pointer; 208 | margin: 0; 209 | padding: 0; 210 | list-style-type: none; 211 | list-style-position: inside; 212 | background: transparent url(../img/zoom.png) no-repeat 0; 213 | height: 32px; 214 | width: 32px; 215 | position: absolute; 216 | left: 0; 217 | opacity: .8; 218 | 219 | &.minus { 220 | bottom: 0; 221 | } 222 | 223 | &.plus { 224 | top: 0; 225 | background-position: -32px 0; 226 | } 227 | 228 | &:hover { 229 | opacity: 1; 230 | } 231 | } 232 | } 233 | 234 | } 235 | 236 | .content { 237 | font-size: 1.8rem; 238 | padding: 4rem; 239 | // text-shadow: rgba(0, 0, 0, 0.3) 1px 0px 0px; 240 | line-height: 1.4; 241 | 242 | a { 243 | &:link, &:visited { 244 | color: #8b2222; 245 | text-decoration: none; 246 | } 247 | 248 | &:hover, &:active { 249 | text-decoration: underline; 250 | } 251 | } 252 | 253 | &#main { 254 | background: $jherereddishold; 255 | color: #fff; 256 | } 257 | 258 | &#extensions { 259 | background: $jherereddishold; 260 | color: #fff; 261 | } 262 | 263 | &#examples { 264 | background: #fff; 265 | color: #333; 266 | 267 | a { 268 | &:link, &:visited { 269 | color: #4169e1; 270 | } 271 | } 272 | } 273 | 274 | &#docs { 275 | background: #fff; 276 | color: #333; 277 | 278 | a { 279 | &:link, &:visited { 280 | color: #4169e1; 281 | } 282 | } 283 | 284 | pre code { 285 | display: block; 286 | } 287 | 288 | code { 289 | display: inline-block; 290 | padding: .3rem; 291 | border-radius: 3px; 292 | background: #F5F2F0; 293 | color: #333; 294 | font-size: 1.4rem; 295 | } 296 | 297 | div { 298 | p:nth-child(2) code, code.dark { 299 | background: #333; 300 | color: #fff; 301 | font-size: 1.6rem; 302 | } 303 | 304 | p { 305 | margin: .5rem 0; 306 | } 307 | 308 | h3 { 309 | text-transform: uppercase; 310 | font-family: 'Oswald', sans-serif; 311 | color: $jherereddishold; 312 | text-shadow: none; 313 | text-shadow: rgba(139, 34, 34, .4) 1px 0px 0px; 314 | } 315 | } 316 | } 317 | 318 | 319 | strong { 320 | font-weight: bold; 321 | // text-transform: uppercase; 322 | // font-size: 120%; 323 | } 324 | 325 | section, header { 326 | max-width: 76.8rem; 327 | margin: 0 auto; 328 | } 329 | 330 | header { 331 | width: auto; 332 | height: auto; 333 | background: transparent; 334 | 335 | h3 { 336 | font-family: 'Oswald', sans-serif; 337 | font-size: 6rem; 338 | margin: 0; 339 | text-transform: uppercase; 340 | font-weight: normal; 341 | text-shadow: rgba(0, 0, 0, 0.3) 1px 0px 0px; 342 | } 343 | } 344 | 345 | .demos { 346 | ul { 347 | margin: 0; 348 | padding: 0; 349 | list-style-type: none; 350 | text-align: center; 351 | } 352 | } 353 | 354 | .demos li { 355 | position: relative; 356 | display: inline-block; 357 | margin: 1rem 1%; 358 | width: 30%; 359 | min-width: 20rem; 360 | height: (76.8rem/3); 361 | border: 2px solid #333; 362 | background: #eee; 363 | overflow: hidden; 364 | 365 | // &:hover { 366 | // border: 2px solid #444; 367 | 368 | // span { 369 | // background: #444; 370 | // } 371 | // } 372 | 373 | span, .caption { 374 | position: absolute; 375 | right: 0; 376 | bottom: 0; 377 | left: 0; 378 | z-index: 10; 379 | display: block; 380 | padding: .4rem 0; 381 | background: #333; 382 | color: #fff; 383 | text-align: center; 384 | text-transform: uppercase; 385 | letter-spacing: .1rem; 386 | font-size: 1.6rem; 387 | font-family: 'Oswald', sans-serif; 388 | } 389 | 390 | a { 391 | &.playground:link, &.playground:visited { 392 | position: absolute; 393 | bottom: 0; 394 | right: 0; 395 | background: transparent url(../img/console-g.png) no-repeat 50%; 396 | width: 3rem; 397 | height: 3rem; 398 | z-index: 10; 399 | } 400 | 401 | &.playground:hover, &.playground:active { 402 | background-image: url(../img/console-r.png) 403 | } 404 | } 405 | 406 | .address, .location { 407 | font-family: 'Oswald', sans-serif; 408 | position: absolute; 409 | color: #333; 410 | top: 1rem; 411 | left: 0; 412 | right: 0; 413 | text-align: center; 414 | } 415 | 416 | .location { 417 | top: 50%; 418 | } 419 | 420 | // .caption a { 421 | // display: inline-block; 422 | // position: absolute; 423 | // right: 5px; 424 | // } 425 | } 426 | 427 | .gravatar { 428 | float: left; 429 | margin: .5rem 1rem 1rem 0; 430 | border: 8px solid #fff; 431 | } 432 | } 433 | 434 | footer { 435 | background: #fff; 436 | padding: 4rem 4rem 1rem 4rem; 437 | position: relative; 438 | 439 | .links { 440 | max-width: 76.8rem; 441 | margin: 0 auto 1rem auto !important; 442 | font-size: 1.8rem; 443 | text-decoration: none; 444 | list-style-type: none; 445 | list-style-position: inside; 446 | padding: 0; 447 | } 448 | 449 | .social { 450 | position: absolute; 451 | right: 1rem; 452 | top: 1rem; 453 | z-index: 11; 454 | margin: 0; 455 | padding: 0; 456 | list-style-type: none; 457 | width: 27rem; 458 | height: 2rem; 459 | overflow: hidden; 460 | 461 | li { 462 | display: inline-block; 463 | 464 | &.facebook { 465 | position: relative; 466 | top: -4px; 467 | left: 15px; 468 | } 469 | } 470 | } 471 | 472 | small { 473 | text-transform: uppercase; 474 | font-size: 1rem; 475 | text-align: center; 476 | display: block; 477 | } 478 | } 479 | --------------------------------------------------------------------------------