I am trying to build a plotting webpage which gets data from multiple xively feeds and plots them with Rickshaw (based on D3). The problem I have is that I can't access the data which is returned from the server outside of the calling function. I'm new to js so I'm not sure how to deal with the asynchronous nature of the calls. I would like to call the xively.feed.history() to get various sections of historical data and them concatenate them onto a single graph. Anyway, here is something similar to what I've tried. It based on the xively tutorial
xively.setKey('xxxx my key ')
// Replace with your own values
var feedID = 12345678, // Feed ID
selector = "#myelement"; // Your element on the page
var series = [];
xively.feed.history(feedID, { duration: "10days", interval: 1800 ,limit: 1000}, function (mydata) {
mydata.datastreams.forEach( function(stream){
if ((stream.id == "tempinside") || (stream.id == "tempoutside")) {
var points = [];
stream.datapoints.forEach( function(datapoint){
points.push({x: new Date(datapoint.at).getTime()/1000.0, y: parseFloat(datapoint.value)});
// Add Datapoints Array to Graph Series Array
});
series.push({
name: stream.id,
data: points
});
};
});
var graph2 = new Rickshaw.Graph( {
element: document.querySelector("#chart2"),
width: 600,
height: 400,
renderer: 'line',
series: [{
data: series[0].data,
name: series[0].name,
color: 'red'
},{
data: series[1].data,
name: series[1].name,
color: 'blue'
}]
})
})
As I said, I'm new to javascript so maybe I'm missing something. The graph works fine if it is placed inside the callback part of the xively.feed.history function. If I try to make multiple calls to the function then the data isn't ready by the time the graph code runs.
Ok, so I made it work and I've put a subset of it here so others can see how I did it.
var starttime = moment().subtract("day", 3);
series['tempoutside']=[
{x:starttime.subtract("second",2).unix(),y:15},
{x:starttime.subtract("second",1).unix(),y:15}
];
graph = new Rickshaw.Graph({
element: document.querySelector("#chart"),
height: 400,
width: 600,
renderer: 'line',
interpolation: 'step-before',
series: new Rickshaw.Series([
{
name: 'temperature',
data: series['tempoutside'],
color: 'blue',
}
], series)
});
xively.datastream.history( "123456789", "tempoutside", query, loadData);
function loadData(data) {
//console.log('Getting ' + data.id + 'data from Xively');
if (data.datapoints != undefined){
//console.log('received ' + data.datapoints.length +' datapoints');
lastdata=data;
var filtedData = data.datapoints.filter(function(x) { return (x.value >0.005); });
for (var i=0; i < filtedData.length; i++ ) {
var date = moment(filtedData[i].at);
var value = parseFloat(filtedData[i].value+0.000001);
series[data.id].push({x: date.unix(), y: value});
}
graph.render();
}
}
In my final code I also removed the dummy initialisation values from the series['tempoutside'] array with .pop(). I needed them in the array because the graph gets built first off before the data has been returned from xively. When the data does return, the xively.datastream.history() function calls the loaddata() callback which pushes the data into the series array. Also, I'd not understood that you don't need to push data into the graph series array, because the array is passed as a reference when the graph is built. Update the array and then call graph.render() and it replots it all. Win! This means that multiple calls can be made to Xively to get more data than is available with one API call (limited to 1000 data points). Remember to sort the data by x value before plotting....
Related
I am trying to only load and save a work order record using the map-reduce script. But I don't see logs for loaded work orders or saved work orders. the script is executing only until work_order_Id. Please Help!
Below is my code...
function getInputData(){
var process_data =[];
try{
var workorderSearchObj = search.create({
type: "workorder",
filters:
[
["type","anyof","WorkOrd"],
"AND",
["mainline","is","T"],
"AND",
["status","anyof","WorkOrd:A","WorkOrd:B","WorkOrd:D"]
],
columns:
[
search.createColumn({name: "internalid", label: "Internal ID"}),
search.createColumn({name: "tranid", label: "Document Number"})
]
});
var searchResultCount = workorderSearchObj.runPaged().count;
log.debug("workorderSearchObj result count",searchResultCount);
workorderSearchObj.run().each(function(result){
// .run().each has a limit of 4,000 results
var work_Order = result.getValue({name:'internalid'});
var document_no = result.getValue({name:'tranid'});
process_data.push({
'work_Order':work_Order,
'document_no':document_no
});
return true;
});
}catch(error){
log.debug(error);
}
return process_data;
}
function map(context){
var process_data=JSON.parse(context.value);
log.debug('process_data',process_data);
var work_order_Id = process_data.work_Order;
log.debug("work_order_Id",work_order_Id);
var work_Order_obj = record.load({
type: record.Type.WORK_ORDER,
id: work_order_Id,
isDynamic: true
});
log.debug("work_Order_obj",work_Order_obj);
var recId=work_Order_obj.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("recId",recId);
}
I am trying to load and save work order record. But its not executing.I am trying to load and save a work order record. but it's not loading.
I usually like to simply return saved searches in getInputData because it's consistent to work with and you don't have to fuss with the going over 4k search results and having to return arrays of objects that you put together yourself. Usually transforming data to be in the format you want is best done in the map stage.
/**
* #NScriptType MapReduceScript
* #NApiVersion 2.x
*/
define(["N/search", "N/record"], function (search, record) {
function getInputData() {
// run a saved search of work orders
return search.create({
type: "workorder",
filters: [
["type","anyof","WorkOrd"],
"AND",
["mainline","is","T"],
"AND",
["status","anyof","WorkOrd:A","WorkOrd:B","WorkOrd:D"]
],
columns: [
search.createColumn({name: "internalid", label: "Internal ID"}),
search.createColumn({name: "tranid", label: "Document Number"}),
]
});
}
function map(context) {
// get the work order id
var workOrderId = JSON.parse(context.value).id;
log.debug("workOrderId", workOrderId);
// load the work order
var wordOrderRecord = record.load({
type: record.Type.WORK_ORDER,
id: work_order_Id,
isDynamic: true,
});
log.debug("wordOrderRecord", wordOrderRecord);
// save the work order
var recId = wordOrderRecord.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("recId",recId);
}
function summarize(context) {
// log any errors that might occur
context.mapSummary.errors.iterator().each(function (_, errJson) {
var error = JSON.parse(errJson);
log.error({title: error.name, details: error.message});
return true;
});
}
return {
getInputData: getInputData,
map: map,
summarize: summarize,
};
})
i want to create a real time chart, using Kendo ui chart and signalr. I see this example, but has no code. So i try alone.
A little demonstration of my code:
At first I created a kendo chart
function queueActivityChart() {
$("#queueActivityChart").kendoChart({
legend: {
visible: true
},
seriesDefaults: {
labels: {
visible: true,
format: "{0}",
background: "transparent"
}
},
series: [{
type: "line",
field: "Incoming",
categoryField: "DateTime",
}],
valueAxis: {
labels: {
format: "{0}"
},
line: {
visible: false
}
},
categoryAxis: {
labels:
{
rotation: -90,
dateFormats:
{
seconds: "ss",
minutes: "HH:mm:ss",
hours: "HH:mm",
days: "dd/MM",
months: "MMM 'yy",
years: "yyyy"
}
}, type: "Date", field: "DateTime", baseUnit: "seconds"
}
});
var chart = $("#queueActivityChart").data("kendoChart");
chart.options.transitions = false;
}
$(document).ready(queueActivityChart);
$(document).bind("kendo:skinChange", queueActivityChart);
Then I have this part of code, that get from server data
$scope.signalRData = [];
$scope.signalR.on('receiveCounters', function (data) {
$scope.queueData = data;
for (var i = 0; i < data.length; i++) {
$scope.signalRData.push(data[i]);
}
while ($scope.signalRData.length > 12) {
$scope.signalRData.splice(0, 1);
}
$("#queueActivityChart").data("kendoChart").setDataSource(
new kendo.data.DataSource({
group: {
field: "Name"
},
data: $scope.signalRData
}));
});
This works! And I get a picture of the latest updated items.
But the problem is that this chart is like to put one picture in front of other. I mean that this is the first time that load Data Source; that creates a chart of my data, the second time my data has changed, some values are still in my array some others has move out, the third too.
It seems like it puts a picture of my current data in front of the
previous data. It's not smoothie and cannot use chart's legend
property because I initialize my Data Source everytime.
Can someone help me how can create a smoothie kendo chart with real time data like the kendo official example? Also can somehow to add scroller to bottom?
I looked at the code for the benchmark and I think you may be missing in your chart which is renderAs: "canvas"
Also, in the example, the data is kept locally (saved) and then moved so it creates that "smooth" effect you may be talking about.
Here is the code that you can be of interest:
function step() {
addPoint();
$("#chart").data("kendoChart").refresh();
frames++;
if (playing) {
kendo.animationFrame(step);
}
}
function addPoint() {
var stockData,
change,
lastValue;
// Shift existing categories to the left and add the next date at the end
lastDate = new Date(lastDate.getTime() + TICKS_PER_DAY);
categoryList.push((lastDate.getMonth() + 1) + "/" + (lastDate.getDay() + 1));
if (categoryList.length > POINTS) {
categoryList.shift();
}
for (var i = 0; i < stocks.length; i++) {
stockData = stocks[i];
change = (Math.random() > 0.5 ? 1 : - 1) * Math.random() * 10;
lastValue = stockData[stockData.length - 1] || Math.random() * 10;
// Add a new pseudo-random data point
stockData.push(Math.min((i + 1) * 20, Math.max((i + 1) * 10, lastValue + change)));
// Shift the data points of each series to the left
if (stockData.length > POINTS) {
stockData.shift();
}
}
}
Check out the source code of your example for the full source code and use the dojo to test our their code and play around with it easily
Hello stackoverflow community,
is it somehow possible to disable the sorting mechanism in a grid for every column on a condition? Like...
if the grid hasn't any data loaded,
the sorting should be disabled,
else enabled.
I have the problem that if there is no data and you click on a column to sort, the remote sorting mechanism, will start loading the whole data and sorts it, too ...
This behaviour isn't needed or wished, so I want to disable the sorting possibility.
Your help is appreciated.
Thanks in advance and have a nice day.
This is a bit of a hack, but seems to work OK:
http://jsfiddle.net/q43HC/6/
var data = [{
data1: 'test',
data2: 'test'
}, {
data1: 'test2',
data2: 'test2'
}];
var store = Ext.create('Ext.data.Store', {
fields: ['data1', 'data2'],
data: data
});
Ext.define('SampleGrid', {
extend: 'Ext.grid.Panel',
store: store,
height: 250,
width: 400,
title: 'My Window',
columns: [{
text: 'test',
dataIndex: 'data1'
}, {
text: 'test2',
dataIndex: 'data2'
}],
bbar: [{
text: 'Clear Store',
handler: function() {
store.removeAll();
var grid = this.up('grid'),
cols = grid.query('gridcolumn'),
i = 0,
len = cols.length;
for (; i < len; i++) {
cols[i].doSort(null);
cols[i].__toggleSortState = cols[i].toggleSortState;
cols[i].toggleSortState = function() {};
}
}
}, {
text: 'Reload Store',
handler: function() {
store.loadData(data);
var grid = this.up('grid'),
cols = grid.query('gridcolumn'),
i = 0,
len = cols.length;
for (; i < len; i++) {
if (cols[i].__toggleSortState) {
cols[i].toggleSortState = cols[i].__toggleSortState;
}
}
}
}],
renderTo: Ext.getBody()
});
Ext.onReady(function() {
var grd = new SampleGrid();
});
I am just changing the sort state when the data is removed in order to remove any current sorting then replacing the toggleSortState function with an empty one so clicking the header will not sort the column. When reloading the store I put the function back.. You will have to adapt this to your project, but could create a store aware grid with similar logic.
You can do this globally by overriding the Ext.data.Store.sort method. The system I was working on uses remoteSort and hence hits the server everytime the user clicks the column header to sort, even if the grid itself is empty, pretty much same with your problem.
This is the code that you only need to declare in a single location (ie. your ext-overrides file or commons file), instead of in every single grid:
Ext.define('Ext.overrides.data.Store', {
override: 'Ext.data.Store',
sort: function() {
//prevents the grid from submitting a request if store is empty, for remote sort
if (this.count() > 0) {
this.callParent(arguments);
}
}
});
I have written the following function to achieve the same solution:
function disableColumnSorting(disable){
var grid = Ext.getCmp('billRecordGrid'),
cols = grid.query('gridcolumn'),
colLength = cols.length,
i = 0;
for(i; i < colLength; i++) {
if (disable) {
cols[i].sortable= false;
} else {
cols[i].sortable= true;
}
}
}
Thanks to drew630, you gave me a helpful hint, so I could solve my problem on my own.
If you do not want anything to happen when the grid is empty, you could put this in the store of the grid:
listeners: {
beforeload: function() {
return false when my conditions is met.;
}
}
This way your store will not load and nothing will happen. This is also handy when you have a pager component on the grid and where your server expects e.g. extraParams that are not yet set. If you expect extraParams, and when not yet set, the user clicks the refresh on the pager, you end up with exceptions. But with this check, you can prevent a call to the back-end if conditions are not met.
I sometimes set my api.read URL to undefined, (in cases where the store needs extraParams that are not yet set) and only when those params are available, I also set the URL (with a call in the store itself where the url is already set e.g. activateRead(). In the beforeload, I then test if the api.read is undefined or not.
Hope it helps.
Regards
Lawrende
I tried to find several places how this work but could not.
The requirement is to drill down by clicking on the slice of the pie to next level. I can get the onclick even but not sure how to get the value from the chart. Everywhere it is pointing to http://www.sitepen.com/blog/2008/05/27/dojo-charting-event-support-has-landed/ but nowhere any live demo is given. Till now i have managed to get the onclick.
chart.addSeries("Monthly Sales - 2010", chartData);
var h = chart.connectToPlot("default", function(o){
if(o.type == "onclick"){
alert("clicked!");
}
});
var store = new dojo.store.Memory({data: [
{ id: '2', value: 10, usedForDrillDown:'x' },
{ id: '3', value: 5, usedForDrillDown: 'y' },
{ id: '4', value: 8, usedForDrillDown:'z' }
]});
// adapter needed, because the chart uses the dojo.data API
var storeAdapter = new dojo.data.ObjectStore({
objectStore: store
});
var ds = new dojox.charting.DataSeries(
storeAdapter/*, { query: { needed if the store contains more than data points } }*/);
var chart = new dojox.charting.Chart("chart");
chart.addPlot("default", { type: "Pie" });
chart.addSeries("default", ds);
chart.connectToPlot("default", function(evt) {
if(evt.type == "onclick"){
var itm = evt.run.source.items[evt.index];
console.dir(itm);
}
});
chart.render();
I have data of matrix stored in table as below tables:
MatrixDimensions - MatrixId, NoOfRows, NoOfCol
MatrixValues - MatrixId, RowNo, ColNo, Value
How can I make jqGrid to take no. of rows & columns dynamically
and also display the serialized data in matrix? Is there a direct way or will I have to implement for loops to upload the data in matrix?
Can I display rows as columns and columns as rows (so having column headers vertically aligned)?
Can I enable only inline editing and disable form based editing?
I just wrote the answer to another question where I described how to create the grid with dynamic number of columns (number of rows is always dynamic in jqGrid). It seems to me this way you can display any matrix. In you case you can probably make the code simpler because you can use generic column names like "1", "2", etc. (or "Col. 1", "Col. 2", etc.) and so on.
I modified the code so that it uses array of arrays (matrix) instead of the array on objects with named properties. So jqGrid will looks like this:
or this:
depending on the input JSON data.
The full demo can be found here. The full JavaScript code of the demo you can find below:
var mygrid=jQuery("#list"),
cmTxtTemplate = {
width:40,
align:"center",
sortable:false,
hidden:true
}, currentTemplate = cmTxtTemplate, i,
cm = [], maxCol = 30, dummyColumnNamePrefix = "", //"Col. ",
clearShrinkToFit = function() {
// save the original value of shrinkToFit
var orgShrinkToFit = mygrid.jqGrid('getGridParam','shrinkToFit');
// set shrinkToFit:false to prevent shrinking
// the grid columns after its showing or hiding
mygrid.jqGrid('setGridParam',{shrinkToFit:false});
return orgShrinkToFit;
},
setGridWidthAndRestoreShrinkToFit = function(orgShrinkToFit,width) {
// restore the original value of shrinkToFit
mygrid.jqGrid('setGridParam',{shrinkToFit:orgShrinkToFit});
mygrid.jqGrid('setGridWidth',width);
},
dummyTestRegex = new RegExp(dummyColumnNamePrefix+"(\\d)+"),
counter = 1;
// Add dummy hidden columns. All the columns has the same template
for (i=0;i<maxCol;i++) {
cm.push({name:dummyColumnNamePrefix+(i+1),template:currentTemplate});
}
mygrid.jqGrid({
url:'Matrix1.json',
datatype: "json",
// colNames will be set based on the properties for JSON input
colModel:cm,
height:"auto",
rownumbers:true,
loadonce:true,
gridview: true,
rowNum: 1000,
sortname:"",
jsonReader: {
cell: "",
id: function (obj) {
return "id"+counter++;
},
page: function (obj) {
var rows = obj.rows, colModel = mygrid[0].p.colModel,
cmi, width = 0, iFirstDummy, cols, orgShrinkToFit,
showColNames = [], hideColNames = [];
if (typeof(rows) === "undefined" || !(rows.length>0)) {
// something wrong need return
return obj.page;
}
// find the index of the first dummy column
// in the colModel. If we use rownumbers:true,
// multiselect:true or subGrid:true additional
// columns will be inserted at the begining
// of the colModel
iFirstDummy = -1;
for(i=0;i<colModel.length;i++) {
cmi = colModel[i];
if (dummyTestRegex.test(cmi.name)) {
iFirstDummy = i;
break;
}
}
if (iFirstDummy === -1) {
// something wrong need return
return obj.page;
}
orgShrinkToFit = clearShrinkToFit();
// we get the first row of the JSON data
cols = rows[0].length;
// fill the list of unused columns
for(i=0;i<colModel.length;i++) {
cmi = colModel[i];
if (i<iFirstDummy+cols) {
cmi.width = currentTemplate.width;
showColNames.push(cmi.name);
} else {
hideColNames.push(cmi.name);
}
}
mygrid.jqGrid('showCol',showColNames);
mygrid.jqGrid('hideCol',hideColNames);
setGridWidthAndRestoreShrinkToFit(orgShrinkToFit,
cols*currentTemplate.width);
return obj.page;
}
}
});
$("#readJson1").click(function() {
mygrid.jqGrid('setGridParam',
{datatype:'json',page:1,url:'Matrix1.json'})
.trigger('reloadGrid');
});
$("#readJson2").click(function() {
mygrid.jqGrid('setGridParam',
{datatype:'json',page:1,url:'Matrix2.json'})
.trigger('reloadGrid');
});
The simplest way to transpose the matrix (reflect it over its main diagonal) is on the server. If you can't do this, you can create and fill the transposed matrix inside of page function (see my code above) and just replace the row part of the obj with the transposed matrix.