Situation: I want to obtain dimensions and position of an element
Context: I am making a card game. Cards can be placed on the board. I need to be able to check that their destination is on the board. I then will store their position relative to the board's dimensions and location. This will help to reproduce the board across a bunch of different clients who may be using different screen dimensions.
Current Styling:
The board's size width and height are defined by:
width: 100%;
flex-grow:1;
It's container has these properties:
display: flex;
flex-direction: column;
You should note that the actual dimensions are [942.922x874]. I cannot find the position information, I assume because default div position:static instead of position:absolute.
My Attempts:
let board = document.getElementById("gameboard");
if (board) {
console.log("style.height", board.style.height);
console.log("style.width", board.style.width);
console.log("offsetHeight", board.offsetHeight);
console.log("offsetWidth", board.offsetWidth);
console.log("getBoundingClientRect" , board.getBoundingClientRect());
}
Note that the output dimensions are different than my actual dimensions. [1137, 920] instead of [942.922x874]. The [1137, 920] are actually the dimensions of the entire body. Also no matter what I do to obtain position it always gives me [0,0].
EDIT-1
We've come to the conclusion that this may be a timing issue. That I need to make sure that the code to retrieve the dimensions and position are run after the elements have been rendered. Since I am using react I found this thread, ReactJS - Get Height of an element. Which basically says I need to hook into React's component lifecycle method componentDidMount() which runs immediately after rendering has been completed. You can see my implementation below. However, even with this implementation I seem to still be getting the dimensions of body container instead of the element I am accessing.
import React, {PureComponent, PropTypes} from 'react';
// import Card from '../../Components/Card/index.js';
// import Collection from '../../Components/Collection/index.js';
import {List} from 'immutable';
import Indicator from '../../Components/Indicator/index.js';
import Counter from '../../Components/Counter/index.js';
import {connect} from 'react-redux';
import * as actionCreators from './../../action_creators.js';
import './styles.scss';
export default class Game extends PureComponent {
componentDidMount() {
let board = document.getElementById("gameboard");
console.log("getBoundingClientRect" , board.getBoundingClientRect());
}
render() {
let playersById = this.props.playersById;
let collections = this.props.collections;
let counters = this.props.counters;
let indic_list = [];
let coll_list = [];
//Indicators
playersById.forEach(function(value, key, map){
indic_list.push(<p className="section-name">{playersById.get(key).get('name')+"'s Indicators"}</p>)
playersById.get(key).get('indicators').forEach(function(value, key2, map){
indic_list.push(<Indicator playerId={key} action={this.props.modIndicator} label={key2}>{value}</Indicator>)
}, this);
},this);
//Collections
collections.forEach(function(value, key, map) {
coll_list.push(<span>{key}: {collections.get(key).get("content").size}</span>);
collections.get(key).get("control").forEach(function(value, key, map){
coll_list.push(<span>Control: {value}</span>);
});
});
return (
<div className="frame">
<div className="left-col">
{indic_list}
</div>
<div className="center-col">
<span className="collections">
{coll_list}
</span>
<div id="gameboard"></div>
</div>
<div className="right-col">
<div className="counters">
{counters.map(function(type){
return <Counter label={type}></Counter>
})}
</div>
</div>
</div>
)
}
}
Game.PropTypes = {
playersById: PropTypes.object.isRequired,
collections: PropTypes.object.isRequired,
counters: PropTypes.object.isRequired,
modIndicator: PropTypes.func.isRequired
}
function mapStateToProps(state) {
return {
playersById: state.get('playersById') || new List(),
collections: state.get('collections') || new List(),
counters: state.get('counters') || new List()
};
}
export const GameContainer = connect(mapStateToProps, actionCreators)(Game);
Edit-2 Solution The solution to my problem came from this thread. Get the height of a Component in React
The following is the implementation in my code.
import React, {PureComponent, PropTypes} from 'react';
// import Card from '../../Components/Card/index.js';
// import Collection from '../../Components/Collection/index.js';
import {List} from 'immutable';
import Indicator from '../../Components/Indicator/index.js';
import Counter from '../../Components/Counter/index.js';
import {connect} from 'react-redux';
import * as actionCreators from './../../action_creators.js';
import './styles.scss';
export default class Game extends PureComponent {
render() {
let playersById = this.props.playersById;
let collections = this.props.collections;
let counters = this.props.counters;
let indic_list = [];
let coll_list = [];
//Indicators
playersById.forEach(function(value, key, map){
indic_list.push(<p className="section-name">{playersById.get(key).get('name')+"'s Indicators"}</p>)
playersById.get(key).get('indicators').forEach(function(value, key2, map){
indic_list.push(<Indicator playerId={key} action={this.props.modIndicator} label={key2}>{value}</Indicator>)
}, this);
},this);
//Collections
collections.forEach(function(value, key, map) {
coll_list.push(<span>{key}: {collections.get(key).get("content").size}</span>);
collections.get(key).get("control").forEach(function(value, key, map){
coll_list.push(<span>Control: {value}</span>);
});
});
return (
<div className="frame">
<div className="left-col">
{indic_list}
</div>
<div className="center-col">
<span className="collections">
{coll_list}
</span>
<div id="gameboard" ref={(node) => this.calcHeight(node)}></div>
</div>
<div className="right-col">
<div className="counters">
{counters.map(function(type){
return <Counter label={type}></Counter>
})}
</div>
</div>
</div>
)
}
calcHeight(node){
if (node) {
console.log("calcHeight", node.getBoundingClientRect());
}
}
}
Game.PropTypes = {
playersById: PropTypes.object.isRequired,
collections: PropTypes.object.isRequired,
counters: PropTypes.object.isRequired,
modIndicator: PropTypes.func.isRequired
}
function mapStateToProps(state) {
return {
playersById: state.get('playersById') || new List(),
collections: state.get('collections') || new List(),
counters: state.get('counters') || new List()
};
}
export const GameContainer = connect(mapStateToProps, actionCreators)(Game);