user3516627
user3516627

Reputation: 41

Dividing an SVG Circle into Three Equal Parts with Responsive Design in Ionic Mobile App

I'm working on an Ionic mobile application, and I need to divide an SVG circle into three equal parts with a focus on responsive design. I've experimented with the element, but I'm facing challenges in achieving both equal division and responsiveness.

Here's a simplified example of what I've attempted:

<svg width="1000" height="1000" viewBox="0 0 1020 1040" fill="none" xmlns="http://www.w3.org/2000/svg">
  
<!-- Green Stroke -->
  <path
    d="M240 120 A120 120 0 0 1 360 240"
    stroke="green"
    stroke-width="60"
    fill="none"
  />
  <!-- Red Stroke -->
  <path
    d="M240 360 A120 120 0 0 1 240 120"
    stroke="red"
    stroke-width="60"
    fill="none"
  />

  <!-- Yellow Stroke -->
  <path
    d="M360 240 A120 120 0 0 1 240 360"
    stroke="yellow"
    stroke-width="60"
    fill="none"
  />
</svg>

I've attached screenshots illustrating the desired outcome. Could anyone provide guidance on adjusting the parameters for both equal parts and responsiveness to achieve a similar look in my Ionic mobile app? Any insights or code examples would be greatly appreciated. Thank you!

image

Upvotes: 0

Views: 162

Answers (2)

Eliseo
Eliseo

Reputation: 57939

Really create an arc is dificult using svg, but we can create a directive.

When an arc is less than 180 degrees it's not dificult and we can do it indicate the point inicial and the point final. But if the arc is greater that 180 degrees we need create two arcs.

Well, we can make a directive in the way

@Directive({
  selector: 'path [arc]',
  standalone: true,
})
export class SvgArc {
  radius: number = 0;
  center: { x: number; y: number } = { x: 0, y: 0 };
  range: { from: number; to: number } = { from: 0, to: 0 };

  @Input('radius') set _radius(value: number | string) {
    this.radius = +value;
    this.calculatePath();
  }
  @Input('center') set _center(value: { x: number; y: number }) {
    this.center = { x: value.x, y: value.y };
    this.calculatePath();
  }
  @Input('range') set _range(value: { from: number; to: number }) {
    this.range = { from: value.from, to: value.to };
    this.calculatePath();
  }

  constructor(private element: ElementRef) {}
  calculatePath() {
    const [ang1, ang2] = [
      this.range.from < this.range.to ? this.range.from : this.range.from - 360,
      this.range.to,
    ];
    const point1 = {
      x: this.center.x + this.radius * Math.cos((Math.PI / 180) * ang1),
      y: this.center.y + this.radius * Math.sin((Math.PI / 180) * ang1),
    };
    const point2 = {
      x: this.center.x + this.radius * Math.cos((Math.PI / 180) * ang2),
      y: this.center.y + this.radius * Math.sin((Math.PI / 180) * ang2),
    };
    if (Math.abs(ang1 - ang2) <= 180) {
      this.element.nativeElement.setAttribute(
        'd',
        `M${point1.x} ${point1.y} A ${this.radius} ${this.radius} 0 0 1 ${point2.x} ${point2.y}`
      );
    } else {
      const point3 = {
        x:
          this.center.x +
          this.radius * Math.cos((Math.PI / 180) * (ang1 + 180)),
        y:
          this.center.y +
          this.radius * Math.sin((Math.PI / 180) * (ang1 + 180)),
      };
      this.element.nativeElement.setAttribute(
        'd',
        `M${point1.x} ${point1.y} A ${this.radius} ${this.radius} 0 0 1 ${point3.x} ${point3.y} A ${this.radius} ${this.radius} 0 0 1 ${point2.x} ${point2.y}`
      );
    }
  }
}

Where range from/to goes from 0 to 360 degrees and the arc goes always in direction from to to in clock direction So, we can do, e.g.

<svg viewBox="0 0 100 100" >
<path stroke-width="30" arc [center]="{x:50,y:50}" radius="34" 
                            [range]="{from:ang1,to:ang2}" />
</svg>

or

<svg viewBox="0 0 100 100" style="max-width:50%;margin:auto" fill="transparent">
    <path stroke-width="30" stroke="green" arc [center]="{x:50,y:50}" radius="34" 
                            [range]="{from:-90,to:30}" />
    <path stroke-width="30" stroke="red" arc [center]="{x:50,y:50}" radius="34" 
                            [range]="{from:30,to:150}" />
    <path stroke-width="30" stroke="yellow" arc [center]="{x:50,y:50}" radius="34" 
                            [range]="{from:150,to:270}" />
</svg>

see stackblitz

Upvotes: 0

Eliseo
Eliseo

Reputation: 57939

you need understand a bit about the values of viewBox and width and height

In your case simple write some like:

<svg width="100%"  
     viewBox="80 80 320 320" fill="none" 
     xmlns="http://www.w3.org/2000/svg">
  ...
</svg>

See that the two first parameters of the viewbox translate the svg, the two last is a "scale" the svg.

NOTE: In general viewbox in the way

  viewBox="minX minY width height"
  • minX+width have the same value than the point more right in the svg
  • minY+heigth have the same value than the point more bottom in your svg

Arcs are the more difficult svg concept. We can use some arcs generators like

http://xahlee.info/js/svg_circle_arc.html#google_vignette

or

https://milevski.co/svg-arc-corners/demo/

e.g. we can write

    <svg width="100%" viewBox="50 50 300 300" fill="none" xmlns="http://www.w3.org/2000/svg">
      
    <!-- Green Stroke -->
      <path
        d="M 209 100 A 100 100 275 0 1 291 242"
        stroke="green"
        stroke-width="60"
        fill="none"
      />
      <path
        d="M 282 257 A 100 100 395 0 1 118 257"
        stroke="red"
        stroke-width="60"
        fill="none"
      />
      <path
        d="M 109 242 A 100 100 515 0 1 191 100"
        stroke="yellow"
        stroke-width="60"
        fill="none" 
      />
    </svg>

Upvotes: 2

Related Questions