145 lines
4.6 KiB
JavaScript
145 lines
4.6 KiB
JavaScript
//>>built
|
|
define("dojox/geo/charting/KeyboardInteractionSupport", ["dojo/_base/lang","dojo/_base/declare","dojo/_base/event","dojo/_base/connect",
|
|
"dojo/_base/html","dojo/dom","dojox/lang/functional","dojo/keys"],
|
|
function(lang, declare, event, connect, html, dom, functional, keys) {
|
|
|
|
return declare("dojox.geo.charting.KeyboardInteractionSupport", null, {
|
|
// summary:
|
|
// class to handle keyboard interactions on a dojox.geo.charting.Map widget
|
|
//
|
|
// The sections on the leading edge should receive the focus in response to a TAB event.
|
|
// Then use cursor keys to the peer sections. The cursor event should go the adjacent section
|
|
// in that direction. With the focus, the section zooms in upon SPACE. The map should zoom out
|
|
// on ESC. Finally, while it has the focus, the map should lose the focus on TAB.
|
|
// tags:
|
|
// private
|
|
_map: null,
|
|
_zoomEnabled: false,
|
|
|
|
constructor: function(map, options){
|
|
// summary:
|
|
// Constructs a new _KeyboardInteractionSupport instance
|
|
// map: dojox.geo.charting.Map
|
|
// the Map widget this class provides touch navigation for.
|
|
this._map = map;
|
|
if(options){
|
|
this._zoomEnabled = options.enableZoom;
|
|
}
|
|
},
|
|
connect: function(){
|
|
// summary:
|
|
// connects this keyboard support class to the Map component
|
|
var container = dom.byId(this._map.container);
|
|
// tab accessing enable
|
|
html.attr(container, {
|
|
tabindex: 0,
|
|
role: "presentation",
|
|
"aria-label": "map"
|
|
});
|
|
// install listeners
|
|
this._keydownListener = connect.connect(container, "keydown", this, "keydownHandler");
|
|
this._onFocusListener = connect.connect(container, "focus", this, "onFocus");
|
|
this._onBlurListener = connect.connect(container, "blur", this, "onBlur");
|
|
},
|
|
disconnect: function(){
|
|
// summary:
|
|
// disconnects any installed listeners
|
|
connect.disconnect(this._keydownListener);
|
|
this._keydownListener = null;
|
|
connect.disconnect(this._onFocusListener);
|
|
this._onFocusListener = null;
|
|
connect.disconnect(this._onBlurListener);
|
|
this._onBlurListener = null
|
|
},
|
|
keydownHandler: function(e){
|
|
switch(e.keyCode){
|
|
case keys.LEFT_ARROW:
|
|
this._directTo(-1,-1,1,-1);
|
|
break;
|
|
case keys.RIGHT_ARROW:
|
|
this._directTo(-1,-1,-1,1);
|
|
break;
|
|
case keys.UP_ARROW:
|
|
this._directTo(1,-1,-1,-1);
|
|
break;
|
|
case keys.DOWN_ARROW:
|
|
this._directTo(-1,1,-1,-1);
|
|
break;
|
|
case keys.SPACE:
|
|
if(this._map.selectedFeature && !this._map.selectedFeature._isZoomIn && this._zoomEnabled){
|
|
this._map.selectedFeature._zoomIn();
|
|
}
|
|
break;
|
|
case keys.ESCAPE:
|
|
if(this._map.selectedFeature && this._map.selectedFeature._isZoomIn && this._zoomEnabled){
|
|
this._map.selectedFeature._zoomOut();
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
event.stop(e);
|
|
},
|
|
onFocus: function(e){
|
|
// select the leading region at the map center
|
|
if(this._map.selectedFeature || this._map.focused){return;}
|
|
this._map.focused = true;
|
|
var leadingRegion,
|
|
needClick = false;
|
|
if(this._map.lastSelectedFeature){
|
|
leadingRegion = this._map.lastSelectedFeature;
|
|
}else{
|
|
var mapCenter = this._map.getMapCenter(),
|
|
minDistance = Infinity;
|
|
// find the region most closing to the map center
|
|
functional.forIn(this._map.mapObj.features, function(feature){
|
|
var distance = Math.sqrt(Math.pow(feature._center[0] - mapCenter.x, 2) + Math.pow(feature._center[1] - mapCenter.y, 2));
|
|
if(distance < minDistance){
|
|
minDistance = distance;
|
|
leadingRegion = feature;
|
|
}
|
|
});
|
|
needClick = true;
|
|
}
|
|
if(leadingRegion){
|
|
if(needClick) {
|
|
leadingRegion._onclickHandler(null);
|
|
}else{
|
|
}
|
|
this._map.mapObj.marker.show(leadingRegion.id);
|
|
}
|
|
},
|
|
onBlur: function(){
|
|
this._map.lastSelectedFeature = this._map.selectedFeature;
|
|
},
|
|
_directTo: function(up,down,left,right){
|
|
var currentSelected = this._map.selectedFeature,
|
|
centerX = currentSelected._center[0],
|
|
centerY = currentSelected._center[1],
|
|
minMargin = Infinity,
|
|
nextSelected = null;
|
|
functional.forIn(this._map.mapObj.features, function(feature){
|
|
var paddingX = Math.abs(centerX - feature._center[0]),
|
|
paddingY = Math.abs(centerY - feature._center[1]),
|
|
paddingSum = paddingX + paddingY;
|
|
if((up - down) * (centerY - feature._center[1]) > 0){
|
|
if(paddingX < paddingY && minMargin > paddingSum){
|
|
minMargin = paddingSum;
|
|
nextSelected = feature;
|
|
}
|
|
}
|
|
if((left - right) * (centerX - feature._center[0]) > 0){
|
|
if(paddingX > paddingY && minMargin > paddingSum){
|
|
minMargin = paddingSum;
|
|
nextSelected = feature;
|
|
}
|
|
}
|
|
});
|
|
if(nextSelected){
|
|
this._map.mapObj.marker.hide();
|
|
nextSelected._onclickHandler(null);
|
|
this._map.mapObj.marker.show(nextSelected.id);
|
|
}
|
|
}
|
|
});
|
|
}); |