Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 63 additions & 21 deletions packages/base/src/mainview/mainView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@ import {
} from '@jupytergis/schema';
import { IObservableMap, ObservableMap } from '@jupyterlab/observables';
import { User } from '@jupyterlab/services';
import { CommandRegistry } from '@lumino/commands';
import { JSONValue, UUID } from '@lumino/coreutils';
import { ContextMenu } from '@lumino/widgets';
import { Collection, MapBrowserEvent, Map as OlMap, View, getUid } from 'ol';
//@ts-expect-error no types for ol-pmtiles
import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles';
import { FeatureLike } from 'ol/Feature';
import { ScaleLine } from 'ol/control';
import { Coordinate } from 'ol/coordinate';
import { singleClick } from 'ol/events/condition';
import { GeoJSON, MVT } from 'ol/format';
import { DragAndDrop, Select } from 'ol/interaction';
import {
Expand All @@ -47,6 +54,8 @@ import {
toLonLat,
transformExtent
} from 'ol/proj';
import { get as getProjection } from 'ol/proj.js';
import { register } from 'ol/proj/proj4.js';
import Feature from 'ol/render/Feature';
import {
GeoTIFF as GeoTIFFSource,
Expand All @@ -55,32 +64,28 @@ import {
VectorTile as VectorTileSource,
XYZ as XYZSource
} from 'ol/source';
import ImageSource from 'ol/source/Image';
import Static from 'ol/source/ImageStatic';
//@ts-expect-error no types for ol-pmtiles
import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles';
import { register } from 'ol/proj/proj4.js';
import { get as getProjection } from 'ol/proj.js';
import TileSource from 'ol/source/Tile';
import { Circle, Fill, Stroke, Style } from 'ol/style';
import { Rule } from 'ol/style/flat';
import proj4 from 'proj4';
import * as React from 'react';
import { isLightTheme, loadGeoTIFFWithCache, throttle } from '../tools';
import { MainViewModel } from './mainviewmodel';
import { Spinner } from './spinner';
//@ts-expect-error no types for proj4-list
//@ts-expect-error no types for proj4list
import proj4list from 'proj4-list';
import { ContextMenu } from '@lumino/widgets';
import { CommandRegistry } from '@lumino/commands';
import { Coordinate } from 'ol/coordinate';
import * as React from 'react';
import AnnotationFloater from '../annotations/components/AnnotationFloater';
import { CommandIDs } from '../constants';
import { FollowIndicator } from './FollowIndicator';
import StatusBar from '../statusbar/StatusBar';
import {
isLightTheme,
loadFile,
loadGeoTIFFWithCache,
throttle
} from '../tools';
import CollaboratorPointers, { ClientPointer } from './CollaboratorPointers';
import { loadFile } from '../tools';
import { Circle, Fill, Stroke, Style } from 'ol/style';
import { singleClick } from 'ol/events/condition';
import TileSource from 'ol/source/Tile';
import { FeatureLike } from 'ol/Feature';
import ImageSource from 'ol/source/Image';
import { FollowIndicator } from './FollowIndicator';
import { MainViewModel } from './mainviewmodel';
import { Spinner } from './spinner';

interface IProps {
viewModel: MainViewModel;
Expand All @@ -95,6 +100,9 @@ interface IStates {
firstLoad: boolean;
annotations: IDict<IAnnotation>;
clientPointers: IDict<ClientPointer>;
viewProjection: { code: string; units: string };
loadingLayer: boolean;
scale: number;
}

export class MainView extends React.Component<IProps, IStates> {
Expand Down Expand Up @@ -131,7 +139,10 @@ export class MainView extends React.Component<IProps, IStates> {
loading: true,
firstLoad: true,
annotations: {},
clientPointers: {}
clientPointers: {},
viewProjection: { code: '', units: '' },
loadingLayer: false,
scale: 0
};

this._sources = [];
Expand Down Expand Up @@ -269,6 +280,7 @@ export class MainView extends React.Component<IProps, IStates> {
const projection = view.getProjection();
const latLng = toLonLat(center, projection);
const bearing = view.getRotation();
const resolution = view.getResolution();

const updatedOptions: Partial<IJGISOptions> = {
latitude: latLng[1],
Expand All @@ -284,6 +296,19 @@ export class MainView extends React.Component<IProps, IStates> {
...currentOptions,
...updatedOptions
});

// Calculate scale
if (resolution) {
// DPI and inches per meter values taken from OpenLayers
const dpi = 25.4 / 0.28;
const inchesPerMeter = 1000 / 25.4;
const scale = resolution * inchesPerMeter * dpi;

this.setState(old => ({
...old,
scale
}));
}
});

this._Map.on('click', this._identifyFeature.bind(this));
Expand All @@ -309,7 +334,14 @@ export class MainView extends React.Component<IProps, IStates> {
this._contextMenu.open(event);
});

this.setState(old => ({ ...old, loading: false }));
this.setState(old => ({
...old,
loading: false,
viewProjection: {
code: view.getProjection().getCode(),
units: view.getProjection().getUnits()
}
}));
}
}

Expand Down Expand Up @@ -759,6 +791,9 @@ export class MainView extends React.Component<IProps, IStates> {
return;
}

this.setState(old => ({ ...old, loadingLayer: true }));
this._loadingLayers.add(id);

if (!this._sources[sourceId]) {
await this.addSource(sourceId, source, id);
}
Expand Down Expand Up @@ -1108,6 +1143,7 @@ export class MainView extends React.Component<IProps, IStates> {
return new Promise(resolve => {
const checkReady = () => {
if (this._loadingLayers.size === 0) {
this.setState(old => ({ ...old, loadingLayer: false }));
resolve();
} else {
setTimeout(checkReady, 50);
Expand Down Expand Up @@ -1685,6 +1721,12 @@ export class MainView extends React.Component<IProps, IStates> {
}}
/>
</div>
<StatusBar
jgisModel={this._model}
loading={this.state.loadingLayer}
projection={this.state.viewProjection}
scale={this.state.scale}
/>
</>
);
}
Expand Down
74 changes: 74 additions & 0 deletions packages/base/src/statusbar/StatusBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
faGlobe,
faLocationDot,
faRuler
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Progress } from '@jupyter/react-components';
import { IJupyterGISModel, JgisCoordinates } from '@jupytergis/schema';
import React, { useEffect, useState } from 'react';
import { version } from '../../package.json'; // Adjust the path as necessary

interface IStatusBarProps {
jgisModel: IJupyterGISModel;
loading?: boolean;
projection?: { code: string; units: string };
scale: number;
}
const StatusBar = ({
jgisModel,
loading,
projection,
scale
}: IStatusBarProps) => {
const [coords, setCoords] = useState<JgisCoordinates>({ x: 0, y: 0 });

useEffect(() => {
const handleClientStateChanged = () => {
const pointer = jgisModel?.localState?.pointer?.value;

if (!pointer) {
return;
}

setCoords({ x: pointer?.coordinates.x, y: pointer?.coordinates.y });
};

jgisModel.clientStateChanged.connect(handleClientStateChanged);

return () => {
jgisModel.clientStateChanged.disconnect(handleClientStateChanged);
};
}, [jgisModel]);

return (
<div className="jgis-status-bar">
{loading && (
<div style={{ width: '16%', padding: '0 6px' }}>
<Progress height={14} />
</div>
)}
<div className="jgis-status-bar-item">
<span>jgis: {version}</span>
</div>
<div className="jgis-status-bar-item jgis-status-bar-coords">
<FontAwesomeIcon icon={faLocationDot} />
<span>
{' '}
x: {Math.trunc(coords.x)} y: {Math.trunc(coords.y)}
</span>
</div>
<div className="jgis-status-bar-item">
<FontAwesomeIcon icon={faRuler} />{' '}
<span>Scale: 1: {Math.trunc(scale)}</span>
</div>
<div className="jgis-status-bar-item">
<FontAwesomeIcon icon={faGlobe} />{' '}
<span>{projection?.code ?? null}</span>
</div>
<div className="jgis-status-bar-item">Units: {projection?.units}</div>
</div>
);
};

export default StatusBar;
1 change: 1 addition & 0 deletions packages/base/style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@import url('./leftPanel.css');
@import url('./filterPanel.css');
@import url('./symbologyDialog.css');
@import url('./statusBar.css');
@import url('ol/ol.css');

.jGIS-Toolbar-GroupName {
Expand Down
16 changes: 16 additions & 0 deletions packages/base/style/statusBar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.jgis-status-bar {
display: flex;
justify-content: space-around;
align-items: center;
height: 16px;
background-color: var(--jp-layout-color1);
font-size: var(--jp-ui-font-size0);
}

.jgis-status-bar-item {
flex: 0 0 content;
}

.jgis-status-bar-coords {
min-width: 160px;
}
2 changes: 1 addition & 1 deletion python/jupytergis_lab/style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ div.jGIS-toolbar-widget > div.jp-Toolbar-item:last-child {

.jGIS-Mainview {
width: 100%;
height: 100%;
height: calc(100% - 16px);
box-sizing: border-box;
}

Expand Down
Binary file modified ui-tests/tests/filters.spec.ts-snapshots/no-filter-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified ui-tests/tests/filters.spec.ts-snapshots/one-filter-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified ui-tests/tests/filters.spec.ts-snapshots/two-filter-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.