CSS Styling Pie Chart / Doughnut chart - javascript

I'm using Recharts to try to accomplish a doughnut chart with rounded segments, which should end by looking more or less like this:
This is the closest I can achieve, but as you can see I'm running into some problems:
First, the first segment is overlapping the others at both edges. I don't know how to correct that despite my searches.
Next, I'm struggling with aligning the legend properly. I found no way to define a width to svg text so long text would go to the next line. (These texts are contained into variables and not hardcoded)
This is my chart.js. I cropped some parts to make it simpler, but I'll post the whole thing if needed.
const renderLabelContent = (props) => {
const { value, title, x, y, midAngle } = props;
return (
<g transform={`translate(${x}, ${y})`} textAnchor={'start'}>
<text x={(midAngle < -90 || midAngle >= 90) ? (0 - (title.length * 3)) : 0} y={0}
{`${title}`}
</text>
<text x={(midAngle < -90 || midAngle >= 90) ? (0 - (title.length * 3)) : 0} y={20}>
{`${value}`}€
</text>
</g>
);
};
...
export default class Chart extends Component {
...
render() {
return (
<div className="pie-charts">
<div className="pie-chart-wrapper">
<PieChart width={400} height={400}>
<Pie
stroke="none"
legendType="circle"
data={this.state.data}
dataKey="value"
startAngle={180}
endAngle={-180}
cornerRadius={100}
innerRadius={60}
outerRadius={80}
label={renderLabelContent}
paddingAngle={-10}
labelLine={false}
isAnimationActive={true}
>
{
data.map((entry, index) => (
<Cell key={`slice-${index}`} fill={entry.color} />
))
}
<Label width={50} position="center">
2,87€
</Label>
</Pie>
</PieChart>
</div>
</div>
);
}
}

I think there are a couple of ways to approach the Labels issue, in recharts you can place a React component on the Label content prop, and this could be the way for you to inject your own custom Text component that has a max-width and wrap, for example:
<Label content={<Text warp style={{maxWidth:"50px"}}>long string </Text> } />
One more option is to play with the offset property of the label, but it is flexible and will impact the overall Label position, for example:
<Label value="Pages of my website" offset={0} position="center" />

Related

Three.js cant see corner of cubes

I created an Orbital Controls with a boxGeometry to render a box. However, when I zoom to my desired distance from the box, the corners of the box do not get rendered like so:
I am currently using react-three-fiber and react-three-drei
const SceneItems = () => {
return (
<>
<OrbitControls
minDistance={0.001}
/>
<ambientLight intensity={0.5} />
<spotLight position={[10, 15, 10]} angle={0.3} />
<Cube />
</>
)
}
const CompleteScene = () => {
return (
<div id={styles.scene}>
<Canvas
camera={{ position: [0, 0, 0] }}
orthographic={true}
>
<SceneItems />
</Canvas>
</div>
)
}
I figured I could reduce the minDistance on the OrbitalControls but to no effect. What am I missing?
Not sure if this counts as a complete answer, but for whatever reason when I remove the camera property in <Canvas> I am finally able to get the result that I want. I think since <Canvas/> provides a perspectiveCamera by default and I added the props there, it overrode my added orbitalControls.

How to rotate a svg based on its center not its starting point in React Native?

I am facing a little problem, I wish I can get some help here!
I have a Picto Icon like this :
const PictoIcon = ({ color, size }) => (
<StyledSvg xmlns="http://www.w3.org/2000/svg" size={size} viewBox="0 0 24 24">
<Path fill={color} d="M12,2L4.5,20.3L5.2,21l6.8-3l6.8,3l0.7-0.7L12,2z" transform="rotate(45)" />
</StyledSvg>
);
The Picto is inside a Map Marker : ( this won't help in my example, thje code above has to be enough )
<Marker
style={isAndroid ? rotation : {}}
tracksViewChanges={showPicto}
key={id}
onPress={handleOnClickMark(marker)}
coordinate={coordinate}
identifier={id}
>
{showPicto && <View style={{backgroundColor: 'red'}}><PictoIcon size={30} color={color}/></View>}
{!showPicto && (isPoint ? <PointWrapper /> : <MarkerIcon size={50} color={color} />)}
</Marker>
I need my marker to be rotated based on the cap variable, but it is not doing good in IOS, so I want that in IOS I rotate the SVG .. But the rotation is based on the starting point of the icon, not its center
Why I am having a problem ? it because my View is a square ( I see that because the backgroudnColor I set there ), and when my svg is rotated by 90 degree for example, it comes off the view, and I don't know why part of it start disappering ( looks like overflow hidden effect in css )
Any help would be mucch appreciated.
The SVG-rotate transformation takes three arguments, of which the last two signify the center of rotation. If omitted, the origin is assumed. See here.
So you need to provide the center-coordinates of your svg as those.
To get the center of any given svg you can use the getBBox-method, to get x, y, width and height of it. With that information you can calculate those two points, for example like so:
const [xP, yP] = [Math.trunc(x + width * 0.5), Math.trunc(y + height * 0.5)];
Edit: I'm not sure if react native supports getBBox!

Recharts — Is there a way to add a padding between the chart and labels for RadarChart?

I'm looking at the simple RadarChart example from their website and I would like to add some padding between the labels and the chart itself but there doesn't seem to be a simple way to do this.
Can this be done somehow or can someone suggest another chart library I could use?
One way to do it is to use a custom tick and manipulate the x and y values
function renderPolarAngleAxis({ payload, x, y, cx, cy, ...rest }) {
return (
<Text
{...rest}
verticalAnchor="middle"
y={y + (y - cy) / 2}
x={x + (x - cx) / 2}
>
{payload.value}
</Text>
);
}
return (
<RadarChart data={data}>
...
<PolarAngleAxis tick={props => renderPolarAngleAxis(props)} />
...
</RadarChart>
)
Here's the result
You can do it with CSS
those have .recharts-polar-angle-axis-tick-value class, so simply add css on it
.recharts-polar-angle-axis-tick-value {
transform: translateX(-3rem);
}

d3.pie() returning 1/4 of a circle when creating a donut chart

I'm trying to create a donut chart with React and d3.js. I've been looking over the doc's on pies and charts here https://github.com/d3/d3-shape/blob/v1.3.7/README.md#pie_startAngle. I'm struggling to figure out where I'm making my mistake. I have an array of objects and I'm getting the pie values using
const createPie = d3
.pie()
.value(function(d) {return d.cases})
This returns an array with
but when ever I try to use that data in an arc generator it only generates the arcs to a quarter of the circle. The following code is used to generate the quarter of an arc
useEffect(
() => {
const data = createPie(pieData);
console.log('data',data)
let arcs = data.map( item => {
let createTry = d3.arc()
.innerRadius(300)
.outerRadius(400)
.startAngle(item.startAngle )
.endAngle(item.endAngle);
return createTry(item);
});
setArcs(arcs);
}, [pieData]
)
Finally I try to map the path generated onto an svg. I believe the problem stems from the d3.pie()
<div>
<svg height={400} width={400}>
{arcs && arcs.map( arc => {
return(
<path d={arc}/>
)
})}
</svg>
</div>
Any help or a point to a place in the docs that might help me understand my mistakes would be greatly appreciated. Thanks. Also here is a working example of the issue I'm having https://codesandbox.io/s/react-d3js-example-f4ylk?file=/src/components/Chart.js
The width and height of the SVG are 400, and the radius of your pie is 400 too. So only a quarter of the pie is visible.
If you increase the size of the SVG to 800 (radius x 2), and add a g element to contain your pie, which is translated to the centre of the SVG, then it will show.
For example, update your code to include:
return (
<div>
<svg height={800} width={800}><g transform="translate(400,400)">
{arcs &&
arcs.map(arc => {
return <path d={arc} />;
})}
</g></svg>
</div>
);

How to loop images with react-native-svg

I'm working on a project with react native and we chose to use react-native-svg in order to display our map. Everything's worked perfectly so far, except for this :
I have an array of objects that each have coordinates and a size. I want to loop through this array to display an image at all of these coordinates. But no luck, I managed to diplay shapes and texts but no images.
Here is the render function of my parent element :
render() {
return (
<View>
<Svg
height={screen.height}
width={screen.width}
>
<G
width={mapSize.x}
height={mapSize.y}
x={this.state.center.x}
y={this.state.center.y}
originX={mapSize.x / 2}
originY={mapSize.y / 2}
rotation={this.state.orientation}
scale={1}
>
<Rect
width={mapSize.x}
height={mapSize.y}
x={0}
y={0}
scale={1}
fill="#0071e9"
/>
<G
width={mapSize.x}
height={mapSize.y}
x={this.state.cnv.x}
y={this.state.cnv.y}
scale={1}
>
// this is my child component's tag
<Islands
islands={this.state.contentToRender}
deg={this.state.orientation}
/>
</G>
</G>
<Image
x={(screen.width / 2) - 50}
y={-(screen.height / 2) + 94.46}
width="100"
height="189.9"
preserveAspectRatio="xMidYMid slice"
href={images.bateau}
/>
</G>
</Svg>
</View>
)
}
}
here is my child component's render :
render(){
const that = this
return(
this.props.islands.map((c) => {
return (
<Image
key={ c.id }
x={ c.position.x }
y={ c.position.y }
width={ c.size.x }
height={ c.size.y }
preserveAspectRatio="xMidYMid slice"
rotation={-that.props.deg}
originX={ c.position.x + (c.size.x / 2) }
originY={ c.position.y + (c.size.y / 2) }
href={images.rouge}
/>
)
})
)
}
And finally my images.js file :
const images = {
boussole: require('./img/Boussole.png'),
aiguille: require('./img/Aiguille.png'),
bateau: require('./img/Bateau.png'),
home: require('./img/home.png'),
cyclop_island: require('./img/ile_cyclope_navig.png'),
rouge: require('./img/smiley-carre-rouge-simple-face-magnetique.jpg'),
}
export default images
I have no issue with any aspect of the Svg component, I can display every image of the images.js file as long as they are not in a loop.
Also, even if the image doesn't display the console shows no error.

Categories

Resources