Skip to content

Javascript Tutorial

Alan D. Snow edited this page Nov 30, 2016 · 19 revisions

In this section we will demonstrate master javascript elements provided by Tethys Platform. ###0. Get the ERDC-CM version of Tethys Platform Until the changes are merged in the master version of Tethys Platform, this tutorial only works if you get the ERDC-CM version.

$ rm -rf /usr/lib/tethys/src
$ git clone https://github.com/erdc-cm/tethys /usr/lib/tethys/src
$ pip install --upgrade -r /usr/lib/tethys/src/requirements.txt
$ python /usr/lib/tethys/src/setup.py develop
$ deactivate
$ t

###1. Start from Advanced Tutorial If you have not completed the advanced tutorial, you can do so here.

If you want to skip to the master javascript section or use the solution to continue:

$ cd tethysdev
$ git clone https://github.com/erdc-cm/tethysapp-dam_break.git
$ cd tethysapp-dam_break
$ git checkout advanced
$ t
(tethys)$ python setup.py develop
(tethys)$ tethys syncstores dam_break

Note: 't' is an alias. To learn how to create one, click here.

###2. Start development server If you have not done so already, start the development server:

(tethys)$ tethys manage start

You will also need to start the postgis docker container:

(tethys)$ tethys docker init -c postgis

###3. Web browser developer tools Most browsers now have web developer consoles where you can see your code and interact with it. Here are examples you can look at:

  1. Firefox - https://developer.mozilla.org/en-US/Learn/Common_questions/What_are_browser_developer_tools
  2. Chrome - https://developer.chrome.com/devtools

There are many other browsers and modern versions usually have developer tools.

###4. Selecting Layers On Map: #####a. Modify map function in controllers.py to make the layer selectable:

...
    geojson_layer = MVLayer(source='GeoJSON',
                            options=geojson_gages,
                            legend_title='Dam Locations',
                            legend_extent=[min(lon_list)-delta, min(lat_list)-delta, max(lon_list)+delta, max(lat_list)+delta],
                            feature_selection=True)
... 

#####b. Create map.js in public/js Add this to your script:

$(function() {
    m_select_interaction = TETHYS_MAP_VIEW.getSelectInteraction();
    //when selected, call function to make hydrograph
    m_select_interaction.getFeatures().on('change:length', function(e) {
      if (e.target.getArray().length > 0) {
        // this means there is at least 1 feature selected
        var selected_feature = e.target.item(0); // 1st feature in Collection
        console.log(selected_feature.get('peak_flow'));
        console.log(selected_feature.get('time_peak'));
        console.log(selected_feature.get('peak_duration'));
        console.log(selected_feature.get('falling_limb_duration'));
      }
    });
});

Note: This uses OpenLayers 3. Check here to find out the current version. It should have a link to the Openlayers API.

#####c. Load script and message box into map.html First, you need to load staticfiles at the top:

{% extends "dam_break/base.html" %}
{% load tethys_gizmos %}
{% load staticfiles %}

{% block app_content %}
  <h1>Dam Locations</h1>
  {% gizmo map_view map_options %}
  {% gizmo message_box hydrograph_box %}
{% endblock %}

{% block scripts %}
  {{ block.super }}
  <script src="{% static 'dam_break/js/map.js' %}" type="text/javascript"></script>
{% endblock %}

#####d. Check your browser console. Go to http://localhost:8000/apps/dam_break/map and then open your console. Click on a dam and you should see data appear in the console.

###5. Perform AJAX calls on feature selection Let's make this interesting and go into AJAX. #####a. Create controller in controllers.py for AJAX call

@login_required()
def hydrograph_ajax(request):
    """
    Controller for the hydrograph ajax request.
    """
    # Default Values
    peak_flow = 800.0
    time_to_peak = 6
    peak_duration = 6
    falling_limb_duration = 24

    if request.GET:
        peak_flow = float(request.GET['peak_flow'])
        time_to_peak = int(request.GET['time_to_peak'])
        peak_duration = int(request.GET['peak_duration'])
        falling_limb_duration = int(request.GET['falling_limb_duration'])

    # Generate hydrograph
    hydrograph = generate_flood_hydrograph(
        peak_flow=peak_flow, 
        time_to_peak=time_to_peak, 
        peak_duration=peak_duration, 
        falling_limb_duration=falling_limb_duration
    )

    # Configure the Hydrograph Plot View
    flood_plot = TimeSeries(
        engine='highcharts',
        title='Flood Hydrograph',
        y_axis_title='Flow',
        y_axis_units='cms',
        series=[
           {
               'name': 'Flood Hydrograph',
               'color': '#0066ff',
               'data': hydrograph,
           },
        ],
        width='500px',
        height='500px'
    )

    context = {'flood_plot': flood_plot}

    return render(request, 'dam_break/hydrograph_ajax.html', context)

#####b. Create html page for chart in templates called hydrograph_ajax.html

{% load tethys_gizmos %}

{% gizmo highcharts_plot_view flood_plot %}

#####c. Add modal to map controller in controllers.py to put plot into

...
    hydrograph_box = MessageBox(name='hydrograph_modal',
                                title='Flood Hydrograph',
                                message='Loading ...')
                            
    # Pass variables to the template via the context dictionary
    context = {'map_options': map_options,
               'hydrograph_box': hydrograph_box}
...

#####d. Add url to ajax function in app.py

...
                    UrlMap(name='hydrograph_ajax',
                           url='dam-break/map/hydrograph',
                           controller='dam_break.controllers.hydrograph_ajax'),
...

#####e. Replace script in map.js

/*****************************************************************************
 *                      LIBRARY WRAPPER
 *****************************************************************************/

var MAP_DAM_BREAK = (function() {
    // Wrap the library in a package function
    "use strict"; // And enable strict mode for this library
    
    /************************************************************************
    *                      MODULE LEVEL / GLOBAL VARIABLES
    *************************************************************************/
    var m_select_interaction, m_selected_feature;

    /************************************************************************
     *                    PRIVATE FUNCTION DECLARATIONS
     *************************************************************************/
    var getModalHTML;


    /************************************************************************
     *                    PRIVATE FUNCTION IMPLEMENTATIONS
     *************************************************************************/
    getModalHTML = function() {
        $.ajax({
            url: 'hydrograph',
            method: 'GET',
            data: {
                'peak_flow': m_selected_feature.get('peak_flow'),
                'time_to_peak': m_selected_feature.get('time_peak'),
                'peak_duration': m_selected_feature.get('peak_duration'),
                'falling_limb_duration': m_selected_feature.get('falling_limb_duration'),
            },
            success: function(data) {
                // add plot data to modal
                $("#hydrograph_modal").find('.modal-body').html(data);
                // display modal
                $('#hydrograph_modal').modal('show');    
                //Initialize Plot
                TETHYS_PLOT_VIEW.initHighChartsPlot($('.highcharts-plot'));
            }
        });
    };

    /************************************************************************
    *                  INITIALIZATION / CONSTRUCTOR
    *************************************************************************/
    
    $(function() {
        m_select_interaction = TETHYS_MAP_VIEW.getSelectInteraction();

        //when selected, call function to make hydrograph
        m_select_interaction.getFeatures().on('change:length', function(e) {
            if (e.target.getArray().length > 0) {
                // this means there is at least 1 feature selected
                m_selected_feature = e.target.item(0); // 1st feature in Collection
                getModalHTML();
            }
        });

        $('#hydrograph_modal').on('hidden.bs.modal', function () {
            m_select_interaction.getFeatures().clear(); //clear selection on close
        });
    }); //document ready
}()); // End of package wrapper 

#####f. Add Highcarts JS to map.html Tethys Platform handles all of the JavaScript libraries for you. However, when using AJAX, you have to do some of the loading yourself.

...
{% block scripts %}
  {{ block.super }}
  <script src="/static/tethys_gizmos/vendor/highcharts/js/highcharts.js" type="text/javascript"></script>
  <script src="/static/tethys_gizmos/vendor/highcharts/js/highcharts-more.js" type="text/javascript"></script>
  <script src="/static/tethys_gizmos/js/plot_view.js" type="text/javascript"></script>
  <script src="{% static 'dam_break/js/map.js' %}" type="text/javascript"></script>
{% endblock %}

#####g. Reload page You need to do a hard refresh (ctrl+r for windows/linux; command+r for mac) to reload the javascript.

Next, click on a dam and see the window pop up.

###6. Check your work The solution to this tutorial is located here: https://github.com/erdc-cm/tethysapp-dam_break/tree/masterjs

Clone this wiki locally