I have created a chart with a subchart with the C3.js library. I used:
subchart:{
show:true
onbrush: function (domain) {
test = chart.internal.filterByXDomain(chart.data(),domain);
},
}
How can I generate a dinamic table with the values into the object "test"?
You can build the HTML and set it to one of the elements
...
onbrush: function (domain) {
var test = chart.internal.filterByXDomain(chart.data(), domain);
var table = '<table><tr><th>x</th><th>y</th></tr>';
test[0].values.forEach(function(e) {
table += '<tr><td>' + e.x + '</td><td>' + e.value + '</td></tr>'
})
table += '</table>';
document.getElementById("range").innerHTML = table;
}
where you have a an element with ID range
Fiddle - http://jsfiddle.net/e3esfsd6/
Related
I'm trying to adapt the nice solution I found here:
How to place an icon inside Google ColumnChart
to insert images on top of chart bars.
I'm using VueJS to dynamically create my Google charts.
HTML Code :
<GChart type="BarChart" id="villesChart" ref="villesChart" :data="dataprox" :options="optionsprox" :events="eventsprox">
then I populate my chart in my VueJS app:
var result_a = [
[
"Ville",
"Prix au m2",
{ role: "annotation" },
{ role: "style" },
{ role: "code_commune" },
],
];
/*data from sql query*/
for (var ligne in reponse) {
result_a.push([
reponse[ligne].ville,
parseInt(reponse[ligne].prix),
reponse[ligne].prix + " €/m2",
"color: " + couleur,
reponse[ligne].code_commune,
]);
}
The proposed solution to insert icons is the following (extract):
var container = document.getElementById('chart_div');
var containerBounds = container.getBoundingClientRect();
var chart = new google.visualization.ColumnChart(container);
google.visualization.events.addListener(chart, 'ready', function () {
var chartLayout = chart.getChartLayoutInterface();
for (var i = 0; i < data.getNumberOfRows(); i++) {
var barBounds = chartLayout.getBoundingBox('bar#0#' + i);
var path = 'http://findicons.com/files/icons/512/star_wars/32/';
var thumb = container.appendChild(document.createElement('img'));
thumb.src = path + data.getProperty(i, 0, 'thumb');
thumb.style.position = 'absolute';
thumb.style.top = (barBounds.top + containerBounds.top - 40) + 'px';
thumb.style.left = (barBounds.left + containerBounds.left + (barBounds.width / 2) - 16) + 'px';
}
});
chart.draw(data, options);
How do I adapt that code in VueJS context? I don't know how to get the chart element and where I should insert my code (mounted?).
Thanks a lot for your help!
Alex
I populate the table with an ajax call. In the first column I have checkboxes for selecting and deselecting rows and submit data to a php script. I have also two columns with select fields.
The render function for the one (of the two) column with select:
{
targets: 6,
render: function(data, type, full, meta) {
if(data.length == 4) {
return '<select class="form-control" id="selectotpionmonths' + data[0].cataloguenumber + '"><option value="'+ data[3].months
+ '">' + data[3].months + '<option value="'+ data[2].months
+ '">' + data[2].months + '<option value="'+ data[1].months
+ '">' + data[1].months + '<option value="'+ data[0].months
+ '">' + data[0].months + '</select>';
} else {
return data[0].months;
}
}
},
And the handler for click event and on change event:
$('#results tbody').on('click', 'input[type="checkbox"]', function(e){
var $row = $(this).closest('tr');
// Get row data
var data = table.row($row).data();
$('#selectotpionmonths' + data['enc_unit']).change(function(){
e.preventDefault();
var selectedoptionformonths = $('#selectotpionmonths' + data['enc_unit']).find("option:selected").text();
if(selectedoptionformonths == 3) {
$('#selectoptionprice' + data['enc_unit']).find('option[value="' + data['price_rrp'][3].price + '"]').prop('selected', true);
} else if(selectedoptionformonths == 6) {
$('#selectoptionprice' + data['enc_unit']).find('option[value="' + data['price_rrp'][2].price + '"]').prop('selected', true);
} else if(selectedoptionformonths == 9) {
$('#selectoptionprice' + data['enc_unit']).find('option[value="' + data['price_rrp'][1].price + '"]').prop('selected', true);
} else if(selectedoptionformonths == 12) {
$('#selectoptionprice' + data['enc_unit']).find('option[value="' + data['price_rrp'][0].price + '"]').prop('selected', true);
}
});
if(data['price_numberofmonths'].length == 4) {
var monthsoption = $('#selectotpionmonths' + data['enc_unit']).find("option:selected").text();
var priceoption = $('#selectoptionprice' + data['enc_unit']).find("option:selected").text();
} else {
var monthsoption = data['price_numberofmonths'][0].months;
var priceoption = data['price_rrp'][0].price;
}
// Get row ID
var dataforserver = {name: data['enc_unit'], duration: monthsoption, price: priceoption};
var rowId = dataforserver.name;
// Determine whether row ID is in the list of selected row IDs
var index = $.inArray(rowId, rows_selected);
// If checkbox is checked and row ID is not in list of selected row IDs
if(this.checked && index === -1){
rows_selected.push(rowId);
units_selected.push(dataforserver);
// Otherwise, if checkbox is not checked and row ID is in list of selected row IDs
} else if (!this.checked && index !== -1){
rows_selected.splice(index, 1);
units_selected.splice(index, 1);
}
if(this.checked){
$row.addClass('selected');
} else {
$row.removeClass('selected');
}
order_total = 0;
for(i=0; i < units_selected.length; i++) {
order_total += parseFloat(units_selected[i].price);
}
//console.log(order_total.toFixed(2));
$( "#ukhoanswer" ).html(
"Number of units selected: " + units_selected.length + "<br/>" +
"Total cost of order: " + order_total.toFixed(2)
);
// Update state of "Select all" control
updateDataTableSelectAllCtrl(table);
// Prevent click event from propagating to parent
e.stopPropagation();
});
// Handle click on table cells with checkboxes
$('#results').on('click', 'tbody td, thead th:first-child', function(e){
$(this).parent().find('input[type="checkbox"]').trigger('click');
});
// Handle click on "Select all" control
$('thead input[name="select_all"]', table.table().container()).on('click', function(e){
if(this.checked){
$('#results tbody input[type="checkbox"]:not(:checked)').trigger('click');
} else {
$('#results tbody input[type="checkbox"]:checked').trigger('click');
}
// Prevent click event from propagating to parent
e.stopPropagation();
});
You may view the initial code for the checkboxes here
When I click on the cell with the select field I want to prevent the click event on the row. I have tried adding e.preventDefault but with no success. For the columns with the select option I want only the change event to be triggered.
Any ideas?
I did the following:
var selectField = $('.form-control');
selectField.on('click', function(event) {
event.stopPropagation();
});
The selector are for the cells with the select options. Now the first time that I click on the select field the row is selected. But next time I select an option the click event is prevented and the row is not selected/deselected.
I am looking on how to prevent the row being selected on the first click on a select field.
I have a Google Fusion Table containing a land parcels layer. Each parcel is assigned an ARN number. I am trying to create a search box where one can type in the ARN number and it will select and hopefully zoom to that parcel. I'm new to java script and am unsure as to why my search box is not working. The Fusion table has a 'geometry' column containing the spatial information and 'ARN' column is a 'number' field containing the ARN numbers. Here is my code.
function changeMapl0() {
var searchString = document.getElementById('search-string-l').value.replace(/'/g, "\\'");
layer.setOptions({
query: {
select: 'geometry',
from: 'tableID',
where: "'ARN' CONTAINS IGNORING CASE '" + searchString + "'"
}
});
}
<body>
<div style="margin-top: 10px;">
<label>Enter Roll Number</label><input type="text" id="search-string-l">
<input type="button" onclick="changeMapl0()" value="Search">
</div>
</body>
Any help would be appreciated.
Thanks;
Matt
You would probably want to do something like this, you will have to call a zoom2query function. You will want to probably want to calculate the lat and long of the centroid of parcel for zoom functionality, make sure to call you geometry column column on the map so you don't have the points.
function changeMap() {
var searchString = document.getElementById('search').value.replace("'", "\\'");
if(searchString == "") {
var query="SELECT 'Lat' FROM " + tableid;
}
else {
var query="SELECT 'Lat' FROM " + tableid + " WHERE 'PARCEL_ID' = '" + searchString + "'";
}
// layer.setQuery(query);
if(searchString == "") {
var query="SELECT 'Lat','Long' FROM " + tableid;
}
else {
var query="SELECT 'Lat','Long' FROM " + tableid + " WHERE 'ARN' = '" + searchString + "'";
}
zoom2query(query);
}
var infowindow = new google.maps.InfoWindow();
function zoom2query(query) {
// zoom and center map on query results
//set the query using the parameter
document.getElementById("query").innerHTML = query;
var queryText = encodeURIComponent(query);
var query = new google.visualization.Query('https://www.google.com/fusiontables/gvizdata?tq=' + queryText);
//set the callback function
query.send(zoomTo);
}
function zoomTo(response) {
if (!response) {
alert('no response');
return;
}
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
numRows = response.getDataTable().getNumberOfRows();
numCols = response.getDataTable().getNumberOfColumns();
var lat = response.getDataTable().getValue(0,0);
var lng = response.getDataTable().getValue(0,1);
var zoom_level = 19;
var location = new google.maps.LatLng(lat,lng);
map.setCenter(location);
map.setZoom(zoom_level);
}
Here is an example of what I have done, we have RP numbers but mine zooms to the parcel
https://googledrive.com/host/0B0J_A50xWBAqNHZqVlUxSkNUbWs/Shoshone.html
I'm building a chart with an accompanying table. The data for both comes from html input elements with data provided by the user. For now I'm just working on getting the table to update when the user clicks the submit button.
The first time the user clicks the submit button, the table displays correctly, however, on subsequent clicks the table is not updated, even though the underlying data is correctly updated (the global variable cashflows contains the user-entered data).
The code is shown below, but I also have a jsfiddle: http://jsfiddle.net/cyclical/xcGSu/5/
(selecting the Load Sample Data button will populate some sample data).
If the table updates correctly on the first click, doesn't that indicate that the data is bound correctly to the DOM?
Thanks,
Neil
var dollars = d3.format(",.2f");
function sampleData() {
d3.select("#cf1")[0][0].value=50000;
d3.select("#dt1")[0][0].value = "2007-05-10";
d3.select("#cf2")[0][0].value = 20000;
d3.select("#dt2")[0][0].value = "2011-01-11";
d3.select("#cf3")[0][0].value = 50000;
d3.select("#dt3")[0][0].value = "2012-07-19";
d3.select("#cf4")[0][0].value = 40000;
d3.select("#dt4")[0][0].value = "2012-08-03";
d3.select("#endMV")[0][0].value = 190551.29 ;
d3.select("#endDate")[0][0].value = "2013-09-30";
}
d3.select("#sample")
.on("click", sampleData);
var cashflows = [];
var total = 0;
var irr = 0;
// bind the cashflows array to a table for display
var column_titles = ['Date','Cashflow','Days','IRR Cashflow'];
var columns = ['date','cf','days','irr_cashflow'];
d3.select("#results").selectAll('table').data([0]).enter().append('table');
var table = d3.select('table');
table.selectAll('thead').data([0]).enter().append('thead');
var thead = table.select('thead');
table.selectAll('tbody').data([0]).enter().append('tbody');
var tbody = table.select('tbody');
table.selectAll('tfoot').data([0]).enter().append('tfoot');
var tfoot = table.select('tbody');
// append the header row
thead.append("tr")
.selectAll("th")
.data(column_titles)
.enter()
.append("th")
.attr("align", function(d) {if (d=='Date') { return "left"} else { return "right"}})
.text(function(column) { return column; });
function calculateIRR(){
cashflows = [];
var cfvalues = [];
var cfdates = [];
// get cashflows
d3.selectAll("input.cashflow")[0]
.forEach(function(d,i) {
if (d.value) {cfvalues.push( 1 * d.value )};
}
)
// get dates
d3.selectAll("input.cfdate")[0]
.forEach(function(d,i) {
if (d.value) {cfdates.push( d.value)};
}
)
// get ending MV and associated date; MV is multiplied by -1
cfvalues.push(-1 * d3.select("#endMV")[0][0].value);
cfdates.push(d3.select("#endDate")[0][0].value);
// convert date strings to date objects
var dates = cfdates.map(function(d) { return new Date(d.replace(/-/g, "/"))});
// calculate the IRR; use 5% as starting value
var rate = XIRR(cfvalues ,dates, .05);
irr = rate;
var r = d3.select("#ratedisplay").selectAll("div")
.data([rate])
.enter()
.append("div")
.attr("class","rate")
.text(function(d,i) {return "IRR: " + d}); //{return "IRR:" + dollars(d) + ""});
var len = cfvalues.length;
var last_day = dates[len -1];
// construct final cashflow array for binding
for (var i = 0; i < len; i++) {
var cf_days = moment(last_day).diff(moment(dates[i]), 'days');
var irr_cashflow = FV(rate, cf_days/365 , 0, cfvalues[i],0);
total += irr_cashflow;
cashflows.push(
{'cf': cfvalues[i], 'date': dates[i], 'days' : cf_days, 'irr_cashflow': irr_cashflow}
);
};
var rows = tbody.selectAll("tr")
.data(function(d) {return cashflows} )
.enter()
.append("tr");
var cells = rows.selectAll("td")
.data(function(row) {
return columns.map(function(column) {
return {'name': column, 'value': row[column]};
});
})
.enter()
.append("td")
.attr("align",function(d) {
if (d.name == 'date') { return "left" } else {return "right"}
})
.html(function(d) {
if (d.name == 'date') {
return d3.time.format("%Y-%m-%d")(d.value);
} else {
return dollars(d.value);
}
});
rows.exit().remove();
cells.exit().remove();
}
d3.select("#submit")
.on("click", calculateIRR);
I have a scenario with grid within grid implemented using the detailInit method. Here when user makes edit, i do some calculations that will change the data in the both parent and child. and then to refresh data, i will call the datasource.read to render data. this works and the data is displayed, however any detail grid which are expanded will be collapsed, is there any way i can prevent this from happening.
To answer this and another question:
"I figured out how to set the data in the master from the child BUT, the
whole table collapses the child grids when anything is updated, this is a
very annoying behavior, is there anyway I can just update a field in
the master table without it collapsing all the child elements?
(basically, update the column, no mass table update)"
in another thread at: telerik
This is extremely annoying behavior of the Kendo Grid and a major bug. Since when does a person want the sub-grid to disappear and hide a change that was just made! But this isn't the only problem; the change function gets called a Fibonacci number of times, which will freeze the browser after a significant number of clicks. That being said, here is the solution that I have come up with:
In the main grid
$('#' + grid_id).kendoGrid({
width: 800,
...
detailExpand: function (e) {
var grid = $('#' + grid_id).data("kendoGrid");
var selItem = grid.select();
var eid = $(selItem).closest("tr.k-master-row").attr('data-uid')
if (contains(expandedItemIDs, eid) == false)
expandedItemIDs.push(eid);
},
detailCollapse: function (e) {
var grid = $('#' + grid_id).data("kendoGrid");
var selItem = grid.select();
var eid = $(selItem).closest("tr.k-master-row").attr('data-uid')
for (var i = 0; i < expandedItemIDs.length; i++)
if (expandedItemIDs[i] == eid)
gridDataMap.expandedItemIDs.splice(i, 1);
},
Unfortunately globally we have:
function subgridChange() {
var grid = $('#' + grid_id).data("kendoGrid");
for (var i = 0; i < expandedItemIDs.length; i++)
grid.expandRow("tr[data-uid='" + expandedItemIDs[i] + "']");
}
function contains(a, obj) {
for (var i = 0; i < a.length; i++)
if (a[i] === obj) return true;
return false;
}
expandedItemIDs = [];
Now the 'subgridChange()' function needs to be called every time a change is made to the subgrid.
The problem is that the number of times the change function in the subgrid gets called increases exponentially on each change call. The Kendo grid should be able to call a stop propagation function to prevent this, or at least give the programmer access to the event object so that the programmer can prevent the propagation. After being completely annoyed, all we have to do is to place the 'subgridChange()' function in the subgrid 'datasource' like so:
dataSource: function (e) {
var ds = new kendo.data.DataSource({
...
create: false,
schema: {
model: {
...
}
},
change: function (e) {
subgridChange();
}
});
return ds;
}
I also had to place the 'subgridChange()' function in the Add button function using something like this
$('<div id="' + gridID + '" data-bind="source: prodRegs" />').appendTo(e.detailCell).kendoGrid({
selectable: true,
...
toolbar: [{ template: "<a class='k-button addBtn' href='javascript://'><span class='k-icon k-add' ></span> Add Product and Region</a>" }]
});
$('.addBtn').click(function (event) {
...
subgridChange();
});
When a user selects a row, record the index of the selected row. Then after your data refresh, use the following code to expand a row
// get a reference to the grid widget
var grid = $("#grid").data("kendoGrid");
// expands first master row
grid.expandRow(grid.tbody.find(">tr.k-master-row:nth-child(1)"));
To expand different rows, just change the number in the nth-child() selector to the index of the row you wish to expand.
Actually all that is needed is the 'subgridChange()' function in the main grid 'dataBound' function:
$('#' + grid_id).kendoGrid({
...
dataBound: function (e) {
gridDataMap.subgridChange();
}
});
Different but similar solution that i used for same problem:
expandedItemIDs = [];
function onDataBound() {
//expand rows
for (var i = 0; i < expandedItemIDs.length; i++) {
var row = $(this.tbody).find("tr.k-master-row:eq(" + expandedItemIDs[i] + ")");
this.expandRow(row);
}
}
function onDetailExpand(e) {
//refresh the child grid when click expand
var grid = e.detailRow.find("[data-role=grid]").data("kendoGrid");
grid.dataSource.read();
//get index of expanded row
$(e.detailCell).text("inner content");
var row = $(e.masterRow).index(".k-master-row");
if (contains(expandedItemIDs, row) == false)
expandedItemIDs.push(row);
}
function onDetailCollapse(e) {
//on collapse minus this row from array
$(e.detailCell).text("inner content");
var row = $(e.masterRow).index(".k-master-row");
for (var i = 0; i < expandedItemIDs.length; i++)
if (expandedItemIDs[i] == row)
expandedItemIDs.splice(i, 1);
}
function contains(a, obj) {
for (var i = 0; i < a.length; i++)
if (a[i] === obj) return true;
return false;
}