Showing Context Menu on right click of High Chart series - highcharts

I want to show a context menu on right click of the series plotted in High charts. I am not able to find any option in High charts to do this. Can any one suggest a way to achieve this requirement.

Well it is 2019 and there still isn't a solution for this that comes with the base HighCharts download. I have found a way to manipulate the LEFT click, in order to show a menu of sorts. Now I understand this may not be the best case scenario, but you still have full access to all of the data from the click, and will still be able to do normal drill down functionality etc. You just might have to rework it. This is a TypeScript example, but can easily be replicated to JavaScript with a few edits.
Please excuse the lack of CSS for the menu.
Your functions initialized before the chart. The variable is used to keep the menu from disappearing and is NOT mandatory here.
let callDrillDown = () => {
alert('drill1');
}
let callDrillDown2 = () => {
alert('drill2');
}
let mouseIn: boolean;
This is the bread and butter, during the click, you're pulling the <div> from the HTML and adding an onclick action to it.
plotOptions: {
column: {
events: {
click: (event: any) => {
let contextMenu = document.getElementById('contextMenu');
let contextMenuItem1 = document.getElementById('contextMenuItem1');
let contextMenuItem2 = document.getElementById('contextMenuItem2');
contextMenuItem1.onclick = callDrillDown;
contextMenuItem2.onclick = callDrillDown2;
contextMenu.onmouseenter = () => {
mouseIn = true;
};
contextMenu.onmouseleave = () => {
mouseIn = false;
setTimeout(() => {
if (!mouseIn) {
contextMenu.setAttribute('style', 'display: none');
}
}, 1000);
};
contextMenu.setAttribute('style', 'top: '
+ event.pageY + 'px; left:'
+ event.pageX + 'px;');
}
}
}
}
Inside of the body add the HTML
<div id="contextMenu" style="display: none" class="contextMenu">
<div id="contextMenuItem1">Data</div>
<div id="contextMenuItem2">Data2</div>
</div>
Here is the jsFiddle. Hope this helped.

I did the solution below. Hope it helps.
plotOptions: {
series: {
point: {
events: {
contextmenu: function (e) {
$('#constext-menu-div').css({top: e.chartY, left: e.chartX});
$('#constext-menu-div').show();
console.log(e);
},
click: function(){
$('#constext-menu-div').hide();
}
}
}
}
},
"http://jsfiddle.net/c42Ms/45/"

It is not built-in functionality, but you can use custom-events extention and then catch right click. Last step will be show/hide any div with menu.

Related

Jquery UI drag and drop - dragged item dissapears when dropped only on mobile

I am trying to get drag and drop working properly and on desktop of laptop pc it is fine. However, on a mobile device, when I drag and drop, when dropped, the dragged item dissapears underneath (i think) everything else and I really am unable to work out why.
I have uploaded a page showing the problem to http://mailandthings.co.uk/dam1/
I have tried setting the zindex in the draggable code and that makes no difference
var $dragContainer = $("div.drag-container");
var $dragItem = $("div.drag-item");
$dragItem.draggable({
cursor: "move",
snap: "div.drag-container",
snapMode: "inner",
snapTolerance: 10,
helper: "clone",
handle: "i",
zIndex: 10000
});
$dragContainer.droppable({
drop: function (event, ui) {
var $elem = $(event.toElement);
var obj = {
posX: event.pageX - $dragContainer.offset().left - event.offsetX,
posY: event.pageY - $dragContainer.offset().top - event.offsetY,
data: $elem.data(),
html: $elem.html()
};
addElement(obj);
masterPos.push(obj);
}
});
function addElement(obj) {
var $child = $("<div>");
$child.html("<i>" + obj.html + "</i>").addClass("drop-item drop-item-mobile");
$child.attr("data-type", obj.data.type);
$child.css({
top: obj.posY,
left: obj.posX
});
$dragContainer.append($child);
}
If it using jQuery UI Touch Punch 0.2.3
Does anyone have any ideas?
There was sort of a logistical issue that I found. Based on your code, I could identify the following state / logic:
User drags an item (A, B, C) to the car image to indicate a Dent, Scratch, or Heavy Damage
The Drop Point indicates where the Type of damage is located
When the dragged item is dropped, a new object should be created that indicates the Type and stores the location on the car map
This new object replaces the dragged item and is appended to the container
To expand on this, you have the following code that is the dragged element, for example:
<div class="drag-item ui-draggable" style="">
<i data-type="A" class="ui-draggable-handle">A</i>Dent
</div>
This is important when creating the new object. In your current code, you're requesting data from an object that does not have any data attributes, $elem.data(). Remember that this is the <div> that contains the <i> that has the attribute. So data is null or undefined. You will want to capture the data from the child element: $elem.find("i").data().
Also, since you append all the HTML to your new object, you make a double wrapped element. $child will look like:
<div class="drop-item drop-item-mobile">
<i>
<div class="drag-item ui-draggable" style="">
<i data-type="A" class="ui-draggable-handle">A</i>Dent
</div>
</i>
</div>
I do not think this was your intention. I suspect your intention was to create:
<div class="drop-item drop-item-mobile">
<i>A</i>
</div>
Here is an example of all this: https://jsfiddle.net/Twisty/g6ojp4ro/40/
JavaScript
$(function() {
var theForm = document.forms.form1;
if (!theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
var masterPos = [];
$("#hidpos").val('');
var $dragContainer = $("div.drag-container");
var $dragItem = $("div.drag-item");
$dragItem.draggable({
cursor: "move",
snap: "div.drag-container",
snapMode: "inner",
snapTolerance: 10,
helper: "clone",
handle: "i",
zIndex: 10000
});
$dragContainer.droppable({
drop: function(event, ui) {
var $elem = ui.helper;
var type = ui.helper.find("i").data("type");
var $child = $("<div>", {
class: "drop-item drop-item-mobile"
}).data("type", type);
$("<i>").html(type).appendTo($child);
$child.appendTo($dragContainer).position({
of: event
});
var obj = {
posX: $child.offset().top,
posY: $child.offset().left,
data: $child.data(),
html: $child.prop("outerHTML")
};
masterPos.push(obj);
}
});
$("map").imageMapResize();
// Save button click
$('#form1').submit(function(e) { //$("#btnsave").click(function () {
if (masterPos.length == 0) {
$("#spnintro").html("Oops!");
$("#spninfo").html("No position data was entered");
$("#dvinfo").fadeTo(5000, 500).slideUp(500, function() {});
} else {
$("#hidpos").val(JSON.stringify(masterPos));
$.ajax({
url: '/handlers/savepositions.ashx',
type: 'POST',
data: new FormData(this),
processData: false,
contentType: false,
success: function(data) {
$("#spnintro").html("Success!");
$("#spninfo").html("Position data has been saved");
$("#dvinfo").fadeTo(5000, 500).slideUp(500, function() {});
}
});
}
e.preventDefault();
});
});
Tested with Mobile client at: https://jsfiddle.net/Twisty/g6ojp4ro/40/show/ and is working as expected.
Hope that helps.

jQuery UI Autocomplete perform search on button click issues

I have a working UI Auto complete with jQuery. I wanted to change the way it worked. Instead of a new browser tab opening with the user selects a value from the list I wanted the user to first pick a value then click a search button to trigger the event.
It works but if you perform a search and then a second search it will trigger the previous URL and new URL at the same time. Also if you perform a search then click the search button without typing anything into the search input it triggers the previous search. Weird right? I'll add my code but I think a codepen example will help clarify what I mean.
The other issue I was having is I am trying to set up a custom alert if the value typed is not in the array but I get the invalid error message no matter what I type. I added that as well in the code. It is one of the if statements.
JS
var mySource = [
{
value: "Google",
url: "http://www.google.com"
},
{
value: "Yahoo",
url: "https://www.yahoo.com"
},
{
value: "Hotmail",
url: "https://hotmail.com"
},
{
value: "Reddit",
url: "https://www.reddit.com"
}
];
//Logic for ui-autocomplete
$(document).ready(function() {
$("input.autocomplete").autocomplete({
minLength: 2,
source: function(req, resp) {
var q = req.term;
var myResponse = [];
$.each(mySource, function(key, item) {
if (item.value.toLowerCase().indexOf(q) === 0) {
myResponse.push(item);
}
if (item.value.toUpperCase().indexOf(q) === 0) {
myResponse.push(item);
}
//Add if statement here to determine if what the user inputs is in the
// array
//and if not in the array give an error to #textAlert.
//Example
if (item.value.indexOf(q) != myResponse) {
$('#alertText').text("Invalid Search");
} else {
return false;
}
});
resp(myResponse);
},
select: function(event, ui) {
$('#appSearchBtn').one("click", function() {
window.open(ui.item.url);
$('#appsearch').val('');
return false;
});
}
});
});
//Input and ui text clears when clicked into
$(document).ready(function() {
var input = document.querySelector('#appsearch');
var ui = document.querySelector(".ui-helper-hidden-accessible");
input.onclick = function() {
input.value = '';
ui.textContent = '';
};
});
HTML
<p id="alertText"></p>
<div class="input-group">
<input type="text" id="appsearch" class="form-control autocomplete" placeholder="Application Search" />
<span class="input-group-btn">
<button class="btn btn-primary inputBtn" id="appSearchBtn" type="button">Search</button>
</span>
</div>
Here is a Code pen https://codepen.io/FrontN_Dev/pen/MEmMRz so you can see how it works. I also added how it should work and what the bugs are.
9/29/17 #0732
I resolved the issue with the event firing the same URL over and over but I still need help with the custom invalid search message that appears for every search even if the value is in the array.

How to make highcharts-ng horizontal bar chart responsive

I have worked with several type of highcharts-ng, and the horizontal bar chart seems to be special - I had hard time to make the chart width adapt to the screen size. To illustrate the problem, I created a jsfiddle. By default, it has a fixed size of 600px, instead of the whole available width. I tried various ways to adjust the width accordingly, but none of them works perfectly. One way is to use $window.onresize as shown in the code, but it doesn't work. However, if I put a Resize button which runs the same code, it does work. Why?
HTML:
<div ng-app="myapp">
<div ng-controller="myctrl">
<input ng-model="chart.title.text">
<button ng-click="resize()">Resize</button>
<highchart id="chart1" series="chart.series" title="chart.title" options="chart.options"></highchart>
</div>
</div>
JS:
var myapp = angular.module('myapp', ["highcharts-ng"]);
myapp.controller('myctrl', function($scope, $window) {
$scope.resize = function() {
$scope.chart.options.chart.width = $window.innerWidth;
}
$window.onresize = function() {
$scope.chart.options.chart.width = $window.innerWidth;
}
$scope.chart = {
options: {
chart: {
type: 'bar'
}
},
series: [{
data: [10, 15, 12, 8, 7]
}],
title: {
text: 'Hello'
}
}
});
this in window.onresize refers to the global window object which does not have the chart config object in opposite to $scope.toggleWidth in which this refers to the scope with the chart.
Chart config can be accessed like this:
$window.onresize = function () {
var chart = $scope.chart.options.chart;
if (chart.width === 400) {
chart.width = 800
} else {
chart.width = 400
}
$scope.$digest();
};
onresize you need to manually call $digest().
example: http://jsfiddle.net/wscqtdvo/

Ember.js + JQuery-UI Tooltip - Tooltip does not reflect the model / controller changes

Context
I have a small Ember app, which, amongst other things, displays a number of connected users and, when hovering an element of the page, their names as a list.
All in all, it works quite well. The applications pulls data from a REST endpoint every two minutes, as the backend didn't allow for pushing data.
The contents of the tooltip are computed in the Controller, with a function that basically concatenate strings in various ways according to the context. Then it's bound to a data attribute of the <img> the tooltip is created on. When the View is ready and didInsertElement is fired, the tooltip is generated (if needs be) based on this data-bindattr value.
Question
When new data is pulled from the backend, everything is updated accordingly, except the tooltip content. (When browsing the page's DOM, the data-bindattr value is updated too.)
What could cause the tooltip to not refresh? Is it a case of JQuery-UI not calculating it again?
Some code
Refreshing code in the app's controller:
Monitor.ApplicationController = Ember.ArrayController.extend({
itemController: 'process',
sortProperties: ['name'],
sortAscending: true,
intervalId: undefined,
startRefreshing: function() {
var self = this;
if (self.get('intervalId')) {
return;
}
self.set( 'intervalId', setInterval(function() {
self.store.find('process');
}, 120000 ));
}
});
View: Process.hbs
<div {{bind-attr class=":inline inactive:inactive"}}>
<img {{bind-attr src=icon}} {{bind-attr data-caption=contentText}} class="caption" />
<div class="counter">{{nbUsers}}</div>
</div>
View: ProcessView
Monitor.ProcessView = Ember.View.extend({
// (...) Various stuff.
didInsertElement: function() {
this.updateTooltip();
},
updateTooltip: function() {
console.log('Inside updateTooltip!');
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
this.$().tooltip({
items: '.caption',
tooltipClass: 'tooltip',
content: function() {
return $(this).data('caption');
},
position: {
my: 'left+15px center',
at: 'right center',
collision: 'flip'
},
show: false,
hide: false
});
}.observes('controller.inactive', 'controller.contentText')
});
Controller: ProcessController
Monitor.ProcessController = Ember.ObjectController.extend({
contentText: function() {
var tooltipContent = '';
this.get('containers').forEach(function(container) {
// Do a lot of things to tooltipContent involving:
// container.get('name')
// container.get('text')
// container.get('size')
// container.get('nbUsers')
// The data-bindattr value refreshes correctly so I cut this out for readability.
return tooltipContent;
}.property('name', 'containers.#each')
});
Edit 1:
Replaced 'containers.#each' by 'contentText' in the observer and added logging.
Here's what I think is happening:
Your tooltip library isn't observing the data-caption attribute. Meaning, when you update the attribute, you have to explicitly tell the library to update the tooltip as well. So although your attribute is updating just fine, the tooltip library isn't actually watching for those updates.
This can be remedied by calling updateTooltip, which you do, in didInsertElement. However, didInsertElement only fires once, when the element is first inserted. It's not called when the content changes.
Those two things combined are, I think, causing your problem. I think that all you need to do is have updateTooltip also observe the controller.contextText property. Then it should be called when the text updates.
So it turns out my codes declares and initialize a tooltip, but once it's done, you can't change the content the same way. Plus it adds unneeded computing anyway.
Thanks to #GJK's answer and that question, I found out what was happening. Turns out you need to set the content of the tooltip to refresh it, not recreate it.
Here is the working code for Ember integration:
Monitor.ProcessView = Ember.View.extend({
// Other stuff
didInsertElement: function() {
this.initTooltip();
},
initTooltip: function() {
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
this.$().tooltip({
items: '.caption',
tooltipClass: 'tooltip',
content: function() {
return $(this).data('caption');
},
position: {
my: 'left+15px center',
at: 'right center',
collision: 'flip'
},
show: false,
hide: false
});
},
updateTooltip: function() {
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
content = this.get('controller').get('contentText');
this.$().tooltip("option", "content", content);
}.observes('controller.contentText')
});
As an added bonus, you can avoid using the data attribute as a buffer now, although I'm not sure why.

jQuery UI Tooltip delayed loading

When hovering over a link, I'd like to wait at least a second before showing a tooltip with dynamically loaded tooltip.
What I've created is the follow jQuery Code:
$(document).ready(function () {
$("div#galleries ul li:not(.active) a").tooltip({
items: "a",
show: { delay: 1000 },
content: 'Loading preview...',
open: function (event, ui) {
previewGallery(event, ui, $(this));
}
});
});
function previewGallery(event, ui, aLinkElement) {
event.preventDefault();
ui.tooltip.load("http://www.someurl.com/Preview.aspx #preview");
}
Which seemed to work pretty fine, you can see it here:
http://fotos.amon.cc/ (simply hover over the list of galleries)
But I didn't realize at the beginning, that the loading of preview text happens immediately when hovering over the link. So if you quickly hover over all the links, you'll set up several requests:
From the users point of view (without knowing that requests are fired) it looks already the way I want, but how to only start loading the preview, when tooltip is actually showing up?
Thanks,
Dominik
What I did in the end was to use window.setTimeout and window.clearTimeout:
var galleryToolTipTimer = null;
var previewElement = null;
$(document).ready(function () {
$("div#photos div a img").tooltip();
$("div#galleries ul li:not(.active) a")
.tooltip({ items: "a", content: 'Loading preview...', disabled: true, open: function (event, ui) { previewElement.appendTo(ui.tooltip.empty()); } })
.mouseover(function (e) {
if (galleryToolTipTimer != null) { window.clearTimeout(galleryToolTipTimer); }
var aLinkObject = $(this);
galleryToolTipTimer = window.setTimeout(function () { previewGallery(aLinkObject); }, 500);
}).mouseleave(function (e) {
window.clearTimeout(galleryToolTipTimer);
$(this).tooltip("option", { disabled: true });
});
});
function previewGallery(aLinkElement) {
previewElement = $("<div/>").load(aLinkElement.closest("div").data("galleryPreview") + "/" + aLinkElement.data("path") + " #preview", function () {
aLinkElement.tooltip("open");
});
}
Works at least the way I want.
To see it in action, simply navigate to http://fotos.amon.cc/ and hover over one of the gallery links on the left for a preview:

Resources