agentscape
Version:
Agentscape is a library for creating agent-based simulations. It provides a simple API for defining agents and their behavior, and for defining the environment in which the agents interact. Agentscape is designed to be flexible and extensible, allowing
279 lines (265 loc) • 9.76 kB
JavaScript
const DRAG_HANDLE_ICON = `
<svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="4.5" cy="2.5" r=".6" fill="#000000" />
<circle cx="4.5" cy="4.5" r=".6" fill="#000000" />
<circle cx="4.5" cy="6.499" r=".6" fill="#000000" />
<circle cx="4.5" cy="8.499" r=".6" fill="#000000" />
<circle cx="4.5" cy="10.498" r=".6" fill="#000000" />
<circle cx="4.5" cy="12.498" r=".6" fill="#000000" />
<circle cx="6.5" cy="2.5" r=".6" fill="#000000" />
<circle cx="6.5" cy="4.5" r=".6" fill="#000000" />
<circle cx="6.5" cy="6.499" r=".6" fill="#000000" />
<circle cx="6.5" cy="8.499" r=".6" fill="#000000" />
<circle cx="6.5" cy="10.498" r=".6" fill="#000000" />
<circle cx="6.5" cy="12.498" r=".6" fill="#000000" />
<circle cx="8.499" cy="2.5" r=".6" fill="#000000" />
<circle cx="8.499" cy="4.5" r=".6" fill="#000000" />
<circle cx="8.499" cy="6.499" r=".6" fill="#000000" />
<circle cx="8.499" cy="8.499" r=".6" fill="#000000" />
<circle cx="8.499" cy="10.498" r=".6" fill="#000000" />
<circle cx="8.499" cy="12.498" r=".6" fill="#000000" />
<circle cx="10.499" cy="2.5" r=".6" fill="#000000" />
<circle cx="10.499" cy="4.5" r=".6" fill="#000000" />
<circle cx="10.499" cy="6.499" r=".6" fill="#000000" />
<circle cx="10.499" cy="8.499" r=".6" fill="#000000" />
<circle cx="10.499" cy="10.498" r=".6" fill="#000000" />
<circle cx="10.499" cy="12.498" r=".6" fill="#000000" />
</svg>
`;
class DragPage extends HTMLElement {
static get observedAttributes() {
return ['heading', 'key', 'minimized', 'color'];
}
constructor() {
super();
this.initWidth = 400;
this.defaultHeaderColor = '#2196F3';
this.handleBtnClick = (event) => {
const el = event.target;
switch (el.id) {
case 'close':
this.dispatchEvent(new Event('remove'));
this.remove();
break;
case 'minimize':
this.minimized = !this.minimized;
this.dispatchEvent(new Event('toggleminimize', { bubbles: true, composed: true }));
break;
default:
break;
}
};
this.handleDblCLick = () => {
this.minimized = !this.minimized;
this.dispatchEvent(new Event('toggleminimize', { bubbles: true, composed: true }));
};
this.pos = { x: 0, y: 0 };
this.didMove = false;
// private moveThreshold: number = 5;
this.beginElementDrag = (event) => {
event.preventDefault();
this.setAttribute('active', 'true');
// get the mouse cursor position at startup:
this.pos.x = event.clientX;
this.pos.y = event.clientY;
document.onmouseup = this.endElementDrag;
// call a function whenever the cursor moves:
document.onmousemove = this.elementDrag;
};
this.elementDrag = (event) => {
event.preventDefault();
// calculate the new cursor position:
const pos1 = this.pos.x - event.clientX;
const pos2 = this.pos.y - event.clientY;
this.pos.x = event.clientX;
this.pos.y = event.clientY;
this.didMove = true;
this.dispatchEvent(new Event('dragstart', { bubbles: true, composed: true }));
// set the element's new position:
const newPosition = { top: this.offsetTop - pos2, left: this.offsetLeft - pos1 };
this.style.top = newPosition.top + 'px';
this.style.left = newPosition.left + 'px';
};
this.endElementDrag = () => {
// release element
document.onmouseup = null;
document.onmousemove = null;
this.setAttribute('active', 'false');
if (this.didMove) {
this.storePosition();
this.dispatchEvent(new Event('dragend', { bubbles: true, composed: true }));
this.didMove = false;
}
};
}
connectedCallback() {
const style = `
:root {
width: auto;
}
:host {
position: absolute;
z-index: 9;
background-color: #ffffff;
text-align: center;
border: 1px solid #000000;
width: auto;
}
:host([active]) {
z-index: 999;
}
:host([disabled]) #header {
background-color: #9E9E9E;
cursor: unset;
}
#header {
display: flex;
justify-content: space-between;
padding: 10px;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
#drag-handle {
width: 20px;
height: 20px;
cursor: move;
}
#drag-handle svg {
width: 20px;
height: 20px;
}
#heading {
margin: 0 auto;
}
#controls {
display: inline-flex;
margin-left: 10px;
}
.btn {
line-height: 9px;
width: 10px;
height: 10px;
border: 1px solid black;
border-radius: 3px;
box-shadow: 1px 1px black;
cursor: pointer;
color: white;
}
.btn:not(:last-of-type) {
margin: 0 5px 0 0;
}
.btn:hover {
box-shadow: -1px -1px black;
border: 1px solid black;
color: white;
}
:host([disabled]) .btn, :host([disabled]) .btn:hover {
border: 1px solid #616161;
box-shadow: inset 1px 1px black;
color: #424242;
cursor: unset;
}
.btn:active {
box-shadow: inset 1px 1px black;
}
`;
const template = document.createElement('template');
template.innerHTML = `
<style>${style}</style>
<div id="header">
<div id="drag-handle">${DRAG_HANDLE_ICON}</div>
<div id="heading">${this.heading}</div>
<div id="controls">
<div id="minimize" class="btn">-</div>
</div>
</div>
<slot id="content"></slot>
`;
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(template.content.cloneNode(true));
this.headerRef = this.shadowRoot.querySelector('#header');
this.titleRef = this.shadowRoot.querySelector('#heading');
this.dragHandleRef = this.shadowRoot.querySelector('#drag-handle');
this.restorePosition();
this.dragHandleRef.addEventListener('mousedown', this.beginElementDrag);
this.dragHandleRef.addEventListener('dblclick', this.handleDblCLick);
this.headerRef.querySelectorAll('.btn').forEach((btnEl) => btnEl.addEventListener('click', this.handleBtnClick));
// set the initial width to the width of the content
this.initWidth = this.getBoundingClientRect().width;
// update the z-index when the element is clicked
this.addEventListener('click', () => {
if (this.id !== 'canvas_main') {
this.style.zIndex = '3';
const otherPanes = Array.from(document.getElementsByTagName('drag-pane')).filter((el) => el !== this && el.id !== 'canvas_main');
otherPanes.forEach((el) => el.style.zIndex = '2');
}
});
}
get heading() {
return this.getAttribute('heading') || '';
}
set heading(newState) {
this.setAttribute('heading', newState);
}
get minimized() {
return this.getAttribute('minimized') === 'true' || this.hasAttribute('minimized') && this.getAttribute('minimized') === '';
}
set minimized(newState) {
if (newState) {
this.setAttribute('minimized', 'true');
}
else {
this.removeAttribute('minimized');
}
}
set color(newColor) {
this.setAttribute('color', newColor);
}
get color() {
return this.getAttribute('color') || this.defaultHeaderColor;
}
get key() {
return this.getAttribute('key') || undefined;
}
set key(newValue) {
if (newValue) {
this.setAttribute('key', newValue);
}
else {
this.removeAttribute('key');
}
}
attributeChangedCallback(_name) {
if (_name === 'minimized') {
if (this.minimized) {
// this.style.height = '30px'
this.shadowRoot.querySelector('#content').style.display = 'none';
this.style.width = this.initWidth + 'px';
}
else {
// this.style.height = 'auto'
this.shadowRoot.querySelector('#content').style.display = 'block';
this.style.width = this.initWidth + 'px';
}
}
}
storePosition() {
if (this.key) {
window.localStorage.setItem(`drag-pane-${this.key}`, JSON.stringify(this.pos));
}
}
restorePosition() {
if (this.key) {
const storeValue = window.localStorage.getItem(`drag-pane-${this.key}`);
if (storeValue) {
this.pos = JSON.parse(storeValue);
this.style.top = this.pos.y + 'px';
this.style.left = this.pos.x + 'px';
}
}
}
}
window.customElements.define('drag-pane', DragPage);
export default DragPage;
//# sourceMappingURL=DragPane.js.map