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 |
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 | 
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 | 
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 | 
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 |
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 | max at jhere dot net. 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 | //
');
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 |
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 |
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 |
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 |