Search code examples
javascriptreactjsgatsbystrapi

Draw dynamic circle in gatsby react issue


I am using Strapi as a backend, and in my frontend I am using Gatsby.

I am using the values from the backend to draw a circle inside a card. The number of cards are generated from the backend value.

For now I am hard coding the three first cards in css with n:th child values with the following css code:

.svgAssesment circle {
  width: 100%;
  height: 100%;
  fill: none;
  stroke-width: 10;
  stroke: rgba(255, 255, 255, 0.05);
  transform: translate(5px, 5px);
  stroke-linecap: round;
}
.svgAssesment circle:nth-child(2) {
  stroke: #fff;
  stroke-dasharray: 440px;
}
.card:nth-child(1) .svgAssesment circle:nth-child(2) {
  stroke-dashoffset: calc(440px - (440px * 9) / 10);
}
.card:nth-child(2) .svgAssesment circle:nth-child(2) {
  stroke-dashoffset: calc(440px - (440px * 9) / 10);
}
.card:nth-child(3) .svgAssesment circle:nth-child(2) {
  stroke-dashoffset: calc(440px - (440px * 8) / 10);
}

Instead of hard coding these values, is there a way to draw them dynamically so that each circle's stroke-dashoffset is based upon the prop {item.rate} I have in my frontend. So in the example above the hard coded values are 9,9 and 8 should be replaced with the values of {item.rate} for each of the cards generated and not just the three I have in my nth:child code.

This is my frontend code:

import React from "react"
import Title from "./Title"
import { graphql, useStaticQuery } from "gatsby"

    const query = graphql`
      {
        allStrapiAssessment {
          nodes {
            title
            rating {
              id
              topic
              rate
            }
          }
        }
      }
    `
    
    const SelfAssesment = () => {
      const data = useStaticQuery(query)
      //console.log(data)
    
      const {
        allStrapiAssessment: { nodes: assesments },
      } = data
      //console.log(assesments)
      const [value] = React.useState(0)
      const { title, rating } = assesments[value]
      console.log(title, rating)
    
      return (
        <section className="section jobs">
          <Title title={title} />
    
          <section className="assesment">
            <div className="container">
              {rating.map(item => {
                return (
                  <div key={item.id} className="card">
                    <div className="box">
                      <div>
                        <div class="percent">
                          <svg className="svgAssesment">
                            <circle cx="70" cy="70" r="70"></circle>
                            <circle cx="70" cy="70" r="70"></circle>
                          </svg>
                          <div class="number">
                            <h2>
                              {item.rate}
                              <span>/10</span>
                            </h2>
                          </div>
                        </div>
                      </div>
                    </div>
                    <div id="buttonColor" className="text">
                      {item.topic}
                    </div>
                  </div>
                )
              })}
            </div>
          </section>
        </section>
      )
    }
    
    export default SelfAssesment

Solution

  • You will need to use styled-components in order to use React props in the styling.

    Alternatively, you can just use inline styles for stroke-dashoffset CSS rule and delegate the rest of the styling into your CSS stylesheet. Something like:

    import React from "react"
    import Title from "./Title"
    import { graphql, useStaticQuery } from "gatsby"
    
    const query = graphql`
      {
        allStrapiAssessment {
          nodes {
            title
            rating {
              id
              topic
              rate
            }
          }
        }
      }
    `
    
    const SelfAssesment = () => {
      const data = useStaticQuery(query)
      //console.log(data)
    
      const {
        allStrapiAssessment: { nodes: assesments },
      } = data
      //console.log(assesments)
      const [value] = React.useState(0)
      const { title, rating } = assesments[value]
      console.log(title, rating)
    
      return (
        <section className="section jobs">
          <Title title={title} />
    
          <section className="assesment">
            <div className="container">
              {rating.map(item => {
                return (
                  <div key={item.id} className="card">
                    <div className="box">
                      <div>
                        <div class="percent">
                          <svg className="svgAssesment">
                            <circle cx="70" cy="70" r="70"/>
                            <circle cx="70" cy="70" r="70" style={{ 
                              strokeDashoffset: `calc(440px - (440px * ${item.rate}) / 10)`
                            }}/>
                          </svg>
                          <div class="number">
                            <h2>
                              {item.rate}
                              <span>/10</span>
                            </h2>
                          </div>
                        </div>
                      </div>
                    </div>
                    <div id="buttonColor" className="text">
                      {item.topic}
                    </div>
                  </div>
                )
              })}
            </div>
          </section>
        </section>
      )
    }
    
    export default SelfAssesment
    

    Note the:

     <circle cx="70" cy="70" r="70" style={{ 
        strokeDashoffset: `calc(440px - (440px * ${item.rate}) / 10)`
      }}/>
    

    In the snippet above you are just calculating the stroke-dashoffset rule with inline styles applying the dynamic item.rate value in the second circle.