by Oliver
18. September 2015 18:55
Here's a simple scenario using Google Maps Javascript API v3 that until today I could not get to work properly: Open a custom map popup window after clicking on a map marker, and close it when clicking anywhere on the map or the rest of the surrounding page. The code I tried to open the map on click of a marker: google.maps.event.addListener(marker, "click", function() { showPopup(marker); }); to close any open marker on clicking anywhere outside the map popup: $(document).on("click.mappopup.offmap", function() { closeAllMarkers(markers); }); The problem I was facing was that the click event that was triggered on the marker would bubble all the way up to the document and the map popup would barely show up when it was already being closed again. Looking for a solution on the web I stumbled upon this old thread on Google code in which several attempts were made to fix the issue and a maps API team member even announced the bug as fixed, but no-one seemed to actually have actually solved the problem. Things I've tried according to the above thread google.maps.event.addListener(marker, "click", function(ev) { showPopup(marker); // does not do a thing ev.cancelBubble = true; // does not exist on the passed in event object ev.stopPropagation && ev.stopPropagation(); // does not exist on the passed in event object ev.preventDefault && ev.preventDefault(); // what Google devs proposed but also did not work ev.stop(); }); But then I stumbled upon this answer on stackoverflow in which the author mentions: Keep in mind that if you pass "event" as an argument to the handler function you will get a custom Google maps click event which does not have stopPropagation method. And that brought me on the right track! So I removed the ev parameter from the handler and used the global event object to try and stop it from bubbling up. After trying a few combinations of the above code I settled with this one: The Working Code google.maps.event.addListener(marker, "click", function() { showPopup(marker); // actually stops the event from bubbling up to the map or the document event.preventDefault(); }); And that was it! I couldn't believe that the solution was so simple.
by Oliver
27. June 2015 12:46
In the process of making Camping.Info more mobile-friendly, I've needed to move around pieces of HTML in the DOM time and again. At last, I've come up with two little helper functions that I wrapped into a little jQuery plugin that I want to share in this post. When To Use Move-Restore The DOM tree on every page on Camping.Info is quite large and often convoluted. At least partly this is a consequence of the many UserControls we use to build our pages on the server using ASP.NET WebForms. To achieve a more mobile-friendly layout of these pages we needed to position certain elements differently, hide some and show others, and in the end also move around some critical parts to fit the mobile design. Much of work could and has been done by our designer via CSS but for the rest of them we need to touch the DOM tree. Move-Restore proves especially helpful in the case of a user-agent switching between two different layouts of your site, e.g. the desktop and the mobile layout (in case you have just those two), because it easily allows you to restore elements you previously moved around. How to Use Move-Restore Just call $("#move-me").moveTo("#target") when you want to move something e.g. in your mobile layout and at a later point, e.g. when switching back to your desktop layout, call $("move-me").restore(). That's it. I've also put together a fiddle to show how to use the plugin here. Also, have a look at the usage.html in the below gist. How It Works The beauty of this plugin, in my opinion, lies in the fact that you don't have to manually keep track of where you get an element from to later restore it. Internally, the plugin inserts a <script> element in place of the moved element. The (highly probably) unique id of that script element is stored as a datum on the moved element and later retrievable when we need to restore the element to its original position. Currently, at revision 2 of the gist, there's one option you can tweak to match your scenario: the jQuery method the plugin should use to move the selected element(s) around. By default, move-restore uses appendTo but there are other sensible options, e.g. prependTo, insertAfter, or insertBefore. Just pass the one that fits your needs as the second optional argument to moveTo. Use Move-Restore at Your Convenience I invite everyone to try and use this handy little plugin and am open for feedback. Happy coding!
by Anton
7. November 2014 15:47
For our new time tracking web application (which not yet live) we need the functionality to create a PDF report. Since we use AngularJS to generate the HTML for the reports, I thought it would be nice to just convert that HTML via JavaScript into a PDF. The search for a solution pointed me to jsPDF – a pretty good tool for creating PDF via JavaScript. But its capabilites to convert HTML into PDF are limited (as of late 2014). We needed to convert a HTML table with all its styles into a PDF. I added jsPdfTablePlugin into the mix, but it still did not look good. So we abandonded the JavaScript way, and let the backend generate the PDF. I added an MVC view that displays the report, which is then captured via wkhtmltopdf. We already knew this process since we use it in our platform tool discoverize generating invoices. It works smoothly.
by Oliver
2. October 2014 18:30
Recently, we at teamaton decided to take a break from Camping.Info and discoverize to dive into something new. We wanted to breathe some fresh air, open our eyes and minds for a world outside of our day-to-day development stack of ASP.NET. During the process we also wanted to check out some tools, frameworks, environments that we'd heard of or read about but hadn't found the time to really take a closer look at. One of these was Meteor. What's Meteor about The elevator pitch on meteor.com reads like this: Meteor is an open-source platform for building top-quality web apps in a fraction of the time, whether you're an expert developer or just getting started. I really encourage you, dear Reader, to check out the Meteor site and take a look at what's waiting for you. I really liked what I found there: Pure JavaScript. Live page updates. Hot Code Pushes. Fully self-contained application bundles. And more. That's stuff, .NET developers aren't used to. Setting up Meteor on Windows [Note: Before proceeding, please have a look at Meteor's Supported Platforms page just to make sure you're not missing out on anything new.] This part took me about 2h to get right, so I took notes to save my colleagues or anyone else interested some precious time. I basically followed this comprehensive guide (and I encourage you to do the same) but made a few adjustments. [A word of warning: Running my first out of the box sample failed and that's where I stopped.] Install Git and add C:\Program Files (x86)\Git\bin to your PATH variable Download and install VirtualBox > 4.3.12 from here: https://www.virtualbox.org/wiki/Downloads Download and install Vagrant >= 1.6.3 from here: http://www.vagrantup.com/downloads.html Install the ChefDK from here: http://downloads.getchef.com/chef-dk/windows/ Now start a command line and run: vagrant plugin install vagrant-berkshelf --plugin-version ">= 2.0.1"
vagrant plugin install vagrant-vbguest
vagrant plugin install vagrant-omnibus
Create C:\vagrant and cd into it, then call:
git clone git://github.com/shoebappa/vagrant-meteor-windows.git meteor
Edit C:\vagrant\meteor\Vagrantfile to use a new virtual machine image (the old one wouldn't work with Meteor's current version):
In line 8, set: config.vm.box = "trusty64"
In line 10, set: config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box"
In Iine 36, use a different name for your first app
Go to C:\vagrant\meteor and initiate Vagrant (will take a while):
vagrant up
Now start your app by:
cd C:\vagrant\meteor
vagrant ssh
cd /vagrant/mymeteorapp
mrt run
Running the app threw a NullReferenceException (or something alike) at me that was triggered from somewhere inside a javascript file – I don't remember exactly where. I tried fiddling around with it for another hour or so, especially when I read that Meteorite (mrt) is no longer needed with Meteor versions >= 0.9.0. But without success.
What to do now?
I shied away from it but you might just feel like setting up a dev environment on a Linux OS and simply running the few lines from the Meteor home page:
$ curl https://install.meteor.com/ | sh
It seems to simple to be true.
But wait! Official Windows support is coming to Meteor – sometime in the near or farther future. So please check if the future isn't already here!
What we did
We went to grab Angular.js and haven't looked back.
Happy coding!
by Oliver
20. September 2014 21:47
At teamaton we're currently developing our own Time Tracking tool that we'll be using instead of KeepTempo as soon as it's good enough. We even plan on making it accessible to the public later but that's a different story. We chose Angular.js to develop the frontend and now want to synchronize our time tracking records with our ASP.NET WebAPI backend. One property of such a record is the date and time it was created at, createdUtc. Let's look at how we can send those date-time values to the server and back again. Some Background on Date and DateTime JavaScript Date instances are seeded at 01/01/1970 00:00:00 and can be instantiated by passing to the Date() constructor the number of milliseconds that have passed since that moment in time. Date.now() will directly output this number, at the moment of writing these words it returned the value 1 411 240 284 042. This value is what all other representations of a given Date instance will be based on. In .NET we have the DateTime type and its seed value is 01/01/0001 00:00:00. Internally, DateTime instances count time in Ticks, where one tick equals 100 nanoseconds, i.e. 0.000 000 1 seconds, thus delivering a theoretical precision of 10000 times that of the JavaScript equivalent. When writing these words, the current number of Ticks of DateTime.Now was 635 468 449 058 588 764 (I use LINQPad to execute C# code snippets). How to Convert JavaScript Date to .NET DateTime So how do we convert those values into each other? If we decide to send the number of milliseconds in a given JavaScript Date instance to our .NET server we can reconstruct an equivalent DateTime instance by seeding it with 01/01/1970 and just adding the milliseconds we got from the client to it: Record.CreatedUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(milliseconds); Going the other way, we actually need to get hold of a TimeSpan instance which has the property TotalMilliseconds that gives us what we want. We'll do that by substracting a DateTime instance representing the 01/01/1970 from the DateTime instance we want to send to the client: (Record.CreatedUtc - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds The code looks a bit ugly because we take care to work with UTC dates so that our code will run the same for clients and servers around the world. It's a very good idea to work with UTC dates internally and only convert them to local dates when you want to display them somewhere. … or Just Use Date Strings There's another way to transfer date objects between JavaScript and your server: using a standardized string representation that both sides will be able to generate and parse. In JavaScript you would use Date.toISOString() and in .NET DateTime.ToString("O") (see the MSDN for the O format string). Happy coding!
by Oliver
4. July 2014 21:56
In our customizable web portal platform discoverize we offer searching for results using a Google Map. In a recent iteration, we were trying to improve the overall map usage experience, and one thing we wanted to do was to zoom into the map as far as possible for all results to still appear on the map. map.fitBounds(map.getBounds()); – does not do what you would like it to The natural choice to achieve that would be to use the fitBounds method on the Map object with the bounding rectangle for the coordinates of all results. Unfortunately, though, Google chose to add a non-configurable 45px margin around that bounding box so that in a lot of cases the map appears to be zoomed out too far for what would be possible. That's why map.fitBounds(map.getBounds()); will zoom the map out! Zoom in if you can After a bit of searching I found a workaround on this Google Groups thread: map.fitBounds(map.getBounds()) zooms out map. The idea behind the solution provided there is to check whether the bounds to fit on the map wouldn't still fit using a higher zoom level and if yes, apply that zoom level. Since I had some problems with the code from the thread I reworked it slightly and now have this: function myFitBounds(myMap, bounds) {
myMap.fitBounds(bounds); // calling fitBounds() here to center the map for the bounds
var overlayHelper = new google.maps.OverlayView();
overlayHelper.draw = function () {
if (!this.ready) {
var extraZoom = getExtraZoom(this.getProjection(), bounds, myMap.getBounds());
if (extraZoom > 0) {
myMap.setZoom(myMap.getZoom() + extraZoom);
}
this.ready = true;
google.maps.event.trigger(this, 'ready');
}
};
overlayHelper.setMap(myMap);
}
function getExtraZoom(projection, expectedBounds, actualBounds) {
// in: LatLngBounds bounds -> out: height and width as a Point
function getSizeInPixels(bounds) {
var sw = projection.fromLatLngToContainerPixel(bounds.getSouthWest());
var ne = projection.fromLatLngToContainerPixel(bounds.getNorthEast());
return new google.maps.Point(Math.abs(sw.y - ne.y), Math.abs(sw.x - ne.x));
}
var expectedSize = getSizeInPixels(expectedBounds),
actualSize = getSizeInPixels(actualBounds);
if (Math.floor(expectedSize.x) == 0 || Math.floor(expectedSize.y) == 0) {
return 0;
}
var qx = actualSize.x / expectedSize.x;
var qy = actualSize.y / expectedSize.y;
var min = Math.min(qx, qy);
if (min < 1) {
return 0;
}
return Math.floor(Math.log(min) / Math.LN2 /* = log2(min) */);
}
Replace map.fitBounds(bounds) with myFitBounds(map, bounds)
That's all you have to do to zoom in as far as possible while keeping your bounds on the map.
Happy coding!
by Anton
9. October 2013 11:41
I haven’t been to a coding dojo for quite some time. Since I have deficiencies in JavaScript, this sounded like fun. The event was again held at Hotelplan CC Services, and Mike Bild was the one who showed us the ropes. He gave us an introduction to node.js, which is a packaged compilation of Google’s V8 JavaScript engine. It is quite extensible, for instance via the npm package manager (similar to nuget). There are many testing frameworks – Mike showed us and used mocha. It even has a runner, wich runs all the tests as soon as you make a change to the code (similar to ncrunch). After the explanatory part to all the tools, we started solving the KataTennis by applying TDD. It went quite well, the results can be seen here. In the end Mike told us a bit about the task runner Grunt, and the possiblity to convert node.js code with requires into browser code with browserify.