How to make highcharts-ng horizontal bar chart responsive - highcharts

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/

Related

Highcharts | Label width control in bar charts

I am trying to find a way to control width of the x-axis labels container in bar charts in styled mode. I want to have preset values and depending on the preset have labels to take 20, 30, 40, 50% of the graphic. Is there a property for that?
Thank you!
If you want to set labels' width depending on their length and relative to chart width, you can use chart.event.render to achieve that. It will allow you to find the number of characters and set dynamically the percentage width.
var allowChartUpdate = true;
Highcharts.chart('container', {
chart: {
type: 'bar',
styledMode: true,
events: {
render: function() {
if (allowChartUpdate) {
this.xAxis[0].categories.forEach(category => {
if (category.length > 10) {
var dynamicMargin = this.chartWidth * 50 / 100;
allowChartUpdate = false;
this.update({
chart: {
marginLeft: dynamicMargin
}
}, true, true, false);
allowChartUpdate = true;
}
})
}
}
}
},
...
Demo:
https://jsfiddle.net/BlackLabel/59xjq4du/
API Reference:
https://api.highcharts.com/highcharts/chart.events.render

How to center the title text in pie chart highchart?

I am trying to do center align the title text of the pie chart Highchart. Was able to achieve that but on mouse hover, and mouse out the title data doesn't get updated. Anyone can help me with the same.
On MouseHOver trying to do the below mentioned code
point: {
events: {
mouseOver: function() {
let span = '<span style="color:${this.color}" class="dealer-title">${this.y}<br/> <span style="color:#33383e;}" class="text-truncate" title="${this.name}"><b> </b></span></span>';
$('.customTitle')[0].innerHTML = span
}
}
}
}
},
fiddle attached:
https://jsfiddle.net/5sutmqv3/1/
You need to enable useHTML argument in the text method call:
chart: {
type: 'pie',
events: {
load: function() {
...
var text = rend.text("textTexttext", left, top, true).attr({
'text-anchor': 'middle',
align: 'center',
'zIndex': 10
}).addClass('customTitle').add();
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/w5a2jpk7/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#text
It looks like you can't include html tags in the title. If you remove the SPANs it'll display the values.
$('.customTitle')[0].innerHTML = this.y

Angular 6 with chart.js TypeError: item is null

I'm trying to use Chartjs in an Angular application I'm developing.
So upon changing the value of a select menu it's supposed to draw a chart according to the selected value. But I'm getting TypeError: item is null . I've looked everywhere and the solutions I've found did not work.
This the selecting part code :
<mat-form-field>
<mat-select [(ngModel)]="selected" placeholder="Y"
(ngModelChange)="drawBubbleChart($event)">
....
</mat-select>
</mat-form-field>
This is my html code :
<div *ngIf="chart">
<canvas #ctrx >{{ chart }}</canvas>
</div>
my ts code :
#ViewChild('ctrx') private chartRef;
drawBubbleChart(){
let ds = this.prepareData();
let chartID = this.chartRef.nativeElement.getContext("ctrx");
let options = {
title: {
display: true,
text: "Testing what's up"
}, scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: "One"
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: "Two"
}
}]
}
}
console.log("data =>", ds);
if (ds.length !== 0) {
console.log("inside if !== 0");
this.chart = new Chart(chartID,{
type: 'bubble',
datasets: ds,
options: options
});
}
}
I tried let chartID = document.getElementById("ctrx"); but it gives me a TypeError: item is null as well .
How can solve this and draw a chart after selecting an option ??
Make sure to not use *ngIf, it destroys your canvas and the ElementRef. Hide it with CSS.
Also, I use getContext('2d')
<canvas #canvas>{{ chart }}</canvas>
#ViewChild('canvas') canvas: ElementRef;
this.canvas.nativeElement.getContext('2d')

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.

Showing Context Menu on right click of High Chart series

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.

Resources