pull/1060/head
Piero Toffanin 2021-09-24 16:56:48 -04:00
rodzic afa064ac20
commit 49072d58b1
2 zmienionych plików z 204 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,152 @@
import React from 'react';
import PropTypes from 'prop-types';
import AssetDownloads from '../classes/AssetDownloads';
import '../css/GCPPopup.scss';
import { _ } from '../classes/gettext';
class GCPPopup extends React.Component {
static propTypes = {
feature: PropTypes.object.isRequired,
task: PropTypes.object.isRequired,
};
constructor(props){
super(props);
this.state = {
error: "",
loading: true,
expandGCPImage: false,
selectedShot: "",
zoom: 1
}
}
selectShot = (shotId) => {
if (shotId !== this.state.selectedShot){
this.setState({loading: true, selectedShot: shotId, error: ""});
}
}
_getCoords = (shotId, key) => {
if (!shotId) return [0.5, 0.5];
const { feature } = this.props;
const ob = feature.properties.observations.find(o => o.shot_id === shotId);
if (ob){
return ob[key];
}else{
return [0.5, 0.5];
}
}
getAnnotationCoords = (shotId) => {
return this._getCoords(shotId, 'annotated');
}
getReprojectedCoords = (shotId) => {
return this._getCoords(shotId, 'reprojected');
}
getThumbUrl = (size) => {
const { task } = this.props;
const { selectedShot, zoom } = this.state;
const annotated = this.getAnnotationCoords(selectedShot);
const reprojected = this.getReprojectedCoords(selectedShot);
return `/api/projects/${task.project}/tasks/${task.id}/images/thumbnail/${selectedShot}?size=${size}&center_x=${annotated[0]}&center_y=${annotated[1]}&draw_point=${annotated[0]},${annotated[1]}&point_color=f29900&point_radius=20&draw_point=${reprojected[0]},${reprojected[1]}&&point_color=00ff00&point_radius=20`;
}
componentDidMount(){
const { feature } = this.props;
if (this.image) this.image.addEventListener("fullscreenchange", this.onFullscreenChange);
if (feature.properties.observations) this.selectShot(feature.properties.observations[0].shot_id);
}
componentWillUnmount(){
if (this.image) this.image.removeEventListener("fullscreenchange", this.onFullscreenChange);
}
onFullscreenChange = (e) => {
if (!document.fullscreenElement){
this.setState({expandGCPImage: false});
}
}
imageOnError = () => {
this.setState({error: _("Image missing"), loading: false});
}
imageOnLoad = () => {
this.setState({loading: false});
}
onImgClick = () => {
const { expandGCPImage } = this.state;
if (!expandGCPImage){
this.image.requestFullscreen();
this.setState({ loading: true, expandGCPImage: true});
}else{
document.exitFullscreen();
this.setState({ expandGCPImage: false });
}
}
render(){
const { error, loading, expandGCPImage, selectedShot, zoom } = this.state;
const { feature, task } = this.props;
const downloadGCPLink = `/api/projects/${task.project}/tasks/${task.id}/download/ground_control_points.geojson`;
const assetDownload = AssetDownloads.only(["ground_control_points.geojson"])[0];
const imageUrl = expandGCPImage ? this.getThumbUrl(999999999) : this.getThumbUrl(320);
const shotLinks = [];
for (let i = 0; i < feature.properties.observations.length; i++){
const obs = feature.properties.observations[i];
if (obs.shot_id === selectedShot){
shotLinks.push(<span key={obs.shot_id}>{obs.shot_id}</span>);
}else{
shotLinks.push(<a key={obs.shot_id} className="gcp-image-link" href="javascript:void(0)" onClick={() => this.selectShot(obs.shot_id)}>{obs.shot_id}</a>);
}
if (i+1 < feature.properties.observations.length) shotLinks.push(<span key={"divider-" + i}> | </span>);
}
const imgStyle = {
borderRadius: "4px"
};
return (<div className="gcp-popup">
<div className="title" title={feature.properties.id}>{feature.properties.id}</div>
<div>
{shotLinks}
</div>
<div className="image-container">
{loading ? <div className="spinner"><i className="fa fa-circle-notch fa-spin fa-fw"></i></div> : ""}
{error ? <div style={{marginTop: "8px"}}>{error}</div> : ""}
{!error && selectedShot !== "" ?
<div className={`image ${expandGCPImage ? "fullscreen" : ""} ${loading ? "loading" : ""}`} style={{marginTop: "8px"}} ref={(domNode) => { this.image = domNode;}}>
{loading && expandGCPImage ? <div><i className="fa fa-circle-notch fa-spin fa-fw"></i></div> : ""}
<a onClick={this.onImgClick} href="javascript:void(0);" title={selectedShot}><img style={imgStyle} src={imageUrl} onLoad={this.imageOnLoad} onError={this.imageOnError} /></a>
</div> : ""}
</div>
<div>
<strong>{_("Horizontal error:")}</strong> {Math.abs(Math.max(feature.properties.error[0], feature.properties.error[1])).toFixed(3)} {_("(meters)")}
</div>
<div>
<strong>{_("Vertical error:")}</strong> {Math.abs(feature.properties.error[2]).toFixed(3)} {_("(meters)")}
</div>
<div>
<a href={downloadGCPLink}><i className={assetDownload.icon}></i> {assetDownload.label} </a>
</div>
</div>);
}
}
export default GCPPopup;

Wyświetl plik

@ -0,0 +1,52 @@
.gcp-popup{
div{
margin-top: 8px;
}
div.title{
margin-top: 0;
font-weight: bold;
max-width: 300px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.image-container{
position: relative;
.spinner{
position: absolute;
left: 4px;
min-height: 32px;
}
}
div.image{
overflow: hidden;
a{
cursor: zoom-in;
}
&.loading{
opacity: 0.2;
}
&.fullscreen{
display: flex;
align-items: center;
justify-content: center;
color: white;
i{
font-size: 200%;
position: absolute;
left: 50%;
top: 45%;
}
a{
cursor: zoom-out;
}
img{
max-width: 100%;
max-height: 100%;
}
}
}
}