kopia lustrzana https://github.com/OpenDroneMap/WebODM
Merge pull request #1597 from pierotofy/multilayer
Simultaneous map items display and swipe viewpull/1604/head
commit
beb7ded028
|
@ -53,11 +53,12 @@ class MapView extends React.Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
selectedMapType,
|
selectedMapType,
|
||||||
tiles: this.getTilesByMapType(selectedMapType)
|
tiles: this.tilesFromMapType(selectedMapType)
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getTilesByMapType = this.getTilesByMapType.bind(this);
|
this.tilesFromMapType = this.tilesFromMapType.bind(this);
|
||||||
this.handleMapTypeButton = this.handleMapTypeButton.bind(this);
|
this.handleMapTypeButton = this.handleMapTypeButton.bind(this);
|
||||||
|
this.hasTilesOfType = this.hasTilesOfType.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
isThermalMap = () => {
|
isThermalMap = () => {
|
||||||
|
@ -75,17 +76,18 @@ class MapView extends React.Component {
|
||||||
return thermalCount === this.props.mapItems.length;
|
return thermalCount === this.props.mapItems.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTilesByMapType(type){
|
tilesFromMapType(type){
|
||||||
// Go through the list of map items and return
|
// Go through the list of map items and return
|
||||||
// only those that match a particular type (in tile format)
|
// only those that match a particular type (in tile format)
|
||||||
const tiles = [];
|
const tiles = [];
|
||||||
|
|
||||||
this.props.mapItems.forEach(mapItem => {
|
this.props.mapItems.forEach(mapItem => {
|
||||||
mapItem.tiles.forEach(tile => {
|
mapItem.tiles.forEach(tile => {
|
||||||
if (tile.type === type) tiles.push({
|
tiles.push({
|
||||||
url: tile.url,
|
url: tile.url,
|
||||||
meta: mapItem.meta,
|
meta: mapItem.meta,
|
||||||
type: tile.type
|
type: tile.type,
|
||||||
|
selected: tile.type === type
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -93,11 +95,22 @@ class MapView extends React.Component {
|
||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasTilesOfType(type){
|
||||||
|
for (let i = 0; i < this.props.mapItems.length; i++){
|
||||||
|
let mapItem = this.props.mapItems[i];
|
||||||
|
for (let j = 0; j < mapItem.tiles.length; j++){
|
||||||
|
let tile = mapItem.tiles[j];
|
||||||
|
if (tile.type === type) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
handleMapTypeButton(type){
|
handleMapTypeButton(type){
|
||||||
return () => {
|
return () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedMapType: type,
|
selectedMapType: type,
|
||||||
tiles: this.getTilesByMapType(type)
|
tiles: this.tilesFromMapType(type)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -126,7 +139,7 @@ class MapView extends React.Component {
|
||||||
type: "dtm",
|
type: "dtm",
|
||||||
icon: "fa fa-chart-area"
|
icon: "fa fa-chart-area"
|
||||||
}
|
}
|
||||||
].filter(mapType => this.getTilesByMapType(mapType.type).length > 0 );
|
].filter(mapType => this.hasTilesOfType(mapType.type));
|
||||||
|
|
||||||
// If we have only one button, hide it...
|
// If we have only one button, hide it...
|
||||||
if (mapTypeButtons.length === 1) mapTypeButtons = [];
|
if (mapTypeButtons.length === 1) mapTypeButtons = [];
|
||||||
|
|
|
@ -29,7 +29,9 @@ export default {
|
||||||
"deleteAnnotation",
|
"deleteAnnotation",
|
||||||
"toggleAnnotation",
|
"toggleAnnotation",
|
||||||
"annotationDeleted",
|
"annotationDeleted",
|
||||||
"downloadAnnotations"
|
"downloadAnnotations",
|
||||||
|
"mapTypeChanged",
|
||||||
|
"sideBySideChanged",
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ export default L.Control.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
update: function(layers, overlays, annotations){
|
update: function(layers, overlays, annotations){
|
||||||
ReactDOM.render(<LayersControlButton map={this.map} layers={layers} overlays={overlays} annotations={annotations} />, this.container);
|
ReactDOM.render(<LayersControlButton ref={r => this.layersControlButton = r} map={this.map} layers={layers} overlays={overlays} annotations={annotations} />, this.container);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -115,8 +115,10 @@ export default class LayersControlAnnotations extends React.Component {
|
||||||
componentDidUpdate(prevProps, prevState){
|
componentDidUpdate(prevProps, prevState){
|
||||||
if (prevState.visible !== this.state.visible){
|
if (prevState.visible !== this.state.visible){
|
||||||
this.annRefs.forEach(ann => {
|
this.annRefs.forEach(ann => {
|
||||||
|
if (ann){
|
||||||
let visible = this.state.visible ? ann.state.visible : false;
|
let visible = this.state.visible ? ann.state.visible : false;
|
||||||
PluginsAPI.Map.toggleAnnotation(ann.props.layer, visible);
|
PluginsAPI.Map.toggleAnnotation(ann.props.layer, visible);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Utils from '../classes/Utils';
|
||||||
import Workers from '../classes/Workers';
|
import Workers from '../classes/Workers';
|
||||||
import ErrorMessage from './ErrorMessage';
|
import ErrorMessage from './ErrorMessage';
|
||||||
import ExportAssetPanel from './ExportAssetPanel';
|
import ExportAssetPanel from './ExportAssetPanel';
|
||||||
|
import PluginsAPI from '../classes/plugins/API';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { _, interpolate } from '../classes/gettext';
|
import { _, interpolate } from '../classes/gettext';
|
||||||
|
|
||||||
|
@ -15,14 +16,16 @@ export default class LayersControlLayer extends React.Component {
|
||||||
layer: null,
|
layer: null,
|
||||||
expanded: false,
|
expanded: false,
|
||||||
map: null,
|
map: null,
|
||||||
overlay: false
|
overlay: false,
|
||||||
|
separator: false,
|
||||||
};
|
};
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
layer: PropTypes.object.isRequired,
|
layer: PropTypes.object.isRequired,
|
||||||
expanded: PropTypes.bool,
|
expanded: PropTypes.bool,
|
||||||
map: PropTypes.object.isRequired,
|
map: PropTypes.object.isRequired,
|
||||||
overlay: PropTypes.bool
|
overlay: PropTypes.bool,
|
||||||
}
|
separator: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props){
|
constructor(props){
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -63,6 +66,7 @@ export default class LayersControlLayer extends React.Component {
|
||||||
hillshade: params.hillshade || "",
|
hillshade: params.hillshade || "",
|
||||||
histogramLoading: false,
|
histogramLoading: false,
|
||||||
exportLoading: false,
|
exportLoading: false,
|
||||||
|
side: false,
|
||||||
error: ""
|
error: ""
|
||||||
};
|
};
|
||||||
this.rescale = params.rescale || "";
|
this.rescale = params.rescale || "";
|
||||||
|
@ -72,14 +76,46 @@ export default class LayersControlLayer extends React.Component {
|
||||||
return this.props.layer._url || "";
|
return this.props.layer._url || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
PluginsAPI.Map.onMapTypeChanged(this.handleMapTypeChange);
|
||||||
|
PluginsAPI.Map.onSideBySideChanged(this.handleSideBySideChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMapTypeChange = (type, autoExpand) => {
|
||||||
|
if (this.meta.type !== undefined){
|
||||||
|
const visible = this.meta.type === type;
|
||||||
|
const expanded = visible && autoExpand;
|
||||||
|
this.setState({visible, expanded});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSideBySideChange = (layer, side) => {
|
||||||
|
// Toggle this layer's side off if it was previously sided
|
||||||
|
// when another layer is set to side
|
||||||
|
if (this.props.layer !== layer && this.state.side && side){
|
||||||
|
setTimeout(() => {
|
||||||
|
let visible = this.state.visible;
|
||||||
|
if (this.wasInvisibleOnSideClick){
|
||||||
|
visible = false;
|
||||||
|
this.wasInvisibleOnSideClick = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ side: false, visible });
|
||||||
|
PluginsAPI.Map.sideBySideChanged(this.props.layer, false);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState){
|
componentDidUpdate(prevProps, prevState){
|
||||||
const { layer } = this.props;
|
const { layer } = this.props;
|
||||||
|
|
||||||
if (prevState.visible !== this.state.visible){
|
if (prevState.visible !== this.state.visible){
|
||||||
if (this.state.visible){
|
if (this.state.visible){
|
||||||
layer.addTo(this.map);
|
if (layer.show) layer.show();
|
||||||
|
else if (!this.map.hasLayer(layer)) layer.addTo(this.map);
|
||||||
}else{
|
}else{
|
||||||
this.map.removeLayer(layer);
|
if (layer.hide) layer.hide();
|
||||||
|
else this.map.removeLayer(layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +129,7 @@ export default class LayersControlLayer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevProps.expanded !== this.props.expanded){
|
if (prevProps.expanded !== this.props.expanded){
|
||||||
this.state.expanded = this.props.expanded;
|
this.setState({expanded: this.props.expanded});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +143,9 @@ export default class LayersControlLayer extends React.Component {
|
||||||
this.exportReq.abort();
|
this.exportReq.abort();
|
||||||
this.exportReq = null;
|
this.exportReq = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PluginsAPI.Map.offSideBySideChanged(this.handleSideBySideChange);
|
||||||
|
PluginsAPI.Map.offMapTypeChanged(this.handleMapTypeChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleZoomToClick = () => {
|
handleZoomToClick = () => {
|
||||||
|
@ -120,6 +159,32 @@ export default class LayersControlLayer extends React.Component {
|
||||||
if (layer.getPopup()) layer.openPopup();
|
if (layer.getPopup()) layer.openPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSideClick = () => {
|
||||||
|
let { side, visible } = this.state;
|
||||||
|
|
||||||
|
if (!side){
|
||||||
|
side = true;
|
||||||
|
if (!visible){
|
||||||
|
visible = true;
|
||||||
|
this.wasInvisibleOnSideClick = true;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
side = false;
|
||||||
|
if (this.wasInvisibleOnSideClick){
|
||||||
|
visible = false;
|
||||||
|
this.wasInvisibleOnSideClick = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ side, visible });
|
||||||
|
PluginsAPI.Map.sideBySideChanged(this.props.layer, side);
|
||||||
|
}
|
||||||
|
|
||||||
|
sideIcon = () => {
|
||||||
|
if (!this.state.side) return "fa-divide fa-rotate-90";
|
||||||
|
else return "fa-chevron-right";
|
||||||
|
}
|
||||||
|
|
||||||
handleLayerClick = () => {
|
handleLayerClick = () => {
|
||||||
if (this.props.overlay){
|
if (this.props.overlay){
|
||||||
this.setState({visible: !this.state.visible});
|
this.setState({visible: !this.state.visible});
|
||||||
|
@ -296,8 +361,8 @@ export default class LayersControlLayer extends React.Component {
|
||||||
|
|
||||||
return (<div className="layers-control-layer">
|
return (<div className="layers-control-layer">
|
||||||
<div className="layer-control-title">
|
<div className="layer-control-title">
|
||||||
{!this.props.overlay ? <ExpandButton bind={[this, 'expanded']} /> : <div className="paddingSpace"></div>}<Checkbox bind={[this, 'visible']}/>
|
{!this.props.overlay ? <ExpandButton bind={[this, 'expanded']} className="expand-layer" /> : <div className="paddingSpace"></div>}<Checkbox bind={[this, 'visible']}/>
|
||||||
<a title={meta.name} className="layer-label" href="javascript:void(0);" onClick={this.handleLayerClick}><i className={"layer-icon " + (meta.icon || "fa fa-vector-square fa-fw")}></i><div className="layer-title">{meta.name}</div></a> <a className="layer-action" href="javascript:void(0)" onClick={this.handleZoomToClick}><i title={_("Zoom To")} className="fa fa-expand"></i></a>
|
<a title={meta.name} className="layer-label" href="javascript:void(0);" onClick={this.handleLayerClick}><i className={"layer-icon " + (meta.icon || "fa fa-vector-square fa-fw")}></i><div className="layer-title">{meta.name}</div></a> {meta.raster ? <a className="layer-action" href="javascript:void(0)" onClick={this.handleSideClick}><i title={_("Side By Side")} className={"fa fa-fw " + this.sideIcon()}></i></a> : ""}<a className="layer-action" href="javascript:void(0)" onClick={this.handleZoomToClick}><i title={_("Zoom To")} className="fa fa-expand"></i></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{this.state.expanded ?
|
{this.state.expanded ?
|
||||||
|
@ -370,6 +435,8 @@ export default class LayersControlLayer extends React.Component {
|
||||||
asset={this.asset}
|
asset={this.asset}
|
||||||
exportParams={this.getLayerParams}
|
exportParams={this.getLayerParams}
|
||||||
dropUp />
|
dropUp />
|
||||||
|
|
||||||
|
{this.props.separator ? <hr className="layer-separator" /> : ""}
|
||||||
</div> : ""}
|
</div> : ""}
|
||||||
</div>);
|
</div>);
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,14 @@ export default class LayersControlPanel extends React.Component {
|
||||||
{group.layers.sort((a, b) => {
|
{group.layers.sort((a, b) => {
|
||||||
const m_a = a[Symbol.for("meta")] || {};
|
const m_a = a[Symbol.for("meta")] || {};
|
||||||
const m_b = b[Symbol.for("meta")] || {};
|
const m_b = b[Symbol.for("meta")] || {};
|
||||||
return m_a.name > m_b.name ? -1 : 1;
|
return m_a.type > m_b.type ? -1 : 1;
|
||||||
}).map((layer, i) => <LayersControlLayer map={this.props.map} expanded={this.props.layers.length === 1} overlay={false} layer={layer} key={i} />)}
|
}).map((layer, i) => <LayersControlLayer map={this.props.map}
|
||||||
|
expanded={(layer[Symbol.for("meta")] || {}).autoExpand || false}
|
||||||
|
overlay={false}
|
||||||
|
layer={layer}
|
||||||
|
key={`${i}-${(layer[Symbol.for("meta")] || {}).type}`}
|
||||||
|
separator={i < group.layers.length - 1}
|
||||||
|
/>)}
|
||||||
</div>);
|
</div>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import Utils from '../classes/Utils';
|
||||||
import '../vendor/leaflet/Leaflet.Ajax';
|
import '../vendor/leaflet/Leaflet.Ajax';
|
||||||
import 'rbush';
|
import 'rbush';
|
||||||
import '../vendor/leaflet/leaflet-markers-canvas';
|
import '../vendor/leaflet/leaflet-markers-canvas';
|
||||||
|
import '../vendor/leaflet/Leaflet.SideBySide/leaflet-side-by-side';
|
||||||
import { _ } from '../classes/gettext';
|
import { _ } from '../classes/gettext';
|
||||||
import UnitSelector from './UnitSelector';
|
import UnitSelector from './UnitSelector';
|
||||||
import { unitSystem, toMetric } from '../classes/Units';
|
import { unitSystem, toMetric } from '../classes/Units';
|
||||||
|
@ -63,12 +64,14 @@ class Map extends React.Component {
|
||||||
opacity: 100,
|
opacity: 100,
|
||||||
imageryLayers: [],
|
imageryLayers: [],
|
||||||
overlays: [],
|
overlays: [],
|
||||||
annotations: []
|
annotations: [],
|
||||||
|
rightLayers: []
|
||||||
};
|
};
|
||||||
|
|
||||||
this.basemaps = {};
|
this.basemaps = {};
|
||||||
this.mapBounds = null;
|
this.mapBounds = null;
|
||||||
this.autolayers = null;
|
this.autolayers = null;
|
||||||
|
this.taskCount = 1;
|
||||||
this.addedCameraShots = {};
|
this.addedCameraShots = {};
|
||||||
|
|
||||||
this.loadImageryLayers = this.loadImageryLayers.bind(this);
|
this.loadImageryLayers = this.loadImageryLayers.bind(this);
|
||||||
|
@ -76,6 +79,14 @@ class Map extends React.Component {
|
||||||
this.handleMapMouseDown = this.handleMapMouseDown.bind(this);
|
this.handleMapMouseDown = this.handleMapMouseDown.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
countTasks = () => {
|
||||||
|
let tasks = {};
|
||||||
|
this.props.tiles.forEach(tile => {
|
||||||
|
tasks[tile.meta.task.id] = true;
|
||||||
|
});
|
||||||
|
return Object.keys(tasks).length;
|
||||||
|
}
|
||||||
|
|
||||||
updateOpacity = (evt) => {
|
updateOpacity = (evt) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
opacity: parseFloat(evt.target.value),
|
opacity: parseFloat(evt.target.value),
|
||||||
|
@ -102,9 +113,9 @@ class Map extends React.Component {
|
||||||
case "plant":
|
case "plant":
|
||||||
return this.props.thermal ? _("Thermal") : _("Plant Health");
|
return this.props.thermal ? _("Thermal") : _("Plant Health");
|
||||||
case "dsm":
|
case "dsm":
|
||||||
return _("DSM");
|
return _("Surface Model");
|
||||||
case "dtm":
|
case "dtm":
|
||||||
return _("DTM");
|
return _("Terrain Model");
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -122,6 +133,10 @@ class Map extends React.Component {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typeZIndex = (type) => {
|
||||||
|
return ["dsm", "dtm", "orthophoto", "plant"].indexOf(type) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
hasBands = (bands, orthophoto_bands) => {
|
hasBands = (bands, orthophoto_bands) => {
|
||||||
if (!orthophoto_bands) return false;
|
if (!orthophoto_bands) return false;
|
||||||
|
|
||||||
|
@ -139,6 +154,8 @@ class Map extends React.Component {
|
||||||
this.tileJsonRequests = [];
|
this.tileJsonRequests = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.taskCount = this.countTasks();
|
||||||
|
|
||||||
const { tiles } = this.props,
|
const { tiles } = this.props,
|
||||||
layerId = layer => {
|
layerId = layer => {
|
||||||
const meta = layer[Symbol.for("meta")];
|
const meta = layer[Symbol.for("meta")];
|
||||||
|
@ -153,14 +170,15 @@ class Map extends React.Component {
|
||||||
if (this.map.hasLayer(layer)) prevSelectedLayers.push(layerId(layer));
|
if (this.map.hasLayer(layer)) prevSelectedLayers.push(layerId(layer));
|
||||||
layer.remove();
|
layer.remove();
|
||||||
});
|
});
|
||||||
this.setState({imageryLayers: []});
|
this.setState({imageryLayers: [], rightLayers: []});
|
||||||
|
|
||||||
// Request new tiles
|
// Request new tiles
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.tileJsonRequests = [];
|
this.tileJsonRequests = [];
|
||||||
|
|
||||||
async.each(tiles, (tile, done) => {
|
async.each(tiles, (tile, done) => {
|
||||||
const { url, meta, type } = tile;
|
const { url, type } = tile;
|
||||||
|
const meta = Utils.clone(tile.meta);
|
||||||
|
|
||||||
let metaUrl = url + "metadata";
|
let metaUrl = url + "metadata";
|
||||||
let unitForward = value => value;
|
let unitForward = value => value;
|
||||||
|
@ -242,16 +260,20 @@ class Map extends React.Component {
|
||||||
tileSize: TILESIZE,
|
tileSize: TILESIZE,
|
||||||
tms: scheme === 'tms',
|
tms: scheme === 'tms',
|
||||||
opacity: this.state.opacity / 100,
|
opacity: this.state.opacity / 100,
|
||||||
detectRetina: true
|
detectRetina: true,
|
||||||
|
zIndex: this.typeZIndex(type),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Associate metadata with this layer
|
// Associate metadata with this layer
|
||||||
meta.name = this.typeToHuman(type);
|
meta.name = this.typeToHuman(type);
|
||||||
meta.icon = this.typeToIcon(type);
|
meta.icon = this.typeToIcon(type);
|
||||||
|
meta.type = type;
|
||||||
|
meta.raster = true;
|
||||||
|
meta.autoExpand = this.taskCount === 1 && type === this.props.mapType;
|
||||||
meta.metaUrl = metaUrl;
|
meta.metaUrl = metaUrl;
|
||||||
meta.unitForward = unitForward;
|
meta.unitForward = unitForward;
|
||||||
meta.unitBackward = unitBackward;
|
meta.unitBackward = unitBackward;
|
||||||
if (this.props.tiles.length > 1){
|
if (this.taskCount > 1){
|
||||||
// Assign to a group
|
// Assign to a group
|
||||||
meta.group = {id: meta.task.id, name: meta.task.name};
|
meta.group = {id: meta.task.id, name: meta.task.name};
|
||||||
}
|
}
|
||||||
|
@ -259,17 +281,19 @@ class Map extends React.Component {
|
||||||
layer[Symbol.for("tile-meta")] = mres;
|
layer[Symbol.for("tile-meta")] = mres;
|
||||||
|
|
||||||
if (forceAddLayers || prevSelectedLayers.indexOf(layerId(layer)) !== -1){
|
if (forceAddLayers || prevSelectedLayers.indexOf(layerId(layer)) !== -1){
|
||||||
|
if (type === this.props.mapType){
|
||||||
layer.addTo(this.map);
|
layer.addTo(this.map);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Show 3D switch button only if we have a single orthophoto
|
// Show 3D switch button only if we have a single orthophoto
|
||||||
if (tiles.length === 1){
|
if (this.taskCount === 1){
|
||||||
this.setState({singleTask: meta.task});
|
this.setState({singleTask: meta.task});
|
||||||
}
|
}
|
||||||
|
|
||||||
// For some reason, getLatLng is not defined for tileLayer?
|
// For some reason, getLatLng is not defined for tileLayer?
|
||||||
// We need this function if other code calls layer.openPopup()
|
// We need this function if other code calls layer.openPopup()
|
||||||
let self = this;
|
const self = this;
|
||||||
layer.getLatLng = function(){
|
layer.getLatLng = function(){
|
||||||
let latlng = self.lastClickedLatLng ?
|
let latlng = self.lastClickedLatLng ?
|
||||||
self.lastClickedLatLng :
|
self.lastClickedLatLng :
|
||||||
|
@ -277,12 +301,38 @@ class Map extends React.Component {
|
||||||
return latlng;
|
return latlng;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Additional layer methods
|
||||||
|
layer.show = function(){
|
||||||
|
if (!self.map.hasLayer(this)) self.map.addLayer(this);
|
||||||
|
else this.getContainer().style.display = '';
|
||||||
|
};
|
||||||
|
layer.hide = function(){
|
||||||
|
this.getContainer().style.display = 'none';
|
||||||
|
};
|
||||||
|
layer.isHidden = function(){
|
||||||
|
if (!this.getContainer()) return false;
|
||||||
|
return this.getContainer().style.display === 'none';
|
||||||
|
};
|
||||||
|
layer.setZIndex = function(z){
|
||||||
|
if (this._originalZ === undefined) this._originalZ = this.options.zIndex;
|
||||||
|
this.options.zIndex = z;
|
||||||
|
this._updateZIndex();
|
||||||
|
};
|
||||||
|
layer.restoreZIndex = function(){
|
||||||
|
if (this._originalZ !== undefined){
|
||||||
|
this.setZIndex(this._originalZ);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
layer.bringToFront = function(){
|
||||||
|
this.setZIndex(this.options.zIndex + 10000);
|
||||||
|
};
|
||||||
|
|
||||||
var popup = L.DomUtil.create('div', 'infoWindow');
|
var popup = L.DomUtil.create('div', 'infoWindow');
|
||||||
|
|
||||||
popup.innerHTML = `<div class="title">
|
popup.innerHTML = `<div class="title">
|
||||||
${name}
|
${name}
|
||||||
</div>
|
</div>
|
||||||
<div class="popup-opacity-slider">Opacity: <input id="layerOpacity" type="range" value="${layer.options.opacity}" min="0" max="1" step="0.01" /></div>
|
<div class="popup-opacity-slider">Opacity: <input id="layerOpacity" class="opacity" type="range" value="${layer.options.opacity}" min="0" max="1" step="0.01" /></div>
|
||||||
<div>Bounds: [${layer.options.bounds.toBBoxString().split(",").join(", ")}]</div>
|
<div>Bounds: [${layer.options.bounds.toBBoxString().split(",").join(", ")}]</div>
|
||||||
<ul class="asset-links loading">
|
<ul class="asset-links loading">
|
||||||
<li><i class="fa fa-spin fa-sync fa-spin fa-fw"></i></li>
|
<li><i class="fa fa-spin fa-sync fa-spin fa-fw"></i></li>
|
||||||
|
@ -351,7 +401,7 @@ class Map extends React.Component {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
shotsLayer[Symbol.for("meta")] = {name: _("Cameras"), icon: "fa fa-camera fa-fw"};
|
shotsLayer[Symbol.for("meta")] = {name: _("Cameras"), icon: "fa fa-camera fa-fw"};
|
||||||
if (this.props.tiles.length > 1){
|
if (this.taskCount > 1){
|
||||||
// Assign to a group
|
// Assign to a group
|
||||||
shotsLayer[Symbol.for("meta")].group = {id: meta.task.id, name: meta.task.name};
|
shotsLayer[Symbol.for("meta")].group = {id: meta.task.id, name: meta.task.name};
|
||||||
}
|
}
|
||||||
|
@ -405,7 +455,7 @@ class Map extends React.Component {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
gcpLayer[Symbol.for("meta")] = {name: _("Ground Control Points"), icon: "far fa-dot-circle fa-fw"};
|
gcpLayer[Symbol.for("meta")] = {name: _("Ground Control Points"), icon: "far fa-dot-circle fa-fw"};
|
||||||
if (this.props.tiles.length > 1){
|
if (this.taskCount > 1){
|
||||||
// Assign to a group
|
// Assign to a group
|
||||||
gcpLayer[Symbol.for("meta")].group = {id: meta.task.id, name: meta.task.name};
|
gcpLayer[Symbol.for("meta")].group = {id: meta.task.id, name: meta.task.name};
|
||||||
}
|
}
|
||||||
|
@ -443,12 +493,17 @@ class Map extends React.Component {
|
||||||
maxZoom: 24
|
maxZoom: 24
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.map.on('viewreset', this.layerVisibilityCheck);
|
||||||
|
this.map.on('zoomstart', this.layerVisibilityCheck);
|
||||||
|
this.map.on('movestart', this.layerVisibilityCheck);
|
||||||
|
|
||||||
// For some reason, in production this class is not added (but we need it)
|
// For some reason, in production this class is not added (but we need it)
|
||||||
// leaflet bug?
|
// leaflet bug?
|
||||||
$(this.container).addClass("leaflet-touch");
|
$(this.container).addClass("leaflet-touch");
|
||||||
|
|
||||||
PluginsAPI.Map.onAddAnnotation(this.handleAddAnnotation);
|
PluginsAPI.Map.onAddAnnotation(this.handleAddAnnotation);
|
||||||
PluginsAPI.Map.onAnnotationDeleted(this.handleDeleteAnnotation);
|
PluginsAPI.Map.onAnnotationDeleted(this.handleDeleteAnnotation);
|
||||||
|
PluginsAPI.Map.onSideBySideChanged(this.handleSideBySideChange);
|
||||||
|
|
||||||
PluginsAPI.Map.triggerWillAddControls({
|
PluginsAPI.Map.triggerWillAddControls({
|
||||||
map: this.map,
|
map: this.map,
|
||||||
|
@ -592,10 +647,11 @@ _('Example:'),
|
||||||
|
|
||||||
this.map.on('click', e => {
|
this.map.on('click', e => {
|
||||||
if (PluginsAPI.Map.handleClick(e)) return;
|
if (PluginsAPI.Map.handleClick(e)) return;
|
||||||
|
if (this.sideBySideCtrl) return;
|
||||||
|
|
||||||
// Find first tile layer at the selected coordinates
|
// Find first visible tile layer at the selected coordinates
|
||||||
for (let layer of this.state.imageryLayers){
|
for (let layer of this.state.imageryLayers){
|
||||||
if (layer._map && layer.options.bounds.contains(e.latlng)){
|
if (layer._map && !layer.isHidden() && layer.options.bounds.contains(e.latlng)){
|
||||||
this.lastClickedLatLng = this.map.mouseEventToLatLng(e.originalEvent);
|
this.lastClickedLatLng = this.map.mouseEventToLatLng(e.originalEvent);
|
||||||
this.updatePopupFor(layer);
|
this.updatePopupFor(layer);
|
||||||
layer.openPopup();
|
layer.openPopup();
|
||||||
|
@ -665,7 +721,7 @@ _('Example:'),
|
||||||
name: name || "",
|
name: name || "",
|
||||||
icon: "fa fa-sticky-note fa-fw"
|
icon: "fa fa-sticky-note fa-fw"
|
||||||
};
|
};
|
||||||
if (this.props.tiles.length > 1 && task){
|
if (this.taskCount > 1 && task){
|
||||||
meta.group = {id: task.id, name: task.name};
|
meta.group = {id: task.id, name: task.name};
|
||||||
}
|
}
|
||||||
layer[Symbol.for("meta")] = meta;
|
layer[Symbol.for("meta")] = meta;
|
||||||
|
@ -679,14 +735,54 @@ _('Example:'),
|
||||||
this.setState({annotations: this.state.annotations.filter(l => l !== layer)});
|
this.setState({annotations: this.state.annotations.filter(l => l !== layer)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSideBySideChange = (layer, side) => {
|
||||||
|
let { rightLayers, imageryLayers } = this.state;
|
||||||
|
|
||||||
|
imageryLayers.forEach(l => l.restoreZIndex());
|
||||||
|
|
||||||
|
rightLayers = rightLayers.filter(l => l !== layer);
|
||||||
|
if (side){
|
||||||
|
rightLayers.push(layer);
|
||||||
|
}
|
||||||
|
rightLayers.forEach(l => l.bringToFront());
|
||||||
|
|
||||||
|
this.setState({rightLayers});
|
||||||
|
|
||||||
|
// Make sure to reset clipping
|
||||||
|
imageryLayers.forEach(l => {
|
||||||
|
let container = l.getContainer();
|
||||||
|
if (container) container.style.clip = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (rightLayers.length > 0){
|
||||||
|
if (!this.sideBySideCtrl){
|
||||||
|
this.sideBySideCtrl = L.control.sideBySide([], rightLayers).addTo(this.map);
|
||||||
|
}else{
|
||||||
|
this.sideBySideCtrl.setRightLayers(rightLayers);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if (this.sideBySideCtrl){
|
||||||
|
this.sideBySideCtrl.remove();
|
||||||
|
this.sideBySideCtrl = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layerVisibilityCheck = () => {
|
||||||
|
// Check if imageryLayers are invisible and remove them to prevent tiles from loading
|
||||||
|
this.state.imageryLayers.forEach(layer => {
|
||||||
|
if (layer.isHidden()) this.map.removeLayer(layer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
this.state.imageryLayers.forEach(imageryLayer => {
|
this.state.imageryLayers.forEach(imageryLayer => {
|
||||||
imageryLayer.setOpacity(this.state.opacity / 100);
|
imageryLayer.setOpacity(this.state.opacity / 100);
|
||||||
this.updatePopupFor(imageryLayer);
|
this.updatePopupFor(imageryLayer);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (prevProps.tiles !== this.props.tiles){
|
if (this.layersControl && prevProps.mapType !== this.props.mapType){
|
||||||
this.loadImageryLayers(true);
|
PluginsAPI.Map.mapTypeChanged(this.props.mapType, this.taskCount === 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.layersControl && (prevState.imageryLayers !== this.state.imageryLayers ||
|
if (this.layersControl && (prevState.imageryLayers !== this.state.imageryLayers ||
|
||||||
|
@ -698,6 +794,9 @@ _('Example:'),
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.map.remove();
|
this.map.remove();
|
||||||
|
this.map.off('viewreset', this.layerVisibilityCheck);
|
||||||
|
this.map.off('zoomstart', this.layerVisibilityCheck);
|
||||||
|
this.map.off('movestart', this.layerVisibilityCheck);
|
||||||
|
|
||||||
if (this.tileJsonRequests) {
|
if (this.tileJsonRequests) {
|
||||||
this.tileJsonRequests.forEach(tileJsonRequest => tileJsonRequest.abort());
|
this.tileJsonRequests.forEach(tileJsonRequest => tileJsonRequest.abort());
|
||||||
|
@ -706,7 +805,7 @@ _('Example:'),
|
||||||
|
|
||||||
PluginsAPI.Map.offAddAnnotation(this.handleAddAnnotation);
|
PluginsAPI.Map.offAddAnnotation(this.handleAddAnnotation);
|
||||||
PluginsAPI.Map.offAnnotationDeleted(this.handleAddAnnotation);
|
PluginsAPI.Map.offAnnotationDeleted(this.handleAddAnnotation);
|
||||||
|
PluginsAPI.Map.offSideBySideChanged(this.handleSideBySideChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMapMouseDown(e){
|
handleMapMouseDown(e){
|
||||||
|
@ -719,7 +818,7 @@ _('Example:'),
|
||||||
<div style={{height: "100%"}} className="map">
|
<div style={{height: "100%"}} className="map">
|
||||||
<ErrorMessage bind={[this, 'error']} />
|
<ErrorMessage bind={[this, 'error']} />
|
||||||
<div className="opacity-slider theme-secondary hidden-xs">
|
<div className="opacity-slider theme-secondary hidden-xs">
|
||||||
<div className="opacity-slider-label">{_("Opacity:")}</div> <input type="range" step="1" value={this.state.opacity} onChange={this.updateOpacity} />
|
<div className="opacity-slider-label">{_("Opacity:")}</div> <input type="range" className="opacity" step="1" value={this.state.opacity} onChange={this.updateOpacity} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Standby
|
<Standby
|
||||||
|
|
|
@ -35,14 +35,16 @@ class Toggle extends React.Component {
|
||||||
class Checkbox extends Toggle{
|
class Checkbox extends Toggle{
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
trueIcon: "far fa-check-square",
|
trueIcon: "far fa-check-square",
|
||||||
falseIcon: "far fa-square"
|
falseIcon: "far fa-square",
|
||||||
|
className: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpandButton extends Toggle{
|
class ExpandButton extends Toggle{
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
trueIcon: "fa fa-caret-down",
|
trueIcon: "fa fa-caret-down",
|
||||||
falseIcon: "fa fa-caret-right"
|
falseIcon: "fa fa-caret-right",
|
||||||
|
className: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,15 @@
|
||||||
padding-right: 6px;
|
padding-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.expand-layer{
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr.layer-separator{
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
select, input{
|
select, input{
|
||||||
height: auto;
|
height: auto;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
height: calc(100% - 20px);
|
height: calc(100% - 20px);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
input[type="range"]{
|
input.opacity[type="range"]{
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 130px;
|
width: 130px;
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2015 Gregor MacLennan
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,17 @@
|
||||||
|
.leaflet-sbs-range {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-divider {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -2px;
|
||||||
|
width: 4px;
|
||||||
|
background-color: #fff;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
|
@ -0,0 +1,270 @@
|
||||||
|
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||||
|
(function (global){
|
||||||
|
var L = (typeof window !== "undefined" ? window['L'] : typeof global !== "undefined" ? global['L'] : null)
|
||||||
|
require('./layout.css')
|
||||||
|
require('./range.css')
|
||||||
|
|
||||||
|
var mapWasDragEnabled
|
||||||
|
var mapWasTapEnabled
|
||||||
|
|
||||||
|
// Leaflet v0.7 backwards compatibility
|
||||||
|
function on (el, types, fn, context) {
|
||||||
|
types.split(' ').forEach(function (type) {
|
||||||
|
L.DomEvent.on(el, type, fn, context)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leaflet v0.7 backwards compatibility
|
||||||
|
function off (el, types, fn, context) {
|
||||||
|
types.split(' ').forEach(function (type) {
|
||||||
|
L.DomEvent.off(el, type, fn, context)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRangeEvent (rangeInput) {
|
||||||
|
return 'oninput' in rangeInput ? 'input' : 'change'
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelMapDrag () {
|
||||||
|
mapWasDragEnabled = this._map.dragging.enabled()
|
||||||
|
mapWasTapEnabled = this._map.tap && this._map.tap.enabled()
|
||||||
|
this._map.dragging.disable()
|
||||||
|
this._map.tap && this._map.tap.disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
function uncancelMapDrag (e) {
|
||||||
|
this._refocusOnMap(e)
|
||||||
|
if (mapWasDragEnabled) {
|
||||||
|
this._map.dragging.enable()
|
||||||
|
}
|
||||||
|
if (mapWasTapEnabled) {
|
||||||
|
this._map.tap.enable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert arg to an array - returns empty array if arg is undefined
|
||||||
|
function asArray (arg) {
|
||||||
|
return (arg === 'undefined') ? [] : Array.isArray(arg) ? arg : [arg]
|
||||||
|
}
|
||||||
|
|
||||||
|
function noop () {}
|
||||||
|
|
||||||
|
L.Control.SideBySide = L.Control.extend({
|
||||||
|
options: {
|
||||||
|
thumbSize: 42,
|
||||||
|
padding: 0
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (leftLayers, rightLayers, options) {
|
||||||
|
this.setLeftLayers(leftLayers)
|
||||||
|
this.setRightLayers(rightLayers)
|
||||||
|
L.setOptions(this, options)
|
||||||
|
},
|
||||||
|
|
||||||
|
getPosition: function () {
|
||||||
|
var rangeValue = this._range.value
|
||||||
|
var offset = (0.5 - rangeValue) * (2 * this.options.padding + this.options.thumbSize)
|
||||||
|
return this._map.getSize().x * rangeValue + offset
|
||||||
|
},
|
||||||
|
|
||||||
|
setPosition: noop,
|
||||||
|
|
||||||
|
includes: L.Evented.prototype || L.Mixin.Events,
|
||||||
|
|
||||||
|
addTo: function (map) {
|
||||||
|
this.remove()
|
||||||
|
this._map = map
|
||||||
|
|
||||||
|
var container = this._container = L.DomUtil.create('div', 'leaflet-sbs', map._controlContainer)
|
||||||
|
|
||||||
|
this._divider = L.DomUtil.create('div', 'leaflet-sbs-divider', container)
|
||||||
|
var range = this._range = L.DomUtil.create('input', 'leaflet-sbs-range', container)
|
||||||
|
range.type = 'range'
|
||||||
|
range.min = 0
|
||||||
|
range.max = 1
|
||||||
|
range.step = 'any'
|
||||||
|
range.value = 0.5
|
||||||
|
range.style.paddingLeft = range.style.paddingRight = this.options.padding + 'px'
|
||||||
|
this._addEvents()
|
||||||
|
this._updateLayers()
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
remove: function () {
|
||||||
|
if (!this._map) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
if (this._leftLayer) {
|
||||||
|
this._leftLayer.getContainer().style.clip = ''
|
||||||
|
}
|
||||||
|
if (this._rightLayer) {
|
||||||
|
this._rightLayer.getContainer().style.clip = ''
|
||||||
|
}
|
||||||
|
this._removeEvents()
|
||||||
|
L.DomUtil.remove(this._container)
|
||||||
|
|
||||||
|
this._map = null
|
||||||
|
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
setLeftLayers: function (leftLayers) {
|
||||||
|
this._leftLayers = asArray(leftLayers)
|
||||||
|
this._updateLayers()
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
setRightLayers: function (rightLayers) {
|
||||||
|
this._rightLayers = asArray(rightLayers)
|
||||||
|
this._updateLayers()
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateClip: function () {
|
||||||
|
var map = this._map
|
||||||
|
var nw = map.containerPointToLayerPoint([0, 0])
|
||||||
|
var se = map.containerPointToLayerPoint(map.getSize())
|
||||||
|
var clipX = nw.x + this.getPosition()
|
||||||
|
var dividerX = this.getPosition()
|
||||||
|
|
||||||
|
this._divider.style.left = dividerX + 'px'
|
||||||
|
this.fire('dividermove', {x: dividerX})
|
||||||
|
var clipLeft = 'rect(' + [nw.y, clipX, se.y, nw.x].join('px,') + 'px)'
|
||||||
|
var clipRight = 'rect(' + [nw.y, se.x, se.y, clipX].join('px,') + 'px)'
|
||||||
|
if (this._leftLayer) {
|
||||||
|
this._leftLayer.getContainer().style.clip = clipLeft
|
||||||
|
}
|
||||||
|
if (this._rightLayer) {
|
||||||
|
this._rightLayer.getContainer().style.clip = clipRight
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateLayers: function () {
|
||||||
|
if (!this._map) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
var prevLeft = this._leftLayer
|
||||||
|
var prevRight = this._rightLayer
|
||||||
|
this._leftLayer = this._rightLayer = null
|
||||||
|
this._leftLayers.forEach(function (layer) {
|
||||||
|
if (this._map.hasLayer(layer)) {
|
||||||
|
this._leftLayer = layer
|
||||||
|
}
|
||||||
|
}, this)
|
||||||
|
this._rightLayers.forEach(function (layer) {
|
||||||
|
if (this._map.hasLayer(layer)) {
|
||||||
|
this._rightLayer = layer
|
||||||
|
}
|
||||||
|
}, this)
|
||||||
|
if (prevLeft !== this._leftLayer) {
|
||||||
|
prevLeft && this.fire('leftlayerremove', {layer: prevLeft})
|
||||||
|
this._leftLayer && this.fire('leftlayeradd', {layer: this._leftLayer})
|
||||||
|
}
|
||||||
|
if (prevRight !== this._rightLayer) {
|
||||||
|
prevRight && this.fire('rightlayerremove', {layer: prevRight})
|
||||||
|
this._rightLayer && this.fire('rightlayeradd', {layer: this._rightLayer})
|
||||||
|
}
|
||||||
|
this._updateClip()
|
||||||
|
},
|
||||||
|
|
||||||
|
_addEvents: function () {
|
||||||
|
var range = this._range
|
||||||
|
var map = this._map
|
||||||
|
if (!map || !range) return
|
||||||
|
map.on('move', this._updateClip, this)
|
||||||
|
map.on('layeradd layerremove', this._updateLayers, this)
|
||||||
|
on(range, getRangeEvent(range), this._updateClip, this)
|
||||||
|
on(range, L.Browser.touch ? 'touchstart' : 'mousedown', cancelMapDrag, this)
|
||||||
|
on(range, L.Browser.touch ? 'touchend' : 'mouseup', uncancelMapDrag, this)
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeEvents: function () {
|
||||||
|
var range = this._range
|
||||||
|
var map = this._map
|
||||||
|
if (range) {
|
||||||
|
off(range, getRangeEvent(range), this._updateClip, this)
|
||||||
|
off(range, L.Browser.touch ? 'touchstart' : 'mousedown', cancelMapDrag, this)
|
||||||
|
off(range, L.Browser.touch ? 'touchend' : 'mouseup', uncancelMapDrag, this)
|
||||||
|
}
|
||||||
|
if (map) {
|
||||||
|
map.off('layeradd layerremove', this._updateLayers, this)
|
||||||
|
map.off('move', this._updateClip, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
L.control.sideBySide = function (leftLayers, rightLayers, options) {
|
||||||
|
return new L.Control.SideBySide(leftLayers, rightLayers, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = L.Control.SideBySide
|
||||||
|
|
||||||
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||||
|
},{"./layout.css":2,"./range.css":4}],2:[function(require,module,exports){
|
||||||
|
var inject = require('./node_modules/cssify');
|
||||||
|
var css = ".leaflet-sbs-range {\r\n position: absolute;\r\n top: 50%;\r\n width: 100%;\r\n z-index: 999;\r\n}\r\n.leaflet-sbs-divider {\r\n position: absolute;\r\n top: 0;\r\n bottom: 0;\r\n left: 50%;\r\n margin-left: -2px;\r\n width: 4px;\r\n background-color: #fff;\r\n pointer-events: none;\r\n z-index: 999;\r\n}\r\n";
|
||||||
|
inject(css, undefined, '_i6aomd');
|
||||||
|
module.exports = css;
|
||||||
|
|
||||||
|
},{"./node_modules/cssify":3}],3:[function(require,module,exports){
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
function injectStyleTag (document, fileName, cb) {
|
||||||
|
var style = document.getElementById(fileName)
|
||||||
|
|
||||||
|
if (style) {
|
||||||
|
cb(style)
|
||||||
|
} else {
|
||||||
|
var head = document.getElementsByTagName('head')[0]
|
||||||
|
|
||||||
|
style = document.createElement('style')
|
||||||
|
if (fileName != null) style.id = fileName
|
||||||
|
cb(style)
|
||||||
|
head.appendChild(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (css, customDocument, fileName) {
|
||||||
|
var doc = customDocument || document
|
||||||
|
/* istanbul ignore if: not supported by Electron */
|
||||||
|
if (doc.createStyleSheet) {
|
||||||
|
var sheet = doc.createStyleSheet()
|
||||||
|
sheet.cssText = css
|
||||||
|
return sheet.ownerNode
|
||||||
|
} else {
|
||||||
|
return injectStyleTag(doc, fileName, function (style) {
|
||||||
|
/* istanbul ignore if: not supported by Electron */
|
||||||
|
if (style.styleSheet) {
|
||||||
|
style.styleSheet.cssText = css
|
||||||
|
} else {
|
||||||
|
style.innerHTML = css
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.byUrl = function (url) {
|
||||||
|
/* istanbul ignore if: not supported by Electron */
|
||||||
|
if (document.createStyleSheet) {
|
||||||
|
return document.createStyleSheet(url).ownerNode
|
||||||
|
} else {
|
||||||
|
var head = document.getElementsByTagName('head')[0]
|
||||||
|
var link = document.createElement('link')
|
||||||
|
|
||||||
|
link.rel = 'stylesheet'
|
||||||
|
link.href = url
|
||||||
|
|
||||||
|
head.appendChild(link)
|
||||||
|
return link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},{}],4:[function(require,module,exports){
|
||||||
|
var inject = require('./node_modules/cssify');
|
||||||
|
var css = ".leaflet-sbs-range {\r\n -webkit-appearance: none;\r\n display: inline-block!important;\r\n vertical-align: middle;\r\n height: 0;\r\n padding: 0;\r\n margin: 0;\r\n border: 0;\r\n background: rgba(0, 0, 0, 0.25);\r\n min-width: 100px;\r\n cursor: pointer;\r\n pointer-events: none;\r\n z-index: 999;\r\n}\r\n.leaflet-sbs-range::-ms-fill-upper {\r\n background: transparent;\r\n}\r\n.leaflet-sbs-range::-ms-fill-lower {\r\n background: rgba(255, 255, 255, 0.25);\r\n}\r\n/* Browser thingies */\r\n\r\n.leaflet-sbs-range::-moz-range-track {\r\n opacity: 0;\r\n}\r\n.leaflet-sbs-range::-ms-track {\r\n opacity: 0;\r\n}\r\n.leaflet-sbs-range::-ms-tooltip {\r\n display: none;\r\n}\r\n/* For whatever reason, these need to be defined\r\n * on their own so dont group them */\r\n\r\n.leaflet-sbs-range::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n margin: 0;\r\n padding: 0;\r\n background: #fff;\r\n height: 40px;\r\n width: 40px;\r\n border-radius: 20px;\r\n cursor: ew-resize;\r\n pointer-events: auto;\r\n border: 1px solid #ddd;\r\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAABlBMVEV9fX3///+Kct39AAAAAnRSTlP/AOW3MEoAAAA9SURBVFjD7dehDQAwDANBZ/+l2wmKoiqR7pHRcaeaCxAIBAL/g7k9JxAIBAKBQCAQCAQC14H+MhAIBE4CD3fOFvGVBzhZAAAAAElFTkSuQmCC\");\r\n background-position: 50% 50%;\r\n background-repeat: no-repeat;\r\n background-size: 40px 40px;\r\n}\r\n.leaflet-sbs-range::-ms-thumb {\r\n margin: 0;\r\n padding: 0;\r\n background: #fff;\r\n height: 40px;\r\n width: 40px;\r\n border-radius: 20px;\r\n cursor: ew-resize;\r\n pointer-events: auto;\r\n border: 1px solid #ddd;\r\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAABlBMVEV9fX3///+Kct39AAAAAnRSTlP/AOW3MEoAAAA9SURBVFjD7dehDQAwDANBZ/+l2wmKoiqR7pHRcaeaCxAIBAL/g7k9JxAIBAKBQCAQCAQC14H+MhAIBE4CD3fOFvGVBzhZAAAAAElFTkSuQmCC\");\r\n background-position: 50% 50%;\r\n background-repeat: no-repeat;\r\n background-size: 40px 40px;\r\n}\r\n.leaflet-sbs-range::-moz-range-thumb {\r\n padding: 0;\r\n right: 0 ;\r\n background: #fff;\r\n height: 40px;\r\n width: 40px;\r\n border-radius: 20px;\r\n cursor: ew-resize;\r\n pointer-events: auto;\r\n border: 1px solid #ddd;\r\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAABlBMVEV9fX3///+Kct39AAAAAnRSTlP/AOW3MEoAAAA9SURBVFjD7dehDQAwDANBZ/+l2wmKoiqR7pHRcaeaCxAIBAL/g7k9JxAIBAKBQCAQCAQC14H+MhAIBE4CD3fOFvGVBzhZAAAAAElFTkSuQmCC\");\r\n background-position: 50% 50%;\r\n background-repeat: no-repeat;\r\n background-size: 40px 40px;\r\n}\r\n.leaflet-sbs-range:disabled::-moz-range-thumb {\r\n cursor: default;\r\n}\r\n.leaflet-sbs-range:disabled::-ms-thumb {\r\n cursor: default;\r\n}\r\n.leaflet-sbs-range:disabled::-webkit-slider-thumb {\r\n cursor: default;\r\n}\r\n.leaflet-sbs-range:disabled {\r\n cursor: default;\r\n}\r\n.leaflet-sbs-range:focus {\r\n outline: none!important;\r\n}\r\n.leaflet-sbs-range::-moz-focus-outer {\r\n border: 0;\r\n}\r\n\r\n";
|
||||||
|
inject(css, undefined, '_1tlt668');
|
||||||
|
module.exports = css;
|
||||||
|
|
||||||
|
},{"./node_modules/cssify":3}]},{},[1]);
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 150 B |
|
@ -0,0 +1,98 @@
|
||||||
|
.leaflet-sbs-range {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
display: inline-block!important;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.25);
|
||||||
|
min-width: 100px;
|
||||||
|
cursor: pointer;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range::-ms-fill-upper {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range::-ms-fill-lower {
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
}
|
||||||
|
/* Browser thingies */
|
||||||
|
|
||||||
|
.leaflet-sbs-range::-moz-range-track {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range::-ms-track {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range::-ms-tooltip {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* For whatever reason, these need to be defined
|
||||||
|
* on their own so dont group them */
|
||||||
|
|
||||||
|
.leaflet-sbs-range::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: #fff;
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: ew-resize;
|
||||||
|
pointer-events: auto;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background-image: url(range-icon.png);
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 40px 40px;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range::-ms-thumb {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: #fff;
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: ew-resize;
|
||||||
|
pointer-events: auto;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background-image: url(range-icon.png);
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 40px 40px;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range::-moz-range-thumb {
|
||||||
|
padding: 0;
|
||||||
|
right: 0 ;
|
||||||
|
background: #fff;
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: ew-resize;
|
||||||
|
pointer-events: auto;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background-image: url(range-icon.png);
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 40px 40px;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range:disabled::-moz-range-thumb {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range:disabled::-ms-thumb {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range:disabled::-webkit-slider-thumb {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range:focus {
|
||||||
|
outline: none!important;
|
||||||
|
}
|
||||||
|
.leaflet-sbs-range::-moz-focus-outer {
|
||||||
|
border: 0;
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ import {
|
||||||
ImplicitTaskFetcher as TaskFetcher,
|
ImplicitTaskFetcher as TaskFetcher,
|
||||||
APIFetcher
|
APIFetcher
|
||||||
} from "./components/Fetcher";
|
} from "./components/Fetcher";
|
||||||
import {AssetConfig, AssetStyles} from "./defaults";
|
import {AssetConfig} from "./defaults";
|
||||||
import { fetchCancelable, getCookie } from "./utils";
|
import { fetchCancelable, getCookie } from "./utils";
|
||||||
|
|
||||||
export default class TaskView extends Component {
|
export default class TaskView extends Component {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { PureComponent, Fragment } from "react";
|
import React, { PureComponent, Fragment } from "react";
|
||||||
import IonAssetLabel from "./IonAssetLabel";
|
import IonAssetLabel from "./IonAssetLabel";
|
||||||
import { AssetStyles } from "../defaults";
|
import { AssetConfig } from "../defaults";
|
||||||
|
|
||||||
import "./IonAssetButton.scss";
|
import "./IonAssetButton.scss";
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ export default class IonAssetButton extends PureComponent {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const menuItems = assets
|
const menuItems = assets
|
||||||
.sort((a, b) => AssetStyles[a].name.localeCompare(AssetStyles[b].name))
|
.sort((a, b) => AssetConfig[a].name.localeCompare(AssetConfig[b].name))
|
||||||
.map(asset => (
|
.map(asset => (
|
||||||
<li>
|
<li>
|
||||||
<a key={asset} style={{cursor:'pointer'}} onClick={this.handleClick(asset)}>
|
<a key={asset} style={{cursor:'pointer'}} onClick={this.handleClick(asset)}>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React, { PureComponent, Fragment } from "react";
|
import React, { PureComponent, Fragment } from "react";
|
||||||
import { AssetStyles } from "../defaults";
|
import { AssetConfig } from "../defaults";
|
||||||
|
|
||||||
const IonAssetLabel = ({ asset, showIcon = false, ...options }) => (
|
const IonAssetLabel = ({ asset, showIcon = false, ...options }) => (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{showIcon && <i className={`${AssetStyles[asset].icon}`} />}
|
{showIcon && <i className={`${AssetConfig[asset].icon}`} />}
|
||||||
{" "}
|
{" "}
|
||||||
{AssetStyles[asset].name}
|
{AssetConfig[asset].name}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "WebODM",
|
"name": "WebODM",
|
||||||
"version": "2.6.0",
|
"version": "2.7.0",
|
||||||
"description": "User-friendly, extendable application and API for processing aerial imagery.",
|
"description": "User-friendly, extendable application and API for processing aerial imagery.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
Ładowanie…
Reference in New Issue