web: add virtualscroll mixin
This commit is contained in:
parent
c39b6e4277
commit
dd1a45140c
|
@ -698,6 +698,60 @@ $.ajaxPrefilter(function(options){
|
|||
}
|
||||
}
|
||||
});
|
||||
var VirtualScrollMixin = {
|
||||
getInitialState: function () {
|
||||
return {
|
||||
start: 0,
|
||||
stop: 0
|
||||
}
|
||||
},
|
||||
getPlaceholderTop: function () {
|
||||
var style = {
|
||||
height: this.state.start * this.props.rowHeight
|
||||
};
|
||||
var spacer = React.createElement("tr", {key: "placeholder-top", style: style});
|
||||
|
||||
if (this.state.start % 2 === 1) {
|
||||
// fix even/odd rows
|
||||
return [spacer, React.createElement("tr", {key: "placeholder-top-2"})];
|
||||
} else {
|
||||
return spacer;
|
||||
}
|
||||
},
|
||||
getPlaceholderBottom: function (total) {
|
||||
var style = {
|
||||
height: Math.max(0, total - this.state.stop) * this.props.rowHeight
|
||||
};
|
||||
return React.createElement("tr", {key: "placeholder-bottom", style: style});
|
||||
},
|
||||
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);
|
||||
this.setState({
|
||||
start: start,
|
||||
stop: stop
|
||||
});
|
||||
},
|
||||
scrollRowIntoView: function(index, head_height){
|
||||
|
||||
var row_top = (index * this.props.rowHeight) + head_height;
|
||||
var row_bottom = row_top + this.props.rowHeight;
|
||||
|
||||
var viewport = this.getDOMNode();
|
||||
var viewport_top = viewport.scrollTop;
|
||||
var viewport_bottom = viewport_top + viewport.offsetHeight;
|
||||
|
||||
// Account for pinned thead
|
||||
if (row_top - head_height < viewport_top) {
|
||||
viewport.scrollTop = row_top - head_height;
|
||||
} else if (row_bottom > viewport_bottom) {
|
||||
viewport.scrollTop = row_bottom - viewport.offsetHeight;
|
||||
}
|
||||
},
|
||||
};
|
||||
var MainMenu = React.createClass({displayName: 'MainMenu',
|
||||
statics: {
|
||||
title: "Traffic",
|
||||
|
@ -993,12 +1047,10 @@ var FlowTableHead = React.createClass({displayName: 'FlowTableHead',
|
|||
var ROW_HEIGHT = 32;
|
||||
|
||||
var FlowTable = React.createClass({displayName: 'FlowTable',
|
||||
mixins: [StickyHeadMixin, AutoScrollMixin],
|
||||
mixins: [StickyHeadMixin, AutoScrollMixin, VirtualScrollMixin],
|
||||
getInitialState: function () {
|
||||
return {
|
||||
columns: all_columns,
|
||||
start: 0,
|
||||
stop: 0
|
||||
columns: all_columns
|
||||
};
|
||||
},
|
||||
componentWillMount: function () {
|
||||
|
@ -1015,46 +1067,26 @@ var FlowTable = React.createClass({displayName: 'FlowTable',
|
|||
}
|
||||
},
|
||||
componentDidMount: function () {
|
||||
this.onScroll();
|
||||
this.onScroll2();
|
||||
},
|
||||
onScroll: function () {
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
rowHeight: ROW_HEIGHT
|
||||
};
|
||||
},
|
||||
onScroll2: function () {
|
||||
this.adjustHead();
|
||||
|
||||
var viewport = this.getDOMNode();
|
||||
var top = viewport.scrollTop;
|
||||
var height = viewport.offsetHeight;
|
||||
var start = Math.floor(top / ROW_HEIGHT);
|
||||
var stop = start + Math.ceil(height / ROW_HEIGHT);
|
||||
this.setState({
|
||||
start: start,
|
||||
stop: stop
|
||||
});
|
||||
this.onScroll();
|
||||
},
|
||||
onChange: function () {
|
||||
console.log("onChange");
|
||||
this.forceUpdate();
|
||||
},
|
||||
scrollIntoView: function (flow) {
|
||||
// Now comes the fun part: Scroll the flow into the view.
|
||||
var viewport = this.getDOMNode();
|
||||
var thead_height = this.refs.body.getDOMNode().offsetTop;
|
||||
|
||||
var flow_top = (this.props.view.index(flow) * ROW_HEIGHT) + thead_height;
|
||||
|
||||
var viewport_top = viewport.scrollTop;
|
||||
var viewport_bottom = viewport_top + viewport.offsetHeight;
|
||||
var flow_bottom = flow_top + ROW_HEIGHT;
|
||||
|
||||
// Account for pinned thead
|
||||
|
||||
|
||||
console.log("scrollInto", flow_top, flow_bottom, viewport_top, viewport_bottom, thead_height);
|
||||
|
||||
if (flow_top - thead_height < viewport_top) {
|
||||
viewport.scrollTop = flow_top - thead_height;
|
||||
} else if (flow_bottom > viewport_bottom) {
|
||||
viewport.scrollTop = flow_bottom - viewport.offsetHeight;
|
||||
}
|
||||
this.scrollRowIntoView(
|
||||
this.props.view.index(flow),
|
||||
this.refs.body.getDOMNode().offsetTop
|
||||
);
|
||||
},
|
||||
render: function () {
|
||||
var space_top = 0, space_bottom = 0, fix_nth_row = null;
|
||||
|
@ -1062,7 +1094,6 @@ var FlowTable = React.createClass({displayName: 'FlowTable',
|
|||
if (this.props.view) {
|
||||
var flows = this.props.view.flows;
|
||||
var max = Math.min(flows.length, this.state.stop);
|
||||
console.log("render", this.props.view.flows.length, this.state.start, max - this.state.start, flows.length - this.state.stop);
|
||||
|
||||
for (var i = this.state.start; i < max; i++) {
|
||||
var flow = flows[i];
|
||||
|
@ -1077,25 +1108,17 @@ var FlowTable = React.createClass({displayName: 'FlowTable',
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
space_top = this.state.start * ROW_HEIGHT;
|
||||
space_bottom = Math.max(0, flows.length - this.state.stop) * ROW_HEIGHT;
|
||||
if(this.state.start % 2 === 1){
|
||||
fix_nth_row = React.createElement("tr", null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "flow-table", onScroll: this.onScroll},
|
||||
React.createElement("div", {className: "flow-table", onScroll: this.onScroll2},
|
||||
React.createElement("table", null,
|
||||
React.createElement(FlowTableHead, {ref: "head",
|
||||
columns: this.state.columns}),
|
||||
React.createElement("tbody", {ref: "body"},
|
||||
React.createElement("tr", {style: {height: space_top}}),
|
||||
fix_nth_row,
|
||||
this.getPlaceholderTop(),
|
||||
rows,
|
||||
React.createElement("tr", {style: {height: space_bottom}})
|
||||
this.getPlaceholderBottom(flows.length)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -43,6 +43,7 @@ var path = {
|
|||
'js/stores/flowstore.js',
|
||||
'js/connection.js',
|
||||
'js/components/utils.jsx.js',
|
||||
'js/components/virtualscroll.jsx.js',
|
||||
'js/components/header.jsx.js',
|
||||
'js/components/flowtable-columns.jsx.js',
|
||||
'js/components/flowtable.jsx.js',
|
||||
|
|
|
@ -39,12 +39,10 @@ var FlowTableHead = React.createClass({
|
|||
var ROW_HEIGHT = 32;
|
||||
|
||||
var FlowTable = React.createClass({
|
||||
mixins: [StickyHeadMixin, AutoScrollMixin],
|
||||
mixins: [StickyHeadMixin, AutoScrollMixin, VirtualScrollMixin],
|
||||
getInitialState: function () {
|
||||
return {
|
||||
columns: all_columns,
|
||||
start: 0,
|
||||
stop: 0
|
||||
columns: all_columns
|
||||
};
|
||||
},
|
||||
componentWillMount: function () {
|
||||
|
@ -61,46 +59,26 @@ var FlowTable = React.createClass({
|
|||
}
|
||||
},
|
||||
componentDidMount: function () {
|
||||
this.onScroll();
|
||||
this.onScroll2();
|
||||
},
|
||||
onScroll: function () {
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
rowHeight: ROW_HEIGHT
|
||||
};
|
||||
},
|
||||
onScroll2: function () {
|
||||
this.adjustHead();
|
||||
|
||||
var viewport = this.getDOMNode();
|
||||
var top = viewport.scrollTop;
|
||||
var height = viewport.offsetHeight;
|
||||
var start = Math.floor(top / ROW_HEIGHT);
|
||||
var stop = start + Math.ceil(height / ROW_HEIGHT);
|
||||
this.setState({
|
||||
start: start,
|
||||
stop: stop
|
||||
});
|
||||
this.onScroll();
|
||||
},
|
||||
onChange: function () {
|
||||
console.log("onChange");
|
||||
this.forceUpdate();
|
||||
},
|
||||
scrollIntoView: function (flow) {
|
||||
// Now comes the fun part: Scroll the flow into the view.
|
||||
var viewport = this.getDOMNode();
|
||||
var thead_height = this.refs.body.getDOMNode().offsetTop;
|
||||
|
||||
var flow_top = (this.props.view.index(flow) * ROW_HEIGHT) + thead_height;
|
||||
|
||||
var viewport_top = viewport.scrollTop;
|
||||
var viewport_bottom = viewport_top + viewport.offsetHeight;
|
||||
var flow_bottom = flow_top + ROW_HEIGHT;
|
||||
|
||||
// Account for pinned thead
|
||||
|
||||
|
||||
console.log("scrollInto", flow_top, flow_bottom, viewport_top, viewport_bottom, thead_height);
|
||||
|
||||
if (flow_top - thead_height < viewport_top) {
|
||||
viewport.scrollTop = flow_top - thead_height;
|
||||
} else if (flow_bottom > viewport_bottom) {
|
||||
viewport.scrollTop = flow_bottom - viewport.offsetHeight;
|
||||
}
|
||||
this.scrollRowIntoView(
|
||||
this.props.view.index(flow),
|
||||
this.refs.body.getDOMNode().offsetTop
|
||||
);
|
||||
},
|
||||
render: function () {
|
||||
var space_top = 0, space_bottom = 0, fix_nth_row = null;
|
||||
|
@ -108,7 +86,6 @@ var FlowTable = React.createClass({
|
|||
if (this.props.view) {
|
||||
var flows = this.props.view.flows;
|
||||
var max = Math.min(flows.length, this.state.stop);
|
||||
console.log("render", this.props.view.flows.length, this.state.start, max - this.state.start, flows.length - this.state.stop);
|
||||
|
||||
for (var i = this.state.start; i < max; i++) {
|
||||
var flow = flows[i];
|
||||
|
@ -123,25 +100,17 @@ var FlowTable = React.createClass({
|
|||
/>
|
||||
);
|
||||
}
|
||||
|
||||
space_top = this.state.start * ROW_HEIGHT;
|
||||
space_bottom = Math.max(0, flows.length - this.state.stop) * ROW_HEIGHT;
|
||||
if(this.state.start % 2 === 1){
|
||||
fix_nth_row = <tr></tr>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="flow-table" onScroll={this.onScroll}>
|
||||
<div className="flow-table" onScroll={this.onScroll2}>
|
||||
<table>
|
||||
<FlowTableHead ref="head"
|
||||
columns={this.state.columns}/>
|
||||
<tbody ref="body">
|
||||
<tr style={{height: space_top}}></tr>
|
||||
{ fix_nth_row }
|
||||
{ this.getPlaceholderTop() }
|
||||
{rows}
|
||||
<tr style={{height: space_bottom}}></tr>
|
||||
{ this.getPlaceholderBottom(flows.length) }
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
var VirtualScrollMixin = {
|
||||
getInitialState: function () {
|
||||
return {
|
||||
start: 0,
|
||||
stop: 0
|
||||
}
|
||||
},
|
||||
getPlaceholderTop: function () {
|
||||
var style = {
|
||||
height: this.state.start * this.props.rowHeight
|
||||
};
|
||||
var spacer = <tr key="placeholder-top" style={style}></tr>;
|
||||
|
||||
if (this.state.start % 2 === 1) {
|
||||
// fix even/odd rows
|
||||
return [spacer, <tr key="placeholder-top-2"></tr>];
|
||||
} else {
|
||||
return spacer;
|
||||
}
|
||||
},
|
||||
getPlaceholderBottom: function (total) {
|
||||
var style = {
|
||||
height: Math.max(0, total - this.state.stop) * this.props.rowHeight
|
||||
};
|
||||
return <tr key="placeholder-bottom" style={style}></tr>;
|
||||
},
|
||||
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);
|
||||
this.setState({
|
||||
start: start,
|
||||
stop: stop
|
||||
});
|
||||
},
|
||||
scrollRowIntoView: function(index, head_height){
|
||||
|
||||
var row_top = (index * this.props.rowHeight) + head_height;
|
||||
var row_bottom = row_top + this.props.rowHeight;
|
||||
|
||||
var viewport = this.getDOMNode();
|
||||
var viewport_top = viewport.scrollTop;
|
||||
var viewport_bottom = viewport_top + viewport.offsetHeight;
|
||||
|
||||
// Account for pinned thead
|
||||
if (row_top - head_height < viewport_top) {
|
||||
viewport.scrollTop = row_top - head_height;
|
||||
} else if (row_bottom > viewport_bottom) {
|
||||
viewport.scrollTop = row_bottom - viewport.offsetHeight;
|
||||
}
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue