I am trying to use latest Highcharts to render data from Web API which is ISO formatted. I am using TypeScript and datejs (http://www.datejs.com/).
I am intending to update this chart on a poll, and the series can be dramatically transformed between requests so I have decided to destroy and recreate the chart from scratch. I tried setting the options directly and redrawing but that did not seem to have any effect.
But to be sure I commented out the initial chart creation and destruction, and I still got the same error. I have checked to see that the parser is returning a date object and it is, and the data seems to be correct.
My guess is it has something to do with how I'm constructing my data element.
Is this an acceptable structure for time-series data for high-charts:
var data: [Date, number][] = [, ];
My Model:
export interface Chart {
Title: string;
Series: ChartSeries[];
XAxisTitle: string;
YAxisTtile: string;
}
export interface ChartSeries {
Title: string;
Points: ChartDataPoint[];
}
export interface ChartDataPoint {
X: string;
Y: number;
}
An example series in XML (using NewtonSoft.Json to do the Json serialization)
<ChartSeries>
<Points>
<ChartDataPoint>
<X>2015-12-16T00:00:00</X>
<Y>184</Y>
</ChartDataPoint>
<ChartDataPoint>
<X>2015-12-16T05:00:00</X>
<Y>168</Y>
</ChartDataPoint>
<ChartDataPoint>
<X>2015-12-16T07:00:00</X>
<Y>282</Y>
</ChartDataPoint>
</Points>
<Title>Version: UNK;Service Type: 1002;Server: UNK;Method Name: GetAllCustomerDetails
</Title>
</ChartSeries>
Relevant portion of the ViewModel:
protected Draw(): void {
var chart = this.ChartData();
if (!Util.Obj.isNullOrUndefined(chart)) {
this.IsDrawing(true);
var series: HighchartsSeriesOptions[] = [];
for (var i = 0; i < chart.Series.length; i++) {
var s = chart.Series[i];
var data: [Date, number][] = [, ];
for (var p = 0; p < s.Points.length; p++) {
var point = s.Points[p];
data.push([Date.parse(point.X), point.Y]);
}
series.push({
type: "line",
data: data,
name: s.Title
});
}
var options: HighchartsOptions = {
chart: {
renderTo: this.chartElementName,
ignoreHiddenSeries: false
},
series: series,
title: chart.Title,
yAxis: {
type: 'logarithmic',
minorTickInterval: 1,
title: chart.YAxisTtile
},
xAxis: {
type: 'datetime',
title: chart.XAxisTitle
}
};
this.Chart.destroy();
this.Chart = new Highcharts.Chart(options);
this.IsDrawing(false);
}
}
The error:
Line: 14084
Error: Unable to set property 'index' of undefined or null reference
Some context for the error from highcharts.src.js:
generatePoints: function () {
var series = this,
options = series.options,
dataOptions = options.data,
data = series.data,
dataLength,
processedXData = series.processedXData,
processedYData = series.processedYData,
pointClass = series.pointClass,
processedDataLength = processedXData.length,
cropStart = series.cropStart || 0,
cursor,
hasGroupedData = series.hasGroupedData,
point,
points = [],
i;
if (!data && !hasGroupedData) {
var arr = [];
arr.length = dataOptions.length;
data = series.data = arr;
}
for (i = 0; i < processedDataLength; i++) {
cursor = cropStart + i;
if (!hasGroupedData) {
if (data[cursor]) {
point = data[cursor];
} else if (dataOptions[cursor] !== UNDEFINED) { // #970
data[cursor] = point = (new pointClass()).init(series, dataOptions[cursor], processedXData[i]);
}
points[i] = point;
} else {
// splat the y data in case of ohlc data array
points[i] = (new pointClass()).init(series, [processedXData[i]].concat(splat(processedYData[i])));
}
points[i].index = cursor; // For faster access in Point.update <-- error happens here, there is a single item in the collection that is undefined
}
As Requested, stack trace:
Series.generatePoints # highcharts.src.js:14084
Series.translate # highcharts.src.js:14165
(anonymous function) # highcharts-more.js:53
obj.(anonymous function) # highcharts.src.js:660
(anonymous function) # highcharts.src.js:12830
each # highcharts.src.js:1106
Chart.renderSeries # highcharts.src.js:12829
(anonymous function) # highcharts-3d.js:26
obj.(anonymous function) # highcharts.src.js:660
Chart.render # highcharts.src.js:12937
Chart.firstRender # highcharts.src.js:13112
Chart.init # highcharts.src.js:11841
(anonymous function) # highcharts-3d.js:25
obj.(anonymous function) # highcharts.src.js:660
Chart.getArgs # highcharts.src.js:11746
Highcharts.Chart # highcharts.src.js:11720
ChartViewModel.Draw # ChartViewModel.ts:160
(anonymous function) # ChartViewModel.ts:180
(anonymous function) # jquery-2.1.4.js:3256
fire # jquery-2.1.4.js:3099
self.fireWith # jquery-2.1.4.js:3211
deferred.(anonymous function) # jquery-2.1.4.js:3301
(anonymous function) # ChartViewModel.ts:244
(anonymous function) # jquery-2.1.4.js:3256
fire # jquery-2.1.4.js:3099
self.fireWith # jquery-2.1.4.js:3211
done # jquery-2.1.4.js:8264
(anonymous function) # jquery-2.1.4.js:8605
As it turns out there were two problems:
var data: [Date, number][] = [, ];
In order to solve the exception:
var data: [Date, number][] = [];
In order for the days to render correctly:
var data: [number, number][] = [];
and
var d = Date.parse(point.X);
data.push([
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds()),
point.Y
]);
Related
I am using this script to draw average spectral signature of all classes together and each class separately of a classified image by RF algorithm in GEE.
var bands = ['B1', 'B2', 'B3', 'B4','B5','B6','B7', 'B8', 'B8A', 'B9' ,'B11', 'B12','NDVI', 'EVI', 'GNDVI', 'NBR', 'NDII'];
var Training_Points = Water.merge(Residential).merge(Agricultural).merge(Arbusti).merge(BoschiMisti).merge(Latifoglie).merge(Conifere).merge(BareSoil);
var classes = ee.Image().byte().paint(Training_Points, "land_class").rename("land_class")
var stratified_points = classes.stratifiedSample({
numPoints: 50,
classBand: 'land_class',
scale: 10,
region: Training_Points,
geometries: false,
tileScale: 6
})
print(stratified_points, 'stratified_points')
//Create training data
var training_Stratified = RF_classified.select(bands).sampleRegions({
collection: stratified_points,
properties: ['land_class'],
scale:10,
tileScale:2
});
var bands = RF_classified.bandNames()
var numBands = bands.length()
var bandsWithClass = bands.add('land_class')
var classIndex = bandsWithClass.indexOf('land_class')
// Use .combine() to get a reducer capable of computing multiple stats on the input
var combinedReducer = ee.Reducer.mean().combine({
reducer2: ee.Reducer.stdDev(),
sharedInputs: true})
// Use .repeat() to get a reducer for each band and then use .group() to get stats by class
var repeatedReducer = combinedReducer.repeat(numBands).group(classIndex)
var stratified_points_Stats = training_Stratified.reduceColumns({
selectors: bands.add('land_class'),
reducer: repeatedReducer,
})
// Result is a dictionary, we do some post-processing to extract the results
var groups = ee.List(stratified_points_Stats.get('groups'))
var classNames = ee.List(['Water','Residential', 'Agricultural', 'Arbusti', 'BoschiMisti', 'Latifoglie','Conifere', 'BareSoil'])
var fc = ee.FeatureCollection(groups.map(function(item) {
// Extract the means
var values = ee.Dictionary(item).get('mean')
var groupNumber = ee.Dictionary(item).get('group')
var properties = ee.Dictionary.fromLists(bands, values)
var withClass = properties.set('class', classNames.get(groupNumber))
return ee.Feature(null, withClass)
}))
// Chart spectral signatures of training data
var options = {
title: 'Average Spectral Signatures',
hAxis: {title: 'Bands'},
vAxis: {title: 'Reflectance',
viewWindowMode:'explicit',
viewWindow: {
max:6000,
min:0
}},
lineWidth: 1,
pointSize: 4,
series: {
0: {color: '105af0'},
1: {color: 'dc350a'},
2: {color: 'caa712'},
3: {color: 'b9ffa4'},
4: {color: '369b47'},
5: {color: '21ff2d'},
6: {color: '275b25'},
7: {color: 'f7e084'},
}};
// Default band names don't sort propertly Instead, we can give a dictionary with labels for each band in the X-Axis
var bandDescriptions = {
'B2': 'B2/Blue',
'B3': 'B3/Green',
'B4': 'B4/Red',
'B5': 'B5/Red Edge 1',
'B6': 'B5/Red Edge 2',
'B7': 'B7/Red Edge 3',
'B8': 'B8/NIR',
'B8A': 'B8A/Red Edge 4',
'B11': 'B11/SWIR-1',
'B12': 'B12/SWIR-2'
}
// Create the chart and set options.
var chart = ui.Chart.feature.byProperty({
features: fc,
xProperties: bandDescriptions,
seriesProperty: 'class'
})
.setChartType('ScatterChart')
.setOptions(options);
print(chart)
var classChart = function(land_class, label, color) {
var options = {
title: 'Spectral Signatures for ' + label + ' Class',
hAxis: {title: 'Bands'},
vAxis: {title: 'Reflectance',
viewWindowMode:'explicit',
viewWindow: {
max:6000,
min:0
}},
lineWidth: 1,
pointSize: 4,
};
var fc = training_Stratified.filter(ee.Filter.eq('land_class', land_class))
var chart = ui.Chart.feature.byProperty({
features: fc,
xProperties: bandDescriptions,
})
.setChartType('ScatterChart')
.setOptions(options);
print(chart)
}
classChart(0, 'Water')
classChart(1, 'Residential')
classChart(2, 'Agricultural')
classChart(3, 'Arbusti')
classChart(4, 'BoschiMisti')
classChart(5, 'Latifoglie')
classChart(6, 'Conifere')
classChart(7, 'BareSoil')
I receive the error:
Error generating chart: Image.select: Pattern 'B1' did not match any
bands.
I do not understand where is the problem since I used the same script before to draw histogram of training data and it worked well.
Using data from database I am trying to simulate the sankey diagram working JSFiddle.
I am assembling my data using the below code
// sdata.php
<?php
$con = sqlsrv_connect($server, $options);
if (!$con){die('Could not connect: ' . sqlsrv_error());}
$sql_query = "select * from test_data";
$result = sqlsrv_query($con, $sql_query);
$series = array();
$series['type'] = 'sankey';
$series['name'] = 'Gendata';
$series['keys'] = '[\'from\',\'to\',\'weight\']';
while($r = sqlsrv_fetch_array($result))
{
$series1 = array();
$series1[] = $r['PARENT'];
$series1[] = $r['CHILD'];
$series1[] = $r['DGEN'];
$series['data'][] = $series1;
}
$result = array();
array_push($result,$series);
print json_encode($result, JSON_NUMERIC_CHECK);
sqlsrv_close($con);
?>
My JSON looks like
[{
"type":"sankey",
"name":"Gendata",
"keys":"['from','to','weight']",
"data":[
["GROUP","COAL",24.46], ["GROUP","GAS",11.96],["GROUP","HYDRO",19.36],
["HYDRO","HYD",19.36], ["COAL","ER2",22.4],["GAS","NR",19]
]
}]
My Chart rending code looks like
$(document).ready(function() {
var options = {
chart: {
renderTo: 'container',
showAxes: true
},
yAxis: [{
lineWidth: 1,
tickPositions: [0, 1, 2, 3]
}],
title: {
text: 'Sankey Diagram'
},
series: []
}
$.getJSON("sdata.php", function(resp) {
console.log(resp);
options.series[0] = resp[1]; //option 1 to assign the data in series
//options.series.push.resp; //option 2 to push the data in series
chart = new Highcharts.Chart(options);
});
});
but I am failing. I am unable to find the error I am missing
Kindly help me.
Let me know if I can be of any further information.
From the code you have posted here, the error is your keys assignment.
You have:
"keys":"['from','to','weight']",
But it needs to be:
"keys": ['from','to','weight'],
That is, the array should not be surrounded by quotes, because then it will be interpreted as a string.
In your PHP that would mean:
$series['keys'] = '[\'from\',\'to\',\'weight\']';
Needs to be:
$series['keys'] = ['from', 'to', 'weight'];
Working example: https://jsfiddle.net/ewolden/aeh02djx/
I am using highcharts for statistical data displaying. I want to display , on the stack label , the average of all the values .
Below is what i am doing but i cant seem to get it right :
yAxis: {
min: 0,
title: {
text: 'Task'
},
stackLabels: {
style: {
color: 'black'
},
enabled: true,
formatter: function() {
return (this.axis.series[1].yData[this.x]).toPrecision(2) + '%';
}
}
},
The above only takes the last value on the stack and shows the percentage. For instance , if the last value is 50 , the above displays 50% as the stack value . I want to take an average of all the values. Any help would be appreciated.
If you want to show any stack's percentage mean if your stacked column has two stack A-5 and B-10 , then the % of B in column is 66% and % of A is 33%. If you want to show that use following in formatter function ( refer This Fiddle Link)
formatter: function() {
return (this.axis.series[1].yData[this.x] / this.total * 100).toPrecision(2) + '%';
}
Updating as per OP 's comment Refer Working fiddle here
Use following code : Make your data in a variable and calculate the sum
var seriesData = [{
name: 'Incomplete',
data: [1, 3, 4, 7, 20]
}, {
name: 'Complete',
data: [3, 4, 4, 2, 5]
}];
var total = 0;
$.each(seriesData,function(item){
$.each(seriesData[item].data,function() {
total += this;
});
});
And then use following in stacklabel formatter :
formatter: function() {
return ( this.total/ total * 100).toPrecision(2) + '%';
}
series:seriesData
hope it helps :)
This doesn't seem to be as easy as it should be.
I would accomplish this by pre-processing the data to generate an array of averages, and then referencing that array from the stackLabels formatter function.
Example, build the averages (assumes array 'data' with sub array for each series data values):
var sum = 0;
var averages = [];
var dataLen = data.length;
$.each(data[0], function(x, point) {
sum = 0;
for(var i = 0; i < dataLen; i++) {
sum += data[i][x];
}
averages.push(sum/dataLen);
})
And then in the formatter:
yAxis : {
stackLabels: {
enabled: true,
formatter: function() {
return Highcharts.numberFormat(averages[this.x],2);
}
}
}
Example:
http://jsfiddle.net/jlbriggs/vatdrecb/
If I could find a way to get a reliable count of the points in each stack, you could just use
return this.total/countOfPoints;
in the formatter without needing to build an array, but I can't seem to reliably get that count.
I build a chart like the lazy loading example (http://www.highcharts.com/stock/demo/lazy-loading) but with having the input fields of the range selector.
When I zoom in everything is fine. Now I would like to change the selected range by using the input fields.
But I am not able to change the input to values beyond the zoomed area despite the fact I have more data visible in my navigator.
In the setExtremes function I am doing some calculations:
DX.IPFixGraphModule.prototype.setExtremes = function(e) {
var fromTime,
maxZoom = 30 * 60 * 1000,
now = new Date().getTime();
if (e.min) {
fromTime = e.min;
} else {
fromTime = e.dataMin;
}
fromTime = Math.round(fromTime);
var diff = now - fromTime;
// -1 month = max 1 week zoom
if (diff >= 2592000000) {
maxZoom = 7 * 24 * 60 * 60 * 1000;
}
// -1 week = max 12 hour zoom
else if (diff >= 604800000) {
maxZoom = 12 * 60 * 60 * 1000;
}
// this refers to axis
// #see http://api.highcharts.com/highstock#Axis.update
this.update({
minRange: maxZoom
}, false);
};
But the values I receive in e.min and e.max are not the original input values but already corrected to the displayed time range.
// handle changes in the input boxes
input.onchange = function () {
var inputValue = input.value,
value = (options.inputDateParser || Date.parse)(inputValue),
xAxis = chart.xAxis[0],
dataMin = xAxis.dataMin,
dataMax = xAxis.dataMax;
// If the value isn't parsed directly to a value by the browser's Date.parse method,
// like YYYY-MM-DD in IE, try parsing it a different way
if (isNaN(value)) {
value = inputValue.split('-');
value = Date.UTC(pInt(value[0]), pInt(value[1]) - 1, pInt(value[2]));
}
if (!isNaN(value)) {
// Correct for timezone offset (#433)
if (!defaultOptions.global.useUTC) {
value = value + new Date().getTimezoneOffset() * 60 * 1000;
}
// Validate the extremes. If it goes beyound the data min or max, use the
// actual data extreme (#2438).
if (isMin) {
if (value > rangeSelector.maxInput.HCTime) {
value = UNDEFINED;
} else if (value < dataMin) {
value = dataMin;
}
} else {
if (value < rangeSelector.minInput.HCTime) {
value = UNDEFINED;
} else if (value > dataMax) {
value = dataMax;
}
}
// Set the extremes
if (value !== UNDEFINED) {
chart.xAxis[0].setExtremes(
isMin ? value : xAxis.min,
isMin ? xAxis.max : value,
UNDEFINED,
UNDEFINED,
{ trigger: 'rangeSelectorInput' }
);
}
}
};
(Code taken from highstock.src.js around line 21126)
So I cannot extend my zoom beyond the current active selection, but the navigator displays more data.
Does anyone know a way to set a date beyond the currently zoomed time range?
Possible Solution
I solved it by checking the navigator range in the "afterSetExtremes" Event.
DX.IPFixGraphModule.prototype.afterSetExtremes = function(e) {
if (e.trigger === 'rangeSelectorInput') {
var fromValue = this.stockchart.rangeSelector.minInput.value,
toValue = this.stockchart.rangeSelector.maxInput.value,
fromTime = parseDateTime(fromValue),
toTime = parseDateTime(toValue),
navigatorAxis = this.stockchart.get('navigator-x-axis'),
maxValue = navigatorAxis.dataMax,
minValue = navigatorAxis.dataMin;
if (fromTime < minValue) {
fromTime = minValue;
}
if (toTime > maxValue) {
toTime = maxValue;
}
this.stockchart.xAxis[0].setExtremes(fromTime, toTime);
} else {
var fromTime,
toTime;
if (e.min) {
fromTime = e.min;
} else {
fromTime = e.dataMin;
}
fromTime = Math.round(fromTime);
if (e.max) {
toTime = e.max;
} else {
toTime = e.dataMax;
}
toTime = Math.round(toTime);
this.settings.afterSetExtremes({startTimestamp: fromTime, endTimestamp: toTime});
}
};
Or see solution below and override the method.
There is no default API for that. Extend Highcharts via overriding drawInput function (your second code snippet).
There is a part of code that you should comment out or remove - the if clause after:
// Validate the extremes. If it goes beyound the data min or max, use the
// actual data extreme (#2438).
Example: http://jsfiddle.net/epL7awo4/1/
$(function () {
(function (H) {
H.wrap(H.RangeSelector.prototype, 'drawInput', function (proceed) {
var name = arguments[1],
merge = H.merge,
createElement = H.createElement,
PREFIX = 'highcharts-',
ABSOLUTE = 'absolute',
PX = 'px',
extend = H.extend,
pInt = H.pInt,
UNDEFINED;
//drawInput: function (name) {
var rangeSelector = this,
chart = rangeSelector.chart,
chartStyle = chart.renderer.style,
renderer = chart.renderer,
options = chart.options.rangeSelector,
defaultOptions = H.getOptions(),
lang = defaultOptions.lang,
div = rangeSelector.div,
isMin = name === 'min',
input,
label,
dateBox,
inputGroup = this.inputGroup;
// Create the text label
this[name + 'Label'] = label = renderer.label(lang[isMin ? 'rangeSelectorFrom' : 'rangeSelectorTo'], this.inputGroup.offset)
.attr({
padding: 2
})
.css(merge(chartStyle, options.labelStyle))
.add(inputGroup);
inputGroup.offset += label.width + 5;
// Create an SVG label that shows updated date ranges and and records click events that
// bring in the HTML input.
this[name + 'DateBox'] = dateBox = renderer.label('', inputGroup.offset)
.attr({
padding: 2,
width: options.inputBoxWidth || 90,
height: options.inputBoxHeight || 17,
stroke: options.inputBoxBorderColor || 'silver',
'stroke-width': 1
})
.css(merge({
textAlign: 'center',
color: '#444'
}, chartStyle, options.inputStyle))
.on('click', function () {
rangeSelector.showInput(name); // If it is already focused, the onfocus event doesn't fire (#3713)
rangeSelector[name + 'Input'].focus();
})
.add(inputGroup);
inputGroup.offset += dateBox.width + (isMin ? 10 : 0);
// Create the HTML input element. This is rendered as 1x1 pixel then set to the right size
// when focused.
this[name + 'Input'] = input = createElement('input', {
name: name,
className: PREFIX + 'range-selector',
type: 'text'
}, extend({
position: ABSOLUTE,
border: 0,
width: '1px', // Chrome needs a pixel to see it
height: '1px',
padding: 0,
textAlign: 'center',
fontSize: chartStyle.fontSize,
fontFamily: chartStyle.fontFamily,
top: chart.plotTop + PX // prevent jump on focus in Firefox
}, options.inputStyle), div);
// Blow up the input box
input.onfocus = function () {
rangeSelector.showInput(name);
};
// Hide away the input box
input.onblur = function () {
rangeSelector.hideInput(name);
};
// handle changes in the input boxes
input.onchange = function () {
var inputValue = input.value,
value = (options.inputDateParser || Date.parse)(inputValue),
xAxis = chart.xAxis[0],
dataMin = xAxis.dataMin,
dataMax = xAxis.dataMax;
// If the value isn't parsed directly to a value by the browser's Date.parse method,
// like YYYY-MM-DD in IE, try parsing it a different way
if (isNaN(value)) {
value = inputValue.split('-');
value = Date.UTC(pInt(value[0]), pInt(value[1]) - 1, pInt(value[2]));
}
if (!isNaN(value)) {
// Correct for timezone offset (#433)
if (!defaultOptions.global.useUTC) {
value = value + new Date().getTimezoneOffset() * 60 * 1000;
}
// Validate the extremes. If it goes beyound the data min or max, use the
// actual data extreme (#2438).
/* if (isMin) {
if (value > rangeSelector.maxInput.HCTime) {
value = UNDEFINED;
} else if (value < dataMin) {
value = dataMin;
}
} else {
if (value < rangeSelector.minInput.HCTime) {
value = UNDEFINED;
} else if (value > dataMax) {
value = dataMax;
}
}*/
// Set the extremes
if (value !== UNDEFINED) {
chart.xAxis[0].setExtremes(
isMin ? value : xAxis.min,
isMin ? xAxis.max : value,
UNDEFINED,
UNDEFINED, {
trigger: 'rangeSelectorInput'
});
}
}
};
//},
});
}(Highcharts));
/**
* Load new data depending on the selected min and max
*/
function afterSetExtremes(e) {
var chart = $('#container').highcharts();
chart.showLoading('Loading data from server...');
$.getJSON('http://www.highcharts.com/samples/data/from-sql.php?start=' + Math.round(e.min) +
'&end=' + Math.round(e.max) + '&callback=?', function (data) {
chart.series[0].setData(data);
chart.hideLoading();
});
}
// See source code from the JSONP handler at https://github.com/highslide-software/highcharts.com/blob/master/samples/data/from-sql.php
$.getJSON('http://www.highcharts.com/samples/data/from-sql.php?callback=?', function (data) {
// Add a null value for the end date
data = [].concat(data, [
[Date.UTC(2011, 9, 14, 19, 59), null, null, null, null]
]);
// create the chart
$('#container').highcharts('StockChart', {
chart: {
type: 'candlestick',
zoomType: 'x'
},
navigator: {
adaptToUpdatedData: false,
series: {
data: data
}
},
scrollbar: {
liveRedraw: false
},
title: {
text: 'AAPL history by the minute from 1998 to 2011'
},
subtitle: {
text: 'Displaying 1.7 million data points in Highcharts Stock by async server loading'
},
rangeSelector: {
buttons: [{
type: 'hour',
count: 1,
text: '1h'
}, {
type: 'day',
count: 1,
text: '1d'
}, {
type: 'month',
count: 1,
text: '1m'
}, {
type: 'year',
count: 1,
text: '1y'
}, {
type: 'all',
text: 'All'
}],
inputEnabled: true,
selected: 4 // all
},
xAxis: {
events: {
afterSetExtremes: afterSetExtremes
},
minRange: 3600 * 1000 // one hour
},
yAxis: {
floor: 0
},
series: [{
data: data,
dataGrouping: {
enabled: false
}
}]
});
});
});
I have one drop-down and a jQDateRangeSlider(a jQuery widget) in index.gsp of my Grails app.I am posting the value selected in the dropdown and the range selected over the slider to a query in my controller using remoteFunction.I want these three values(2 values from the slider and one value from the drop-down) to be posted to the controller when either of the following events occur:
Drop-down changes
Values over the slider change
The remoteFunction works fine from the onChange of the drop-down but when I replicate the remoteFunction inside the UserValuesChanged block of the slider, it throws an error.This is how my code looks like:
Controller
class PgtypController {
def ajaxGetMv = {
def pgtyp = Pgtyp.executeQuery("select p.date_hour ,p.visits, p.mv, p.browser,p.pagetype,p.platform,p.device,p.time_period from Pgtyp p where p.mv = ? and p.date_hour >= ? and p.date_hour <= ? order by col_0_0_ asc ",[ params.mv ] + params.list( 'date_hour' ))
render pgtyp as JSON
}
def dataSource
def datejson = {
def sql = new Sql(dataSource)
def rows = sql.rows("select min(date_hour) as a , max(date_hour) as b from pgtyp")
sql.close()
render rows as JSON
}
def index() {
}
GSP
<form>
<g:select from="['AFFILIATES', 'CSE','DISPLAYADS','EMAIL','MOBILEWEB','OTHERS','ORGANIC','SEO', 'SEM']" name="mv" id = "mv"
onchange="${remoteFunction(
controller:'Pgtyp',
action:'ajaxGetMv',
params:'\'mv=\' + escape(this.value)+\'&date_hour=\'+ z+\'&date_hour=\'+ b',
//params:'\'mv=\'+this.value',
onSuccess: 'printpgtyp(data)')}"
></g:select>
</form>
<script>
dataFile = "http://localhost:8080/marchmock2/Pgtyp/datejson";
d3.json(dataFile, function(error,data) {
if (data)
dataset = data;
var min = dataset[0].a;
var min2 = new Date(min);
var max = dataset[dataset.length - 1].b;
var max2 = new Date(max);
function addZero(val) {
if (val < 10) {
return "0" + val;
}
return val;
}
var s = $j("#slider").dateRangeSlider({
bounds: {
"min": min2,
"max": max2
},
range: {
min: {
hours: 1
}
},
formatter:function(val){
var m = moment(val);
return m.format("DD/MM/YYYY HH:00:00 ");
},
defaultValues:{
min: min2,
max: max2
}
});
x = (s.dateRangeSlider("values").min);
x.setMinutes(0);
x.setSeconds(0);
z = x.getFullYear()+'-'+(x.getMonth()+1)+ '-'+x.getDate()+' '+x.getHours()+':'+'00'+':'+'00' ;
var y = (s.dateRangeSlider("values").max);
y.setMinutes(0);
y.setSeconds(0);
b = y.getFullYear()+'-'+(y.getMonth()+1)+ '-'+y.getDate()+' '+y.getHours()+':'+'00'+':'+'00' ;
$j('#slider').on("userValuesChanged",function (e, data) {
var x = datavalues.min;
x.setMinutes(0);
x.setSeconds(0);
z = x.getFullYear()+'-'+(x.getMonth()+1)+ '-'+x.getDate()+' '+x.getHours()+':'+'00'+':'+'00' ;
var last = data.values.max;
last.setMinutes(0);
last.setSeconds(0);
b = last.getFullYear()+'-'+(last.getMonth()+1)+ '-'+last.getDate()+' '+last.getHours()+':'+'00'+':'+'00' ;
${remoteFunction(
controller:'Pgtyp',
action:'ajaxGetMv',
params:'\'mv=\' +$(\'mv\').value+\'&date_hour=\'+ z+\'&date_hour=\'+ b',
onSuccess: 'printpgtyp(data)')}
})
});
function printpgtyp(data)
{
console.log(data)
console.log(data.length)
}//end of printpgtyp
</script>
This however gives an error like this:
Uncaught SyntaxError: Unexpected token &
Can anyone tell me where exactly am I going wrong? If the code is working fine inside onChange of select tag then why am I getting this error inside UserValuesChanged of the slider?