import { extend, isNil, isString } from "../core/util";
import { createEl } from "../core/util/dom";
import { Point } from "../geo";
import DragHandler from "../handler/Drag";
import Control, { ControlOptionsType, DomPositionType } from "./Control";
/**
* @property {Object} options - options
* @property {Object} [options.position='top-right'] - position of the control
* @property {Boolean} [options.draggable=true] - whether the panel can be dragged
* @property {Boolean} [options.custom=false] - whether the panel's content is customized .
* @property {String|HTMLElement} options.content - panel's content, can be a dom element or a string.
* @property {Boolean} [options.closeButton=true] - whether to display the close button on the panel.
* @memberOf control.Panel
* @instance
*/
const options: PanelOptionsType = {
position: "top-right",
draggable: true,
custom: false,
content: "",
closeButton: true,
};
/**
* @classdesc
* Class for panel controls.
* @category control
* @extends control.Control
* @memberOf control
* @example
* var panel = new Panel({
* position : {'bottom': '0', 'right': '0'},
* draggable : true,
* custom : false,
* content : '
hello
',
* closeButton : true
* }).addTo(map);
*/
class Panel extends Control {
draggable: DragHandler;
//@internal
_startPos: Point;
//@internal
_startPosition: DomPositionType;
/**
* method to build DOM of the control
* @param {Map} map map to build on
* @return {HTMLDOMElement}
*/
buildOn(): HTMLDivElement {
let dom;
if (this.options["custom"]) {
if (isString(this.options["content"])) {
dom = createEl("div");
dom.innerHTML = this.options["content"];
this._appendCustomClass(dom);
} else {
dom = this.options["content"];
}
} else {
dom = createEl("div", "maptalks-panel");
this._appendCustomClass(dom);
if (this.options["closeButton"]) {
const closeButton = createEl(
"a",
"maptalks-close"
) as HTMLLinkElement;
closeButton.innerText = "×";
closeButton.href = "javascript:;";
closeButton.onclick = () => {
dom.style.display = "none";
this.fire("close");
};
dom.appendChild(closeButton);
}
const panelContent = createEl("div", "maptalks-panel-content");
if (isString(this.options["content"])) {
panelContent.innerHTML = this.options["content"];
} else {
panelContent.appendChild(this.options.content);
}
dom.appendChild(panelContent);
}
this.draggable = new DragHandler(dom, {
cancelOn: this._cancelOn.bind(this),
ignoreMouseleave: true,
});
this.draggable
.on("dragstart", this._onDragStart, this)
.on("dragging", this._onDragging, this)
.on("dragend", this._onDragEnd, this);
if (this.options["draggable"]) {
this.draggable.enable();
}
return dom;
}
/**
* update control container
* @return {control.Panel} this
*/
update() {
if (this.draggable) {
this.draggable.disable();
delete this.draggable;
}
return Control.prototype.update.call(this);
}
/**
* Set the content of the Panel.
* @param {String|HTMLElement} content - content of the infowindow.
* return {control.Panel} this
* @fires Panel#contentchange
*/
setContent(content: string | HTMLElement) {
const old = this.options["content"];
this.options["content"] = content;
/**
* contentchange event.
*
* @event Panel#contentchange
* @type {Object}
* @property {String} type - contentchange
* @property {control.Panel} target - Panel
* @property {String|HTMLElement} old - old content
* @property {String|HTMLElement} new - new content
*/
this.fire("contentchange", {
old: old,
new: content,
});
if (this.isVisible()) {
this.update();
}
return this;
}
/**
* Get content of the infowindow.
* @return {String|HTMLElement} - content of the infowindow
*/
getContent() {
return this.options["content"];
}
//@internal
_cancelOn(domEvent) {
const target = domEvent.srcElement || domEvent.target,
tagName = target.tagName.toLowerCase();
if (
tagName === "button" ||
tagName === "input" ||
tagName === "select" ||
tagName === "option" ||
tagName === "textarea"
) {
return true;
}
return false;
}
//@internal
_onDragStart(param) {
this._startPos = param["mousePos"];
this._startPosition = extend({}, this.getPosition());
/**
* drag start event
* @event control.Panel#dragstart
* @type {Object}
* @property {String} type - dragstart
* @property {UIMarker} target - the panel control fires event
* @property {Point} mousePos - mouse position
* @property {Event} domEvent - dom event
*/
this.fire("dragstart", param);
}
//@internal
_onDragging(param) {
const pos = param["mousePos"];
const offset = pos.sub(this._startPos);
const startPosition = this._startPosition;
const position = this.getPosition();
if (!isNil(position["top"])) {
position["top"] =
parseInt(startPosition["top"] as string) + offset.y;
}
if (!isNil(position["bottom"])) {
position["bottom"] =
parseInt(startPosition["bottom"] as string) - offset.y;
}
if (!isNil(position["left"])) {
position["left"] =
parseInt(startPosition["left"] as string) + offset.x;
}
if (!isNil(position["right"])) {
position["right"] =
parseInt(startPosition["right"] as string) - offset.x;
}
this.setPosition(position);
/**
* dragging event
* @event control.Panel#dragging
* @type {Object}
* @property {String} type - dragging
* @property {UIMarker} target - the panel control fires event
* @property {Point} mousePos - mouse position
* @property {Event} domEvent - dom event
*/
this.fire("dragging", param);
}
//@internal
_onDragEnd(param) {
delete this._startPos;
delete this._startPosition;
/**
* drag end event
* @event control.Panel#dragend
* @type {Object}
* @property {String} type - dragend
* @property {UIMarker} target - the panel control fires event
* @property {Point} mousePos - mouse position
* @property {Event} domEvent - dom event
*/
this.fire("dragend", param);
}
/**
* Get the connect points of panel for connector lines.
* @private
*/
//@internal
_getConnectPoints() {
const map = this.getMap();
const containerPoint = this.getContainerPoint();
const dom = this.getDOM(),
width = parseInt(dom.clientWidth + ""),
height = parseInt(dom.clientHeight + "");
const anchors = [
//top center
map.containerPointToCoordinate(containerPoint.add(width / 2, 0)),
//middle right
map.containerPointToCoordinate(
containerPoint.add(width, height / 2)
),
//bottom center
map.containerPointToCoordinate(
containerPoint.add(width / 2, height)
),
//middle left
map.containerPointToCoordinate(containerPoint.add(0, height / 2)),
];
return anchors;
}
}
Panel.mergeOptions(options);
export default Panel;
export type PanelOptionsTypeSpec = {
draggable?: boolean;
custom?: boolean;
content?: string | HTMLElement;
closeButton?: boolean;
};
export type PanelOptionsType = ControlOptionsType & PanelOptionsTypeSpec;