Continue 'Paint' implementation, and make the DrawingArea canvas resize automatically.

[GB.WEB.GUI]
* NEW: DrawingArea: The canvas now resizes automatically, and send its size to the server.
* NEW: Paint: Implement 'Width' and 'Height' properties.
* NEW: Paint: Add 'Translate()', 'Rotate()', 'Scale()' and 'Reset()' methods.
* NEW: Paint: Add write-only 'Operator' property. Not all composition modes are supported at the moment.
* BUG: Move focus frame when the window is resized.
This commit is contained in:
Benoît Minisini 2022-08-09 17:04:06 +02:00
parent f94f6ecf87
commit 5f958623a4
9 changed files with 194 additions and 49 deletions

View file

@ -5,8 +5,14 @@ Export
Static Private $aStack As New PaintDriver[]
Static Property Read Device As WebControl
Static Property Write LineWidth As Float
Static Property Brush As PaintBrush
Static Property W, Width As Integer Use $iWidth
Static Property H, Height As Integer Use $iHeight
Static Property Write LineWidth As Float
Static Property Write Operator As Integer
Public Enum OperatorOver, OperatorIn, OperatorOut, OperatorATop, OperatorDestOver, OperatorDestIn, OperatorDestOut, OperatorDestATop, OperatorAdd, OperatorSource, OperatorXor
Static Private $hCurrent As New PaintDriver
@ -172,3 +178,34 @@ Static Public Sub DrawImage(Image As String, X As Float, Y As Float, Optional Wi
$hCurrent.DrawImage(Image, X, Y, Width, Height, Opacity, Source)
End
Static Public Sub Translate(TX As Float, TY As Float)
$hCurrent.Translate(TX, TY)
End
Static Public Sub Rotate(Angle As Float)
$hCurrent.Rotate(Angle)
End
Static Public Sub Scale(SX As Float, Optional SY As Float)
If IsMissing(SY) Then SY = SX
$hCurrent.Scale(SX, SY)
End
Static Public Sub Reset()
$hCurrent.Reset()
End
Static Private Sub Operator_Write(Value As Integer)
$hCurrent.SetOperator(Value)
End

View file

@ -73,3 +73,22 @@ Public Sub DrawImage((Image) As String, (X) As Float, (Y) As Float, (Width) As F
End
Public Sub Translate((TX) As Float, (TY) As Float)
End
Public Sub Rotate((Angle) As Float)
End
Public Sub Scale((SX) As Float, (SY) As Float)
End
Public Sub Reset()
End
Public Sub SetOperator((Op) As Integer)
End

View file

@ -6,9 +6,16 @@ Private $aEnd As New String[]
Public Sub Begin()
WebForm._AddJavascript("{ var $_c = $_(" & JS(Me.Device.Name) & ").getContext('2d');")
Dim hDrawingArea As WebDrawingArea
WebForm._AddJavascript("{ var $_c = $_(" & JS(Me.Device.Name & ":canvas") & ").getContext('2d');")
WebForm._AddJavascript("$_c.beginPath();")
hDrawingArea = Me.Device
Paint.W = hDrawingArea._Width
Paint.H = hDrawingArea._Height
End
Public Sub End()
@ -198,3 +205,60 @@ Public Sub DrawImage(Image As String, X As Float, Y As Float, Width As Float, He
$aEnd.Add("});\n")
End
Public Sub Translate(TX As Float, TY As Float)
WebForm._AddJavascript("$_c.translate(" & JS(TX) & "," & JS(TY) & ");")
End
Public Sub Rotate(Angle As Float)
WebForm._AddJavascript("$_c.rotate(" & JS(Angle) & ");")
End
Public Sub Scale(SX As Float, SY As Float)
WebForm._AddJavascript("$_c.scale(" & JS(SX) & "," & JS(SY) & ");")
End
Public Sub Reset()
WebForm._AddJavascript("$_c.resetTransform();")
End
Public Sub SetOperator(Op As Integer)
Dim sOp As String
Select Case Op
Case Paint.OperatorOver
sOp = "source-over"
Case Paint.OperatorIn
sOp = "source-in"
Case Paint.OperatorOut
sOp = "source-out"
Case Paint.OperatorATop
sOp = "source-atop"
Case Paint.OperatorDestOver
sOp = "destination-over"
Case Paint.OperatorDestIn
sOp = "destination-in"
Case Paint.OperatorDestOut
sOp = "destination-out"
Case Paint.OperatorDestATop
sOp = "destination-atop"
Case Paint.OperatorAdd
sOp = "lighter"
Case Paint.OperatorSource
sOp = "copy"
Case Paint.OperatorXor
sOp = "xor"
End Select
If sOp Then WebForm._AddJavascript("$_c.globalCompositeOperation = " & JS(sOp) & ";")
End

View file

@ -35,6 +35,10 @@ Public Sub WebDrawingArea1_Draw()
Paint.DrawImage("favicon.png", 150, 10, 200, 200, 0.5, Rect(10, 10, 100, 100))
Paint.Rectangle(5.5, 5.5, Paint.W - 12, Paint.H - 12)
Paint.LineWidth = 1
Paint.Stroke(Color.Red)
End
Static Public Sub _init()

View file

@ -2,20 +2,18 @@
{ WebForm WebForm
#MoveScaled(0,0,64,91)
Height = "40em"
Background = Color.SoftYellow
Arrangement = Arrange.Vertical
Margin = True
Spacing = True
{ WebContainer1 WebHBox
#MoveScaled(1,1,62,32)
{ WebDrawingArea1 WebDrawingArea
#MoveScaled(1,1,34,30)
Width = "400px"
Height = "400px"
Border = True
}
{ WebDrawingArea1 WebDrawingArea
#MoveScaled(1,1,62,30)
Expand = True
Border = True
}
{ WebHBox1 WebHBox
#MoveScaled(1,34,62,7)
#MoveScaled(1,32,62,7)
{ WebButton1 WebButton
#MoveScaled(1,1,16,5)
Text = ("Refresh")

View file

@ -7,6 +7,9 @@ Public Const _Properties As String = "*,Border"
Public Const _DrawWith As String = "DrawingArea"
Public Const _DefaultEvent As String = "Draw"
Public _Width As Integer
Public _Height As Integer
Event Draw
' Event MouseDown
' Event MouseMove
@ -19,46 +22,21 @@ Public Sub _new()
End
Public Sub _BeforeRender()
Dim sWidth As String
Dim iWidth As Integer
Dim sHeight As String
Dim iHeight As Integer
sWidth = Me.Width
If sWidth Ends "px" Then Try iWidth = CInt(Left(sWidth, -2))
sHeight = Me.Height
If sHeight Ends "px" Then Try iHeight = CInt(Left(sHeight, -2))
Print "<canvas"; Me._GetClassId();
Me._RenderStyleSheet()
If iWidth And If iHeight Then Print " width=\""; iWidth; "\" height=\""; iHeight; "\"";
Print ">";
End
Public Sub _Render()
If Object.CanRaise(Me, "Draw") Then WebForm._AddJavascript("gw.update(" & JS(Me.Name) & ",'#',null);")
Print "<canvas id=\""; Html(Me.Name & ":canvas"); "\"></canvas>";
WebForm._AddJavascript("gw.paint.init(" & JS(Me.Name) & ");")
End
Public Sub _UpdateProperty(sProp As String, (vValue) As Variant)
Public Sub _UpdateProperty(sProp As String, vValue As Variant)
If sProp = "#" Then
_Width = vValue[0]
_Height = vValue[1]
Paint.Begin(Me)
Raise Draw
Paint.End
Endif
End
Public Sub _AfterRender()
Raise Render
Print "</canvas>";
End

View file

@ -791,7 +791,7 @@ Public Sub Render()
$aJavascript.Clear
Print "<body onload=\"gw.onload();\">"
Print "<body onload=\"gw.body.onLoad();\" onresize=\"gw.body.onResize();\">"
If $sActiveControl Then $aJavascript.Add("gw.setFocus(" & JS($sActiveControl) & ");")
@ -1684,3 +1684,4 @@ Static Public Function _GetActiveControl() As WebControl
Endif
End

View file

@ -249,7 +249,8 @@ gw = {
{
if (xhr.status == 200 && xhr.responseText)
{
xhr.gw_command && gw.log('==> ' + xhr.gw_command + '...');
if (gw.debug && xhr.gw_command)
gw.log('==> ' + xhr.gw_command + '...');
gw.focus = false;
var save = gw.saveFocus();
@ -1783,6 +1784,31 @@ gw = {
paint:
{
init: function(id)
{
if (!gw.resizeObserver)
{
gw.resizeObserver = new ResizeObserver(function(entries)
{
for (let elt of entries)
gw.paint.update(elt.target.id);
});
}
gw.resizeObserver.observe($_(id));
gw.paint.update(id);
},
update: function(id)
{
var w = $_(id + ':canvas').offsetWidth;
var h = $_(id + ':canvas').offsetHeight;
$_(id + ':canvas').width = w;
$_(id + ':canvas').height = h;
console.log('gw.paint.update: ' + w + ',' + h);
gw.update(id, '#', [w, h]);
},
makeGradient: function(ctx, mo, coords, stops)
{
var grad, i, st;
@ -1898,14 +1924,23 @@ gw = {
gw.sendKeyPress(event, id);
},
onload: function()
body:
{
document.body.addEventListener('focusin', gw.onFocus);
document.body.addEventListener('focusout', gw.onFocus);
gw.raise(null, 'open');
document.body.style.opacity = '1';
document.body.style.pointerEvents = 'auto';
onLoad: function()
{
document.body.addEventListener('focusin', gw.onFocus);
document.body.addEventListener('focusout', gw.onFocus);
gw.raise(null, 'open');
document.body.style.opacity = '1';
document.body.style.pointerEvents = 'auto';
},
onResize: function()
{
gw.onFocus();
}
}
}
document.onkeydown = gw.onKeyDown;

View file

@ -1105,9 +1105,18 @@ TD.gw-table-check {
}
.gw-drawingarea {
position: relative;
border: solid 1px #C0C0C0;
}
.gw-drawingarea.gw-noborder {
border: none;
}
.gw-drawingarea > CANVAS {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}