added geo widget
This commit is contained in:
parent
16c8a6068b
commit
2e55fa7510
|
@ -13,6 +13,7 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||
<script src="https://cdn.cloud-dev.d4science.org/common/js/bss-min-1.2.6.js"></script>
|
||||
<script src="../storage/d4s-storage.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/ol@v9.2.4/dist/ol.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="m-4">
|
||||
|
|
|
@ -43,6 +43,11 @@ class CCPInputWidgetController extends HTMLElement {
|
|||
this.innerHTML += `<d4s-ccp-input-remotefile readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-remotefile>`
|
||||
this.querySelector("d4s-ccp-input-remotefile").default = this.#data.schema.default
|
||||
|
||||
} else if (this.isGeo()) {
|
||||
|
||||
this.innerHTML += `<d4s-ccp-input-geo readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-remotefile>`
|
||||
this.querySelector("d4s-ccp-input-geo").default = this.#data.schema.default
|
||||
|
||||
} else if (this.isSecret()) {
|
||||
|
||||
this.innerHTML += `<d4s-ccp-input-secret readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs }" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-secret>`
|
||||
|
@ -130,6 +135,13 @@ class CCPInputWidgetController extends HTMLElement {
|
|||
(this.#data.schema.format.toLowerCase() === "remotefile")
|
||||
}
|
||||
|
||||
isGeo() {
|
||||
return (this.#data.schema.type === "string") &&
|
||||
("format" in this.#data.schema) &&
|
||||
(this.#data.schema.format != null) &&
|
||||
(this.#data.schema.format.toLowerCase() === "geo")
|
||||
}
|
||||
|
||||
isDateTime() {
|
||||
return (this.#data.schema.type === "string") &&
|
||||
("format" in this.#data.schema) &&
|
||||
|
@ -770,4 +782,206 @@ class CCPSecretInputWidgetController extends CCPBaseInputWidgetController {
|
|||
return out
|
||||
}
|
||||
}
|
||||
window.customElements.define('d4s-ccp-input-secret', CCPSecretInputWidgetController);
|
||||
window.customElements.define('d4s-ccp-input-secret', CCPSecretInputWidgetController);
|
||||
|
||||
class CCPGeoInputWidgetController extends CCPBaseInputWidgetController {
|
||||
|
||||
#format_dialog = null;
|
||||
#target = null
|
||||
#draw = null;
|
||||
#raster = null
|
||||
#source = null
|
||||
#map = null;
|
||||
#vector = null
|
||||
#index = null;
|
||||
#widget = null
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
|
||||
addToolContent() {
|
||||
|
||||
this.rootdoc.querySelector("div[name=tools]").innerHTML += `
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<svg name="trigger" style="width:24;height:24;fill:#007bff; cursor:pointer" viewBox="0 -960 960 960">
|
||||
<path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm-40-82v-78q-33 0-56.5-23.5T360-320v-40L168-552q-3 18-5.5 36t-2.5 36q0 121 79.5 212T440-162Zm276-102q20-22 36-47.5t26.5-53q10.5-27.5 16-56.5t5.5-59q0-98-54.5-179T600-776v16q0 33-23.5 56.5T520-680h-80v80q0 17-11.5 28.5T400-560h-80v80h240q17 0 28.5 11.5T600-440v120h40q26 0 47 15.5t29 40.5Z"/>
|
||||
</svg>
|
||||
<div name="map" class="d-none position-absolute shadow border border-primary bg-light p-2" style="right:0;z-index:1000; line-height:1.5rem;overflow:hidden;padding:5px;">
|
||||
<div name="maptoolbar" class="mb-1" style="border-bottom: solid 1px gray;">
|
||||
<div class="d-flex justify-content-between m-0">
|
||||
<div>
|
||||
<span title="Draw a circle" name="Circle" class="btn text-primary p-0 material-icons">radio_button_unchecked</span>
|
||||
<span title="Select a Point" name="Point" class="btn text-primary p-0 material-icons">my_location</span>
|
||||
<span title="Draw a Polygon" name="Polygon" class="btn text-primary p-0 material-icons">polyline</span>
|
||||
<span title="Delete all" name="deletebtn" class="btn text-danger p-0 material-icons">delete</span>
|
||||
</div>
|
||||
<div>
|
||||
<span title="Set geometry" class="btn btn-primary" style="font-weight:bold" name="selectbtn">Export</span>
|
||||
<span title="Close" class="material-icons btn text-danger p-0" style="font-weight:bold" name="closebtn">close</span>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted m-0">Draw and export geometry</small>
|
||||
</div>
|
||||
<div style="width:500px;height:500px;position:relative;">
|
||||
<style>
|
||||
#div[name=internalmap]{
|
||||
width: 100%;
|
||||
height:100%;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
<div name="internalmap"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" style="background-color:rgba(0,0,0,0.3)" name="format" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content shadow-lg border-primary">
|
||||
<div class="modal-body">
|
||||
Choose export format.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<span title="Export WKT" name="wkt" class="btn btn-info">WKT</span>
|
||||
<span title="Export to GML" name="gml" class="btn btn-primary">GML</span>
|
||||
<span title="Export to GeoJSON" name="geojson" class="btn btn-secondary">GeoJSON</span>
|
||||
<span title="Cancel" name="cancel" class="btn btn-danger">Cancel</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
// Init map
|
||||
this.init()
|
||||
|
||||
this.rootdoc.querySelector("div[name=maptoolbar]").addEventListener("click", ev=>{
|
||||
const type = ev.target.getAttribute("name")
|
||||
if(type === "closebtn"){
|
||||
this.#widget.classList.add("d-none")
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
}if(type === "selectbtn"){
|
||||
this.#widget.classList.add("d-none")
|
||||
this.#format_dialog.style.display = "block"
|
||||
this.#format_dialog.classList.add("show")
|
||||
this.#index = this.value.length - 1
|
||||
const alltargets = this.#target = this.rootdoc.querySelectorAll("textarea")
|
||||
for(let i=0; i < alltargets.length;i++){
|
||||
if(!alltargets.item(i).value[i]){
|
||||
this.#index = i
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.#target = this.rootdoc.querySelectorAll("textarea").item(this.#index)
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
}else if(["Circle", "Point", "Polygon"].indexOf(type) !== -1){
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
if(this.#draw != null && this.#draw.type === type) return;
|
||||
if(this.#draw != null) this.#map.removeInteraction(this.#draw);
|
||||
this.#draw = new ol.interaction.Draw({source: this.#source, type : type})
|
||||
this.#map.addInteraction(this.#draw)
|
||||
}else if(type === "deletebtn"){
|
||||
this.undoAllDrawings()
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener("keydown", ev=>{
|
||||
if (ev.ctrlKey && ev.key === 'z') {
|
||||
this.undoDrawing()
|
||||
}else if(ev.key === "Escape"){
|
||||
this.stopDrawing()
|
||||
}
|
||||
})
|
||||
|
||||
this.#format_dialog = this.rootdoc.querySelector("div.modal[name=format]")
|
||||
this.#format_dialog.addEventListener("click", ev => {
|
||||
ev.stopPropagation()
|
||||
ev.preventDefault()
|
||||
const features = this.#source.getFeatures()
|
||||
if( features.length && this.#index != null && this.#target != null){
|
||||
const name = ev.target.getAttribute("name")
|
||||
var format
|
||||
if(name === "wkt") {
|
||||
format = new ol.format.WKT()
|
||||
}else if(name === "geojson"){
|
||||
format = new ol.format.GeoJSON()
|
||||
}else if(name === "gml"){
|
||||
format = new ol.format.GML()
|
||||
}
|
||||
const result = features.map(f=>{
|
||||
const geom = f.getGeometry().getType() === "Circle" ? ol.geom.Polygon.fromCircle(f.getGeometry(), 50) : f.getGeometry()
|
||||
return format.writeGeometry(geom)
|
||||
}).join("\n")
|
||||
|
||||
this.#target.value = this.value[this.#index] = result
|
||||
const newev = new Event("input", { bubbles : true})
|
||||
this.dispatchEvent(newev)
|
||||
}
|
||||
|
||||
this.#format_dialog.style.display = "none"
|
||||
this.#format_dialog.classList.remove("show")
|
||||
})
|
||||
|
||||
this.rootdoc.querySelector("svg[name=trigger]").addEventListener("click", ev => {
|
||||
this.#widget.classList.toggle("d-none")
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
})
|
||||
}
|
||||
|
||||
init(){
|
||||
this.#widget = this.rootdoc.querySelector("div[name=map]")
|
||||
this.#draw = null
|
||||
this.#raster = new ol.layer.Tile({source: new ol.source.OSM()});
|
||||
this.#source = new ol.source.Vector({wrapX: false});
|
||||
this.#vector = new ol.layer.Vector({source: this.#source});
|
||||
|
||||
this.#map = new ol.Map({
|
||||
layers: [this.#raster, this.#vector],
|
||||
target: this.rootdoc.querySelector("div[name=internalmap]"),
|
||||
view: new ol.View({center: [0, 0], zoom: 4 }),
|
||||
controls :[]
|
||||
})
|
||||
}
|
||||
|
||||
undoAllDrawings(){
|
||||
this.#source.clear()
|
||||
}
|
||||
|
||||
undoDrawing(){
|
||||
const features = this.#source.getFeatures()
|
||||
if(features.length){
|
||||
this.#source.removeFeature(features[features.length-1])
|
||||
}
|
||||
}
|
||||
|
||||
stopDrawing(){
|
||||
if(this.#draw){
|
||||
this.#draw.abortDrawing()
|
||||
this.#map.removeInteraction(this.#draw);
|
||||
this.#draw = null
|
||||
}
|
||||
}
|
||||
|
||||
content() {
|
||||
if(!this.readonly && !this.querySelector("div[name=map]")) this.addToolContent();
|
||||
if (this.value.length <= 1) {
|
||||
return `
|
||||
<textarea name="${this.name}" data-index="0" class="ccp-input my-2 form-control" placeholder="${this.title}" type="${this.type}" name="${this.name}" rows="5" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}>${this.value.length ? this.value[0] : ''}</textarea>
|
||||
`
|
||||
}
|
||||
var out =
|
||||
this.value.map((c, i) => {
|
||||
return `
|
||||
<textarea name="${this.name}" data-index="${i}" class="ccp-input my-2 form-control" placeholder="${this.title}" type="${this.type}" name="${this.name}" rows="5" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}>${c}</textarea>
|
||||
`
|
||||
}).join("\n")
|
||||
return out
|
||||
}
|
||||
}
|
||||
window.customElements.define('d4s-ccp-input-geo', CCPGeoInputWidgetController);
|
||||
|
|
|
@ -127,6 +127,7 @@ class CCPInputWidgetEditorController extends HTMLElement{
|
|||
<option value="code" ${this.isSelectedFormat('code') ? "selected" : ""}>Code</option>
|
||||
<option value="file" ${this.isSelectedFormat('file') ? "selected" : ""}>File</option>
|
||||
<option value="remotefile" ${this.isSelectedFormat('remotefile') ? "selected" : ""}>Workspace file</option>
|
||||
<option value="geo" ${this.isSelectedFormat('geo') ? "selected" : ""}>Geography</option>
|
||||
<option value="secret" ${this.isSelectedFormat('secret') ? "selected" : ""}>Secret</option>
|
||||
<option value="url" ${this.isSelectedFormat('url') ? "selected" : ""}>Url</option>
|
||||
</select>
|
||||
|
|
Loading…
Reference in New Issue