본문 바로가기

엉터리 개발 이야기

Paging table

반응형
import d3 from 'd3';
import dt from 'datatables.net-bs';
import 'datatables.net-bs/css/dataTables.bootstrap.css';

import { fixDataTableBodyHeight, d3TimeFormatPreset } from '../javascripts/modules/utils';
import './table.css';

const $ = require('jquery');

dt(window, $);

function pagingTableVis(slice, payload) {
const container = $(slice.selector);
const fC = d3.format('0,000');

//const data = payload.data;
const fd = slice.formData;

let metrics = fd.metrics || [];
// Add percent metrics
metrics = metrics.concat((fd.percent_metrics || []).map(m => '%' + m));
// Removing metrics (aggregates) that are strings
//metrics = metrics.filter(m => !isNaN(data.records[0][m]));
/*
function col(c) {
const arr = [];
for (let i = 0; i < data.records.length; i += 1) {
arr.push(data.records[i][c]);
}
return arr;
}
*/
/*
const maxes = {};
const mins = {};
for (let i = 0; i < metrics.length; i += 1) {
if (fd.align_pn) {
maxes[metrics[i]] = d3.max(col(metrics[i]).map(Math.abs));
} else {
maxes[metrics[i]] = d3.max(col(metrics[i]));
mins[metrics[i]] = d3.min(col(metrics[i]));
}
}
*/

const tsFormatter = d3TimeFormatPreset(fd.table_timestamp_format);

const div = d3.select(slice.selector);
div.html('');
const table = div.append('table')
.classed(
'dataframe dataframe table table-striped ' +
'table-condensed table-hover dataTable no-footer', true)
.attr('width', '100%');

const verboseMap = slice.datasource.verbose_map;
/*
const cols = data.columns.map((c) => {
if (verboseMap[c]) {
return verboseMap[c];
}
// Handle verbose names for percents
if (c[0] === '%') {
const cName = c.substring(1);
return '% ' + (verboseMap[cName] || cName);
}
return c;
});
*/
/*
table.append('thead').append('tr')
.selectAll('th')
.data(cols)
.enter()
.append('th')
.text(function (d) {
return d;
});
*/
const filters = slice.getFilters();
/*
table.append('tbody')
.selectAll('tr')
.data(data.records)
.enter()
.append('tr')
.selectAll('td')
.data(row => data.columns.map((c) => {
const val = row[c];
let html;
const isMetric = metrics.indexOf(c) >= 0;
if (c === '__timestamp') {
html = tsFormatter(val);
}
if (typeof (val) === 'string') {
html = `<span class="like-pre">${val}</span>`;
}
if (isMetric) {
html = slice.d3format(c, val);
}
if (c[0] === '%') {
html = d3.format('.3p')(val);
}
return {
col: c,
val,
html,
isMetric,
};
}))
.enter()
.append('td')
.style('background-image', function (d) {
if (d.isMetric) {
const r = (fd.color_pn && d.val < 0) ? 150 : 0;
if (fd.align_pn) {
const perc = Math.abs(Math.round((d.val / maxes[d.col]) * 100));
// The 0.01 to 0.001 is a workaround for what appears to be a
// CSS rendering bug on flat, transparent colors
return (
`linear-gradient(to right, rgba(${r},0,0,0.2), rgba(${r},0,0,0.2) ${perc}%, ` +
`rgba(0,0,0,0.01) ${perc}%, rgba(0,0,0,0.001) 100%)`
);
}
const posExtent = Math.abs(Math.max(maxes[d.col], 0));
const negExtent = Math.abs(Math.min(mins[d.col], 0));
const tot = posExtent + negExtent;
const perc1 = Math.round((Math.min(negExtent + d.val, negExtent) / tot) * 100);
const perc2 = Math.round((Math.abs(d.val) / tot) * 100);
// The 0.01 to 0.001 is a workaround for what appears to be a
// CSS rendering bug on flat, transparent colors
return (
`linear-gradient(to right, rgba(0,0,0,0.01), rgba(0,0,0,0.001) ${perc1}%, ` +
`rgba(${r},0,0,0.2) ${perc1}%, rgba(${r},0,0,0.2) ${perc1 + perc2}%, ` +
`rgba(0,0,0,0.01) ${perc1 + perc2}%, rgba(0,0,0,0.001) 100%)`
);
}
return null;
})
.classed('text-right', d => d.isMetric)
.attr('title', (d) => {
if (!isNaN(d.val)) {
return fC(d.val);
}
return null;
})
.attr('data-sort', function (d) {
return (d.isMetric) ? d.val : null;
})
// Check if the dashboard currently has a filter for each row
.classed('filtered', d =>
filters &&
filters[d.col] &&
filters[d.col].indexOf(d.val) >= 0,
)
.on('click', function (d) {
if (!d.isMetric && fd.table_filter) {
const td = d3.select(this);
if (td.classed('filtered')) {
slice.removeFilter(d.col, [d.val]);
d3.select(this).classed('filtered', false);
} else {
d3.select(this).classed('filtered', true);
slice.addFilter(d.col, [d.val]);
}
}
})
.style('cursor', function (d) {
return (!d.isMetric) ? 'pointer' : '';
})
.html(d => d.html ? d.html : d.val);
*/
const height = slice.height();
let total_count = 0;
let paging = false;
let pageLength;
if (fd.page_length && fd.page_length > 0) {
paging = true;
pageLength = parseInt(fd.page_length, 10);
}
const datatable = container.find('.dataTable').DataTable({
paging,
pageLength,
aaSorting: [],
searching: fd.include_search,
bInfo: false,
scrollY: height + 'px',
scrollCollapse: true,
scrollX: true,
processing: true,
serverSide: true,
columns: [
{'data': 'committer', 'title': 'committer'},
{'data': 'loc' , 'title': 'loc'},
{'data': 'headline' , 'title': 'headline'}
//{'data': 'eventId'},
//{'data': 'routingInfo'},
],

ajax: {
url: 'http://localhost:8088/superset/explore_json/?form_data=%7B%22slice_id%22%3A10%7D',
type: 'POST',
dataType: 'json',
contentType: "application/json",
data: function (oSettings){
if($.fn.dataTableSettings != null && $.fn.dataTableSettings[0] != null) {
var startDisplay = $.fn.dataTableSettings[0]._iDisplayStart;
var pageLength = $.fn.dataTableSettings[0]._iDisplayLength;
console.log(startDisplay);
console.log(pageLength);
slice.formData['limit'] = pageLength;
slice.formData['offset'] = startDisplay;
} else {

}
return JSON.stringify(slice.formData);
},

dataSrc: function (json) {
console.log(json);
total_count = json.total_count.records[0].count;
return json.data.records;

//return JSON.parse('[{"eventId":"mc","routingInfo":"prodbemview01"}, {"eventId":"mc","routingInfo":"prodbemview01"}]');

//return JSON.parse(json.data.records);
//return {"data" : {committer: '1', loc: '2', headline: '3' }}
},
},

drawCallback: function( settings ) {
$('#DataTables_Table_0').dataTable().fnCustomPagign(settings, total_count);
}
});
fixDataTableBodyHeight(
container.find('.dataTables_wrapper'), height);
// Sorting table by main column
let sortBy;
if (fd.timeseries_limit_metric) {
// Sort by as specified
sortBy = fd.timeseries_limit_metric;
} else if (metrics.length > 0) {
// If not specified, use the first metric from the list
sortBy = metrics[0];
}
/*
if (sortBy) {
datatable.column(data.columns.indexOf(sortBy)).order(fd.order_desc ? 'desc' : 'asc');
}
if (fd.timeseries_limit_metric && metrics.indexOf(fd.timeseries_limit_metric) < 0) {
// Hiding the sortBy column if not in the metrics list
datatable.column(data.columns.indexOf(sortBy)).visible(false);
}
*/
datatable.draw();
container.parents('.widget').find('.tooltip').remove();

datatable.on( 'draw.dt', function () {//페이지 이동 후 셀병합, 문자열 자르기
$('#DataTables_Table_0').dataTable().fnMovePage();
});


}

$.fn.dataTableExt.oApi.fnMovePage = function ( oSettings ) {

}

$.fn.dataTableExt.oApi.fnCustomPagign = function (aa, oSettings, total_row_cnt ) {
var plugin = $.fn.dataTable.ext.pager['simple_numbers'];
var features = oSettings.aanFeatures;

var start = oSettings._iDisplayStart;
var len = oSettings._iDisplayLength;
var visRecords = total_row_cnt;
var all = len === -1;
var page = all ? 0 : Math.ceil( start / len );
var pages = all ? 1 : Math.ceil( visRecords / len );
var buttons = plugin(page, pages);
var i, ien;

for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
$.fn.dataTableExt.oApi._fnRenderer( oSettings, 'pageButton' )
(oSettings, features.p[i], i, buttons, page, pages);
}
}

module.exports = pagingTableVis;

paging_table.js


if(this.props.vizType === 'paging_table') {
viz(this, null);
return;
}

Chart.jsx renderViz()


def get_payload(self, query_obj=None):
"""Returns a payload of metadata and data"""
query_obj = self.query_obj()

# column 삭제 후 count 만 돌림
# query_obj['columns'].remove()
columns_list = [i for i in query_obj['columns']]
del query_obj['columns'][:]
print(query_obj['columns'])
offset = query_obj['offset']
limit = query_obj['limit']
del query_obj['offset']
del query_obj['limit']
payload_count = self.get_df_payload(query_obj)

countDF = payload_count.get('df')
cntData = dict(
records=countDF.to_dict(orient='records'),
columns=list(countDF.columns),
)

# metrics 삭제 후 data 돌림
query_obj['columns'] = [i for i in columns_list]
query_obj['offset'] = offset
query_obj['limit'] = limit
#query_obj['offset'] = 0
#query_obj['limit'] = 100
del query_obj['metrics'][:]
payload = self.get_df_payload(query_obj)

df = payload.get('df')
if self.status != utils.QueryStatus.FAILED:
if df is not None and df.empty:
payload['error'] = 'No data'
else:
payload['data'] = self.get_data(df)
payload['total_count'] = cntData
if 'df' in payload:
del payload['df']
return payload

PagingTableViz


request_param_data = request.data


if request_param_data:
form_data.update(json.loads(request_param_data))

core.py get_form_data

반응형

'엉터리 개발 이야기' 카테고리의 다른 글

docker  (0) 2018.06.09
DataTables Column Data Function  (0) 2018.05.25
[Linux] 환경변수(PATH) 확인하기  (0) 2018.04.03
[CSS] 특정 Class 만 제외 시키기  (0) 2018.04.03
[JS] subDate, addDate  (0) 2018.04.02