diff --git a/app/assets/scripts/actions/actions.js b/app/assets/scripts/actions/actions.js
index d0ef35d2..06bf6b27 100644
--- a/app/assets/scripts/actions/actions.js
+++ b/app/assets/scripts/actions/actions.js
@@ -12,6 +12,7 @@ module.exports = Reflux.createActions({
'resultsChange': {},
// Results pane related actions.
+ 'resultItemSelect': {},
'resultItemView': {},
'resultListView': {},
'prevResult' : {},
diff --git a/app/assets/scripts/components/map.js b/app/assets/scripts/components/map.js
index 36f8831a..1bfb987a 100644
--- a/app/assets/scripts/components/map.js
+++ b/app/assets/scripts/components/map.js
@@ -24,7 +24,9 @@ var Map = React.createClass({
Reflux.listenTo(actions.mapSquareUnselected, "onMapSquareUnselected"),
Reflux.listenTo(actions.resultOver, "onResultOver"),
Reflux.listenTo(actions.resultOut, "onResultOut"),
+ Reflux.listenTo(actions.resultItemSelect, "onResultItemSelect"),
Reflux.listenTo(actions.resultItemView, "onResultItemView"),
+ Reflux.listenTo(actions.resultListView, "onResultListView"),
Reflux.listenTo(actions.goToLatest, "onGoToLatest"),
Reflux.listenTo(actions.geocoderResult, "onGeocoderResult"),
@@ -38,6 +40,8 @@ var Map = React.createClass({
fauxLineGridLayer: null,
// Layer to store the footprint when hovering a result.
overFootprintLayer: null,
+ // Layer with the image of the selected result.
+ overImageLayer: null,
// When the user clicks browse latest imagery we move the map to the correct
// locations. Then, when the query is finished and the map rendered we
@@ -46,19 +50,45 @@ var Map = React.createClass({
// square that contains it. Check updateGrid()
selectIntersecting: null,
+ getInitialState: function() {
+ return {
+ loading: true
+ };
+ },
+
// Store listener.
onMapData: function(data) {
this.setState({
- mapData: data
+ mapData: data,
+ loading: false
});
},
// Actions listener.
- onResultItemView: function(feature) {
+ onResultItemSelect: function() {
// Remove footprint highlight.
this.overFootprintLayer.clearLayers();
},
+ // Actions listener.
+ onResultItemView: function(item) {
+ if (this.map.hasLayer(this.overImageLayer)) {
+ this.map.removeLayer(this.overImageLayer);
+ }
+
+ var imageBounds = [[item.bbox[1], item.bbox[0]], [item.bbox[3], item.bbox[2]]];
+ this.overImageLayer = L.imageOverlay(item.properties.thumbnail, imageBounds);
+
+ this.map.addLayer(this.overImageLayer);
+ },
+
+ // Actions listener.
+ onResultListView: function() {
+ if (this.map.hasLayer(this.overImageLayer)) {
+ this.map.removeLayer(this.overImageLayer);
+ }
+ },
+
// Actions listener.
onMapSquareSelected: function(sqrFeature) {
var intersected = mapStore.getResultsIntersect(sqrFeature);
@@ -73,6 +103,10 @@ var Map = React.createClass({
// Actions listener.
onMapSquareUnselected: function() {
+ if (this.map.hasLayer(this.overImageLayer)) {
+ this.map.removeLayer(this.overImageLayer);
+ }
+
actions.resultsChange([]);
this.updateGrid();
},
@@ -303,10 +337,10 @@ var Map = React.createClass({
var _this = this;
var view = [60.177, 25.148];
- this.map = L.mapbox.map(this.getDOMNode(), 'devseed.m9i692do', {
+ this.map = L.mapbox.map(this.getDOMNode().querySelector('#map'), 'devseed.m9i692do', {
zoomControl: false,
minZoom : 4,
- maxZoom : 18,
+ //maxZoom : 18,
maxBounds: L.latLngBounds([-90, -180], [90, 180])
}).setView(view, 6);
@@ -355,6 +389,7 @@ var Map = React.createClass({
// Map move listener.
this.map.on('moveend', function() {
+ _this.setState({loading: true});
actions.mapMove(_this.map);
_this.updateFauxGrid();
});
@@ -375,7 +410,10 @@ var Map = React.createClass({
render: function() {
return (
-
+
+ {this.state.loading ?
Loading
: null}
+
+
);
},
diff --git a/app/assets/scripts/components/results_item.js b/app/assets/scripts/components/results_item.js
index ae012904..3a0b24b6 100644
--- a/app/assets/scripts/components/results_item.js
+++ b/app/assets/scripts/components/results_item.js
@@ -38,7 +38,7 @@ var ResultsItem = React.createClass({
return (
diff --git a/app/assets/scripts/components/results_list.js b/app/assets/scripts/components/results_list.js
index 2e0b2537..3b89d2b9 100644
--- a/app/assets/scripts/components/results_list.js
+++ b/app/assets/scripts/components/results_list.js
@@ -6,7 +6,7 @@ var utils = require('../utils/utils');
var ResultsListItem = React.createClass({
onClick: function(e) {
e.preventDefault();
- actions.resultItemView(this.props.data);
+ actions.resultItemSelect(this.props.data);
},
onOver: function(e) {
e.preventDefault();
diff --git a/app/assets/scripts/stores/results_store.js b/app/assets/scripts/stores/results_store.js
index 181e6e25..dd22d54c 100644
--- a/app/assets/scripts/stores/results_store.js
+++ b/app/assets/scripts/stores/results_store.js
@@ -12,7 +12,7 @@ module.exports = Reflux.createStore({
init: function() {
this.listenTo(actions.resultsChange, this.onResultsChange);
- this.listenTo(actions.resultItemView, this.onResultItemView);
+ this.listenTo(actions.resultItemSelect, this.onResultItemSelect);
this.listenTo(actions.resultListView, this.onResultListView);
this.listenTo(actions.nextResult, this.onNextResult);
this.listenTo(actions.prevResult, this.onPrevResult);
@@ -28,8 +28,8 @@ module.exports = Reflux.createStore({
},
// Action listener.
- onResultItemView: function(data) {
- console.log('onImageSelect');
+ onResultItemSelect: function(data) {
+ console.log('onResultItemSelect');
this.storage.selectedItem = data;
// Find the object index.
for (var i in this.storage.results) {
@@ -38,6 +38,7 @@ module.exports = Reflux.createStore({
break;
}
}
+ actions.resultItemView(this.storage.selectedItem);
this.trigger(this.storage);
},
@@ -53,6 +54,7 @@ module.exports = Reflux.createStore({
this.storage.selectedItemIndex++;
var i = this.storage.selectedItemIndex;
this.storage.selectedItem = this.storage.results[i];
+ actions.resultItemView(this.storage.selectedItem);
this.trigger(this.storage);
},
@@ -61,6 +63,7 @@ module.exports = Reflux.createStore({
this.storage.selectedItemIndex--;
var i = this.storage.selectedItemIndex;
this.storage.selectedItem = this.storage.results[i];
+ actions.resultItemView(this.storage.selectedItem);
this.trigger(this.storage);
},
diff --git a/app/assets/scripts/utils/utils.js b/app/assets/scripts/utils/utils.js
index 383817fd..26ce286d 100644
--- a/app/assets/scripts/utils/utils.js
+++ b/app/assets/scripts/utils/utils.js
@@ -38,11 +38,16 @@ module.exports.getPolygonFeature = function(coords) {
/**
* Coverts the given gsb to meters or centimeters
- * @param float gsd
+ * @param float gsd in meters
* @return string
*/
module.exports.gsdToUnit = function(gsd) {
- var cm = gsd * 100 * 100;
- var unit = cm >= 100 ? 'm' : 'cm';
- return Math.round(cm) + ' ' + unit;
-};
\ No newline at end of file
+ var unit = 'm';
+ // If it's less than 1m, convert to cm so it displays more nicely
+ if (gsd < 1) {
+ unit = 'cm';
+ gsd *= 100;
+ }
+
+ return Math.round(gsd) + ' ' + unit;
+};
diff --git a/app/assets/styles/_base.scss b/app/assets/styles/_base.scss
index 21136d96..0153b9e8 100644
--- a/app/assets/styles/_base.scss
+++ b/app/assets/styles/_base.scss
@@ -236,3 +236,46 @@ a:active{
}
}
+
+.loading {
+ @extend .antialiased;
+ position: absolute;
+ z-index: 9980;
+ top: 50%;
+ left: 50%;
+ width: 8rem;
+ height: 8rem;
+ margin: -4rem 0 0 -4rem;
+ background: rgba($base-color, 0.8);
+ padding: 2rem 1rem;
+ border-radius: $global-radius;
+ color: #fff;
+ text-align: center;
+
+ opacity: 0;
+ visibility: hidden;
+ @include transform(scale(0));
+ @include transition(all 0.24s ease 0s);
+
+ &.revealed {
+ opacity: 1;
+ visibility: visible;
+ @include transform(scale(1));
+ }
+
+ &:before {
+ display: block;
+ @extend .icon-spinner;
+ font-size: 2rem;
+ width: 2rem;
+ height: 2rem;
+ line-height: 1;
+ margin: 0 auto 0.5rem auto;
+ @include animation(spin-c 1s linear 0s infinite);
+ }
+}
+
+@include keyframes(spin-c) {
+ from { @include transform(rotate(0deg)); }
+ to { @include transform(rotate(360deg)); }
+}