event log: virtual scrolling

This commit is contained in:
Maximilian Hils 2014-11-28 20:54:52 +01:00
parent dd1a45140c
commit f6c0e000da
5 changed files with 136 additions and 74 deletions

View File

@ -485,7 +485,7 @@ _.extend(FlowView.prototype, EventEmitter.prototype, {
//Ugly workaround: Call .sortfun() for each flow once in order,
//so that SortByInsertionOrder make sense.
for(var i = 0; i < flows.length; i++) {
for (var i = 0; i < flows.length; i++) {
this.sortfun(flows[i]);
}
@ -705,35 +705,57 @@ var VirtualScrollMixin = {
stop: 0
}
},
componentWillMount: function(){
if(!this.props.rowHeight){
console.warn("VirtualScrollMixin: No rowHeight specified", this);
}
},
getPlaceholderTop: function () {
var Tag = this.props.placeholderTagName || "tr";
var style = {
height: this.state.start * this.props.rowHeight
};
var spacer = React.createElement("tr", {key: "placeholder-top", style: style});
var spacer = React.createElement(Tag, {key: "placeholder-top", style: style});
if (this.state.start % 2 === 1) {
// fix even/odd rows
return [spacer, React.createElement("tr", {key: "placeholder-top-2"})];
return [spacer, React.createElement(Tag, {key: "placeholder-top-2"})];
} else {
return spacer;
}
},
getPlaceholderBottom: function (total) {
var Tag = this.props.placeholderTagName || "tr";
var style = {
height: Math.max(0, total - this.state.stop) * this.props.rowHeight
};
return React.createElement("tr", {key: "placeholder-bottom", style: style});
return React.createElement(Tag, {key: "placeholder-bottom", style: style});
},
componentDidMount: function () {
this.onScroll();
},
onScroll: function () {
var viewport = this.getDOMNode();
var top = viewport.scrollTop;
var height = viewport.offsetHeight;
var start = Math.floor(top / this.props.rowHeight);
var stop = start + Math.ceil(height / this.props.rowHeight);
var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight));
this.setState({
start: start,
stop: stop
});
console.log(start, stop);
},
renderRows: function(elems){
var rows = [];
var max = Math.min(elems.length, this.state.stop);
for (var i = this.state.start; i < max; i++) {
var elem = elems[i];
rows.push(this.renderRow(elem));
}
return rows;
},
scrollRowIntoView: function(index, head_height){
@ -1066,9 +1088,6 @@ var FlowTable = React.createClass({displayName: 'FlowTable',
nextProps.view.addListener("add update remove recalculate", this.onChange);
}
},
componentDidMount: function () {
this.onScroll2();
},
getDefaultProps: function () {
return {
rowHeight: ROW_HEIGHT
@ -1088,27 +1107,20 @@ var FlowTable = React.createClass({displayName: 'FlowTable',
this.refs.body.getDOMNode().offsetTop
);
},
render: function () {
var space_top = 0, space_bottom = 0, fix_nth_row = null;
var rows = [];
if (this.props.view) {
var flows = this.props.view.flows;
var max = Math.min(flows.length, this.state.stop);
for (var i = this.state.start; i < max; i++) {
var flow = flows[i];
renderRow: function (flow) {
var selected = (flow === this.props.selected);
rows.push(
React.createElement(FlowRow, {key: flow.id,
return React.createElement(FlowRow, {key: flow.id,
ref: flow.id,
flow: flow,
columns: this.state.columns,
selected: selected,
selectFlow: this.props.selectFlow}
)
);
}
}
},
render: function () {
var flows = this.props.view ? this.props.view.flows : [];
var rows = this.renderRows(flows);
return (
React.createElement("div", {className: "flow-table", onScroll: this.onScroll2},
@ -1599,7 +1611,7 @@ var LogMessage = React.createClass({displayName: 'LogMessage',
});
var EventLogContents = React.createClass({displayName: 'EventLogContents',
mixins: [AutoScrollMixin],
mixins: [AutoScrollMixin, VirtualScrollMixin],
getInitialState: function () {
return {
log: []
@ -1614,18 +1626,37 @@ var EventLogContents = React.createClass({displayName: 'EventLogContents',
this.log.close();
},
onEventLogChange: function () {
var log = this.log.getAll().filter(function (entry) {
return this.props.filter[entry.level];
}.bind(this));
this.setState({
log: this.log.getAll()
log: log
});
},
render: function () {
var messages = this.state.log.map(function (row) {
if (!this.props.filter[row.level]) {
return null;
componentWillReceiveProps: function () {
if (this.log) {
this.onEventLogChange();
}
return React.createElement(LogMessage, {key: row.id, entry: row});
}.bind(this));
return React.createElement("pre", null, messages);
},
getDefaultProps: function () {
return {
rowHeight: 45,
rowHeightMin: 15,
placeholderTagName: "div"
};
},
renderRow: function(elem){
return React.createElement(LogMessage, {key: elem.id, entry: elem});
},
render: function () {
var rows = this.renderRows(this.state.log);
return React.createElement("pre", {onScroll: this.onScroll},
this.getPlaceholderTop(),
rows,
this.getPlaceholderBottom(this.state.log.length)
);
}
});

View File

@ -24,7 +24,7 @@ var LogMessage = React.createClass({
});
var EventLogContents = React.createClass({
mixins: [AutoScrollMixin],
mixins: [AutoScrollMixin, VirtualScrollMixin],
getInitialState: function () {
return {
log: []
@ -39,18 +39,37 @@ var EventLogContents = React.createClass({
this.log.close();
},
onEventLogChange: function () {
var log = this.log.getAll().filter(function (entry) {
return this.props.filter[entry.level];
}.bind(this));
this.setState({
log: this.log.getAll()
log: log
});
},
render: function () {
var messages = this.state.log.map(function (row) {
if (!this.props.filter[row.level]) {
return null;
componentWillReceiveProps: function () {
if (this.log) {
this.onEventLogChange();
}
return <LogMessage key={row.id} entry={row}/>;
}.bind(this));
return <pre>{messages}</pre>;
},
getDefaultProps: function () {
return {
rowHeight: 45,
rowHeightMin: 15,
placeholderTagName: "div"
};
},
renderRow: function(elem){
return <LogMessage key={elem.id} entry={elem}/>;
},
render: function () {
var rows = this.renderRows(this.state.log);
return <pre onScroll={this.onScroll}>
{ this.getPlaceholderTop() }
{rows}
{ this.getPlaceholderBottom(this.state.log.length) }
</pre>;
}
});

View File

@ -58,9 +58,6 @@ var FlowTable = React.createClass({
nextProps.view.addListener("add update remove recalculate", this.onChange);
}
},
componentDidMount: function () {
this.onScroll2();
},
getDefaultProps: function () {
return {
rowHeight: ROW_HEIGHT
@ -80,27 +77,20 @@ var FlowTable = React.createClass({
this.refs.body.getDOMNode().offsetTop
);
},
render: function () {
var space_top = 0, space_bottom = 0, fix_nth_row = null;
var rows = [];
if (this.props.view) {
var flows = this.props.view.flows;
var max = Math.min(flows.length, this.state.stop);
for (var i = this.state.start; i < max; i++) {
var flow = flows[i];
renderRow: function (flow) {
var selected = (flow === this.props.selected);
rows.push(
<FlowRow key={flow.id}
return <FlowRow key={flow.id}
ref={flow.id}
flow={flow}
columns={this.state.columns}
selected={selected}
selectFlow={this.props.selectFlow}
/>
);
}
}
/>;
},
render: function () {
var flows = this.props.view ? this.props.view.flows : [];
var rows = this.renderRows(flows);
return (
<div className="flow-table" onScroll={this.onScroll2}>

View File

@ -5,35 +5,57 @@ var VirtualScrollMixin = {
stop: 0
}
},
componentWillMount: function(){
if(!this.props.rowHeight){
console.warn("VirtualScrollMixin: No rowHeight specified", this);
}
},
getPlaceholderTop: function () {
var Tag = this.props.placeholderTagName || "tr";
var style = {
height: this.state.start * this.props.rowHeight
};
var spacer = <tr key="placeholder-top" style={style}></tr>;
var spacer = <Tag key="placeholder-top" style={style}></Tag>;
if (this.state.start % 2 === 1) {
// fix even/odd rows
return [spacer, <tr key="placeholder-top-2"></tr>];
return [spacer, <Tag key="placeholder-top-2"></Tag>];
} else {
return spacer;
}
},
getPlaceholderBottom: function (total) {
var Tag = this.props.placeholderTagName || "tr";
var style = {
height: Math.max(0, total - this.state.stop) * this.props.rowHeight
};
return <tr key="placeholder-bottom" style={style}></tr>;
return <Tag key="placeholder-bottom" style={style}></Tag>;
},
componentDidMount: function () {
this.onScroll();
},
onScroll: function () {
var viewport = this.getDOMNode();
var top = viewport.scrollTop;
var height = viewport.offsetHeight;
var start = Math.floor(top / this.props.rowHeight);
var stop = start + Math.ceil(height / this.props.rowHeight);
var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight));
this.setState({
start: start,
stop: stop
});
console.log(start, stop);
},
renderRows: function(elems){
var rows = [];
var max = Math.min(elems.length, this.state.stop);
for (var i = this.state.start; i < max; i++) {
var elem = elems[i];
rows.push(this.renderRow(elem));
}
return rows;
},
scrollRowIntoView: function(index, head_height){

View File

@ -144,7 +144,7 @@ _.extend(FlowView.prototype, EventEmitter.prototype, {
//Ugly workaround: Call .sortfun() for each flow once in order,
//so that SortByInsertionOrder make sense.
for(var i = 0; i < flows.length; i++) {
for (var i = 0; i < flows.length; i++) {
this.sortfun(flows[i]);
}