Kate speckle poc (#7)

* 3d demos

* url_constructor_demo

* readme update

* troubleshooting

* formatting

* formatting

* readme

* .

* readme

* readme

* fix titles

* colors with opacity

* demo3d

* fix mesh split

* maptalks_fixed geometry

* vertical coords

* 3d display

* building example

* print

* demos
This commit is contained in:
KatKatKateryna
2024-09-02 03:35:27 +01:00
committed by GitHub
parent d7a5cb6576
commit a174694961
8 changed files with 1057 additions and 76 deletions
+57 -4
View File
@@ -39,19 +39,72 @@ Example: [https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/pr
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.
- Model seems to be loaded incomplete
Solution: Check the message "feature count limited to ..." next to the Model name on the top of the page. If the message is present, try increasing the feature limit using "&limit=10000" URL parameter
- Attribute table doesn't have original feature attributes and properties
Enable the URL parameter "&preserveAttributes=true". It is disabled by default due to the faulty display of the 3-dimentional multiPolygons overlapping themselves in 2d space, when viweving in the browser on 2d map. Enabling this parameter might make the multipolygons appear "transparent" due to self-overlap.
Report any other issues here or on our [Community Forum](https://speckle.community/invites/qxEmQb1QcM).
Solution: Enable the URL parameter "&preserveAttributes=true". It is disabled by default due to the faulty display of the 3-dimentional multiPolygons overlapping themselves in 2d space, when viweving in the browser on 2d map. Enabling this parameter might make the multipolygons appear "transparent" due to self-overlap.
### Add Speckle Feature Layer to a web-based map
Report any other issues here or on our [Community Forum](https://speckle.community/).
Check out the examples in 'speckle_demos' folder for Leaflet and OpenLayers implementation.
## Add Speckle Feature Layers to web-based maps and desktop apps
### Add Speckle layer in Javascript
Javascript-based mapping libraries can load speckle data as JSON using the following function:
```javascript
async function loadSpeckleData() => {
var speckle_model_url = 'https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=polygons';
const speckle_data = await fetch(speckle_model_url, {
headers: {'Accept': 'application/geo+json'}
}).then(response => response.json());
}
```
Then you can add it to the base map (e.g. using Leaflet and OpenStreetMap basemap tiles). The following example assumes an html div element with id="items-map":
```html
<script>
var map = L.map('items-map').setView([ 45 , -75 ], 5);
map.addLayer(new L.TileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 22,
attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a> &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
}
));
loadSpeckleData();
async function loadSpeckleData() => {
var speckle_model_url = 'https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=polygons';
const speckle_data = await fetch(speckle_model_url, {
headers: {'Accept': 'application/geo+json'}
}).then(response => response.json());
speckle_layer = L.geoJSON(speckle_data, {
onEachFeature: function (feature, layer) {
layer.setStyle({
fillColor: feature.displayProperties['color'],
color: myFillColor,
fillOpacity: 0.8,
weight: feature.displayProperties['lineWidth'],
radius: feature.displayProperties['radius']
});
}
});
speckle_layer.addTo(map);
map.fitBounds(speckle_layer.getBounds())
};
</script>
```
Check out 'speckle_demos' folder for more Leaflet and OpenLayers implementation.
### Add Speckle WFS layer in QGIS
1. Add new WFS Layer
+3
View File
@@ -88,13 +88,16 @@ def get_config(raw: bool = False, request: Request = None) -> dict:
# make sure to restrict the usage for the key
if ".speckle.systems" in request.url.split("?")[0] and map_api_key_speckle and len(map_api_key_speckle)>=20:
CONFIG["server"]["map"]["url"] = r'https://api.maptiler.com/maps/dataviz/{z}/{x}/{y}.png' + f'?key={map_api_key_speckle}'
CONFIG["server"]["map"]["key"] = f'{map_api_key_speckle}'
CONFIG["server"]["map"]["attribution"] = r'<a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'
elif map_api_key_local and len(map_api_key_local)>=20:
CONFIG["server"]["map"]["url"] = r'https://api.maptiler.com/maps/dataviz/{z}/{x}/{y}.png' + f'?key={map_api_key_local}'
CONFIG["server"]["map"]["key"] = f'{map_api_key_local}'
CONFIG["server"]["map"]["attribution"] = r'<a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'
else:
CONFIG["server"]["map"]["url"] = r'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
CONFIG["server"]["map"]["key"] = ""
CONFIG["server"]["map"]["attribution"] = r'&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>'
@@ -51,10 +51,11 @@ def separate_display_vals(displayValue: List) -> List[Tuple["Base"]]:
for i, item in enumerate(displayValue):
if isinstance(item, Mesh):
count = 0
all_count = len(item.faces)
for _ in item.faces:
try:
if count < all_count:
faces = []
verts = []
colors = []
@@ -71,20 +72,16 @@ def separate_display_vals(displayValue: List) -> List[Tuple["Base"]]:
new_vert = item.vertices[3*vert_index : 3*vert_index + 3]
verts.extend(new_vert)
if isinstance(item.colors, List) and len(item.colors)>2:
if isinstance(item.colors, List) and len(item.colors) > vert_index:
color = item.colors[vert_index]
colors.append(color)
count += vert_num+1
except IndexError:
continue
if len(colors)>0:
mesh = Mesh.create(faces= faces, vertices=verts, colors=colors)
else:
mesh = Mesh.create(faces= faces, vertices=verts)
display_objs.append((mesh, item))
if len(colors)>0:
mesh = Mesh.create(faces= faces, vertices=verts, colors=colors)
else:
mesh = Mesh.create(faces= faces, vertices=verts)
display_objs.append((mesh, item))
elif item is not None:
display_objs.append((item, item))
@@ -225,6 +222,7 @@ def assign_color(obj_display, props) -> None:
# initialize Speckle Blue color
color = DEFAULT_COLOR
opacity = None
try:
# prioritize renderMaterials for Meshes & Brep
@@ -232,8 +230,10 @@ def assign_color(obj_display, props) -> None:
# print(obj_display.get_member_names())
if hasattr(obj_display, 'renderMaterial'):
color = obj_display['renderMaterial']['diffuse']
opacity = obj_display['renderMaterial']['opacity']
elif hasattr(obj_display, '@renderMaterial'):
color = obj_display['@renderMaterial']['diffuse']
opacity = obj_display['@renderMaterial']['opacity']
elif isinstance(obj_display, Mesh) and isinstance(obj_display.colors, List) and len(obj_display.colors)>1:
sameColors = True
@@ -256,26 +256,35 @@ def assign_color(obj_display, props) -> None:
color = obj_display['@displayStyle']['color']
elif hasattr(obj_display, 'renderMaterial'):
color = obj_display['renderMaterial']['diffuse']
opacity = obj_display['renderMaterial']['opacity']
elif hasattr(obj_display, '@renderMaterial'):
color = obj_display['@renderMaterial']['diffuse']
opacity = obj_display['@renderMaterial']['opacity']
except Exception as e:
print(e)
r, g, b = get_r_g_b(color)
hex_color = '#%02x%02x%02x' % (r, g, b)
props['color'] = hex_color
a, r, g, b = get_r_g_b(color)
if opacity is not None and isinstance(opacity, float):
a_test = int(255* opacity)
if 0 <= a_test <= 255:
a = a_test
# hex_color = '#%02x%02x%02x' % (r, g, b)
props['color'] = f'rgba({r},{g},{b},{a})'
def get_r_g_b(rgb: int) -> Tuple[int, int, int]:
"""Get R, G, B values from int."""
r = g = b = 0
a = 255
try:
a = (rgb & 0xFF000000) >> 24
r = (rgb & 0xFF0000) >> 16
g = (rgb & 0xFF00) >> 8
b = rgb & 0xFF
except Exception as e:
r = g = b = 150
return r, g, b
a = 255
return a, r, g, b
def assign_display_properties(feature: Dict, f_base: "Base", obj_display: "Base") -> None:
"""Assign displayProperties to the feature."""
+64
View File
@@ -1,5 +1,69 @@
<!doctype html>
<html lang="en">
<style>
.switch {
position: absolute;
display: inline-block;
right: 1vw;
top: 10px;
width: 70px;
height: 23px;
z-index: 1000000;
}
.switch span {
position: absolute;
left: 30px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
border-radius: 12px;
}
.slider:before {
position: absolute;
content: "";
height: 15px;
width: 15px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(17px);
-ms-transform: translateX(17px);
transform: translateX(17px);
}
</style>
<head>
<meta charset="{{ config['server']['encoding'] }}">
<title>{% block title %}{% endblock %}{% if not self.title() %}{{ config['metadata']['identification']['title'] }}{% endif %}</title>
+223 -56
View File
@@ -5,15 +5,37 @@
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.css"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.Default.css"/>
<script src="https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster-src.js"></script>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<script src="https://cdn.maptiler.com/maptiler-sdk-js/v2.2.2/maptiler-sdk.umd.js"></script>
<link href="https://cdn.maptiler.com/maptiler-sdk-js/v2.2.2/maptiler-sdk.css" rel="stylesheet" />
{% endblock %}
{% block body_map %}
<div class="row">
{% if not data['missing_url'] %}
<div id="items-map" style="min-height: 80vh;"></div>
<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>
{% else %}
<div id="items-map" style="min-height: 40vh;"></div>
<div class="form-group" >
<label class="switch">3D
<input id="modeSwitch" type="checkbox" disabled="true">
<span class="slider round"></span>
</label>
</div>
<div id="map2d" style="height: 40vh;"></div>
{% endif %}
</div>
@@ -290,7 +312,12 @@
</tr>
<tr>
<p>
4. Speckle project comments: <a href = "https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments">https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments</a>
4. Rhino detailed building: <a href = "https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/9c43d7569c&limit=100000&northDegrees=-117">https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/9c43d7569c&limit=100000&northDegrees=-117</a>
</p>
</tr>
<tr>
<p>
5. Speckle project comments: <a href = "https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments">https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments</a>
</p>
</tr>
@@ -314,64 +341,204 @@
{% block extrafoot %}
<script>
var map = L.map('items-map').setView([45, 0], 2);
map.addLayer(new L.TileLayer(
'{{ config['server']['map']['url'] }}', {
maxZoom: 22,
attribution: '{{ config['server']['map']['attribution'] | safe }} &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
// attach even to modeSwitch btn
document.getElementById("modeSwitch").onclick = switchMode;
var el = document.getElementById("modeSwitch");
if (el.addEventListener)
el.addEventListener("click", switchMode, false);
else if (el.attachEvent)
el.attachEvent('onclick', switchMode);
function switchMode() {
btn = document.getElementById('modeSwitch');
if (btn.checked){
document.getElementById('map2d').style.height = '0vh';
document.getElementById('map3d').style.height = '80vh';
}
));
var geojson_data = {{ data['features'] | to_json | safe }};
// var geojson_comments = {{ data['comments'] | to_json | safe }};
var items = new L.GeoJSON(geojson_data, {
filter: (feature) => {
return feature.displayProperties["object_type"] == "geometry"
},
pointToLayer: (feature, latlng) => {
return new L.circleMarker(latlng)
},
onEachFeature: function (feature, layer) {
var url = '{{ data['speckle_project_url'] }}/models/' + feature.id.split("_")[0]
var html = '<span><td><p>' + feature['properties']['speckle_type'] + '</p></td><a href="' + url + '" target="_blank">' + feature['properties']['id'].split("_")[0] + '</a></span>';
layer.bindPopup(html);
var myFillColor = feature.displayProperties['color'];
var mylineWeight = feature.displayProperties['lineWidth'];
var myRadius = feature.displayProperties['radius'];
layer.setStyle({
fillColor: myFillColor,
color: myFillColor,
fillOpacity: 0.8,
weight: mylineWeight,
radius: myRadius
});
else {
document.getElementById('map2d').style.height = '80vh';
document.getElementById('map3d').style.height = '0vh';
}
}); //.addTo(map);
var comments = new L.GeoJSON(geojson_data, {
filter: (feature) => {
return feature.displayProperties["object_type"] == "comment"
},
pointToLayer: (feature, latlng) => {
return new L.marker(latlng)
},
onEachFeature: function (feature, layer) {
var url = '{{ data['speckle_project_url'] }}/models/' + feature.properties.resource_id + '#threadId=' + feature.id;
var html = '<span><td><a href="' + url + '" target="_blank">Go to thread</a></td> <td><p>' + feature['properties']['text_html'] + '</p></td> </span>';
layer.bindPopup(html);
}
}); //.addTo(map);
}
var group = L.featureGroup([items, comments])
.addTo(map);
//map.addLayer(lines);
var data = {{ data | to_json | safe }};
var geojson_data = {{ data['features'] | to_json | safe }};
map.fitBounds(group.getBounds());
// map.setZoom(19); // in order for the tiles to load
// Leaflet 2d map
function initialize2d() {
var map = L.map('map2d').setView([45, 0], 2);
map.addLayer(new L.TileLayer(
'{{ config['server']['map']['url'] }}', {
maxZoom: 22,
attribution: '{{ config['server']['map']['attribution'] | safe }} &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
}
));
var items = new L.GeoJSON(geojson_data, {
filter: (feature) => {
return feature.displayProperties["object_type"] == "geometry"
},
pointToLayer: (feature, latlng) => {
return new L.circleMarker(latlng)
},
onEachFeature: function (feature, layer) {
var url = '{{ data['speckle_project_url'] }}/models/' + feature.id.split("_")[0]
var html = '<span><td><p>' + feature['properties']['speckle_type'] + '</p></td><a href="' + url + '" target="_blank">' + feature['properties']['id'].split("_")[0] + '</a></span>';
layer.bindPopup(html);
var myFillColor = feature.displayProperties['color'];
var mylineWeight = feature.displayProperties['lineWidth'];
var myRadius = feature.displayProperties['radius'];
layer.setStyle({
fillColor: myFillColor,
color: myFillColor,
fillOpacity: 0.8,
weight: mylineWeight,
radius: myRadius
});
}
}); //.addTo(map);
var comments = new L.GeoJSON(geojson_data, {
filter: (feature) => {
return feature.displayProperties["object_type"] == "comment"
},
pointToLayer: (feature, latlng) => {
return new L.marker(latlng)
},
onEachFeature: function (feature, layer) {
var url = '{{ data['speckle_project_url'] }}/models/' + feature.properties.resource_id + '#threadId=' + feature.id;
var html = '<span><td><a href="' + url + '" target="_blank">Go to thread</a></td> <td><p>' + feature['properties']['text_html'] + '</p></td> </span>';
layer.bindPopup(html);
}
}); //.addTo(map);
var group = L.featureGroup([items, comments])
.addTo(map);
//map.addLayer(lines);
map.fitBounds(group.getBounds());
// map.setZoom(19); // in order for the tiles to load
};
// MapTiler 3d map
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16), parseInt(result[0], 16)] : null;
};
function rgbaToArgbList(color) {
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) {
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 initialize3d() {
maptilersdk.config.apiKey = '{{ config["server"]["map"]["key"] }}';
speckle_data = JSON.parse(JSON.stringify(data))
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (feature.geometry.type.includes("Polygon")) {
// check orientation of each PolygonPart, if vertical - shift points slightly
for (let p = 0; p < coords.length; p++) {
for (let c = 0; c < coords[p].length; c++) {
sum_orientation = 0;
polygon_pts = coords[p][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
createdPolygon = false;
if (-0.01 < sum_orientation && sum_orientation <0.01){
coords[p][c][0][0] += 0.0000001;
coords[p][c][0][1] += 0.0000001;
coords[p][c][1][0] -= 0.0000001;
coords[p][c][1][1] -= 0.0000001;
if(polygon_pts.length==3) {
createdPolygon = true;
multipolygon_coords = [coords[p][c]];
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":[multipolygon_coords]},
"properties": speckle_data.features[i].properties });
}
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",
"geometry": {"type": "MultiPolygon", "coordinates":[multipolygon_coords]},
"properties": speckle_data.features[i].properties });
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 });
};
};
if (createdPolygon == false){
multipolygon_coords = [coords[p][c]];
speckle_features.push({"id": speckle_features.length, "type":"Feature",
"geometry": {"type": "MultiPolygon", "coordinates":[multipolygon_coords]},
"properties": speckle_data.features[i].properties });
}
};
};
}
}
var extent = speckle_data["extent"];
speckle_data.features = speckle_features;
// Create deck.gl map
const deckgl = new deck.DeckGL({
container: 'map3d',
map: maptilersdk,
mapStyle: maptilersdk.MapStyle.STREETS.PASTEL,
initialViewState: {
longitude: extent[0] + (extent[2]-extent[0])/2,
latitude: extent[1] + (extent[3]-extent[1])/2,
zoom: 22,
pitch: 60,
bearing: 1.469387755102039
},
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),
})
]
});
}
initialize2d();
initialize3d();
</script>
+175
View File
@@ -0,0 +1,175 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Leaflet demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
</head>
<body>
<main style="margin-left: 20px;margin-right: 20px;">
<div class="row">
<h3>Speckle pygeoapi demo: construct URL</h3>
<div class="form-group" ><label style="min-width: 10vw;display:inline-block">Speckle Model URL: </label>
<input value="https://app.speckle.systems/projects/64753f52b7/models/338b386787" id="speckle_model" type="text" maxlength="512" style="min-width: 55vw;" class="searchField"/></div>
<div class="form-group"><label style="min-width: 10vw;display:inline-block">Data type: </label>
<select id="data_type" style="min-width: 55vw;">
<option value="polygons">polygons</option>
<option value="points">points</option>
<option value="lines">lines</option>
<option value="projectcomments">projectcomments</option>
</select>
</div>
<div class="form-group"><label style="min-width: 10vw;display:inline-block">Preserve attributes: </label>
<select id="preserve_attributes" style="min-width: 55vw;">
<option value="false">false</option>
<option value="true">true</option>
</select>
</div>
<div class="form-group"><label style="min-width: 10vw;display:inline-block">Feature limit: </label>
<input value="100000" id="limit" type="text" maxlength="512" style="min-width: 55vw;" class="searchField"/></div>
<div class="form-group"><label style="min-width: 10vw;display:inline-block">Lat: </label>
<input value="-0.031405" id="lat" type="text" maxlength="512" style="min-width: 55vw;" class="searchField"/></div>
<div class="form-group"><label style="min-width: 10vw;display:inline-block">Lon: </label>
<input value="109.335828" id="lon" type="text" maxlength="512" style="min-width: 55vw;" class="searchField"/></div>
<div class="form-group"><label style="min-width: 10vw;display:inline-block">North (degrees): </label>
<input value="" id="north_degrees" type="text" maxlength="512" style="min-width: 55vw;" class="searchField"/></div>
<div class="form-group"><label style="min-width: 10vw;display:inline-block">Final URL: </label>
<input value="" id="link" type="text" maxlength="512" style="min-width: 55vw;" class="searchField"/></div>
<input id="clickMe" type="button" value="Refresh map" onclick="doFunction();" />
</div>
<div>
<div class="row"><p></p></div>
<div class="row">
<div id="items-map" style="min-height: 60vh;"></div>
</div>
</div>
</main>
<script>
// attach event to a button click
document.getElementById("clickMe").onclick = doFunction;
var el = document.getElementById("clickMe");
if (el.addEventListener)
el.addEventListener("click", doFunction, false);
else if (el.attachEvent)
el.attachEvent('onclick', doFunction);
// create map
var map = L.map('items-map').setView([ 45 , -75 ], 5);
map.addLayer(new L.TileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 22,
attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a> &copy; Data: <a href="https://speckle.systems/">Speckle Systems</a>'
}
));
// load Speckle data
document.getElementById('link').disabled=true;
doFunction();
async function doFunction() {
map.eachLayer(function (layer) {
if (!(layer instanceof L.TileLayer)){
map.removeLayer(layer);
}
});
// construnt data URL
var link = "https://geo.speckle.systems/?speckleUrl=";
if (document.getElementById("speckle_model").value!=""){
link += document.getElementById("speckle_model").value.replace(" ", "")
}
if (document.getElementById("data_type").value!=""){
link += "&datatype=" + document.getElementById("data_type").value.replace(" ", "")
}
if (document.getElementById("limit").value!=""){
link += "&limit=" + document.getElementById("limit").value.replace(" ", "")
}
if (document.getElementById("preserve_attributes").value!=""){
link += "&preserveAttributes=" + document.getElementById("preserve_attributes").value.replace(" ", "")
}
if (document.getElementById("lon").value!=""){
link += "&lon=" + document.getElementById("lon").value.replace(" ", "")
}
if (document.getElementById("lat").value!=""){
link += "&lat=" + document.getElementById("lat").value.replace(" ", "")
}
if (document.getElementById("north_degrees").value!=""){
link += "&northDegrees=" + document.getElementById("north_degrees").value.replace(" ", "")
}
// set URL value to the text field
document.getElementById("link").value = link;
// get Speckle data
const speckle_data = await fetch(link, {
headers: {
'Accept': 'application/geo+json'
}
}).then(response => response.json());
// add data to map
speckle_layer = L.geoJSON(speckle_data, {
filter: (feature) => {
return feature.displayProperties["object_type"] == "comment"
},
pointToLayer: (feature, latlng) => {
return new L.marker(latlng)
},
onEachFeature: function (feature, layer) {
var html = '<span><td><p>' + feature['properties']['text_html'] + '</p></td> </span>';
layer.bindPopup(html);
}
});
speckle_layer.addTo(map);
speckle_layer2 = L.geoJSON(speckle_data, {
filter: (feature) => {
return feature.displayProperties["object_type"] == "geometry"
},
pointToLayer: (feature, latlng) => {
return new L.circleMarker(latlng)
},
onEachFeature: function (feature, layer) {
var html = '<span><td><p>' + feature['properties']['speckle_type'] + '</p></td></span>';
layer.bindPopup(html);
var myFillColor = feature.displayProperties['color'];
var mylineWeight = feature.displayProperties['lineWidth'];
var myRadius = feature.displayProperties['radius'];
layer.setStyle({
fillColor: myFillColor,
color: myFillColor,
fillOpacity: 0.8,
weight: mylineWeight,
radius: myRadius
});
}
});
speckle_layer2.addTo(map);
if (document.getElementById("data_type").value.replace(" ","").toLowerCase() == "projectcomments"){
map.fitBounds(speckle_layer.getBounds())
}else{
map.fitBounds(speckle_layer2.getBounds())
}
};
</script>
</body>
</html>
+287
View File
@@ -0,0 +1,287 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Maptalks demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<link rel="stylesheet" href="https://unpkg.com/maptalks/dist/maptalks.css">
<script type="text/javascript" src="https://unpkg.com/maptalks/dist/maptalks.min.js"></script>
<body>
<div class="row">
<h3>Speckle pygeoapi demo: display comments</h3>
</div>
<div id="map" class="container"></div>
<script>
var map = new maptalks.Map('map', {
center: [-0.113049, 51.498568],
zoom: 14,
pitch : 56,
bearing : 60,
baseLayer: new maptalks.TileLayer('base', {
urlTemplate: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
subdomains: ["a","b","c","d"],
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>'
})
});
(async () => {
const speckle_data2 = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/37d93c5d32&preserveAttributes=true', {
//const speckle_data = await fetch('http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/64753f52b7/models/338b386787&limit=1000000&lat=-0.031405&lon=109.335828&preserveAttributes=true', {
headers: {
'Accept': 'application/geo+json'
}
}).then(response => response.json());
console.log(speckle_data2)
var speckle_features = []
for (let i = 0; i < speckle_data2.features.length; i++) {
feature = speckle_data2.features[i];
coords = feature.geometry.coordinates;
if (feature.geometry.type.includes("Polygon")) {
// check orientation of each PolygonPart
for (let c = 0; c < coords[0].length; c++) {
sum_orientation = 0;
polygon_pts = coords[0][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
if (sum_orientation <0.01 ){
coords[0][c][0][0] += 0.000001;
coords[0][c][0][1] += 0.000001;
};
};
speckle_features.push(
new maptalks.MultiPolygon(coords, {
visible : true,
cursor : null,
symbol: {
'lineColor' : 'rgb(200,200,200)',
'lineOpacity' : 0.9,
'lineWidth' : 1.5,
'polygonFill' : feature.displayProperties.color,
'polygonOpacity' : 1
}
})
);
} else if (feature.geometry.type.includes("MultiLineString")){
speckle_features.push(
new maptalks.MultiLineString(coords, {
visible : true,
cursor : null,
symbol: {
'lineColor' : feature.displayProperties.color,
'lineOpacity' : 1,
'lineWidth' : 2
}
})
);
} else if (feature.geometry.type.includes("LineString")){
speckle_features.push(
new maptalks.LineString(coords, {
visible : true,
cursor : null,
symbol: {
'lineColor' : feature.displayProperties.color,
'lineOpacity' : 1,
'lineWidth' : 2
}
})
);
} else if (feature.geometry.type.includes("MultiPoint")){
symbol= {
'markerType': 'ellipse',
'markerFill': speckle_data.features[i].displayProperties.color,
'markerFillOpacity': 0.7,
'markerLineColor': speckle_data.features[i].displayProperties.color,
'markerLineWidth': 0,
'markerLineOpacity': 1,
'markerLineDasharray':[],
'markerWidth': 10,
'markerHeight': 10,
'markerDx': -10,
'markerDy': 0,
'markerOpacity' : 1,
'textFaceName' : 'sans-serif',
'textName' : speckle_data.features[i].properties["FID"],
'textFill' : '#34495e',
'textHorizontalAlignment' : 'right',
'textSize' : 20
};
if (feature.displayProperties["object_type"] == "comment"){
var strippedHtml = feature.properties.text_html.replaceAll('&emsp;', ' ').replaceAll('<br>', '\n').replace(/<[^>]+>/g, '');
symbol.textName = strippedHtml;
symbol.textSize = 10;
};
speckle_features.push(
new maptalks.MultiPoint(coords, {
visible : true,
cursor : null,
cursor : 'pointer',
symbol: symbol
})
);
}
}
speckle_layer2 = new maptalks.VectorLayer('vector2', speckle_features, { enableAltitude : true
, drawAltitude : {
//polygonFill : '#1bbc9b',
//polygonOpacity : 0.3,
//lineWidth : 0
}
}
);
speckle_layer2.addTo(map);
map.fitExtent(speckle_layer2.getExtent(), 0);
//map.fitBounds(speckle_layer.getBounds())
const speckle_data = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments', {
//const speckle_data = await fetch('http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/64753f52b7/models/338b386787&limit=1000000&lat=-0.031405&lon=109.335828&preserveAttributes=true', {
headers: {
'Accept': 'application/geo+json'
}
}).then(response => response.json());
console.log(speckle_data)
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (feature.geometry.type.includes("Polygon")) {
// check orientation of each PolygonPart
for (let c = 0; c < coords[0].length; c++) {
sum_orientation = 0;
polygon_pts = coords[0][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
if (sum_orientation <0.01 ){
coords[0][c][0][0] += 0.000001;
coords[0][c][0][1] += 0.000001;
};
};
speckle_features.push(
new maptalks.MultiPolygon(coords, {
visible : true,
cursor : null,
symbol: {
'lineColor' : 'rgb(200,200,200)',
'lineOpacity' : 0.3,
'lineWidth' : 0.5,
'polygonFill' : feature.displayProperties.color,
'polygonOpacity' : 1
}
})
);
} else if (feature.geometry.type.includes("MultiLineString")){
speckle_features.push(
new maptalks.MultiLineString(coords, {
visible : true,
cursor : null,
symbol: {
'lineColor' : feature.displayProperties.color,
'lineOpacity' : 1,
'lineWidth' : 2
}
})
);
} else if (feature.geometry.type.includes("LineString")){
speckle_features.push(
new maptalks.LineString(coords, {
visible : true,
cursor : null,
symbol: {
'lineColor' : feature.displayProperties.color,
'lineOpacity' : 1,
'lineWidth' : 2
}
})
);
} else if (feature.geometry.type.includes("MultiPoint")){
symbol= {
'markerType': 'ellipse',
'markerFill': speckle_data.features[i].displayProperties.color,
'markerFillOpacity': 0.7,
'markerLineColor': speckle_data.features[i].displayProperties.color,
'markerLineWidth': 0,
'markerLineOpacity': 1,
'markerLineDasharray':[],
'markerWidth': 10,
'markerHeight': 10,
'markerDx': -10,
'markerDy': 0,
'markerOpacity' : 1,
'textFaceName' : 'sans-serif',
'textName' : speckle_data.features[i].properties["FID"],
'textFill' : '#34495e',
'textHorizontalAlignment' : 'right',
'textSize' : 20
};
if (feature.displayProperties["object_type"] == "comment"){
var strippedHtml = feature.properties.text_html.replaceAll('&emsp;', ' ').replaceAll('<br>', '\n').replace(/<[^>]+>/g, '');
symbol.textName = strippedHtml;
symbol.textSize = 10;
};
speckle_features.push(
new maptalks.MultiPoint(coords, {
visible : true,
cursor : null,
cursor : 'pointer',
symbol: symbol
})
);
}
}
speckle_layer = new maptalks.VectorLayer('vector', speckle_features, { enableAltitude : true
, drawAltitude : {
//polygonFill : '#1bbc9b',
//polygonOpacity : 0.3,
//lineWidth : 0
}
}
);
speckle_layer.addTo(map);
map.fitExtent(speckle_layer.getExtent(), 0);
//map.fitBounds(speckle_layer.getBounds())
})();
</script>
</body>
</html>
+223
View File
@@ -0,0 +1,223 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Maptalks demo</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<link rel="stylesheet" href="https://unpkg.com/maptalks/dist/maptalks.css">
<script type="text/javascript" src="https://unpkg.com/maptalks/dist/maptalks.min.js"></script>
<body>
<div class="row">
<h3>Speckle pygeoapi demo: display polygons</h3>
</div>
<div id="map" class="container"></div>
<script>
var map = new maptalks.Map('map', {
center: [-0.113049, 51.498568],
zoom: 14,
pitch : 56,
bearing : 60,
baseLayer: new maptalks.TileLayer('base', {
urlTemplate: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
subdomains: ["a","b","c","d"],
attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>'
})
});
(async () => {
//const speckle_data = await fetch('https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/344f803f81/models/5582ab673e&datatype=projectcomments', {
//var speckle_url = 'http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/9c43d7569c&limit=1000000&datatype=polygons&preserveattributes=false';
// https://app.speckle.systems/projects/5feae56049/models/01c4183677
var speckle_url = 'http://localhost:5000/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/01c4183677&limit=1000000&datatype=polygons&preserveattributes=true';
//var speckle_url = 'https://geo.speckle.systems/?speckleUrl=https://app.speckle.systems/projects/5feae56049/models/9c43d7569c&northDegrees=-30&preserveAttributes=true';
const speckle_data = await fetch(speckle_url, {
headers: {
'Accept': 'application/geo+json'
}
}).then(response => response.json());
var speckle_features = []
for (let i = 0; i < speckle_data.features.length; i++) {
feature = speckle_data.features[i];
coords = feature.geometry.coordinates;
if (feature.geometry.type.includes("Polygon")) {
// check orientation of each PolygonPart, if vertical - shift points slightly
for (let p = 0; p < coords.length; p++) {
for (let c = 0; c < coords[p].length; c++) {
// each polygon Part unpacked
sum_orientation = 0;
polygon_pts = coords[p][c]; // usually 3 for Mesh faces
for (let k = 0; k < polygon_pts.length; k++){
index = k + 1
if (k == polygon_pts.length - 1){index = 0}
pt = polygon_pts[k]
pt2 = polygon_pts[index]
sum_orientation += (pt2[0] - pt[0]) * (pt2[1] + pt[1])
};
createdPolygon = false;
if (-0.01 < sum_orientation && sum_orientation <0.01){
coords[p][c][0][0] += 0.0000001;
coords[p][c][0][1] += 0.0000001;
coords[p][c][1][0] -= 0.0000001;
coords[p][c][1][1] -= 0.0000001;
if(polygon_pts.length==3) {
createdPolygon = true;
speckle_features.push(
new maptalks.MultiPolygon([coords[p][c]], {
visible : true,
cursor : null,
symbol: {
'lineColor' : 'rgb(200,200,200)',
'lineOpacity' : 0.3,
'lineWidth' : 0.5,
'polygonFill' : feature.displayProperties.color,
'polygonOpacity' : 1
}
})
);
}
else if (polygon_pts.length==4) {
createdPolygon = true;
speckle_features.push(
new maptalks.MultiPolygon([coords[p][c].slice(0,3)], {
visible : true,
cursor : null,
symbol: {
'lineColor' : 'rgb(200,200,200)',
'lineOpacity' : 0.3,
'lineWidth' : 0.5,
'polygonFill' : feature.displayProperties.color,
'polygonOpacity' : 1
}
})
);
speckle_features.push(
new maptalks.MultiPolygon([[coords[p][c][2], coords[p][c][3], coords[p][c][0]]], {
visible : true,
cursor : null,
symbol: {
'lineColor' : 'rgb(200,200,200)',
'lineOpacity' : 0.3,
'lineWidth' : 0.5,
'polygonFill' : feature.displayProperties.color,
'polygonOpacity' : 1
}
})
);
}
};
if (createdPolygon == false){
speckle_features.push(
new maptalks.MultiPolygon([coords[0][c]], {
visible : true,
cursor : null,
symbol: {
'lineColor' : 'rgb(200,200,200)',
'lineOpacity' : 0.3,
'lineWidth' : 0.5,
'polygonFill' : feature.displayProperties.color,
'polygonOpacity' : 1
}
})
);
}
};
};
} else if (feature.geometry.type.includes("MultiLineString")){
speckle_features.push(
new maptalks.MultiLineString(coords, {
visible : true,
cursor : null,
symbol: {
'lineColor' : feature.displayProperties.color,
'lineOpacity' : 1,
'lineWidth' : 2
}
})
);
} else if (feature.geometry.type.includes("LineString")){
speckle_features.push(
new maptalks.LineString(coords, {
visible : true,
cursor : null,
symbol: {
'lineColor' : feature.displayProperties.color,
'lineOpacity' : 1,
'lineWidth' : 2
}
})
);
} else if (feature.geometry.type.includes("MultiPoint")){
symbol= {
'markerType': 'ellipse',
'markerFill': speckle_data.features[i].displayProperties.color,
'markerFillOpacity': 0.7,
'markerLineColor': speckle_data.features[i].displayProperties.color,
'markerLineWidth': 0,
'markerLineOpacity': 1,
'markerLineDasharray':[],
'markerWidth': 10,
'markerHeight': 10,
'markerDx': -10,
'markerDy': 0,
'markerOpacity' : 1,
'textFaceName' : 'sans-serif',
'textName' : speckle_data.features[i].properties["FID"],
'textFill' : '#34495e',
'textHorizontalAlignment' : 'right',
'textSize' : 20
};
if (feature.displayProperties["object_type"] == "comment"){
var strippedHtml = feature.properties.text_html.replaceAll('&emsp;', ' ').replaceAll('<br>', '\n').replace(/<[^>]+>/g, '');
symbol.textName = strippedHtml;
symbol.textSize = 10;
};
speckle_features.push(
new maptalks.MultiPoint(coords, {
visible : true,
cursor : null,
cursor : 'pointer',
symbol: symbol
})
);
}
}
speckle_layer = new maptalks.VectorLayer('vector', speckle_features, { enableAltitude : true
, drawAltitude : {
//polygonFill : '#1bbc9b',
//polygonOpacity : 0.3,
//lineWidth : 0
}
}
);
speckle_layer.addTo(map);
map.fitExtent(speckle_layer.getExtent(), 0);
//map.fitBounds(speckle_layer.getBounds())
})();
</script>
</body>
</html>