Context Menus in RaphaelJS
Read all about it in http://terryyoung.blogspot.com/2011/08/context-menus-for-raphaeljs.html
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<p>Drag, click or right-click on the elements, and fool around with them.</p>
<br>
<div id="SVG_DND_HOLDER_1" class="SVG_GETABOX_HOLDER"></div>
<!-- Yes, I know, custom attributes below. I've made the decision for now, so no debates -->
<ul id="menuRect" class="contextMenu">
<li><a type="radio" name="size" w="64" href="#size_64">Set size to 64</a></li>
<li><a type="radio" name="size" w="100" href="#size_100">Set size to 100</a></li>
<li><a type="radio" name="size" w="130" href="#size_130">Set size to 130</a></li>
<li class="separator"><a type="radio" name="style" val="default" href="#style_default">Use Default Style</a></li>
<li><a type="radio" name="style" val="custom" href="#style_custom">Use Custom Style</a></li>
</ul>
<ul id="menuCircle" class="contextMenu">
<li><a type="radio" name="radius" r="30" href="#radius_30">Set radius to 30</a></li>
<li><a type="radio" name="radius" r="50" href="#radius_50">Set radius to 50</a></li>
<li><a type="radio" name="radius" r="80" href="#radius_80">Set radius to 80</a></li>
<li class="separator"><a type="radio" name="style" val="default" href="#style_default">Use Default Style</a></li>
<li><a type="radio" name="style" val="custom" href="#style_custom">Use Custom Style</a></li>
</ul>
CSS
/***********************************************************************
Common styles
***********************************************************************/
html, body
{
font-family: Tahoma;
font-size: 9pt;
}
br.clear
{
clear: both;
}
/***********************************************************************
Common styles
***********************************************************************/
.SVG_GETABOX_HOLDER {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border: solid 1px #2b333c;
background-color: #dcdfe4;
width: 640px;
height: 200px;
}
/***********************************************************************
Context Menu
***********************************************************************/
.contextMenu {
position: absolute;
width: 150px;
z-index: 99999;
border: solid 1px #CCC;
background: #EEE;
padding: 0px;
margin: 0px;
display: none;
}
.contextMenu LI {
list-style: none;
padding: 0px;
margin: 0px;
}
.contextMenu A {
color: #333;
text-decoration: none;
display: block;
line-height: 20px;
height: 20px;
background-position: 6px center;
background-repeat: no-repeat;
outline: none;
padding: 1px 5px;
padding-left: 28px;
}
.contextMenu LI.hover A {
color: #FFF;
background-color: #3399FF;
}
.contextMenu LI.disabled A {
color: #AAA;
cursor: default;
}
.contextMenu LI.hover.disabled A {
background-color: transparent;
}
.contextMenu LI.separator {
border-top: solid 1px #CCC;
}
/***********************************************************************
Context Menu Icons
***********************************************************************/
.contextMenu LI.checked A { background-image: url(http://dl.dropbox.com/u/20165443/jsFiddle/images/ICON_OK.png); }
JavaScript
/**
* @blog http://terryyoung.blogspot.com/2011/08/context-menus-for-raphaeljs.html
*/
///////////////////////////////////////////////////////////////////////////////
// Please scroll to the bottom to look at the usage code of this demo.
// These below are some core extensions to RaphaelJS that makes it all happen.
/**
* Simplifies something like this:
*
* this.ox = this.type == 'rect' ? this.attr('x') : this.attr('cx');
* this.oy = this.type == 'rect' ? this.attr('y') : this.attr('cy');
*
* to this:
*
* el.o(); // and better, it supports chaining
*
* @copyright Terry Young <terryyounghk [at] gmail.com>
* @license WTFPL Version 2 ( http://en.wikipedia.org/wiki/WTFPL )
*/
Raphael.el.is = function (type) { return this.type == (''+type).toLowerCase(); };
Raphael.el.x = function () { return this.is('circle') ? this.attr('cx') : this.attr('x'); };
Raphael.el.y = function () { return this.is('circle') ? this.attr('cy') : this.attr('y'); };
Raphael.el.o = function () { this.ox = this.x(); this.oy = this.y(); return this; };
/**
*
* getABox() for RaphaelJS - getBBox() On Steroids
* More routine, pre-calculated values that getBBox() doesn't provide
*
* @author Terry Young <terryyounghk [at] gmail.com>
* @license WTFPL Version 2 ( http://en.wikipedia.org/wiki/WTFPL )
*
*/
Raphael.el.getABox = function ()
{
var b = this.getBBox(); // thanks, I'll take it from here...
var o =
{
// we'd still return what the original getBBox() provides us with
x: b.x,
y: b.y,
width: b.width,
height: b.height,
// now we can actually pre-calculate the following into properties that are more readible for humans
// x coordinates have three points: left edge, centered, and right edge
xLeft: b.x,
xCenter: b.x + b.width / 2,
xRight: b.x + b.width,
// y coordinates have three...