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;
options: PanelOptionsType;
//@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 PanelOptionsType = {
draggable?: boolean;
custom?: boolean;
content?: string | HTMLElement;
closeButton?: boolean;
} & ControlOptionsType;