I am trying to make a circular progress bar with dashed line. I programmatically create stroke-dasharray
and stroke-dashoffset
to draw a circle with pe
Not sure if this is somewhat in the range of what you are looking for. ( full snippet / demo below)
Im not an expert on this subject, so there might be another option (like two half circles with different styling) - but what is basically done here is to lay another circle on top of the solid circle, and make sure it has the same stroke color as the page. This will then mask over gaps of the circle behind, (basically hide parts of the circle).
<circle
className="circle-dashes"
cx={this.props.sqSize / 2}
cy={this.props.sqSize / 2}
r={radius}
strokeWidth={`${this.props.strokeWidth}px`}
style={{
strokeDasharray: "5 10" // Adjust the spacing here
}} />
css:
.circle-dashes {
stroke: #FFF;
fill: none;
}
and remove
stroke-linecap: round;
stroke-linejoin: round;
A few minor tweaks to fit your need, and hopefully you got it!
If you take a look at the app with another background color, the changes might be more obvious.
class CircularProgressBar extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
// Size of the enclosing square
const sqSize = this.props.sqSize;
// SVG centers the stroke width on the radius, subtract out so circle fits in square
const radius = (this.props.sqSize - this.props.strokeWidth) / 2;
// Enclose cicle in a circumscribing square
const viewBox = `0 0 ${sqSize} ${sqSize}`;
// Arc length at 100% coverage is the circle circumference
const dashArray = radius * Math.PI * 2;
// Scale 100% coverage overlay with the actual percent
const dashOffset = dashArray - dashArray * this.props.percentage / 100;
return (
<svg
width={this.props.sqSize}
height={this.props.sqSize}
viewBox={viewBox}>
<circle
className="circle-background"
cx={this.props.sqSize / 2}
cy={this.props.sqSize / 2}
r={radius}
strokeWidth={`${this.props.strokeWidth}px`} />
<circle
className="circle-progress"
cx={this.props.sqSize / 2}
cy={this.props.sqSize / 2}
r={radius}
strokeWidth={`${this.props.strokeWidth}px`}
// Start progress marker at 12 O'Clock
transform={`rotate(-90 ${this.props.sqSize / 2} ${this.props.sqSize / 2})`}
style={{
strokeDasharray: dashArray,
strokeDashoffset: dashOffset
}} />
<circle
className="circle-dashes"
cx={this.props.sqSize / 2}
cy={this.props.sqSize / 2}
r={radius}
strokeWidth={`${this.props.strokeWidth}px`}
style={{
strokeDasharray: "5 10"
}} />
</svg>
);
}
}
CircularProgressBar.defaultProps = {
sqSize: 200,
percentage: 25,
strokeWidth: 10
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
percentage: 25
};
this.handleChangeEvent = this.handleChangeEvent.bind(this);
}
handleChangeEvent(event) {
this.setState({
percentage: event.target.value
});
}
render() {
return (
<div>
<CircularProgressBar
strokeWidth="10"
sqSize="200"
percentage={this.state.percentage}/>
<div>
<input
id="progressInput"
type="range"
min="0"
max="100"
step="1"
value={this.state.percentage}
onChange={this.handleChangeEvent}/>
</div>
</div>
);
}
}
ReactDOM.render(
<App/>,
document.getElementById('app')
);
#app {
margin-top: 40px;
margin-left: 50px;
}
#progressInput {
margin: 20px auto;
width: 30%;
}
.circle-background,
.circle-progress {
fill: none;
}
.circle-background {
stroke: #ffffd;
}
.circle-dashes {
stroke: #fff;
fill: none;
}
.circle-progress {
stroke: #F99123;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div class="container">
<div class="text-center" id="app">
</div>
</div>