Spotlight in React Js - reactjs

I created the spotlight using react js. I am not able to click the objects below it. I tried to apply pointerEvents: 'none' to the styling but that doesn't move the spotlight. How should I make the objects below clickable?
Here is the code:-
import React from 'react';
export default class Spot extends React.Component {
constructor(props) {
super(props);
this.state = { x: 0, y: 0};
}
_onMouseMove(e) {
this.setState({ x: e.screenX , y: e.screenY });
}
render() {
const { x, y } = this.state;
return (
<div className={'spot'} onMouseMove={this._onMouseMove.bind(this)}
style={{background: `radial-gradient(${this.props.height}px
${this.props.width}px at ${x}px ${y}px , transparent 90%,
${this.props.color})`, top: '0', bottom: '0', left: '0', right:
'0', position: 'absolute'}}>
</div>
);
}
}
Here is the other component:-
import React from 'react'
import Scene from '../components/Scene'
import Sobject from '../components/Object'
import Room from '../images/level1/Room.png'
import Spot from './Spotlight.js'
export default class Level1 extends React.Component {
constructor(props) {
super(props)
}
clickIt(){
console.log('room')
}
render() {
return (
<div>
<Scene>
<Sobject name={'room'} xPos={0} yPos={0}>
<img src={Room} height="725" width="1536" onClick=
{this.clickIt.bind(this)} />
</Sobject>
<Spot height={200} width={200} color={'rgba(0,0,0,0.91)'} />
</Scene>
</div>
)
}
}

Refactor level1 component to be as follow:
Please note the importance of the components sequence, if you put Spot after Sobject it will not work.
Other below points are just code refactoring
Use arrow functions instead of bind(this).
For rendering components inside each other, instead of using {this.props.children} you could just import the component inside the parent component and added there, unless you have a specific reason for that
// level1 component
import React from "react";
import Scene from "../components/Scene.js";
import Sobject from "../components/Object.js";
import Spot from "./Spotlight.js";
export default class Level1 extends React.Component {
render() {
return (
<div>
<Scene>
<Spot height={200} width={200} color={"rgba(0,0,0,0.91)"} />
<Sobject name={"room"} xPos={0} yPos={0}/>
</Scene>
</div>
);
}
}
//spotlight component
import React from "react";
export default class Spot extends React.Component {
state = { x: 0, y: 0 };
_onMouseMove =(e) =>{
this.setState({ x: e.screenX, y: e.screenY });
}
render() {
const { x, y } = this.state;
return (
<div
className={"spot"}
onMouseMove={this._onMouseMove}
style={{
background: `radial-gradient(${this.props.height}px ${
this.props.width
}px at ${x}px ${y}px , transparent 90%, ${this.props.color})`,
top: "0",
bottom: "0",
left: "0",
right: "0",
position: "absolute"
}}
/>
);
}
}
// Scene component
import React from "react";
export default class Scene extends React.Component {
renderObjects = () => this.props.children;
render() {
return (
<div
className={"scene-container"}
style={{ position: "absolute", height: "100vh", width: "100%" }}
>
{this.renderObjects()}
</div>
);
}
}
//object component
import React from "react";
export default class Sobject extends React.Component {
click =() =>{
console.log("clicked");
}
render() { // below we use default values in case the prop is not there
const { name = "", type = "generic", xPos =0, yPos =0, ismoving =false} = this.props;
return (
<div
className={"object-container"}
style={{ left: xPos, top: yPos, position: "absolute" }}
>
<h1 onClick={this.click}>Hello</h1>
</div>
);
}
}

Related

How to change the color of avatar based on onclick in reactjs?

I have material ui avatar which take colors(pink/green) from styles.The problem arise when, i need to change the color from pink to green based on onclick. I tried to keep the color name in tate,but its not working,
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
import { green, pink } from '#material-ui/core/colors';
import Avatar from '#material-ui/core/Avatar';
import FolderIcon from '#material-ui/icons/Folder';
import PageviewIcon from '#material-ui/icons/Pageview';
import AssignmentIcon from '#material-ui/icons/Assignment';
const styles = (theme) => ({
root: {
display: 'flex',
'& > *': {
margin: theme.spacing(1),
},
},
pink: {
color: theme.palette.getContrastText(pink[500]),
backgroundColor: pink[500],
},
green: {
color: '#fff',
backgroundColor: green[500],
},
});
class IconAvatars extends React.Component {
constructor(props) {
super(props)
this.state = {
color:""
}
}
render(){
console.log(this.state.color)
const {classes} = this.props;
return (
<div className={classes.root}>
<Avatar className={classes.pink} >
<div onClick=''>M</div>
</Avatar>
</div>
);
}
}
export default withStyles(styles)(IconAvatars)
Its working fine with this code
<div className={classes.root}>
<Avatar className={classes.pink} >
<div onClick=''>M</div>
</Avatar>
</div>
But I want to change the color from pink to green based on onclick
Set the state based on onClick event and dynamically destructure the appropriate color from the classes
class IconAvatars extends React.Component {
constructor(props) {
super(props)
this.state = {
color:""
}
}
render(){
const {color} = this.state;
const {classes} = this.props;
const AvatarClass = classes[color] || classes.pink;
return (
<div className={classes.root}>
<Avatar className={AvatarClass} >
<div onClick={() => this.setState({color: 'green'})}>M</div>
</Avatar>
</div>
);
}
}
export default withStyles(styles)(IconAvatars);
Sample demo

How would I open a modal to allow a user to select what component to add?

I have a react app that creates a widget layout where they can add and remove widgets in a grid of 4. Currently in the addEvent I have it defaulted to add the "DataTable" component.Instead, I want it to open a modal from which they can select from the "DataTable" or "CheckboxList" component and a larger list of components later on. I am new to react and not exactly sure how to implement this, any help would be great.
import React, { Component } from 'react';
import Swappable from './components/SwappableComponent'
import './App.css';
import DataTable from './components/tableWidget';
import CheckboxList from './components/CheckboxList';
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
import Grid from "#material-ui/core/Grid";
const styles = theme => ({
root: {
flexGrow: 1
},
paper: {
padding: theme.spacing.unit * 2,
textAlign: "center",
color: theme.palette.text.secondary
}
});
class App extends Component {
constructor(props) {
super(props);
this.state={
widgets:[
{id:1, content: <DataTable/>},
{id:2, content: <CheckboxList/>},
{id:3, content: ""},
{id:4, content: ""}
]
}
}
deleteEvent=(index)=>{
const copyWidgets=Object.assign([],this.state.widgets);
let widget=this.state.widgets[index];
widget.content="";
copyWidgets[index]=widget;
this.setState({
widgets:copyWidgets
})
}
addEvent=(index)=>{
const copyWidgets=Object.assign([],this.state.widgets);
let widget=this.state.widgets[index];
widget.content=<DataTable/>;
copyWidgets[index]=widget;
this.setState({
widgets:copyWidgets
})
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<Grid container spacing={24}>
{
this.state.widgets.map((widget,index)=>{
return(
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}><Swappable id={widget.id} content={widget.content} delete={this.deleteEvent.bind(this,index)} add={this.addEvent.bind(this,index)}/></Paper>
</Grid>
)
})
}
</Grid>
</div>
);
}
}
App.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(App);
The basics of a modal component is below. You can add header and footer sections, fade-in effects, opacity on background etc - go crazy
class Modal extends React.Component {
render() {
const { display, close, children } = this.props;
if (!display) return null;
return (
<div className="modal">
{children}
<button onClick={close}>Close</button>
</div>
)
}
}
// css
.modal {
position: fixed;
top: 10%;
width: 90%;
height: 90%;
}
// use it
<Modal display={this.state.displayModal}
close={()=>this.setState({displayModal: false})} >
// add your modal content here
<h1>Add Event</h1>
<p>Some relevant jsx here</p>
</Modal>
to initiate the modal you just set displayModal to true:
addEvent = () => {
this.setState({displayModal:true});
}

Material-UI: ListItem onClick not called

I am working with React and Material-UI. I am trying to display a list and call a function when one of the items of the list is clicked.
The code below is a simplified version of my code, but it should contain all the lines concerning the issue.
The onClick function is apparently never called. What am I missing?
App.js:
import React, { Component } from 'react';
import './App.css';
import Grid from '#material-ui/core/Grid';
import Map from './Map.js';
class App extends Component {
render() {
return (
<div >
<Grid container spacing={24}>
<Grid item xs={3}>
Column text
</Grid>
<Grid item xs={9}>
<Map/>
</Grid>
</Grid>
</div>
);
}
}
export default App;
Map.js:
import React from 'react';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
class Map extends React.Component {
constructor(props) {
super(props);
this.state = {
sensorsList: {
isLoaded: false,
data: null,
},
};
}
componentDidMount() {
// retrieve list of sensors
fetch("https://api-of-things.plenar.io/api/sensors?size=10000")
.then(res => res.json())
.then(
(result) => {
this.setState({
sensorsList: {
isLoaded: true,
data: Object.keys(result.data).map(key => result.data[key].path),
}
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
error
});
}
)
}
selectSensor(name) {
console.log(name);
}
_renderSensorsList() {
const {sensorsList} = this.state;
return sensorsList.isLoaded && (
<div style={{
position: 'absolute',
zIndex: 1,
pointerEvents: 'none',
right: 10,
top: 10,
backgroundColor: 'white',
}}>
<List component="nav">
{ sensorsList.data.map(key =>
<ListItem button key={key} onClick={() => this.selectSensor("ciao")} >
<ListItemText primary={key} />
</ListItem>
)}
</List>
</div>
);
}
render() {
const {sensorsList, selectedSensor} = this.state;
return (
<div>
{ this._renderSensorsList() }
</div>
);
}
}
export default Map;
The problem is that in your div's style you are setting pointerEvents: 'none', preventing the click to reach the DOM event listener, remove it and it will work.
<div style={{
position: 'absolute',
zIndex: 1,
pointerEvents: 'none', //<---- remove this line
right: 10,
top: 10,
backgroundColor: 'white',
}}>
try replacing this
_renderSensorsList() {
with arrow function like this
_renderSensorsList = () => {

React App using Radium fails to compile due to StyleRoot in App component

My App has failed to compile based on the following error:
./src/App.js
Syntax error: Unexpected token (12:2)
10 | class App extends Component {
11 |
> 12 | <StyleRoot>
| ^
13 | <AppContent />
14 | </StyleRoot>
15 |
My App is divided between App.js and AppContent.js. I decided that this might be a janky if workable way to wrap my app in StyleRoot.
App.js
import React, { Component } from 'react';
import Radium from 'radium';
import {StyleRoot} from 'radium';
import AppContent from './AppContent.js';
class App extends Component {
<StyleRoot>
<AppContent />
</StyleRoot>
}
export default App;
AppContent.js
import React, { Component } from 'react';
import axios from 'axios';
import Radium from 'radium';
import Title from './Title.js'
import {fadeInDown} from 'react-animations';
const styles = {
appContent: {
textAlign: 'center'
},
fadeInDown: {
animation: 'x 1s',
animationName: Radium.keyframes(fadeInDown, 'fadeInDown')
},
quoteBox: {
margin: '0 auto',
padding: '50px',
maxWidth: '25%',
minHeight: '200px',
backgroundColor: 'aquamarine'
},
quoteAuthor: {
backgroundColor: 'orange',
textAlign: 'right',
height: '15%',
marginTop: '50px'
}
}
class AppContent extends Component {
constructor() {
super();
this.state = {
quote: '',
quoteAuthor: ''
};
this.getRandomQuote = this.getRandomQuote.bind(this);
}
getRandomQuote() {
return axios.get('https://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=json')
.then((response) => {
console.log(response);
var author;
(response.data.quoteAuthor === "") ? author = "Anonymous" : author = response.data.quoteAuthor;
this.setState( {quote: response.data.quoteText, quoteAuthor: author} );
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div className="App" style={ styles.app }>
<Title words="Quote Machine"/>
<div className="quote-box" style={ styles.quoteBox }>
<h2 className="quote-text" style={ styles.fadeInDown }>{ this.state.quote }</h2>
<h3 className="quote-author" style={ styles.fadeInDown, styles.quoteAuthor }>{ this.state.quoteAuthor }</h3>
</div>
<button className="" onClick={ this.getRandomQuote }>Retrieve A Quote</button>
</div>
);
}
}
AppContent = Radium(AppContent);
export default AppContent
This is my first time using Radium and I don't understand why line 12 is considered an error.
You need render/return so it renders the component.:
class App extends Component {
render(){
return (
<StyleRoot>
<AppContent />
</StyleRoot>
)
}
}

Render the same component twice on onClick in react

I am writing an electron application where I am using react for the UI. I am trying to add shapes(rectangle,square...), so I have created components for each of the shapes. And I have a list of shapes, when I click on the list the corresponding shapes are added. But I want to add the same shape twice which I am not able to do. Can someone help me here?
Below is my code.
List.js
import React from 'react';
class List extends React.Component{
render(){
return (
<div>
<li onClick={this.props.drawSquare}>Square</li>
<li onClick={this.props.drawRectangle}>Rectangle</li>
<li onClick={this.props.drawCircle}>Circle</li>
</div>
);
}
}
export default List
AppContainer.js
import React from 'react'
import List from '../components/List'
import Square from '../components/Square'
import Rect from '../components/Rect'
import Cir from '../components/Cir'
import But from '../components/basic/button'
const style={
position: 'fixed',
width: '800',
height: '800'
};
const butStyle={
position: 'relative',
top: '500px'
}
const style1={
borderStyle: 'groove',
position: 'fixed',
width: '500',
height: '500'
};
class AppContainer extends React.Component{
constructor(props) {
super(props);
this.state={squareclicked:0,
rectClicked:0,
circleClicked:0,};
}
drawSquare(){
console.log("inside square function");
this.setState({squareclicked:this.state.squareclicked+1})
console.log(this.state.squareclicked);
}
drawRectangle(){
console.log("inside rect function");
this.setState({rectClicked:this.state.rectClicked+1})
}
drawCircle(){
console.log("inside circle function");
this.setState({circleClicked:this.state.circleClicked+1})
}
render(){
console.log('render called');
return (
<div style={style}>
<div id="mainAppDiv" >
<List drawSquare={this.drawSquare.bind(this)}
drawRectangle={this.drawRectangle.bind(this)}
drawCircle={this.drawCircle.bind(this)}/>
<div id="shapeConatinerDiv" style={style1}>
{this.state.squareclicked}
{this.state.squareclicked > 0 && (<Square/>)}
{this.state.circleClicked > 0 && (<Cir/>)}
{this.state.rectClicked > 0 && (<Rect/>)}
</div>
</div>
<div style={butStyle}>
<But/>
</div>
</div>
);
}
}
export default AppContainer
Square.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Rectangle} from 'react-shapes';
import Rnd from 'react-rnd'
import Modal from 'react-bootstrap/lib/Modal'
import ColorPallete from './Badging/ColorPalette'
import Button from 'react-bootstrap/lib/Button'
const style = {
border: 'solid 1px',
};
const style1={
position: 'fixed',
width: '500',
height: '500'
};
class Square extends React.Component{
constructor(props) {
super(props);
this.state={w:100,
h:100,
col:{color:'#ff0000'},
zIndex: 99,
modalShow: false,
};
}
close(){
this.setState({modalShow: false});
}
onDrag(){
console.log('hi');
}
onResi(dir, styleSize, clientSize, delta){
this.setState({w:clientSize.width});
this.setState({h:clientSize.height});
}
editSquare(){
this.setState({ modalShow: true });
}
render(props) {
return (
<Rnd ref={c => { this.rnd = c; }}
initial={{
x: parent.innerWidth / 2 - 700,
y: parent.innerHeight / 2 - 80,
width: this.state.w,
height: this.state.h,
}}
style={style}
minWidth={this.state.w}
minHeight={this.state.h}
maxWidth={500}
maxHeight={500}
bounds={'parent'}
lockAspectRatio={true}
onResize={this.onResi.bind(this)}
onDrag={this.onDrag.bind(this)}
>
<Rectangle width={this.state.w} height={this.state.h} fill={this.state.col} stroke={{color:'#E65243'}} strokeWidth={1} onClick={this.editSquare.bind(this)}/>
</Rnd >
);
}
}
export default Square
And the other shapes have the same kind of code.
Right now I am able to add only one square and when I click again nothing happens. But I am able to add other shapes which is once.
You'll want to add elements to an array and render the array of elements.
Here's some rough code that might help:
Component {
constructor() {
super(props)
this.state = { elements: [] }
}
render() {
return (<div>
<div onClick={()=>this.add()}>Add</div>
<div>{this.state.elements}</div>
</div>)
}
add() {
this.setState({
elements: this.state.elements.push(<div id={elements.length}>Element</div>)
})
}
}

Resources