How to create context pad in mxgraph? - javascript

I am trying to create a list of example shapes which will be shown when any shapes in canvas is clicked. How do i create this in mxgraph.
i tried using popup menu in mxgraph and tried adding shapes to it.But i am unable to create the popup menu. i am using graph editor examples and want to create popup menu in mxgraph when any shape created is clicked.
var newDiv = document.createElement("div");
newDiv.setAttribute("id","geApp");
var graphs = new mxGraph(document.getElementById("geApp"))
graphs.setTooltips(true);
new mxRubberband(graphs);
var parent = graphs.getDefaultParent();
graphs.popupMenuHandler.autoExpand = true;
// Installs context menu
graphs.popupMenuHandler.factoryMethod = function(menu, cell, evt)
{
menu.addItem('Item 1', null, function()
{
alert('Item 1');
});
menu.addItem('Item 2', null, function()
{
alert('Item 2');
});
menu.addSeparator();
var submenu1 = menu.addItem('Submenu 1', null, null);
menu.addItem('Subitem 1', null, function()
{
alert('Subitem 1');
}, submenu1);
menu.addItem('Subitem 1', null, function()
{
alert('Subitem 2');
}, submenu1);
};
I am getting error as
it skips the
graphs.popupMenuHandler.factoryMethod().
I want to create a popup menu or a context pad in mxgraph whenever a shape created on canvas is clicked.

The graph does not have createElement() function, instead you should use :
var t = document.createElement('div');
But why are you appending this div to container?
Please write the code in the following way. The return statement is missing in your code
graph.popupMenuHandler.factoryMethod = function(menu, cell, evt)
{
return createPopupMenu(menu, cell, evt);
};
function createPopupMenu(menu, cell, evt)
{
// Your code to add the menu item
}

Related

Openlayers 5 Display different Popup informations for different layers on the same map

im using OpenLayers 5 to display two different layers on the same map. I can see both Markers on the Map with different icons. The code below writes in the popup of one layer. Now my question is: how can i display different Infos on the Popup for each specific layer. For example when the mouse is over the first icon the popup should contain the name of the first layer and when it is over the second different icon it shows the name of the second layer.
I assume i should use map.getFeaturesAtPixel(event.pixel, function (layer1)) or something like this but im facing problems right there
//display the pop with on mouse over event
map.on('pointermove', function (event) {
const features = map.getFeaturesAtPixel(event.pixel);
if (features.length > 0 ) {
var coordinate = event.coordinate;
//get the infos that are going to be displayed in the Pop-up window;
const layerOneName = features[0].get('vehName');
// text written inside the popup
content.innerHTML = '<b>'+layerOneName +'</b>';
overlay.setPosition(coordinate);
}
});
If you use forEachFeatureAtPixel use can add a layer filter function and use that to set the layer
map.on('pointermove', function (event) {
let layer;
const feature = map.forEachFeatureAtPixel(
event.pixel,
function (feature) {
return feature;
},
{
layerFilter: function (candidate) {
layer = candidate;
return true;
}
}
);
if (feature) {
var coordinate = event.coordinate;
//get the infos that are going to be displayed in the Pop-up window;
const layerOneName = feature.get('vehName');
// text written inside the popup
content.innerHTML = '<b>'+layerOneName +'</b>';
overlay.setPosition(coordinate);
}
});

window.onresize event deletes d3 data from chart object

I have created a js constructor function to create a D3 chart object.
The function appears to work on initial load. However,I have also added an onresize listener to re-draw the chart on resize.
However, when the resize event occurs, a console.log() of the data used to make the chart shows that the dates field (the first field) is all null. I have not been successful in using console.log to find where this change actually occurs. The data seems normal before the resize and before the chart drawing function runs.
Here is a jsfiddle, which as the full code. When you resize the viewport, the chart disappears. console shows myData is null
Relevant code:
HTML
var firstChart = new LineChart(myData,'chart-container','chart_area','This Is A Chart',["red","yellow","blue"],"temp","date")
//Re draw on resize
window.onresize = function(){
firstChart.drawChart();
console.log(myData);
}
DATA
var myData = [
{"date":20111001,"New_York":63.4,"San_Francisco":62.7,"Austin":72.2},
{"date":20111002,"New_York":58,"San_Francisco":59.9,"Austin":67.7},
{"date":20111003,"New_York":53.3,"San_Francisco":59.1,"Austin":69.4},
{"date":20111004,"New_York":55.7,"San_Francisco":58.8,"Austin":68},
{"date":20111005,"New_York":64.2,"San_Francisco":58.7,"Austin":72.4},
{"date":20111006,"New_York":58.8,"San_Francisco":57,"Austin":77},
{"date":20111007,"New_York":57.9,"San_Francisco":56.7,"Austin":82.3},
{"date":20111008,"New_York":61.8,"San_Francisco":56.8,"Austin":78.9},
{"date":20111009,"New_York":69.3,"San_Francisco":56.7,"Austin":68.8},
{"date":20111010,"New_York":71.2,"San_Francisco":60.1,"Austin":68.7},
{"date":20111011,"New_York":68.7,"San_Francisco":61.1,"Austin":70.3},
{"date":20111012,"New_York":61.8,"San_Francisco":61.5,"Austin":75.3},
{"date":20111013,"New_York":63,"San_Francisco":64.3,"Austin":76.6},
{"date":20111014,"New_York":66.9,"San_Francisco":67.1,"Austin":66.6},
{"date":20111015,"New_York":61.7,"San_Francisco":64.6,"Austin":68},
{"date":20111016,"New_York":61.8,"San_Francisco":61.6,"Austin":70.6},
{"date":20111017,"New_York":62.8,"San_Francisco":61.1,"Austin":71.1},
{"date":20111018,"New_York":60.8,"San_Francisco":59.2,"Austin":70},
{"date":20111019,"New_York":62.1,"San_Francisco":58.9,"Austin":61.6},
{"date":20111020,"New_York":65.1,"San_Francisco":57.2,"Austin":57.4},
{"date":20111021,"New_York":55.6,"San_Francisco":56.4,"Austin":64.3}
]
On resize the date column is all null
JS
function LineChart(data,chartContainerID,chartAreaId,chartTitle,colorArray,yaxisLabel,xaxisLabel,legend,yaxisFormat, marginsDict){
this.data = data;
this.chartContainer = document.getElementById(chartContainerID)
this.chartArea = document.getElementById(chartAreaId);
this.chartTitle = chartTitle;
this.colors = colorArray;
this.yaxisLabel=yaxisLabel;
this.xaxisLabel=xaxisLabel;
this.isLegend = legend;
this.yaxisFormat= yaxisFormat;
this.margins = marginsDict;
///....more code here in js fiddle.....
this.drawChart = function(){
///....more code here in js fiddle.....
///Console leads me here. more code above it
var items = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
console.log(d)
return {
date: d.date,
result: +d[name]
};
})
};
});
///....more code here in js fiddle.....
}
}

(Vis.js network) Incorrect node coordinates with getPositions?

In my vis.js network, I want to make a popup appear at the position of a node when I click on the node.
I used the getPositions method but the popup appears in the wrong place (too much on the left and top corner), as if the coordinates were incorrect.
network.on("click", function (params) {
// Get the node ID
var nodeId = params.nodes[0];
if (nodeId) {
// Get the node title to show in the popup
var popup = this.body.nodes[nodeId].options.title;
// Get the node coordinates
var nodePosition = network.getPositions(nodeId);
var nodeX = nodePosition[nodeId].x;
var nodeY = nodePosition[nodeId].y;
// Show the tooltip in a div
document.getElementById('popup').innerHTML = popup;
document.getElementById('popup').style.display = "block";
// Place the div
document.getElementById('popup').style.position = "absolute";
document.getElementById('popup').style.top = nodeY+'px';
document.getElementById('popup').style.left = nodeX+'px';
}
});
// Empty and hide the div when click elsewhere
network.on("deselectNode", function (params) {
document.getElementById('popup').innerHTML = null;
document.getElementById('popup').style.display = "none";
});
I got some help on the vis support section of github.
Turns out the trick was to use canvasToDOM().
Here's how it applied to my code:
network.on("click", function(params) {
// Get the node ID
var nodeId = params.nodes[0];
if (nodeId) {
// Get the node title to show in the popup
var popup = this.body.nodes[nodeId].options.title;
// Get the node coordinates
var { x: nodeX, y: nodeY } = network.canvasToDOM(
network.getPositions([nodeId])[nodeId]
);
// Show the tooltip in a div
document.getElementById("popup").style.display = "block";
// Place the div
document.getElementById("popup").style.position = "absolute";
document.getElementById("popup").style.top = nodeY + "px";
document.getElementById("popup").style.left = nodeX + "px";
}
});
It works when the network stays put, but in my case I want to fit the network and zoom on the clicked node, so the popup doesn't follow, but since this is a separate issue I will post another question.
You are using network.getPositions(params.nodes[0]), but since the nodes can change a lot when zooming in and out and moving the network on the canvas somehow the positions do not match the real position of the node. I do not know if this is a bug in visjs or there is some other reason for it. The docs say they return the position of the node in the canvas space. But thats clearly not the case in your example.
Looking at the docs [ https://visjs.github.io/vis-network/docs/network/#Events ] the click event argument contains:
{
nodes: [Array of selected nodeIds],
edges: [Array of selected edgeIds],
event: [Object] original click event,
pointer: {
DOM: {x:pointer_x, y:pointer_y}, // << Try using this values
canvas: {x:canvas_x, y:canvas_y}
}
}
Try to use the params.pointer.DOM or params.pointer.canvas positions X and Y to position your popup. This should be the location of the cursor. This will be the same position as the node, since you clicked on it.
So try something like:
document.getElementById('popup').style.top = params.pointer.DOM.y +'px';
document.getElementById('popup').style.left = params.pointer.DOM.x +'px';
-- Untested
use the click event and paint a div over the canvas.
network.on("click", function(params) {
// Get the node ID
var nodeId = params.nodes[0];
if (nodeId) {
// Get the node title to show in the popup
var popup = this.body.nodes[nodeId].options.title;
//use JQUERY to see where the canvas is on the page.
var canvasPosition = $('.vis-network').position();
//the params give x & y relative to the edge of the canvas, not to the
//whole document.
var clickX = params.pointer.DOM.x + canvasPosition.top;
var clickY = params.pointer.DOM.y + canvasPosition.left;
// Show the tooltip in a div
document.getElementById("popup").style.display = "block";
// Place the div
document.getElementById("popup").style.position = "absolute";
document.getElementById("popup").style.top = clickY + "px";
document.getElementById("popup").style.left = clickX + "px";
}
});
fixed position for tooltip/popup example

leaflet custom control in front of everything

I am working with leaflet and wanted to add some custom controls on my leaflet map. That worked fine. However my problem is, that those custom controls are more in front of the map and not 'on' the map.
So here an example to better understand what i mean: (the navbar is in the same html file as the leaflet map)
I have a navbar and beneath there is the leaflet map. In the left corner of the leaflet map is a custom control (compass). So now when I use the dropdown menu from the navbar, i barely can click on on of the options, as the custom control is 'in front of it' and is blocking the hit bock. (picture below).
Is there a way to put the custom control more on the map than in front of the map?
Here is my custom control (compass):
onAdd: function() {
var controlDiv = L.DomUtil.create('div', 'leaflet-compass');
L.DomEvent
.addListener(controlDiv, 'click', L.DomEvent.stopPropagation)
.addListener(controlDiv, 'click', L.DomEvent.preventDefault);
var compassDiv = document.createElement('div');
compassDiv.id = 'compassGroup';
var compassImage = document.createElement('img');
compassImage.id = 'cpImage';
compassImage.setAttribute('src', 'images/kompass.png');
var speedHeadline = document.createElement('h2');
speedHeadline.id = 'speedHL';
var arrowImage = document.createElement('img');
arrowImage.id = 'arImage';
arrowImage.setAttribute('src', 'images/arrow.png');
controlDiv.appendChild(compassDiv);
compassDiv.appendChild(compassImage);
compassDiv.appendChild(arrowImage);
controlDiv.appendChild(speedHeadline);
return controlDiv;
}
});
L.control.compass = function(options) {
return new L.Control.Compass(options);
};
function initCompass(map, timestamp) {
var compassControl = L.control.compass();
map.addControl(compassControl);
rotateCompass(timestamp);
}

Multiple instances of InfoVis RGraph visualisations

I am developing an application that has multiple tabs (using jQuery UI). These can be opened and closed by the user. Within each tab is an rGraph visualisation from the JavaScript InfoVis Toolkit (http://philogb.github.io/jit/static/v20/Jit/Examples/RGraph/example1.html). (The code for both the tabs and the visualisations are very similar to the examples on their respective websites)
Whenever I create a new tab, the rGraph is generated correctly. This seems to scale quite nicely and I can click back and forth through multiple tabs without any problems. However, if I interact with an rGraph in any way (e.g. by clicking on a node to move it around), the existing rGraphs in the other tabs stop working. When I click on any of the existing rGraphs, it produces the error: TypeError: node is undefined. In other words, new instances work fine but clicking on the newest one breaks the previous ones.
Is there anything that can be done about this?
Note: There does appear to be some allowance for multiple instances in the docs - you can create each instance with a different variable name, e.g. var graph1 = new ... var graph2 = new ... etc. This does indeed work, but as the tabs (and therefore the graphs) are dynamically generated, I cannot assign specific variable names like this. I tried doing the following:
var graphs = {};
graphs[unique_id_i_pass_in] = new Graph();
...but this didn't seem to make any difference.
EDIT: Here is the code I am using to call the rGraphs (document_id is the unique variable I am passing in for each graph):
var doc_rgraph = {};
//init RGraph
doc_rgraph[document_id] = new $jit.RGraph({
//Where to append the visualization
injectInto: 'document_vis_'+document_id,
//Optional: create a background canvas that plots
//concentric circles.
background: {
CanvasStyles: {
//Colour of the background circles
strokeStyle: '#C5BE94'
}
},
//Add navigation capabilities:
//zooming by scrolling and panning.
Navigation: {
enable: true,
panning: true,
zooming: 10
},
//Set Node and Edge styles.
Node: {
//Colour of the actual nodes
color: '#660000'
},
Edge: {
//Color of lines between nodes
color: '#660000',
lineWidth:1.5
},
onBeforeCompute: function(node){
Log.write("Centering " + node.name + "...");
},
//Add the name of the node in the correponding label
//and a click handler to move the graph.
//This method is called once, on label creation.
onCreateLabel: function(domElement, node){
domElement.innerHTML = node.name;
domElement.onclick = function(){
doc_rgraph[document_id].onClick(node.id, {
onComplete: function() {
Log.write("Done");
}
});
};
},
//Change some label dom properties.
//This method is called each time a label is plotted.
onPlaceLabel: function(domElement, node){
var style = domElement.style;
style.display = '';
style.cursor = 'pointer';
if (node._depth == 0) {
style.fontSize = "0.8em";
//Text colour of ring 1 nodes
style.color = "#000000";
style.backgroundColor = "#F05322";
style.padding = "1px 3px";
} else if (node._depth == 1) {
style.fontSize = "0.8em";
//Text colour of ring 1 nodes
style.color = "#FFFFFF";
style.backgroundColor = "#164557";
style.padding = "1px 3px";
} else if(node._depth == 2){
style.fontSize = "0.7em";
//Text colour of ring 2 nodes
style.color = "#333333";
style.backgroundColor = "#CAC399";
} else {
style.display = 'none';
}
var left = parseInt(style.left);
var w = domElement.offsetWidth;
style.left = (left - w / 2) + 'px';
},
onComplete: function(){
Log.write("Done");
}
});
//load JSON data
doc_rgraph[document_id].loadJSON(document_data[document_id]);
//trigger small animation
doc_rgraph[document_id].graph.eachNode(function(n) {
var pos = n.getPos();
pos.setc(-200, -200);
});
doc_rgraph[document_id].compute('end');
doc_rgraph[document_id].fx.animate({
modes:['polar'],
duration: 1000
});
//end

Categories