/* In this example, we will build a list of cities that interacts with a map. */ 'use strict'; /* We load the `UI` and `Geo` modules. The latter provides a number of methods to retrieve geographic and political information about countries. */ Ox.load({UI: {showScreen: true}, Geo: {}}, function() { /* We load the list of cities. */ Ox.getJSON('json/cities.json', function(cities) { /* The JSON data originally comes from geonames.org. It's an array of 10,000 city objects, each of which has the following properties:
{
"country_code": "CN",
"elevation": 0,
"feature_code": "PPLA",
"latitude": 31.22222,
"longitude": 121.45806,
"name": "Shanghai",
"population": 14608512
}
*/
cities = cities.map(function(data, id) {
/*
First of all, we have to patch this data, so that it becomes more
useful both for the list and the map. Ox.getCountryByCode gives us
the names of the country, region and continent. For the map, we need
a geoname, and the cities have to be rectangular areas, not just
points. So we set the area to 100 square meters per inhabitant,
which will turn out to be relatively realistic. Then we calculate
how large the resulting square will be, in degrees. (The number of
degrees from west to east depends on the city's proximity to the
equator. OxJS has some utility functions built in that make this
easy to compute.) Finally, we can set the values for south, north,
west and east. A nice side effect of deriving the size of the city
from its population is that the map, which will always show the
largest places in the visible area, will now show the most populated
cities.
*/
var area = Math.max(data.population, 1) * 100,
country = Ox.getCountryByCode(data.country_code),
latSize = Math.sqrt(area) / Ox.EARTH_CIRCUMFERENCE * 360,
lngSize = Math.sqrt(area) * Ox.getDegreesPerMeter(data.latitude);
/*
Our city object will look like this:
{
"area": 1460851200,
"capital": false,
"country": "China",
"east": 121.65880869475835,
"elevation": 0,
"geoname": "Shanghai, China",
"id": "0",
"lat": 31.22222,
"lng": 121.45806,
"name": "Shanghai",
"north": 31.393892916013158,
"population": 14608512,
"region": "Asia, Eastern Asia, China",
"south": 31.050547083986842,
"west": 121.25731130524166
}
Obviously, in a real-world scenario, you would make sure that the
data already comes in this form.
*/
return {
area: area,
capital: data.feature_code == 'PPLC',
country: country.name,
east: data.longitude + lngSize / 2,
elevation: data.elevation,
geoname: [data.name, country.name].join(', '),
id: id.toString(),
lat: data.latitude,
lng: data.longitude,
name: data.name,
north: data.latitude + latSize / 2,
population: data.population,
region: [country.continent, country.region, country.name].join(', '),
south: data.latitude - latSize / 2,
west: data.longitude - lngSize / 2
};
});
/*
The preview button opens or closes the preview dialog (which we will
create later). It does so by calling the `openPreview` or `closePreview`
method of the list (which we will also create in a moment).
*/
var $preview = Ox.Button({
disabled: true,
selectable: true,
title: 'view',
type: 'image'
})
.bindEvent({
change: function(data) {
$list[(data.value ? 'open' : 'close') + 'Preview']();
}
}),
/*
As we want the list to be searchable, we add an input element.
*/
$find = Ox.Input({
clear: true,
placeholder: 'Find',
width: 192
})
.bindEvent({
submit: function(data) {
$list.options({
/*
This query will find matches in either `name`,
`region` or `continent`.
*/
query: {
conditions: data.value ? [
{
key: 'name',
operator: '=',
value: data.value
},
{
key: 'region',
operator: '=',
value: data.value
},
{
key: 'continent',
operator: '=',
value: data.value
}
] : [],
operator: '|'
}
});
}
}),
/*
The toolbar holds the preview button and the find element.
*/
$toolbar = Ox.Bar({size: 24})
.attr({id: 'toolbar'})
.append($preview)
.append($find),
/*
This is our list.
*/
$list = Ox.TableList({
/*
First of all, we define the columns.
*/
columns: [
{
/*
We don't want to display the id, so we omit the
`visible` attribute, which defaults to `false`. We
still have to include the id in the list of columns,
since it's the unique key of our table. In
consequence, whenever the list fires a `select`
event, it will reference this value as the item's
id.
*/
id: 'id',
operator: '+',
title: 'ID',
unique: true,
width: 80
},
{
/*
We use the `format` function to display the region
as a colored icon with a tooltip. The region class
is added to apply our own custom CSS, and
Ox.getGeoColor returns a color for the region. Note
that the actual value is 'Continent, Region,
Country', which results in a nicer sort order than
just 'Region'.
*/
format: function(value) {
var region = value.split(', ')[1];
return Ox.Element({
tooltip: region
})
.addClass('region')
.css({
background: 'rgb('
+ Ox.getGeoColor(region).join(', ')
+ ')'
});
},
id: 'region',
/*
The operator indicates that we want the default sort
order for this column to be ascending.
*/
operator: '+',
/*
We want the column title to be a symbol, so we pass
the 'icon' symbol as the `titleImage`. We can pick
anything from the collection of symbols that comes
with Ox.UI. The column still needs a textual title,
to be displayed in the menu that allows to show or
hide specific columns.
*/
title: 'Region',
titleImage: 'icon',
/**/
visible: true,
width: 16
},
{
/*
Ox.getFlagByGeoname and Ox.getFlagByCountryCode
return pretty flag icons.
*/
format: function(value) {
return Ox.Element({
element: '