ol-extent
Version:
a JavaScript library for openlayers extent
419 lines (390 loc) • 10.9 kB
JavaScript
/**
* Created by FDD on 2016/11/7.
* @desc 右键功能
*/
import '../assets/scss/contextMenu.scss'
import ol from 'openlayers'
import {BASE_CLASS_NAME} from '../constants'
import { cloneDeep, getElement, create, setStyle, stopPropagation, preventDefault, addClass, on } from '../utils';
class ContextMenu extends ol.control.Control {
constructor (options = {}) {
/**
* className
* @type {string}
*/
const className_ = (options.className !== undefined ? options.className : 'ole-context-menu-content');
/**
* @private
* @type {Element}
*/
const element_ = create('div', (className_ + ' ' + BASE_CLASS_NAME.CLASS_UNSELECTABLE));
setStyle(element_, 'display', 'none');
super({
element: element_,
target: options['target']
});
this.options = options;
/**
* className
* @type {string}
* @private
*/
this.className_ = className_;
/**
* 地图容器
* @type {null}
*/
this.mapContent = null;
/**
* 鼠标右键的位置
* @type {Array}
*/
this.pixel = [];
/**
* width
* @type {number}
*/
this.itemWidth = (typeof this.options['itemWidth'] === 'number' ? this.options['itemWidth'] : 160);
/**
* height
* @type {number}
*/
this.itemHeight = (typeof this.options['itemHeight'] === 'number' ? this.options['itemHeight'] : 30);
}
/**
* 初始化dom
* @param items
*/
initDomInternal (items) {
this.htmlUtils(items, '', this.element);
if (this.getMap()) {
this.mapContent = this.getMap().getViewport();
on(this.mapContent, 'contextmenu', this.mouseDownHandle_, this);
}
}
/**
* 初始化事件
* @param event
* @private
*/
mouseDownHandle_ (event) {
let that = this;
stopPropagation(event);
preventDefault(event);
if (event.button === 2) {
that.pixel = this.getMap().getEventPixel(event);
that.dispatchEvent({
type: 'before-show',
target: this,
event: event
});
window.setTimeout(() => {
that.show(that.pixel);
that.dispatchEvent({
type: 'show',
target: this,
event: event
});
}, 50)
}
on(event.target, 'mousedown', function () {
that.hide();
that.dispatchEvent({
type: 'hide',
target: this,
event: event
});
}, this, true);
}
/**
* showMenu
* @param position
*/
show (position) {
setStyle(this.element, {
display: 'block',
top: position[1] + 'px',
left: position[0] + 'px'
});
let aDoc = this.getMap().getSize();
let maxWidth = aDoc[0] - this.element.offsetWidth;
let maxHeight = aDoc[1] - this.element.offsetHeight;
if (this.element.offsetTop > maxHeight) {
setStyle(this.element, {
top: maxHeight + 'px'
});
}
if (this.element.offsetLeft > maxWidth) {
setStyle(this.element, {
left: maxWidth + 'px'
});
}
}
/**
* hideMenu
*/
hide () {
this.element.style.display = 'none';
this.pixel = [];
}
/**
* html处理工具
* @param items
* @param index
* @param content
* @param isOffset
* @returns {*}
*/
htmlUtils (items, index, content, isOffset) {
let ulList = null;
if (items && Array.isArray(items) && items.length > 0) {
ulList = create('ul', this.className_ + '-ul' + index + '-inner', content, this.className_ + '-ul' + index + '-inner');
if (isOffset) {
setStyle(ulList, {
position: 'absolute',
top: '0px',
left: this.itemWidth + 20 + 'px'
});
}
items.forEach((item, index_) => {
if (item && item['name'] && item['alias']) {
let numList = index + '-' + index_;
let li_ = create('li', this.className_ + '-li-' + numList + '-inner', ulList, this.className_ + '-li-' + numList + '-inner');
setStyle(li_, {
width: this.itemWidth + 'px',
height: this.itemHeight + 'px',
lineHeight: this.itemHeight + 'px'
});
li_.setAttribute('data-name', item['alias']);
on(li_, 'click', this.handleItemClick_.bind(this, item), this);
if (item['icon']) {
let span_ = create('span', 'li-icon-content', li_);
if (item['iconType'] === 'iconfont') {
let fontName = item['fontName'] ? item['fontName'] : 'iconfont';
addClass(span_, fontName + ' ' + item['icon']);
if (item['iconColor']) {
span_.style.color = item['iconColor'];
}
} else {
span_.style.background = 'url(' + item['icon'] + ') 0px 0px no-repeat';
}
}
let name_ = create('span', 'li-name-content', li_);
name_.innerHTML = item['name'];
if (item['showLine']) {
li_.style.borderBottom = '1px solid #CCCCCC'
}
if (item['items']) {
this.htmlUtils(item['items'], numList, li_, true);
on(li_, 'mouseenter', this.handleItemMouseOver_, this);
on(li_, 'mouseleave', this.handleItemMouseOut_, this);
}
}
})
}
return ulList
}
/**
* 更新面板元素
* @param type
* @param item
* @param items
* @private
*/
updateElement_ (type, item, items) {
let child_ = getElement(this.className_ + '-ul' + '-inner');
let cloneItems = cloneDeep(this.options['items']);
let afterItems = null;
switch (type) {
case 'pop': // 移除最后一个
this.element.removeChild(child_);
afterItems = cloneItems.pop();
this.htmlUtils(cloneItems, '', this.element);
break;
case 'push': // 数组的末尾添加新的元素
this.element.removeChild(child_);
afterItems = cloneItems = cloneItems.push(item);
this.htmlUtils(cloneItems, '', this.element);
break;
case 'shift': // 删除数组的第一个元素
this.element.removeChild(child_);
afterItems = cloneItems.shift();
this.htmlUtils(cloneItems, '', this.element);
break;
case 'unshift': // 在数组的开头添加新元素
this.element.removeChild(child_);
afterItems = cloneItems = cloneItems.unshift(item);
this.htmlUtils(cloneItems, '', this.element);
break;
case 'reverse':
this.element.removeChild(child_);
afterItems = cloneItems.reverse();
this.htmlUtils(cloneItems, '', this.element);
break;
default:
this.element.removeChild(child_);
afterItems = items;
this.htmlUtils(items, '', this.element);
}
return afterItems;
}
/**
* 获取鼠标右键位置的像素坐标
* @returns {ol.Pixel|*|Array}
*/
getCurrentPixel () {
return this.pixel;
}
/**
* 获取鼠标点击位置的地图坐标
* @returns {ol.Coordinate}
*/
getCurrentCoordinates () {
return (this.getMap().getCoordinateFromPixel(this.getCurrentPixel()));
}
/**
* 处理列表点击事件
* @param item
* @param event
* @private
*/
handleItemClick_ (item, event) {
stopPropagation(event);
if (item && item['callback'] && typeof item['callback'] === 'function') {
item['callback']({
type: 'item-click',
target: this,
event: event,
source: item,
pixel: this.getCurrentPixel(),
coordinates: this.getCurrentCoordinates()
})
}
this.dispatchEvent({
type: 'item-click',
event: event,
source: item,
pixel: this.getCurrentPixel(),
coordinates: this.getCurrentCoordinates()
});
window.setTimeout(() => {
this.hide();
}, 50);
}
/**
* 处理鼠标移入事件
* @param event
* @private
*/
handleItemMouseOver_ (event) {
stopPropagation(event);
if (event.target && event.target.childNodes) {
let elements = Array.prototype.slice.call(event.target.childNodes, 0);
if (elements && elements.length > 0) {
elements.every(ele => {
if (ele && ele.nodeName.toLowerCase() === 'ul') {
ele.style.display = 'block';
return false
} else {
return true
}
})
}
}
}
/**
* 处理鼠标移出事件
* @param event
* @private
*/
handleItemMouseOut_ (event) {
stopPropagation(event);
if (event.target && event.target.childNodes) {
let elements = Array.prototype.slice.call(event.target.childNodes, 0);
if (elements && elements.length > 0) {
elements.every(ele => {
if (ele && ele.nodeName.toLowerCase() === 'ul') {
ele.style.display = 'none';
return false
} else {
return true
}
})
}
}
}
/**
* setMap
* @param map
*/
setMap (map) {
super.setMap.call(this, map);
if (map && map instanceof ol.Map) {
this.initDomInternal(this.options['items']);
}
}
/**
* 移除菜单最后一项
*/
pop () {
return this.updateElement_('pop');
}
/**
* 向菜单末尾添加一项
* @param item
*/
push (item) {
if (item && typeof item === 'object') {
return this.updateElement_('push', item);
} else {
throw new Error('传入的不是对象');
}
}
/**
* 移除菜单第一项
*/
shift () {
return this.updateElement_('shift');
}
/**
* 倒叙菜单
*/
reverse () {
return this.updateElement_('reverse');
}
/**
* 向菜单开头添加一项
* @param item
*/
unshift (item) {
if (item && typeof item === 'object') {
return this.updateElement_('unshift', item);
} else {
throw new Error('传入的不是对象');
}
}
/**
* 更新菜单
* @param items
*/
update (items) {
if (items && Array.isArray(items) && items.length > 0) {
this.updateElement_('', '', items);
} else {
throw new Error('传入的数组有误!');
}
}
/**
* 更新内置配置
* @param items
*/
updateOption (items) {
if (items && Array.isArray(items) && items.length > 0) {
this.options['items'] = items;
this.updateElement_('', '', items);
} else {
throw new Error('传入的数组有误!');
}
}
}
export default ContextMenu