Polishing (#8)

* typo

* points and lines in 3d: TODO: edit HTML text, add popups, add pins

* html and popups

* add floating pins

* proper 3d display

* loading screen, fixed mesh displayProperties

* html

* .

* typo
This commit is contained in:
KatKatKateryna
2024-09-04 02:30:48 +01:00
committed by GitHub
parent 607dc2e9b4
commit 8c3202290d
6 changed files with 180 additions and 26 deletions
+1 -4
View File
@@ -40,7 +40,7 @@ List of possible issues you can experience and solutions to them:
- Page or Map stays blank and Developer Tools Console shows "net::ERR_QUIC_PROTOCOL_ERROR 200 (OK)"
Solution: Try reloading the page. Otherwise, if in Google Chrome, navigate to chrome://flags/#enable-quic in and change Experimental QUIC Protocol dropdown to Disabled.
Solution: Try reloading the page. Otherwise, if in Google Chrome, navigate to chrome://flags/#enable-quic and change Experimental QUIC Protocol dropdown to Disabled.
- Model seems to be loaded incomplete
@@ -170,9 +170,6 @@ Repeated launch:
cd pygeoapi_venv
Scripts\activate
cd pygeoapi
python -m pip install --upgrade specklepy==2.19.6
python -m pip install pydantic==1.10.17
python pygeoapi\provider\speckle_utils\patch\patch_specklepy.py
python setup.py install
set PYGEOAPI_CONFIG=example-config.yml
set PYGEOAPI_OPENAPI=example-config.yml
+21 -3
View File
@@ -35,7 +35,8 @@ from typing import Union
import click
from flask import (Flask, Blueprint, make_response, request,
send_from_directory, Response, Request)
send_from_directory, Response, Request, stream_with_context)
from http import HTTPStatus
from pygeoapi.api import API, APIRequest, apply_gzip
import pygeoapi.api.coverages as coverages_api
@@ -47,7 +48,7 @@ import pygeoapi.api.stac as stac_api
import pygeoapi.api.tiles as tiles_api
from pygeoapi.openapi import load_openapi_document
from pygeoapi.config import get_config
from pygeoapi.util import get_mimetype, get_api_rules
from pygeoapi.util import get_mimetype, get_api_rules, render_j2_template
CONFIG = get_config()
@@ -195,12 +196,29 @@ def landing_page():
# if requested from the browser, return this, otherwise ignore IF statement
if request.method == 'GET' and browser_agent: # list items
return execute_from_flask(itemtypes_api.get_collection_items,
def generate():
yield loading_screen().data
browser_response = execute_from_flask(itemtypes_api.get_collection_items,
request, collection_id,
skip_valid_check=True)
yield browser_response.data
return Response(stream_with_context(generate()))
return get_response(api_.landing_page(request))
def loading_screen():
"""
Loading empty page
:returns: HTTP response
"""
content = render_j2_template(api_.tpl_config, 'loading_screen.html',{})
return get_response((request.headers, HTTPStatus.OK, content))
@BLUEPRINT.route('/openapi')
def openapi():
"""
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

+7
View File
@@ -123,6 +123,13 @@
</a>
{% endif %}
<div class="form-group" >
<label class="switch">3D
<input id="modeSwitch" type="checkbox">
<span class="slider round"></span>
</label>
</div>
<ul class="nav nav-pills"> </ul>
</header>
</div>
+139 -19
View File
@@ -17,12 +17,6 @@
<div class="row">
{% if not data['missing_url'] %}
<div class="form-group" >
<label class="switch">3D
<input id="modeSwitch" type="checkbox">
<span class="slider round"></span>
</label>
</div>
<div id="map2d" style="height: 80vh;"></div>
<div id="map3d" style="height: 0vh;"></div>
@@ -329,7 +323,7 @@
<b>Note: this is not a production server.</b> It is still work in progress,
and we are very curious
to <a href = "https://speckle.community/invites/qxEmQb1QcM" target="_blank">hear about your use case and your feedback</a>
so we can make it better.
so we can make it better!
</p>
</tr>
</div>
@@ -341,6 +335,8 @@
{% block extrafoot %}
<script>
document.getElementById("loading_screen").style.height = '0px';
// attach even to modeSwitch btn
document.getElementById("modeSwitch").onclick = switchMode;
var el = document.getElementById("modeSwitch");
@@ -431,15 +427,72 @@
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16), parseInt(result[0], 16)] : null;
};
function rgbaToArgbList(color) {
if (color == null){
return [10,132,255,255];
}
col = color.replace('rgba(','').replace(')','').split(',',4);
value = [ parseInt(col[0]), parseInt(col[1]), parseInt(col[2]), parseInt(col[3]) ];
return value;
}
function rgbaToArgbListDarker(color) {
if (color == null){
return [7,120,235,255];
}
col = color.replace('rgba(','').replace(')','').split(',',4);
value = [ parseInt(col[0])*0.95, parseInt(col[1])*0.95, parseInt(col[2])*0.95, parseInt(col[3]) ];
return value;
}
function getMessagesNumber(properties)
{
if (properties == null || properties.messages == null) {return 1}
else
{
return properties.messages.length
}
}
function getDisplayText(properties)
{
if (properties != null && properties.text_html != null){
return properties.text_html
}
else if (properties != null && properties.speckle_type != null && properties.id != null){
return `${properties.speckle_type}: ${properties.id.split("_")[0]}`
}
else{
return ``
}
}
// Callback to populate the default tooltip with content
function getTooltip({object}) {
return object && {
html: getDisplayText(object.properties),
style: {
backgroundColor: 'rgb(255,255,255)',
color: 'rgb(0,0,0)',
fontSize: '0.9em'
}
};
}
function createSVGIcon(n) {
const label = n < 10 ? n.toString() : '10+';
return `\
<svg width="100" height="100" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" fill="rgb(10,132,255)" stroke="rgb(200,200,200)" stroke-width="2"/>
<text x="12" y="12" fill="#fff" text-anchor="middle" alignment-baseline="middle" font-family="verdana" font-size="8">${label}</text>
</svg>`;
}
// Note that a xml string cannot be directly embedded in a data URL
// it has to be either escaped or converted to base64.
function svgToDataUrl(svg) {
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
}
// You may need base64 encoding if the SVG contains certain special characters
function svgToDataUrlBase64(svg) {
return `data:image/svg+xml;base64,${btoa(svg)}`;
}
function initialize3d() {
maptilersdk.config.apiKey = '{{ config["server"]["map"]["key"] }}';
@@ -451,6 +504,7 @@
coords = feature.geometry.coordinates;
if (feature.geometry.type.includes("Polygon")) {
polygons = []
// check orientation of each PolygonPart, if vertical - shift points slightly
for (let p = 0; p < coords.length; p++) {
@@ -476,38 +530,82 @@
createdPolygon = true;
multipolygon_coords = [coords[p][c]];
speckle_features.push({"id": speckle_features.length, "type":"Feature",
polygons.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":[multipolygon_coords]},
"properties": speckle_data.features[i].properties });
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties });
}
else if (polygon_pts.length==4) {
createdPolygon = true;
multipolygon_coords = [coords[p][c].slice(0,3)];
speckle_features.push({"id": speckle_features.length, "type":"Feature",
polygons.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":[multipolygon_coords]},
"properties": speckle_data.features[i].properties });
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties });
multipolygon_coords = [[coords[p][c][2], coords[p][c][3], coords[p][c][0]]];
speckle_features.push({"id": speckle_features.length, "type":"Feature", "geometry": {"type": "MultiPolygon", "coordinates":[multipolygon_coords]}, "properties": speckle_data.features[i].properties });
polygons.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":[multipolygon_coords]},
"properties": speckle_data.features[i].properties ,
"displayProperties": speckle_data.features[i].displayProperties });
};
};
if (createdPolygon == false){
multipolygon_coords = [coords[p][c]];
speckle_features.push({"id": speckle_features.length, "type":"Feature",
polygons.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":[multipolygon_coords]},
"properties": speckle_data.features[i].properties });
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties });
}
};
};
polygons.forEach((element, index, array) => {
element.displayProperties.lineWidth = 0.05
speckle_features.push(element);
});
}
else if (speckle_data.features[i].displayProperties.object_type == "comment")
{
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": speckle_data.features[i].geometry.type, "coordinates":speckle_data.features[i].geometry.coordinates},
"properties": speckle_data.features[i].properties,
"displayProperties":
{
"color": 'rgba(10,132,255,255)',
"lineWidth": 2,
"radius": 10,
"object_type": "comments",
}
});
}
else
{
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": speckle_data.features[i].geometry.type, "coordinates":speckle_data.features[i].geometry.coordinates},
"properties": speckle_data.features[i].properties,
"displayProperties": speckle_data.features[i].displayProperties });
}
}
var extent = speckle_data["extent"];
speckle_data.features = speckle_features;
speckle_data.features = [];
speckle_features.forEach((element, index, array) => {
if (element.displayProperties.object_type != "comments"){
speckle_data.features.push(element);
}
});
speckle_comments = [];
speckle_features.forEach((element, index, array) => {
if (element.displayProperties.object_type == "comments"){
speckle_comments.push(element);
}
});
// Create deck.gl map
const deckgl = new deck.DeckGL({
@@ -524,16 +622,38 @@
controller: true,
layers: [
new deck.GeoJsonLayer({
id: 'speckle_data',
data: speckle_data,
// Styles
filled: true,
getFillColor: f => rgbaToArgbList(f.properties.color),
getLineWidth: 0.05,
getLineColor: f => rgbaToArgbListDarker(f.properties.color),
getFillColor: f => rgbaToArgbList(f.displayProperties.color),
getLineWidth: f => f.displayProperties.lineWidth,
getLineColor: f => rgbaToArgbListDarker(f.displayProperties.color),
getPointRadius: f => f.displayProperties.radius / 2,
// Interactive props
pickable: true,
autoHighlight: true,
}),
new deck.IconLayer({
id: 'IconLayer',
data: speckle_comments,
// getColor: d => [Math.sqrt(getMessagesNumber(d.properties)), 140, 0],
getIcon: d => ({
url: svgToDataUrl(createSVGIcon( getMessagesNumber(d.properties).toString() )), //'https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/icon-atlas.png',
width: 128,
height: 128
}),
getPosition: d => d.geometry.coordinates[0],
getSize: f => 50 * Math.pow(getMessagesNumber(f.properties),0.3),
pickable: true
})
]
],
getTooltip
});
}
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<body>
<div id="loading_screen" style="position: absolute;top:100px;left:0;right:0;width: fit-content;margin-inline: auto;height:200px;">
<img style="height:200px;" src="{{ config['server']['url'] }}/static/img/speckle_cube_loading.gif" alt="Loading data.." >
<h3 style="margin-bottom: 0px;font-family: 'Verdana'; text-align: center; color:rgb(40, 127, 209);font-size: x-large;">"I'm on my way!"</h3>
<p style="font-family: 'Verdana'; text-align: right; color:rgb(40, 127, 209)">- your data </p>
</div>
</body>
</html>