I'm trying to import and SVG logo as a component and I get the error as seen in the screenshot below.
Opening the SVG into a web browser, this renders fine as expected but when dropping into my app it doesn't like it for some reason.
The only thing I note is the name of the SVG - the actual name of the svg is "test.svg" however, the error recognises it as "test.5d5d9eef.svg". I'm not sure where or how this number is being generated.
Please also note the "SVG" code within my component is a test to see if this will render and it does render just fine.
Here is my code:
import React from 'react';
import MainLogo from '../../../assets/svg/logos/test.svg';
export default class Logo extends React.Component {
render() {
return (
<div className="logo-wrap col-xs-2">
<h1>Heading</h1>
<MainLogo />
<svg>
<circle cx={50} cy={50} r={10} fill="red" />
</svg>
</div>
)
}
}
You can create a generic component which accepts some props and creates any SVG for you, like this:
import React from 'react';
export class BuildNewSVG extends React.Component {
constructor(props) {
super(props);
}
render() {
let bg = props.color || '#000';
let height = props.height || props.size || '24';
let width = props.width || props.size || '24';
let path1 = props.path1 || 'M7 10l5 5 5-5z';
let path2 = props.path2;
let fill1 = props.fill1 || '';
let fill2 = props.fill2 || 'none';
let viewBox = props.viewBox || '0 0 24 24';
return (
<svg fill={bg} className={props.class} height={height} viewBox={viewBox} width={width}>
<path d={path1} fill={fill1} />
<path d={path2} fill={fill2} />
</svg>
);
}
}
You can call the component like this:
<BuildNewSVG color={'red'} height={'100'} viewBox={'0 0 24 24'} width={'100'} size={'50'}
path1="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" path2="M0 0h24v24H0z" fill1={'#ffffff'} fill2={'red'} />
Note: This will be a generic component and will only accept SVG paths (path1 and path2). Path2 is the outer container. Any simple or complex shape (for example: circle) can be defined as svg path(s).
Related
I am new to react and HTML5 and I try to create a canvas that has 3 images one under the other. I am using react for that.
I create a function that renders an App component. This function returns something like this
return (
<div className="App">
<canvas className="canvas1" id="canvas1" width="70" height="300"></canvas>
{Game()}
</div>
);
The Game is the function that(lives inside the App function) I want to preload the images and do some initial changes to the canvas element. The implementation is something like this:
function Game() {
var c1 = document.getElementById("canvas1").getContext("2d");
//Here the code will do changes to the canvas element
this.draw(true);
}
The problem that I am facing is that the code above does not compile. I get error that getElementById returns Null.
TypeError: document.getElementById(...) is null
I can not understand what is going on. I suspect that something has not loaded correctly and there is nothing at c1 when I call getElementById but I can not find out how to check this possibility.
What can I do to start debugging it?
Thanks for your time.
When you want to operate on dom directly consider using refs, below is hooks implementation.
const App = () => {
const ref = React.useRef(null);
React.useEffect(() => {
const canvas = ref.current
const ctx = canvas.getContext("2d")
}, [])
return (
<div className="App">
<canvas className="canvas1" ref={ref} width="70" height="300"></canvas>
{Game()}
</div>
);
}
There is no reference to image
eg:
class Canvas extends React.Component {
render() {
return(
<div>
<canvas ref="canvas" width={640} height={425} />
<img ref="image" src={cheese} className="hidden" />
</div>
)
}
}
export default Canvas
I have a simple component which looks like this:
import React from "react";
import './MyContainer.css';
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
showWhereClicked = (e) => {
console.log(`you have clicked X:${e.screenX} Y:${e.screenY}`);
// do stuff
}
render() {
return (
<div className="myContainer" onClick={this.showWhereClicked}>
I am 500px tall.
</div>
);
}
}
export default MyContainer;
Whenever I click anywhere inside <MyContainer />, I get a console message giving me an X and Y coordinate of where I clicked on screen.
I wish to place a <div> inside at the X and Y location of my mouse click. Ideally a box or something, say 100x100px wide.
Later I wish to implement a way for me to freely move these <div> components around the screen.
How can I achieve this?
The way I would handle this is by using css in js.
You can set the position of any DOM-Element with position: absolute;, top : yCoordinate and left : xCoordinate css attributes.
// take control over the style of a component
const [style, setStyle] = useState(initialStyle);
const setCoordinates = (x,y) => {
// You don't need whitespace in here, I added it for readability
// I would recommend using something like EmotionJS for this
return `position:absolute;
left:${x}px;
top:${y}px;`
}
...
return(
<div
style = {style}
onClick = { e => {
const newStyle =
setCoordinates(e.target.screenX,
e.target.screenY);
setStyle(newStyle);
}}
></div>)
You can then set those in any shape or form and the desired result should be visible. You won't need to redraw anything, because the DOM didn't change, just the css.
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
placedDiv:{
top:-9999px;
left:-9999px; // hide div first
width:100px;
height:100px;
position:absolute;
}
};
}
showWhereClicked = (e) => {
console.log(`you have clicked X:${e.screenX} Y:${e.screenY}`);
this.setState({
placedDiv:{
top:e.screenY + 'px'
left:e.screenX + 'px'
}
})
// do stuff
}
render() {
return (
<div className="myContainer" onClick={this.showWhereClicked}>
I am 500px tall.
<div style={this.state.placedDiv}></div>
</div>
);
}
}
export default MyContainer;
.myContainer {
position:relative /// in CSS!!!
}
I'm trying to become more fluent with how React passes around information, and this test case came up:
I have a component made up of a Canvas object and an indefinite amount of children. I would like to give the children access to this component's canvas context.
I was wondering if I could give the component a React Context with the canvas context and wrap the children with it, then have the individual children choose to be consumers. However, I'm not used to React or its lifecycle enough to know how to do this correctly. Am I completely off? Is this even possible?
This is the component in question:
const CanvasContext = React.createContext('default');
class Screen extends React.Component
{
render(){
return (<div>
<canvas id="myCanvas" ref={(c) => this.context = c.getContext('2d')} width="200" height="100" style={{border: '1px solid black'}}></canvas>
<CanvasContext.Provider value = {this.context}>{this.props.children}
</CanvasContext.Provider>
</div>);
}
}
Right now, it contains one child:
class Test extends React.Component{
render(){
return <CanvasContext.Consumer>{ctx => {
ctx.moveTo(0, 0);
ctx.lineTo(200, 100);
ctx.stroke();}}
</CanvasContext.Consumer>;
}
}
ReactDOM.render(<Screen><Test/></Screen>, document.getElementsByClassName('container-fluid')[0]);
Help with this would be greatly appreciated.
EDIT: Here's a Codepen: https://codepen.io/ejpg/pen/XqvGdp
This is a fine idea, but you have a few issues:
1) The version of React in your codepen is 15.4. The new context api which you are using was introduced in 16.3. This is why your codepen is throwing the error:
Uncaught TypeError: React.createContext is not a function
2) When the first render happens, the ref won't exist yet which will cause this function call to crash since the context can't possibly exist yet:
ctx.moveTo(0, 0); // ctx isn't defined yet
ctx.moveTo is not a function
3) This is a great opportunity to use 16.3's createRef function which helps manage your ref;
class Screen extends React.Component {
canvas = React.createRef();
render() {
return <canvas ref={this.canvas} />
}
}
4) Getting the context needs to happen after the first render anyway, then you want to trigger a re-render once you have that context to pass it down so state is a good place for that:
class Screen extends React.Component {
state = { context: null };
canvas = React.createRef();
componentDidMount() {
this.setState({ context: this.canvas.current.getContext("2d") });
}
render() {
return (
<div>
<canvas ref={this.canvas} />
{this.state.context && (
<CanvasContext.Provider value={this.state.context}>
{this.props.children}
</CanvasContext.Provider>
)}
</div>
);
}
}
That's enough to get your Test component to draw on render!
Full code on codesandbox
I have three SVGs that I'm using as React components. The three SVGs are currently being saved as JavaScript files. They are being used like this:
import React from 'react';
import PictureA from '../components/SVGs/PictureA.js'
import PictureB from '../components/SVGs/PictureB.js'
import PictureC from '../components/SVGs/PictureC.js'
const IndexPage = () => (
<div className="mainArea">
<PictureB />
<PictureA />
<PictureC />
</div>
)
export default IndexPage
The above part works fine. Within, for example, PictureA.js, I would like to have something like this happen:
import React from 'react';
export default function PictureA(props) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
svg width = "12rem"
height = "auto"
version = "1.1"
viewBox = "-10 -110 100 250"
preserveAspectRatio="xMinYMax slice">
<g transform="translate(-2.202509394435669,-16.15250659108221)"
fill = "FILL THIS WITH A RANDOM COLOR"
fill-opacity = "0.90087" >
<path
d="very long path" />
</g>
</svg>
);
}
I have an array of pre-selected colors, and it's no problem to select from that array. The problem I'm having is in inserting a color once selected into:
fill = "FILL THIS WITH A RANDOM COLOR"
I've been trying to save the randomly selected color as a variable and populate it directly inside the tag. After doing some research, I get the feeling that's the wrong approach. But if there is a way to make that work, that would be optimal. If that isn't the right approach, I would still really appreciate any help making the randomization work within the PictureA.js file. It would be best to have the SVGs self-contained, if that's possible.
Thanks very much!
Have you tried passing a generated color as a prop?
fill = { props.color }
And then call it as
<PictureA color={ chooseRandomColor() } />
[EDIT] If you want this to be self-contained, you can also just inline the call to the random color generator:
return (
<svg
xmlns="http://www.w3.org/2000/svg"
svg width = "12rem"
height = "auto"
version = "1.1"
viewBox = "-10 -110 100 250"
preserveAspectRatio="xMinYMax slice">
<g transform="translate(-2.202509394435669,-16.15250659108221)"
fill = { chooseRandomColor() }
fill-opacity = "0.90087" >
<path ... />
)
}
You can inline JavaScript by surrounding it with { } tags in React JSX templates. See here in the react docs for an example.
I'm really new with React and having trouble with something. I'm trying to set the a progress bar's progress equal to a variable I have inside of a constructor function in my react component. I'm just using a regular old bootstrap progress bar. The progress bar appears, but no width setting I've tried will actually fill the progress bar. If anyone can help out I'd be grateful. Here's my code:
import React, { Component } from 'react';
import SalesData from '../data/salesData';
class ProgressBar extends Component {
constructor() {
super();
this.ordersInProgress = 0;
this.totalSales = 0;
this.orderGoal = 260;
SalesData.forEach(item => {
this.ordersInProgress += item.orders;
this.totalSales += item.orders * item.price;
});
this.progressBarPercentage = Math.floor((this.ordersInProgress / this.orderGoal) * 100);
this.completedOrders = this.orderGoal - this.ordersInProgress;
}
render() {
return (
<div className="progressBarBlock">
<div className = "progress progressBar">
<div className='progress-bar progressBarColor'
role='progressbar'
aria-valuenow='70'
aria-valuemin='0'
aria-valuemax='100'
styles={{width: this.progressBarPercentage}}>
</div>
</div>
</div>
)
}
}
export default ProgressBar
tldr: I'm trying to set the progress bar progress equal to that progressBarPercentage I've calculated in my constructor function, and it's not filling. Again, thank you in advance for any help you can provide!
It is not recommemded to you class fields (e.g. this.ordersGoal) to keep data in, especially if your component depends on that data for rendering, as it will not track changes. this.state / this.setState() are designed fro this purpose.
2) It should be style, not styles, as already mentioned above
class ProgressBar extends Component {
constructor() {
super();
let ordersInProgress = 0;
let totalSales = 0;
let orderGoal = 260;
SalesData.forEach(item => {
ordersInProgress += item.orders;
totalSales += item.orders * item.price;
});
const progressBarPercentage = Math.floor((ordersInProgress / orderGoal) * 100);
const completedOrders = orderGoal - ordersInProgress;
this.state = { progressBarPercentage, completedOrders };
}
render() {
return (
<div className="progressBarBlock">
<div className = "progress progressBar">
<div className='progress-bar progressBarColor'
role='progressbar'
aria-valuenow='70'
aria-valuemin='0'
aria-valuemax='100'
style={{width: this.state.progressBarPercentage}}>
</div>
</div>
</div>
)
}
}
export default ProgressBar
3) After a closer study I found numerous problems: 1) data should come as props 2) state is not needed in this case 3) component becomes stateless functional 4) the percentage was always zero due to an error in calculation
This is the sandbox to see it working https://codesandbox.io/s/o51lnz7o99