Highstock Angular value in legend - highcharts

I'm looking for alternatives for the plug In values in legend.
The plug in uses jQuery and I'm running a Angular 5 application.
Has someone created a solution for that before?
labelFormat: '<span style="color:{color}">{name}</span>: <b>{point.y:.2f} USD</b> ({point.change:.2f}%)<br/>'
Here is a sample of Hicharts using jQuery to access the chart container and display the series value on legend.

To get rid of jquery you can replace jquery .bind method with js addEventListener on chart.container. Next, follow highcharts-angular documentation and create your own wrapper for this plugin. Check demo posted below.
Value-in-legend.js plugin:
(function(factory) {
if (typeof module === "object" && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
})(function(Highcharts) {
Highcharts.Series.prototype.point = {}; // The active point
Highcharts.Chart.prototype.callbacks.push(function(chart) {
chart.container.addEventListener("mousemove", function() {
var legendOptions = chart.legend.options,
hoverPoints = chart.hoverPoints;
// Return when legend is disabled (#4)
if (legendOptions.enabled === false) {
return;
}
if (!hoverPoints && chart.hoverPoint) {
hoverPoints = [chart.hoverPoint];
}
if (hoverPoints) {
Highcharts.each(hoverPoints, function(point) {
point.series.point = point;
});
Highcharts.each(chart.legend.allItems, function(item) {
item.legendItem.attr({
text: legendOptions.labelFormat
? Highcharts.format(legendOptions.labelFormat, item)
: legendOptions.labelFormatter.call(item)
});
});
chart.legend.render();
}
});
});
// Hide the tooltip but allow the crosshair
Highcharts.Tooltip.prototype.defaultFormatter = function() {
return false;
};
});
Next, initialize it in your component:
require("./path-to-your-file/value-in-legend")(Highcharts);
Demo:
https://codesandbox.io/s/j2j7wxwv7y

Related

highcharts - save chart button of stock tool chart does not save currently selected RangeSelector

Can functionality described here: save chart button of stock tool chart not working in highcharts save also currently selected RangeSelector?
The simplest solution seems to be to overwrite the default saveChart button functionality. In the below example saving all indicators and x-axis extremes should work correctly.
const savedOptions = localStorage.getItem(['highcharts-chart']);
const baseOptions = {...};
H.stockChart('container', H.merge({
navigation: {
bindings: {
saveChart: {
init: function(button) {
var navigation = this,
chart = navigation.chart,
annotations = [],
series = [],
xAxis = [],
yAxis = [];
annotations = chart.annotations.map(annotation => annotation.userOptions);
chart.series.forEach(s => {
if (!s.options.isInternal) {
series.push(s.userOptions);
}
});
chart.yAxis.forEach(axis => {
if (axis.userOptions.className !== 'highcharts-navigator-yaxis') {
yAxis.push(axis.userOptions);
}
});
chart.xAxis.forEach((axis, index) => {
if (!axis.options.isInternal) {
xAxis.push(axis.userOptions);
xAxis[index].min = axis.userMin;
xAxis[index].max = axis.userMax;
}
});
H.win.localStorage.setItem('highcharts-chart', JSON.stringify({
series,
annotations,
yAxis,
xAxis
}));
H.fireEvent(this, 'deselectButton', {
button
});
}
}
}
}
}, savedOptions ? JSON.parse(savedOptions) : baseOptions));
Live demo: https://jsfiddle.net/BlackLabel/r92b475e/
API Reference: https://api.highcharts.com/highstock/navigation.bindings.saveChart

Collapse Highcharts Organization Chart

I'm using Highcharts to create organization charts as in provided example : https://jsfiddle.net/vegaelce/7rb6esqt/
Is it possible to add a "collapse" feature as in the Google organization chart ? In the following example https://jsfiddle.net/vegaelce/kb2gted4 when you double clic on "Mike" or "Jim" cell, it collapse all the cells above. I need to reproduce an equivalent mode with Highcharts, do you have an idea to do that ? (in Google API, the collapse mode is enabled via
allowCollapse:true
Thanks
There is no such built-in functionality in Highcharts, but you can add it by using click event and show/hide methods. Example:
plotOptions: {
series: {
point: {
events: {
click: function() {
const operateChildren = (point, operation) => {
point.linksFrom.forEach(link => {
link.graphic[operation]();
link.toNode.graphic[operation]();
operateChildren(link.toNode, operation);
});
};
if (this.linksFrom && this.linksFrom[0]) {
if (this.linksFrom[0].graphic.visibility === 'hidden') {
operateChildren(this, 'show');
} else {
operateChildren(this, 'hide');
}
}
}
}
}
}
},
tooltip: {
formatter: function(tooltip) {
if (this.point.graphic.visibility !== 'hidden') {
return tooltip.defaultFormatter.call(this, tooltip);
}
return false;
}
}
Live demo: https://jsfiddle.net/BlackLabel/dp03gq6a/
API Reference:
https://api.highcharts.com/class-reference/Highcharts.SVGElement#show
https://api.highcharts.com/class-reference/Highcharts.SVGElement#hide

Change zIndex in HighChart

using Highchart, how can we change the zIndex for a line according to its state, or dynamically from a click event ?
I tried :
plotOptions: {
series: {
states: {
select: {
lineWidth: 2,
zIndex:10
}
},
with : this.setState(this.state === 'select' ? '' : 'select'); in the Click event but it doesn't work.
Alright, it's definitely not pretty, but I couldn't find a way to actually set the zIndex, so I had to do some maneuvering to fake it and bring each series to the front in a certain order. Here's the snippet to include:
Highcharts.Series.prototype.setState = (function (func) {
return function () {
if (arguments.length>0){
if (arguments[0] !== ''){
if (typeof this.options.states[arguments[0]]['zIndex'] !== 'undefined'){
this.options.oldZIndex = this.group.zIndex;
this.group.zIndex = this.options.states[arguments[0]]['zIndex'];
}
}else{
if (typeof this.options['oldZIndex'] !== "undefined"){
this.group.zIndex = this.options['oldZIndex'];
}
}
var order = [], i = 0;
$.each(this.chart.series, function(){
order.push({id:i,zIndex:this.group.zIndex,me:this});
i++;
});
order.sort(function(a,b){return (a.zIndex>b.zIndex) ? 1 : -1;});
$.each(order, function(){
this.me.group.toFront();
});
func.apply(this, arguments);
}
};
} (Highcharts.Series.prototype.setState));
And here's the JSFiddle demonstrating:
http://jsfiddle.net/G9d9H/9/
Let me know if that's what you needed.
I think a better solution is to set the series.group.toFront() method on click (I prefer to use it on mouseover)
plotOptions: {
series: {
events: {
click: function () {
this.group.toFront();//bring series to front when hovered over
}
}
}
}

How to validate select with JQuery.Validate while using JQueryMobile

I'm just exploring the Validate plug-in for JQuery. During implementing in my webapp made with JQueryMobile I stumbled over the fact that validating such an element is not so simple like usual input-elements.
So the Question is: How to enable validation for select?
The trick consists out of two parts:
Validate is by default ignoring :hidden. But that's what JQM does with an <select>: hide it and placing a div-span-wrapper on top. Solution is to redefine the ignore-selector:
{ignore: ":hidden:not(select)"}
To inform the user about the invalid field you have to show the error right on the wrapper:
$(error.element).closest('.ui-select').attr("title", error.message).addClass("invalidInput")
And now in an working example:
$.validator.setDefaults({
debug: true,
ignore: ":hidden:not(select)",
submitHandler: function() { alert("submitted!"); },
showErrors: function(map, list) {
$(this.currentElements).each(function() {
if(this.nodeName == "SELECT") {
$(this).closest('.ui-select').removeAttr("title").removeClass("invalidInput");
return true;
}
$(this).removeAttr("title").removeClass("invalidInput");
});
$.each(list, function(index, error) {
if(error.element.nodeName == "SELECT") {
$(error.element).closest('.ui-select').attr("title", error.message).addClass("invalidInput");
return true;
}
$(error.element).attr("title", error.message).addClass("invalidInput");
});
}
});
$('div[data-role="page"]').bind('pageinit', function(event) {
var rules = {};
$('input:not(:button)').each(function() {
rules[this.name] = {required:true};
});
$('#fzgherst').each(function() {
// revalidates the select when changed, other elements gets revalidatet onblur
$(this).on('change', function() {$(this).valid();});
rules[this.name] = {required:true};
});
$("form").validate({
rules: rules
});
});
That's all folks!

AngularJS - jQuery UI - binding issue

I am currently porting a large application over to a HTML5 based web app - I have started building the app in AngularJS and enjoying the power of the AngularJS framework - I have one issue standing in my way currently:
I have a directive that gives me a jQuery Datepicker however the binding to the model does not seem to be working.
http://jsfiddle.net/9BRNf/
I am probably misunderstanding the way directives work and would like to see if I can patch this part of my understanding of the framework. I have gone through loads of examples (including the angularui project on github but still not making sense of why the binding is not happening)
any assistance will be greatly appreciated.
For those Googling this issue (as I was), a simpler way of tying in the jQuery UI datepicker with Angular is to do this...
$.datepicker.setDefaults({
// When a date is selected from the picker
onSelect: function(newValue) {
if (window.angular && angular.element)
// Update the angular model
angular.element(this).controller("ngModel").$setViewValue(newValue);
}
});
Just place it prior to your .datepicker() initialisation code.
(Taken from another answer I posted here: https://stackoverflow.com/a/17206242/195835)
First off, it's great that you are using angularjs, its a sweet framework. An offshoot project was started awhile back to deal with things like wrapping jquery-ui and creating ui modules.
Below is link to Peter Bacon Darwin's implementation.
https://github.com/angular-ui/angular-ui/tree/master/modules/directives/date
--dan
The angular-ui datepicker wasn't working with Angular 1.0.0, so I rewrote it. My fork gives you the ability to set how the date is formatted inside the input and how it gets saved back to the model.
Code: https://gist.github.com/2967979
jsFiddle: http://jsfiddle.net/m8L8Y/8/ (It's missing jquery-ui styles but works just the same)
// Code inspired by angular-ui https://github.com/angular-ui/angular-ui/blob/master/modules/directives/date/src/date.js
/*
Features:
* via the ui-date attribute:
* Ability to say how model is parsed into a date object
* Ability to say how input's value is parsed into a date object
* Ability to say how a date object is saved to the model
* Ability to say how a date object is displayed in the input
* via the ui-date-picker attribute
* Ability to directly configure the jQuery-ui datepicker
*/
angular.module('ui.directives', [])
.directive('uiDate', function () {
return {
require: '?ngModel',
//scope: {},
link: function ($scope, element, attrs, ngModel) {
// Date Handling Functions
var dateHandler = $.extend({ model: {}, view: {} }, $scope.$eval(attrs.uiDate));
// This will attempt to use preferredParser to parse a date.
function defaultDateParse(date, preferredParser) {
if (!preferredParser)
return new Date(date);
return preferredParser(date);
}
// This will attempt to use preferredFormatter to format a date, otherwise use 'mm/dd/yy'.
function defaultDateFormatter(date, preferredFormatter) {
if (!preferredFormatter)
preferredFormatter = "mm/dd/yy";
if (typeof preferredFormatter == 'string')
return $.datepicker.formatDate(preferredFormatter, date);
else
return preferredFormatter(date);
}
// Functions for Parsing & Formatting on the Model & View
function parseDateFromModel(date) {
return defaultDateParse(date, dateHandler.model.parse)
}
function parseDateFromView(date) {
return defaultDateParse(date, dateHandler.view.parse)
}
function formatDateForModel(date) {
return defaultDateFormatter(date, dateHandler.model.format)
}
function formatDateForView(date) {
return defaultDateFormatter(date, dateHandler.view.format)
}
var defaultDateViewFormat = (
typeof dateHandler.view.format == 'string'
? dateHandler.view.format
: 'mm/dd/yy'
)
// Initialize the jQuery-ui datePicker
var datePickerSettings = $.extend({ dateFormat: defaultDateViewFormat }, $scope.$eval(attrs.uiDatePicker))
var oldOnSelect = datePickerSettings.onSelect;
datePickerSettings.onSelect = function (dateVal) {
$scope.$apply(function () {
element.focus().val(dateVal);
updateModel();
})
if (oldOnSelect)
oldOnSelect.apply(this, arguments)
}
element.datepicker(datePickerSettings);
if (ngModel) {
// Specify how UI should be updated
ngModel.$render = function () {
element.val(ngModel.$viewValue || '');
};
// Listen for change events to enable binding
element.bind('blur keyup change', function () {
$scope.$apply(updateModel);
});
// Write data to the model
function updateModel() {
ngModel.$setViewValue(element.val());
}
// Convert the model into a string value
ngModel.$formatters.push(function (v) {
if (v != "" && v != null)
return formatDateForView(parseDateFromModel(v));
return null;
});
// Convert the string value into the model
ngModel.$parsers.push(function (v) {
if (v != "" && v != null)
return formatDateForModel(parseDateFromView(v))
return null;
});
}
}
};
})
Similar to praveepd (using their's as a base), but this will include deep model selection.
http://jsfiddle.net/c8PMa/
var myApp = angular.module('myApp', ['myApp.directives']);
function MainCtrl($scope) {
$scope.deepValue = {
fromDate: null,
toDate: null
}
}
angular.module('myApp.directives', [])
.directive('myDatepicker', function() {
return function(scope, element, attrs) {
element.datepicker({
changeYear : true,
changeMonth : true,
appendText : '(yyyy-mm-dd)',
dateFormat : 'yy-mm-dd',
onSelect: function(dateText) {
var mdlAttr = $(this).attr('ng-model').split(".");
if (mdlAttr.length > 1) {
var objAttr = mdlAttr[mdlAttr.length-1];
var s = scope[mdlAttr[0]];
for (var i=0; i < mdlAttr.length-2; i++) {
s = s[mdlAttr[i]];
}
s[objAttr] = dateText;
} else {
scope[mdlAttr[0]] = dateText;
}
scope.$apply();
}
});
}
});​
http://jsfiddle.net/9BRNf/74/ here is the solution :)
code:
var myApp = angular.module('myApp', ['myApp.directives']);
function MainCtrl() {
}
angular.module('myApp.directives', [])
.directive('myDatepicker', function() {
return {
require: '?ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
element.datepicker({
changeYear : true,
changeMonth : true,
appendText : '(yyyy-mm-dd)',
dateFormat : 'yy-mm-dd',
onSelect: function(date) {
ngModelCtrl.$setViewValue(date);
scope.$apply();
}
});
}
}
});
Old question, but this was the first hit for me in google search for this. Anyways, I used dual datepickers working together using jquery and angular directives, so I thought I'd share to help anyone else trying to do this.
Here's the plunker for it:
http://plnkr.co/edit/veEmtCM3ZnQAhGTn5EGy?p=preview
Basically it initializes the form using json. The datepickers have their own conditions like mindate's, etc. The first select box if true = disables sundays on the calendars, else enables them.
The viewmodel get's updates when 'done' is clicked. Here's a bit of the code for one of the datepickers:
Html:
<input id="StartDate" data-ng-model="viewModel.startdate" date-from />
Directive:
app.directive('dateFrom', function() {
return function (scope, element, attrs) {
var doDate = $('#EndDate');
element.datepicker({
dateFormat: 'dd-M-yy', showOtherMonths: true,
selectOtherMonths: true, minDate: '0',
beforeShowDay: function (date) {
var day = date.getDay();
console.log(scope.nosunday);
if (scope.nosunday === 'true') return [(day !== 0), '']; // disable sundays
else return [true, ''];
},
onSelect: function (selectedDate) {
var toDate = new Date(element.datepicker("getDate"));
toDate.setDate(toDate.getDate() + 1);
doDate.datepicker('option', 'minDate', toDate);
scope.viewModel.startdate = selectedDate;
scope.viewModel.enddate = doDate.val();
}
});
}
})
Feel free to optimize it further. Post a comment with a forked plunk if you do :)
I had just trimmed the code, have a look at this: http://jsfiddle.net/YU5mV/
HTML
<input id="date1" value="1/1/1980" ng-model="fromDate" my-datepicker />
<input id="date2" value="1/1/1980" ng-model="toDate" my-datepicker />
JavaScript
angular.module('myApp.directives', [])
.directive('myDatepicker', function() {
return function(scope, element, attrs) {
element.datepicker({
changeYear : true,
changeMonth : true,
appendText : '(yyyy-mm-dd)',
dateFormat : 'yy-mm-dd',
onSelect: function(dateText) {
var mdlAttr = $(this).attr('ng-model');
scope[mdlAttr] = dateText;
scope.$apply();
}
});
}
});

Resources