{"id":23158460,"url":"https://github.com/jonataswalker/ol-contextmenu","last_synced_at":"2025-10-05T22:58:16.892Z","repository":{"id":3228385,"uuid":"41478177","full_name":"jonataswalker/ol-contextmenu","owner":"jonataswalker","description":"Custom Context Menu for OpenLayers","archived":false,"fork":false,"pushed_at":"2024-10-14T18:10:23.000Z","size":6904,"stargazers_count":229,"open_issues_count":7,"forks_count":87,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-05-03T18:03:19.302Z","etag":null,"topics":["contextmenu","openlayers"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonataswalker.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"jonataswalker","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2015-08-27T09:35:21.000Z","updated_at":"2025-04-12T04:48:09.000Z","dependencies_parsed_at":"2024-01-16T15:59:09.060Z","dependency_job_id":"45a8b005-f334-481f-8788-b82940900777","html_url":"https://github.com/jonataswalker/ol-contextmenu","commit_stats":{"total_commits":197,"total_committers":18,"mean_commits":"10.944444444444445","dds":"0.29949238578680204","last_synced_commit":"e5037a46a3811fb11f5e590b2ee385e796afb279"},"previous_names":["jonataswalker/ol3-contextmenu"],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonataswalker%2Fol-contextmenu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonataswalker%2Fol-contextmenu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonataswalker%2Fol-contextmenu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonataswalker%2Fol-contextmenu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonataswalker","download_url":"https://codeload.github.com/jonataswalker/ol-contextmenu/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254179900,"owners_count":22027884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["contextmenu","openlayers"],"created_at":"2024-12-17T22:19:43.883Z","updated_at":"2025-10-05T22:58:11.871Z","avatar_url":"https://github.com/jonataswalker.png","language":"TypeScript","funding_links":["https://github.com/sponsors/jonataswalker"],"categories":[],"sub_categories":[],"readme":"# OpenLayers Custom Context Menu\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/jonataswalker/ol-contextmenu/actions/workflows/test.yml\"\u003e\n        \u003cimg src=\"https://github.com/jonataswalker/ol-contextmenu/actions/workflows/test.yml/badge.svg?branch=master\" alt=\"Build Status\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/package/ol-contextmenu\"\u003e\n        \u003cimg src=\"https://img.shields.io/npm/v/ol-contextmenu.svg\" alt=\"npm version\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://img.shields.io/npm/dm/ol-contextmenu\"\u003e\n        \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/dm/ol-contextmenu\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/jonataswalker/ol-contextmenu/blob/master/LICENSE\"\u003e\n        \u003cimg src=\"https://img.shields.io/npm/l/ol-contextmenu.svg\" alt=\"license\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nA `contextmenu` extension for [OpenLayers](http://openlayers.org/). **Requires** OpenLayers **v7.0.0** or higher.\n\n![contextmenu anim](https://raw.githubusercontent.com/jonataswalker/ol-contextmenu/screenshot/images/anim.gif)\n\n## Demo\n\n[JSFiddle](https://jsfiddle.net/jonataswalker/ooxs1w5d/)\n[CodeSandbox](https://codesandbox.io/s/openlayers-custom-context-menu-5s99kb?file=/src/index.js)\n\n## How to use it?\n\n##### NPM\n\n`npm install ol-contextmenu`\n\n##### CDN Hosted - [jsDelivr](https://www.jsdelivr.com/package/npm/ol-contextmenu)\n\nLoad CSS and Javascript:\n\n```HTML\n\u003clink href=\"https://cdn.jsdelivr.net/npm/ol-contextmenu@latest/dist/ol-contextmenu.css\" rel=\"stylesheet\"\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/ol-contextmenu\"\u003e\u003c/script\u003e\n```\n\n##### CDN Hosted - UNPKG\n\nLoad CSS and Javascript:\n\n```HTML\n\u003clink href=\"https://unpkg.com/ol-contextmenu/dist/ol-contextmenu.css\" rel=\"stylesheet\"\u003e\n\u003cscript src=\"https://unpkg.com/ol-contextmenu\"\u003e\u003c/script\u003e\n```\n\n##### Self hosted\n\nDownload [latest release](https://github.com/jonataswalker/ol-contextmenu/releases/latest) and (obviously) load CSS and Javascript.\n\n##### Instantiate with some options and add the Control\n\n```javascript\nconst contextmenu = new ContextMenu({\n    width: 170,\n    defaultItems: true, // defaultItems are (for now) Zoom In/Zoom Out\n    items: [\n        {\n            text: 'Center map here',\n            classname: 'some-style-class', // add some CSS rules\n            callback: center, // `center` is your callback function\n        },\n        {\n            text: 'Add a Marker',\n            classname: 'some-style-class', // you can add this icon with a CSS class\n            // instead of `icon` property (see next line)\n            icon: 'img/marker.png', // this can be relative or absolute\n            callback: marker,\n        },\n        '-', // this is a separator\n    ],\n});\nmap.addControl(contextmenu);\n```\n\n##### You can add a (nested) submenu like this:\n\nIf you provide `items {Array}` a submenu will be created as a child of the current item.\n\n```javascript\nconst all_items = [\n    {\n        text: 'Some Actions',\n        items: [\n            // \u003c== this is a submenu\n            {\n                text: 'Action 1',\n                callback: action,\n            },\n            {\n                text: 'Other action',\n                callback: action2,\n            },\n        ],\n    },\n    {\n        text: 'Add a Marker',\n        icon: 'img/marker.png',\n        callback: marker,\n    },\n    '-', // this is a separator\n];\n```\n\n##### Would you like to propagate custom data to the callback handler?\n\n```javascript\nconst removeMarker = function (obj) {\n    vectorLayer.getSource().removeFeature(obj.data.marker);\n};\nconst removeMarkerItem = {\n    text: 'Remove this Marker',\n    icon: 'img/marker.png',\n    callback: removeMarker,\n};\n\nlet restore = false;\ncontextmenu.on('open', function (evt) {\n    const feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {\n        return ft;\n    });\n    if (feature) {\n        contextmenu.clear();\n        removeMarkerItem.data = { marker: feature };\n        contextmenu.push(removeMarkerItem);\n        restore = true;\n    } else if (restore) {\n        contextmenu.clear();\n        contextmenu.extend(contextmenu_items);\n        contextmenu.extend(contextmenu.getDefaultItems());\n        restore = false;\n    }\n});\n```\n\n# API\n\n## Constructor\n\n#### `new ContextMenu(options)`\n\n###### `options` is an object with the following possible properties:\n\n-   `eventType`: `contextmenu`; The listening event type (You could use `'click'`, `'dblclick'`)\n-   `defaultItems`: `true`; Whether the default items (which are: Zoom In/Out) are enabled\n-   `width`: `150`; The menu's width\n-   `items`: `[]`; An array of object|string\n\n## Methods\n\n#### contextmenu.clear()\n\nRemove all elements from the menu.\n\n#### contextmenu.closeMenu()\n\nClose the menu programmatically.\n\n#### contextmenu.extend(arr)\n\n`@param {Array} arr`\n\nAdd items to the menu. This pushes each item in the provided array to the end of the menu.\n\nExample:\n\n```js\nconst contextmenu = new ContextMenu();\nmap.addControl(contextmenu);\n\nconst add_later = [\n    '-', // this is a separator\n    {\n        text: 'Add a Marker',\n        icon: 'img/marker.png',\n        callback: marker,\n    },\n];\ncontextmenu.extend(add_later);\n```\n\n#### contextmenu.push(item)\n\n`@param {Object|String} item`\n\nInsert the provided item at the end of the menu.\n\n#### contextmenu.shift()\n\nRemove the first item of the menu.\n\n#### contextmenu.pop()\n\nRemove the last item of the menu.\n\n#### contextmenu.getDefaultItems()\n\nGet an array of default items.\n\n#### contextmenu.isOpen()\n\nWhether the menu is open.\n\n#### contextmenu.updatePosition(pixel)\n\n`@param {Array} pixel`\n\nUpdate menu's position.\n\n## Events\n\n#### If you want to disable this plugin under certain circumstances, listen to `beforeopen`\n\n```javascript\ncontextmenu.on('beforeopen', function (evt) {\n    const feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {\n        return ft;\n    });\n\n    if (feature) {\n        // open only on features\n        contextmenu.enable();\n    } else {\n        contextmenu.disable();\n    }\n});\n```\n\n#### Listen and make some changes when context menu opens\n\n```javascript\ncontextmenu.on('open', function (evt) {\n    const feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {\n        return ft;\n    });\n\n    if (feature) {\n        // add some other items to the menu\n    }\n});\n```\n\n#### Any action when context menu gets closed?\n\n```javascript\ncontextmenu.on('close', function (evt) {\n    // it's upon you\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonataswalker%2Fol-contextmenu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonataswalker%2Fol-contextmenu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonataswalker%2Fol-contextmenu/lists"}