Android Question [Solved] How to create a circle like this?

asales

Expert
Licensed User
Longtime User
There are a (easy) way to create a circle like that?

A circle made of other indexed littles circles, with different sizes, which I can change the color of the individual circle?

The way that I found is create individual panels in the designer, but is difficult to arranje in a circle format.

I will grad to hear other ideas.
Thanks in advance.
 
Solution
Is it something like this what you are looking for ?


And the code:

B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    
    Private pnlCircles As B4XView
    Private cvsCircles As B4XCanvas
    Private X0, Y0, BigRadius As Int
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    
    cvsCircles.Initialize(pnlCircles)
    
    X0 = pnlCircles.Width / 2
    Y0 = pnlCircles.Height / 2
    BigRadius = 120dip
    DrawCircles
End Sub

Private Sub DrawCircles
    Private Angle As Double
    Private R1, R2 As Int
    
    R1 = 4dip
    R2 = 6dip
    
    cvsCircles.DrawCircle(X0, Y0...

Sandman

Expert
Licensed User
Longtime User
Pretty simple, yes. It's just a loop with a little sin() and a little cos() and you got a circle. Adjust that and instead use as center for a small circle that toggle between sizes and colors as you like. All in a canvas, obviously.
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
A follow-up. Conceptually there's nothing different between what you want to achieve and the gauges here:
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Is it something like this what you are looking for ?


And the code:

B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    
    Private pnlCircles As B4XView
    Private cvsCircles As B4XCanvas
    Private X0, Y0, BigRadius As Int
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    
    cvsCircles.Initialize(pnlCircles)
    
    X0 = pnlCircles.Width / 2
    Y0 = pnlCircles.Height / 2
    BigRadius = 120dip
    DrawCircles
End Sub

Private Sub DrawCircles
    Private Angle As Double
    Private R1, R2 As Int
    
    R1 = 4dip
    R2 = 6dip
    
    cvsCircles.DrawCircle(X0, Y0, BigRadius, xui.Color_Black, False, 1dip)
    For Angle = 0 To 350 Step 10
        If (Angle Mod 40) = 0 Then
            DrawCircle(Angle, R2, xui.Color_Red)
            Else
            DrawCircle(Angle, R1, xui.Color_RGB(Rnd(0, 255), Rnd(0, 255), Rnd(0, 255)))
        End If
    Next
End Sub

Private Sub DrawCircle(Angle As Double, Radius As Int, Color As Int)
    Private x, y As Int
    
    x = X0 + BigRadius * CosD(Angle)
    y = Y0 + BigRadius * SinD(Angle)
    
    cvsCircles.DrawCircle(x, y, Radius, Color, True, 1dip)
End Sub

Attached the test B4XPages project.
 
Upvote 3
Solution

javiers

Active Member
Licensed User
Longtime User
Hello, would it be possible for each of the circles created to respond to an event (mouse click...?
Thanks in advance...
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Yes, but not directly with the method used.
The circle is drawn on a Panel.
This means that the Panel_Touch event would be used then you need to memorize the position of each circle and check if the touch coordinates are on a circle and return the index of the touched circle.

Another method could be to use Labels or Panels for the small circles as tried by asales.
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
A third possibility is to keep a separate parallel B4XBitmap that has the pixels corresponding to the circle with a color definition that encodes the
identity of the circles. However, because your shapes are circles, the simplest approach is the one proposed by @klaus

In any case, if you are interested, any shape can be turned into a button with a parallel bitmap. See link
There is very little code, but it is not very intuitive. Each pixel's co-ordinates in the clicked panel are indexed in the bitmap for the shape's identity.

https://www.b4x.com/android/forum/t...scellaneous-image-shapes-into-buttons.140309/
 
Upvote 0

emexes

Expert
Licensed User
A fourth possibility, thanks to the circles being arranged in a regular fashion on the larger circle, is to convert the touch (x, y) back to an angle about the centre of the larger circle (X0, Y0) and multiply that angular fraction by the number of smaller circles to get the index of the small circle.

<JOKE>
I dub this the go forth and multiply solution. ?
</JOKE>
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
convert the touch (x, y) back to an ... index of the small circle

B4X:
Sub WhichCircle(CenterX As Int, CenterY As Int, NumCircles As Int, TouchX As Int, TouchY As Int) As Int
    Dim A As Float = ATan2D(TouchY - CenterY, TouchX - CenterX)

    Dim I As Int = Floor(A / 360 * NumCircles + 0.5)    'might be negative or too many
    Dim AI As Int = (I + NumCircles) Mod NumCircles    'bring back into range 0..NumCircles-1
 
    Return AI
End Sub
 
Last edited:
Upvote 0

klaus

Expert
Licensed User
Longtime User
Dim A As Float = 90 - ATan2D(TouchX - CenterX, TouchY - CenterY) 'to match Klaus clockwise angle
This is the same :
B4X:
Dim A As Float = ATan2D(TouchY - CenterY, TouchX - CenterX)
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Attached a modified version with the Touch event.
You may need to adjust the snap distance.

And the code:

B4X:
Private Sub pnlCircles_Touch (Action As Int, X As Float, Y As Float)
    Private Radius, Delta, DAngle, AngleTouch, AngleCircle As Double
    
    Delta = 8dip        'snap distance in pixels
    DAngle = Delta * 180 / cPI / BigRadius    'snap angle in degrees
    If Action = pnlCircles.TOUCH_ACTION_UP Then
        Radius = Sqrt((X - X0) * (X - X0) + (Y - Y0) * (Y - Y0))    'touch radius
        If Abs(Radius - BigRadius) <= Delta Then    'checks if the cursor is near the big cicle
            AngleTouch = ATan2D(Y - Y0, X - X0)    'cursor angle
            If AngleTouch < 0 Then    'Atan2 returns angles between -180 and + 180 degrees
                If AngleTouch > -DAngle Then
                    AngleTouch = 0    'near 0, the angle can be 0.xxx or 359.xxx
                Else
                    AngleTouch = 360 + AngleTouch    'converts the -180 - +180 range to 0 - 360
                End If
            End If
            For i = 0 To lstCircles.Size - 1
                AngleCircle = lstCircles.Get(i)
                If Abs(AngleTouch - AngleCircle) <= DAngle Then
                    CircleTouched(i, AngleCircle)
                    Exit
                End If
            Next
        End If
    End If
End Sub

Private Sub CircleTouched(Index As Int, Angle As Double)
    Log("Index: = " & Index & "  Angle = " & Angle)
End Sub
 

Attachments

  • Circles1.zip
    3.3 KB · Views: 63
Upvote 0

klaus

Expert
Licensed User
Longtime User
I played a bit further with this project to show what can be done.
When you touch the screen and move the finger a cursor is displayed, the red cross.
When the cursor is near a circle, this one is highlighted with a blue circle.
In B4A and B4i the cursor is not just underneath the finger but shifted upwards by OffsetY.
The picture below is drawn with the B4J version, this is why you see the mouse cursor.

 

Attachments

  • Circles2.zip
    3.7 KB · Views: 72
Last edited:
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…