PictureBox

From NSB App Studio
Jump to navigation Jump to search

Description

The PictureBox control allows the placement of text, images and drawings on the screen. It is a very powerful control, based on HTML5’s Canvas element.

To add a PictureBox to your app, choose the PictureBox icon in the Toolbar, then position it on the Design Screen. Use the Property Editor to set the properties you need, then add functions to your code to respond to the events that come from the button.

Images should be in your project folder or a subfolder. Add the name of the file or folder to the manifest in Project Properties.

The PictureBox acts as a container for a runtime context which contains the actual images and drawing. Use getContext("2d") to get the context. Once you have the context, you can manipulate its contents using the Runtime Context Properties and Methods shown below.

If you change the content of a scrolling PictureBox, do Picturebox1.refresh() to reset the scrolling.

Resizing at Runtime

PictureBoxes do not work well when sized by percentages.

PictureBoxes (which are based on the HTML5 Canvas element) are a bit trickier than most other controls. The main thing to keep in mind is that a canvas has both dimensions (specified by CSS - that is, PB.style.height), and a canvas size, specified by attributes on the actual tag (that is PB.height - NOT PB.Height).

Keeping that in mind, the next thing to be aware of is that AppStudio tries to do the right thing in most cases - so, when you set PB.Height, it not only sets the dimensions of the canvas, but also sets the canvas size as well. So, setting PB.Height actually does two things:

  1. Sets PB.style.height
  2. Sets PB.height

Now, problems start to happen when you use percentages. If you read the HTML5 spec, you'll see that the canvas size CANNOT be specified with anything other than integers. If you specify the canvas size as 66%, for instance, the result is fairly implementation dependent, but most browsers seem to interpret this as 66px. So, when you set PB.Height = "66%", what happens is that PB.style.height is set to 66%, but PB.height is set to 66. This is obviously a problem.

The solution is to set the dimensions and canvas size discretely. Probably the easiest way to do this would be to size the PictureBox using percentages in the IDE. Then, on form load, run the following code before drawing:

Dim actualHeight = PB.getBoundingClientRect().height
Dim actualWidth = PB.getBoundingClientRect().width
PB["height"] = actualHeight
PB["width"] = actualWidth

You may notice that AppStudio was tricked by typing PB["height"] as opposed to PB.height. The syntax is actually equivalent, but since we're trying to explicity set only the canvas size, we trick the IDE - otherwise, it would think we were trying to use PB.Height and set both dimensions.

Properties

Standard properties are supported. To change the height at runtime, change the value of height.

refresh() Recalculates the size of the scrolling area after additions or deletions.
scroll_options This control makes use of iScroll. It has a number of options, including:

bounce: true/false. When the end of the scroll area is reached, should the image bounce?

zoom: true/false. Allow two finger zoom in gesture?

The full list of options is documented here: https://github.com/cubiq/iscroll

scrolling Allow choices in the menu to scroll? On or off. (design time)

Runtime Properties and Methods

getContext("2d") Gets the drawing context. Returns the object that the PictureBox Context functions use. "2d" is currently the only valid argument.
refresh() Redraws the entire PictureBox. Required after resizing the box or scrolling.
toDataURL(type) Returns the current picturebox in a Base64 string image. If type is not specified, it is in PNG format. Type can also be "image/jpeg" or "image/gif".

Runtime Context Properties and Methods

The following functions can be performed on the result of a getContext("2d") call.

addColorStop(stop,color) Specifies the positions (0-1) and colors in a gradient object.
addImage(filename[,x,y]) Draw an image and position x,y. Filename can also be a Base64 string containing an image.
addImage(filename,x,y,width,height) Position the image on the canvas, and specify width and height of the image.
addImage(filename,sx,sy,swidth,sheight,x,y,width,height) Clip the image and position the clipped part on the canvas
arc(x, y, radius, startAngle, endAngle, counterclockwise) Adds an arc to the current path using a radius and specified angles(in radians).
arcTo(x1, y1, x2, y2, radius) Adds an arc of a circle to the current sub path by using a radius and tangent points.
beginPath() Creates a new path in the canvas and sets the starting point to the coordinate (0,0).
bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x, y) Adds a cubic Bezier's curve to the current sub path using two control points.
clearRect(x, y, width, height) Clears the specified rectangle region and makes it transparent.
clip() Clips the current rectangle of any shape and size from the original canvas.
closePath() Closes an open path and attempts to draw a straight line from the current point to starting point of the path. The use of closePath() is optional.
createImageData(width, height) Creates a new, blank ImageData object.
createLinearGradient(x1, y1, x2, y2) The createLinearGradient(x1, y1, x2, y2) method takes four arguments that represent the start point (x1, y1) and end point (x2, y2) of the gradient.
createPattern(image, repetitionStyle) Creates a pattern by repeating an image. repetitionStyle can be repeat, repeat-x, repeat-y, no-repeat.
createRadialGradient(x1, y1, radius1, x2, y2, radius2) Radially interprets colors between two circles.
drawImage(img,x,y) Draw an image and position x,y. Img must be an Image object.
drawImage(img,x,y,width,height) Position the image on the canvas, and specify width and height of the image.
drawImage(img,sx,sy,swidth,sheight,x,y,width,height) Clip the image and position the clipped part on the canvas
fill() Closes the current path and paints the area within it.
fillRect(x, y, width, height) Draws a filled rectangle.
fillStyle gradient|pattern
fillText(text, x, y) Writes text using current settings of font, textAlign and textBaseline.
font The font to use for text. It is a string with three parts: "style size fontname". style can be normal, italic or bold. Example: "italic 40px Calibri"
getImageData(x,y,height,width) Return the image data for a portion of the image. Includes width, height, data array [rgba].
globalAlpha The transparency value. Must be a number between 0.0 (fully transparent) and 1.0 (no transparancy).
globalCompositeOperation(source-over, source-atop, source-in, source-out, destination-over, destination-atop, destination-in, destination-out, lighter, copy, xor ) Sets or returns how a source (new) images are drawn onto a destination (existing) image.
isPointInPath(x,y) Returns true if the specified point is in the current path, otherwise false.
lineCap Sets style of end caps for a line. "butt", "round" or "square".
lineJoin Set style where two lines meet. "bevel", "round" or "mitre".
lineWidth The current line width, in pixels.
lineTo(x, y) Adds a line segment from the current point to the specified coordinate. The appearance of the line can be set by the following properties:

fillStyle, strokeStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor

measureText(text) Returns a rectangle object with text's size.
miterLimit The miterLimit property sets or returns the maximum miter length for line ends.
moveTo(x, y) Moves the starting point to a new coordinate specified by x,y values.
putImageData(imgData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight) Puts the image data (from a specified ImageData object) back onto the canvas.
quadraticCurveTo(x, y, x1, y1) Adds a quadratic Bezier's curve to the current sub path.
rect(x, y, width, height) Adds a rectangle.
restore() Restores the state of the saved context space.
rotate(angle) Rotate the entire context on specified angle(in radians).
save() Save the state of the original context space so that you can restore later.
scale(x, y) Add the scaling transformation described by the arguments to the transformation matrix. The x argument represents the scale factor in the horizontal direction and the y argument represents the scale factor in the vertical direction. The factors are multiples.
setTransform(a,b,c,d,e,f) Transforms drawing. Scale horizontal, skew horizontal, skew vertical, scale vertical, move horizontal, move vertical.
stroke() Actually draws the path you have defined
strokeRect(x, y, width, height) Draws a rectangular outline.
strokeStyle color or gradient or pattern
strokeText(text, x, y, maxWidth) Draws text (with no fill) on the canvas.
textAlign Controls text alignment. Possible values are start, end, left, right and center.
textBaseline Controls where the text is drawn relative to the starting point. Possible values are top, hanging, middle, alphabetic, ideographic and bottom.
style(x, y, width, height) Any valid style string.
translate(x, y) Translate the origin of the context space to the specified of the canvas.

Events

Standard events are supported.

Example 1: Display an image, drawing and text

dim pb
 
Sub Main() 
  pb = PictureBox1.getContext("2d")
 
  'Draw a red oval with black border
  pb.strokeStyle = vbBlack
  pb.fillStyle = vbRed
  pb.beginPath()
  pb.arc(100,100,50,0,Math.PI*2,true)
  pb.closePath()
  pb.stroke()
  pb.fill()
 
  'do some text as well
  pb.textBaseline = "top"
  pb.font="16px sans-serif"
  pb.fillText("This is a picturebox",0,0)
  
  'Draw an image (AppStudio 4)
  pb.addImage("mario.jpg")
End Sub

Output

Sample code to just display an image.

pb = PictureBox1.getContext("2d")
pb.addImage("Testimage.png") 

Example 2: Resize an image

resize = PictureBox1.style
resize.width = "200px"

Example 3: Process some image data

Sub Main
  Image1.src="image001.jpg"
  Image2.src="image002.jpg"
End Sub

Function Button1_onclick()
  ImageMatch=True
  Pix1 = pb1.getImageData(0,0,199,199)
  Pix2 = pb2.getImageData(0,0,199,199)
  For i=0 To 199*199*4 Step 4
    r = Pix1.data[i] <> Pix2.data[i]
    g = Pix1.data[i+1] <> Pix2.data[i+1]
    b = Pix1.data[i+2] <> Pix2.data[i+2]
    If r | g | b Then
      ImageMatch=False
      Pix1.data[i] = 255 - Pix1.data[i]
      Pix1.data[i+1] = 255 - Pix1.data[i+1]
      Pix1.data[i+2] = 255 - Pix1.data[i+2]
    End If
  Next i
  pb1.putImageData(Pix1,0,0)
  If !ImageMatch Then MsgBox "These cards are MARKED !"
End Function
 

Example 4: Draw a red box

  'Do some drawing: start by setting our colors.
  pb.strokeStyle = vbBlack
  pb.fillStyle = vbRed
  'Now, we define the lines we want to draw in a path.
  pb.beginPath()
  pb.moveTo(10,10)
  pb.lineTo(10,50)
  pb.lineTo(50,50)
  pb.lineTo(50,10)
  pb.lineTo(10,10)
  pb.closePath()
  'Path is complete: draw it
  pb.stroke()
  'and paint the area inside the path
  pb.fill()

Example 5: Draw an image using drawImage (addImage is easier!)

Dim pb
var img = new Image()
img.src = "mario.jpg"
pb = PictureBox1.getContext("2d")

Function img_onload()
  pb.drawImage(img,0,0)
End Function

Other Examples

Make a PictureBox not selectable:

Function PictureBox1_onselectstart()
  return False
End Function

JavaScript version

PictureBox1.onselectstart = function () { return false; }