cytoscape-cxtmenu
Advanced tools
Comparing version 2.10.3 to 3.0.0
{ | ||
"name": "cytoscape-cxtmenu", | ||
"description": "A context menu for Cytoscape.js", | ||
"description": "A circular, swipeable context menu extension for Cytoscape.js", | ||
"main": "cytoscape-cxtmenu.js", | ||
"dependencies": { | ||
"cytoscape": "^3.2.0" | ||
}, | ||
"repository": { | ||
@@ -9,5 +12,2 @@ "type": "git", | ||
}, | ||
"dependencies": { | ||
"cytoscape": "^2.2.0 || ^3.0.0" | ||
}, | ||
"ignore": [ | ||
@@ -22,7 +22,5 @@ "**/.*", | ||
"cytoscape", | ||
"cytoscape.js", | ||
"cytoscapejs", | ||
"extension" | ||
"cytoscape-extension" | ||
], | ||
"license": "MIT" | ||
} |
@@ -1,661 +0,763 @@ | ||
/*! | ||
Copyright (c) The Cytoscape Consortium | ||
(function webpackUniversalModuleDefinition(root, factory) { | ||
if(typeof exports === 'object' && typeof module === 'object') | ||
module.exports = factory(); | ||
else if(typeof define === 'function' && define.amd) | ||
define([], factory); | ||
else if(typeof exports === 'object') | ||
exports["cytoscapeCxtmenu"] = factory(); | ||
else | ||
root["cytoscapeCxtmenu"] = factory(); | ||
})(this, function() { | ||
return /******/ (function(modules) { // webpackBootstrap | ||
/******/ // The module cache | ||
/******/ var installedModules = {}; | ||
/******/ | ||
/******/ // The require function | ||
/******/ function __webpack_require__(moduleId) { | ||
/******/ | ||
/******/ // Check if module is in cache | ||
/******/ if(installedModules[moduleId]) { | ||
/******/ return installedModules[moduleId].exports; | ||
/******/ } | ||
/******/ // Create a new module (and put it into the cache) | ||
/******/ var module = installedModules[moduleId] = { | ||
/******/ i: moduleId, | ||
/******/ l: false, | ||
/******/ exports: {} | ||
/******/ }; | ||
/******/ | ||
/******/ // Execute the module function | ||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | ||
/******/ | ||
/******/ // Flag the module as loaded | ||
/******/ module.l = true; | ||
/******/ | ||
/******/ // Return the exports of the module | ||
/******/ return module.exports; | ||
/******/ } | ||
/******/ | ||
/******/ | ||
/******/ // expose the modules object (__webpack_modules__) | ||
/******/ __webpack_require__.m = modules; | ||
/******/ | ||
/******/ // expose the module cache | ||
/******/ __webpack_require__.c = installedModules; | ||
/******/ | ||
/******/ // identity function for calling harmony imports with the correct context | ||
/******/ __webpack_require__.i = function(value) { return value; }; | ||
/******/ | ||
/******/ // define getter function for harmony exports | ||
/******/ __webpack_require__.d = function(exports, name, getter) { | ||
/******/ if(!__webpack_require__.o(exports, name)) { | ||
/******/ Object.defineProperty(exports, name, { | ||
/******/ configurable: false, | ||
/******/ enumerable: true, | ||
/******/ get: getter | ||
/******/ }); | ||
/******/ } | ||
/******/ }; | ||
/******/ | ||
/******/ // getDefaultExport function for compatibility with non-harmony modules | ||
/******/ __webpack_require__.n = function(module) { | ||
/******/ var getter = module && module.__esModule ? | ||
/******/ function getDefault() { return module['default']; } : | ||
/******/ function getModuleExports() { return module; }; | ||
/******/ __webpack_require__.d(getter, 'a', getter); | ||
/******/ return getter; | ||
/******/ }; | ||
/******/ | ||
/******/ // Object.prototype.hasOwnProperty.call | ||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; | ||
/******/ | ||
/******/ // __webpack_public_path__ | ||
/******/ __webpack_require__.p = ""; | ||
/******/ | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(__webpack_require__.s = 4); | ||
/******/ }) | ||
/************************************************************************/ | ||
/******/ ([ | ||
/* 0 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
this software and associated documentation files (the “Software”), to deal in | ||
the Software without restriction, including without limitation the rights to | ||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
of the Software, and to permit persons to whom the Software is furnished to do | ||
so, subject to the following conditions: | ||
"use strict"; | ||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
*/ | ||
var defaults = __webpack_require__(2); | ||
var assign = __webpack_require__(1); | ||
;(function(){ 'use strict'; | ||
var _require = __webpack_require__(3), | ||
removeEles = _require.removeEles, | ||
setStyles = _require.setStyles, | ||
createElement = _require.createElement, | ||
getPixelRatio = _require.getPixelRatio, | ||
getOffset = _require.getOffset; | ||
var defaults = { | ||
menuRadius: 100, // the radius of the circular menu in pixels | ||
selector: 'node', // elements matching this Cytoscape.js selector will trigger cxtmenus | ||
commands: [ // an array of commands to list in the menu or a function that returns the array | ||
/* | ||
{ // example command | ||
fillColor: 'rgba(200, 200, 200, 0.75)', // optional: custom background color for item | ||
content: 'a command name' // html/text content to be displayed in the menu | ||
select: function(ele){ // a function to execute when the command is selected | ||
console.log( ele.id() ) // `ele` holds the reference to the active element | ||
}, | ||
enabled: true // whether the command is selectable | ||
} | ||
*/ | ||
], // function( ele ){ return [ /*...*/ ] }, // example function for commands | ||
fillColor: 'rgba(0, 0, 0, 0.75)', // the background colour of the menu | ||
activeFillColor: 'rgba(1, 105, 217, 0.75)', // the colour used to indicate the selected command | ||
activePadding: 20, // additional size in pixels for the active command | ||
indicatorSize: 24, // the size in pixels of the pointer to the active command | ||
separatorWidth: 3, // the empty spacing in pixels between successive commands | ||
spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight | ||
minSpotlightRadius: 24, // the minimum radius in pixels of the spotlight | ||
maxSpotlightRadius: 38, // the maximum radius in pixels of the spotlight | ||
openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here | ||
itemColor: 'white', // the colour of text in the command's content | ||
itemTextShadowColor: 'transparent', // the text shadow colour of the command's content | ||
zIndex: 9999, // the z-index of the ui div | ||
atMouse: false // draw menu at mouse position | ||
var cxtmenu = function cxtmenu(params) { | ||
var options = assign({}, defaults, params); | ||
var cy = this; | ||
var container = cy.container(); | ||
var target = void 0; | ||
var data = { | ||
options: options, | ||
handlers: [], | ||
container: createElement({ class: 'cxtmenu' }) | ||
}; | ||
// Object.assign Polyfill for IE | ||
if (typeof Object.assign != 'function') { | ||
(function () { | ||
Object.assign = function (target) { | ||
// We must check against these specific cases. | ||
if (target === undefined || target === null) { | ||
throw new TypeError('Cannot convert undefined or null to object'); | ||
} | ||
var wrapper = data.container; | ||
var parent = createElement(); | ||
var canvas = createElement({ tag: 'canvas' }); | ||
var commands = []; | ||
var c2d = canvas.getContext('2d'); | ||
var r = options.menuRadius; | ||
var containerSize = (r + options.activePadding) * 2; | ||
var activeCommandI = void 0; | ||
var offset = void 0; | ||
var output = Object(target); | ||
for (var index = 1; index < arguments.length; index++) { | ||
var source = arguments[index]; | ||
if (source !== undefined && source !== null) { | ||
for (var nextKey in source) { | ||
if (source.hasOwnProperty(nextKey)) { | ||
output[nextKey] = source[nextKey]; | ||
} | ||
} | ||
} | ||
} | ||
return output; | ||
}; | ||
})(); | ||
} | ||
container.insertBefore(wrapper, container.firstChild); | ||
wrapper.appendChild(parent); | ||
parent.appendChild(canvas); | ||
var removeEles = function(query, ancestor) { | ||
var els = [].slice.call(ancestor.querySelectorAll(query)); | ||
setStyles(wrapper, { | ||
position: 'absolute', | ||
zIndex: options.zIndex, | ||
userSelect: 'none' | ||
}); | ||
ancestor = ancestor || document; | ||
setStyles(parent, { | ||
display: 'none', | ||
width: containerSize + 'px', | ||
height: containerSize + 'px', | ||
position: 'absolute', | ||
zIndex: 1, | ||
marginLeft: -options.activePadding + 'px', | ||
marginTop: -options.activePadding + 'px', | ||
userSelect: 'none' | ||
}); | ||
for (var i = 0, l = els.length; i < l; i++) { | ||
els[i].remove(); | ||
} | ||
}; | ||
canvas.width = containerSize; | ||
canvas.height = containerSize; | ||
var setStyles = function(el, style) { | ||
var props = Object.keys(style); | ||
function createMenuItems() { | ||
removeEles('.cxtmenu-item', parent); | ||
var dtheta = 2 * Math.PI / commands.length; | ||
var theta1 = Math.PI / 2; | ||
var theta2 = theta1 + dtheta; | ||
for (var i = 0, l = props.length; i < l; i++) { | ||
el.style[props[i]] = style[props[i]]; | ||
} | ||
}; | ||
for (var i = 0; i < commands.length; i++) { | ||
var command = commands[i]; | ||
var createElement = function(options){ | ||
options = options || {}; | ||
var midtheta = (theta1 + theta2) / 2; | ||
var rx1 = 0.66 * r * Math.cos(midtheta); | ||
var ry1 = 0.66 * r * Math.sin(midtheta); | ||
var el = document.createElement(options.tag || 'div'); | ||
var item = createElement({ class: 'cxtmenu-item' }); | ||
setStyles(item, { | ||
color: options.itemColor, | ||
cursor: 'default', | ||
display: 'table', | ||
'text-align': 'center', | ||
//background: 'red', | ||
position: 'absolute', | ||
'text-shadow': '-1px -1px 2px ' + options.itemTextShadowColor + ', 1px -1px 2px ' + options.itemTextShadowColor + ', -1px 1px 2px ' + options.itemTextShadowColor + ', 1px 1px 1px ' + options.itemTextShadowColor, | ||
left: '50%', | ||
top: '50%', | ||
'min-height': r * 0.66 + 'px', | ||
width: r * 0.66 + 'px', | ||
height: r * 0.66 + 'px', | ||
marginLeft: rx1 - r * 0.33 + 'px', | ||
marginTop: -ry1 - r * 0.33 + 'px' | ||
}); | ||
el.className = options.class || ''; | ||
var content = createElement({ class: 'cxtmenu-content' }); | ||
if (options.style) { | ||
setStyles(el, options.style); | ||
if (command.content instanceof HTMLElement) { | ||
content.appendChild(command.content); | ||
} else { | ||
content.innerHTML = command.content; | ||
} | ||
setStyles(content, { | ||
'width': r * 0.66 + 'px', | ||
'height': r * 0.66 + 'px', | ||
'vertical-align': 'middle', | ||
'display': 'table-cell' | ||
}); | ||
setStyles(content, command.contentStyle || {}); | ||
if (command.disabled === true || command.enabled === false) { | ||
content.classList.add('cxtmenu-disabled'); | ||
} | ||
parent.appendChild(item); | ||
item.appendChild(content); | ||
theta1 += dtheta; | ||
theta2 += dtheta; | ||
} | ||
} | ||
return el; | ||
}; | ||
function queueDrawBg(rspotlight) { | ||
redrawQueue.drawBg = [rspotlight]; | ||
} | ||
var getPixelRatio = function(){ | ||
return window.devicePixelRatio || 1; | ||
}; | ||
function drawBg(rspotlight) { | ||
rspotlight = rspotlight !== undefined ? rspotlight : rs; | ||
// registers the extension on a cytoscape lib ref | ||
var register = function(cytoscape){ | ||
if( !cytoscape ){ return; } // can't register if cytoscape unspecified | ||
c2d.globalCompositeOperation = 'source-over'; | ||
cytoscape('core', 'cxtmenu', function(params){ | ||
var options = Object.assign({}, defaults, params); | ||
var cy = this; | ||
var container = cy.container(); | ||
var target; | ||
c2d.clearRect(0, 0, containerSize, containerSize); | ||
function getOffset( el ){ | ||
var offset = el.getBoundingClientRect(); | ||
// draw background items | ||
c2d.fillStyle = options.fillColor; | ||
var dtheta = 2 * Math.PI / commands.length; | ||
var theta1 = Math.PI / 2; | ||
var theta2 = theta1 + dtheta; | ||
return { | ||
left: offset.left + document.body.scrollLeft + | ||
parseFloat(getComputedStyle(document.body)['padding-left']) + | ||
parseFloat(getComputedStyle(document.body)['border-left-width']), | ||
top: offset.top + document.body.scrollTop + | ||
parseFloat(getComputedStyle(document.body)['padding-top']) + | ||
parseFloat(getComputedStyle(document.body)['border-top-width']) | ||
}; | ||
for (var index = 0; index < commands.length; index++) { | ||
var command = commands[index]; | ||
if (command.fillColor) { | ||
c2d.fillStyle = command.fillColor; | ||
} | ||
c2d.beginPath(); | ||
c2d.moveTo(r + options.activePadding, r + options.activePadding); | ||
c2d.arc(r + options.activePadding, r + options.activePadding, r, 2 * Math.PI - theta1, 2 * Math.PI - theta2, true); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
var data = { | ||
options: options, | ||
handlers: [] | ||
}; | ||
var wrapper = createElement({class: 'cxtmenu'}); | ||
data.container = wrapper; | ||
var parent = createElement(); | ||
var canvas = createElement({tag: 'canvas'}); | ||
var commands = []; | ||
var c2d = canvas.getContext('2d'); | ||
var r = options.menuRadius; | ||
var containerSize = (r + options.activePadding)*2; | ||
var activeCommandI; | ||
var offset; | ||
theta1 += dtheta; | ||
theta2 += dtheta; | ||
container.insertBefore(wrapper, container.firstChild); | ||
wrapper.appendChild(parent); | ||
parent.appendChild(canvas); | ||
c2d.fillStyle = options.fillColor; | ||
} | ||
setStyles(wrapper, { | ||
position: 'absolute', | ||
zIndex: options.zIndex | ||
}); | ||
// draw separators between items | ||
c2d.globalCompositeOperation = 'destination-out'; | ||
c2d.strokeStyle = 'white'; | ||
c2d.lineWidth = options.separatorWidth; | ||
theta1 = Math.PI / 2; | ||
theta2 = theta1 + dtheta; | ||
setStyles(parent, { | ||
display: 'none', | ||
width: containerSize + 'px', | ||
height: containerSize + 'px', | ||
position: 'absolute', | ||
zIndex: 1, | ||
marginLeft: - options.activePadding + 'px', | ||
marginTop: - options.activePadding + 'px' | ||
}); | ||
for (var i = 0; i < commands.length; i++) { | ||
var rx1 = r * Math.cos(theta1); | ||
var ry1 = r * Math.sin(theta1); | ||
c2d.beginPath(); | ||
c2d.moveTo(r + options.activePadding, r + options.activePadding); | ||
c2d.lineTo(r + options.activePadding + rx1, r + options.activePadding - ry1); | ||
c2d.closePath(); | ||
c2d.stroke(); | ||
canvas.width = containerSize; | ||
canvas.height = containerSize; | ||
theta1 += dtheta; | ||
theta2 += dtheta; | ||
} | ||
function createMenuItems() { | ||
removeEles('.cxtmenu-item', parent); | ||
var dtheta = 2 * Math.PI / (commands.length); | ||
var theta1 = Math.PI / 2; | ||
var theta2 = theta1 + dtheta; | ||
c2d.fillStyle = 'white'; | ||
c2d.globalCompositeOperation = 'destination-out'; | ||
c2d.beginPath(); | ||
c2d.arc(r + options.activePadding, r + options.activePadding, rspotlight + options.spotlightPadding, 0, Math.PI * 2, true); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
for (var i = 0; i < commands.length; i++) { | ||
var command = commands[i]; | ||
c2d.globalCompositeOperation = 'source-over'; | ||
} | ||
var midtheta = (theta1 + theta2) / 2; | ||
var rx1 = 0.66 * r * Math.cos(midtheta); | ||
var ry1 = 0.66 * r * Math.sin(midtheta); | ||
function queueDrawCommands(rx, ry, theta) { | ||
redrawQueue.drawCommands = [rx, ry, theta]; | ||
} | ||
var item = createElement({class: 'cxtmenu-item'}); | ||
setStyles(item, { | ||
color: options.itemColor, | ||
cursor: 'default', | ||
display: 'table', | ||
'text-align': 'center', | ||
//background: 'red', | ||
position: 'absolute', | ||
'text-shadow': '-1px -1px 2px ' + options.itemTextShadowColor + ', 1px -1px 2px ' + options.itemTextShadowColor + ', -1px 1px 2px ' + options.itemTextShadowColor + ', 1px 1px 1px ' + options.itemTextShadowColor, | ||
left: '50%', | ||
top: '50%', | ||
'min-height': (r * 0.66) + 'px', | ||
width: (r * 0.66) + 'px', | ||
height: (r * 0.66) + 'px', | ||
marginLeft: (rx1 - r * 0.33) + 'px', | ||
marginTop: (-ry1 - r * 0.33) + 'px' | ||
}); | ||
function drawCommands(rx, ry, theta) { | ||
var dtheta = 2 * Math.PI / commands.length; | ||
var theta1 = Math.PI / 2; | ||
var theta2 = theta1 + dtheta; | ||
var content = createElement({class: 'cxtmenu-content'}); | ||
content.innerHTML = command.content; | ||
setStyles(content, { | ||
'width': (r * 0.66) + 'px', | ||
'height': (r * 0.66) + 'px', | ||
'vertical-align': 'middle', | ||
'display': 'table-cell' | ||
}); | ||
theta1 += dtheta * activeCommandI; | ||
theta2 += dtheta * activeCommandI; | ||
if (command.disabled === true || command.enabled === false) { | ||
content.classList.add('cxtmenu-disabled'); | ||
} | ||
c2d.fillStyle = options.activeFillColor; | ||
c2d.strokeStyle = 'black'; | ||
c2d.lineWidth = 1; | ||
c2d.beginPath(); | ||
c2d.moveTo(r + options.activePadding, r + options.activePadding); | ||
c2d.arc(r + options.activePadding, r + options.activePadding, r + options.activePadding, 2 * Math.PI - theta1, 2 * Math.PI - theta2, true); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
parent.appendChild(item); | ||
item.appendChild(content); | ||
c2d.fillStyle = 'white'; | ||
c2d.globalCompositeOperation = 'destination-out'; | ||
theta1 += dtheta; | ||
theta2 += dtheta; | ||
} | ||
} | ||
var tx = r + options.activePadding + rx / r * (rs + options.spotlightPadding - options.indicatorSize / 4); | ||
var ty = r + options.activePadding + ry / r * (rs + options.spotlightPadding - options.indicatorSize / 4); | ||
var rot = Math.PI / 4 - theta; | ||
function queueDrawBg( rspotlight ){ | ||
redrawQueue.drawBg = [ rspotlight ]; | ||
} | ||
c2d.translate(tx, ty); | ||
c2d.rotate(rot); | ||
function drawBg( rspotlight ){ | ||
rspotlight = rspotlight !== undefined ? rspotlight : rs; | ||
// clear the indicator | ||
c2d.beginPath(); | ||
c2d.fillRect(-options.indicatorSize / 2, -options.indicatorSize / 2, options.indicatorSize, options.indicatorSize); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
c2d.globalCompositeOperation = 'source-over'; | ||
c2d.rotate(-rot); | ||
c2d.translate(-tx, -ty); | ||
c2d.clearRect(0, 0, containerSize, containerSize); | ||
// c2d.setTransform( 1, 0, 0, 1, 0, 0 ); | ||
// draw background items | ||
c2d.fillStyle = options.fillColor; | ||
var dtheta = 2*Math.PI/(commands.length); | ||
var theta1 = Math.PI/2; | ||
var theta2 = theta1 + dtheta; | ||
// clear the spotlight | ||
c2d.beginPath(); | ||
c2d.arc(r + options.activePadding, r + options.activePadding, rs + options.spotlightPadding, 0, Math.PI * 2, true); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
for( var index = 0; index < commands.length; index++ ){ | ||
var command = commands[index]; | ||
c2d.globalCompositeOperation = 'source-over'; | ||
} | ||
if( command.fillColor ){ | ||
c2d.fillStyle = command.fillColor; | ||
} | ||
c2d.beginPath(); | ||
c2d.moveTo(r + options.activePadding, r + options.activePadding); | ||
c2d.arc(r + options.activePadding, r + options.activePadding, r, 2*Math.PI - theta1, 2*Math.PI - theta2, true); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
function updatePixelRatio() { | ||
var pxr = getPixelRatio(); | ||
var w = container.clientWidth; | ||
var h = container.clientHeight; | ||
theta1 += dtheta; | ||
theta2 += dtheta; | ||
canvas.width = w * pxr; | ||
canvas.height = h * pxr; | ||
c2d.fillStyle = options.fillColor; | ||
} | ||
canvas.style.width = w + 'px'; | ||
canvas.style.height = h + 'px'; | ||
// draw separators between items | ||
c2d.globalCompositeOperation = 'destination-out'; | ||
c2d.strokeStyle = 'white'; | ||
c2d.lineWidth = options.separatorWidth; | ||
theta1 = Math.PI/2; | ||
theta2 = theta1 + dtheta; | ||
c2d.setTransform(1, 0, 0, 1, 0, 0); | ||
c2d.scale(pxr, pxr); | ||
} | ||
for( var i = 0; i < commands.length; i++ ){ | ||
var rx1 = r * Math.cos(theta1); | ||
var ry1 = r * Math.sin(theta1); | ||
c2d.beginPath(); | ||
c2d.moveTo(r + options.activePadding, r + options.activePadding); | ||
c2d.lineTo(r + options.activePadding + rx1, r + options.activePadding - ry1); | ||
c2d.closePath(); | ||
c2d.stroke(); | ||
var redrawing = true; | ||
var redrawQueue = {}; | ||
var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; | ||
var redraw = function redraw() { | ||
if (redrawQueue.drawBg) { | ||
drawBg.apply(null, redrawQueue.drawBg); | ||
} | ||
theta1 += dtheta; | ||
theta2 += dtheta; | ||
} | ||
if (redrawQueue.drawCommands) { | ||
drawCommands.apply(null, redrawQueue.drawCommands); | ||
} | ||
redrawQueue = {}; | ||
c2d.fillStyle = 'white'; | ||
c2d.globalCompositeOperation = 'destination-out'; | ||
c2d.beginPath(); | ||
c2d.arc(r + options.activePadding, r + options.activePadding, rspotlight + options.spotlightPadding, 0, Math.PI*2, true); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
if (redrawing) { | ||
raf(redraw); | ||
} | ||
}; | ||
c2d.globalCompositeOperation = 'source-over'; | ||
// kick off | ||
updatePixelRatio(); | ||
redraw(); | ||
var ctrx = void 0, | ||
ctry = void 0, | ||
rs = void 0; | ||
var bindings = { | ||
on: function on(events, selector, fn) { | ||
var _fn = fn; | ||
if (selector === 'core') { | ||
_fn = function _fn(e) { | ||
if (e.cyTarget === cy || e.target === cy) { | ||
// only if event target is directly core | ||
return fn.apply(this, [e]); | ||
} | ||
}; | ||
} | ||
function queueDrawCommands( rx, ry, theta ){ | ||
redrawQueue.drawCommands = [ rx, ry, theta ]; | ||
data.handlers.push({ | ||
events: events, | ||
selector: selector, | ||
fn: _fn | ||
}); | ||
if (selector === 'core') { | ||
cy.on(events, _fn); | ||
} else { | ||
cy.on(events, selector, _fn); | ||
} | ||
function drawCommands( rx, ry, theta ){ | ||
var dtheta = 2*Math.PI/(commands.length); | ||
var theta1 = Math.PI/2; | ||
var theta2 = theta1 + dtheta; | ||
return this; | ||
} | ||
}; | ||
theta1 += dtheta * activeCommandI; | ||
theta2 += dtheta * activeCommandI; | ||
function addEventListeners() { | ||
var grabbable = void 0; | ||
var inGesture = false; | ||
var dragHandler = void 0; | ||
var zoomEnabled = void 0; | ||
var panEnabled = void 0; | ||
var boxEnabled = void 0; | ||
var gestureStartEvent = void 0; | ||
c2d.fillStyle = options.activeFillColor; | ||
c2d.strokeStyle = 'black'; | ||
c2d.lineWidth = 1; | ||
c2d.beginPath(); | ||
c2d.moveTo(r + options.activePadding, r + options.activePadding); | ||
c2d.arc(r + options.activePadding, r + options.activePadding, r + options.activePadding, 2*Math.PI - theta1, 2*Math.PI - theta2, true); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
var restoreZoom = function restoreZoom() { | ||
if (zoomEnabled) { | ||
cy.userZoomingEnabled(true); | ||
} | ||
}; | ||
c2d.fillStyle = 'white'; | ||
c2d.globalCompositeOperation = 'destination-out'; | ||
var restoreGrab = function restoreGrab() { | ||
if (grabbable) { | ||
target.grabify(); | ||
} | ||
}; | ||
var tx = r + options.activePadding + rx/r*(rs + options.spotlightPadding - options.indicatorSize/4); | ||
var ty = r + options.activePadding + ry/r*(rs + options.spotlightPadding - options.indicatorSize/4); | ||
var rot = Math.PI/4 - theta; | ||
var restorePan = function restorePan() { | ||
if (panEnabled) { | ||
cy.userPanningEnabled(true); | ||
} | ||
}; | ||
c2d.translate( tx, ty ); | ||
c2d.rotate( rot ); | ||
var restoreBoxSeln = function restoreBoxSeln() { | ||
if (boxEnabled) { | ||
cy.boxSelectionEnabled(true); | ||
} | ||
}; | ||
// clear the indicator | ||
c2d.beginPath(); | ||
c2d.fillRect(-options.indicatorSize/2, -options.indicatorSize/2, options.indicatorSize, options.indicatorSize); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
var restoreGestures = function restoreGestures() { | ||
restoreGrab(); | ||
restoreZoom(); | ||
restorePan(); | ||
restoreBoxSeln(); | ||
}; | ||
c2d.rotate( -rot ); | ||
c2d.translate( -tx, -ty ); | ||
window.addEventListener('resize', updatePixelRatio); | ||
// c2d.setTransform( 1, 0, 0, 1, 0, 0 ); | ||
bindings.on('resize', function () { | ||
updatePixelRatio(); | ||
}).on(options.openMenuEvents, options.selector, function (e) { | ||
target = this; // Remember which node the context menu is for | ||
var ele = this; | ||
var isCy = this === cy; | ||
// clear the spotlight | ||
c2d.beginPath(); | ||
c2d.arc(r + options.activePadding, r + options.activePadding, rs + options.spotlightPadding, 0, Math.PI*2, true); | ||
c2d.closePath(); | ||
c2d.fill(); | ||
if (inGesture) { | ||
parent.style.display = 'none'; | ||
c2d.globalCompositeOperation = 'source-over'; | ||
inGesture = false; | ||
restoreGestures(); | ||
} | ||
function updatePixelRatio(){ | ||
var pxr = getPixelRatio(); | ||
var w = container.clientWidth; | ||
var h = container.clientHeight; | ||
if (typeof options.commands === 'function') { | ||
commands = options.commands(target); | ||
} else { | ||
commands = options.commands; | ||
} | ||
canvas.width = w * pxr; | ||
canvas.height = h * pxr; | ||
if (!commands || commands.length === 0) { | ||
return; | ||
} | ||
canvas.style.width = w + 'px'; | ||
canvas.style.height = h + 'px'; | ||
zoomEnabled = cy.userZoomingEnabled(); | ||
cy.userZoomingEnabled(false); | ||
c2d.setTransform( 1, 0, 0, 1, 0, 0 ); | ||
c2d.scale( pxr, pxr ); | ||
panEnabled = cy.userPanningEnabled(); | ||
cy.userPanningEnabled(false); | ||
boxEnabled = cy.boxSelectionEnabled(); | ||
cy.boxSelectionEnabled(false); | ||
grabbable = target.grabbable && target.grabbable(); | ||
if (grabbable) { | ||
target.ungrabify(); | ||
} | ||
var redrawing = true; | ||
var redrawQueue = {}; | ||
var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; | ||
var redraw = function(){ | ||
if( redrawQueue.drawBg ){ | ||
drawBg.apply( null, redrawQueue.drawBg ); | ||
} | ||
var rp = void 0, | ||
rw = void 0, | ||
rh = void 0; | ||
if (!isCy && ele.isNode() && !ele.isParent() && !options.atMouse) { | ||
rp = ele.renderedPosition(); | ||
rw = ele.renderedWidth(); | ||
rh = ele.renderedHeight(); | ||
} else { | ||
rp = e.renderedPosition || e.cyRenderedPosition; | ||
rw = 1; | ||
rh = 1; | ||
} | ||
if( redrawQueue.drawCommands ){ | ||
drawCommands.apply( null, redrawQueue.drawCommands ); | ||
} | ||
offset = getOffset(container); | ||
redrawQueue = {}; | ||
ctrx = rp.x; | ||
ctry = rp.y; | ||
if( redrawing ){ | ||
raf( redraw ); | ||
} | ||
}; | ||
createMenuItems(); | ||
// kick off | ||
updatePixelRatio(); | ||
redraw(); | ||
setStyles(parent, { | ||
display: 'block', | ||
left: rp.x - r + 'px', | ||
top: rp.y - r + 'px' | ||
}); | ||
var ctrx, ctry, rs; | ||
rs = Math.max(rw, rh) / 2; | ||
rs = Math.max(rs, options.minSpotlightRadius); | ||
rs = Math.min(rs, options.maxSpotlightRadius); | ||
var bindings = { | ||
on: function(events, selector, fn){ | ||
queueDrawBg(); | ||
var _fn = fn; | ||
if( selector === 'core'){ | ||
_fn = function( e ){ | ||
if( e.cyTarget === cy || e.target === cy ){ // only if event target is directly core | ||
return fn.apply( this, [ e ] ); | ||
} | ||
}; | ||
} | ||
activeCommandI = undefined; | ||
data.handlers.push({ | ||
events: events, | ||
selector: selector, | ||
fn: _fn | ||
}); | ||
inGesture = true; | ||
gestureStartEvent = e; | ||
}).on('cxtdrag tapdrag', options.selector, dragHandler = function dragHandler(e) { | ||
if( selector === 'core' ){ | ||
cy.on(events, _fn); | ||
} else { | ||
cy.on(events, selector, _fn); | ||
} | ||
if (!inGesture) { | ||
return; | ||
} | ||
return this; | ||
} | ||
}; | ||
var origE = e.originalEvent; | ||
var isTouch = origE.touches && origE.touches.length > 0; | ||
function addEventListeners(){ | ||
var grabbable; | ||
var inGesture = false; | ||
var dragHandler; | ||
var zoomEnabled; | ||
var panEnabled; | ||
var boxEnabled; | ||
var gestureStartEvent; | ||
var pageX = isTouch ? origE.touches[0].pageX : origE.pageX; | ||
var pageY = isTouch ? origE.touches[0].pageY : origE.pageY; | ||
var restoreZoom = function(){ | ||
if( zoomEnabled ){ | ||
cy.userZoomingEnabled( true ); | ||
} | ||
}; | ||
activeCommandI = undefined; | ||
var restoreGrab = function(){ | ||
if( grabbable ){ | ||
target.grabify(); | ||
} | ||
}; | ||
var dx = pageX - offset.left - ctrx; | ||
var dy = pageY - offset.top - ctry; | ||
var restorePan = function(){ | ||
if( panEnabled ){ | ||
cy.userPanningEnabled( true ); | ||
} | ||
}; | ||
if (dx === 0) { | ||
dx = 0.01; | ||
} | ||
var restoreBoxSeln = function(){ | ||
if( boxEnabled ){ | ||
cy.boxSelectionEnabled( true ); | ||
} | ||
}; | ||
var d = Math.sqrt(dx * dx + dy * dy); | ||
var cosTheta = (dy * dy - d * d - dx * dx) / (-2 * d * dx); | ||
var theta = Math.acos(cosTheta); | ||
var restoreGestures = function(){ | ||
restoreGrab(); | ||
restoreZoom(); | ||
restorePan(); | ||
restoreBoxSeln(); | ||
}; | ||
if (d < rs + options.spotlightPadding) { | ||
queueDrawBg(); | ||
return; | ||
} | ||
window.addEventListener('resize', updatePixelRatio); | ||
queueDrawBg(); | ||
bindings | ||
.on('resize', function(e){ | ||
updatePixelRatio(); | ||
}) | ||
var rx = dx * r / d; | ||
var ry = dy * r / d; | ||
.on(options.openMenuEvents, options.selector, function(e){ | ||
target = this; // Remember which node the context menu is for | ||
var ele = this; | ||
var isCy = this === cy; | ||
if (dy > 0) { | ||
theta = Math.PI + Math.abs(theta - Math.PI); | ||
} | ||
if (inGesture) { | ||
parent.style.display = 'none'; | ||
var dtheta = 2 * Math.PI / commands.length; | ||
var theta1 = Math.PI / 2; | ||
var theta2 = theta1 + dtheta; | ||
inGesture = false; | ||
for (var i = 0; i < commands.length; i++) { | ||
var command = commands[i]; | ||
restoreGestures(); | ||
} | ||
var inThisCommand = theta1 <= theta && theta <= theta2 || theta1 <= theta + 2 * Math.PI && theta + 2 * Math.PI <= theta2; | ||
if( typeof options.commands === 'function' ){ | ||
commands = options.commands(target); | ||
} else { | ||
commands = options.commands; | ||
} | ||
if (command.disabled) { | ||
inThisCommand = false; | ||
} | ||
if( !commands || commands.length === 0 ){ return; } | ||
if (inThisCommand) { | ||
activeCommandI = i; | ||
break; | ||
} | ||
zoomEnabled = cy.userZoomingEnabled(); | ||
cy.userZoomingEnabled( false ); | ||
theta1 += dtheta; | ||
theta2 += dtheta; | ||
} | ||
panEnabled = cy.userPanningEnabled(); | ||
cy.userPanningEnabled( false ); | ||
queueDrawCommands(rx, ry, theta); | ||
}).on('tapdrag', dragHandler).on('cxttapend tapend', function () { | ||
parent.style.display = 'none'; | ||
boxEnabled = cy.boxSelectionEnabled(); | ||
cy.boxSelectionEnabled( false ); | ||
if (activeCommandI !== undefined) { | ||
var select = commands[activeCommandI].select; | ||
grabbable = target.grabbable && target.grabbable(); | ||
if( grabbable ){ | ||
target.ungrabify(); | ||
} | ||
if (select) { | ||
select.apply(target, [target, gestureStartEvent]); | ||
activeCommandI = undefined; | ||
} | ||
} | ||
var rp, rw, rh; | ||
if( !isCy && ele.isNode() && !ele.isParent() && !options.atMouse ){ | ||
rp = ele.renderedPosition(); | ||
rw = ele.renderedWidth(); | ||
rh = ele.renderedHeight(); | ||
} else { | ||
rp = e.renderedPosition || e.cyRenderedPosition; | ||
rw = 1; | ||
rh = 1; | ||
} | ||
inGesture = false; | ||
offset = getOffset(container); | ||
restoreGestures(); | ||
}); | ||
} | ||
ctrx = rp.x; | ||
ctry = rp.y; | ||
function removeEventListeners() { | ||
var handlers = data.handlers; | ||
createMenuItems(); | ||
for (var i = 0; i < handlers.length; i++) { | ||
var h = handlers[i]; | ||
setStyles(parent, { | ||
display: 'block', | ||
left: (rp.x - r) + 'px', | ||
top: (rp.y - r) + 'px' | ||
}); | ||
if (h.selector === 'core') { | ||
cy.off(h.events, h.fn); | ||
} else { | ||
cy.off(h.events, h.selector, h.fn); | ||
} | ||
} | ||
rs = Math.max(rw, rh)/2; | ||
rs = Math.max(rs, options.minSpotlightRadius); | ||
rs = Math.min(rs, options.maxSpotlightRadius); | ||
window.removeEventListener('resize', updatePixelRatio); | ||
} | ||
queueDrawBg(); | ||
function destroyInstance() { | ||
redrawing = false; | ||
activeCommandI = undefined; | ||
removeEventListeners(); | ||
inGesture = true; | ||
gestureStartEvent = e; | ||
}) | ||
wrapper.remove(); | ||
} | ||
.on('cxtdrag tapdrag', options.selector, dragHandler = function(e){ | ||
addEventListeners(); | ||
if( !inGesture ){ return; } | ||
return { | ||
destroy: function destroy() { | ||
destroyInstance(); | ||
} | ||
}; | ||
}; | ||
var origE = e.originalEvent; | ||
var isTouch = origE.touches && origE.touches.length > 0; | ||
module.exports = cxtmenu; | ||
var pageX = isTouch ? origE.touches[0].pageX : origE.pageX; | ||
var pageY = isTouch ? origE.touches[0].pageY : origE.pageY; | ||
/***/ }), | ||
/* 1 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
activeCommandI = undefined; | ||
"use strict"; | ||
var dx = pageX - offset.left - ctrx; | ||
var dy = pageY - offset.top - ctry; | ||
if( dx === 0 ){ dx = 0.01; } | ||
// Simple, internal Object.assign() polyfill for options objects etc. | ||
var d = Math.sqrt( dx*dx + dy*dy ); | ||
var cosTheta = (dy*dy - d*d - dx*dx)/(-2 * d * dx); | ||
var theta = Math.acos( cosTheta ); | ||
module.exports = Object.assign != null ? Object.assign.bind(Object) : function (tgt) { | ||
for (var _len = arguments.length, srcs = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
srcs[_key - 1] = arguments[_key]; | ||
} | ||
if( d < rs + options.spotlightPadding ){ | ||
queueDrawBg(); | ||
return; | ||
} | ||
srcs.forEach(function (src) { | ||
Object.keys(src).forEach(function (k) { | ||
return tgt[k] = src[k]; | ||
}); | ||
}); | ||
queueDrawBg(); | ||
return tgt; | ||
}; | ||
var rx = dx*r / d; | ||
var ry = dy*r / d; | ||
/***/ }), | ||
/* 2 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
if( dy > 0 ){ | ||
theta = Math.PI + Math.abs(theta - Math.PI); | ||
} | ||
"use strict"; | ||
var dtheta = 2*Math.PI/(commands.length); | ||
var theta1 = Math.PI/2; | ||
var theta2 = theta1 + dtheta; | ||
for( var i = 0; i < commands.length; i++ ){ | ||
var command = commands[i]; | ||
var defaults = { | ||
menuRadius: 100, // the radius of the circular menu in pixels | ||
selector: 'node', // elements matching this Cytoscape.js selector will trigger cxtmenus | ||
commands: [// an array of commands to list in the menu or a function that returns the array | ||
/* | ||
{ // example command | ||
fillColor: 'rgba(200, 200, 200, 0.75)', // optional: custom background color for item | ||
content: 'a command name' // html/text content to be displayed in the menu | ||
contentStyle: {}, // css key:value pairs to set the command's css in js if you want | ||
select: function(ele){ // a function to execute when the command is selected | ||
console.log( ele.id() ) // `ele` holds the reference to the active element | ||
}, | ||
enabled: true // whether the command is selectable | ||
} | ||
*/ | ||
], // function( ele ){ return [ /*...*/ ] }, // example function for commands | ||
fillColor: 'rgba(0, 0, 0, 0.75)', // the background colour of the menu | ||
activeFillColor: 'rgba(1, 105, 217, 0.75)', // the colour used to indicate the selected command | ||
activePadding: 20, // additional size in pixels for the active command | ||
indicatorSize: 24, // the size in pixels of the pointer to the active command | ||
separatorWidth: 3, // the empty spacing in pixels between successive commands | ||
spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight | ||
minSpotlightRadius: 24, // the minimum radius in pixels of the spotlight | ||
maxSpotlightRadius: 38, // the maximum radius in pixels of the spotlight | ||
openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here | ||
itemColor: 'white', // the colour of text in the command's content | ||
itemTextShadowColor: 'transparent', // the text shadow colour of the command's content | ||
zIndex: 9999, // the z-index of the ui div | ||
atMouse: false // draw menu at mouse position | ||
}; | ||
var inThisCommand = theta1 <= theta && theta <= theta2 | ||
|| theta1 <= theta + 2*Math.PI && theta + 2*Math.PI <= theta2; | ||
module.exports = defaults; | ||
if( command.disabled ){ | ||
inThisCommand = false; | ||
} | ||
/***/ }), | ||
/* 3 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
if( inThisCommand ){ | ||
activeCommandI = i; | ||
break; | ||
} | ||
"use strict"; | ||
theta1 += dtheta; | ||
theta2 += dtheta; | ||
} | ||
queueDrawCommands( rx, ry, theta ); | ||
}) | ||
var removeEles = function removeEles(query) { | ||
var ancestor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document; | ||
.on('tapdrag', dragHandler) | ||
ancestor.querySelectorAll(query).forEach(function (el) { | ||
return el.parentNode.removeChild(el); | ||
}); | ||
}; | ||
.on('cxttapend tapend', function(e){ | ||
parent.style.display = 'none'; | ||
var setStyles = function setStyles(el, style) { | ||
var props = Object.keys(style); | ||
if( activeCommandI !== undefined ){ | ||
var select = commands[ activeCommandI ].select; | ||
for (var i = 0, l = props.length; i < l; i++) { | ||
el.style[props[i]] = style[props[i]]; | ||
} | ||
}; | ||
if( select ){ | ||
select.apply( target, [target, gestureStartEvent] ); | ||
activeCommandI = undefined; | ||
} | ||
} | ||
var createElement = function createElement(options) { | ||
options = options || {}; | ||
inGesture = false; | ||
var el = document.createElement(options.tag || 'div'); | ||
restoreGestures(); | ||
}) | ||
; | ||
} | ||
el.className = options.class || ''; | ||
function removeEventListeners(){ | ||
var handlers = data.handlers; | ||
if (options.style) { | ||
setStyles(el, options.style); | ||
} | ||
for( var i = 0; i < handlers.length; i++ ){ | ||
var h = handlers[i]; | ||
return el; | ||
}; | ||
if( h.selector === 'core' ){ | ||
cy.off(h.events, h.fn); | ||
} else { | ||
cy.off(h.events, h.selector, h.fn); | ||
} | ||
} | ||
var getPixelRatio = function getPixelRatio() { | ||
return window.devicePixelRatio || 1; | ||
}; | ||
window.removeEventListener('resize', updatePixelRatio); | ||
} | ||
var getOffset = function getOffset(el) { | ||
var offset = el.getBoundingClientRect(); | ||
function destroyInstance(){ | ||
redrawing = false; | ||
return { | ||
left: offset.left + document.body.scrollLeft + parseFloat(getComputedStyle(document.body)['padding-left']) + parseFloat(getComputedStyle(document.body)['border-left-width']), | ||
top: offset.top + document.body.scrollTop + parseFloat(getComputedStyle(document.body)['padding-top']) + parseFloat(getComputedStyle(document.body)['border-top-width']) | ||
}; | ||
}; | ||
removeEventListeners(); | ||
module.exports = { removeEles: removeEles, setStyles: setStyles, createElement: createElement, getPixelRatio: getPixelRatio, getOffset: getOffset }; | ||
wrapper.remove(); | ||
} | ||
/***/ }), | ||
/* 4 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
addEventListeners(); | ||
"use strict"; | ||
return { | ||
destroy: function(){ | ||
destroyInstance(); | ||
} | ||
}; | ||
}); | ||
var cxtmenu = __webpack_require__(0); | ||
}; // reg | ||
// registers the extension on a cytoscape lib ref | ||
var register = function register(cytoscape) { | ||
if (!cytoscape) { | ||
return; | ||
} // can't register if cytoscape unspecified | ||
if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module | ||
module.exports = register; | ||
} else if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module | ||
define('cytoscape-cxtmenu', function(){ | ||
return register; | ||
}); | ||
} | ||
cytoscape('core', 'cxtmenu', cxtmenu); // register with cytoscape.js | ||
}; | ||
if( typeof cytoscape !== typeof undefined ){ // expose to global cytoscape (i.e. window.cytoscape) | ||
register(cytoscape); | ||
} | ||
if (typeof cytoscape !== 'undefined') { | ||
// expose to global cytoscape (i.e. window.cytoscape) | ||
register(cytoscape); | ||
} | ||
})(); | ||
module.exports = register; | ||
/***/ }) | ||
/******/ ]); | ||
}); |
{ | ||
"name": "cytoscape-cxtmenu", | ||
"version": "2.10.3", | ||
"description": "A context menu for Cytoscape.js", | ||
"version": "3.0.0", | ||
"description": "A circular, swipeable context menu extension for Cytoscape.js", | ||
"main": "cytoscape-cxtmenu.js", | ||
"author": { | ||
"name": "Max Franz", | ||
"email": "maxkfranz@gmail.com" | ||
}, | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"postpublish": "run-s gh-pages:demo gh-pages:deploy gh-pages:clean", | ||
"gh-pages:demo": "cpy demo.html . --rename=index.html", | ||
"gh-pages:deploy": "gh-pages -d .", | ||
"gh-pages:clean": "rimraf index.html", | ||
"copyright": "update license", | ||
"lint": "eslint src", | ||
"build": "cross-env NODE_ENV=production webpack", | ||
"build:min": "cross-env NODE_ENV=production MIN=true webpack", | ||
"build:release": "run-s build copyright", | ||
"watch": "webpack --progress --watch", | ||
"dev": "webpack-dev-server --open", | ||
"test": "mocha" | ||
}, | ||
@@ -15,4 +30,3 @@ "repository": { | ||
"cytoscape", | ||
"extension", | ||
"cyext" | ||
"cytoscape-extension" | ||
], | ||
@@ -25,13 +39,23 @@ "license": "MIT", | ||
"devDependencies": { | ||
"gulp": "^3.8.8", | ||
"gulp-jshint": "^1.8.5", | ||
"gulp-prompt": "^0.1.1", | ||
"gulp-replace": "^0.4.0", | ||
"gulp-shell": "^0.2.9", | ||
"jshint-stylish": "^1.0.0", | ||
"run-sequence": "^1.0.0" | ||
"babel-core": "^6.24.1", | ||
"babel-loader": "^7.0.0", | ||
"babel-preset-env": "^1.5.1", | ||
"camelcase": "^4.1.0", | ||
"chai": "4.0.2", | ||
"cpy-cli": "^1.0.1", | ||
"cross-env": "^5.0.0", | ||
"eslint": "^3.9.1", | ||
"gh-pages": "^1.0.0", | ||
"mocha": "3.4.2", | ||
"npm-run-all": "^4.1.2", | ||
"rimraf": "^2.6.2", | ||
"update": "^0.7.4", | ||
"updater-license": "^1.0.0", | ||
"webpack": "^2.6.1", | ||
"webpack-dev-server": "^2.4.5" | ||
}, | ||
"peerDependencies": { | ||
"cytoscape": "^2.2.0 || ^3.0.0" | ||
} | ||
"cytoscape": "^3.2.0" | ||
}, | ||
"dependencies": {} | ||
} |
cytoscape-cxtmenu | ||
================================================================================ | ||
![Preview](https://raw.githubusercontent.com/cytoscape/cytoscape.js-cxtmenu/master/img/preview.png) | ||
[![DOI](https://zenodo.org/badge/16010906.svg)](https://zenodo.org/badge/latestdoi/16010906) | ||
![Preview](https://raw.githubusercontent.com/cytoscape/cytoscape.js-cxtmenu/master/preview.png) | ||
## Description | ||
A context menu for Cytoscape.js | ||
A circular, swipeable context menu extension for Cytoscape.js ([demo](https://cytoscape.github.io/cytoscape.js-cxtmenu)) | ||
This plugin creates a widget that lets the user operate circular context menus on nodes in Cytoscape.js. The user swipes along the circular menu to select a menu item and perform a command on the node of interest. | ||
This extension creates a widget that lets the user operate circular context menus on nodes in Cytoscape.js. The user swipes along the circular menu to select a menu item and perform a command on either a node, a edge, or the graph background. | ||
## Dependencies | ||
* Cytoscape.js ^2.2.0 || ^3.0.0 | ||
* Cytoscape.js ^3.2.0 | ||
@@ -25,13 +26,24 @@ | ||
`require()` the library as appropriate for your project: | ||
Import the library as appropriate for your project: | ||
CommonJS: | ||
ES import: | ||
```js | ||
var cytoscape = require('cytoscape'); | ||
var cxtmenu = require('cytoscape-cxtmenu'); | ||
import cytoscape from 'cytoscape'; | ||
import cxtmenu from 'cytoscape-cxtmenu'; | ||
cxtmenu( cytoscape ); // register extension | ||
cytoscape.use( cxtmenu ); | ||
``` | ||
CommonJS require: | ||
```js | ||
let cytoscape = require('cytoscape'); | ||
let cxtmenu = require('cytoscape-cxtmenu'); | ||
cytoscape.use( cxtmenu ); // register extension | ||
``` | ||
AMD: | ||
```js | ||
@@ -57,3 +69,3 @@ require(['cytoscape', 'cytoscape-cxtmenu'], function( cytoscape, cxtmenu ){ | ||
var cy = cytoscape({ | ||
let cy = cytoscape({ | ||
container: document.getElementById('cy'), | ||
@@ -64,3 +76,3 @@ /* ... */ | ||
// the default values of each option are outlined below: | ||
var defaults = { | ||
let defaults = { | ||
menuRadius: 100, // the radius of the circular menu in pixels | ||
@@ -73,2 +85,3 @@ selector: 'node', // elements matching this Cytoscape.js selector will trigger cxtmenus | ||
content: 'a command name' // html/text content to be displayed in the menu | ||
contentStyle: {}, // css key:value pairs to set the command's css in js if you want | ||
select: function(ele){ // a function to execute when the command is selected | ||
@@ -82,3 +95,3 @@ console.log( ele.id() ) // `ele` holds the reference to the active element | ||
fillColor: 'rgba(0, 0, 0, 0.75)', // the background colour of the menu | ||
activeFillColor: 'rgba(92, 194, 237, 0.75)', // the colour used to indicate the selected command | ||
activeFillColor: 'rgba(1, 105, 217, 0.75)', // the colour used to indicate the selected command | ||
activePadding: 20, // additional size in pixels for the active command | ||
@@ -92,3 +105,3 @@ indicatorSize: 24, // the size in pixels of the pointer to the active command | ||
itemColor: 'white', // the colour of text in the command's content | ||
itemTextShadowColor: 'black', // the text shadow colour of the command's content | ||
itemTextShadowColor: 'transparent', // the text shadow colour of the command's content | ||
zIndex: 9999, // the z-index of the ui div | ||
@@ -98,3 +111,3 @@ atMouse: false // draw menu at mouse position | ||
var cxtmenuApi = cy.cxtmenu( defaults ); | ||
let menu = cy.cxtmenu( defaults ); | ||
``` | ||
@@ -105,8 +118,19 @@ | ||
```js | ||
var cxtmenuApi = cy.cxtmenu( someOptions ); | ||
let menu = cy.cxtmenu( someOptions ); | ||
cxtmenuApi.destroy(); | ||
menu.destroy(); | ||
``` | ||
## Build targets | ||
* `npm run test` : Run Mocha tests in `./test` | ||
* `npm run build` : Build `./src/**` into `cytoscape-cxtmenu.js` | ||
* `npm run watch` : Automatically build on changes with live reloading (N.b. you must already have an HTTP server running) | ||
* `npm run dev` : Automatically build on changes with live reloading with webpack dev server | ||
* `npm run lint` : Run eslint on the source | ||
N.b. all builds use babel, so modern ES features can be used in the `src`. | ||
## Publishing instructions | ||
@@ -116,4 +140,8 @@ | ||
1. Set the version number environment variable: `export VERSION=1.2.3` | ||
1. Publish: `gulp publish` | ||
1. Build the extension : `npm run build:release` | ||
1. Commit the build : `git commit -am "Build for release"` | ||
1. Bump the version number and tag: `npm version major|minor|patch` | ||
1. Push to origin: `git push && git push --tags` | ||
1. Publish to npm: `npm publish .` | ||
1. If publishing to bower for the first time, you'll need to run `bower register cytoscape-cxtmenu https://github.com/cytoscape/cytoscape.js-cxtmenu.git` | ||
1. [Make a new release](https://github.com/cytoscape/cytoscape.js-cxtmenu/releases/new) for Zenodo. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
0
0
139
1
1
81346
16
17
1155