右键菜单
ContextMenu 上下文菜单用于右键弹出菜单界面显示。
常用方法
| 方法 | 描述 |
|---|---|
| add | 增加菜单项 |
| show | 显示菜单 |
| hide | 隐藏菜单 |
| toggle | 切换菜单状态 |
菜单项类型
| 类型 | 描述 |
|---|---|
| seperator | 分隔线 |
| custom | 自定义菜单项 |
| multi | 多个按钮 |
| submenu | 子菜单项 |
| hovermenu | 悬浮菜单项 |
| normal | 缺省正常菜单项 |
示例
地图上下文菜单
// 选中的图标,也可以直接指定src路径
const checkIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAANpJREFUOE9jZKAQMFKon2FgDKjZHVHf4rqiEeR6kl1QuzOyn+E/4/lmj2WLSDagekdkASMjg1aL+/I0WNgR7YLaHRG2/xgZYlrdV6QjBzzRBtTsijzzl4nVvd1l0VucBtTsjlz5/z/jt1a3ZYnIimp2RZ7//+9fQ6vHyo3o0Q53Qc32CAcGpv88DIxMxQyMDB9aXJcHghTX7IxcyMjAeLTZfdksbGkGqxdqdkUuZ2BgkPjPyDCFgeG/W6srqr+JCoPqXZG9jAwM9iyszy0aHA/8wZViiQ7EYWwAAPShQBF/1IlVAAAAAElFTkSuQmCC";
map.setMenu(event => {
return new vjmap.ContextMenu({
event: event.originalEvent,
theme: "dark", //light
width: "250px",
items: [
{type: 'custom', markup: `<span style="color: #ffff00; padding-left: 30px">菜单右键功能演示</span>`},
{type: 'multi', items: [
{label: '全图', onClick: () => { map.fitMapBounds(); }},
{label: '不旋转', onClick: () => { map.setBearing(0); }},
{label: '不倾斜', onClick: () => { map.setPitch(0); }},
]},
{label: '获取此位置的坐标', onClick: () => {
let point = map.fromLngLat(event.lngLat);
map.logInfo(`当前坐标为 x: ${point.x}, y: ${point.y}`);
}},
{type: 'seperator'},
{type: 'submenu', label: '地图缩放', items: [
{label: '放大一级', onClick: () => { map.setZoom(map.getZoom() + 1)}},
{label: '缩小一级', onClick: () => { map.setZoom(map.getZoom() - 1)}, enabled: map.getZoom() - 1 > 0},
{label: '缩小至最小级', onClick: () => { map.setZoom(0)}},
{label: '飞行至此位置', onClick: () => {
map.flyTo({
center: event.lngLat,
pitch: 60,
zoom: 5
})
}}
]},
{type: 'hovermenu', label: '地图设置', items: [
{
label: '双击鼠标进行缩放',
icon: map.doubleClickZoom.isEnabled() ? checkIcon : "",
onClick: () => {
if (map.doubleClickZoom.isEnabled()) {
map.doubleClickZoom.disable()
} else {
map.doubleClickZoom.enable()
}
}
},
{
label: '允许地图旋转',
icon: map.dragRotate.isEnabled() ? checkIcon : "",
onClick: () => {
if (map.dragRotate.isEnabled()) {
map.dragRotate.disable();
} else {
map.dragRotate.enable();
}
}
},
{
label: '允许地图倾斜',
icon: map.getMaxPitch() != 0 ? checkIcon : "",
onClick: () => {
if (map.getMaxPitch() == 0) {
map.setMaxPitch(85)
} else {
map.setMaxPitch(0)
}
}
}
]}
]
});
})
在沙箱中运行,调用唯杰地图公共演示服务
// --地图上下文菜单--
// 地图服务对象
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// 打开地图
let res = await svc.openMap({
mapid: env.exampleMapId, // 地图ID
mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap.openMapDarkStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
// 如果打开出错
message.error(res.error)
}
// 根据地图范围建立几何投影坐标系
let prj = new vjmap.GeoProjection(res.bounds);
// 地图对象
let map = new vjmap.Map({
container: 'map', // DIV容器ID
style: svc.rasterStyle(), // 样式,这里是栅格样式
center: prj.toLngLat(prj.getMapExtent().center()), // 设置地图中心点
zoom: 2, // 设置地图缩放级别
renderWorldCopies: false
});
// 关联服务对象和投影对象
map.attach(svc, prj);
let mapBounds = map.getGeoBounds(); // 得到地图地理范围
// 选中的图标,也可以直接指定src路径
const checkIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAANpJREFUOE9jZKAQMFKon2FgDKjZHVHf4rqiEeR6kl1QuzOyn+E/4/lmj2WLSDagekdkASMjg1aL+/I0WNgR7YLaHRG2/xgZYlrdV6QjBzzRBtTsijzzl4nVvd1l0VucBtTsjlz5/z/jt1a3ZYnIimp2RZ7//+9fQ6vHyo3o0Q53Qc32CAcGpv88DIxMxQyMDB9aXJcHghTX7IxcyMjAeLTZfdksbGkGqxdqdkUuZ2BgkPjPyDCFgeG/W6srqr+JCoPqXZG9jAwM9iyszy0aHA/8wZViiQ7EYWwAAPShQBF/1IlVAAAAAElFTkSuQmCC";
map.setMenu(event => {
return new vjmap.ContextMenu({
event: event.originalEvent,
theme: "dark", //light
width: "250px",
items: [
{type: 'custom', markup: `<span style="color: #ffff00; padding-left: 30px">菜单右键功能演示</span>`},
{type: 'multi', items: [
{label: '全图', onClick: () => { map.fitMapBounds(); }},
{label: '不旋转', onClick: () => { map.setBearing(0); }},
{label: '不倾斜', onClick: () => { map.setPitch(0); }},
]},
{label: '获取此位置的坐标', onClick: () => {
let point = map.fromLngLat(event.lngLat);
map.logInfo(`当前坐标为 x: ${point.x}, y: ${point.y}`);
}},
{type: 'seperator'},
{type: 'submenu', label: '地图缩放', items: [
{label: '放大一级', onClick: () => { map.setZoom(map.getZoom() + 1)}},
{label: '缩小一级', onClick: () => { map.setZoom(map.getZoom() - 1)}, enabled: map.getZoom() - 1 > 0},
{label: '缩小至最小级', onClick: () => { map.setZoom(0)}},
{label: '飞行至此位置', onClick: () => {
map.flyTo({
center: event.lngLat,
pitch: 60,
zoom: 5
})
}}
]},
{type: 'hovermenu', label: '地图设置', items: [
{
label: '双击鼠标进行缩放',
icon: map.doubleClickZoom.isEnabled() ? checkIcon : "",
onClick: () => {
if (map.doubleClickZoom.isEnabled()) {
map.doubleClickZoom.disable()
} else {
map.doubleClickZoom.enable()
}
}
},
{
label: '允许地图旋转',
icon: map.dragRotate.isEnabled() ? checkIcon : "",
onClick: () => {
if (map.dragRotate.isEnabled()) {
map.dragRotate.disable();
} else {
map.dragRotate.enable();
}
}
},
{
label: '允许地图倾斜',
icon: map.getMaxPitch() != 0 ? checkIcon : "",
onClick: () => {
if (map.getMaxPitch() == 0) {
map.setMaxPitch(85)
} else {
map.setMaxPitch(0)
}
}
}
]}
]
});
})
map.logInfo('请点击右键弹出菜单');覆盖物图层右键菜单
// 设置点击一个覆盖物时弹出菜单,key值可以自定义设置。如果函数返回空时,将触发上面的地图右键菜单。如果函数不返回空,则会弹出此函数的菜单
map.setMenu(event => {
let features = map.queryRenderedFeatures(event.point, {
layers: [polygon.layerId]
});
if (features.length == 0) {
// 如果点击位置没有上面多边形图层的实体,则将回空,这样将会弹出上面的默认地图菜单
return null;
}
// 如果点击位置有上面多边形图层的实体,则弹出此图层的自定义右键菜单
return new vjmap.ContextMenu({
event: event.originalEvent,
theme: "dark", //light
width: "250px",
items: [
{type: 'custom', markup: `<span style="color: #ffff00; padding-left: 30px">我是多边形图层的右键菜单</span>`},
{
label: '查看选择的多边形信息',
onClick: () => {
map.logInfo(`当前多边形ID: ${features[0].properties.id}, 当前多边形颜色: ${features[0].properties.color}`);
}
},
{
label: '删除',
onClick: () => {
let data = polygon.getData();
data.features = data.features.filter(f => f.id != features[0].properties.id);
polygon.setData(data);
}
}
]
});
}, "overlay")
在沙箱中运行,调用唯杰地图公共演示服务
// --覆盖物图层右键菜单--
// 地图服务对象
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// 打开地图
let res = await svc.openMap({
mapid: env.exampleMapId, // 地图ID
mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap.openMapDarkStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
// 如果打开出错
message.error(res.error)
}
// 根据地图范围建立几何投影坐标系
let prj = new vjmap.GeoProjection(res.bounds);
// 地图对象
let map = new vjmap.Map({
container: 'map', // DIV容器ID
style: svc.rasterStyle(), // 样式,这里是栅格样式
center: prj.toLngLat(prj.getMapExtent().center()), // 设置地图中心点
zoom: 2, // 设置地图缩放级别
renderWorldCopies: false
});
// 关联服务对象和投影对象
map.attach(svc, prj);
await map.onLoad();
// 下面加很多多边形做测试,在多边形上右键时将弹出多边形的右键菜单,否则弹出地图的右键菜单
let mapBounds = map.getGeoBounds(0.6);
let len = mapBounds.width() / 50;
let polygons = []
for(let i = 0; i < 200; i++) {
const p1 = mapBounds.randomPoint();
const p2 = vjmap.geoPoint([p1.x, p1.y + len]);
const p3 = vjmap.geoPoint([p1.x + len, p1.y]);
polygons.push({
points: map.toLngLat([p1, p2, p3]),
properties: {
name: "polygon" + (i + 1),
color: vjmap.randomColor()
}
})
}
let polygon = new vjmap.Polygon({
data: polygons,
// 如果是hover状态时,用红色,非hover状态时,取属性中的'color'做为颜色值
fillColor: ['case', ['to-boolean', ['feature-state', 'hover']], 'red', ['get', 'color']],
fillOpacity: 0.8,
fillOutlineColor: "#f00",
isHoverPointer: true,
isHoverFeatureState: true
});
polygon.addTo(map);
polygon.clickLayer(e => map.logInfo(`您点击了第 ${e.features[0].id} 个,名称为 ${e.features[0].properties.name},颜色为 ${e.features[0].properties.color} 的多边形`))
// 默认情况下显示的是地图菜单,因为这里的key是空,如果多次设置setMenu时,根据key值排序倒序,空值会在最后面
map.setMenu(event => {
return new vjmap.ContextMenu({
event: event.originalEvent,
theme: "dark", //light
width: "250px",
items: [
{type: 'custom', markup: `<span style="color: #ffff00; padding-left: 30px">我是地图的右键菜单</span>`},
{
label: '全图范围显示',
onClick: () => {
map.setBearing(0);
map.setPitch(0);
map.fitMapBounds();
}
},
{
label: '获取此位置的坐标',
onClick: () => {
let point = map.fromLngLat(event.lngLat);
map.logInfo(`当前坐标为 x: ${point.x}, y: ${point.y}`);
}
}
]
});
})
// 设置点击一个覆盖物时弹出菜单,key值可以自定义设置。如果函数返回空时,将触发上面的地图右键菜单。如果函数不返回空,则会弹出此函数的菜单
map.setMenu(event => {
let features = map.queryRenderedFeatures(event.point, {
layers: [polygon.layerId]
});
if (features.length == 0) {
// 如果点击位置没有上面多边形图层的实体,则将回空,这样将会弹出上面的默认地图菜单
return null;
}
// 如果点击位置有上面多边形图层的实体,则弹出此图层的自定义右键菜单
return new vjmap.ContextMenu({
event: event.originalEvent,
theme: "dark", //light
width: "250px",
items: [
{type: 'custom', markup: `<span style="color: #ffff00; padding-left: 30px">我是多边形图层的右键菜单</span>`},
{
label: '查看选择的多边形信息',
onClick: () => {
map.logInfo(`当前多边形ID: ${features[0].properties.id}, 当前多边形颜色: ${features[0].properties.color}`);
}
},
{
label: '删除',
onClick: () => {
let data = polygon.getData();
data.features = data.features.filter(f => f.id != features[0].properties.id);
polygon.setData(data);
}
}
]
});
}, "overlay")
// 绘图控件右键菜单
const draw = new vjmap.Draw.Tool();
map.addControl(draw, 'top-right');
map.on("draw.simpleselect.contextmenu", function (e) {
// 如果不是此draw对象的事件,则不用管
if (e.styleId != draw.options.styleId) return;
let feature = e.event.featureTarget
if (!feature) return
//if (draw.getMode() != "simple_select") return
let selectFeatureId = feature.properties.id
// 需要选中的才能右键
let selectIds = draw.getSelectedIds() || []
if (selectIds.indexOf(selectFeatureId)== -1) return
let event = e.event.originalEvent
// 阻止地图默认右键菜单触发
event.preventDefault();
event.stopPropagation();
return new vjmap.ContextMenu({
event: event,
theme: "dark", //light
width: "250px",
items: [
{
label: "删除",
onClick: () => {
draw.delete(selectFeatureId)
}
}
]
});
});标记Marker右键菜单
// marker与多边形等覆盖物图层不同的时,marker是div,而覆盖物图层是canvas渲染与map属于同一个div
// 所以marker的右键,得由自己的div的上下文菜单来触发
marker.getElement().addEventListener("mousedown", event => {
if (event.button != 2) return;//不是右键
// 阻止地图默认右键菜单触发
event.preventDefault();
event.stopPropagation();
return new vjmap.ContextMenu({
event: event,
theme: "dark", //light
width: "250px",
items: [
{type: 'custom', markup: `<span style="color: #ffff00; padding-left: 30px">我是标注Marker的右键菜单</span>`},
{
label: '获取此Marker的信息',
onClick: () => {
map.logInfo(`当前MarkerId为 ${marker.id}`);
}
}
]
});
})
在沙箱中运行,调用唯杰地图公共演示服务
// --标记Marker右键菜单--
// 地图服务对象
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// 打开地图
let res = await svc.openMap({
mapid: env.exampleMapId, // 地图ID
mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap.openMapDarkStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
// 如果打开出错
message.error(res.error)
}
// 根据地图范围建立几何投影坐标系
let prj = new vjmap.GeoProjection(res.bounds);
// 地图对象
let map = new vjmap.Map({
container: 'map', // DIV容器ID
style: svc.rasterStyle(), // 样式,这里是栅格样式
center: prj.toLngLat(prj.getMapExtent().center()), // 设置地图中心点
zoom: 2, // 设置地图缩放级别
renderWorldCopies: false
});
// 关联服务对象和投影对象
map.attach(svc, prj);
await map.onLoad();
map.setMenu(event => {
return new vjmap.ContextMenu({
event: event.originalEvent,
theme: "dark", //light
width: "250px",
items: [
{type: 'custom', markup: `<span style="color: #ffff00; padding-left: 30px">我是地图的右键菜单</span>`},
{
label: '全图范围显示',
onClick: () => {
map.setBearing(0);
map.setPitch(0);
map.fitMapBounds();
}
},
{
label: '获取此位置的坐标',
onClick: () => {
let point = map.fromLngLat(event.lngLat);
app.logInfo(`当前坐标为 x: ${point.x}, y: ${point.y}`);
}
}
]
});
})
let mapBounds = map.getGeoBounds(); // 得到地图地理范围
for(let i = 0; i < 50; i++) {
let point = mapBounds.randomPoint(); // 在地理范围里随机生成一个点
// marker
let marker = new vjmap.Marker({
color: vjmap.randomColor()
});
marker.setLngLat(map.toLngLat(point))
marker.addTo(map);
marker.id = i + 1;
// marker与多边形等覆盖物图层不同的时,marker是div,而覆盖物图层是canvas渲染与map属于同一个div
// 所以marker的右键,得由自己的div的上下文菜单来触发
marker.getElement().addEventListener("mousedown", event => {
if (event.button != 2) return;//不是右键
// 阻止地图默认右键菜单触发
event.preventDefault();
event.stopPropagation();
return new vjmap.ContextMenu({
event: event,
theme: "dark", //light
width: "250px",
items: [
{type: 'custom', markup: `<span style="color: #ffff00; padding-left: 30px">我是标注Marker的右键菜单</span>`},
{
label: '获取此Marker的信息',
onClick: () => {
map.logInfo(`当前MarkerId为 ${marker.id}`);
}
}
]
});
})
}类型定义文件
/**
* 上下文菜单.
*
**/
export class ContextMenu {
private options;
private menuControl;
private position;
/**
* Creates a new ContextMenu menu
* @param {object} opts options which build the menu e.g. position and items
* @param {number} opts.width sets the width of the menu including children
* @param {object} opts.event 事件对象
* @param {theme} opts.theme 自定义的样式主题,支持dark和light,默认dark
* @param {boolean} opts.isSticky sets how the menu apears, follow the mouse or sticky
* @param {Array<ContextMenuItem>} opts.items sets the default items in the menu
*/
constructor(opts: ContextMenuOptions);
/**
* Adds item to this ContextMenu menu instance
* @param {ContextMenuItem} item item to add to the ContextMenu menu
*/
add(item: any): void;
/**
* Makes this ContextMenu menu visible
*/
show(): void;
/**
* Hides this ContextMenu menu
*/
hide(): void;
/**
* Toggle visibility of menu
*/
toggle(): void;
}
/**
* 上下文菜单选项.
*
**/
export interface ContextMenuOptions {
/** 事件对象. */
event: Event;
/** 菜单宽度(包括子菜单),像素,默认150px. */
width?: string;
/** 菜单主题色.(dark和light,默认dark)*/
theme?: string;
/** 菜单外面容器的内部宽,用于菜单超时范围时自动调位置,默认是window大小宽 可通过 map.getContainer().getBoundingClientRect().width来设置 */
innerWidth?: number;
/** 菜单外面容器的内部宽,用于菜单超时范围时自动调位置,默认是window大小高 可通过 map.getContainer().getBoundingClientRect().height来设置 */
innerHeight?: number;
/** 子项 */
items: ContextMenuSubItemOptions[];
}
/**
* 上下文菜单子项选项.
*
**/
export interface ContextMenuSubItemOptions {
/** 子菜单类型. */
type?: "custom" | "multi" | "Button" | "seperator" | "submenu" | "hovermenu" | "normal";
/** 类型为'custom'时的自定义html内容 */
markup?: string;
/** 类型为'multi'时子菜单项*/
items?: ContextMenuSubItemOptions[];
/** 点击事件*/
onClick?: Function;
/** 菜单名称*/
label?: string;
/** 快捷菜单*/
shortcut?: string;
/** 是否能用*/
enabled?: boolean;
/** css图标*/
cssIcon?: string;
/** 图标*/
icon?: string;
}
这篇文档有帮助吗?感谢反馈!