DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • How To Use Pandas and Matplotlib To Perform EDA In Python
  • Top 10 Engineering KPIs Technical Leaders Should Know
  • Automating the Migration From JS to TS for the ZK Framework
  • Effective Java Collection Framework: Best Practices and Tips

Trending

  • How To Use Pandas and Matplotlib To Perform EDA In Python
  • Top 10 Engineering KPIs Technical Leaders Should Know
  • Automating the Migration From JS to TS for the ZK Framework
  • Effective Java Collection Framework: Best Practices and Tips
  1. DZone
  2. Data Engineering
  3. Data
  4. Using Drawing Tools and Maps to Find Data

Using Drawing Tools and Maps to Find Data

Raymond Camden user avatar by
Raymond Camden
·
Sep. 26, 13 · Interview
Like (0)
Save
Tweet
Share
8.93K Views

Join the DZone community and get the full member experience.

Join For Free

A few years back, a good buddy of mine (Ryan LeTulle) demoed a cool real estate map application he built. I asked him to blog it (because everyone has a blog, and time to blog, right?) but he never got around to it. Last week I asked him if he minded me rebuilding what I saw him do, and he said go for it. Thanks, Ryan, for the inspiration!

Have you ever tried to use a real estate site to find homes but had trouble narrowing down your search criteria? For example, you know what city you want to live in, but also what area. If you're lucky, the site lets you search by subdivision, but how in the heck do you figure that out? My subdivision is Ivanhoe, but I lived here about 10 years before I realized that.

What you would really like, I imagine, is being able to draw your search criteria. Given a map of the city and a vague notion of where you want to live, what if we could draw a region and find results within it?

This idea relies on two main aspects. First is the ability to draw on a map. I'm going to be using Google Maps for this project. Google Maps is a pretty darn deep API. It allows you to draw markers, lines, boxes, and polygons in general on a map. It also allows for deep interaction with those UI items as well.

While I researched this idea, I discovered they had a feature called "User-editable Shapes". As you can imagine, this lets a user move and adjust a shape on a map:

This is nice - but a box isn't exactly precise enough. I decided to begin with simple lines (what Google calls Polylines). I created a map and then used click events to add markers with lines connecting them. Luckily, Google had an example of this already (Polyline complex), so I began with that. I made one modification, though. I set it up so that as soon as you had clicked three times, I'd "close" the box automatically for you.

As an example:

The code is rather simple - just notice how many lines we've drawn and on the 3rd click, automatically close the box:

function initialize() {

  var mapOptions = {
		center: new google.maps.LatLng(-34.397, 150.644),
		zoom: 8,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};

	var map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);

	var polyOptions = {
		strokeColor: '#000000',
		strokeOpacity: 1.0,
		strokeWeight: 3
	}

	var markers = [];
	
	poly = new google.maps.Polyline(polyOptions);
	poly.setMap(map);
	
	google.maps.event.addListener(map, 'click', function(event) {

		var path = poly.getPath();

		path.push(event.latLng);
		
		markers.push(new google.maps.Marker({
			position: event.latLng,
			title: '#' + path.getLength(),
			map: map
		}));
		
		if(path.getLength() == 4) {
			console.log('box it');
			path.push(markers[0].getPosition());
			console.dir(markers);
		}

	});
}

google.maps.event.addDomListener(window, 'load', initialize);

This worked ... OK (and you can demo it here), but I felt bad that I was forcing you to search within a four sided polygon. What I really wanted was the ability to let you click as much as you want, and when you're done, close the 'box' automatically. As an example, I've created a multi-segmented polygon here and clicked search to complete the region:

Overall, I felt like this was a good solution. Now - right away you may be asking - what happens if you draw something crazy, like, oh say this:

Don't do that. Seriously.

OK ... so, at this point, we've covered the first main aspect of this project - giving you the ability to 'draw' a region. Now comes the second. Given that we know the region, how do we find crap inside it?

I was a bit torn about this aspect. Turns out there is a client-side solution provided by Google (no surprise), but also server side code you can use as as well. CFLib has a UDF (PointInPolygon) nearly 10 years old that would do this. So, in theory, we could hit a server database, do some logic, and return the points. Or we could do it client side. Keeping the data on the server allows for quicker initial load. Keeping it in the client lets us search a bit quicker, but makes the first load 'fatter.'

I decided to go with a client-side solution mainly because I wanted to test this particular Google API, but also because I was curious how 'bad' the hit would be if I did store a large set of data on the client. In my example, I'm only storing longitude/latitude data. I'd imagine that once you click on a result, we could do an AJAX ping to get further data. Or heck, we could do so as soon as you complete your polygon. I wrote a script (you can view source here) to generate 400 different long/lat pairs that were roughly in the Lafayette area. This script outputs a JavaScript variable I could then take and save into a file called data.json.

Now that I had my data, I could update my code to load it into memory. As to how I could filter the data, I made use of Google's Geometry library. It lets you pass a long/lat point and a polygon and it returns true if the point is within it. Here is the updated edition. You want to pay attention to the doSearch function:

function initialize() {

  var locData;
	
	var searchButton = document.querySelector("#searchButton");
	var resultsDiv = document.querySelector("#results");
	
	var mapOptions = {
		center: new google.maps.LatLng(30.223178, -92.024231),
		zoom: 12,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};

	var map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);

	var polyOptions = {
		strokeColor: '#000000',
		strokeOpacity: 1.0,
		strokeWeight: 3
	}

	var blueIcon = {
		url:"http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png"
	};
	
	var markers = [];
	
	poly = new google.maps.Polyline(polyOptions);
	poly.setMap(map);
	
	google.maps.event.addListener(map, 'click', function(event) {

		var path = poly.getPath();

		path.push(event.latLng);
		
		markers.push(new google.maps.Marker({
			position: event.latLng,
			title: '#' + path.getLength(),
			icon:blueIcon,
			map: map
		}));
		
	});
	
	searchButton.addEventListener("click", function(e) {
		var path = poly.getPath();
		if(path.getLength() < 4) {
			alert('Please select at least 4 points.');
			return;
		}
		path.push(markers[0].getPosition());
		searchButton.setAttribute("disabled","disabled");
		doSearch();
	});
	
	$.get("data.json", {}, function(res) {
		locData=res;
		searchButton.innerText = "Search";
		searchButton.removeAttribute("disabled");;
	});
	
	function doSearch() {
		results.innerHTML = "<i>Searching for matches...</i>";
		var totalFound = 0;
		for(var i=0; i<locData.length; i++) {
			//I should probably cache this creation!
			var point = new google.maps.LatLng(locData[i][0],locData[i][1]);
			if(google.maps.geometry.poly.containsLocation(point,poly)) {
				var m = new google.maps.Marker({
					position: point,
					title: 'Location '+i,
					map: map
				});
				totalFound++;
			} 
		}
		results.innerHTML = "Found " + totalFound + " results.";		
	}
	
}

google.maps.event.addDomListener(window, 'load', initialize);

As you can see, I loop over the data and pass it to the Geometry API. If a match is found, I add a marker. When done, I report on the total matches. You can demo this by hitting the giant demo button below. Note that hitting Search twice will destroy the universe. Don't hit search twice.

Demo

P.S. I actually tested "crossing the streams" and it worked perfectly. I knew it would. Honest.


Data (computing)

Published at DZone with permission of Raymond Camden, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • How To Use Pandas and Matplotlib To Perform EDA In Python
  • Top 10 Engineering KPIs Technical Leaders Should Know
  • Automating the Migration From JS to TS for the ZK Framework
  • Effective Java Collection Framework: Best Practices and Tips

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: