Highchart gantt : https://www.highcharts.com/docs/gantt/getting-started-gantt
I want to change this dropdown btn icon to right of text label.
How to edit it?
Jsfiddle : https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/gantt/demo/project-management
This is not possible from the API but you can achieve that by wrapping the renderLabel function.
(function(H) {
const {
addEvent,
isNumber,
isObject,
pick
} = H,
onTickHoverExit = function(label, options) {
var css = isObject(options.style) ? options.style : {};
label.removeClass('highcharts-treegrid-node-active');
if (!label.renderer.styledMode) {
label.css({
textDecoration: css.textDecoration
});
}
},
onTickHover = function(label) {
label.addClass('highcharts-treegrid-node-active');
if (!label.renderer.styledMode) {
label.css({
textDecoration: 'underline'
});
}
},
renderLabelIcon = function(tick, params) {
var treeGrid = tick.treeGrid,
isNew = !treeGrid.labelIcon,
renderer = params.renderer,
labelBox = params.xy,
options = params.options,
width = options.width || 0,
height = options.height || 0,
iconCenter = {
x: labelBox.x + tick.label.getBBox().width + width,
y: labelBox.y - (height / 2)
},
rotation = params.collapsed ? 90 : 180,
shouldRender = params.show && isNumber(iconCenter.y);
var icon = treeGrid.labelIcon;
if (!icon) {
treeGrid.labelIcon = icon = renderer
.path(renderer.symbols['circle'](options.x || 0, options.y || 0, width, height))
.addClass('highcharts-label-icon')
.add(params.group);
}
// Set the new position, and show or hide
icon[shouldRender ? 'show' : 'hide'](); // #14904, #1338
// Presentational attributes
if (!renderer.styledMode) {
icon
.attr({
cursor: 'pointer',
'fill': pick(params.color, "#666666" /* Palette.neutralColor60 */ ),
'stroke-width': 1,
stroke: options.lineColor,
strokeWidth: options.lineWidth || 0
});
}
// Update the icon positions
icon[isNew ? 'attr' : 'animate']({
translateX: iconCenter.x,
translateY: iconCenter.y,
rotation: rotation
});
};
H.wrap(H.Tick.prototype, 'renderLabel', function(proceed) {
var tick = this,
pos = tick.pos,
axis = tick.axis,
label = tick.label,
mapOfPosToGridNode = axis.treeGrid.mapOfPosToGridNode,
options = axis.options,
labelOptions = pick(tick.options && tick.options.labels, options && options.labels),
symbolOptions = (labelOptions && isObject(labelOptions.symbol, true) ?
labelOptions.symbol : {}),
node = mapOfPosToGridNode && mapOfPosToGridNode[pos],
level = node && node.depth,
isTreeGrid = options.type === 'treegrid',
shouldRender = axis.tickPositions.indexOf(pos) > -1,
prefixClassName = 'highcharts-treegrid-node-',
styledMode = axis.chart.styledMode;
var collapsed,
addClassName,
removeClassName;
if (isTreeGrid && node) {
// Add class name for hierarchical styling.
if (label &&
label.element) {
label.addClass(prefixClassName + 'level-' + level);
}
}
proceed.apply(tick, Array.prototype.slice.call(arguments, 1));
if (isTreeGrid &&
label &&
label.element &&
node &&
node.descendants &&
node.descendants > 0) {
collapsed = axis.treeGrid.isCollapsed(node);
renderLabelIcon(tick, {
color: (!styledMode &&
label.styles &&
label.styles.color ||
''),
collapsed: collapsed,
group: label.parentGroup,
options: symbolOptions,
renderer: label.renderer,
show: shouldRender,
xy: label.xy
});
// Add class name for the node.
addClassName = prefixClassName +
(collapsed ? 'collapsed' : 'expanded');
removeClassName = prefixClassName +
(collapsed ? 'expanded' : 'collapsed');
label
.addClass(addClassName)
.removeClass(removeClassName);
if (!styledMode) {
label.css({
cursor: 'pointer'
});
}
// Add events to both label text and icon
[label, tick.treeGrid.labelIcon].forEach(function(object) {
if (object && !object.attachedTreeGridEvents) {
// On hover
addEvent(object.element, 'mouseover', function() {
onTickHover(label);
});
// On hover out
addEvent(object.element, 'mouseout', function() {
onTickHoverExit(label, labelOptions);
});
addEvent(object.element, 'click', function() {
tick.treeGrid.toggleCollapse();
});
object.attachedTreeGridEvents = true;
}
});
}
});
}(Highcharts))
Demo:
https://jsfiddle.net/BlackLabel/k2rb6zgy/
Extending Highcharts:
https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
Related
I'm facing a problem when import Highstock. I'd like to import csv/xml in a highstock graph.
It's work fine but is getting the total of data present in chart. I'd like to export CVS/XML only visible/selected range.
Here what I found in Highstock forum:
https://www.highcharts.com/forum/viewtopic.php?f=12&t=41056
jsfiddle: jsfiddle example
The example in JSFiddle works but is getting an number in Unix Timestemp.
var defined = Highcharts.defined,
each = Highcharts.each,
pick = Highcharts.pick,
win = Highcharts.win,
doc = win.document,
seriesTypes = Highcharts.seriesTypes,
downloadAttrSupported = doc.createElement('a').download !== undefined;
Highcharts.Chart.prototype.getDataRows = function (multiLevelHeaders) {
var time = this.time,
csvOptions = (this.options.exporting && this.options.exporting.csv) ||
{},
xAxis,
xAxes = this.xAxis,
rows = {},
rowArr = [],
dataRows,
topLevelColumnTitles = [],
columnTitles = [],
columnTitleObj,
i,
x,
xTitle,
// Options
columnHeaderFormatter = function (item, key, keyLength) {
if (csvOptions.columnHeaderFormatter) {
var s = csvOptions.columnHeaderFormatter(item, key, keyLength);
if (s !== false) {
return s;
}
}
if (!item) {
return 'Category';
}
if (item instanceof Highcharts.Axis) {
return (item.options.title && item.options.title.text) ||
(item.isDatetimeAxis ? 'DateTime' : 'Category');
}
if (multiLevelHeaders) {
return {
columnTitle: keyLength > 1 ? key : item.name,
topLevelColumnTitle: item.name
};
}
return item.name + (keyLength > 1 ? ' (' + key + ')' : '');
},
xAxisIndices = [];
// Loop the series and index values
i = 0;
this.setUpKeyToAxis();
each(this.series, function (series) {
var keys = series.options.keys,
pointArrayMap = keys || series.pointArrayMap || ['y'],
valueCount = pointArrayMap.length,
xTaken = !series.requireSorting && {},
categoryMap = {},
datetimeValueAxisMap = {},
xAxisIndex = Highcharts.inArray(series.xAxis, xAxes),
mockSeries,
j;
// Map the categories for value axes
each(pointArrayMap, function (prop) {
var axisName = (
(series.keyToAxis && series.keyToAxis[prop]) ||
prop
) + 'Axis';
categoryMap[prop] = (
series[axisName] &&
series[axisName].categories
) || [];
datetimeValueAxisMap[prop] = (
series[axisName] &&
series[axisName].isDatetimeAxis
);
});
if (
series.options.includeInCSVExport !== false &&
!series.options.isInternal &&
series.visible !== false // #55
) {
// Build a lookup for X axis index and the position of the first
// series that belongs to that X axis. Includes -1 for non-axis
// series types like pies.
if (!Highcharts.find(xAxisIndices, function (index) {
return index[0] === xAxisIndex;
})) {
xAxisIndices.push([xAxisIndex, i]);
}
// Compute the column headers and top level headers, usually the
// same as series names
j = 0;
while (j < valueCount) {
columnTitleObj = columnHeaderFormatter(
series,
pointArrayMap[j],
pointArrayMap.length
);
columnTitles.push(
columnTitleObj.columnTitle || columnTitleObj
);
if (multiLevelHeaders) {
topLevelColumnTitles.push(
columnTitleObj.topLevelColumnTitle || columnTitleObj
);
}
j++;
}
mockSeries = {
chart: series.chart,
autoIncrement: series.autoIncrement,
options: series.options,
pointArrayMap: series.pointArrayMap
};
// Export directly from options.data because we need the uncropped
// data (#7913), and we need to support Boost (#7026).
each(series.options.data, function eachData(options, pIdx) {
var key,
prop,
val,
name,
point;
point = { series: mockSeries };
series.pointClass.prototype.applyOptions.apply(
point,
[options]
);
if (point.x >= series.xAxis.min && point.x <= series.xAxis.max) {
key = point.x;
name = series.data[pIdx] && series.data[pIdx].name;
if (xTaken) {
if (xTaken[key]) {
key += '|' + pIdx;
}
xTaken[key] = true;
}
j = 0;
// Pies, funnels, geo maps etc. use point name in X row
if (!series.xAxis || series.exportKey === 'name') {
key = name;
}
//console.log(point)
if (!rows[key]) {
// Generate the row
rows[key] = [];
// Contain the X values from one or more X axes
rows[key].xValues = [];
}
rows[key].x = point.x;
rows[key].name = name;
rows[key].xValues[xAxisIndex] = point.x;
while (j < valueCount) {
prop = pointArrayMap[j]; // y, z etc
val = point[prop];
rows[key][i + j] = pick(
categoryMap[prop][val], // Y axis category if present
datetimeValueAxisMap[prop] ?
time.dateFormat(csvOptions.dateFormat, val) :
null,
val
);
j++;
}
}
});
i = i + j;
}
});
// Make a sortable array
for (x in rows) {
if (rows.hasOwnProperty(x)) {
rowArr.push(rows[x]);
}
}
var xAxisIndex, column;
// Add computed column headers and top level headers to final row set
dataRows = multiLevelHeaders ? [topLevelColumnTitles, columnTitles] :
[columnTitles];
i = xAxisIndices.length;
while (i--) { // Start from end to splice in
xAxisIndex = xAxisIndices[i][0];
column = xAxisIndices[i][1];
xAxis = xAxes[xAxisIndex];
// Sort it by X values
rowArr.sort(function (a, b) { // eslint-disable-line no-loop-func
return a.xValues[xAxisIndex] - b.xValues[xAxisIndex];
});
// Add header row
xTitle = columnHeaderFormatter(xAxis);
dataRows[0].splice(column, 0, xTitle);
if (multiLevelHeaders && dataRows[1]) {
// If using multi level headers, we just added top level header.
// Also add for sub level
dataRows[1].splice(column, 0, xTitle);
}
// Add the category column
each(rowArr, function (row) { // eslint-disable-line no-loop-func
var category = row.name;
if (xAxis && !defined(category)) {
if (xAxis.isDatetimeAxis) {
if (row.x instanceof Date) {
row.x = row.x.getTime();
}
category = time.dateFormat(
csvOptions.dateFormat,
row.x
);
} else if (xAxis.categories) {
category = pick(
xAxis.names[row.x],
xAxis.categories[row.x],
row.x
);
} else {
category = row.x;
}
}
// Add the X/date/category
row.splice(column, 0, category);
});
}
dataRows = dataRows.concat(rowArr);
Highcharts.fireEvent(this, 'exportData', { dataRows: dataRows });
return dataRows;
};
var chart = new Highcharts.StockChart({
chart: {
renderTo: 'container'
},
navigator: {
series: {
includeInCSVExport: false
}
},
series: [{
data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4, 32, 221, 123, 321, 322, 29, 177, 76, 46, 245, 122, 67],
pointStart: Date.UTC(2013, 0, 1),
pointInterval: 24 * 36e5
}],
exporting: {
csv: {
dateFormat: '%Y-%m-%d'
}
}
});
document.getElementById('getcsv').addEventListener('click', function () {
alert(chart.getCSV());
});
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<div id="container" style="height: 300px; margin-top: 2em"></div>
<button id="getcsv">Alert CSV</button>
I got the answer.
Just include this condition inside of export-data in funciton Highcharts.Chart.prototype.getDataRows:
(...)
point = { series: mockSeries };
series.pointClass.prototype.applyOptions.apply(point, [options]);
key = point.x;
name = series.data[pIdx] && series.data[pIdx].name;
j = 0;
if (point.x >= series.xAxis.min && point.x <= series.xAxis.max) {// ***this condition
if (!xAxis || series.exportKey === "name" || (!hasParallelCoords && xAxis && xAxis.hasNames && name)) {
key = name;
}
(...)
}
If don't want change the lib following this example in fiddleJs
example Highstock period time export
In my project, we are using the highchart version: Highcharts JS v3.0.10.
What should be equivalent code or property which is suitable for allowOverlap = false according to the newer version?
How to achieve alloOverlap= false in the older version?
Link: https://api.highcharts.com/highcharts/series.timeline.dataLabels.allowOverlap
The code that is responsible for hiding the overlapping data labels is currently in Highcharts core: https://code.highcharts.com/highcharts.src.js, but previously it was a separate module: https://code.highcharts.com/5/modules/overlapping-datalabels.src.js
However, to make it work you would have to make many changes in your code. I think using the plugin below will be the best solution for you:
(function(H) {
var each = H.each,
extend = H.extend;
/**
* Hide overlapping labels. Labels are moved and faded in and out on zoom to provide a smooth
* visual imression.
*/
H.Series.prototype.hideOverlappingDataLabels = function() {
var points = this.points,
len = points.length,
i,
j,
label1,
label2,
intersectRect = function(pos1, pos2, size1, size2) {
return !(
pos2.x > pos1.x + size1.width ||
pos2.x + size2.width < pos1.x ||
pos2.y > pos1.y + size1.height ||
pos2.y + size2.height < pos1.y
);
};
// Mark with initial opacity
each(points, function(point, label) {
label = point.dataLabel;
if (label) {
label.oldOpacity = label.opacity;
label.newOpacity = 1;
}
});
// Detect overlapping labels
for (i = 0; i < len - 1; ++i) {
label1 = points[i].dataLabel;
for (j = i + 1; j < len; ++j) {
label2 = points[j].dataLabel;
if (label1 && label2 && label1.newOpacity !== 0 && label2.newOpacity !== 0 &&
intersectRect(label1.alignAttr, label2.alignAttr, label1, label2)) {
(points[i].labelrank < points[j].labelrank ? label1 : label2).newOpacity = 0;
}
}
}
// Hide or show
each(points, function(point, label) {
label = point.dataLabel;
if (label) {
if (label.oldOpacity !== label.newOpacity) {
label[label.isOld ? 'animate' : 'attr'](extend({
opacity: label.newOpacity
}, label.alignAttr));
}
label.isOld = true;
}
});
};
H.wrap(H.Series.prototype, 'drawDataLabels', function(proceed) {
proceed.call(this);
this.hideOverlappingDataLabels();
});
}(Highcharts));
Live demo: http://jsfiddle.net/BlackLabel/6s5ycrwa/
<script>
var passings = [["New York","5001","05/18 00:36","S 28 MPH"], ["Phili","5002","05/18 01:36","S 50 MPH"], ["Richmond","5003","05/18 02:36","S 40 MPH"], ["Wilson","5004","05/18 03:36","S 30 MPH"],
["Savannah","5005","05/18 04:36","S 29 MPH"], ["Miami","5006","05/18 05:36","S 40 MPH"]]
leftK1 = ["20","30","50","20","30","40"]
var labelL1 = "Rain %";
var ctx = document.getElementById("myChart").getContext("2d");
var canvasWidth = 600;
ctx.canvas.width = canvasWidth;
ctx.canvas.height = 700;
Chart.defaults.global.defaultFontSize = 14;
Chart.defaults.global.defaultFontFamily = "Lato, sans-serif";
var chartData = null;
var chartOptions = null;
var chartDataSets = [ {
label : labelL1,
fill : false,
data : leftK1,
borderColor : 'rgb(255, 99, 132)'
} ];
chartData = {
labels : passings,
datasets : chartDataSets
}
chartOptions = {
responsive : true,
maintainAspectRatio : false,
elements : {
line : {
tension : 0, // disables bezier curves
}
},
animation : {
},
legend : {
display : true,
position : 'top',
labels : {
fontColor : 'rgb(255, 99, 132)'
}
},
title : {
display : true,
text : 'Passings Chart'
},
scales : {
yAxes : [ {
ticks : {
max : 80,
min : 0
},
gridLines : {
zeroLineWidth : 5
},
scaleLabel : {
display : true,
labelString : "Rain Percantage",
fontFamily : "Lato, sans-serif",
fontSize : 18
}
} ],
xAxes : [ {
ticks : {
autoSkip : false,
maxTicksLimit : 15,
maxRotation : 0,
minRotation : 0,
fontFamily : "Lato, sans-serif",
fontSize : 12
}
} ]
}
// end scales
}
window.myChart = new Chart(ctx, {
type : 'line',
data : chartData,
options : chartOptions
});
</script>
<h:form id="ChartForm">
<div >
<canvas id="myChart" ></canvas>
</div>
</h:form>
enter image description hereI have passed Labels as an array to the chart (Chart.js version 2.7) so that I have multiple rows of X-Axis Labels. While displaying as tool tip, it is displaying whole array for each tool tip. I have seen several postings where they gave ways to display values from legend and and customizing Y-axis data.
Is there a way to display a short form of Label (X-axis label) as tooltip ?
You can use Callbacks as it is mentioned in Chart.js Documentatoin
You can even customize your tooltips for example:
var myPieChart = new Chart(ctx, {
type: 'pie',
data: data,
options: {
tooltips: {
// Disable the on-canvas tooltip
enabled: false,
custom: function(tooltipModel) {
// Tooltip Element
var tooltipEl = document.getElementById('chartjs-tooltip');
// Create element on first render
if (!tooltipEl) {
tooltipEl = document.createElement('div');
tooltipEl.id = 'chartjs-tooltip';
tooltipEl.innerHTML = "<table></table>";
document.body.appendChild(tooltipEl);
}
// Hide if no tooltip
if (tooltipModel.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set caret Position
tooltipEl.classList.remove('above', 'below', 'no-transform');
if (tooltipModel.yAlign) {
tooltipEl.classList.add(tooltipModel.yAlign);
} else {
tooltipEl.classList.add('no-transform');
}
function getBody(bodyItem) {
return bodyItem.lines;
}
// Set Text
if (tooltipModel.body) {
var titleLines = tooltipModel.title || [];
var bodyLines = tooltipModel.body.map(getBody);
var innerHtml = '<thead>';
titleLines.forEach(function(title) {
innerHtml += '<tr><th>' + title + '</th></tr>';
});
innerHtml += '</thead><tbody>';
bodyLines.forEach(function(body, i) {
var colors = tooltipModel.labelColors[i];
var style = 'background:' + colors.backgroundColor;
style += '; border-color:' + colors.borderColor;
style += '; border-width: 2px';
var span = '<span style="' + style + '"></span>';
innerHtml += '<tr><td>' + span + body + '</td></tr>';
});
innerHtml += '</tbody>';
var tableRoot = tooltipEl.querySelector('table');
tableRoot.innerHTML = innerHtml;
}
// `this` will be the overall tooltip
var position = this._chart.canvas.getBoundingClientRect();
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.position = 'absolute';
tooltipEl.style.left = position.left + tooltipModel.caretX + 'px';
tooltipEl.style.top = position.top + tooltipModel.caretY + 'px';
tooltipEl.style.fontFamily = tooltipModel._bodyFontFamily;
tooltipEl.style.fontSize = tooltipModel.bodyFontSize + 'px';
tooltipEl.style.fontStyle = tooltipModel._bodyFontStyle;
tooltipEl.style.padding = tooltipModel.yPadding + 'px ' + tooltipModel.xPadding + 'px';
}
}
}
});
See the Samples
and more
How I can select column (crosshairs) on mouseover xAxis labels?
I can mouseover label, but don't know how to select column.
$(document).on('mouseover', '.highcharts-axis:eq(' + (axisCount - 1) + ') text, .highcharts-axis-labels:eq(' + (axisCount - 1) + ') text', function () {
console.log('mouseover');
// hover current column - crosshairs
});
http://jsfiddle.net/o355e82b/3/ (image how it should be - inside)
You can wrap crosshairs function and modify height of plotted element.
(function (HC) {
HC.wrap(HC.Axis.prototype, 'drawCrosshair', function (proceed, e, point) {
var path,
options = this.crosshair,
animation = options.animation,
pos,
attribs,
categorized;
if (
// Disabled in options
!this.crosshair ||
// Snap
((defined(point) || !HC.pick(this.crosshair.snap, true)) === false)) {
this.hideCrosshair();
} else {
// Get the path
if (!HC.pick(options.snap, true)) {
pos = (this.horiz ? e.chartX - this.pos : this.len - e.chartY + this.pos);
} else if (defined(point)) {
pos = this.isXAxis ? point.plotX : this.len - point.plotY; // #3834
}
if (this.isRadial) {
path = this.getPlotLinePath(this.isXAxis ? point.x : pick(point.stackY, point.y)) || null; // #3189
} else {
path = this.getPlotLinePath(null, null, null, null, pos) || null; // #3189
}
if (path === null) {
this.hideCrosshair();
return;
}
// Draw the cross
if (this.cross) {
//overwrite a height
path[5] = point.series.chart.containerHeight;
this.cross.attr({
visibility: VISIBLE
})[animation ? 'animate' : 'attr']({
d: path
}, animation);
} else {
categorized = this.categories && !this.isRadial;
attribs = {
'stroke-width': options.width || (categorized ? this.transA : 1),
stroke: options.color || (categorized ? 'rgba(155,200,255,0.2)' : '#C0C0C0'),
zIndex: options.zIndex || 2
};
if (options.dashStyle) {
attribs.dashstyle = options.dashStyle;
}
this.cross = this.chart.renderer.path(path).attr(attribs).add();
}
}
});
})(Highcharts);
Example: http://jsfiddle.net/o355e82b/5/
I'm trying to link two jQuery UI sliders so they'll add up to 100%. I've found the perfect solution for three sliders here on SO, but for some reason I am unable to get the math to add up correctly when modifying this jsFiddle example to strip out the third slider: http://jsfiddle.net/gWbMp/3/
Can anyone help me out in forking this to simply include two sliders instead of three?
Here's the (close) javascript I've ended up with but it's not quite right:
var min = 0;
var max = 100;
$("input").change(function(){
console.log("a");
var index = $(this).attr('class').substring(0,1);
$("#slider_"+ index).slider('value', this.value);
refreshSliders( index - 0 );
});
$('.selector').slider({
animate : true
}, {
min : min
}, {
max : max
}, {
change : function(event, ui) {
totalvalue = $("#slider_1").slider("value") + $("#slider_2").slider("value");
$('.1percent').val($("#slider_1").slider("value"));
$('.2percent').val($("#slider_2").slider("value"));
}
}, {
slide : function(event, ui) {
$('.1percent').val($("#slider_1").slider("value"));
$('.2percent').val($("#slider_2").slider("value"));
}
});
$("#slider_1").slider('value', 10);
$("#slider_2").slider('value', 90);
$('.1percent').val($("#slider_1").slider("value"));
$('.2percent').val($("#slider_2").slider("value"));
function refreshSliders(slidermainin) {
var value1 = $("#slider_1").slider("option", "value");
var value2 = $("#slider_2").slider("option", "value");
var valuechange = (value1 + value2) - 100;
var valuemain = 0, valueother1 = 0;
switch(slidermainin) {
case 1:
slidermain = "#slider_1";
sliderother1 = "#slider_2";
valuemain = value1;
valueother1 = value2;
break;
case 2:
slidermain = "#slider_2";
sliderother1 = "#slider_1";
valuemain = value2;
valueother1 = value1;
break;
}
if (valueother1 === 0) {
if (valueother1 === 0) {
if (valuechange <= 0) {
$(sliderother1).slider('value', valueother1 - (valuechange / 2));
}
} else {
if (valuechange <= 0) {
$(sliderother1).slider('value', valueother1 - (valuechange / 2));
} else {
$(sliderother1).slider('value', valueother1 - valuechange);
}
}
} else {
$(sliderother1).slider('value', valueother1 - (valuechange / 2));
}
}
var bindSliders = function(selector, value) {
$(selector).bind("slidechange slide", function(event, ui) {
event.originalEvent && (event.originalEvent.type == 'mousemove' || event.originalEvent.type == 'mouseup' || event.originalEvent.type == 'keydown') && refreshSliders(value);
});
};
bindSliders("#slider_1", 1);
bindSliders("#slider_2", 2);
I think this can be done much shorter for two sliders
You can rewrite refreshSliders function to calculate second value on the basis of max value
And call it directly on slider "change" and "slide" (or even just second one)
function refreshSliders(thisSlider, ui){
var thisNum = $(thisSlider).attr("id").replace("slider_", "");
var otherNum = (thisNum==1)?2:1;
$('.'+thisNum+'percent').val(ui.value);
if ($("#slider_"+otherNum).slider("value")!=max-ui.value){
$("#slider_"+otherNum).slider("value", max-ui.value);
$('.'+otherNum+'percent').val(max-ui.value);
}
}
have a look at this jsfiddle, i forked it from original one and adjusted a bit: http://jsfiddle.net/paulitto/fBxCm/1/