How to Make a Simple Drawing App With Swift

In this article, we grasp the very basics of a canvas. We learn every piece of knowledge that is needed to create a simple drawing app that can also save our images and load them back to the editor.

The basics of a canvas

With the < canvas >  element, we can draw images using JavaScript. The above gives us many possibilities, limited by what you can imagine and put into life with your code. When you put the < canvas >  in your page, you start with a blank rectangle with its size defined by thewidth and height– those are the only canvas-specific attributes.

<canvas width = "500" height = "500" > </canvas>

As you can see, you can also put something inside of the < canvas >  tag – if you do so, it acts as a fallback in case the browser does not support it. The chances of that happening are pretty slim though! The only culprit seems to be the Internet Explorer in version 8 and older.

caniuse.com

Since we need to access the canvas from our code, let's give it an id.

<canvas id = "canvas" width = "500" height = "500" > </canvas>

window . onload = ( ) = > {

const canvas = document . getElementById ( 'canvas' ) ;

} ;

I'm using the window . onload  here to make sure that our DOM tree is ready

Once we've got the canvas, we can access itscontext. It is a rendering context for our drawing surface, and we use it to draw any shape. Today we focus on 2D graphics, that's we use theCanvasRenderingContext2D interface.

const context = canvas . getContext ( '2d' ) ;

Let's start by drawing some simple rectangles. To do this, we use the fillRect  function.

context . fillRect ( 0 , 0 , 50 , 50 ) ;

This gives us our first rectangle! The arguments of a function are:

  • x-coordinate of the upper-left corner
  • y-coordinate of the upper-left corner
  • width of the rectangle
  • height of the rectangle

As you can see, there is no argument for the color. The above is because we need to set it separately and to do that, we set the fillStyle  attribute.

context . fillStyle = 'red' ;

context . fillRect ( 0 , 0 , 50 , 50 ) ;

context . fillStyle = 'blue' ;

context . fillRect ( 10 , 10 , 50 , 50 ) ;

The fillStyle property accepts different ways of specifying the color

There are many other different ways to draw shapes and define how they look, such as the strokeStyle.

Drawing on the canvas

To draw on the canvas, we need to attach some event listeners. Let's start with mousedown.

When to start drawing

Themousedown event is fired at anElement when a pointing device button is pressed while the pointer is inside the element.

let isDrawing = false ;

window . onload = ( ) = > {

const canvas = document . getElementById ( 'canvas' ) ;

const context = canvas . getContext ( '2d' ) ;

canvas . addEventListener ( 'mousedown' , startDrawing ) ;

} ;

function startDrawing ( ) {

isDrawing = true ;

}

As soon as someone presses a mouse inside of our canvas, we want to start drawing!

When to stop drawing

Another event that we need is themouseup.

Themousedown event is fired at anElement when a pointing device button is pressed while the pointer is inside the element.

canvas . addEventListener ( 'mouseup' , stopDrawing ) ;

function startDrawing ( ) {

isDrawing = true ;

}

The drawing itself

In our simple example, we draw a rectangle every time the mouse moves if the previous conditions are met: the user hovers over the canvas and he clicked a mouse once. To do that, we need themousemoveevent.

Themousemove event is fired at an element when a pointing device (usually a mouse) is moved while the cursor's hotspot is inside it.

const canvas = document . getElementById ( 'canvas' ) ;

const context = canvas . getContext ( '2d' ) ;

canvas . addEventListener ( 'mousemove' , ( event ) = > draw ( event , context ) ) ;

function draw ( event , context ) {

if ( isDrawing ) {

context . fillRect ( event . pageX , event . pageY , 2 , 2 ) ;

}

}

As you can see, in this example, I use an arrow function because I want to pass both the event and the context to the draw  function.

The event . pageX  and event . pageY  are coordinates of the cursorrelative to the left edge of the entire document. This means that if the canvas is not in the top left corner of the page, it is not accurate. To account for it, we can use the getBoundingClientRect  function.

function draw ( event , canvas ) {

if ( isDrawing ) {

const context = canvas . getContext ( '2d' ) ;

const rect = canvas . getBoundingClientRect ( ) ;

context . fillRect ( event . pageX - rect . left , event . pageY - rect . top , 2 , 2 ) ;

}

}

And thanks to that, we have a fully working functionality of drawing on a canvas!

Saving and loading images

To save and load images, we need a button and an input first.

< button id = "save" type = "button" >

save

< / button >

< input

type = "file"

id = "load"

name = "avatar"

accept = "image/png"

>

Saving an image

To save an image, we use the toDataUrl  function. It returns the data in the URI format that contain the representation of the image in the type that we choose.

window . onload = ( ) = > {

const canvas = document . getElementById ( 'canvas' ) ;

const context = canvas . getContext ( '2d' ) ;

const saveButton = document . getElementById ( 'save' ) ;

saveButton . addEventListener ( 'click' , ( ) = > save ( canvas ) ) ;

} ;

function save ( canvas ) {

const data = canvas . toDataURL ( 'image/png' ) ;

const anchor = document . createElement ( 'a' ) ;

anchor . href = data ;

anchor . download = 'image.png' ;

anchor . click ( ) ;

}

In the save  function, we create a dummy anchor, then attach the data, define a filename, and initiate the download.

Loading an image

To load an image, we listen for thechange event of the input.

window . onload = ( ) = > {

const canvas = document . getElementById ( 'canvas' ) ;

const loadInput = document . getElementById ( 'load' ) ;

loadInput . addEventListener ( 'change' , ( event ) = > load ( event , canvas ) ) ;

} ;

Since the input stores the files in an array, we need to choose the last element:

function getFile ( event ) {

return [ . . . event . target . files ] . pop ( ) ;

}

When we have the file, we need to read it to interpret it accurately. To do it, we need the File Reader.

function readTheFile ( file ) {

const reader = new FileReader ( ) ;

return new Promise ( ( resolve ) = > {

reader . onload = ( event ) = > {

resolve ( event . target . result ) ;

} ;

reader . readAsDataURL ( file ) ;

} )

}

As soon as it reads the file successfully, we resolve the promise. The last thing to do is to load the image to the canvas.

function loadTheImage ( image , canvas ) {

const img = new Image ( ) ;

img . onload = function ( ) {

const context = canvas . getContext ( '2d' ) ;

context . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;

context . drawImage ( img , 0 , 0 ) ;

} ;

img . src = image ;

}

Since the drawImage  function that we want to use accepts an instance of the Image, we need to convert it first. When we have it, we clear the canvas and load the image.

Once we have all that, we can successfully load an image.

function load ( event , canvas ) {

const file = getFile ( event ) ;

readTheFile ( file , canvas )

. then ( ( image ) = > loadTheImage ( image , canvas ) )

}

Putting it all together

My proposition of making it all work together is to use a class.

See the Pen
xoRJVx by Marcin Wanago (@mwanago)
on CodePen.

Summary

In this article, we've learned how to create a simple drawing using canvas. To do this we had to learn the very basics of the canvas and how to work with certain event listeners. While this is an elementary example, you are free to expand it and add new features.

How to Make a Simple Drawing App With Swift

Source: https://wanago.io/2019/06/24/creating-a-simple-drawing-app-using-canvas-saving-and-loading-images/

0 Response to "How to Make a Simple Drawing App With Swift"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel