<commit_before>define([
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/dom",
    "dojo/dom-construct",
    "dojo/dom-style",
    "dojo/on",
    "application/StatsBlock",
    "dojo/dom-class",
    "esri/symbols/SimpleFillSymbol",
    "esri/symbols/SimpleLineSymbol",
    "dojo/_base/Color",
    "dojo/_base/event",
    "esri/graphic",
    "esri/layers/GraphicsLayer",
    "esri/graphicsUtils",
    "esri/tasks/query",
    "dojo/window"
],
    function (
        declare,
        lang,
        dom,
        domConstruct,
        domStyle,
        on,
        StatsBlock,
         domClass,
        SimpleFillSymbol, SimpleLineSymbol,
        Color,
        event,
        Graphic, GraphicsLayer, graphicsUtils,
        Query,
        win
    ) {
        return declare("", null, {
            initArea: function () {
                this._entireAreaValue = "summarize";
                this.areaCSS = {
                    rendererMenu: 'menu-list',
                    rendererMenuItem: 'item',
                    rendererSelected: 'selected',
                    rendererLoading: 'loading-features',
                    rendererContainer: 'item-container',
                    rendererSummarize: 'summarize'
                };
                // if we have a layer title or layer id
                if (this.config.summaryLayer && this.config.summaryLayer.id) {
                    // get layer by id/title
                    this._aoiLayer = this._getAOILayer(this.config.summaryLayer.id);
                }
                // get layer infos
                this._getLayerInfos();
                // out fields
                this._getOutFields();
            },
            startupArea: function(){
                // stats block
                if (this._aoiLayer) {
                    this._sb = new StatsBlock({
                        config: this.config.summaryAttributes,
                        direction: this.config.i18n.direction,
                        appConfig: this.config //we need a config object here to check for edit mode and adding "+" variables
                    }, dom.byId('geoData'));   //So, i think we need not need this.data l.e entire response
                    this._sb.startup();
                    // init layer
                    // layer found
                    if (this._aoiLayer) {
                        // selected graphics layer
                        this._selectedGraphics = new GraphicsLayer({
                            id: "selectedArea",
                            visible: this._aoiLayer.visible
                        });
                        this.map.addLayer(this._selectedGraphics, (this._impactLayerIndex + 1));
                    }
                    // renderer layer infos
                    if (this._aoiInfos) {
                        // create renderer menu
                        this._createRendererItems(this._aoiInfos);
                    }
                    // if layer exists
                    if (this._aoiLayer) {
                        if(this.config.selectEntireAreaOnStart && this._selectAllNode){
                            this._queryFeatures(this._selectAllNode, this._entireAreaValue, false);
                        }
                        else{
                            // get highest value feature
                            this._queryGreatestFeature();
                        }
                        // selected poly from graphics layer
                        on(this._selectedGraphics, 'click', lang.hitch(this, function (evt) {
                            this._hideInfoWindow();
                            this._selectEvent(evt);
                        }));
                        // selected poly from layer
                        on(this._aoiLayer, 'click', lang.hitch(this, function (evt) {
                            this._hideInfoWindow();
                            this._selectEvent(evt);
                        }));
                        // layer show/hide
                        on(this._aoiLayer, 'visibility-change', lang.hitch(this, function (evt) {
                            // set visibility of graphics layer
                            this._selectedGraphics.setVisibility(evt.visible);
                            // if not visible
                            if (!evt.visible) {
                                // hide stats
                                this._sb.hide();
                            } else {
                                // show stats
                                this._sb.show();
                            }
                        }));
                    }
                    // set layer title
                    this._setImpactLayerTitle();
                    this._sb.show();
                        // drawer resize event
                    on(this._drawer, 'resize', lang.hitch(this, function () {
                        // resize stats block
                        if (this._sb) {
                            this._sb.resize();
                        }
                    }));
                }
                // description
                if (this.config.enableSummary) {
                    this._setSummary(this.config.summary || this.item.snippet);
                }
            },
            _setSummary: function (description) {
                // map title node
                var node = dom.byId('summary');
                if (node) {
                    // set title
                    node.innerHTML = description;
                }
            },
            _selectFeatures: function (features) {
                if (features && features.length) {
                    // add features to graphics layer
                    this._selectedGraphics.clear();
                    // each selected feature
                    for (var i = 0; i < features.length; i++) {
                        // selected line symbol
                        var sls = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([0, 255, 255, 1]), 2);
                        // selected fill symbol
                        var symbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, sls, new Color([0, 255, 255, 0]));
                        // selected graphic
                        var g = new Graphic(features[i].geometry, symbol, features[i].attributes, null);
                        if (g) {
                            // add graphic to layer
                            this._selectedGraphics.add(g);
                        }
                    }
                    // single fature
                    if (features.length === 1) {
                        // has attribute field for renderer
                        if (this._attributeField && features[0].attributes.hasOwnProperty(this._attributeField)) {
                            var value = features[0].attributes[this._attributeField];
                            if (this._rendererNodes && this._rendererNodes.length) {
                                // each renderer nodes
                                for (i = 0; i < this._rendererNodes.length; i++) {
                                    // value matches
                                    if (this._rendererNodes[i].value.toString() === value.toString()) {
                                        // set selected
                                        domClass.add(this._rendererNodes[i].node, this.areaCSS.rendererSelected);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            },
            _setImpactLayerTitle: function(){
                var node;
                // set title of header to layer title
                if(this._impactAreaTitle && this._rendererNodes && this._rendererNodes.length){
                    node = dom.byId('impact_area_title');
                    if(node){
                        node.innerHTML = this._impactAreaTitle;
                    }
                }
                else{
                    node = dom.byId('impact_area_section');
                    if(node){
                        node.innerHTML = '';
                    }
                }
            },
            // get layer
            _getAOILayer: function (id) {
                if (id && this.layers && this.map) {
                    var mapLayer = this.map.getLayer(id);
                    if(mapLayer){
                        if(mapLayer.arcgisProps && mapLayer.arcgisProps.title){
                            this._impactAreaTitle = mapLayer.arcgisProps.title;
                        }
                        return mapLayer;
                    }
                    else{
                        return false;
                    }
                }
                return false;
            },
            _queryGreatestFeature: function () {
                // features query
                var q = new Query();
                q.returnGeometry = true;
                q.where = '1=1';
                q.num = 1;
                q.start = 0;
                if(this._aoiOutFields){
                    q.outFields = this._aoiOutFields;
                }
                // if multiple features. (determined by renderer)
                if (this._multiple && this._attributeField) {
                    // order by attribute field
                    q.orderByFields = [this._attributeField + ' ' + this.config.summaryAttributeOrder];
                }
                // get features
                this._aoiLayer.queryFeatures(q, lang.hitch(this, function (fs) {
                    // features were returned
                    if (fs.features && fs.features.length) {
                        // display stats
                        this._sb.set("features", [fs.features[0]]);
                        this._sb.startup();
                        // selected features
                        this._selectFeatures([fs.features[0]]);
                    }
                }));
            },
            _queryFeatures: function (node, value, zoom) {
                // show layer if invisible
                if (!this._aoiLayer.visible) {
                    this._aoiLayer.setVisibility(true);
                }
                // remove any selected
                this._clearSelected();
                domClass.add(node, this.areaCSS.rendererSelected);
                domClass.add(node, this.areaCSS.rendererLoading);
                // search query
                var q = new Query();
                q.returnGeometry = true;
                if (value === this._entireAreaValue || value === "") {
                    // results
                    q.where = '1 = 1';
                } else {
                    // match value
                    if (isNaN(value)) {
                        q.where = this._attributeField + ' = ' + "'" + value + "'";
                    } else {
                        q.where = this._attributeField + ' = ' + value;
                    }
                }
                if(this._aoiOutFields){
                    q.outFields = this._aoiOutFields;
                }
                var ct = node;
                // query features
                this._aoiLayer.queryFeatures(q, lang.hitch(this, function (fs) {
                    // remove current renderer
                    domClass.remove(ct, this.areaCSS.rendererLoading);
                    // display geo stats
                    this._sb.set("features", fs.features);
                    this._selectFeatures(fs.features);
                    // zoom to feature
                    if(zoom){
                        // set extent for features
                        this.map.setExtent(graphicsUtils.graphicsExtent(fs.features), true);
                    }
                }), lang.hitch(this, function () {
                    // remove selected
                    this._clearSelected();
                }));
            },
            _createRendererItemClick: function (node, value) {
                // renderer item click
                on(node, 'click', lang.hitch(this, function (evt) {
                    this._hideInfoWindow();
                    var ct = evt.currentTarget;
                    // current renderer isn't already selected
                    if (!domClass.contains(ct, this.areaCSS.rendererSelected)) {
                        // view screen
                        var vs = win.getBox();
                        // hide drawer for small res
                        if (vs.w < this._showDrawerSize) {
                            this._drawer.toggle().then(lang.hitch(this, function () {
                                // resize map
                                this.map.resize(true);
                                // wait for map to be resized
                                setTimeout(lang.hitch(this, function () {
                                    // get features
                                    this._queryFeatures(ct, value, true);
                                }), 250);
                            }));
                        } else {
                            // get features
                            this._queryFeatures(ct, value, true);
                        }
                    }
                }));
            },
            _createRendererItems: function (infos) {
                // renderer node items created
                this._rendererNodes = [];
                // create list
                var ulList = domConstruct.create('ul', {
                    className: this.areaCSS.rendererMenu
                });
                // Entire area button in renderer list
                if(this.config.enableEntireAreaButton){
                    // create select all item
                    var selectAll = domConstruct.create('li', {
                        title: this.config.i18n.general.summarizeTitle,
                        className: this.areaCSS.rendererMenuItem + " " + this.areaCSS.rendererSummarize
                    });
                    // create select all item container
                    domConstruct.create('div', {
                        className: this.areaCSS.rendererContainer,
                        innerHTML: this.config.i18n.general.summarize
                    }, selectAll);
                    // select all click event
                    this._createRendererItemClick(selectAll, this._entireAreaValue);
                    // place item
                    domConstruct.place(selectAll, ulList, 'last');
                    // save reference to select all node
                    this._rendererNodes.push({
                        value: this._entireAreaValue,
                        node: selectAll
                    });
                    // select all node
                    this._selectAllNode = selectAll;
                }
                // each renderer item
                for (var i = 0; i < infos.length; i++) {
                    // create list item
                    var liItem = domConstruct.create('li', {
                        title: this.config.i18n.general.rendererTitle,
                        className: this.areaCSS.rendererMenuItem
                    });
                    // symbol color
                    var symbolColor = infos[i].symbol.color;
                    var hex = symbolColor.toHex();
                    // i18n border direction
                    var borderDirection = 'left';
                    if(this.config.i18n.direction === 'rtl'){
                        borderDirection = 'right';
                    }
                    // create list container
                    domConstruct.create('div', {
                        className: this.areaCSS.rendererContainer,
                        style: 'border-' + borderDirection + '-color:' + hex + '; border-' + borderDirection + '-color:rgb(' + symbolColor.r + ',' + symbolColor.g + ',' + symbolColor.b + '); border-' + borderDirection + '-color:rgba(' + symbolColor.r + ',' + symbolColor.g + ',' + symbolColor.b + ',' + symbolColor.a + ');',
                        innerHTML: infos[i].label
                    }, liItem);
                    // value
                    var value = infos[i].maxValue || infos[i].value || "";
                    // click event
                    this._createRendererItemClick(liItem, value);
                    // place item
                    domConstruct.place(liItem, ulList, 'last');
                    // save node for reference
                    this._rendererNodes.push({
                        value: value,
                        node: liItem
                    });
                }
                // renderer dom node
                var rendererMenu = dom.byId('renderer_menu');
                if (rendererMenu) {
                    // place
                    domConstruct.place(ulList, rendererMenu);
                    // display renderer
                    domStyle.set(rendererMenu, 'display', 'block');
                }
            },
            _getLayerInfos: function () {
                this._multiple = false;
                if (this._aoiLayer) {
                    // multiple polygons
                    var renderer = this._aoiLayer.renderer;
                    // renderer exists
                    if (renderer) {
                        this._attributeField = renderer.attributeField;
                        // renderer layer infos
                        var infos = renderer.infos;
                        if (infos && infos.length) {
                            infos = (this.config.summaryAttributeOrder == "DESC") ? infos : infos.reverse();
                            this._multiple = true;
                            this._aoiInfos = infos;
                        }
                    }
                }
            },
            _getOutFields: function(){
                var outFields = [];
                // each parent
                for(var i = 0; i < this.config.summaryAttributes.length; i++){
                    var parent = this.config.summaryAttributes[i];
                    var children = parent.children;
                    // add parent field
                    outFields.push(parent.attribute);
                    // parent children
                    if(children && children.length){
                        // each child
                        for(var j = 0; j < children.length; j++){
                            var child = children[j];
                            // add child field
                            outFields.push(child.attribute);
                        }
                    }
                }
                // if outFields set
                if(outFields && outFields.length){
                    this._aoiOutFields = outFields;
                }
            },
            // clear selected renderer & loading status
            _clearSelected: function () {
                // if items are there
                if (this._rendererNodes && this._rendererNodes.length) {
                    // remove classes from each item
                    for (var i = 0; i < this._rendererNodes.length; i++) {
                        domClass.remove(this._rendererNodes[i].node, this.areaCSS.rendererSelected);
                        domClass.remove(this._rendererNodes[i].node, this.areaCSS.rendererLoading);
                    }
                }
            },
            _selectEvent: function (evt) {
                // graphic selected
                if (evt.graphic) {
                    this._clearSelected();
                    this._sb.set("features", [evt.graphic]);
                    this._selectFeatures([evt.graphic]);
                    event.stop(evt);
                }
            },
            _hideInfoWindow: function () {
                if (this.map && this.map.infoWindow) {
                    this.map.infoWindow.hide();
                }
            }
        });
    });<commit_msg>ImpactSummary: horizontal lines<commit_after>define([
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/dom",
    "dojo/dom-construct",
    "dojo/dom-style",
    "dojo/on",
    "application/StatsBlock",
    "dojo/dom-class",
    "esri/symbols/SimpleFillSymbol",
    "esri/symbols/SimpleLineSymbol",
    "dojo/_base/Color",
    "dojo/_base/event",
    "esri/graphic",
    "esri/layers/GraphicsLayer",
    "esri/graphicsUtils",
    "esri/tasks/query",
    "dojo/window"
],
    function (
        declare,
        lang,
        dom,
        domConstruct,
        domStyle,
        on,
        StatsBlock,
         domClass,
        SimpleFillSymbol, SimpleLineSymbol,
        Color,
        event,
        Graphic, GraphicsLayer, graphicsUtils,
        Query,
        win
    ) {
        return declare("", null, {
            initArea: function () {
                this._entireAreaValue = "summarize";
                this.areaCSS = {
                    rendererMenu: 'menu-list',
                    rendererMenuItem: 'item',
                    rendererSelected: 'selected',
                    rendererLoading: 'loading-features',
                    rendererContainer: 'item-container',
                    rendererSummarize: 'summarize'
                };
                // if we have a layer title or layer id
                if (this.config.summaryLayer && this.config.summaryLayer.id) {
                    // get layer by id/title
                    this._aoiLayer = this._getAOILayer(this.config.summaryLayer.id);
                }
                // get layer infos
                this._getLayerInfos();
                // out fields
                this._getOutFields();
            },
            startupArea: function(){
                // stats block
                if (this._aoiLayer) {
                    this._sb = new StatsBlock({
                        config: this.config.summaryAttributes,
                        direction: this.config.i18n.direction,
                        appConfig: this.config //we need a config object here to check for edit mode and adding "+" variables
                    }, dom.byId('geoData'));   //So, i think we need not need this.data l.e entire response
                    this._sb.startup();
                    // init layer
                    // layer found
                    if (this._aoiLayer) {
                        // selected graphics layer
                        this._selectedGraphics = new GraphicsLayer({
                            id: "selectedArea",
                            visible: this._aoiLayer.visible
                        });
                        this.map.addLayer(this._selectedGraphics, (this._impactLayerIndex + 1));
                    }
                    // renderer layer infos
                    if (this._aoiInfos) {
                        // create renderer menu
                        this._createRendererItems(this._aoiInfos);
                    }
                    // if layer exists
                    if (this._aoiLayer) {
                        if(this.config.selectEntireAreaOnStart && this._selectAllNode){
                            this._queryFeatures(this._selectAllNode, this._entireAreaValue, false);
                        }
                        else{
                            // get highest value feature
                            this._queryGreatestFeature();
                        }
                        // selected poly from graphics layer
                        on(this._selectedGraphics, 'click', lang.hitch(this, function (evt) {
                            this._hideInfoWindow();
                            this._selectEvent(evt);
                        }));
                        // selected poly from layer
                        on(this._aoiLayer, 'click', lang.hitch(this, function (evt) {
                            this._hideInfoWindow();
                            this._selectEvent(evt);
                        }));
                        // layer show/hide
                        on(this._aoiLayer, 'visibility-change', lang.hitch(this, function (evt) {
                            // set visibility of graphics layer
                            this._selectedGraphics.setVisibility(evt.visible);
                            // if not visible
                            if (!evt.visible) {
                                // hide stats
                                this._sb.hide();
                            } else {
                                // show stats
                                this._sb.show();
                            }
                        }));
                    }
                    // set layer title
                    this._setImpactLayerTitle();
                    this._sb.show();
                        // drawer resize event
                    on(this._drawer, 'resize', lang.hitch(this, function () {
                        // resize stats block
                        if (this._sb) {
                            this._sb.resize();
                        }
                    }));
                }
                // description
                if (this.config.enableSummary) {
                    this._setSummary(this.config.summary || this.item.snippet);
                }
            },
            _setSummary: function (description) {
                // map title node
                var node = dom.byId('summary');
                if (node) {
                    // set title
                    node.innerHTML = description;
                }
            },
            _selectFeatures: function (features) {
                if (features && features.length) {
                    // add features to graphics layer
                    this._selectedGraphics.clear();
                    // each selected feature
                    for (var i = 0; i < features.length; i++) {
                        // selected line symbol
                        var sls = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([0, 255, 255, 1]), 2);
                        // selected fill symbol
                        var symbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_BACKWARD_DIAGONAL, sls, new Color([0, 255, 255, 0]));
                        // selected graphic
                        var g = new Graphic(features[i].geometry, symbol, features[i].attributes, null);
                        if (g) {
                            // add graphic to layer
                            this._selectedGraphics.add(g);
                        }
                    }
                    // single fature
                    if (features.length === 1) {
                        // has attribute field for renderer
                        if (this._attributeField && features[0].attributes.hasOwnProperty(this._attributeField)) {
                            var value = features[0].attributes[this._attributeField];
                            if (this._rendererNodes && this._rendererNodes.length) {
                                // each renderer nodes
                                for (i = 0; i < this._rendererNodes.length; i++) {
                                    // value matches
                                    if (this._rendererNodes[i].value.toString() === value.toString()) {
                                        // set selected
                                        domClass.add(this._rendererNodes[i].node, this.areaCSS.rendererSelected);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            },
            _setImpactLayerTitle: function(){
                var node;
                // set title of header to layer title
                if(this._impactAreaTitle && this._rendererNodes && this._rendererNodes.length){
                    node = dom.byId('impact_area_title');
                    if(node){
                        node.innerHTML = this._impactAreaTitle;
                    }
                }
                else{
                    node = dom.byId('impact_area_section');
                    if(node){
                        node.innerHTML = '';
                    }
                }
            },
            // get layer
            _getAOILayer: function (id) {
                if (id && this.layers && this.map) {
                    var mapLayer = this.map.getLayer(id);
                    if(mapLayer){
                        if(mapLayer.arcgisProps && mapLayer.arcgisProps.title){
                            this._impactAreaTitle = mapLayer.arcgisProps.title;
                        }
                        return mapLayer;
                    }
                    else{
                        return false;
                    }
                }
                return false;
            },
            _queryGreatestFeature: function () {
                // features query
                var q = new Query();
                q.returnGeometry = true;
                q.where = '1=1';
                q.num = 1;
                q.start = 0;
                if(this._aoiOutFields){
                    q.outFields = this._aoiOutFields;
                }
                // if multiple features. (determined by renderer)
                if (this._multiple && this._attributeField) {
                    // order by attribute field
                    q.orderByFields = [this._attributeField + ' ' + this.config.summaryAttributeOrder];
                }
                // get features
                this._aoiLayer.queryFeatures(q, lang.hitch(this, function (fs) {
                    // features were returned
                    if (fs.features && fs.features.length) {
                        // display stats
                        this._sb.set("features", [fs.features[0]]);
                        this._sb.startup();
                        // selected features
                        this._selectFeatures([fs.features[0]]);
                    }
                }));
            },
            _queryFeatures: function (node, value, zoom) {
                // show layer if invisible
                if (!this._aoiLayer.visible) {
                    this._aoiLayer.setVisibility(true);
                }
                // remove any selected
                this._clearSelected();
                domClass.add(node, this.areaCSS.rendererSelected);
                domClass.add(node, this.areaCSS.rendererLoading);
                // search query
                var q = new Query();
                q.returnGeometry = true;
                if (value === this._entireAreaValue || value === "") {
                    // results
                    q.where = '1 = 1';
                } else {
                    // match value
                    if (isNaN(value)) {
                        q.where = this._attributeField + ' = ' + "'" + value + "'";
                    } else {
                        q.where = this._attributeField + ' = ' + value;
                    }
                }
                if(this._aoiOutFields){
                    q.outFields = this._aoiOutFields;
                }
                var ct = node;
                // query features
                this._aoiLayer.queryFeatures(q, lang.hitch(this, function (fs) {
                    // remove current renderer
                    domClass.remove(ct, this.areaCSS.rendererLoading);
                    // display geo stats
                    this._sb.set("features", fs.features);
                    this._selectFeatures(fs.features);
                    // zoom to feature
                    if(zoom){
                        // set extent for features
                        this.map.setExtent(graphicsUtils.graphicsExtent(fs.features), true);
                    }
                }), lang.hitch(this, function () {
                    // remove selected
                    this._clearSelected();
                }));
            },
            _createRendererItemClick: function (node, value) {
                // renderer item click
                on(node, 'click', lang.hitch(this, function (evt) {
                    this._hideInfoWindow();
                    var ct = evt.currentTarget;
                    // current renderer isn't already selected
                    if (!domClass.contains(ct, this.areaCSS.rendererSelected)) {
                        // view screen
                        var vs = win.getBox();
                        // hide drawer for small res
                        if (vs.w < this._showDrawerSize) {
                            this._drawer.toggle().then(lang.hitch(this, function () {
                                // resize map
                                this.map.resize(true);
                                // wait for map to be resized
                                setTimeout(lang.hitch(this, function () {
                                    // get features
                                    this._queryFeatures(ct, value, true);
                                }), 250);
                            }));
                        } else {
                            // get features
                            this._queryFeatures(ct, value, true);
                        }
                    }
                }));
            },
            _createRendererItems: function (infos) {
                // renderer node items created
                this._rendererNodes = [];
                // create list
                var ulList = domConstruct.create('ul', {
                    className: this.areaCSS.rendererMenu
                });
                // Entire area button in renderer list
                if(this.config.enableEntireAreaButton){
                    // create select all item
                    var selectAll = domConstruct.create('li', {
                        title: this.config.i18n.general.summarizeTitle,
                        className: this.areaCSS.rendererMenuItem + " " + this.areaCSS.rendererSummarize
                    });
                    // create select all item container
                    domConstruct.create('div', {
                        className: this.areaCSS.rendererContainer,
                        innerHTML: this.config.i18n.general.summarize
                    }, selectAll);
                    // select all click event
                    this._createRendererItemClick(selectAll, this._entireAreaValue);
                    // place item
                    domConstruct.place(selectAll, ulList, 'last');
                    // save reference to select all node
                    this._rendererNodes.push({
                        value: this._entireAreaValue,
                        node: selectAll
                    });
                    // select all node
                    this._selectAllNode = selectAll;
                }
                // each renderer item
                for (var i = 0; i < infos.length; i++) {
                    // create list item
                    var liItem = domConstruct.create('li', {
                        title: this.config.i18n.general.rendererTitle,
                        className: this.areaCSS.rendererMenuItem
                    });
                    // symbol color
                    var symbolColor = infos[i].symbol.color;
                    var hex = symbolColor.toHex();
                    // i18n border direction
                    var borderDirection = 'left';
                    if(this.config.i18n.direction === 'rtl'){
                        borderDirection = 'right';
                    }
                    // create list container
                    domConstruct.create('div', {
                        className: this.areaCSS.rendererContainer,
                        style: 'border-' + borderDirection + '-color:' + hex + '; border-' + borderDirection + '-color:rgb(' + symbolColor.r + ',' + symbolColor.g + ',' + symbolColor.b + '); border-' + borderDirection + '-color:rgba(' + symbolColor.r + ',' + symbolColor.g + ',' + symbolColor.b + ',' + symbolColor.a + ');',
                        innerHTML: infos[i].label
                    }, liItem);
                    // value
                    var value = infos[i].maxValue || infos[i].value || "";
                    // click event
                    this._createRendererItemClick(liItem, value);
                    // place item
                    domConstruct.place(liItem, ulList, 'last');
                    // save node for reference
                    this._rendererNodes.push({
                        value: value,
                        node: liItem
                    });
                }
                // renderer dom node
                var rendererMenu = dom.byId('renderer_menu');
                if (rendererMenu) {
                    // place
                    domConstruct.place(ulList, rendererMenu);
                    // display renderer
                    domStyle.set(rendererMenu, 'display', 'block');
                }
            },
            _getLayerInfos: function () {
                this._multiple = false;
                if (this._aoiLayer) {
                    // multiple polygons
                    var renderer = this._aoiLayer.renderer;
                    // renderer exists
                    if (renderer) {
                        this._attributeField = renderer.attributeField;
                        // renderer layer infos
                        var infos = renderer.infos;
                        if (infos && infos.length) {
                            infos = (this.config.summaryAttributeOrder == "DESC") ? infos : infos.reverse();
                            this._multiple = true;
                            this._aoiInfos = infos;
                        }
                    }
                }
            },
            _getOutFields: function(){
                var outFields = [];
                // each parent
                for(var i = 0; i < this.config.summaryAttributes.length; i++){
                    var parent = this.config.summaryAttributes[i];
                    var children = parent.children;
                    // add parent field
                    outFields.push(parent.attribute);
                    // parent children
                    if(children && children.length){
                        // each child
                        for(var j = 0; j < children.length; j++){
                            var child = children[j];
                            // add child field
                            outFields.push(child.attribute);
                        }
                    }
                }
                // if outFields set
                if(outFields && outFields.length){
                    this._aoiOutFields = outFields;
                }
            },
            // clear selected renderer & loading status
            _clearSelected: function () {
                // if items are there
                if (this._rendererNodes && this._rendererNodes.length) {
                    // remove classes from each item
                    for (var i = 0; i < this._rendererNodes.length; i++) {
                        domClass.remove(this._rendererNodes[i].node, this.areaCSS.rendererSelected);
                        domClass.remove(this._rendererNodes[i].node, this.areaCSS.rendererLoading);
                    }
                }
            },
            _selectEvent: function (evt) {
                // graphic selected
                if (evt.graphic) {
                    this._clearSelected();
                    this._sb.set("features", [evt.graphic]);
                    this._selectFeatures([evt.graphic]);
                    event.stop(evt);
                }
            },
            _hideInfoWindow: function () {
                if (this.map && this.map.infoWindow) {
                    this.map.infoWindow.hide();
                }
            }
        });
    });<|endoftext|>


<commit_before>define([
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/dom",
    "dojo/dom-construct",
    "dojo/dom-class",
    "dojo/on",
    "esri/geometry/Extent",
],
    function (
        declare,
        lang,
        dom,
        domConstruct,
        domClass,
        on,
        Extent
    ) {
        return declare("", null, {
            initArea: function () {
                this.areaCSS = {
                    noteContainer: 'note-container',
                    noteItem: 'note-item',
                    noteContent: 'note-content',
                    notePadding: 'note-padding',
                    noteSelected: 'note-selected',
                    noteImage: 'note-image',
                    noteLink: 'note-link',
                    bookmarkItem: 'bookmark-item'
                };
                this._placeBookmarks();
                this._placeNotes();
            },
            _placeNotes: function(){
                this._notesLayers = this._getNotesLayers({
                    map: this.map,
                    layers: this.layers,
                    title: this.config.notes_layer_title,
                    id: this.config.notes_layer_id
                });
                if(this._notesLayers && this._notesLayers.length){
                    if(this._notesLayerTitle){
                        var node = dom.byId('map_notes_title');
                        if(node){
                            node.innerHTML = this._notesLayerTitle;
                        }
                    }
                    this._placeNoteItems();
                }
            },
            _placeNoteItems: function(){
                this.noteNodes = [];
                this.noteGraphics = [];
                this.noteGeometries = [];
                var count = 0;
                var notesNode = dom.byId('area_notes');
                for(var i = 0; i < this._notesLayers.length; i++){
                    for(var j = 0; j < this._notesLayers[i].graphics.length; j++){
                        var graphic = this._notesLayers[i].graphics[j];
                        var attributes = this._notesLayers[i].graphics[j].attributes;
                        var geometry = this._notesLayers[i].graphics[j].geometry;
                        this.noteGeometries.push(geometry);
                        this.noteGraphics.push(graphic);
                        // note container
                        var containerNode = domConstruct.create('div', {
                            className: this.areaCSS.noteContainer
                        });
                        // text symbol
                        if(graphic.symbol.type === 'textsymbol'){
                            attributes.TITLE = graphic.symbol.text;
                        }
                        // note title
                        var titleNode = domConstruct.create('div', {
                            innerHTML: attributes.TITLE || this.config.i18n.area.untitledNote,
                            className: this.areaCSS.noteItem
                        });
                        domConstruct.place(titleNode, containerNode, 'last');
                        // note HTML
                        var noteContent = '';
                        if (attributes.DESCRIPTION) {
                            noteContent = attributes.DESCRIPTION + "\n";
                        }
                        if (attributes.IMAGE_URL) {
                            if (attributes.IMAGE_LINK_URL) {
                                noteContent += '<image class="' + this.areaCSS.noteImage + '" src= "' + attributes.IMAGE_URL + '" alt="' + attributes.TITLE + '" />';
                            }
                            else {
                                noteContent += '<image class="' + this.areaCSS.noteImage + '" src="' + attributes.IMAGE_URL + '" alt="' + attributes.TITLE + '" />';
                            }
                        }
                        if(!noteContent){
                            noteContent = this.config.i18n.area.notesUnavailable;
                        }
                        // note content
                        var contentNode = domConstruct.create('div', {
                            className: this.areaCSS.noteContent,
                            innerHTML: '
' + noteContent + '
'
                        });
                        domConstruct.place(contentNode, containerNode, 'last');
                        // store nodes
                        this.noteNodes.push({
                            containerNode: containerNode,
                            titleNode: titleNode,
                            contentNode: contentNode
                        });
                        // note event
                        this._noteEvent(count);
                        // insert node
                        domConstruct.place(containerNode, notesNode, 'last');
                        // keep score!
                        count++;
                    }
                }
            },
            // get layer
            _getNotesLayers: function (obj) {
                var mapLayer, mapLayers = [], layers, layer, i, j;
                // if we have a layer id
                if (obj.id) {
                    for (i = 0; i < obj.layers.length; i++) {
                        layer = obj.layers[i];
                        if (layer.id === obj.id) {
                            this._notesLayerTitle = layer.title;
                            layers = layer.featureCollection.layers;
                            for(j = 0; j < layers.length; j++){
                                mapLayer = obj.map.getLayer(layers[j].id);
                                if(mapLayer){
                                    mapLayers.push(mapLayer);
                                }
                            }
                            return mapLayers;
                        }
                    }
                } else if (obj.title) {
                    // use layer title
                    for (i = 0; i < obj.layers.length; i++) {
                        layer = obj.layers[i];
                        if (layer.title.toLowerCase() === obj.title.toLowerCase()) {
                            this._notesLayerTitle = layer.title;
                            layers = layer.featureCollection.layers;
                            for(j = 0; j < layers.length; j++){
                                mapLayer = obj.map.getLayer(layers[j].id);
                                if(mapLayer){
                                    mapLayers.push(mapLayer);
                                }
                            }
                            return mapLayers;
                        }
                    }
                }
                return false;
            },
            _noteEvent: function(idx){
                on(this.noteNodes[idx].titleNode, 'click', lang.hitch(this, function(){
                    // if note open
                    if(domClass.contains(this.noteNodes[idx].containerNode, this.areaCSS.noteSelected)){
                        // close note
                        domClass.toggle(this.noteNodes[idx].containerNode, this.areaCSS.noteSelected);
                        // dont do any more
                        return;
                    }
                    else{
                        // close selected notes
                        for(var i = 0; i < this.noteNodes.length; i++){
                            domClass.remove(this.noteNodes[i].containerNode, this.areaCSS.noteSelected);
                        }
                        // open note
                        domClass.toggle(this.noteNodes[idx].containerNode, this.areaCSS.noteSelected);
                    }
                    var geometry = this.noteGeometries[idx];
                    var extent;
                    switch(geometry.type){
                        case "point":
                            extent = this.map.extent.centerAt(geometry);
                            break;
                        default:
                            extent = geometry.getExtent();
                    }
                    this.map.setExtent(extent, true).then(lang.hitch(this, function(){
                        // select graphic
                        if(this.map.infoWindow){
                            this.map.infoWindow.set("popupWindow", false);
                            this.map.infoWindow.setFeatures([this.noteGraphics[idx]]);
                            this.map.infoWindow.show(extent.getCenter());
                            this.map.infoWindow.set("popupWindow", true);
                        }
                    }));
                }));
            },
            _bookmarkEvent: function(idx){
                on(this.bmNodes[idx], 'click', lang.hitch(this, function(){
                    var extent = new Extent(this.bookmarks[idx].extent);
                    this.map.setExtent(extent);
                }));
            },
            _placeBookmarks: function(){
                var bookmarks = this.bookmarks;
                if (bookmarks && bookmarks.length){
                    var bookmarksNode = dom.byId('area_bookmarks');
                    this.bmNodes = [];
                    for(var i = 0; i < bookmarks.length; i++){
                        var node = domConstruct.create('div', {
                            innerHTML: bookmarks[i].name,
                            className: this.areaCSS.bookmarkItem
                        });
                        this.bmNodes.push(node);
                        this._bookmarkEvent(i);
                        domConstruct.place(node, bookmarksNode, 'last');
                    }
                }
            }
        });
    });<commit_msg>no message<commit_after>define([
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/dom",
    "dojo/dom-construct",
    "dojo/dom-class",
    "dojo/on",
    "esri/geometry/Extent",
],
    function (
        declare,
        lang,
        dom,
        domConstruct,
        domClass,
        on,
        Extent
    ) {
        return declare("", null, {
            initArea: function () {
                this.areaCSS = {
                    noteContainer: 'note-container',
                    noteItem: 'note-item',
                    noteContent: 'note-content',
                    notePadding: 'note-padding',
                    noteSelected: 'note-selected',
                    noteImage: 'note-image',
                    noteLink: 'note-link',
                    bookmarkItem: 'bookmark-item'
                };
                this._placeBookmarks();
                this._placeNotes();
            },
            _placeNotes: function(){
                this._notesLayers = this._getNotesLayers({
                    map: this.map,
                    layers: this.layers,
                    title: this.config.notes_layer_title,
                    id: this.config.notes_layer_id
                });
                if(this._notesLayers && this._notesLayers.length){
                    if(this._notesLayerTitle){
                        var node = dom.byId('map_notes_title');
                        if(node){
                            node.innerHTML = this._notesLayerTitle;
                        }
                    }
                    this._placeNoteItems();
                }
            },
            _placeNoteItems: function(){
                this.noteNodes = [];
                this.noteGraphics = [];
                this.noteGeometries = [];
                var count = 0;
                var notesNode = dom.byId('area_notes');
                for(var i = 0; i < this._notesLayers.length; i++){
                    for(var j = 0; j < this._notesLayers[i].graphics.length; j++){
                        var graphic = this._notesLayers[i].graphics[j];
                        var attributes = this._notesLayers[i].graphics[j].attributes;
                        var geometry = this._notesLayers[i].graphics[j].geometry;
                        this.noteGeometries.push(geometry);
                        this.noteGraphics.push(graphic);
                        // note container
                        var containerNode = domConstruct.create('div', {
                            className: this.areaCSS.noteContainer
                        });
                        // text symbol
                        if(graphic.symbol.type === 'textsymbol'){
                            attributes.TITLE = graphic.symbol.text;
                        }
                        // note title
                        var titleNode = domConstruct.create('div', {
                            innerHTML: attributes.TITLE || this.config.i18n.area.untitledNote,
                            className: this.areaCSS.noteItem
                        });
                        domConstruct.place(titleNode, containerNode, 'last');
                        // note HTML
                        var noteContent = '';
                        if (attributes.DESCRIPTION) {
                            noteContent = attributes.DESCRIPTION + "\n";
                        }
                        if (attributes.IMAGE_URL) {
                            if (attributes.IMAGE_LINK_URL) {
                                noteContent += '<image class="' + this.areaCSS.noteImage + '" src= "' + attributes.IMAGE_URL + '" alt="' + attributes.TITLE + '" />';
                            }
                            else {
                                noteContent += '<image class="' + this.areaCSS.noteImage + '" src="' + attributes.IMAGE_URL + '" alt="' + attributes.TITLE + '" />';
                            }
                        }
                        if(!noteContent){
                            noteContent = this.config.i18n.area.notesUnavailable;
                        }
                        // note content
                        var contentNode = domConstruct.create('div', {
                            className: this.areaCSS.noteContent,
                            innerHTML: '
' + noteContent + '
'
                        });
                        domConstruct.place(contentNode, containerNode, 'last');
                        // store nodes
                        this.noteNodes.push({
                            containerNode: containerNode,
                            titleNode: titleNode,
                            contentNode: contentNode
                        });
                        // note event
                        this._noteEvent(count);
                        // insert node
                        domConstruct.place(containerNode, notesNode, 'last');
                        // keep score!
                        count++;
                    }
                }
            },
            // get layer
            _getNotesLayers: function (obj) {
                var mapLayer, mapLayers = [], layers, layer, i, j;
                // if we have a layer id
                if (obj.id) {
                    for (i = 0; i < obj.layers.length; i++) {
                        layer = obj.layers[i];
                        if (layer.id === obj.id) {
                            this._notesLayerTitle = layer.title;
                            layers = layer.featureCollection.layers;
                            for(j = 0; j < layers.length; j++){
                                mapLayer = obj.map.getLayer(layers[j].id);
                                if(mapLayer){
                                    mapLayers.push(mapLayer);
                                }
                            }
                            return mapLayers;
                        }
                    }
                } else if (obj.title) {
                    // use layer title
                    for (i = 0; i < obj.layers.length; i++) {
                        layer = obj.layers[i];
                        if (layer.title.toLowerCase() === obj.title.toLowerCase()) {
                            this._notesLayerTitle = layer.title;
                            layers = layer.featureCollection.layers;
                            for(j = 0; j < layers.length; j++){
                                mapLayer = obj.map.getLayer(layers[j].id);
                                if(mapLayer){
                                    mapLayers.push(mapLayer);
                                }
                            }
                            return mapLayers;
                        }
                    }
                }
                return false;
            },
            _noteEvent: function(idx){
                on(this.noteNodes[idx].titleNode, 'click', lang.hitch(this, function(){
                    // if note open
                    if(domClass.contains(this.noteNodes[idx].containerNode, this.areaCSS.noteSelected)){
                        // close note
                        domClass.toggle(this.noteNodes[idx].containerNode, this.areaCSS.noteSelected);
                        // clear selected feature
                        if(this.map.infoWindow){
                            this.map.infoWindow.clearFeatures();
                        }
                        // dont do any more
                        return;
                    }
                    else{
                        // close selected notes
                        for(var i = 0; i < this.noteNodes.length; i++){
                            domClass.remove(this.noteNodes[i].containerNode, this.areaCSS.noteSelected);
                        }
                        // open note
                        domClass.toggle(this.noteNodes[idx].containerNode, this.areaCSS.noteSelected);
                    }
                    var geometry = this.noteGeometries[idx];
                    var extent;
                    switch(geometry.type){
                        case "point":
                            extent = this.map.extent.centerAt(geometry);
                            break;
                        default:
                            extent = geometry.getExtent();
                    }
                    this.map.setExtent(extent, true).then(lang.hitch(this, function(){
                        // select graphic
                        if(this.map.infoWindow){
                            this.map.infoWindow.set("popupWindow", false);
                            this.map.infoWindow.setFeatures([this.noteGraphics[idx]]);
                            this.map.infoWindow.show(extent.getCenter());
                            this.map.infoWindow.set("popupWindow", true);
                        }
                    }));
                }));
            },
            _bookmarkEvent: function(idx){
                on(this.bmNodes[idx], 'click', lang.hitch(this, function(){
                    var extent = new Extent(this.bookmarks[idx].extent);
                    this.map.setExtent(extent);
                }));
            },
            _placeBookmarks: function(){
                var bookmarks = this.bookmarks;
                if (bookmarks && bookmarks.length){
                    var bookmarksNode = dom.byId('area_bookmarks');
                    this.bmNodes = [];
                    for(var i = 0; i < bookmarks.length; i++){
                        var node = domConstruct.create('div', {
                            innerHTML: bookmarks[i].name,
                            className: this.areaCSS.bookmarkItem
                        });
                        this.bmNodes.push(node);
                        this._bookmarkEvent(i);
                        domConstruct.place(node, bookmarksNode, 'last');
                    }
                }
            }
        });
    });<|endoftext|>


<commit_before>
/**
 * Defines the interface for a 3DCityDBLayer. This Object is an interface for
 * documentation purpose and is not intended to be instantiated directly.
 *
 * @alias CitydbKmlLayer
 * @constructor
 *
 * @param {Object} [options] Object with the following properties:
 * @param {String} [options.url] url to the layer data
 * @param {String} [options.id] id of this layer
 * @param {String} [options.name] name of this layer
 * @param {String} [options.region] boundingbox  of this layer Cesium.Rectangle
 * @param {Number} [options.minLevel] minLevel
 * @param {Number} [options.maxLevel] maxLevel
 *
 */
(function() {
	function CitydbKmlLayer(options){
		this._url = options.url;
		this._id = options.id;
		this._name = options.name;
		this._region = options.region;
		this._highlightedObjects = {};
		this._active = true;
		this._hiddenObjects = [];
		this._cameraPosition = {};
		this._cesiumViewer = null;
		this._jsonLayerInfo = null;
		this._citydbKmlDataSource = new CitydbKmlDataSource(this._id);
		this._citydbKmlLayerManager = new CitydbKmlLayerManager(this);

		/**
		 * handles ClickEvents
		 * @type {Cesium.Event} clickEvent
		 */
		this._clickEvent = new Cesium.Event();

		/**
		 * handles ClickEvents
		 * @type {Cesium.Event} clickEvent
		 */
		this._mouseInEvent = new Cesium.Event();

		/**
		 * handles ClickEvents
		 * @type {Cesium.Event} clickEvent
		 */
		this._mouseOutEvent = new Cesium.Event();
	}

	Object.defineProperties(CitydbKmlLayer.prototype, {
	    /**
	     * Gets the active
	     * @memberof 3DCityDBLayer.prototype
	     * @type {Boolean}
	     */
	    active : {
	        get : function(){
	        	return this._active;
	        }
	    },
	    /**
	     * Gets the currently highlighted Objects as an array
	     * @memberof 3DCityDBLayer.prototype
	     * @type {Array}
	     */
	    highlightedObjects : {
	        get : function(){
	        	return this._highlightedObjects;
	        }
	    },
	    /**
	     * Gets the currently hidden Objects as an array
	     * @memberof 3DCityDBLayer.prototype
	     * @type {Array}
	     */
	    hiddenObjects : {
	        get : function(){
	        	return this._hiddenObjects;
	        }
	    },
	    /**
	     * Gets/Sets the CameraPosition.
	     * @memberof DataSource.prototype
	     * @type {Object}
	     */
	    cameraPosition : {
	        get : function(){
	        	return this._cameraPosition;
	        },
	        set : function(value){
	        	this._cameraPosition = value;
	        }
	    },
	    /**
	     * Gets the url of the datasource
	     * @memberof DataSource.prototype
	     * @type {String}
	     */
	    url : {
	        get : function(){
	        	return this._url;
	        }
	    },
	    /**
	     * Gets the name of this datasource.
	     * @memberof DataSource.prototype
	     * @type {String}
	     */
	    name : {
	        get : function(){
	        	return this._name;
	        }
	    },
	    /**
	     * Gets the id of this datasource, the id should be unique.
	     * @memberof DataSource.prototype
	     * @type {String}
	     */
	    id : {
	        get : function(){
	        	return this._id;
	        }
	    },
	    /**
	     * Gets boundingbox of this layer as an Cesium Rectangle Object with longitude/latitude values in radians.
	     * @memberof DataSource.prototype
	     * @type {Cesium.Rectangle}
	     */
	    region : {
	        get : function(){
	        	return this._region;
	        }
	    },

	    cesiumViewer : {
	        get : function(){
	        	return this._cesiumViewer;
	        }
	    },

	    jsonLayerInfo : {
	        get : function(){
	        	return this._jsonLayerInfo;
	        }
	    },

	    citydbKmlDataSource : {
	        get : function(){
	        	return this._citydbKmlDataSource;
	        }
	    },

	    citydbKmlLayerManager : {
	        get : function(){
	        	return this._citydbKmlLayerManager;
	        }
	    }

	});

	/**
	 * adds this layer to the given Cesium viewer
	 * @param {CesiumViewer} cesiumViewer
	 */
	CitydbKmlLayer.prototype.addToCesium = function(cesiumViewer){
		this._cesiumViewer = cesiumViewer;
		var that = this;
		if (this._url.indexOf(".json") >= 0) {
			jQuery.noConflict().ajax({
		        url: that._url +'?jsoncallback=?',
		        dataType: "jsonp",
		        jsonpCallback: "handle_3DCityDB_data", // the function name was defined by 3DCityDB KML/collada Exporter
		        timeout: 30000, // timeout in order to trigger the JQuery ajax error callback function
		        success: function(json, status){
		        	that._citydbKmlDataSource._name = json.layername;
		        	that._citydbKmlDataSource._proxy = json;
		    		console.log(that._citydbKmlDataSource);
		            viewer.dataSources.add(that._citydbKmlDataSource);
		            that._citydbKmlLayerManager.doStart();
		        },
		        error: function(XHR, textStatus, errorThrown){
		        	console.log('can not find the json file for ' + kmlUrl);
		        }
		    });
    	}
		else {
			this._citydbKmlDataSource.load(this._url).then(function() {
				console.log(that._citydbKmlDataSource);
				cesiumViewer.dataSources.add(that._citydbKmlDataSource);
				that._citydbKmlLayerManager.doStart();
		    });
		}
	}

	/**
	 * adds this layer to the given cesium viewer
	 * @param {CesiumViewer} cesiumViewer
	 */
	CitydbKmlLayer.prototype.removeFromCesium = function(cesiumViewer){
		// TODO
	}

	/**
	 * activates or deactivates the layer
	 * @param {Boolean} value
	 */
	CitydbKmlLayer.prototype.activate = function(active){

	}

	/**
	 * highlights one or more object with a given color;
	 * @param {Object<String, Cesium.Color>} An Object with the id and a Cesium Color value
	 */
	CitydbKmlLayer.prototype.highlight = function(toHighlight){
		// TODO
	};

	/**
	 * undo highlighting
	 * @param {Array<String>} A list of Object Ids. The default material will be restored
	 */
	CitydbKmlLayer.prototype.unHighlight = function(toUnHighlight){
		// TODO
	};

	/**
	 * hideObjects
	 * @param {Array<String>} A list of Object Ids which will be hidden
	 */
	CitydbKmlLayer.prototype.hideObjects = function(toHide){
		// TODO
	};

	/**
	 * showObjects, to undo hideObjects
	 * @param {Array<String>} A list of Object Ids which will be unhidden.
	 */
	CitydbKmlLayer.prototype.showObjects = function(toUnhide){
		// TODO
	};

	/**
	 * removes an Eventhandler
	 * @param {String} event (either CLICK, MOUSEIN or MOUSEOUT)
	 * @param {function} callback function to be called
	 */
	CitydbKmlLayer.prototype.removeEventHandler = function(event, callback){
		if(event == "CLICK"){
			this._clickEvent.removeEventListener(callback, this);
		}else if(event == "MOUSEIN"){
			this._mouseInEvent.removeEventListener(callback, this);
		}else if(event == "MOUSEOUT"){
			this._mouseOutEvent.removeEventListener(callback, this);
		}
	}

	/**
	 * adds an Eventhandler
	 * @param {String} event (either CLICK, MOUSEIN or MOUSEOUT)
	 * @param {function} callback function to be called
	 * @return {String} id of the event Handler, can be used to remove the event Handler
	 */
	CitydbKmlLayer.prototype.registerEventHandler = function(event, callback){
		if(event == "CLICK"){
			this._clickEvent.addEventListener(callback, this);
		}else if(event == "MOUSEIN"){
			this._mouseInEvent.addEventListener(callback, this);
		}else if(event == "MOUSEOUT"){
			this._mouseOutEvent.addEventListener(callback, this);
		}
	}

	/**
	 * triggers an Event
	 * @param {String} event (either CLICK, MOUSEIN or MOUSEOUT)
	 * @param {*} arguments, any number of arguments
	 */
	CitydbKmlLayer.prototype.triggerEvent = function(event, object){
		if(event == "CLICK"){
			this._clickEvent.raiseEvent(object);
		}else if(event == "MOUSEIN"){
			this._mouseInEvent.raiseEvent(object);
		}else if(event == "MOUSEOUT"){
			this._mouseOutEvent.raiseEvent(object);
		}
	}
	window.CitydbKmlLayer = CitydbKmlLayer;
})();

<commit_msg>small fix<commit_after>
/**
 * Defines the interface for a 3DCityDBLayer. This Object is an interface for
 * documentation purpose and is not intended to be instantiated directly.
 *
 * @alias CitydbKmlLayer
 * @constructor
 *
 * @param {Object} [options] Object with the following properties:
 * @param {String} [options.url] url to the layer data
 * @param {String} [options.id] id of this layer
 * @param {String} [options.name] name of this layer
 * @param {String} [options.region] boundingbox  of this layer Cesium.Rectangle
 * @param {Number} [options.minLevel] minLevel
 * @param {Number} [options.maxLevel] maxLevel
 *
 */
(function() {
	function CitydbKmlLayer(options){
		this._url = options.url;
		this._id = options.id;
		this._name = options.name;
		this._region = options.region;
		this._highlightedObjects = {};
		this._active = true;
		this._hiddenObjects = [];
		this._cameraPosition = {};
		this._cesiumViewer = null;
		this._jsonLayerInfo = null;
		this._citydbKmlDataSource = new CitydbKmlDataSource(this._id);
		this._citydbKmlLayerManager = new CitydbKmlLayerManager(this);

		/**
		 * handles ClickEvents
		 * @type {Cesium.Event} clickEvent
		 */
		this._clickEvent = new Cesium.Event();

		/**
		 * handles ClickEvents
		 * @type {Cesium.Event} clickEvent
		 */
		this._mouseInEvent = new Cesium.Event();

		/**
		 * handles ClickEvents
		 * @type {Cesium.Event} clickEvent
		 */
		this._mouseOutEvent = new Cesium.Event();
	}

	Object.defineProperties(CitydbKmlLayer.prototype, {
	    /**
	     * Gets the active
	     * @memberof 3DCityDBLayer.prototype
	     * @type {Boolean}
	     */
	    active : {
	        get : function(){
	        	return this._active;
	        }
	    },
	    /**
	     * Gets the currently highlighted Objects as an array
	     * @memberof 3DCityDBLayer.prototype
	     * @type {Array}
	     */
	    highlightedObjects : {
	        get : function(){
	        	return this._highlightedObjects;
	        }
	    },
	    /**
	     * Gets the currently hidden Objects as an array
	     * @memberof 3DCityDBLayer.prototype
	     * @type {Array}
	     */
	    hiddenObjects : {
	        get : function(){
	        	return this._hiddenObjects;
	        }
	    },
	    /**
	     * Gets/Sets the CameraPosition.
	     * @memberof DataSource.prototype
	     * @type {Object}
	     */
	    cameraPosition : {
	        get : function(){
	        	return this._cameraPosition;
	        },
	        set : function(value){
	        	this._cameraPosition = value;
	        }
	    },
	    /**
	     * Gets the url of the datasource
	     * @memberof DataSource.prototype
	     * @type {String}
	     */
	    url : {
	        get : function(){
	        	return this._url;
	        }
	    },
	    /**
	     * Gets the name of this datasource.
	     * @memberof DataSource.prototype
	     * @type {String}
	     */
	    name : {
	        get : function(){
	        	return this._name;
	        }
	    },
	    /**
	     * Gets the id of this datasource, the id should be unique.
	     * @memberof DataSource.prototype
	     * @type {String}
	     */
	    id : {
	        get : function(){
	        	return this._id;
	        }
	    },
	    /**
	     * Gets boundingbox of this layer as an Cesium Rectangle Object with longitude/latitude values in radians.
	     * @memberof DataSource.prototype
	     * @type {Cesium.Rectangle}
	     */
	    region : {
	        get : function(){
	        	return this._region;
	        }
	    },

	    cesiumViewer : {
	        get : function(){
	        	return this._cesiumViewer;
	        }
	    },

	    jsonLayerInfo : {
	        get : function(){
	        	return this._jsonLayerInfo;
	        }
	    },

	    citydbKmlDataSource : {
	        get : function(){
	        	return this._citydbKmlDataSource;
	        }
	    },

	    citydbKmlLayerManager : {
	        get : function(){
	        	return this._citydbKmlLayerManager;
	        }
	    }

	});

	/**
	 * adds this layer to the given Cesium viewer
	 * @param {CesiumViewer} cesiumViewer
	 */
	CitydbKmlLayer.prototype.addToCesium = function(cesiumViewer){
		this._cesiumViewer = cesiumViewer;
		var that = this;
		if (this._url.indexOf(".json") >= 0) {
			jQuery.noConflict().ajax({
		        url: that._url +'?jsoncallback=?',
		        dataType: "jsonp",
		        jsonpCallback: "handle_3DCityDB_data", // the function name was defined by 3DCityDB KML/collada Exporter
		        timeout: 30000, // timeout in order to trigger the JQuery ajax error callback function
		        success: function(json, status){
		        	that._citydbKmlDataSource._name = json.layername;
		        	that._citydbKmlDataSource._proxy = json;
		    		console.log(that._citydbKmlDataSource);
		    		cesiumViewer.dataSources.add(that._citydbKmlDataSource);
		            that._citydbKmlLayerManager.doStart();
		        },
		        error: function(XHR, textStatus, errorThrown){
		        	console.log('can not find the json file for ' + kmlUrl);
		        }
		    });
    	}
		else {
			this._citydbKmlDataSource.load(this._url).then(function() {
				console.log(that._citydbKmlDataSource);
				cesiumViewer.dataSources.add(that._citydbKmlDataSource);
				that._citydbKmlLayerManager.doStart();
		    });
		}
	}

	/**
	 * adds this layer to the given cesium viewer
	 * @param {CesiumViewer} cesiumViewer
	 */
	CitydbKmlLayer.prototype.removeFromCesium = function(cesiumViewer){
		// TODO
	}

	/**
	 * activates or deactivates the layer
	 * @param {Boolean} value
	 */
	CitydbKmlLayer.prototype.activate = function(active){

	}

	/**
	 * highlights one or more object with a given color;
	 * @param {Object<String, Cesium.Color>} An Object with the id and a Cesium Color value
	 */
	CitydbKmlLayer.prototype.highlight = function(toHighlight){
		var highlightedObjects = this._highlightedObjects;
		for (var id in toHighlight){
			highlightedObjects[id] = toHighlight[id]
			console.log(id);
			delete toHighlight[id];
		}
	};

	/**
	 * undo highlighting
	 * @param {Array<String>} A list of Object Ids. The default material will be restored
	 */
	CitydbKmlLayer.prototype.unHighlight = function(toUnHighlight){
		// TODO
	};

	/**
	 * hideObjects
	 * @param {Array<String>} A list of Object Ids which will be hidden
	 */
	CitydbKmlLayer.prototype.hideObjects = function(toHide){
		// TODO
	};

	/**
	 * showObjects, to undo hideObjects
	 * @param {Array<String>} A list of Object Ids which will be unhidden.
	 */
	CitydbKmlLayer.prototype.showObjects = function(toUnhide){
		// TODO
	};

	/**
	 * removes an Eventhandler
	 * @param {String} event (either CLICK, MOUSEIN or MOUSEOUT)
	 * @param {function} callback function to be called
	 */
	CitydbKmlLayer.prototype.removeEventHandler = function(event, callback){
		if(event == "CLICK"){
			this._clickEvent.removeEventListener(callback, this);
		}else if(event == "MOUSEIN"){
			this._mouseInEvent.removeEventListener(callback, this);
		}else if(event == "MOUSEOUT"){
			this._mouseOutEvent.removeEventListener(callback, this);
		}
	}

	/**
	 * adds an Eventhandler
	 * @param {String} event (either CLICK, MOUSEIN or MOUSEOUT)
	 * @param {function} callback function to be called
	 * @return {String} id of the event Handler, can be used to remove the event Handler
	 */
	CitydbKmlLayer.prototype.registerEventHandler = function(event, callback){
		if(event == "CLICK"){
			this._clickEvent.addEventListener(callback, this);
		}else if(event == "MOUSEIN"){
			this._mouseInEvent.addEventListener(callback, this);
		}else if(event == "MOUSEOUT"){
			this._mouseOutEvent.addEventListener(callback, this);
		}
	}

	/**
	 * triggers an Event
	 * @param {String} event (either CLICK, MOUSEIN or MOUSEOUT)
	 * @param {*} arguments, any number of arguments
	 */
	CitydbKmlLayer.prototype.triggerEvent = function(event, object){
		if(event == "CLICK"){
			this._clickEvent.raiseEvent(object);
		}else if(event == "MOUSEIN"){
			this._mouseInEvent.raiseEvent(object);
		}else if(event == "MOUSEOUT"){
			this._mouseOutEvent.raiseEvent(object);
		}
	}
	window.CitydbKmlLayer = CitydbKmlLayer;
})();

<|endoftext|>


<commit_before>// Copyright 2013-2017, University of Colorado Boulder

/**
 * Shows the home screen for a multi-screen simulation, which lets the user see all of the screens and select one.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var Bounds2 = require( 'DOT/Bounds2' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var inherit = require( 'PHET_CORE/inherit' );
  var joist = require( 'JOIST/joist' );
  var JoistA11yStrings = require( 'JOIST/JoistA11yStrings' );
  var Node = require( 'SCENERY/nodes/Node' );
  var PhetButton = require( 'JOIST/PhetButton' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Property = require( 'AXON/Property' );
  var ScreenButton = require( 'JOIST/ScreenButton' );
  var ScreenView = require( 'JOIST/ScreenView' );
  var StringUtils = require( 'PHETCOMMON/util/StringUtils' );
  var Text = require( 'SCENERY/nodes/Text' );

  // a11y-strings
  var simScreensString = JoistA11yStrings.simScreens.value;
  var simScreenString = JoistA11yStrings.simScreen.value;
  var homeScreenDescriptionPatternString = JoistA11yStrings.homeScreenDescriptionPattern.value;

  // constants
  var LAYOUT_BOUNDS = new Bounds2( 0, 0, 768, 504 );

  // iPad doesn't support Century Gothic, so fall back to Futura, see http://wordpress.org/support/topic/font-not-working-on-ipad-browser
  var TITLE_FONT_FAMILY = 'Century Gothic, Futura';

  /**
   * @param {Sim} sim
   * @param {Tandem} tandem
   * @param {Object} [options]
   * @constructor
   */
  function HomeScreenView( sim, tandem, options ) {
    var self = this;

    options = _.extend( {
      showSmallHomeScreenIconFrame: false,
      warningNode: null // {Node | null}, to display below the icons as a warning if available
    }, options );

    ScreenView.call( this, {
      layoutBounds: LAYOUT_BOUNDS,
      tandem: tandem,

      // a11y
      labelContent: sim.name,
      descriptionContent: StringUtils.fillIn( homeScreenDescriptionPatternString, {
        name: sim.name,
        screens: sim.screens.length
      } )
    } );

    var title = new Text( sim.name, {
      font: new PhetFont( {
        size: 52,
        family: TITLE_FONT_FAMILY
      } ),
      fill: 'white',
      y: 110,
      tandem: tandem.createTandem( 'title' )
    } );
    this.addChild( title );
    title.scale( Math.min( 1, 0.9 * this.layoutBounds.width / title.width ) );
    title.centerX = this.layoutBounds.centerX;

    // Keep track of which screen is highlighted so the same screen can remain highlighted even if nodes are replaced
    // (say when one grows larger or smaller).
    var highlightedScreenIndexProperty = new Property( -1 );

    var screenElements = _.map( sim.screens, function( screen, index ) {

      assert && assert( screen.name, 'name is required for screen ' + sim.screens.indexOf( screen ) );
      assert && assert( screen.homeScreenIcon, 'homeScreenIcon is required for screen ' + screen.name );

      // Even though in the user interface the small and large buttons seem like a single UI component that has grown
      // larger, it would be quite a headache to create a composite button for the purposes of tandem, so instead the
      // large and small buttons are registered as separate instances.  See https://github.com/phetsims/phet-io/issues/99
      var largeTandem = tandem.createTandem( screen.screenTandem.tail + 'LargeButton' );

      // a11y
      var a11yScreenButtonOptions = {
        tagName: 'button',
        innerContent: screen.name,
        descriptionContent: screen.descriptionContent,
        appendDescription: true,
        containerTagName: 'li'
      };

      var largeScreenButton = new ScreenButton(
        true,
        sim,
        index,
        highlightedScreenIndexProperty,
        largeTandem,
        _.extend( a11yScreenButtonOptions, {
          // Don't 40 the VBox or it will shift down when the border becomes thicker
          resize: false,
          cursor: 'pointer'
        } ) );

      // Even though in the user interface the small and large buttons seem like a single UI component that has grown
      // larger, it would be quite a headache to create a composite button for the purposes of tandem, so instead the
      // large and small buttons are registered as separate instances.  See https://github.com/phetsims/phet-io/issues/99
      var smallTandem = tandem.createTandem( screen.screenTandem.tail + 'SmallButton' );

      var smallScreenButton = new ScreenButton(
        false,
        sim,
        index,
        highlightedScreenIndexProperty,
        smallTandem,
        _.extend( a11yScreenButtonOptions, {
            spacing: 3,
            cursor: 'pointer',
            showSmallHomeScreenIconFrame: options.showSmallHomeScreenIconFrame
          }
        ) );

      smallScreenButton.addInputListener( smallScreenButton.highlightListener );
      largeScreenButton.addInputListener( smallScreenButton.highlightListener );

      // a11y support for click listeners on the screen buttons
      var toggleListener = function() {
        smallScreenButton.visible && smallScreenButton.focus();
        largeScreenButton.visible && largeScreenButton.focus();
      };
      smallScreenButton.addAccessibleInputListener( { focus: toggleListener } );
      largeScreenButton.addAccessibleInputListener( { click: toggleListener } );
      // largeScreenButton.mouseArea = largeScreenButton.touchArea = Shape.bounds( largeScreenButton.bounds ); // cover the gap in the vbox

      // a11y - add the right aria attributes to the buttons
      smallScreenButton.setAccessibleAttribute( 'aria-roledescription', simScreenString );
      largeScreenButton.setAccessibleAttribute( 'aria-roledescription', simScreenString );

      return { screen: screen, small: smallScreenButton, large: largeScreenButton, index: index };
    } );

    // a11y this is needed to create the right PDOM structure, the phet menu shouldn't be a child of this 'nav', so
    // the HomeScreenView can't be the 'nav' tag.
    var navIconsNode = new Node( {

      // a11y
      tagName: 'nav',
      ariaLabel: simScreensString
    } );

    // Intermediate node, so that icons are always in the same rendering layer
    var iconsParentNode = new Node( { tagName: 'ol' } );

    // add the icons to the nav tag Node
    navIconsNode.addChild( iconsParentNode );
    this.addChild( navIconsNode );

    // Space the icons out more if there are fewer, so they will be spaced nicely.
    // Cannot have only 1 screen because for 1-screen sims there is no home screen.
    var spacing = 60;
    if ( sim.screens.length === 4 ) {
      spacing = 33;
    }
    if ( sim.screens.length >= 5 ) {
      spacing = 20;
    }

    var hBox = null;

    // @public - for a11y, allow focus to be set when returning to home screen from sim
    this.highlightedScreenButton = null;

    sim.screenIndexProperty.link( function( screenIndex ) {

      // remove previous layout of icons
      if ( hBox ) {
        hBox.removeAllChildren(); // because icons have reference to hBox (their parent)
        iconsParentNode.removeChild( hBox );
      }

      // add new layout of icons
      var icons = _.map( screenElements, function( screenChild ) {

        // check for the current screen
        if ( screenChild.index === screenIndex ) {
          self.highlightedScreenButton = screenChild.large;
        }
        return screenChild.index === screenIndex ? screenChild.large : screenChild.small;
      } );
      hBox = new HBox( {
        spacing: spacing,
        children: icons,
        align: 'top',
        resize: false,
        maxWidth: self.layoutBounds.width - 118
      } );
      iconsParentNode.addChild( hBox );

      // position the icons
      iconsParentNode.centerX = self.layoutBounds.width / 2;
      iconsParentNode.centerY = self.layoutBounds.height / 2 + 20;
    } );

    //TODO move these Properties to LookAndFeel, see https://github.com/phetsims/joist/issues/255
    var homeScreenFillProperty = new Property( 'black' );
    var homeScreenTextFillProperty = new Property( 'white' );

    // @public (joist-internal) - This PhET button is public since our creator (Sim.js) is responsible for positioning
    // this button. See https://github.com/phetsims/joist/issues/304.
    this.phetButton = new PhetButton( sim, homeScreenFillProperty, homeScreenTextFillProperty, tandem.createTandem( 'phetButton' ) );
    this.addChild( this.phetButton );

    if ( options.warningNode ) {
      var warningNode = options.warningNode;

      this.addChild( warningNode );
      warningNode.centerX = this.layoutBounds.centerX;
      warningNode.bottom = this.layoutBounds.maxY - 20;
    }
  }

  joist.register( 'HomeScreenView', HomeScreenView );

  return inherit( ScreenView, HomeScreenView, {},
    // @public - statics
    {
      TITLE_FONT_FAMILY: TITLE_FONT_FAMILY,
      LAYOUT_BOUNDS: LAYOUT_BOUNDS
    }
  );
} );<commit_msg>Fix the top of the home screen icons in space, rather than the center. See https://github.com/phetsims/joist/issues/470<commit_after>// Copyright 2013-2017, University of Colorado Boulder

/**
 * Shows the home screen for a multi-screen simulation, which lets the user see all of the screens and select one.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var Bounds2 = require( 'DOT/Bounds2' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var inherit = require( 'PHET_CORE/inherit' );
  var joist = require( 'JOIST/joist' );
  var JoistA11yStrings = require( 'JOIST/JoistA11yStrings' );
  var Node = require( 'SCENERY/nodes/Node' );
  var PhetButton = require( 'JOIST/PhetButton' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Property = require( 'AXON/Property' );
  var ScreenButton = require( 'JOIST/ScreenButton' );
  var ScreenView = require( 'JOIST/ScreenView' );
  var StringUtils = require( 'PHETCOMMON/util/StringUtils' );
  var Text = require( 'SCENERY/nodes/Text' );

  // a11y-strings
  var simScreensString = JoistA11yStrings.simScreens.value;
  var simScreenString = JoistA11yStrings.simScreen.value;
  var homeScreenDescriptionPatternString = JoistA11yStrings.homeScreenDescriptionPattern.value;

  // constants
  var LAYOUT_BOUNDS = new Bounds2( 0, 0, 768, 504 );

  // iPad doesn't support Century Gothic, so fall back to Futura, see http://wordpress.org/support/topic/font-not-working-on-ipad-browser
  var TITLE_FONT_FAMILY = 'Century Gothic, Futura';

  /**
   * @param {Sim} sim
   * @param {Tandem} tandem
   * @param {Object} [options]
   * @constructor
   */
  function HomeScreenView( sim, tandem, options ) {
    var self = this;

    options = _.extend( {
      showSmallHomeScreenIconFrame: false,
      warningNode: null // {Node | null}, to display below the icons as a warning if available
    }, options );

    ScreenView.call( this, {
      layoutBounds: LAYOUT_BOUNDS,
      tandem: tandem,

      // a11y
      labelContent: sim.name,
      descriptionContent: StringUtils.fillIn( homeScreenDescriptionPatternString, {
        name: sim.name,
        screens: sim.screens.length
      } )
    } );

    var title = new Text( sim.name, {
      font: new PhetFont( {
        size: 52,
        family: TITLE_FONT_FAMILY
      } ),
      fill: 'white',
      y: 110,
      tandem: tandem.createTandem( 'title' )
    } );
    this.addChild( title );
    title.scale( Math.min( 1, 0.9 * this.layoutBounds.width / title.width ) );
    title.centerX = this.layoutBounds.centerX;

    // Keep track of which screen is highlighted so the same screen can remain highlighted even if nodes are replaced
    // (say when one grows larger or smaller).
    var highlightedScreenIndexProperty = new Property( -1 );

    var screenElements = _.map( sim.screens, function( screen, index ) {

      assert && assert( screen.name, 'name is required for screen ' + sim.screens.indexOf( screen ) );
      assert && assert( screen.homeScreenIcon, 'homeScreenIcon is required for screen ' + screen.name );

      // Even though in the user interface the small and large buttons seem like a single UI component that has grown
      // larger, it would be quite a headache to create a composite button for the purposes of tandem, so instead the
      // large and small buttons are registered as separate instances.  See https://github.com/phetsims/phet-io/issues/99
      var largeTandem = tandem.createTandem( screen.screenTandem.tail + 'LargeButton' );

      // a11y
      var a11yScreenButtonOptions = {
        tagName: 'button',
        innerContent: screen.name,
        descriptionContent: screen.descriptionContent,
        appendDescription: true,
        containerTagName: 'li'
      };

      var largeScreenButton = new ScreenButton(
        true,
        sim,
        index,
        highlightedScreenIndexProperty,
        largeTandem,
        _.extend( a11yScreenButtonOptions, {
          // Don't 40 the VBox or it will shift down when the border becomes thicker
          resize: false,
          cursor: 'pointer'
        } ) );

      // Even though in the user interface the small and large buttons seem like a single UI component that has grown
      // larger, it would be quite a headache to create a composite button for the purposes of tandem, so instead the
      // large and small buttons are registered as separate instances.  See https://github.com/phetsims/phet-io/issues/99
      var smallTandem = tandem.createTandem( screen.screenTandem.tail + 'SmallButton' );

      var smallScreenButton = new ScreenButton(
        false,
        sim,
        index,
        highlightedScreenIndexProperty,
        smallTandem,
        _.extend( a11yScreenButtonOptions, {
            spacing: 3,
            cursor: 'pointer',
            showSmallHomeScreenIconFrame: options.showSmallHomeScreenIconFrame
          }
        ) );

      smallScreenButton.addInputListener( smallScreenButton.highlightListener );
      largeScreenButton.addInputListener( smallScreenButton.highlightListener );

      // a11y support for click listeners on the screen buttons
      var toggleListener = function() {
        smallScreenButton.visible && smallScreenButton.focus();
        largeScreenButton.visible && largeScreenButton.focus();
      };
      smallScreenButton.addAccessibleInputListener( { focus: toggleListener } );
      largeScreenButton.addAccessibleInputListener( { click: toggleListener } );
      // largeScreenButton.mouseArea = largeScreenButton.touchArea = Shape.bounds( largeScreenButton.bounds ); // cover the gap in the vbox

      // a11y - add the right aria attributes to the buttons
      smallScreenButton.setAccessibleAttribute( 'aria-roledescription', simScreenString );
      largeScreenButton.setAccessibleAttribute( 'aria-roledescription', simScreenString );

      return { screen: screen, small: smallScreenButton, large: largeScreenButton, index: index };
    } );

    // a11y this is needed to create the right PDOM structure, the phet menu shouldn't be a child of this 'nav', so
    // the HomeScreenView can't be the 'nav' tag.
    var navIconsNode = new Node( {

      // a11y
      tagName: 'nav',
      ariaLabel: simScreensString
    } );

    // Intermediate node, so that icons are always in the same rendering layer
    var iconsParentNode = new Node( { tagName: 'ol' } );

    // add the icons to the nav tag Node
    navIconsNode.addChild( iconsParentNode );
    this.addChild( navIconsNode );

    // Space the icons out more if there are fewer, so they will be spaced nicely.
    // Cannot have only 1 screen because for 1-screen sims there is no home screen.
    var spacing = 60;
    if ( sim.screens.length === 4 ) {
      spacing = 33;
    }
    if ( sim.screens.length >= 5 ) {
      spacing = 20;
    }

    var hBox = null;

    // @public - for a11y, allow focus to be set when returning to home screen from sim
    this.highlightedScreenButton = null;

    sim.screenIndexProperty.link( function( screenIndex ) {

      // remove previous layout of icons
      if ( hBox ) {
        hBox.removeAllChildren(); // because icons have reference to hBox (their parent)
        iconsParentNode.removeChild( hBox );
      }

      // add new layout of icons
      var icons = _.map( screenElements, function( screenChild ) {

        // check for the current screen
        if ( screenChild.index === screenIndex ) {
          self.highlightedScreenButton = screenChild.large;
        }
        return screenChild.index === screenIndex ? screenChild.large : screenChild.small;
      } );
      hBox = new HBox( {
        spacing: spacing,
        children: icons,
        align: 'top',
        resize: false,
        maxWidth: self.layoutBounds.width - 118
      } );
      iconsParentNode.addChild( hBox );

      // position the icons
      iconsParentNode.centerX = self.layoutBounds.width / 2;
      iconsParentNode.top = self.layoutBounds.height / 3;
    } );

    //TODO move these Properties to LookAndFeel, see https://github.com/phetsims/joist/issues/255
    var homeScreenFillProperty = new Property( 'black' );
    var homeScreenTextFillProperty = new Property( 'white' );

    // @public (joist-internal) - This PhET button is public since our creator (Sim.js) is responsible for positioning
    // this button. See https://github.com/phetsims/joist/issues/304.
    this.phetButton = new PhetButton( sim, homeScreenFillProperty, homeScreenTextFillProperty, tandem.createTandem( 'phetButton' ) );
    this.addChild( this.phetButton );

    if ( options.warningNode ) {
      var warningNode = options.warningNode;

      this.addChild( warningNode );
      warningNode.centerX = this.layoutBounds.centerX;
      warningNode.bottom = this.layoutBounds.maxY - 20;
    }
  }

  joist.register( 'HomeScreenView', HomeScreenView );

  return inherit( ScreenView, HomeScreenView, {},
    // @public - statics
    {
      TITLE_FONT_FAMILY: TITLE_FONT_FAMILY,
      LAYOUT_BOUNDS: LAYOUT_BOUNDS
    }
  );
} );<|endoftext|>