B4J Tutorial [BANanoAPI] - Scripting the DOM: The HTML5 Canvas Story (Advanced Users)

Mashiane

Expert
Licensed User
Longtime User
On the demo source code, on the Main module, on BANano_Ready Sub, UNCOMMENT ONLY - pgCanvasDay18.Init



B4X:
Dim ctx1 As JSCanvas = canvdays.Skeleton(document, tb1, "ctx1", 1, 1)
    ctx1.Canvas.width = 600
    ctx1.Canvas.height = 600
    Dim legend As JSElement = document.createElement("DIV")
    tb1.row(1).cell(1).appendChild(legend)
    
    Dim myVinyls As Map = CreateMap("Classical music": 10, "Alternative rock": 14, "Pop": 2, "Jazz": 12)
    Dim colors As List
    colors.Initialize 
    colors.AddAll(Array("#fde23e", "#f16e23", "#57d9ff","#937e88"))
    Dim options As Map = CreateMap("data":myVinyls, "colors":colors)
    'options.put("doughnutHoleSize", 0.5)
    options.Put("legend", legend)
    '
    'calculate total value
    Dim total_value As Int = 0
    Dim color_index As Int = 0
    Dim idata As Map = options.Get("data")
    Dim icolors As List = options.get("colors") 
    '
    For Each k As String In idata.keys
        Dim v As Int = idata.get(k)
        total_value = total_value + v
    Next
    '
    Dim m As JSMath
    m.initialize
    
    Dim start_angle As Int = 0
    Dim color_index As Int = -1
    For Each categ As String In idata.keys
        Dim val As String = idata.get(categ) 
        val = BANano.parseint(val)
        '
        Dim slice_angle As Double = (2 * cPI * val) / total_value
        '
        Dim minof As Int = m.min1(Array(ctx1.canvas.width / 2, ctx1.canvas.height / 2))
        '
        color_index = color_index + 1
        Dim scolor As String = icolors.get(color_index)
         '
        ctx1.drawPieSlice(ctx1.canvas.width / 2, ctx1.canvas.height / 2, minof, start_angle, start_angle + slice_angle, scolor)
        
        start_angle = start_angle + slice_angle
    Next
    
    'drawing a white circle over the chart
    'To create the doughnut chart
    Dim doughnutHoleSize As Double = options.getdefault("doughnutHoleSize",0)
    If doughnutHoleSize > 0 Then
        ctx1.drawPieSlice(ctx1.canvas.width / 2, ctx1.canvas.height / 2, doughnutHoleSize * m.min1(Array(ctx1.canvas.width / 2, ctx1.canvas.height / 2)) , 0, 2 * cPI, "#ff0000")
    End If
    '
    start_angle = 0
    For Each categ As String In idata.keys
        Dim val As String = idata.get(categ) 
        val = BANano.parseInt(val)
        slice_angle = 2 * cPI * val / total_value
        Dim pieRadius As Double = m.min1(Array(ctx1.canvas.width/2,ctx1.canvas.height/2))
        Dim labelX As Int = ctx1.canvas.width/2 + (pieRadius / 2) * Cos(start_angle + slice_angle/2)
        Dim labelY As Int = ctx1.canvas.height/2 + (pieRadius / 2) * Sin(start_angle + slice_angle/2)
 
        If (doughnutHoleSize) > 0 Then
            Dim offset As Int = (pieRadius * doughnutHoleSize ) / 2
            labelX = ctx1.canvas.width/2 + (offset + pieRadius / 2) * Cos(start_angle + slice_angle/2)
            labelY = ctx1.canvas.height/2 + (offset + pieRadius / 2) * Sin(start_angle + slice_angle/2)
        End If
     
        Dim labelText As Int = Round(100 * val / total_value)
        ctx1.fillStyle = "white"
        ctx1.font = "bold 20px Arial"
        ctx1.fillText1(labelText & "%", labelX, labelY)
        start_angle = start_angle + slice_angle
    Next
    '
    If options.ContainsKey("legend") Then
        color_index = -1
        Dim legendHTML As StringBuilder
        legendHTML.initialize
        For Each categ As String In idata.keys
            color_index = color_index + 1
            legendHTML.Append("<div><span style='display:inline-block;width:20px;background-color:")
            legendHTML.append(icolors.get(color_index) & ";'>&nbsp;</span> " & categ & "</div>")
        Next    
        Dim lgnd As JSElement = options.get("legend")
        lgnd.innerHTML = legendHTML
    End If

Enjoy!
 

Mashiane

Expert
Licensed User
Longtime User
On the demo source code, on the Main module, on BANano_Ready Sub, UNCOMMENT ONLY - pgCanvasDay19.Init



B4X:
'Turn transparency on
    ctx.globalAlpha = 0.2
    ctx.fillStyle = "blue"
    ctx.fillRect1(50, 50, 75, 50)
    ctx.fillStyle = "green"
    ctx.fillRect1(80, 80, 75, 50)

The other example...

B4X:
ctx1.fillStyle = "red"
    ctx1.fillRect1(20, 20, 75, 50)
    ctx1.fillStyle = "blue"
    ctx1.globalCompositeOperation = "source-over"
    ctx1.fillRect1(50, 50, 75, 50)
    ctx1.fillStyle = "red"
    ctx1.fillRect1(150, 20, 75, 50)
    ctx1.fillStyle = "blue"
    ctx1.globalCompositeOperation = "destination-over"
    ctx1.fillRect1(180, 50, 75, 50)
 

Mashiane

Expert
Licensed User
Longtime User
On the demo source code, on the Main module, on BANano_Ready Sub, UNCOMMENT ONLY - pgCanvasDay20.Init

We want to style the canvases that we will draw, we use #if css

B4X:
#if css
canvas {
  border: 1px solid #d3d3d3;
  margin-right: 10px;
  margin-bottom: 20px;
}
#End If



We loop through each composition using a list..

B4X:
Dim gco As List
    gco.Initialize 
    gco.add("source-atop")
    gco.add("source-in")
    gco.add("source-out")
    gco.add("source-over")
    gco.add("destination-atop")
    gco.add("destination-in")
    gco.add("destination-out")
    gco.add("destination-over")
    gco.add("lighter")
    gco.add("copy")
    gco.add("xor")

    Dim n As Int
    Dim g As Int = gco.Size - 1
    For n = 0 To g
        Dim p As JSElement = document.createElement("P")
        p.id = $"p_${n}"$
        p.innerHTML = gco.Get(n) & ":<br>"
        p.style.float1 = "left"
        
        Dim c As JSElement = document.createElement("canvas")
        c.width = 120
        c.height = 100
        'add canvas to paragraph
        p.appendChild(c)
        Dim ctx As JSCanvas
        ctx.Initialize(c, "2d")
        ctx.fillStyle = "blue"
        ctx.fillRect1(10, 10, 50, 50)
        ctx.globalCompositeOperation = gco.Get(n)
        ctx.beginPath1
        ctx.fillStyle = "red"
        ctx.arc1(50, 50, 30, 0, 2 * cPI)
        ctx.fill1
        '
        body.appendChild(p)
        body.appendChild(document.createElement("DIV"))
    Next

This covers the basics of managing the canvas.
 

Mashiane

Expert
Licensed User
Longtime User
Let's create a clock, based on the canvas...



Based on everything we have learned and some, its time to create a clock. We will use .setInterval for this to fire every 1 second.

B4X:
'creare the context for drawing
    ctx.Initialize(canvas, "2d")
    'the radius is based on the height of the canvas
    radius = canvas.height / 2
    'remap and center the
    ctx.translate1(radius, radius)
    'clock should be inside radius
    radius = radius * 0.90
    window.setInterval(Me, "drawclock", 1000)

The code we will run will do 3 things..

B4X:
Sub drawClock()
    drawFace(ctx, radius)
    drawNumbers(ctx, radius)
    drawTime(ctx, radius)
End Sub

See the pgClock code module on the download.

Ta!
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…