{
panelMap: { [id: string]: PanelModel };
panelRef: { [id: string]: HTMLElement } = {};
componentDidMount() {
const { dashboard } = this.props;
dashboard.on(panelAdded, this.triggerForceUpdate);
dashboard.on(panelRemoved, this.triggerForceUpdate);
dashboard.on(CoreEvents.repeatsProcessed, this.triggerForceUpdate);
dashboard.on(PanelEvents.viewModeChanged, this.onViewModeChanged);
dashboard.on(CoreEvents.rowCollapsed, this.triggerForceUpdate);
dashboard.on(CoreEvents.rowExpanded, this.triggerForceUpdate);
}
componentWillUnmount() {
const { dashboard } = this.props;
dashboard.off(panelAdded, this.triggerForceUpdate);
dashboard.off(panelRemoved, this.triggerForceUpdate);
dashboard.off(CoreEvents.repeatsProcessed, this.triggerForceUpdate);
dashboard.off(PanelEvents.viewModeChanged, this.onViewModeChanged);
dashboard.off(CoreEvents.rowCollapsed, this.triggerForceUpdate);
dashboard.off(CoreEvents.rowExpanded, this.triggerForceUpdate);
}
buildLayout() {
const layout = [];
this.panelMap = {};
for (const panel of this.props.dashboard.panels) {
const stringId = panel.id.toString();
this.panelMap[stringId] = panel;
if (!panel.gridPos) {
console.log('panel without gridpos');
continue;
}
const panelPos: any = {
i: stringId,
x: panel.gridPos.x,
y: panel.gridPos.y,
w: panel.gridPos.w,
h: panel.gridPos.h,
};
if (panel.type === 'row') {
panelPos.w = GRID_COLUMN_COUNT;
panelPos.h = 1;
panelPos.isResizable = false;
panelPos.isDraggable = panel.collapsed;
}
layout.push(panelPos);
}
return layout;
}
onLayoutChange = (newLayout: ReactGridLayout.Layout[]) => {
for (const newPos of newLayout) {
this.panelMap[newPos.i].updateGridPos(newPos);
}
this.props.dashboard.sortPanelsByGridPos();
// Call render() after any changes. This is called when the layour loads
this.forceUpdate();
};
triggerForceUpdate = () => {
this.forceUpdate();
};
onWidthChange = () => {
for (const panel of this.props.dashboard.panels) {
panel.resizeDone();
}
this.forceUpdate();
};
onViewModeChanged = () => {
ignoreNextWidthChange = true;
};
updateGridPos = (item: ReactGridLayout.Layout, layout: ReactGridLayout.Layout[]) => {
this.panelMap[item.i].updateGridPos(item);
// react-grid-layout has a bug (#670), and onLayoutChange() is only called when the component is mounted.
// So it's required to call it explicitly when panel resized or moved to save layout changes.
this.onLayoutChange(layout);
};
onResize: ItemCallback = (layout, oldItem, newItem) => {
this.panelMap[newItem.i].updateGridPos(newItem);
};
onResizeStop: ItemCallback = (layout, oldItem, newItem) => {
this.updateGridPos(newItem, layout);
this.panelMap[newItem.i].resizeDone();
};
onDragStop: ItemCallback = (layout, oldItem, newItem) => {
this.updateGridPos(newItem, layout);
};
isInView = (panel: PanelModel): boolean => {
if (panel.fullscreen || panel.isEditing) {
return true;
}
// elem is set *after* the first render
const elem = this.panelRef[panel.id.toString()];
if (!elem) {
// NOTE the gridPos is also not valid until after the first render
// since it is passed to the layout engine and made to be valid
// for example, you can have Y=0 for everything and it will stack them
// down vertically in the second call
return false;
}
const top = elem.offsetTop;
const height = panel.gridPos.h * GRID_CELL_HEIGHT + 40;
const bottom = top + height;
// Show things that are almost in the view
const buffer = 250;
const viewTop = this.props.scrollTop;
if (viewTop > bottom + buffer) {
return false; // The panel is above the viewport
}
// Use the whole browser height (larger than real value)
// TODO? is there a better way
const viewHeight = isNaN(window.innerHeight) ? (window as any).clientHeight : window.innerHeight;
const viewBot = viewTop + viewHeight;
if (top > viewBot + buffer) {
return false;
}
return !this.props.dashboard.otherPanelInFullscreen(panel);
};
renderPanels() {
const panelElements = [];
for (const panel of this.props.dashboard.panels) {
const panelClasses = classNames({ 'react-grid-item--fullscreen': panel.fullscreen });
const id = panel.id.toString();
panel.isInView = this.isInView(panel);
panelElements.push(
{
this.panelRef[id] = elem;
}}
>
);
}
return panelElements;
}
render() {
const { dashboard, isFullscreen } = this.props;
return (
{this.renderPanels()}
);
}
}
export default hot(module)(DashboardGrid);