Crude geo data for conservatipn place

This commit is contained in:
Nicolò P 2024-11-14 15:54:47 +01:00
parent 99383daf3e
commit 70f1b7090a
8 changed files with 147 additions and 17 deletions

View File

@ -1,13 +1,63 @@
import { Controller } from '@hotwired/stimulus';
import L from "leaflet";
/**
*/
export default class extends Controller {
static targets = [ 'map',];
static values = {
state: Number,
};
static targets = [ 'map', 'modal', 'coords', 'name', 'container'];
initialize() {
this.setIcon();
this.coordinates = this.coordsTarget.textContent.split(', ');
const map = L.map(this.mapTarget.id, {
attributionControl: false,
minZoom: 5,
}).setView(this.coordinates, 17);
map.crs = L.CRS.EPSG4326;
this.map = map;
this.addOsMap();
this.addMarker();
}
open() {
this.modalTarget.classList.add('is-active');
let map = this.map;
map.invalidateSize();
}
close() {
this.modalTarget.classList.remove('is-active');
}
addOsMap() {
let osmap = new L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxNativeZoom : 22,
maxZoom: 22,
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
osmap.addTo(this.map);
}
setIcon() {
this.icon = L.icon({
iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png'
});
}
addMarker() {
L.marker(
this.coordinates,
{icon: this.icon}
)
.bindTooltip(this.nameTarget.textContent)
.openTooltip()
.addTo(this.map);
}
}

View File

@ -1,6 +1,7 @@
@import url('../fonts/stylesheet.css');
@import url('../fontawesome-free-6.6.0-web/css/all.min.css');
@import url('../vendor/bulma/css/bulma.min.css');
@import url('../vendor/leaflet/dist/leaflet.min.css');
:root {
--arcoa-blue: rgba(66,135,199,0.98);

View File

@ -40,6 +40,7 @@ security:
- { path: ^/bibliography, roles: ROLE_USER }
- { path: ^/collection, roles: ROLE_USER }
- { path: ^/collector, roles: ROLE_USER }
- { path: ^/conservation_place, roles: ROLE_USER }
- { path: ^/document, roles: ROLE_USER }
- { path: ^/object, roles: ROLE_USER }
- { path: ^/site, roles: ROLE_USER }

View File

@ -17,6 +17,13 @@ class ConservationPlaceController extends AbstractController
#[Route('/conservation_place/{id<\d+>}', name: 'app_conservation_place')]
public function index(ConservationPlace $conservationPlace, EntityManagerInterface $em): Response
{
$repo = $em->getRepository(ConservationPlace::class);
$coords = $repo->coordinates($conservationPlace->getId());
$conservationPlace->setLat((float) $coords['lat']);
$conservationPlace->setLng((float) $coords['lng']);
return $this->render('conservation_place/index.html.twig', [
'controller_name' => 'ConservationPlaceController',
'record' => $conservationPlace,

View File

@ -29,7 +29,9 @@ class ConservationPlace implements RecordInterface
private ?string $place = null;
//#[ORM\Column(name: 'coord_cons', type: Types::TEXT)]
private ?string $coordinates = null;
private ?float $lat = null;
private ?float $lng = null;
#[ORM\Column(name: 'reg_cons', type: Types::TEXT)]
private ?string $region = null;
@ -309,4 +311,28 @@ class ConservationPlace implements RecordInterface
return $this;
}
public function getLat(): float
{
return $this->lat;
}
public function setLat(float $lat): static
{
$this->lat = $lat;
return $this;
}
public function getLng(): float
{
return $this->lng;
}
public function setLng(float $lng): static
{
$this->lng = $lng;
return $this;
}
}

View File

@ -75,4 +75,22 @@ class ConservationPlaceRepository extends ServiceEntityRepository
return new ArrayCollection($query->getResult());
}
public function coordinates(int $id): ?array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT
ST_X(coord_cons) as lng,
ST_Y(coord_cons) as lat
FROM conservation_place cp
WHERE cp.id = :id
';
$result = $conn->executeQuery($sql, ['id' => $id]);
return $result->fetchAssociative();
}
}

View File

@ -3,7 +3,7 @@
{% block title %}Conservation place - {{ record.place }} | ArCOA{% endblock %}
{% block rightpanel %}
<div class="container" style="max-width: 60vw" data-controller="delete-record">
<div class="container" style="max-width: 60vw" data-controller="delete-record map">
<p class="pb-3">
<a class="button is-link is-outlined"
@ -38,7 +38,7 @@
</article>
<div class="card p-5">
{% if not is_granted('ROLE_READER') %}
{% if app.user and not is_granted('ROLE_READER') %}
<div class="columns">
<div class="column is-half"></div>
<div class="column has-text-right">
@ -83,10 +83,24 @@
<tr><th>Record ID</th><td>{{ record.id }}</td></tr>
<tr><th>Status</th><td>{{ record.getStatus() }}</td></tr>
<tr><th>Editor(s)</th><td>{{ record.editor }}</td></tr>
<tr><th>Conservation place</th><td data-delete-record-target="name">{{ record.place }}</td></tr>
<tr><th>Conservation place</th>
<td data-delete-record-target="name" data-map-target="name">
{{ record.place }}
</td>
</tr>
<tr><th>Region</th><td>{{ record.region }}</td></tr>
<tr><th>Province</th><td>{{ record.province }}</td></tr>
<tr><th>Municipality</th><td>{{ record.municipality }}</td></tr>
<tr><th>Coordinates</th>
<td>
<span data-map-target="coords">{{ record.lat }}, {{ record.lng }}</span>
<button class="button is-link is-small ml-3" data-action="click->map#open">
<span class="icon is-small p-2">
<i class="fa fa-map"></i>
</span>
</button>
</td>
</tr>
<tr><th>Description</th><td>{{ record.description }}</td></tr>
<tr><th>Short description</th><td>{{ record.shortDescription }}</td></tr>
<tr><th>External identifier(s)</th><td>{{ record.externalIdentifier }}</td></tr>
@ -121,5 +135,26 @@
</footer>
</div>
</div>
<div class="modal" data-map-target="modal">
<div class="modal-background" data-action="click->map#close"></div>
<div class="modal-card" style="min-width: 900px;">
<header class="modal-card-head">
<span class="icon is-large has-text-link">
<i class="fa fa-map fa-2x"></i>
</span>
<p class="modal-card-title pl-2 pt-1 pb-1"><strong>Interactive map</strong></p>
<button class="delete" aria-label="close" data-action="click->map#close"></button>
</header>
<section class="modal-card-body p-0">
<div data-map-target="map" id="map" style="min-height: 400px; max-width: 900px"></div>
</section>
<footer class="modal-card-foot">
<div class="buttons is-right">
<button class="button is-light" data-action="click->map#close">Close</button>
</div>
</footer>
</div>
</div>
</div>
{% endblock %}

View File

@ -61,15 +61,7 @@
<div class="column is-one-fifth arcoa-menu mb-0">
<aside class="menu" data-controller="menu"
data-menu-state-value="0">
{% if app.request.attributes.get('_route') != 'app_home' %}
<p class="menu-label has-text-white mt-3 pt-5 pl-5 is-size-6">
<span class="icon is-clickable">
<i class="fa fa-home"></i>
</span>
<a href="{{ path('app_home') }}" class="has-text-white">ArCOA Home</a>
</p>
{% endif %}
{% if 'ROLE_READER' not in app.user.roles %}
{% if app.user and 'ROLE_READER' not in app.user.roles %}
<p class="menu-label has-text-white mt-3 pt-5 pl-5 is-size-6">
Vocabularies
<span class="icon is-clickable pl-4" id="for-vocabs" data-action="click->menu#toggle">