I'm trying find out a method or a way by which i can move handson tables scroll bar to specific row and column.
I tried using
selectCell (row: Number, col: Number, rows: Number, cols: Number, scrollToSelection: Boolean (Optional)) but it doesn't seems to work
here is the Fiddle link for it http://jsfiddle.net/hpfvc9bx/
$(document).ready(function () {
function createBigData() {
var rows = []
, i
, j;
for (i = 0; i < 1000; i++) {
var row = [];
for (j = 0; j < 6; j++) {
row.push(Handsontable.helper.spreadsheetColumnLabel(j) + (i + 1));
}
rows.push(row);
}
return rows;
}
var maxed = false
, resizeTimeout
, availableWidth
, availableHeight
, $window = $(window)
, $example1 = $('#example1');
var calculateSize = function () {
if(maxed) {
var offset = $example1.offset();
availableWidth = $window.width() - offset.left + $window.scrollLeft();
availableHeight = $window.height() - offset.top + $window.scrollTop();
$example1.width(availableWidth).height(availableHeight);
}
};
$window.on('resize', calculateSize);
var table = $example1.handsontable({
data: createBigData(),
colWidths: [55, 80, 80, 80, 80, 80, 80], //can also be a number or a function
rowHeaders: true,
colHeaders: true,
fixedColumnsLeft: 2,
fixedRowsTop: 2,
minSpareRows: 1,
stretchH: 'all',
contextMenu: true,
afterChange : function(changes){
console.log(changes);
}
});
$('.maximize').on('click', function () {
maxed = !maxed;
if(maxed) {
calculateSize();
}
else {
$example1.width(400).height(200);
}
$example1.handsontable('render');
});
$("#setSelectedRow").on('click',function(){
console.log(table);
table.select(9,3,12,6,true); // not working as it doesnt move scroll bar to specified column and range
})
function bindDumpButton() {
$('body').on('click', 'button[name=dump]', function () {
var dump = $(this).data('dump');
var $container = $(dump);
console.log('data of ' + dump, $container.handsontable('getData'));
});
}
bindDumpButton();
});
Can anyone please help me on this...
Thanks In advance...
You can move to specific cell using "selectCell" of handsontable.
You have use table.select(...) in $("#setSelectedRow").on('click',function(){....
It won't work as you are using table DOM element but you need to have "instance" of handsontable. That can be done as,
First Way:
var tblInstance = $example1.handsontable('getInstance');
And then apply "selectCell()" as
tblInstance.selectCell(rowNum, colNum);
Second Way:
Use $example1.handsontable("selectCell", rowNum, colNum);
Please refer to fiddle for the second way, in which :
$("#setSelectedRow").on('click',function(){
console.log(table);
$example1.handsontable("selectCell", 9, 5); // select 9th row's 5th column
})
Hope this will help you :)
Related
I am trying to display a stacked bar chart with dates as xAxis. it display the number of sport session by type of sport.
The idea is to have for a specific time range the number of sessions displayed. For example for the last 4 weeks, the number of sessions per day will be displayed, and for the last 12 weeks, it will display the number of sessions per week.
These values are being calculated and displayed fine. The issue is that they are displayed as a 1px wide bar, instead of a "wide" automatically calculated bar width.
If someone have an idea how this fix this kind of issue... please help!
Data are structured as follows. I only show concerned data
const sessions_summary = [
{
activity_name: 'regular_biking',
date_time: '2020-03-18T15:57:47.853Z',
// ...
},
{
activity_name: 'swimming',
date_time: '2020-03-18T15:57:47.853Z'
},
{
activity_name: 'running',
date_time: '2020-03-19T15:57:47.853Z'
},
// ...
];
Crossfilter:
const ndx = crossfilter(sessions_summary);
const Dimension = ndx.dimension(function(d) {
return d3.timeDay(new Date(d.date_time));
});
Scaletime:
const today = new Date(new Date().toDateString());
const minDate = d3.timeDay(
new Date(
new Date().setDate(
today.getDate() - parseFloat(timeranges[timerange_name]) // 7 or 30 or 90 or 180 or 360 : number of days, depends on the interval selected in Select Entry
)
)
);
let maxDate = d3.timeDay(today);
maxDate = d3.timeDay.offset(maxDate, 1);
const scaletime = d3.scaleTime().domain([minDate, maxDate]);
Chart.x(scaletime);
const interval = intervals[timerange_name]; // d3.timeDay or d3.timeWeek or d3.timeMonth, depending on the choice made in Select Entry
Chart.xUnits(interval);
Group:
const types = [...new Set(sessions_summary.map(session => session.type))];
Group = Dimension.group(function(k) {
return interval(k);
}).reduce(
function(p, v) {
if (v.type in p.types) {
p.types[v.type]++;
} else {
p.types[v.type] = 1;
}
return p;
},
function(p, v) {
p.types[v.type]--;
if (p.types[v.type] === 0) {
delete p.types[v.type];
}
return p;
},
function() {
return {
types: {}
};
}
);
Chart.group(Group, types[0], sel_stack(types[0])).render();
for (let i = 1; i < types.length; i++) {
Chart.stack(Group, types[i], sel_stack(types[i]));
}
Bar Chart:
const Chart = dc.barChart('#sessions_chart');
Chart.width(968)
.height(240)
.elasticY(true)
.margins({
left: 40,
top: 10,
right: 20,
bottom: 40
})
.gap(5)
.centerBar(true)
.round(d3.timeDay.round)
.alwaysUseRounding(true)
.xUnits(d3.timeDays)
.brushOn(false)
.renderHorizontalGridLines(true)
.renderVerticalGridLines(false)
.dimension(Dimension)
.title(d => {
return (
'Date: ' +
new Date(d.key).toDateString() +
'\n' +
'Sessions: ' +
Object.keys(d.value.types)
);
});
Chart.legend(
dc
.legend()
.x(40)
.y(465)
.gap(10)
.horizontal(true)
.autoItemWidth(true)
);
Chart.render();
Complete code can be found on JSFiddle
Thanks in advance
[SOLVED]
The issue was the double xUnits, and the wrong use of d3.TimeDay instead of d3.TimeDays.
How can we allow the users to only select one row per group?
I have the following code.
var data = [
{ ActionItemId: "AAZ08702-0001104", StrarTime: "2007-10-01", Category: "General", CategoryDetails: "dummy text of industry. a galley of type ", TargetCategory: "200.00",
TargetDateCategory: "10.00", ActualCategory: "210.00"}
];
$("#jqGrid").jqGrid({
data: data,
datatype: "local",
colModel: [
{ label: 'Action Item ID', name: 'ActionItemId', key: true },
{ label: 'Start Time', name: 'StrarTime'},
{ label: 'Category', name: 'Category'},
{ label: 'Details', name: 'CategoryDetails', cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal;"' }},
{ label: 'Target <Category>', name: 'TargetCategory' },
{ label: 'Target Date <Category>', name: 'TargetDateCategory'}
],
loadonce: true,
viewrecords: true,
//width: 1000,
height: 400,
rowNum: 20,
rowList: [20, 30, 50],
rownumbers: true,
rownumWidth: 25,
multiselect: true,
shrinkToFit: false,
pager: "#jqGridPager",
grouping: true,
groupingView: {
groupField: ["Category"],
groupColumnShow: [true],
groupText: ["Category: <b>{0}</b>"],
groupOrder: ["asc"],
groupSummary: [false],
groupCollapse: false
}
});
I need to disable the ability to select multiple rows per column. is it possible?
Is there a setting in the grouping function to enable which will work as mu requirement? or should it be custom development?
Note: I have only added one column to avoid a very long code in the question
One of the possible implementation could be adding add callback which return false if another row from the same group is already selected. An example of the implementation is the following:
beforeSelectRow: function (rowid, e) {
var selarrrow = $(this).jqGrid("getGridParam", "selarrrow"),
$tr = $(e.target).closest("tr.jqgrow"),
otherIdsOfTheGroup;
if ($tr.length > 0) {
otherIdsOfTheGroup =
// get all rows of the group before the current
$tr.prevUntil("tr.jqgroup")
// add all rows of the group after the current
.add($tr.nextUntil("tr.jqgroup"))
// enum all the rows of the group without the current
.map(function () {
// test whether the rowid is already selected
if ($.inArray(this.id, selarrrow) >= 0) {
// add the rowid to the array of returned values
return this.id;
}
});
// otherIdsOfTheGroup contains the array of rowids of the rows
// from the same group, which are already selected
if (otherIdsOfTheGroup.length > 0) {
return false; // prevent selection
}
}
return true; // allow selection
}
See the demo
UPDATED: One can easy modify the aboce vode to unselect the previously selected rows from the same group. One need just call resetSelection for every rowid from otherIdsOfTheGroup array and return true from otherIdsOfTheGroup to allow selection:
beforeSelectRow: function (rowid, e) {
var $this = $(this),
selarrrow = $this.jqGrid("getGridParam", "selarrrow"),
$tr = $(e.target).closest("tr.jqgrow"),
otherIdsOfTheGroup;
if ($tr.length > 0) {
otherIdsOfTheGroup =
// get all rows of the group before the current
$tr.prevUntil("tr.jqgroup")
// add all rows of the group after the current
.add($tr.nextUntil("tr.jqgroup"))
// enum all the rows of the group without the current
.map(function () {
// test whether the rowid is already selected
if ($.inArray(this.id, selarrrow) >= 0) {
// add the rowid to the array of returned values
return this.id;
}
});
// otherIdsOfTheGroup contains the array of rowids of the rows
// from the same group, which are already selected
if (otherIdsOfTheGroup.length > 0) {
$.each(otherIdsOfTheGroup, function () {
$this.jqGrid("resetSelection", this);
});
}
}
return true; // allow selection
}
See the next demo. I included hiding of the column header of "Select All" button just to write less code. You can implement onSelectAll callback and allow to select only one (for example the first) row from every group.
I managed to solve this issue using the following code.
beforeSelectRow: function (id, e) {
var rowdata = $("#jqGrid").getRowData(id);
var category = rowdata.Category;
var selectedRowTR = $("#jqGrid").find("tr[id='" + id + "']");
var groupTRs = $("#jqGrid").find("tbody> tr.jqgrow > td[title='" + category + "']").parents("tr");
var ids = groupTRs.map(function () {
return this.id;
}).get();
var selectedIDs = $("#jqGrid").getGridParam("selarrrow");
var commonValues = [];
var i, j;
var arr1Length = ids.length;
var arr2Length = selectedIDs.length;
for (i = 0; i < arr1Length; i++) {
for (j = 0; j < arr2Length; j++) {
if (ids[i] === selectedIDs[j]) {
commonValues.push(ids[i]);
}
}
}
for (var i = 0; i < commonValues.length; i++) {
$("#jqGrid").jqGrid('setSelection', commonValues[i], false);
}
return true;
},
rowdata.Category; is the variable which the table is grouped. The only issue is that the user cannot untick what he/she has already selected in a group. so it works like a radio button set. But it works for my requirement.
hopefully we can improve this and introduce radio kind of behavior for grouping in jqgrid.
thanks everyone.
I'm working with a Kendo treelist widget, and disappointed to see there's no rowTemplate option as there is on the Kendo grid.
I see a columnTemplate option (i.e. http://docs.telerik.com/kendo-ui/api/javascript/ui/treelist#configuration-columns.template ), but this will affect the entire column.
However, I need to drill into each cell value and set a css color property based on a ratio ( i.e. If value/benchmark < .2, assign <span style='color:red;'> , but my color value is dynamic.
There's a dataBound: and dataBinding: event on the treelist, but I'm still trying to figure out how to intercept each cell value and set the color once I've done my calculation.
var treeOptions = {
dataSource: ds,
columns: colDefs,
selectable: true,
scrollable: true,
resizable: true,
reorderable: true,
height: 320,
change: function (e) {
// push selected dataItem
var selectedRow = this.select();
var row = this.dataItem(selectedRow);
},
dataBound: function (e) {
console.log("dataBinding");
var ds = e.sender.dataSource.data();
var rows = e.sender.table.find("tr");
}
};
and this is where I'm building out the `colDefs' object (column definitions):
function parseHeatMapColumns(data, dimId) {
// Creates the Column Headers of the heatmap treelist.
// typeId=0 is 1st Dimension; typeId=1 is 2nd Dimension
var column = [];
column.push({
"field": "field0",
"title": "Dimension",
headerAttributes: { style: "font-weight:" + 'bold' + ";" },
attributes : { style: "font-weight: bold;" }
});
var colIdx = 1; // start at column 1 to build col headers for the 2nd dimension grouping
_.each(data, function (item) {
if (item.typeId == dimId) {
// Dimension values are duplicated, so push unique values (i.e. trade types may have dupes, whereas a BkgLocation may not).
var found = _.find(column, { field0: item.field0 });
if (found == undefined) {
column.push({
field: "field2",
title: item.field0,
headerAttributes: {
style: "font-weight:" + 'bold'
}
,template: "<span style='color:red;'>#: field2 #</span>"
});
colIdx++;
}
}
});
return column;
}
**** UPDATE ****
In order to embed some logic within the template :
function configureHeatMapColumnDefs(jsonData, cols, model) {
var colDef = '';
var dimId = 0;
var colorProp;
var columns = kendoGridService.parseHeatMapColumns(jsonData, dimId);
// iterate columns and set color property; NB: columns[0] is the left-most "Dimension" column, so we start from i=1.
for (var i = 1; i <= columns.length-1; i++) {
columns[i]['template'] = function (data) {
var color = 'black';
if (data.field2 < 1000) {
color = 'red';
}
else if (data.field2 < 5000) {
color = 'green';
}
return "<span style='color:" + color + ";'>" + data.field2 + "</span>";
};
}
return columns;
}
Advice is appreciated.
Thanks,
Bob
In the databound event you can iterate through the rows. For each row you can get the dataItem associated with it using the dataitem() method (http://docs.telerik.com/kendo-ui/api/javascript/ui/treelist#methods-dataItem)
Once you have the dataitem, calculate your ration and if the row meets the criteria for color, change the cell DOM element:
dataBound: function (e) {
var that = e.sender;
var rows = e.sender.table.find("tr");
rows.each(function(idx, row){
var dataItem = that.dataItem(row);
var ageCell = $(row).find("td").eq(2);
if (dataItem.Age > 30) {
//mark in red
var ageText = ageCell.text();
ageCell.html('<span style="color:red;">' + ageText + '</span>');
}
}
DEMO
UPDATE: you can also do this with a template:
$("#treelist").kendoTreeList({
dataSource: dataSource,
height: 540,
selectable: true,
columns: [
{ field: "Position"},
{ field: "Name" },
{ field: "Age",
template: "# if ( data.Age > 30 ) { #<span style='color:red;'> #= data.Age # </span> #}else{# #= data.Age # #}#"
}
],
});
DEMO
I am using google API to create charts. I am able to create OHLC(Candlestick) charts. But I want to add an overlay of Moving Average to it. Can anyone please guide me as to how I can do it?
Thanks in advance.
Here's an example of how to add a moving average line to a CandlestickChart:
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Low');
data.addColumn('number', 'Open');
data.addColumn('number', 'Close');
data.addColumn('number', 'High');
var low, open, close = 45, high;
for (var i = 0; i < 30; i++) {
open = close;
close += ~~(Math.random() * 10) * Math.pow(-1, ~~(Math.random() * 2));
high = Math.max(open, close) + ~~(Math.random() * 10);
low = Math.min(open, close) - ~~(Math.random() * 10);
data.addRow([new Date(2014, 0, i + 1), low, open, close, high]);
}
// use a DataView to calculate an x-day moving average
var days = 5;
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, 2, 3, 4, {
type: 'number',
label: days + '-day Moving Average',
calc: function (dt, row) {
// calculate average of closing value for last x days,
// if we are x or more days into the data set
if (row >= days - 1) {
var total = 0;
for (var i = 0; i < days; i++) {
total += dt.getValue(row - i, 3);
}
var avg = total / days;
return {v: avg, f: avg.toFixed(2)};
}
else {
// return null for < x days
return null;
}
}
}]);
var chart = new google.visualization.ComboChart(document.querySelector('#chart_div'));
chart.draw(view, {
height: 400,
width: 600,
chartArea: {
left: '7%',
width: '70%'
},
series: {
0: {
type: 'candlesticks'
},
1: {
type: 'line'
}
}
});
}
google.load("visualization", "1", {packages:["corechart"], callback: drawChart});
see it working here: http://jsfiddle.net/asgallant/74u6ox8b/
I have a sample fiddle here in which the Google visualization Category Filter control is created as,
var countryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnIndex': 0,
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var regionPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnIndex': 1,
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var cityPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control3',
'options': {
'filterColumnIndex': 2,
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
Here We can select the filter in any combination. But, If I directly select Albany in CityPicker control then, how can I get its parent's values (ie, The value USA from countryPicker and the value New York from regionPicker) in which that particular city belongs to?
You can use a statechange event handler to get the current city, and then filter the DataTable by city to get the region and country combo(s) that correspond to that city. Here's an example:
google.visualization.events.addListener(cityPicker, 'statechange', function () {
var state = cityPicker.getState();
if (state.selectedValues.length) {
// there is a selected city
// since you set allowMultiple to false, there can be only one, so it is safe to do this:
var city = state.selectedValues[0];
var rows = data.getFilteredRows([{column: 2, value: city}]);
// parse the rows for all country/region/state combos
var regionsCountries = [];
var comboChecker = {};
for (var i = 0; i < rows.length; i++) {
var country = data.getValue(rows[i], 0);
var region = data.getValue(rows[i], 1);
// the comboChecker makes sure we don't add a region/country combo more than once to the data set
if (!comboChecker[region + country]) {
comboChecker[region + country] = true;
regionsCountries.push({region: region, country: country});
}
}
// do something with regionsCountries
}
});
See working example here: http://jsfiddle.net/asgallant/KLhD3/1/