PDA

View Full Version : Prevent default on chart context menu not working



leejwright
23 Jun 2015, 9:04 AM
Hi all,

I've added a context menu to a chart segment but for some reason I am unable to prevent the default browser menu from also appearing.

I define my menu as this:




Ext.define('HistoryWorkSheet.view.ChartContextMenu', {
extend: 'Ext.menu.Menu',
config: {
productID: '',
productLevelInput: '',
parentPanelID: '',
filters: {}
},
constructor: function (config) {
this.initConfig(config); //mixes incoming config with pre-defined config
this.callParent(arguments);
},
preventDefault: true,
alias: 'widget.chartcontextmenu',

items: [],
showItem: function (item, position) {
},
showMenu: function (level, id, position) {
var me = this;
me.showAt(position);
}
,
refreshChart: function (level, id) {
alert('refresh ' + level);
}
});


and when I add my series I do this...




newSeries = {
type: me.chartType,
xField: 'product',
yField: [],
stacked: me.stacked,
preventDefault: true,
style: {
stroke: '#666666',
fillOpacity: 0.8
},
listeners: {

itemmousedown: function (item, e) {
e.stopEvent();
e.preventDefault();

var click = {0: 'left', 1: 'middle', 2: 'right'};

if (click[e.button] == 'right') {
var position = e.getXY();
... etc ...


for some reason the stopEvent and preventDefault are failing.
Or maybe there's another event firing that I need to catch?

Many thanks to anyone that has ideas on this.

Also maybe there's an easier way to add a context menu to a chart segment. This seems more difficult than it should be

Lee

tristan.lee
23 Jun 2015, 1:43 PM
itemmousedown is not a browser event for the context menu. contextmenu is the browser event for handling that.

What component are you setting the itemmousedown listener to?

leejwright
24 Jun 2015, 6:43 AM
I have it on a series for a chart.




newSeries = { type: me.chartType, xField: 'product', yField: [], stacked: me.stacked, preventDefault: true, style: { stroke: '#666666', fillOpacity: 0.8 }, listeners: { itemmousedown: function (item, e) { e.stopEvent(); e.preventDefault();


Basically I am dynamically adding series to various chart types. I need a context menu for any given segment of a chart. Let me know if there's an easier way of doing this.


The listener is added to the series and the series is added to the chart.

Thanks

Lee

tristan.lee
26 Jun 2015, 6:05 AM
I don't think that itemmousedown is going to work because you aren't going to be able to distinguish between which button was clicked. What I've done in this example is added a contextmenu listener to the Ext.chart.Chart element, delegating to element with a chart-sprite class (which I add to each of the surface items). This way, the menu is only display when you right-click on one of the data points of the chart.

pg1

leejwright
26 Jun 2015, 6:43 AM
Thanks Tristan,that certainly prevents the browser menu from appearing. However, when the click event is fired in the contextmenu how do I determine which segment was selected?I have a stacked bar with multiple segments and I want the menu actions to only apply to a given segment.Your help is greatly appreciated!Lee

tristan.lee
26 Jun 2015, 12:08 PM
Check out the fiddle below. I used a stacked bar chart and continued with the same contextmenu listener. Based on the target element of the mouse click, I check to see if the XY of that element is a valid item for the series. If the item is valid, I stop the event and show the menu.

At this point, item contains a lot of information that should have what you're looking for.

http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.chart.series.Series-method-getItemForPoint

phs

leejwright
30 Jun 2015, 10:59 AM
Thanks for the reply...it very nearly works. However, it only works for the first item on the chart. e.g. If there are 5 bars on the chart the context menu only works for the first bar :-( It seems like there should be and easier way... Thanks Lee

leejwright
30 Jun 2015, 11:29 AM
So I did manage to get it working with this:




listeners: {
render: function (cmp) {
cmp.el.on('contextmenu', function (evt, t) {
var x = evt.browserEvent.clientX;
var y = evt.browserEvent.clientY;
var me = this;
var chart = cmp.down('chart');
evt.stopEvent();
var
// clicked element
// target = Ext.get(t),

// xy position based on the element (sprite), not the mouse
xy = target.getXY();

console.log(xy);
var series = chart.series.get(0);
console.log(chart.series.length);

var item = series.getItemForPoint(xy[0] - chart.getX(), xy[1] - chart.getY());
if (item) {
createCtxMenu(item, x, y);
}
});
}
}


Its a little ugly and confusing but seems to work for stacked charts etc.
I have my charts within a panel that is dynamically added to the view. ie.A user can add/remove/resize charts and change the series/y axis etc on-the-fly.

Thanks again for the help...without the hints I would have never got it working.

tristan.lee
2 Jul 2015, 8:10 AM
Thanks for providing your solution.

harryBundles
10 Aug 2017, 4:09 AM
This is still an issue and not working for ExtJS 6.x

This answer doesn't seem to work and fails getting sprite items. I can disable the content menu on the empty space on the chart but right clicking the bars still shows the browser context menu and I have to hold ALT or long hold the mouse button to see my menu (it's z-index is lower than the browser's contextmenu)

Any ideas?