@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
129 lines (123 loc) • 4.51 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import GirafeHTMLElement from './GirafeHTMLElement.js';
import { debounce } from '../tools/utils/debounce.js';
/*
Minimal template for a draggable object :
It must have 2 divs :
- One for the whole box (id="draggable")
- One for the header (id="header"). This is the div that will be used for dragging the whole box
- footer is optional
- use class girafe-draggable-window to get the gg floating window style
Example:
<div id="draggable" class="girafe-draggable-window">
<div id="header">
Click here to move
<img id="close" alt="close-icon" src="icons/close.svg" />
</div>
<div id="content">
<!-- PLACE CONTENT HERE -->
</div>
<div id="footer"></div>
</div>
Then in order to make an component draggable,
the base method makeDraggable() must be called after rendering the template.
That's it, it should work.
*/
class GirafeDraggableElement extends GirafeHTMLElement {
header;
closeButton;
container;
get host() {
return this.shadow.getRootNode().host;
}
posX = 0;
posY = 0;
constructor(component) {
super(component);
}
makeDraggable(container) {
this.container = container || document.querySelector('#content');
this.header = this.shadow.querySelector('#header');
this.setDefaultPosition();
this.header.onmousedown = (e) => this.dragMouseDown(this, e);
// Reposition the draggable element in the window if it is out of bounds
window.addEventListener('resize', debounce(() => this.resize(this), 200));
this.closeButton = this.shadow.getElementById('close');
if (!this.isNullOrUndefined(this.closeButton)) {
this.closeButton.onclick = () => this.closeWindow();
}
}
setDefaultPosition() {
const css = getComputedStyle(this.host);
this.host.style.top = css.top;
this.host.style.left = css.left;
}
closeWindow() {
throw new Error('This function must be overriden to close the associated window');
}
dragMouseDown(_this, e) {
e.preventDefault();
// get the mouse cursor position at startup:
_this.posX = e.clientX;
_this.posY = e.clientY;
document.onmouseup = () => _this.closeDragElement();
// call a function whenever the cursor moves:
document.onmousemove = (e) => _this.elementDrag(_this, e);
}
elementDrag(_this, e) {
e.preventDefault();
const hostRect = _this.host.getBoundingClientRect();
// Position left
const pos1 = _this.posX - e.clientX;
const newLeft = _this.host.offsetLeft - pos1;
const newRight = newLeft + hostRect.width;
if (newLeft < 0) {
_this.host.style.left = '0px';
}
else if (newRight > this.getContainerWidth()) {
_this.host.style.left = this.getContainerWidth() - hostRect.width + 'px';
}
else {
_this.posX = e.clientX;
_this.host.style.left = newLeft + 'px';
}
// Position top
const pos2 = _this.posY - e.clientY;
const newTop = _this.host.offsetTop - pos2;
const newBottom = newTop + hostRect.height;
if (newTop < 0) {
_this.host.style.top = '0px';
}
else if (newBottom > this.getContainerHeight()) {
_this.host.style.top = this.getContainerHeight() - hostRect.height + 'px';
}
else {
_this.posY = e.clientY;
_this.host.style.top = newTop + 'px';
}
}
getContainerWidth() {
return Math.max(this.container?.scrollWidth, this.container?.offsetWidth);
}
getContainerHeight() {
return Math.max(this.container?.scrollHeight, this.container?.offsetHeight);
}
resize(_this) {
const width = this.getContainerWidth();
const height = this.getContainerHeight();
const left = _this.host.style.left;
const top = _this.host.style.top;
if (parseInt(left) + _this.host.offsetWidth > width) {
_this.host.style.left = width - _this.host.offsetWidth + 'px';
}
if (parseInt(top) + _this.host.offsetHeight > height) {
_this.host.style.top = height - _this.host.offsetHeight + 'px';
}
}
closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
export default GirafeDraggableElement;