I want users to be able to click on some text inside the node and do some action, like show some dialog or open some other window. Is this possible?
In the documentation there is something like :
text-events : Whether events should occur on an element if the label receives an event; may be yes or no. You may want a style applied to the text on :active so you know the text is activatable.
it seems like the thing but there is no example how to use it on the label level..
EDIT: example
on the diagram
how I imagine it could be in the code:
label_element.on('tap', function(event){
// cyTarget holds a reference to the label
var evtTarget = event.cyTarget;
//...
});
or
cy.on('tap', function(event){
var evtTarget = event.cyTarget;
//evtTarget holds element but I can somehow get the text which got tap event??
});
According Cytoscape.js documentation, you may try do this using
cy.on('tap')
, like this:
Examples
Bind to events that bubble up from elements matching the specified node selector:
cy.on('tap', 'node', { foo: 'bar' }, function(evt){
console.log( evt.data.foo ); // 'bar'
var node = evt.cyTarget;
console.log( 'tapped ' + node.id() );
});
Bind to all tap events that the core receives:
cy.on('tap', function(event){
// cyTarget holds a reference to the originator
// of the event (core or element)
var evtTarget = event.cyTarget;
if( evtTarget === cy ){
console.log('tap on background');
} else {
console.log('tap on some element');
}
});
At http://js.cytoscape.org/#cy.on
If text-events: yes, tapping a node's label will trigger tap on the node.
If you want to have arbitrary UIs on top of nodes that can be independently interacted with, then you should create a separate layer in the DOM.
Rationale : The labels are relatively simple in Cytoscape.js, because supporting complex ones would be on the same order of complexity as the DOM. In that case, it's better to use the DOM as a layer on top of the graph rather than to reimplement it in Cytoscape.js.
Related
Is there a way to observe the mouse click event and determine which widget was clicked?
So basically I wish I could do something like this (on mouse click anywhere on the page)
on("click", function (e) {
//var aWidget = dijit.getEnclosingWidget(e.target);
//var id = aWidget.id
//do something based on the widget id
});
You can but it will requires some extra steps.
Basically, the logic is:
- When you click on a node, you have to go up in the DOM until you find a node with the attribute widgetId
- When you have it, use dijit/registry::byNode to fetch the widget.
If you skip the node traversing, you will find the widget only if the main domNode of the widget was clicked.
require(['dojo/on', 'dijit/registry'], function(on, registry){
on(document, 'click', function(event){
var target = event.target,
widget;
while(!target.getAttribute('widgetId') && target.parentNode) {
target = target.parentNode;
}
widget = registry.byNode(target);
console.warn(widget);
});
});
Be aware, this method will work ONLY if you have 1 dojo instance loaded on in the page.
If you page have more than one dojo instance then the document click event must be attached by every dojo instances.
Might be a lot of overhead but yes you can
require(["dojox/mobile/deviceTheme","dojo/on","dijit/registry"],function(theme,on,reg){
on(document,'click', function(e){
console.log(e.target);
var widget = reg.byNode(e.target);
console.log("foundWidget::" + widget.id);
});
});
I've started to do a visualization using svg. it's a simple column chart thing and working fine that far. I'm loading the data from an external XML file and display a column chart.
Now I want to add a hover-effect, that will change the color of the bar when hovering a column.
So the question is how do I add an eventhandler to a previously generated svg element.
I tried different ways:
(1) When generating the element trying to add the eventhandler already:
newElement.onmouseclick="highlightOn(this)";
(2) adding the event handler this supposedly more advanced way I don't know how to select the right element that fired the event inside the SVG.
newElement.addEventListener("mouseover", highlightOn, false)
(3) some forum showed this as a possibility (doesn't work either: contentDocument returns null)
theSVG.addEventListener("click", function(){
console.log("svg hovered");
var svgDoc = theSVG.contentDocument; //get the inner DOM of alpha.svg
console.log(svgDoc);
var allColums= svgDoc.getElementsByTagName("rect");
for (var i = 0; i < allColums.length; i++) {
allColums[i].addEventListener("click", function(){
console.log("clicked!"); })
};
});
so all in all, I'm quite confused and have no idea how to proceed.
Here is how I'm generating the svg:
for (var i = 0; i < allLogs.length; i++) {
//reading data
date =allLogs[i].getElementsByTagName("date")[0].firstChild.data;
console.log("date "+date);
time5000m =allLogs[i].getElementsByTagName("TimeFivethousandMeter")[0].firstChild.data;
if (time5000m==" ") {time5000m=0;};
console.log("time 5000m"+time5000m);
//adding data to SVG
//>> colum
var newElement = document.createElementNS("http://www.w3.org/2000/svg", 'rect'); //Create a rect in SVG's namespace
newElement.setAttribute("width",width);
newElement.setAttribute("height",time5000m*scaleFactor);
var xPos=width*i+i*offset+sideMargins/2;
newElement.setAttribute("x",xPos);
var yPos=height-time5000m*scaleFactor-verticalMargin/2;
newElement.setAttribute("y", yPos);
newElement.style.fill = "#cf004e"; //Set fill colour
newElement.style.opacity="0.75";
theSVG.appendChild(newElement);
};
How to deal with this?
Looking at your first attempt:
newElement.onmouseclick="highlightOn(this)";
You have one mistake: onmouseclick should just be onclick
I've had trouble using this in mouse events, so the best method I've used is to set an ID for the element in question, then use a helper function to assign to the onlick, so add something like this to your element creation loop:
var id = 'el'+i;
newElement.id = id;
newElement.onclick = funcHighlightOn(id);
Then, use a function like this that you can use to assign the onclick action:
function funcHighlightOn(id) {
return function() {
highlightOn(id);
}
}
The reason for the weirdness of the above is that it's difficult to pass parameters (in this case, the element's ID) into the mouse events when assigned this way.
There are a few things odd here. First, why in (3) are you trying to add click handlers inside a click handler? It may be that every click is being intercepted by the SVG click handler, and all you are ever doing is replacing the rect click handlers.
Why don't you just add the click handler when you create each <rect> in the first place? Add your handler to newElement when you append it.
I've been struggling with what seems to be a simple problem for a few hours now. I've written a REGEX expression that works however I was hoping for a more elegant approach for dealing with the HTML. The string would be passed in to the function, rather than dealing with the content directly in the page. After looking at many examples I feel like I must be doing something wrong. I'm attempting to take a string and clean it of client Events before saving it to our Database, I thought jQuery would be perfect for this.
I Want:
Some random text click here and a link with any event type
//to become:
Some random text click here and a link with any event type
Here's my code
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv).find('a').unbind();
return $(myDiv).html();
}
My results are, the onClick remains in the anchor tag.
Here's a pure Javascript solution that removes any attribute from any DOM element (and its children) that starts with "on":
function cleanHandlers(el) {
// only do DOM elements
if (!('tagName' in el)) return;
// attributes is a live node map, so don't increment
// the counter when removing the current node
var a = el.attributes;
for (var i = 0; i < a.length; ) {
if (a[i].name.match(/^on/i)) {
el.removeAttribute(a[i].name);
} else {
++i;
}
}
// recursively test the children
var child = el.firstChild;
while (child) {
cleanHandlers(child);
child = child.nextSibling;
}
}
cleanHandlers(document.body);
working demo at http://jsfiddle.net/alnitak/dqV5k/
unbind() doesn't work because you are using inline onclick event handler. If you were binding your click event using jquery/javascript the you can unbind the event using unbind(). To remove any inline events you can just use removeAttr('onclick')
$('a').click(function(){ //<-- bound using script
alert('clicked');
$('a').unbind(); //<-- will unbind all events that aren't inline on all anchors once one link is clicked
});
http://jsfiddle.net/LZgjF/1/
I ended up with this solution, which removes all events on any item.
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv)
.find('*')
.removeAttr('onload')
.removeAttr('onunload')
.removeAttr('onblur')
.removeAttr('onchange')
.removeAttr('onfocus')
.removeAttr('onreset')
.removeAttr('onselect')
.removeAttr('onsubmit')
.removeAttr('onabort')
.removeAttr('onkeydown')
.removeAttr('onkeypress')
.removeAttr('onkeyup')
.removeAttr('onclick')
.removeAttr('ondblclick')
.removeAttr('onmousedown')
.removeAttr('onmousemove')
.removeAttr('onmouseout')
.removeAttr('onmouseover')
.removeAttr('onmouseup');
return $(myDiv).html();
}
I am adding a custom data attribute data-js-href to various HTML elements, and these elements should behave just like a link when clicked. If a link within such an element is clicked, the link should take precedence and the data-js-href functionality should be ignored, though. Furthermore, the solution also needs to work with elements that are dynamically added at a later time.
So far, I have come up with the following solution. It basically checks if the click was performed on a link, or any child element of a link (think <a href='…'><img src='…' alt='…' /></a>).
// Make all elements with a `data-js-href` attribute clickable
$$('body').addEvent('click:relay([data-js-href])',
function(event, clicked) {
var link = clicked.get('data-js-href');
if (link && !event.target.match('a')) {
var parents = event.target.getParents();
for (var i = 0; i < parents.length && parents[i] != clicked; i++) {
if (parents[i].match('a')) {
return;
}
}
document.location.href = link;
}
});
It works, but it feels very clumsy, and I think that there has to be a more elegant solution. I tried something along the lines of
$$('body').addEvent('click:relay([data-js-href] a)',
function(event, clicked) {
event.stopPropagation();
}
but to no avail. (I littered the code with some console.log() messages to verify the behavior.) Any idea is welcome.
you can do this with 2 delegated events - no reverse lookups and it's cheap as they will share the same event. the downside is, it is the same event so it will fire for both and there's no stopping it via the event methods (already bubbled, it's a single event that stacks up multiple pseudo event callbacks and executes them in order--the event has stopped but the callbacks continue) That's perhaps an inconsistency in mootools event vs delegation implementation but it's a subject of another issue.
Workarounds for now can be:
to have the 2 event handlers communicate through each other. It will scale and work with any new els added.
to add the delegators on 2 different elements. eg. document.body and #mainWrap.
http://jsfiddle.net/dimitar/J59PD/4/
var showURL = function(howLong) {
// debug.
return function() {
console.log(window.location.href);
}.delay(howLong || 1000);
};
document.id(document.body).addEvents({
"click:relay([data-js-href] a))": function(e) {
// performance on lookup for repeat clicks.
var parent = this.retrieve("parent");
if (!parent) {
parent = this.getParent("[data-js-href]");
this.store("parent", parent);
}
// communicate it's a dummy event to parent delegator.
parent.store("linkEvent", e);
// let it bubble...
},
"click:relay([data-js-href])": function(e) {
// show where we have gone.
showURL(1500);
if (this.retrieve("linkEvent")) {
this.eliminate("linkEvent");
return;
}
var prop = this.get("data-js-href");
if (prop)
window.location.href = prop;
}
});
Discussed this with Ibolmo and Keeto from the mootools team on IRC as well when my initial attempt failed to work and both callbacks fired despite the event.stop: http://jsfiddle.net/dimitar/J59PD/
As a result, there was briefly a ticket open on the mootools github issues: https://github.com/mootools/mootools-core/issues/2105 but it then went into a discussion of what the right thing to do from the library standpoint is and how viable it is to pursue changing the way things work so...
Mootools: How to Allow and Disallow var drag depending on checkbox checked or not?
window.addEvent('domready',function() {
var z = 2;
$$('#dragable').each(function(e) {
var drag = new Drag.Move(e,{
grid: false,
preventDefault: true,
onStart: function() {
e.setStyle('z-index',z++);
}
});
});
});
function check(tag){
if(tag.checked){
//checkbox checked
//How to Disallow Drag.Move for #dragable ?
//Unfortunately so it does not work - drag.destroy(); drag.removeEvents();
}else{
//How to Allow Drag.Move for #dragable ?
}
}
<input type="checkbox" onClick="check(this);">
<div id="dragable">Drag-able DIV</div>
Store the instance of Drag in MooTools Element Store so when the checkbox is clicked, we can retrieve this instance and manipulate it.
Drag.Move is an extension to the base Drag class, and if you see the docs, you will notice it has two methods for this situation:
attach
detach
You need to call these methods on the drag object that gets created when you call new Drag.Move(..) to enable or disable dragging.
So first create the drag object as you are already doing:
var drag = new Drag.Move(e, {
...
});
And then store a reference of this drag object inside the Element Store for later retrieval.
e.store('Drag', drag);
You can use any key you want here - I've used "Drag".
Then later in the check function, retrieve the drag object, and call attach or detach on it depending on the state of the checkbox.
function check(elem) {
var drag = elem.retrieve('Drag'); // retrieve the instance we stored before
if(elem.checked) {
drag.detach(); // disable dragging
}
else {
drag.attach(); // enable dragging
}
}
See your example modified to work this the checkbox.
On a side note, if you are retrieving an element by id, you don't need to use $$ as ideally there should only be only element with that id. $$("#dragable") is just too redundant and less performant. Use document.id('dragable') or $("dragable") instead.