- How a page loads a query into an embedded map with
applyQuery. - How messages travel both ways:
sendfrom the page,ExtjsUtils.QUERY.postMessagefrom the map. - Where to find a complete page to start from.
A map in an <iframe> (step 9) is a separate page. MappiaIO is the small library that lets your page and the map work together. Your page loads it from the map server and connects to the iframe:
<iframe id="mappia" src="https://maps.csr.ufmg.br/calculator/?lang=eng"></iframe>
<script src="https://maps.csr.ufmg.br/mappia_io.js"></script>
<script>
var mappia = MappiaIO("mappia", true); // true: keep talking after connecting
mappia.applyQuery('[{ name: "CSR:estados", visibility: true }]');
mappia.send({ operation: "show_city", message: { name: "Belo Horizonte" } });
mappia.addOnMessageCallback(function (msg) { console.log("the map says", msg); });
</script>
applyQuery(text)loads a query into the map - any query of this tutorial, built by your page or kept in your own files. Every live example of these pages runs this way.send(object)delivers an object to the query, which receives it in the function it registered withExtjsUtils.QUERY.setMappiaIoCallback.- The query answers, or reports a click, with
ExtjsUtils.QUERY.postMessage(object); the page receives it inaddOnMessageCallback.
Here is the map side of such a conversation: a query that lists, shows and adds cities when the page asks, and tells the page which city the reader clicked. Its panel shows what the page asked last.
The query 98 lines · runs as is
// MappiaIO, the map side of an embed: the query listens to the page that embeds it
// (setMappiaIoCallback) and answers it (postMessage). Both sides have buttons: the page's buttons
// send operations (list, show, add a city) and the panel shows what the page asked; the panel's
// own button and a click on a city report to the page. The operation names are this example's
// own - the platform reserves only the ones starting with "mappia__". On its own it is an
// ordinary map; the page side is on the MappiaIO page of the documentation.
ExtjsUtils.QUERY.setQueryGlobalProperties({
citiesLayer: null, // set by onAdded below; cleared with the query like every global here
onPageMessage: function (msg) {
var layer = window.citiesLayer;
if (!msg || !msg.operation || !layer) return; // not for this query, or not loaded yet
var said = Ext.getCmp("page_said"); // the panel label: what the page asked last
if (said) said.setText("The page asked: " + msg.operation + (msg.message && msg.message.name ? " " + msg.message.name : ""));
var reply = { requestId: msg.requestId }; // echo the id so the page can match the answer
if (msg.operation === "list_cities") {
reply.operation = "cities";
reply.message = layer.features.map(function (feature) { return feature.attributes; });
} else if (msg.operation === "show_city") {
var city = layer.features.filter(function (feature) {
return feature.attributes.name === msg.message.name;
})[0];
if (city) {
layer.map.setCenter(city.geometry.getBounds().getCenterLonLat(), 7);
layer.selectController.unselectAll();
layer.selectController.select(city);
}
reply.operation = "city_shown";
reply.message = { name: msg.message.name, found: !!city };
} else if (msg.operation === "add_city") {
var point = new OpenLayers.Geometry.Point(msg.message.lon, msg.message.lat)
.transform(new OpenLayers.Projection("EPSG:4326"), layer.map.getProjectionObject());
layer.addFeatures([new OpenLayers.Feature.Vector(point, { name: msg.message.name, population: msg.message.population })]);
reply.operation = "city_added";
reply.message = { name: msg.message.name, count: layer.features.length };
} else {
reply.operation = "unknown_operation";
reply.message = { operation: msg.operation };
}
ExtjsUtils.QUERY.postMessage(reply);
},
// map -> page from a button of the panel: {{button|handler=sendViewToPage}} finds it by name
sendViewToPage: function () {
var layer = window.citiesLayer;
var view = layer.map.getExtent();
var inView = layer.features.filter(function (feature) {
return view.containsLonLat(feature.geometry.getBounds().getCenterLonLat());
});
ExtjsUtils.QUERY.postMessage({
operation: "cities_in_view",
message: { zoom: layer.map.getZoom(), cities: inView.map(function (feature) { return feature.attributes.name; }) },
});
},
}) &&
ExtjsUtils.QUERY.setMappiaIoCallback(window.onPageMessage) && [
{
title: "Cities - talking to the page",
name: "mappia_io_cities",
source: "file",
type: "json",
fromProj: "EPSG:4326",
visibility: true,
paramsButtonConfig: [{ type: "query", pressed: true }],
descriptionHtml:
"{{label|id=page_said|text=Waiting for the page to send something.}}<br>" +
"{{button|id=send_view|text=Send the cities in view to the page|handler=sendViewToPage}}",
json: {
type: "FeatureCollection",
features: [
["Sao Paulo", -46.63, -23.55, 11451999],
["Rio de Janeiro", -43.2, -22.91, 6211423],
["Brasilia", -47.88, -15.79, 2817381],
["Fortaleza", -38.54, -3.73, 2428708],
["Salvador", -38.5, -12.97, 2417678],
["Belo Horizonte", -43.94, -19.92, 2315560],
["Manaus", -60.02, -3.12, 2063689],
["Curitiba", -49.27, -25.43, 1773718],
].map(function (city) {
return {
type: "Feature",
properties: { name: city[0], population: city[3] },
geometry: { type: "Point", coordinates: [city[1], city[2]] },
};
}),
},
defaultStyle: { graphicName: "circle", pointRadius: 9, fillColor: "#277cea", fillOpacity: 0.9, strokeColor: "#ffffff", strokeWidth: 2 },
selectStyle: { pointRadius: 12, fillColor: "#e74c3c" },
onAdded: function (event) {
window.citiesLayer = (event && event.layer) || this;
},
// map -> page: tell the embedding page which city the user clicked
onClick: function (feature) {
ExtjsUtils.QUERY.postMessage({
operation: "city_clicked",
message: { name: feature.attributes.name, population: feature.attributes.population },
});
},
},
];On its own, as here, the map has no page to talk to. The MappiaIO page runs it with a page: a playground that sends it messages, a complete page you can copy, and real sites built this way - a real-estate search and a tool for offline maps.
You are done
You now know the parts every Mappia map is made of: layers and their names, sources and servers, calculations and controls, groups, the && chain and globals, the ExtjsUtils helpers, saving and sharing, and MappiaIO. From here, the tools show each widget and layer type with runnable examples, and the real maps show them together, at full scale. When you look something up, Where to find it says which part of the API reference to open.
Try this
- Open the complete page, press its buttons and click a city on its map: every message shows in its log.
- In the playground, pick MappiaIO and send
{"operation":"show_city","message":{"name":"Manaus"}}. - Copy the complete page from the MappiaIO page and open it from your computer: it works as it is.
Read more
- MappiaIO - every step, the complete page, sites that use it
- Embedding a map and talking to it - the full contract