I was recently asked if a JavaScript Metawidget could be used to display a map when given a location.
Metawidget is designed around a 5 stage pluggable pipeline. To incorporate a map widget, the best plugin point is a WidgetBuilder.
WidgetBuilders are passed all metadata for a given property, and try to return the most suitable widget. Or they can return nothing, and let another WidgetBuilder further down the chain have a try. In our case, we could inspect the property name (say, zip) and return either a map widget or nothing (in which case the standard HtmlWidgetBuilder can have a try).
Here's a complete example:
<head>
<script src="http://metawidget.org/js/3.7/metawidget-core.min.js"></script>
<style>
#metawidget {
border: 1px solid #cccccc;
width: 385px;
border-radius: 10px;
padding: 10px;
margin: 50px auto;
}
</style>
</head>
<body>
<div id="metawidget"></div>
<script type="text/javascript">
var config = {
widgetBuilder: new metawidget.widgetbuilder.CompositeWidgetBuilder([
function(elementName, attributes, mw) {
// If metadata indicates this property needs a map...
if (attributes.name === 'zip') {
// ...read the value...
var typeAndNames = metawidget.util.splitPath(mw.path);
var toInspect = metawidget.util.traversePath(mw.toInspect, typeAndNames.names);
var value = toInspect[attributes.name];
// ...and build a map widget
var img = document.createElement('img');
img.setAttribute('src', 'http://maps.googleapis.com/maps/api/staticmap?center=' + value + '&size=300x300&sensor=false');
return img;
}
},
new metawidget.widgetbuilder.HtmlWidgetBuilder()
])
}
var mw = new metawidget.Metawidget(document.getElementById('metawidget'), config);
mw.toInspect = {
firstname: 'Homer',
surname: 'Simpson',
zip: 90212
};
mw.buildWidgets();
</script>
</body>
</html>
This will display:
Of course in a real-world scenario inspecting a property's name may not be a good approach. Better to have some orthogonal metadata that determines whether to return a map widget. Metawidget supports many ways to supply such orthogonal metadata. Here's an example using JSON Schema:
<head>
<script src="http://metawidget.org/js/3.7/metawidget-core.min.js"></script>
<style>
#metawidget {
border: 1px solid #cccccc;
width: 385px;
border-radius: 10px;
padding: 10px;
margin: 50px auto;
}
</style>
</head>
<body>
<div id="metawidget"></div>
<script type="text/javascript">
var config = {
inspector: new metawidget.inspector.CompositeInspector( [
new metawidget.inspector.PropertyTypeInspector(),
function() {
return { properties: { zip: { type: 'location' } } }
}
] ),
widgetBuilder: new metawidget.widgetbuilder.CompositeWidgetBuilder([
function(elementName, attributes, mw) {
// If metadata indicates this property needs a map...
if (attributes.type === 'location') {
// ...read the value...
var typeAndNames = metawidget.util.splitPath(mw.path);
var toInspect = metawidget.util.traversePath(mw.toInspect, typeAndNames.names);
var value = toInspect[attributes.name];
// ...and build a map widget
var img = document.createElement('img');
img.setAttribute('src', 'http://maps.googleapis.com/maps/api/staticmap?center=' + value + '&size=300x300&sensor=false');
return img;
}
},
new metawidget.widgetbuilder.HtmlWidgetBuilder()
])
}
var mw = new metawidget.Metawidget(document.getElementById('metawidget'), config);
mw.toInspect = {
firstname: 'Homer',
surname: 'Simpson',
zip: 90212
};
mw.buildWidgets();
</script>
</body>
</html>
Hope that helps. Feedback welcome!