/*
* SOFTWARE NAME: Thematic Mapping Engine
* SOFTWARE RELEASE: 1.6
* COPYRIGHT NOTICE: Copyright (C) 2008 Bjorn Sandvik,
* bjorn@thematicmapping.org
* SOFTWARE LICENSE: GNU General Public License version 3 (GPLv3)
* NOTICE: >
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 3 of the GNU General
* Public License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* http://www.gnu.org/licenses/
*
*/
// Load Google Earth API
google.load("earth", "1");
// Define namespaces for Thematic Mapping Engine (TME)
// Encapsulate all variables and methods in one global object
Ext.namespace('TME');
// Variables for Google Earth API
TME.google = {
earth: null, // Google Earth instance
baseURL: 'http://localhost/thematicmapping/tme/', // Local URL
networkLink: null // Link to KMZ file
}
// Various data stores used by form fields
TME.data = {
// Indicator store (loaded from server)
indicators: new Ext.data.JsonStore({
url: 'TME_FormHandler.php',
baseParams: {task: 'indicators'},
root: 'indicators',
fields: ['id', 'name', 'description', 'source'],
autoLoad: true
}),
// Year store (loaded from server when indicator is selected)
years: new Ext.data.JsonStore({
url: 'TME_FormHandler.php',
baseParams: {task:'indYears'},
root: 'years',
fields: ['year']
}),
// Proportional symbol: Images
images: [
['circle', 'Circle'],
['square', 'Square']
],
// Proportional symbol: Regular polygons
polygons: [
['circle', 'Circle'],
['square', 'Square']
],
// Proportional symbol: 3d objects
colladas: [
['dome', 'Dome'],
['sphere', 'Sphere'],
['cube', 'Cube']
],
shapeStore: new Ext.data.SimpleStore({
fields: ['id', 'name'],
data: []
})
}
// All form fields
TME.field = {
// Thematic mapping technique: Prism Radio
prism: {
xtype: 'radio',
boxLabel: 'Prism',
hideLabel: true,
name: 'mapType',
inputValue: 'prism',
checked: false,
listeners: {focus:{fn:function(field) {
TME.field.hideField(TME.field.barSize);
TME.field.symbolShape.allowBlank = true;
TME.fieldset.symbolStyle.hide();
TME.fieldset.prismStyle.show();
TME.field.showField(TME.field.colourScale);
TME.field.showField(TME.field.singleColour);
}}}
},
choropleth: {
xtype: 'radio',
boxLabel: 'Choropleth',
hideLabel: true,
name: 'mapType',
inputValue: 'choropleth',
checked: true,
listeners: {focus:{fn:function(field) {
TME.field.symbolShape.allowBlank = true;
TME.fieldset.symbolStyle.hide();
TME.fieldset.prismStyle.hide();
TME.field.colourScale.setValue(true);
TME.field.hideField(TME.field.colourScale);
TME.field.hideField(TME.field.singleColour);
TME.field.hideField(TME.field.colour);
TME.field.showField(TME.field.startColour);
TME.field.showField(TME.field.endColour);
TME.field.showLegend.enable();
}}}
},
bar: new Ext.form.Radio({
xtype: 'radio',
boxLabel: 'Bar',
hideLabel: true,
name: 'mapType',
inputValue: 'bar',
checked: false,
listeners: {focus:{fn:function(field) {
TME.field.showField(TME.field.barSize);
TME.field.symbolShape.allowBlank = true;
TME.fieldset.symbolStyle.hide();
TME.fieldset.prismStyle.show();
TME.field.showField(TME.field.colourScale);
TME.field.showField(TME.field.singleColour);
}}}
}),
// Thematic mapping technique: Proportional symbol Radio
symbol: new Ext.form.Radio({
boxLabel: 'Proportional symbol',
hideLabel: true,
name: 'mapType',
inputValue: 'symbol',
checked: false,
listeners: {focus:{fn:function(field) {
TME.fieldset.prismStyle.hide();
TME.fieldset.symbolStyle.show();
TME.field.symbolShape.allowBlank = false;
TME.field.showField(TME.field.colourScale);
TME.field.showField(TME.field.singleColour);
}}}
}),
// Indicator ComboBox
indicator: {
xtype: 'combo',
fieldLabel: 'Indicator',
hiddenName: 'indicator',
store: TME.data.indicators,
valueField: 'id',
displayField: 'name',
editable: true,
forceSelection: true,
mode: 'local',
triggerAction: 'all',
anchor:'94%',
allowBlank: false,
emptyText: 'Select an indicator...',
listeners: {select:{fn:function(combo, record, index) {
// Set default title, description and source
TME.field.mapTitle.setValue(record.data.name);
TME.field.mapTitle.setDisabled(false);
TME.field.mapDescription.setValue(record.data.description);
TME.field.mapDescription.setDisabled(false);
TME.field.mapSource.setValue('Statistics from ' + record.data.source);
TME.field.mapSource.setDisabled(false);
// Load available years
TME.field.year.setValue('');
TME.field.year.setDisabled(false);
TME.field.year.store.reload({
params: { id: combo.getValue() }
});
// Buttons are disables before year is selected
TME.button.submit.disable();
TME.button.preview.disable();
}}}
},
// Year ComboBox
year: new Ext.form.ComboBox({
fieldLabel: 'Year',
hiddenName: 'year',
store: TME.data.years,
valueField: 'year',
displayField: 'year',
editable: true,
forceSelection: true,
mode: 'local',
triggerAction: 'all',
anchor: '55%',
allowBlank: false,
emptyText: 'Select year...',
disabled: true,
listeners: {select:{fn:function(combo, value) {
TME.button.submit.enable();
TME.button.preview.enable();
}}}
}),
// Proportional symbol: Image
imageSymbol: {
xtype: 'radio',
boxLabel: 'Image',
hideLabel: true,
checked: true,
name: 'symbolType',
inputValue: 'image',
listeners: {focus:{fn:function(field) {
TME.field.symbolShape.reset();
TME.data.shapeStore.removeAll();
TME.data.shapeStore.loadData( TME.data.images );
}}}
},
// Proportional symbol: Regular polygon
polygonSymbol: {
xtype: 'radio',
boxLabel: 'Regular polygon',
hideLabel: true,
checked: false,
name: 'symbolType',
inputValue: 'polygon',
listeners: {focus:{fn:function(field) {
TME.field.symbolShape.reset();
TME.data.shapeStore.removeAll();
TME.data.shapeStore.loadData( TME.data.polygons );
}}}
},
// Proportional symbol: 3D object
colladaSymbol: {
xtype: 'radio',
boxLabel: 'Collada (3d)',
hideLabel: true,
checked: false,
name: 'symbolType',
inputValue: 'collada',
listeners: {focus:{fn:function(field) {
TME.field.symbolShape.reset();
TME.data.shapeStore.removeAll();
TME.data.shapeStore.loadData( TME.data.colladas );
}}}
},
// Proportional symbol: shape
symbolShape: new Ext.form.ComboBox({
fieldLabel: 'Shape',
hiddenName: 'symbolShape',
store: TME.data.shapeStore,
valueField: 'id',
displayField: 'name',
emptyText: 'Select shape...',
editable: false,
forceSelection: true,
mode: 'local',
triggerAction: 'all',
anchor:'94%'
}),
barSize: new Ext.form.NumberField({
xtype: 'numberfield',
fieldLabel: 'Bar radius',
name: 'barSize',
value: 50000,
width: 77,
allowDecimals: false,
allowNegative: false,
allowBlank: false
}),
// Max sixe NumberField
size: new Ext.form.NumberField({
xtype: 'numberfield',
fieldLabel: 'Max size',
name: 'symbolMaxSize',
value: '5',
width: 30,
allowDecimals: false,
allowNegative: false,
allowBlank: false
}),
// Max height NumberField
maxHeight: new Ext.form.NumberField({
fieldLabel: 'Max height',
name: 'maxHeight',
value: '2000000',
width: 80,
allowDecimals: false,
allowNegative: false,
allowBlank: false
}),
// Map title TextFiled
mapTitle: new Ext.form.TextField({
fieldLabel: 'Title',
name: 'title',
allowBlank: false
}),
// Map description TextField
mapDescription: new Ext.form.TextArea({
fieldLabel: 'Description',
name: 'description'
}),
// Map source TextField
mapSource: new Ext.form.TextField({
fieldLabel: 'Source',
name: 'source',
allowBlank: false
}),
colourScale: new Ext.form.Radio({
boxLabel: 'Colour scale',
hideLabel: true,
name: 'colourType',
inputValue: 'scale',
checked: true,
listeners: {focus:{fn:function(field) {
TME.field.hideField(TME.field.colour);
TME.field.showField(TME.field.startColour);
TME.field.showField(TME.field.endColour);
TME.field.showLegend.enable();
TME.classification.show();
}}}
}),
singleColour: new Ext.form.Radio({
boxLabel: 'Single colour',
hideLabel: true,
name: 'colourType',
inputValue: 'single',
checked: false,
listeners: {focus:{fn:function(field) {
TME.field.showField(TME.field.colour);
TME.field.hideField(TME.field.startColour);
TME.field.hideField(TME.field.endColour);
TME.field.showLegend.disable();
TME.classification.hide();
}}}
}),
// Colour ColorField (extension)
colour: new Ext.form.ColorField({
fieldLabel: 'Colour',
name: 'colour',
defaultColor: 'FF6600',
width: 80,
showHexValue: false
}),
// Start colour ColorField (extension)
startColour: new Ext.form.ColorField({
fieldLabel: 'Start colour',
name: 'startColour',
defaultColor: 'FFFF99',
anchor:'90%',
showHexValue: false
}),
// End colour ColorField (extension)
endColour: new Ext.form.ColorField({
fieldLabel: 'End colour',
name: 'endColour',
defaultColor: 'FF6600',
anchor:'90%',
showHexValue: false
}),
// No data colour ColorField (extension)
noDataColour: new Ext.form.ColorField({
fieldLabel: 'No value',
name: 'noDataColour',
defaultColor: 'C0C0C0',
anchor:'90%',
showHexValue: false
}),
// Classification: Unclassed
unclassed: new Ext.form.Radio({
boxLabel: 'Unclassed',
hideLabel: true,
name: 'classification',
inputValue: 'unclassed',
checked: true,
listeners: {focus:{fn:function(field) {
TME.field.hideField(TME.field.numClasses);
}}}
}),
// Classification: Equal interval
equalInterval: new Ext.form.Radio({
boxLabel: 'Equal intervals',
hideLabel: true,
name: 'classification',
inputValue: 'equal',
checked: false,
listeners: {focus:{fn:function(field) {
TME.field.showField(TME.field.numClasses);
}}}
}),
// Classification: Quantiles
quantile: new Ext.form.Radio({
boxLabel: 'Quantiles',
hideLabel: true,
name: 'classification',
inputValue: 'quantile',
checked: false,
listeners: {focus:{fn:function(field) {
TME.field.showField(TME.field.numClasses);
}}}
}),
// Number of classes
numClasses: new Ext.form.NumberField({
fieldLabel: 'Classes',
name: 'numClasses',
value: 5,
maxValue: 9,
minValue: 2,
width: 22,
allowDecimals: false,
allowBlank: false
}),
// Time: One year
singleYear: {
xtype: 'radio',
boxLabel: 'Single year',
hideLabel: true,
name: 'timeType',
inputValue: 'year',
checked: true,
listeners: {focus:{fn:function(field) {
TME.field.quantile.enable();
if (TME.field.year.value) {
TME.button.preview.enable();
}
}}}
},
// Time: Time series
timeSeries: {
xtype: 'radio',
boxLabel: 'Time series',
hideLabel: true,
name: 'timeType',
inputValue: 'series',
checked: false,
listeners: {focus:{fn:function(field) {
if (TME.field.quantile.getValue()) { // Not valid for time series
TME.field.equalInterval.setValue(true);
}
TME.field.quantile.disable();
TME.button.preview.disable();
}}}
},
// Time: Time slider
timeSlider: {
xtype: 'radio',
boxLabel: 'Time slider',
hideLabel: true,
name: 'timeType',
inputValue: 'slider',
checked: false,
listeners: {focus:{fn:function(field) {
if (TME.field.quantile.getValue()) { // Not valid for time series
TME.field.equalInterval.setValue(true);
}
TME.field.quantile.disable();
TME.button.preview.disable();
}}}
},
// Show title
showTitle: new Ext.form.Checkbox({
boxLabel: 'Show title & source',
hideLabel: true,
checked: true,
name: 'showTitle'
}),
// Show legend
showLegend: new Ext.form.Checkbox({
boxLabel: 'Show colour legend',
hideLabel: true,
checked: true,
name: 'showLegend'
}),
// Show values
showValues: new Ext.form.Checkbox({
boxLabel: 'Show values',
hideLabel: true,
name: 'showValues'
}),
// Show names
showNames: new Ext.form.Checkbox({
boxLabel: 'Show names',
hideLabel: true,
name: 'showNames'
}),
// Max height NumberField
opacity: new Ext.form.NumberField({
fieldLabel: 'Opacity',
name: 'opacity',
value: 90,
maxValue: 100,
width: 80,
allowDecimals: false,
allowNegative: false,
allowBlank: false
}),
// METHODS
// Hide form field
hideField: function(field){
field.hide();
field.getEl().up('.x-form-item').setDisplayed(false); // hide label
},
// Show form field
showField: function(field){
field.show();
field.getEl().up('.x-form-item').setDisplayed(true);// show label
}
}
// Classification FieldSet
TME.classification = new Ext.form.FieldSet({
title: 'Classification',
collapsible: false,
autoHeight: true,
labelWidth: 65,
style: 'margin-top: 10px',
items: [{
layout: 'column',
defaults: {layout: 'form'},
items:[
{items: [TME.field.unclassed, TME.field.numClasses], columnWidth: .32},
{items: [TME.field.equalInterval], columnWidth: .4},
{items: [TME.field.quantile], columnWidth: .28}
]
}]
});
// Grouping fields in fieldsets
TME.fieldset = {
// Symbol fieldset (column)
technique: new Ext.form.FieldSet({
title: 'Technique',
collapsible: false,
autoHeight: true,
labelWidth: 65,
items: [{
layout: 'column',
defaults: {layout: 'form'},
items:[
{items: [TME.field.choropleth], columnWidth: .27},
{items: [TME.field.prism], columnWidth: .19},
{items: [TME.field.bar], columnWidth: .17},
{items: [TME.field.symbol], columnWidth: .37}
]
}]
}),
// Statistics FieldSet (title, description source)
statistics: new Ext.form.FieldSet({
title: 'Statistics',
collapsible: false,
autoHeight: true,
items: [
TME.field.indicator,
TME.field.year
]
}),
// Description FieldSet (title, description source)
description: new Ext.form.FieldSet({
title: 'Map description',
collapsible: true,
autoHeight: true,
collapsed: true,
defaults: {anchor: '94%', disabled: true},
items: [
TME.field.mapTitle,
TME.field.mapDescription,
TME.field.mapSource
]
}),
// Prism style FieldSet
prismStyle: new Ext.form.FieldSet({
title: 'Prism / bar style',
collapsible: true,
autoHeight: true,
items: [
{
layout:'column',
items:[{
columnWidth:.5,
layout: 'form',
items: [
TME.field.maxHeight
]
},{
columnWidth:.5,
layout: 'form',
items: [
TME.field.barSize
]
}]
}]
}),
// Symbol style FieldSet
symbolStyle: new Ext.form.FieldSet({
title: 'Symbol style',
collapsible: true,
autoHeight: true,
items: [
{
layout: 'column',
style: 'padding-bottom: 10px',
defaults: {layout: 'form'},
items:[
{items: [TME.field.imageSymbol], columnWidth: .3},
{items: [TME.field.polygonSymbol], columnWidth: .4},
{items: [TME.field.colladaSymbol], columnWidth: .3}
]
},
TME.field.symbolShape,
{
layout: 'column',
defaults: {layout: 'form'},
items:[
{items: [TME.field.size], columnWidth: .5}
]
}
]
}),
// Colour FieldSet
colours: new Ext.form.FieldSet({
title: 'Colours',
collapsible: true,
autoHeight: true,
style: 'padding-bottom: 0px',
items: [{
layout: 'column',
style: 'padding-bottom: 10px',
defaults: {layout: 'form'},
items:[
{items: [TME.field.colourScale], columnWidth: .5},
{items: [TME.field.singleColour], columnWidth: .5}
]
},
{
layout:'column',
items:[{
columnWidth:.5,
layout: 'form',
items: [
TME.field.colour,
TME.field.startColour,
TME.field.endColour
]
},{
columnWidth:.5,
layout: 'form',
items: [
TME.field.noDataColour,
TME.field.opacity
]
}
]
}, TME.classification
]
}),
// Time FieldSet
time: new Ext.form.FieldSet({
title: 'Time',
collapsible: true,
autoHeight: true,
labelWidth: 65,
items: [{
layout: 'column',
defaults: {layout: 'form'},
items:[
{items: [TME.field.singleYear], columnWidth: .35},
{items: [TME.field.timeSeries], columnWidth: .35},
{items: [TME.field.timeSlider], columnWidth: .30}
]
}]
}),
// Display FieldSet
display: new Ext.form.FieldSet({
title: 'Display',
collapsible: true,
collapsed: false,
autoHeight: true,
labelWidth: 65,
items: [
{
layout:'column',
items:[{
columnWidth:.5,
layout: 'form',
items: [
TME.field.showTitle,
TME.field.showLegend
]
},{
columnWidth:.5,
layout: 'form',
items: [
TME.field.showValues,
TME.field.showNames
]
}]
}]
})
}
TME.engine = new Ext.FormPanel({
labelWidth: 70,
frame: true,
bodyStyle: 'padding:10px 10px 0',
width: 400,
items: [
TME.fieldset.statistics,
TME.fieldset.technique,
TME.fieldset.symbolStyle,
TME.fieldset.prismStyle,
TME.fieldset.colours,
TME.fieldset.time,
TME.fieldset.display,
TME.fieldset.description
]
});
// Form buttons
TME.button = {
// Preview button
preview: TME.engine.addButton({
text: 'Preview *',
disabled: true,
handler: function(){
TME.engine.form.submit({
url:'TME_FormHandler.php',
params: {task: 'makeKMZ'},
waitMsg:'Generating KML...',
success: function(form, action) {
// Check if GE plugin
if (TME.google.earth) {
// Link to KMZ file
var kmzlink = TME.google.baseURL + action.result.file;
// Remove existing KML (if exists)
if (TME.google.networkLink) {
TME.google.earth.getGlobe().getFeatures().removeChild(TME.google.networkLink);
TME.google.networkLink = null;
}
// Show borders if bar or proportional symbol map
TME.google.earth.getLayerRoot().enableLayerById(TME.google.earth.LAYER_BORDERS, false);
if (TME.field.symbol.getValue() || TME.field.bar.getValue()) {
TME.google.earth.getLayerRoot().enableLayerById(TME.google.earth.LAYER_BORDERS, true);
}
// Load KML
TME.google.networkLink = TME.google.earth.createNetworkLink("");
TME.google.networkLink.setFlyToView(true);
var link = TME.google.earth.createLink("");
link.setHref(kmzlink);
TME.google.networkLink.setLink(link);
// Add KML to GE plugin and show window
TME.google.earth.getGlobe().getFeatures().appendChild(TME.google.networkLink);
TME.google.earth.getWindow().setVisibility(true);
}
TME.window.previw.show();
},
failure: function(form, action) {
Ext.MessageBox.alert('Error', 'Engine failed');
}
});
}
}),
// Submit button
submit: TME.engine.addButton({
text: 'Download',
disabled: true,
handler: function(){
TME.engine.form.submit({
url:'TME_FormHandler.php',
params: {task: 'makeKMZ'},
waitMsg:'Generating KML...',
success: function (form, action) {
Ext.Msg.buttonText.cancel = 'Close';
Ext.Msg.show({
title: 'Download',
msg: '