Friday, 11 April 2014

Google analytics event tracking in PhoneGap / Cordova

I spent (wasted) hours trying to get this GAPlugin to work but simply couldn't. So I went back to square one, did some more googling and found Dan Wilson's Google Analytics Plugin. I'm pleased to say I had it running in minutes simply by following his concise instructions:

cordova plugin add https://github.com/danwilson/google-analytics-plugin.git

Then, in deviceready add the following:

analytics.startTrackerWithId('UA-XXXX-YY') 

And for each event, simply:

analytics.trackEvent('Category', 'Action', 'Label', Value) 

Job done. Big-up to Dan Wilson!

Tuesday, 1 April 2014

Leaflet.js clickable marker label

I couldn't find any documentation or examples on how to make a label clickable in leaflet.js.

I tried adding a myLabel.on('click',function(){ }); event but it simply wasn't working. After poking around in the console for a while and logging the label object I found you need to change a seemingly undocumented 'clickable' option. So I ended up with something like this:


var myLabel = myMarker.label;
myLabel.options.clickable = true;
myLabel.on('click',function(){  
//do your stuff
})

Friday, 28 March 2014

Visual Studio slow startup when debugging

I've been recently struggling with a really slow startup time when debugging in Visual Studio. Typically it would take nearly two minutes, which is unacceptable especially if you're working on something that requires regular iterations and test runs, which is a way I like to work.

I tried symbol caching but this had little effect. Eventually I picked up on a subtle comment on an SO thread where someone had resolved a similar problem simply by deleting a breakpoint.

So, I deleted all my breakpoints, and hey presto my startup time was sorted - back to an acceptable 20 seconds!

Wednesday, 26 February 2014

Markers, popups and labels with leaflet and openstreetmap

It took me a while to get this code working right, and now I have I thought I'd share/store it. It could probably do with a little refactoring by outsourcing some of it to other methods, but it's good to go and its linear nature makes it easier to post here. I started this off using google maps but the performance was terrible and after a bit of zooming/panning the app would crash when running on a device. So I opted for leaflet with openstreetmap and I'm really please with the results.

What I'm doing with this code is plotting 40 or so holiday parks with markers and labels, with an associated popup when clicked. In the popup is a button (a JQM widget) that performs an action. Further to this I wanted to switch the marker for a larger one and hide/show labels at a certain zoom level, and I also wanted to specify different label orientations (top,right,left,bottom) for each park.

The end result looks something like this:

              

mapPagePopulate:function(){

                var self=this;
                self.show_loader("Loading map data...");

                //set initial zoom depending on device
                var initZoom = 7;
                if(self.deviceIsMobile()){ initZoom = 6; }

                //init map with centre around Nottingham
                var map = L.map('map_canvas').setView([52.946104,-1.170044], initZoom);
              
                //add copyright - v important!
                L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                    attribution: 'Map data © OpenStreetMap contributors',
                    maxZoom: 18,
                    minZoom: 6
                }).addTo(map);


                //get park data from local storage
                    var parkListLite = $.parseJSON(window.localStorage.getItem(self.localStorageKeys.parkListLite));
                   
                   //declare empty arrays
                    var locations = [];
                    var markers = [];

                    //get label positiong (t,r,b,l)
                    var labelPositions = self.settings.mapLabelPositions();
   
                    //loop through park data, create location object with everything we need,
                    //and push it to locations array
                    $(parkListLite).each(function(i, obj){ 
                        var location = [];

                        //popup html
                        var calloutMarkup = String.format('

{0}

'+ '{1} '+ 'From {4}', obj['ParkName'], obj['MapCopy'], obj['EPiServerPageId'], self.endpoints.img_url + obj['MapThumbnail'], self.utils.makePriceFriendly(obj['CheapestPrice'],"£") ); var wrapper = document.createElement("div"); wrapper.innerHTML = calloutMarkup; wrapper.className="mapCallout"; location[0] = obj['ParkName']; location[1] = obj['Latitude']; location[2] = obj['Longitude']; location[3] = wrapper; location[4] = labelPositions[obj['ParkName']]; location[5] = ''+ obj['ParkName'] +''; locations.push(location); }); //create icons var mapMarkerSmall, mapMarkerLarge, iconAnchor; $(locations).each(function(i, loc){ //label anchor influences where the popup appears //here we check if we want top, left, right or bottom //and specify the anchor and css accordingly switch(loc[4]) { case 't': labelAnchor= [-128,-63]; labelClass = "mapLabel top"; break; case 'r': labelAnchor= [-263,-24]; labelClass = "mapLabel right"; break; case 'b': labelAnchor= [-128,25]; labelClass = "mapLabel bottom"; break; case 'l': labelAnchor= [0,-24]; labelClass = "mapLabel left"; break; default: labelAnchor= [0,-24]; labelClass = "mapLabel left"; } //create the large and small icon for each park, with the anchor specified above mapMarkerSmall = L.icon({ iconUrl: 'img/mapParkMarker.png', iconRetinaUrl: 'img/mapParkMarker.png', iconSize: [20, 20], iconAnchor: [10,10], popupAnchor: [0,-20], labelAnchor: labelAnchor }); mapMarkerLarge = L.icon({ iconUrl: 'img/mapMarkerLarge.png', iconRetinaUrl: 'img/mapMarkerLarge.png', iconSize: [130, 130], iconAnchor: [65,65], popupAnchor: [0,-20], labelAnchor: labelAnchor }); //add marker to map with label var marker = L.marker([loc[1], loc[2]], {icon: mapMarkerSmall}).bindLabel(loc[5], {noHide: true,direction: 'left',className:labelClass}).addTo(map); //bind popup to marker marker.bindPopup(loc[3]); //we can assign arbitrary properties to marker. here we assign small and large markers marker.iconSmall = mapMarkerSmall; marker.iconLarge = mapMarkerLarge; //hide labels on initial load map.removeLayer(marker.label); //push marker to marker array markers.push(marker); }); //for some zooms we need to show/hide labels or switch out markers for larger/smaller map.on('zoomend', function(event) { var zoom = map.getZoom(); var markerLabelClass; for (i = 0; i < locations.length; i++) { markerLabelClass = markers[i].labelClass; if(zoom <= 10){ markers[i].setIcon(markers[i].iconSmall); map.removeLayer(markers[i].label); }else{ markers[i].setIcon(markers[i].iconLarge); map.addLayer(markers[i].label); } } }); //capture popup open event and run JQM create so it creates the button widget //also assign click event to park view button map.on('popupopen', function(e) { $('#map_canvas').trigger('create'); $('.parkButton').unbind(); $('.parkButton').on('click',function(){ self.setLocalStorage(self.localStorageKeys.lastRequestedParkId,$(this).data('parkPageId')); self.utils.notify('Not yet implemented','OK'); //$.mobile.changePage('#parkoverview'); }); }); self.hide_loader(); }

SkyDrive needs to be updated AppStoreRequiredUpdateAva'ilableMessage

So, it looks like Microsoft have lazily given us a painful upgrade path now that they've been forced to rename SkyDrive. This morning I logged into my Mac and got this bizarre message:



At first I thought this may be some kind of virus duping me into handing over my SkyDrive detail, and there's no mention of this update in the app store, presumably because the SkyDrive app no longer exists, and it's not an update at all, more a replacement.

They've switched off SkyDrive and done a runner; The 'Get the Update' button takes you to the appstore where you can download OneDrive, and sure enough you have to reconfigure your SkyDrive settings (folder, preferences) all over again, just like you were a new user. As I type, my new OneDrive installation is slowly synching with the server. It was all bang up-to-date yesterday at 5pm but it looks like it's going through every single file to work out what yesterday it already knew.

And no doubt I'll have to go through the same ball-ache on my other devices too. Grrr.

Friday, 21 February 2014

Changing the name of a Phonegap project

This is always a pain, but these instructions found on StackOverflow seem to hit the spot:
  • Edit the file ./.cordova/config.json Change the "name" field to your new project name. 
  • Edit the file ./www/config.xml Change the "name" field to your new project name. 
  • Make a copy of your ./platforms/ios directory (optional, only needed if you have modified the ios code directly) 
  • Remove the ./platforms/ios directory. 
  • Run "phonegap build ios" This will create a new project with the correct name.