--- a/devtools/client/inspector/grids/components/GridOutline.js
+++ b/devtools/client/inspector/grids/components/GridOutline.js
@@ -10,48 +10,58 @@ const { throttle } = require("devtools/c
const Types = require("../types");
// The delay prior to executing the grid cell highlighting.
const GRID_CELL_MOUSEOVER_TIMEOUT = 150;
// Move SVG grid to the right 100 units, so that it is not flushed against the edge of
// layout border
-const TRANSLATE_X = -100;
+const TRANSLATE_X = 0;
const TRANSLATE_Y = 0;
-const VIEWPORT_HEIGHT = 100;
-const VIEWPORT_WIDTH = 450;
+const GRID_CELL_SCALE_FACTOR = 50;
+
+const VIEWPORT_MIN_HEIGHT = 100;
+const VIEWPORT_MAX_HEIGHT = 150;
module.exports = createClass({
displayName: "GridOutline",
propTypes: {
grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
onShowGridAreaHighlight: PropTypes.func.isRequired,
onShowGridCellHighlight: PropTypes.func.isRequired,
},
mixins: [ addons.PureRenderMixin ],
getInitialState() {
return {
selectedGrids: [],
+ height: 0,
+ width: 0,
};
},
componentWillMount() {
// Throttle the grid highlighting of grid cells. It makes the UX smoother by not
// lagging the grid cell highlighting if a lot of grid cells are mouseover in a
// quick succession.
this.highlightCell = throttle(this.highlightCell, GRID_CELL_MOUSEOVER_TIMEOUT);
},
componentWillReceiveProps({ grids }) {
+ if (this.state.selectedGrids.length < 2) {
+ this.setState({
+ height: 0,
+ width: 0,
+ });
+ }
this.setState({
selectedGrids: grids.filter(grid => grid.highlighted),
});
},
/**
* Returns the grid area name if the given grid cell is part of a grid area, otherwise
* null.
@@ -72,16 +82,33 @@ module.exports = createClass({
if (!gridArea) {
return null;
}
return gridArea.name;
},
+ /**
+ * Returns the height of the grid outline ranging between a minimum and maximum height.
+ *
+ * @return {Number} The height of the grid outline.
+ */
+ getHeight() {
+ const { height } = this.state;
+
+ if (height >= VIEWPORT_MAX_HEIGHT) {
+ return VIEWPORT_MAX_HEIGHT;
+ } else if (height <= VIEWPORT_MIN_HEIGHT) {
+ return VIEWPORT_MIN_HEIGHT;
+ }
+
+ return height;
+ },
+
highlightCell({ target }) {
const {
grids,
onShowGridAreaHighlight,
onShowGridCellHighlight,
} = this.props;
const name = target.getAttribute("data-grid-area-name");
const id = target.getAttribute("data-grid-id");
@@ -92,61 +119,83 @@ module.exports = createClass({
target.setAttribute("fill", color);
if (name) {
onShowGridAreaHighlight(grids[id].nodeFront, name, color);
}
if (fragmentIndex && rowNumber && columnNumber) {
- onShowGridCellHighlight(grids[id].nodeFront, fragmentIndex,
+ onShowGridCellHighlight(grids[id].nodeFront, color, fragmentIndex,
rowNumber, columnNumber);
}
},
- /**
- * Renders the grid outline for the given grid container object.
- *
- * @param {Object} grid
- * A single grid container in the document.
- */
+ /**
+ * Renders the grid outline for the given grid container object.
+ *
+ * @param {Object} grid
+ * A single grid container in the document.
+ */
renderGrid(grid) {
const { id, color, gridFragments } = grid;
// TODO: We are drawing the first fragment since only one is currently being stored.
// In the future we will need to iterate over all fragments of a grid.
let gridFragmentIndex = 0;
const { rows, cols, areas } = gridFragments[gridFragmentIndex];
const numberOfColumns = cols.lines.length - 1;
const numberOfRows = rows.lines.length - 1;
const rectangles = [];
-
- // Draw a rectangle that acts as a border for the grid outline.
- const border = this.renderGridOutlineBorder(numberOfRows, numberOfColumns, color);
- rectangles.push(border);
-
let x = 1;
let y = 1;
- const width = 10;
- const height = 10;
+ let width = 0;
+ let height = 0;
+ // The grid outline border height/width is the total height/width of grid cells drawn.
+ let totalHeight = 0;
+ let totalWidth = 0;
- // Draw the cells within the grid outline border.
+ // Draw the cells contained within the grid outline border.
for (let rowNumber = 1; rowNumber <= numberOfRows; rowNumber++) {
+ height = GRID_CELL_SCALE_FACTOR * (rows.tracks[rowNumber - 1].breadth / 100);
for (let columnNumber = 1; columnNumber <= numberOfColumns; columnNumber++) {
+ width = GRID_CELL_SCALE_FACTOR * (cols.tracks[columnNumber - 1].breadth / 100);
+
const gridAreaName = this.getGridAreaName(columnNumber, rowNumber, areas);
- const gridCell = this.renderGridCell(id, gridFragmentIndex, x, y, rowNumber,
- columnNumber, color, gridAreaName);
+ const gridCell = this.renderGridCell(id, gridFragmentIndex, x, y,
+ rowNumber, columnNumber, color, gridAreaName, width, height);
rectangles.push(gridCell);
x += width;
}
x = 1;
y += height;
+ totalHeight += height;
}
+ // Find the total width of the grid container so we can draw the border for it
+ for (let columnNumber = 0; columnNumber < numberOfColumns; columnNumber++) {
+ totalWidth += GRID_CELL_SCALE_FACTOR * (cols.tracks[columnNumber].breadth / 100);
+ }
+
+ // Store the height of the grid container in the
+ // component state to prevent overflow issues.
+ // We want to store the width of the grid container as well so that the viewbox
+ // is only the calculated width of the grid outline.
+ if (totalHeight > this.state.height || totalWidth > this.state.width) {
+ this.setState({
+ height: totalHeight + 20,
+ width: totalWidth,
+ });
+ }
+
+ // Draw a rectangle that acts as the grid outline border.
+ const border = this.renderGridOutlineBorder(totalWidth, totalHeight, color);
+ rectangles.unshift(border);
+
return rectangles;
},
/**
* Renders the grid cell of a grid fragment.
*
* @param {Number} id
* The grid id stored on the grid fragment
@@ -157,31 +206,35 @@ module.exports = createClass({
* @param {Number} y
* The y-position of the grid cell.
* @param {Number} rowNumber
* The row number of the grid cell.
* @param {Number} columnNumber
* The column number of the grid cell.
* @param {String|null} gridAreaName
* The grid area name or null if the grid cell is not part of a grid area.
+ * @param {Number} width
+ * The width of grid cell.
+ * @param {Number} height
+ * The height of the grid cell.
*/
renderGridCell(id, gridFragmentIndex, x, y, rowNumber, columnNumber, color,
- gridAreaName) {
+ gridAreaName, width, height) {
return dom.rect(
{
className: "grid-outline-cell",
"data-grid-area-name": gridAreaName,
"data-grid-fragment-index": gridFragmentIndex,
"data-grid-id": id,
"data-grid-row": rowNumber,
"data-grid-column": columnNumber,
x,
y,
- width: 10,
- height: 10,
+ width,
+ height,
fill: "none",
stroke: color,
onMouseOver: this.onMouseOverCell,
onMouseOut: this.onMouseLeaveCell,
}
);
},
@@ -189,24 +242,24 @@ module.exports = createClass({
return dom.g(
{
className: "grid-cell-group",
},
grids.map(grid => this.renderGrid(grid))
);
},
- renderGridOutlineBorder(numberOfRows, numberOfColumns, color) {
+ renderGridOutlineBorder(borderWidth, borderHeight, color) {
return dom.rect(
{
className: "grid-outline-border",
x: 1,
y: 1,
- width: numberOfColumns * 10,
- height: numberOfRows * 10,
+ width: borderWidth,
+ height: borderHeight,
stroke: color,
}
);
},
onMouseLeaveCell({ target }) {
const {
grids,
@@ -214,32 +267,34 @@ module.exports = createClass({
onShowGridCellHighlight,
} = this.props;
const id = target.getAttribute("data-grid-id");
const color = target.getAttribute("stroke");
target.setAttribute("fill", "none");
onShowGridAreaHighlight(grids[id].nodeFront, null, color);
- onShowGridCellHighlight(grids[id].nodeFront);
+ onShowGridCellHighlight(grids[id].nodeFront, color);
},
onMouseOverCell(event) {
event.persist();
this.highlightCell(event);
},
render() {
- return this.state.selectedGrids.length ?
+ const { selectedGrids, height, width } = this.state;
+
+ return selectedGrids.length ?
dom.svg(
{
className: "grid-outline",
width: "100%",
- height: 100,
- viewBox: `${TRANSLATE_X} ${TRANSLATE_Y} ${VIEWPORT_WIDTH} ${VIEWPORT_HEIGHT}`,
+ height: this.getHeight(),
+ viewBox: `${TRANSLATE_X} ${TRANSLATE_Y} ${width} ${height}`,
},
- this.renderGridOutline(this.state.selectedGrids)
+ this.renderGridOutline(selectedGrids)
)
:
null;
},
});