//>>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); } } }); });