diff --git a/LICENSE b/LICENSE index 3c5c715..fe354c5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2023 Tethys Platform +Copyright Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -8,4 +8,4 @@ Redistribution and use in source and binary forms, with or without modification, 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/install.yml b/install.yml index ffbaf82..68d19c6 100644 --- a/install.yml +++ b/install.yml @@ -1,5 +1,5 @@ # This file should be committed to your app code. -version: 1.0 +version: 1.1 # This should be greater or equal to your tethys-platform in your environment tethys_version: ">=4.0.0" # This should match the app - package name in your setup.py @@ -10,14 +10,18 @@ requirements: skip: false conda: channels: - - conda-forge + - conda-forge packages: - - earthengine-api - - oauth2client - - geojson - - pyshp + - earthengine-api + - oauth2client + - geojson + - pandas + - pyshp + - simplejson + - djangorestframework + pip: npm: -post: \ No newline at end of file +post: diff --git a/README.md b/readme.md similarity index 100% rename from README.md rename to readme.md diff --git a/setup.py b/setup.py index e07f378..39d2d0a 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,9 @@ dependencies = [] # -- Get Resource File -- # -resource_files = find_all_resource_files(app_package, TethysAppBase.package_namespace) +resource_files = find_all_resource_files( + app_package, TethysAppBase.package_namespace +) with open('README.md', 'r') as f: long_description = f.read() @@ -20,13 +22,13 @@ version='1.0.0', description='A Google Earth Engine demonstration Tethys App.', long_description=long_description, - author='Luke Skywalker', - author_email='lskywalker@example.com', - url='', + author='', + author_email='', + url='', # The URL will be set in a future step. license='BSD-3-Clause', packages=find_namespace_packages(), package_data={'': resource_files}, include_package_data=True, zip_safe=False, install_requires=dependencies, -) \ No newline at end of file +) diff --git a/tethysapp/earth_engine/app.py b/tethysapp/earth_engine/app.py index 9e001cb..53f1e40 100644 --- a/tethysapp/earth_engine/app.py +++ b/tethysapp/earth_engine/app.py @@ -1,13 +1,11 @@ -from tethys_sdk.app_settings import CustomSetting from tethys_sdk.base import TethysAppBase +from tethys_sdk.app_settings import CustomSetting - -class EarthEngine(TethysAppBase): +class App(TethysAppBase): """ Tethys app class for Earth Engine. """ - - name = 'Google Earth Engine Tutorial' + name = 'Earth Engine' description = '' package = 'earth_engine' # WARNING: Do not change this value index = 'home' diff --git a/tethysapp/earth_engine/controllers/home.py b/tethysapp/earth_engine/controllers/home.py index 4509cf1..3963bcb 100644 --- a/tethysapp/earth_engine/controllers/home.py +++ b/tethysapp/earth_engine/controllers/home.py @@ -1,7 +1,8 @@ import logging -from django.shortcuts import render from tethys_sdk.routing import controller +from ..app import App + log = logging.getLogger(f'tethys.apps.{__name__}') @@ -11,7 +12,7 @@ def home(request): Controller for the app home page. """ context = {} - return render(request, 'earth_engine/home.html', context) + return App.render(request, 'home.html', context) @controller @@ -20,4 +21,4 @@ def about(request): Controller for the app about page. """ context = {} - return render(request, 'earth_engine/about.html', context) + return App.render(request, 'about.html', context) \ No newline at end of file diff --git a/tethysapp/earth_engine/controllers/rest.py b/tethysapp/earth_engine/controllers/rest.py index a1a15e0..e41c533 100644 --- a/tethysapp/earth_engine/controllers/rest.py +++ b/tethysapp/earth_engine/controllers/rest.py @@ -1,14 +1,15 @@ -import datetime as dt import logging -import geojson -from django.http import JsonResponse, HttpResponseBadRequest, HttpResponseServerError +from django.http import JsonResponse, HttpResponseBadRequest +from tethys_sdk.routing import controller from rest_framework.authentication import TokenAuthentication from rest_framework.decorators import api_view, authentication_classes -from simplejson import JSONDecodeError -from tethys_sdk.routing import controller +from ..gee.products import EE_PRODUCTS +import datetime as dt from ..helpers import compute_dates_for_product +import geojson +from simplejson import JSONDecodeError +from django.http import HttpResponseServerError from ..gee.methods import get_time_series_from_image_collection -from ..gee.products import EE_PRODUCTS log = logging.getLogger(f'tethys.apps.{__name__}') @@ -145,6 +146,8 @@ def get_time_series(request): f'The "scale" parameter must be a valid number, but "{scale_str}" was given.' ) + + # geometry bad_geometry_msg = 'The "geometry" parameter is required and must be a valid geojson string.' if not geometry_str: @@ -192,3 +195,4 @@ def get_time_series(request): } return JsonResponse(response_data) + diff --git a/tethysapp/earth_engine/controllers/viewer.py b/tethysapp/earth_engine/controllers/viewer.py index 1ebca8f..a377e84 100644 --- a/tethysapp/earth_engine/controllers/viewer.py +++ b/tethysapp/earth_engine/controllers/viewer.py @@ -4,22 +4,23 @@ from simplejson.errors import JSONDecodeError from django.http import JsonResponse, HttpResponseNotAllowed, HttpResponseRedirect -from django.shortcuts import render from tethys_sdk.routing import controller from tethys_sdk.gizmos import SelectInput, DatePicker, Button, MapView, MVView, PlotlyView, MVDraw +from ..app import App + from ..helpers import generate_figure, handle_shapefile_upload, compute_dates_for_product from ..gee.methods import get_image_collection_asset, get_time_series_from_image_collection, \ get_boundary_fc_props_for_user from ..gee.products import EE_PRODUCTS -log = logging.getLogger(f'tethys.apps.{__name__}') +log = logging.getLogger(f'tethys.apps.{__name__}') -@controller(user_workspace=True, url='viewer') -def viewer(request, user_workspace): +@controller(user_media=True, url='viewer') +def viewer(request, user_media): """ - Controller for the app viewer page. + Controller for the app home page. """ default_platform = 'modis' default_sensors = EE_PRODUCTS[default_platform] @@ -115,7 +116,7 @@ def viewer(request, user_workspace): style='outline-secondary', attributes={'id': 'load_map'} ) - + # Get bounding box from user boundary if it exists boundary_props = get_boundary_fc_props_for_user(request.user) @@ -143,7 +144,7 @@ def viewer(request, user_workspace): maxZoom=18, minZoom=2 ), - draw=MVDraw( + draw = MVDraw( controls=['Pan', 'Modify', 'Delete', 'Move', 'Point', 'Polygon', 'Box'], initial='Pan', output_format='GeoJSON' @@ -176,11 +177,10 @@ def viewer(request, user_workspace): 'data-bs-target': '#set-boundary-modal', # ID of the Set Boundary Modal } ) - # Handle Set Boundary Form set_boundary_error = '' if request.POST and request.FILES: - set_boundary_error = handle_shapefile_upload(request, user_workspace) + set_boundary_error = handle_shapefile_upload(request, user_media) if not set_boundary_error: # Redirect back to this page to clear form @@ -202,8 +202,8 @@ def viewer(request, user_workspace): 'map_view': map_view } - return render(request, 'earth_engine/viewer.html', context) + return App.render(request, 'viewer.html', context) @controller(url='viewer/get-image-collection') def get_image_collection(request): @@ -316,4 +316,6 @@ def get_time_series_plot(request): context['error'] = f'An unexpected error has occurred. Please try again.' log.exception('An unexpected error occurred.') - return render(request, 'earth_engine/plot.html', context) + print(context) + return App.render(request, 'plot.html', context) + diff --git a/tethysapp/earth_engine/gee/cloud_mask.py b/tethysapp/earth_engine/gee/cloud_mask.py index 6ffc3bf..ec8a5e9 100644 --- a/tethysapp/earth_engine/gee/cloud_mask.py +++ b/tethysapp/earth_engine/gee/cloud_mask.py @@ -10,7 +10,7 @@ def mask_l8_sr(image): cloudsBitMask = (1 << 5) # Get the pixel QA band. - qa = image.select('pixel_qa') + qa = image.select('QA_PIXEL') # Both flags should be set to zero, indicating clear conditions. mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0).And(qa.bitwiseAnd(cloudsBitMask).eq(0)) @@ -21,7 +21,7 @@ def cloud_mask_l457(image): """ Cloud Mask for Landsat 7 surface reflectance. Derived From: https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LE07_C01_T1_SR """ - qa = image.select('pixel_qa') + qa = image.select('QA_PIXEL') # If the cloud bit (5) is set and the cloud confidence (7) is high # or the cloud shadow bit is set (3), then it's a bad pixel. @@ -46,4 +46,4 @@ def mask_s2_clouds(image): # Both flags should be set to zero, indicating clear conditions. mask = qa.bitwiseAnd(cloudBitMask).eq(0).And(qa.bitwiseAnd(cirrusBitMask).eq(0)) - return image.updateMask(mask).divide(10000) + return image.updateMask(mask).divide(10000) \ No newline at end of file diff --git a/tethysapp/earth_engine/gee/methods.py b/tethysapp/earth_engine/gee/methods.py index 4a0dd1b..7ea6b96 100644 --- a/tethysapp/earth_engine/gee/methods.py +++ b/tethysapp/earth_engine/gee/methods.py @@ -1,18 +1,20 @@ -import math -import os import logging import ee from ee.ee_exception import EEException -import geojson -import pandas as pd from .products import EE_PRODUCTS from . import cloud_mask as cm -from ..app import EarthEngine as app +import geojson +import pandas as pd +import os +import json +import math + +from ..app import App log = logging.getLogger(f'tethys.apps.{__name__}') -service_account = app.get_custom_setting('service_account_email') -private_key_path = app.get_custom_setting('private_key_file') +service_account = App.get_custom_setting('service_account_email') +private_key_path = App.get_custom_setting('private_key_file') if service_account and private_key_path and os.path.isfile(private_key_path): try: @@ -41,7 +43,6 @@ def image_to_map_id(image_name, vis_params={}): except EEException: log.exception('An error occurred while attempting to retrieve the map id.') - def get_image_collection_asset(request, platform, sensor, product, date_from=None, date_to=None, reducer='median'): """ Get tile url for image collection asset. @@ -88,7 +89,6 @@ def get_image_collection_asset(request, platform, sensor, product, date_from=Non except EEException: log.exception('An error occurred while attempting to retrieve the image collection asset.') - def get_time_series_from_image_collection(platform, sensor, product, index_name, scale=30, geometry=None, date_from=None, date_to=None, reducer='median', orient='df'): """ @@ -153,8 +153,7 @@ def get_index(image): log.debug(f'Time Series: {time_series}') return time_series - - + def upload_shapefile_to_gee(user, shp_file): """ Upload a shapefile to Google Earth Engine as an asset. @@ -182,10 +181,9 @@ def upload_shapefile_to_gee(user, shp_file): features.append(ee.Feature(geojson_feature)) feature_collection = ee.FeatureCollection(features) - # Get unique folder for each user to story boundary asset user_boundary_asset_path = get_user_boundary_path(user) - + # Overwrite an existing asset with this name by deleting it first try: ee.batch.data.deleteAsset(user_boundary_asset_path) @@ -204,7 +202,6 @@ def upload_shapefile_to_gee(user, shp_file): task.start() - def get_asset_dir_for_user(user): """ Get a unique asset directory for given user. @@ -247,7 +244,6 @@ def get_asset_dir_for_user(user): return user_root_dir - def get_user_boundary_path(user): """ Get a unique path for the user boundary asset. @@ -262,7 +258,6 @@ def get_user_boundary_path(user): user_boundary_asset_path = os.path.join(user_asset_dir, 'boundary') return user_boundary_asset_path - def get_boundary_fc_for_user(user): """ Get the boundary FeatureClass for the given user if it exists. @@ -285,7 +280,6 @@ def get_boundary_fc_for_user(user): return None - def get_boundary_fc_props_for_user(user): """ Get various properties of the boundary FeatureCollection. @@ -324,4 +318,4 @@ def get_boundary_fc_props_for_user(user): 'centroid': centroid.get('coordinates') } - return fc_props + return fc_props \ No newline at end of file diff --git a/tethysapp/earth_engine/gee/params.py b/tethysapp/earth_engine/gee/params.py new file mode 100644 index 0000000..a6274d1 --- /dev/null +++ b/tethysapp/earth_engine/gee/params.py @@ -0,0 +1,4 @@ +from pathlib import Path + +service_account = '' # your google service account +private_key = '' # path to the json private key for the service account diff --git a/tethysapp/earth_engine/gee/products.py b/tethysapp/earth_engine/gee/products.py index b3cb5f5..6641c4a 100644 --- a/tethysapp/earth_engine/gee/products.py +++ b/tethysapp/earth_engine/gee/products.py @@ -3,7 +3,7 @@ 'terra': { 'snow': { 'display': 'Snow Cover Daily Global 500m', - 'collection': 'MODIS/006/MOD10A1', + 'collection': 'MODIS/061/MOD10A1', 'index': 'NDSI_Snow_Cover', 'vis_params': { 'min': 0.0, @@ -15,7 +15,7 @@ }, 'temperature': { 'display': 'Land Surface Temperature and Emissivity Daily Global 1km', - 'collection': 'MODIS/006/MOD11A1', + 'collection': 'MODIS/061/MOD11A1', 'index': 'LST_Day_1km', 'vis_params': { 'min': 13000.0, @@ -98,91 +98,63 @@ } }, 'landsat': { - '7': { + '8': { 'surface': { 'display': 'Surface Reflectance', - 'collection': 'LANDSAT/LE07/C01/T1_SR', + 'collection': 'LANDSAT/LC08/C02/T1_L2', 'index': None, 'vis_params': { - 'bands': ['B3', 'B2', 'B1'], + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], 'min': 0, 'max': 3000, 'gamma': 1.4, }, - 'cloud_mask': 'cloud_mask_l457', - 'start_date': '1999-01-01', - 'end_date': None # to present - }, - 'evi': { - 'display': '8-day Enhanced Vegetation Index (EVI)', - 'collection': 'LANDSAT/LE07/C01/T1_8DAY_EVI', - 'index': 'EVI', - 'vis_params': { - 'min': 0.0, - 'max': 1.0, - 'palette': [ - 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', - '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01', - '012E01', '011D01', '011301' - ], - }, - 'start_date': '1999-01-01', + 'cloud_mask': 'mask_l8_sr', + 'start_date': '2013-04-01', 'end_date': None # to present }, - 'ndwi': { - 'display': '8-day Normalized Difference Water Index (NDWI)', - 'collection': 'LANDSAT/LE07/C01/T1_8DAY_NDWI', - 'index': 'NDWI', + 'toa': { + 'display': 'Top-of-Atmosphere(TOA) Reflectance', + 'collection': 'LANDSAT/LC08/C02/T1_TOA', + 'index': None, 'vis_params': { - 'min': 0.0, - 'max': 1.0, - 'palette': ['0000ff', '00ffff', 'ffff00', 'ff0000', 'ffffff'], + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 3000, + 'gamma': 1.4, }, - 'start_date': '1999-01-01', + 'start_date': '2013-04-01', 'end_date': None # to present }, }, - '8': { + '9': { 'surface': { 'display': 'Surface Reflectance', - 'collection': 'LANDSAT/LC08/C01/T1_SR', + 'collection': 'LANDSAT/LC09/C02/T1_L2', 'index': None, 'vis_params': { - 'bands': ['B4', 'B3', 'B2'], + 'bands': ['SR_B4', 'SR_B3', 'SR_B2'], 'min': 0, 'max': 3000, 'gamma': 1.4, }, 'cloud_mask': 'mask_l8_sr', - 'start_date': '2013-04-01', + 'start_date': '2021-10-31', 'end_date': None # to present }, - 'ndvi': { - 'display': '8-day Normalized Difference Vegetation (NDVI)', - 'collection': 'LANDSAT/LC08/C01/T1_8DAY_NDVI', - 'index': 'NDVI', - 'vis_params': { - 'min': 0.0, - 'max': 1.0, - 'palette': [ - 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', - '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01', - '012E01', '011D01', '011301' - ], - }, - 'start_date': '2013-04-01', - 'end_date': None # to present - }, - 'ndsi': { - 'display': '8-day Normalized Difference Snow Index (NDSI)', - 'collection': 'LANDSAT/LC08/C01/T1_8DAY_NDSI', - 'index': 'NDSI', + 'toa': { + 'display': 'Top-of-Atmosphere(TOA) Reflectance', + 'collection': 'LANDSAT/LC09/C02/T1_TOA', + 'index': None, 'vis_params': { - 'palette': ['000088', '0000FF', '8888FF', 'FFFFFF'], + 'bands': ['B4', 'B3', 'B2'], + 'min': 0, + 'max': 3000, + 'gamma': 1.4, }, - 'start_date': '2013-04-01', + 'start_date': '2021-10-31', 'end_date': None # to present }, } } -} +} \ No newline at end of file diff --git a/tethysapp/earth_engine/helpers.py b/tethysapp/earth_engine/helpers.py index da759bc..584bb43 100644 --- a/tethysapp/earth_engine/helpers.py +++ b/tethysapp/earth_engine/helpers.py @@ -1,18 +1,17 @@ -import datetime as dt +import pandas as pd +from plotly import graph_objs as go import os -import logging -import glob import tempfile import zipfile -import ee -import pandas as pd -from plotly import graph_objs as go import shapefile +import glob +import logging +import ee from .gee.methods import upload_shapefile_to_gee +import datetime as dt log = logging.getLogger(f'tethys.apps.{__name__}') - def generate_figure(figure_title, time_series): """ Generate a figure from a list of time series Pandas DataFrames. @@ -61,14 +60,12 @@ def generate_figure(figure_title, time_series): return figure - -def handle_shapefile_upload(request, user_workspace): +def handle_shapefile_upload(request, user_media): """ Uploads shapefile to Google Earth Engine as an Asset. Args: request (django.Request): the request object. - user_workspace (tethys_sdk.workspaces.Workspace): the User workspace object. Returns: str: Error string if errors occurred. @@ -92,7 +89,7 @@ def handle_shapefile_upload(request, user_workspace): except zipfile.BadZipFile: # Return error message return 'You must provide a zip archive containing a shapefile.' - + # Verify that it contains a shapefile try: # Find a shapefile in directory where we extracted the archive @@ -106,11 +103,11 @@ def handle_shapefile_upload(request, user_workspace): if shp_file.shapeType != shapefile.POLYGON: return 'Only shapefiles containing Polygons are supported.' - # Setup workspace directory for storing shapefile - workspace_dir = prep_boundary_dir(user_workspace.path) + # Setup user media directory for storing shapefile + media_dir = prep_boundary_dir(user_media.path) - # Write the shapefile to the workspace directory - write_boundary_shapefile(shp_file, workspace_dir) + # Write the shapefile to the media directory + write_boundary_shapefile(shp_file, media_dir) # Upload shapefile as Asset in GEE upload_shapefile_to_gee(request.user, shp_file) @@ -122,8 +119,7 @@ def handle_shapefile_upload(request, user_workspace): msg = 'An unexpected error occurred while uploading the shapefile to Google Earth Engine.' log.exception(msg) return msg - - + def find_shapefile(directory): """ Recursively find the path to the first file with an extension ".shp" in the given directory. @@ -148,7 +144,6 @@ def find_shapefile(directory): return shapefile_path - def prep_boundary_dir(root_path): """ Setup the workspace directory that will store the uploaded boundary shapefile. @@ -177,7 +172,6 @@ def prep_boundary_dir(root_path): return boundary_dir - def write_boundary_shapefile(shp_file, directory): """ Write the shapefile to the given directory. The shapefile will be called "boundary.shp". @@ -204,7 +198,6 @@ def write_boundary_shapefile(shp_file, directory): return shapefile_path - def compute_dates_for_product(product_dict): """ Compute default dates and date range for given product. @@ -236,4 +229,4 @@ def compute_dates_for_product(product_dict): 'end_valid_date_range': end_valid_date_range } - return product_dates + return product_dates \ No newline at end of file diff --git a/tethysapp/earth_engine/public/css/about.css b/tethysapp/earth_engine/public/css/about.css index 2674735..58978cf 100644 --- a/tethysapp/earth_engine/public/css/about.css +++ b/tethysapp/earth_engine/public/css/about.css @@ -1,24 +1,24 @@ .page-header h1 { - text-align: center; - font-size: 48pt; - color: black; + text-align: center; + font-size: 48pt; + color: black; } .about-img { - width: 100%; - max-width: 360px; - margin-bottom: 20px; + width: 100%; + max-width: 360px; + margin-bottom: 20px; } .about-footer-content { - text-align: center; - margin: 50px 0 100px 0; -} - -.about-footer-content h3 { - margin-bottom: 26px; -} - -.about-footer-content img { - margin: 0 5px; -} \ No newline at end of file + text-align: center; + margin: 50px 0 100px 0; + } + + .about-footer-content h3 { + margin-bottom: 26px; + } + + .about-footer-content img { + margin: 0 5px; + } \ No newline at end of file diff --git a/tethysapp/earth_engine/public/css/home.css b/tethysapp/earth_engine/public/css/home.css index bde0dd0..0644092 100644 --- a/tethysapp/earth_engine/public/css/home.css +++ b/tethysapp/earth_engine/public/css/home.css @@ -1,76 +1,75 @@ -#inner-app-content { - padding: 0; -} - .info-container { - background-color: #0000009f; - box-shadow: 3px 5px 3px rgba(0,0,0,0.35); - padding: 10px; - margin-bottom: 30px; + background-color: #0000009f; + box-shadow: 3px 5px 3px rgba(0,0,0,0.35); + padding: 10px; + margin-bottom: 30px; } .info-container .info-title { - color: #067ef5; - text-shadow: 2px 2px #000000; + color: #067ef5; + text-shadow: 2px 2px #000000; } .info-container p { - color: #eee; - text-shadow: 2px 2px #000000; - font-size: 16px; + color: #eee; + text-shadow: 2px 2px #000000; + font-size: 16px; } .info-container .media-body { - color: #eee; - text-shadow: 2px 2px #000000; + color: #eee; + text-shadow: 2px 2px #000000; } .info-container .media-object { - border-radius: 5px; + border-radius: 5px; } .info-container .media-heading { - color: #eee; - text-shadow: 2px 2px #000000; + color: #eee; + text-shadow: 2px 2px #000000; } #feature-image { - width: 100%; + width: 100%; } - #get-started-btn { - display: inline-block; - border-radius: 15px; - padding: 5px 10px; - background-color: #fff; - color: #044777; - border: solid 2px rgb(6, 126, 245); - text-transform: uppercase; - font-weight: 600; - align-items: center; - font-size: 14pt; - cursor: pointer; - width: fit-content; - text-decoration: none !important; - justify-content: center; - margin: 10px 0; + display: inline-block; + border-radius: 15px; + padding: 5px 10px; + background-color: #fff; + color: #044777; + border: solid 2px rgb(6, 126, 245); + text-transform: uppercase; + font-weight: 600; + align-items: center; + font-size: 14pt; + cursor: pointer; + width: fit-content; + text-decoration: none !important; + justify-content: center; + margin: 10px 0; } #get-started-btn:hover { - background-color: #eee; + background-color: #eee; } #get-started-btn:active, #get-started-btn:focus { - background-color: #044777; - color: white; + background-color: #044777; + color: white; } #home-content-container { - padding: 20px; - min-height: 100%; - background: url('/static/earth_engine/images/earth-engine-backdrop.png'); - background-color: #d2dadc; - background-position: center; - background-repeat: no-repeat + padding: 20px; + min-height: 100%; + background: url('/static/earth_engine/images/earth-engine-backdrop.png'); + background-color: #d2dadc; + background-position: center; + background-repeat: no-repeat +} + +#inner-app-content { + padding: 0; } \ No newline at end of file diff --git a/tethysapp/earth_engine/public/images/earth-engine-viewer.png b/tethysapp/earth_engine/public/images/earth-engine-viewer.png index 2d784ed..b897825 100644 Binary files a/tethysapp/earth_engine/public/images/earth-engine-viewer.png and b/tethysapp/earth_engine/public/images/earth-engine-viewer.png differ diff --git a/tethysapp/earth_engine/public/images/icon.gif b/tethysapp/earth_engine/public/images/icon.gif new file mode 100644 index 0000000..5c8236e Binary files /dev/null and b/tethysapp/earth_engine/public/images/icon.gif differ diff --git a/tethysapp/earth_engine/public/images/map-loader.gif b/tethysapp/earth_engine/public/images/map-loader.gif index 74da381..0ee0c73 100644 Binary files a/tethysapp/earth_engine/public/images/map-loader.gif and b/tethysapp/earth_engine/public/images/map-loader.gif differ diff --git a/tethysapp/earth_engine/public/js/gee_datasets.js b/tethysapp/earth_engine/public/js/gee_datasets.js index ff11280..2e451c3 100644 --- a/tethysapp/earth_engine/public/js/gee_datasets.js +++ b/tethysapp/earth_engine/public/js/gee_datasets.js @@ -24,14 +24,13 @@ var GEE_DATASETS = (function() { // Map Variables var m_map, - m_gee_layer; + m_gee_layer; /************************************************************************ * PRIVATE FUNCTION DECLARATIONS *************************************************************************/ // Dataset Select Methods var bind_controls, update_product_options, update_sensor_options, update_date_bounds, collect_data; - // Map Methods var update_map, update_data_layer, create_data_layer, clear_map; @@ -45,7 +44,7 @@ var GEE_DATASETS = (function() { bind_controls = function() { $('#platform').on('change', function() { let platform = $('#platform').val(); - + if (platform !== m_platform) { m_platform = platform; console.log(`Platform Changed to: ${m_platform}`); @@ -53,10 +52,10 @@ var GEE_DATASETS = (function() { update_sensor_options(); } }); - + $('#sensor').on('change', function() { let sensor = $('#sensor').val(); - + if (sensor !== m_sensor) { m_sensor = sensor; console.log(`Sensor Changed to: ${m_sensor}`); @@ -64,10 +63,10 @@ var GEE_DATASETS = (function() { update_product_options(); } }); - + $('#product').on('change', function() { let product = $('#product').val(); - + if (product !== m_product) { m_product = product; console.log(`Product Changed to: ${m_product}`); @@ -75,34 +74,33 @@ var GEE_DATASETS = (function() { update_date_bounds(); } }); - + $('#start_date').on('change', function() { let start_date = $('#start_date').val(); - + if (start_date !== m_start_date) { m_start_date = start_date; console.log(`Start Date Changed to: ${m_start_date}`); } }); - + $('#end_date').on('change', function() { let end_date = $('#end_date').val(); - + if (end_date !== m_end_date) { m_end_date = end_date; console.log(`End Date Changed to: ${m_end_date}`); } }); - + $('#reducer').on('change', function() { let reducer = $('#reducer').val(); - + if (reducer !== m_reducer) { m_reducer = reducer; console.log(`Reducer Changed to: ${m_reducer}`); } }); - $('#load_map').on('click', function() { update_map(); }); @@ -209,12 +207,11 @@ var GEE_DATASETS = (function() { product: m_product, start_date: m_start_date, end_date: m_end_date, - reducer: m_reducer, + reducer: m_reducer, geometry: get_geometry() }; return data; }; - // Map Methods update_map = function() { let data = collect_data(); @@ -249,25 +246,25 @@ var GEE_DATASETS = (function() { url: url, attributions: 'Google Earth Engine' }); - + source.on('tileloadstart', function() { $('#loader').addClass('show'); }); - + source.on('tileloadend', function() { $('#loader').removeClass('show'); }); - + source.on('tileloaderror', function() { $('#loader').removeClass('show'); }); - + m_gee_layer = new ol.layer.Tile({ source: source, opacity: 0.7 }); - // Insert below the draw layer (so drawn polygons and points render on top of the data layer). + // Insert below the draw layer (so drawn polygons and points render on top of data layer). m_map.getLayers().insertAt(1, m_gee_layer); }; @@ -301,7 +298,7 @@ var GEE_DATASETS = (function() { '' ); $('#plot-modal').modal('show'); - }; + } /************************************************************************ * PUBLIC INTERFACE @@ -314,10 +311,10 @@ var GEE_DATASETS = (function() { $(function() { // Initialize Global Variables bind_controls(); - + // EE Products EE_PRODUCTS = $('#ee-products').data('ee-products'); - + // Initialize values m_platform = $('#platform').val(); m_sensor = $('#sensor').val(); @@ -325,7 +322,7 @@ var GEE_DATASETS = (function() { INITIAL_START_DATE = m_start_date = $('#start_date').val(); INITIAL_END_DATE = m_end_date = $('#end_date').val(); m_reducer = $('#reducer').val(); - + m_map = TETHYS_MAP_VIEW.getMap(); // Open boundary file modal if it has an error diff --git a/tethysapp/earth_engine/workspaces/app_workspace/.gitkeep b/tethysapp/earth_engine/resources/.gitkeep similarity index 100% rename from tethysapp/earth_engine/workspaces/app_workspace/.gitkeep rename to tethysapp/earth_engine/resources/.gitkeep diff --git a/tethysapp/earth_engine/templates/earth_engine/about.html b/tethysapp/earth_engine/templates/earth_engine/about.html index b2390bf..6e89699 100644 --- a/tethysapp/earth_engine/templates/earth_engine/about.html +++ b/tethysapp/earth_engine/templates/earth_engine/about.html @@ -1,9 +1,9 @@ {% extends "tethys_apps/app_header_content.html" %} -{% load static %} +{% load static tethys %} {% block styles %} {{ block.super }} - + {% endblock %} {% block header_buttons %} @@ -11,49 +11,49 @@ {% endblock %} {% block app_content %} -
+
-
+
{% endblock %} {% block after_app_content %} diff --git a/tethysapp/earth_engine/templates/earth_engine/base.html b/tethysapp/earth_engine/templates/earth_engine/base.html index 6ca00b0..e45b3c2 100644 --- a/tethysapp/earth_engine/templates/earth_engine/base.html +++ b/tethysapp/earth_engine/templates/earth_engine/base.html @@ -1,6 +1,6 @@ {% extends "tethys_apps/app_base.html" %} -{% load static %} +{% load static tethys %} {% block title %}{{ tethys_app.name }}{% endblock %} @@ -13,7 +13,7 @@ {% block app_title %}{{ tethys_app.name }}{% endblock %} {% block header_buttons %} - {% include "earth_engine/header_buttons.html" %} + {% include tethys_app.package|add:"/header_buttons.html" %} {% endblock %} {% block app_navigation_items %} @@ -32,20 +32,20 @@ {% block app_content %} {% endblock %} -{% block app_actions_override %} -{% endblock %} - {% block after_app_content %} {{ block.super }} {% include "earth_engine/disclaimer.html" %} {% endblock %} +{% block app_actions_override %} +{% endblock %} + {% block content_dependent_styles %} {{ block.super }} - + {% endblock %} {% block scripts %} {{ block.super }} - + {% endblock %} \ No newline at end of file diff --git a/tethysapp/earth_engine/templates/earth_engine/disclaimer.html b/tethysapp/earth_engine/templates/earth_engine/disclaimer.html index 78b9e17..5c79850 100644 --- a/tethysapp/earth_engine/templates/earth_engine/disclaimer.html +++ b/tethysapp/earth_engine/templates/earth_engine/disclaimer.html @@ -1,58 +1,57 @@ -