In this article I demonstrate how you can use image maps with web viewers in FileMaker. In doing so, you can display images that, when clicked, can report the coordinate chosen back to FileMaker to handle in whichever manner you wish…
What are Image Maps?
Wikipedia says that an image map is a list of coordinates relating to a specific image, created in order to hyperlink areas of the image to various destinations. The intention of an image map is to provide an easy way of linking various parts of an image without dividing the image into separate image files.
Can we use them in FileMaker?
Wouldn't it be great if we could use an image map in FileMaker. This would allow us to display an image, and have FileMaker know the exact location on that image the user clicked. In knowing this information, you could then program a response, perhaps via a script.
Lets establish an example
Below is a photograph of a farm, with the paddocks on that farm outlined. We have a database that is used to manage the farm and the paddocks on it. Each Paddock is a record in the database.
Wait, so why not just use buttons?
Well, we could (but c'mon where is the fun in that!). A common method of making a clickable image in FileMaker would be to place the image direct on the layout, or in a container, and underly buttons beneath the image that when clicked, run a script.
Here's the problem - paddocks are not necessarily rectangular, circular, or oval shaped. As such, to underly buttons beneath a paddock, you must use a combination of many buttons or shapes to replicate the paddocks shape, then group those objects and turn them into one large button.
Furthermore to this issue, what happens if in future the paddock fence-line changes? What happens if two paddocks become one? What happens if more paddocks are added? Basically it all boils down to the fact that the layout is going to have to be changed - not a very nice soft-coded solution.
So why is an Image Map Different?
If the image of the farm were presented as an image map, then there would be some feedback as to the location on the image that was clicked. We could then leave it up to FileMaker to determine what to do with that coordinate such as find out the paddock chosen, and run an appropriate script. In doing so, there would be no need for hard-coding of buttons required.
Lets do it then!
Okay enough talk, lets get into the nitty gritty.
Here is some very basic html code to establish an image map. We have specified an image called "Map.png". It is given width and height dimensions in pixels. The image is established as an image map via the use of the "ismap" attribute. the html file is called Map.html.
Pretty simple, around 6 lines of code. Image maps are widely varied and can include more fanciful features, but for this example we are sticking to the basics. In the example file we offer a slight variation on the above but basically its the same code.
Using the Web Viewer
Web Viewers are the tool in FileMaker that allow you to display web content on a layout. Given image maps are used on the web, it only makes sense that we will be using the web viewer. Basically we require to display the above html file in the web viewer, this can be achieved in a few ways.
The first is via a web server. If we host Map.html and Map.png on a web server then we simply need to point the web viewer to that URL and the image map will be displayed. Of course, this method requires the database have access to the web server location, either via local network or over the internet. In the demo file, we give an example of this method.
The second option for those not averse to using a plugin, is to use Reactor plugin, or any other plugin capable of hosting up web content. The reactor plugin is perfect for this because it is exactly what it was designed to do.
For those not familiar with the Reactor plugin, what it does is emulate a web server within a plugin. You can pass any file to the plugin using ReactorFeed function, and it will in return give you a URL which you can then place in the web viewer to display that content.
We normally use ReactorFeed for things such as displaying PDF documents or images within a web viewer, and it does a great job. In this situation we are going to pass it Map.html and Map.png, and it in turn gives us a URL to use in our web viewer.
We have included a reactor example in the demo file for those readers who have Reactor installed. If you do not have Reactor, you can download a demo copy Here.
An attempt at a third method
The above methods outlined require either a plugin or access to a web server hosting the content. Both methods work great, but in developing this technique we aimed to provide an all-encompassing self contained solution. Unfortunately we failed (someone take up the challenge!) but I thought I would mention that method here.
We attempted to base-64 encode both Map.html and Map.png and serve it up in the web viewer by using a data url. While we were able to display the map in the web viewer, we were unable to obtain the selected clicked coordinate via this method, more on what I'm talking about later...
The "isMap" image map and how it works
We are using the isMap attribute to setup an image map on the image. How this works is when the user clicks on a location on the image, the chosen coordinate in pixels is appended to the end of the URL of the page.
When we defined the image map code, you'll notice we gave it a width and height in pixels. This defines the area of the image. The top-left corner of the image is given the x,y coordinate of 0,0, and from there the coordinates extend out to all four corners of the image.
When the user clicks on a point on the image, the x,y coordinate is placed on the end of the link.
For example if the URL to the image map page is:
and the user clicks at coordinate 100,200 then the resulting URL of the page becomes
Grabbing this Coordinate in FileMaker
It all boils down to the GetLayoutObjectAttribute function. This FileMaker function allows you to obtain the source url of a web viewer. Thus if we are able to obtain the source URL of the web viewer after the user has clicked in it, then it will tell us the URL with the coordinate appended! Brilliant!
GetLayoutObjectAttribute ( "WebViewer" ; "Source" )
How can we tell the user has clicked?
Web viewers generally offer up content that the user interacts with independently of FileMaker. What we need is a way for FileMaker to know the user has just clicked on a position in the image map.
We can achieve this now using script triggers that were introduced in FileMaker 10. Specifically, the onObjectEnter script trigger can fire off a script to run when the user enters an object - including a web viewer. This is how we are going to go about obtaining the source URL of the web viewer after the user enters the web viewer.
It's all a matter of timing…
Now, if we were to run a script triggered by onObjectEnter as soon as the user clicks into the web viewer, the problem is that the script runs before the users interaction with the web viewer occurs. So if we run a script that tries to evaluate the source of the web viewer, it's just going to tell us the original URL because the users click on the image map has not yet been registered. What we need to do instead is delay our script from evaluating the source URL of the web viewer - finally a great use for the onTimer script step!
Setting up the onTimer delay
As you can see in the image above, we set an onTimer to run .25 seconds after the triggered script is run. The delay you specify depends upon various factors, mostly related to the speed of the web server hosting the image map, or your internet connection (Rector being local tends to be faster). We find that a quarter of a second is ample time for the URL to update, and short enough to not be noticeable by the user.
The process of events that occurs from the moment the user clicks into the web viewer is:
- User Clicks into web viewer
- onObjectEnter triggers a script
- The script installs an onTimer for a main script to run
- The users click now happens, and the web viewers URL is updated
- Now the delayed script runs, and is able to reference the web viewers new updated URL
- The script will run a commit record step to put the user back out of the web viewer, ready for the next click
And there you have it!
So that's basically it. You have an image with a width and height in pixels, and by using script triggers, onTimers, and various FM functions you can obtain the x,y coordinate clicked. From there, you can parse out the coordinates from the end of the web viewers URL, and do with them whatever you want, great.... but is that the end?
Well not really. Once you have the coordinates the question now becomes what do you do with them? Being able to obtain the coordinates is nice, but unless you can do something meaningful with them, whats the point.
Lets go back to the example…
So lets now return to the example originally established, and see if we can figure out a nice way to select paddocks using this technique.
Recall that each paddock is a record in the database, and we know the x,y coordinate clicked, but we don't yet know which paddock the user clicked in. What we now need to do is establish a method of defining paddocks in terms of their coordinates on the image map, and then evaluating the chosen coordinate to determine if it falls within one of the paddock boundaries.
Defining a Paddock by its boundary coordinates
Paddocks are shapes, and shapes are called polygons. A polygon is simply a shape with many sides (according to the weetbicks big book of mathematics).
Where two edges meet, you get a corner, and a corner is defined by an x,y coordinate. We can define a polygon by a series of x,y coordinates, obtained by traversing the polygon in a clockwise (or anti-clockwise) fashion, and grabbing the coordinates of the corners.
Lets assume for example we have a paddock defined by:
This defines the paddock as a perfect square, 20x20 in size on the image map. The paddock begins in the upper left corner at 0,0. From there, the upper right edge of the paddock is at 20,0. the lower right corner at 20,20, and the lower left corner at 20,0.
We can define paddocks in this fashion regardless of their shape or location simply by plotting the corners of that paddock in order. In the example file, these are recorded on the paddock records in return-delimited lists of both the X and Y coordinates respectively.
Determining if a coordinate is within a polygon
So now we have a paddock defined as a series of x,y coordinates. What we now need to determine is whether a given x,y coordinate lies within the boundaries of that polygon.
For more information about this technique, you can check out this great site that explains how the process works, and gives a C function of how to achieve it. Also please check out the acknowledgements at the bottom of this article for those who helped me take this C function and turn it into a FileMaker custom function.
In the example file you will find this function which can tell you if a given coordinate is inside or outside of a polygon. the pointinPolygon function treats coordinates that fall on the edge of a polygon as outside. There is also an alternative function provided that treats boundary coordinates as inside the polygon. The functions have been provided by Nick Orr and Jason DeLooze respectively.
Let the Paddocks Decide
With the function now in place, we can let each paddock determine if they were selected by adding a calculation field to each record, that calls the custom function, testing its own coordinates against that of the selected coordinate.
Each paddock now has basically a flag set that determines if it was chosen or not. What you do with that information is up to you. In the example file, I am grabbing the ID of the chosen paddock, and using it in a relationship to that record for editing purposes, but the possibilities for this application are huge.
Further Applications or Improvements
Hopefully this article has proved enlightening and helpful for people. This is very much a work in progress and one of the goals of this article is to get peoples minds thinking about how this technique can be used and applied to FileMaker solutions, and also how it can be refined and improved upon, I would love to see peoples examples of how they can take this technique and run with it. Possible applications or improvements might include:
- iPad applications (in fact this was the reason for its development in the first place)
- Improved image mapping techniques, highlight entire polygon chosen
- Figuring out how to make this scaleable - allowing you to resize web viewer & image and have the record coordinates gracefully scale (right now this is a fixed image size and paddock coordinates are also fixed to this scale)
- Using it for navigation
- Writing a script that lets you click on the image map to create your "paddock" records easily
- Generating an image based upon polygon coordinates in records (could then be served up with Reactor)
- Figuring out how to make an "all-in-one" solution without the need for a web server or plugins, perhaps you can crack the base-64 encoding solution...
Please find attached an example file. This file was used for all the screenshots in this article, and is provided to help you fully understand what is going on in this article, and to let you experiment in FileMaker with this solution.
Note: Example file updated on 4/5/11 to fix an issue in alternate ptInPoly function.