In the second tutorial of the series, you learned how to draw some basic shapes like rectangles, circles, and regular polygons using Konva. The third tutorial covered how you can use Konva to draw some more complex shapes like stars and rings as well as sprites on the canvas.
In this tutorial, we will go one step further and learn how to apply different styling to shapes by changing their fill and stroke values. You will also learn how to control the opacity of a shape and apply shadows to it. In the final sections, you will learn how to use blend modes to specify what the final result should look like if different shapes overlap.
Applying Fill and Stroke
We have been using the fill
and stroke
properties from the first tutorial of the series. However, we have only used them to fill shapes with a solid color so far. You can also fill a shape with gradients (both linear and radial) as well as images. The same goes for different strokes applied to a shape.
There are two ways of applying a fill to different shapes. You can either set the fill value using the fill
property when a shape is first created in Konva, or you can use the fill()
method to apply a fill dynamically in response to some events like hover, button click, etc.
When filling an element with a solid color, you can specify a value for the fill
property and it will work just fine. When using a linear gradient to fill the inside of a shape, you need to specify valid values for a lot of other properties like fillLinearGradientStartPoint
, fillLinearGradientEndPoint
, and fillLinearGradientColorStops
. The first two properties accept objects that specify the x and y co-ordinates of the start and end points of a gradient. You can also specify the x and y values separately using the fillLinearGradientStartPointX
, fillLinearGradientStartPointY
, fillLinearGradientEndPointX
, and fillLinearGradientEndPointY
properties.
Radial gradients also have the same set of properties, but the word Linear
is replaced with Radial
. Two additional properties related to radial gradients are fillRadialGradientStartRadius
and fillRadialGradientEndRadius
.
var canvasWidth = 600; var canvasHeight = 400; var stage = new Konva.Stage({ container: "example", width: canvasWidth, height: canvasHeight }); var layerA = new Konva.Layer(); var rectA = new Konva.Rect({ x: 25, y: 25, width: 200, height: 150, fillLinearGradientStartPoint: { x: 0, y: 0 }, fillLinearGradientEndPoint: { x: 200, y: 150 }, fillLinearGradientColorStops: [0, 'blue', 1, 'yellow'], stroke: "black" }); var rectB = new Konva.Rect({ x: 375, y: 25, width: 200, height: 150, fillLinearGradientStartPoint: { x: 0, y: 50 }, fillLinearGradientEndPoint: { x: 100, y: -50 }, fillLinearGradientColorStops: [0, 'green', 0.1, 'yellow', 0.5, 'red', 0.9, 'black'], stroke: "black" }); var rectC = new Konva.Rect({ x: 25, y: 200, width: 200, height: 150, fillRadialGradientStartRadius: 0, fillRadialGradientEndRadius: 220, fillRadialGradientColorStops: [0, 'green', 0.5, 'yellow', 0.75, 'red', 0.9, 'black'], stroke: "black" }); var rectD = new Konva.Rect({ x: 375, y: 200, width: 200, height: 150, fillRadialGradientStartRadius: 0, fillRadialGradientEndRadius: 150, fillRadialGradientStartPoint: { x: 100, y: 75 }, fillRadialGradientEndPoint: { x: 100, y: 75 }, fillRadialGradientColorStops: [0, 'blue', 0.5, 'yellow', 0.9, 'green'], stroke: "black" }); layerA.add(rectA, rectB, rectC, rectD); stage.add(layerA);
When not specified, the start and end point of a radial gradient are assumed to be 0,0
. This is why the radial gradient in the third rectangle originates from the top left corner. Also remember that the start and end points are specified relative to the shape itself.
Just like the fill, you can set a value for the stroke color and stroke width using the stroke
and strokeWidth
properties when a shape is first instantiated. You can also dynamically set both these values using the stroke()
and strokewidth()
methods.
Creating Shadows in Konva
You can apply shadows to any shapes created using Konva with the help of four different properties called shadowColor
, shadowOffset
, shadowBlur
, and shadowOpacity
. The shadowOffset
property accepts an object with x
and y
components as its value, but you can also use shadowOffsetX
and shadowOffsetY
to specify the x
and y
co-ordinates separately. You also have the option of enabling and disabling the shadows for any particular shape using the shadowEnabled
property.
You can control the opacity of the shape itself using the opacity
property. Please note that a fully transparent object will not cast any shadow. Similarly, if you have set the fill
color of a shape to transparent, only the shadow of its stroke
will be rendered on the canvas.
var canvasWidth = 600; var canvasHeight = 400; var stage = new Konva.Stage({ container: "example", width: canvasWidth, height: canvasHeight }); var layerA = new Konva.Layer(); var rectA = new Konva.Rect({ x: 25, y: 25, width: 200, height: 150, cornerRadius: 5, fill: "orange", opacity: 0.5, shadowColor: "black", shadowOffset: { x: -10, y: 10 }, shadowBlur: 10, stroke: "black" }); var starA = new Konva.Star({ x: 400, y: 200, numPoints: 10, innerRadius: 50, outerRadius: 150, fill: "transparent", stroke: "black", strokeWidth: 5, shadowColor: "red", shadowOffset: { x: 5, y: 5 }, shadowBlur: 0 }); layerA.add(rectA, starA); stage.add(layerA);
Setting the shadowBlur
property to 0 makes the shadow as sharp as the original shape itself. Setting this value too high will make the shadow lose the original shape; you will only see a dark patch on the canvas.
I would like to point out that you can also create text shadows with the same set of properties once you have instantiated a Konva.Text()
object.
Applying Blend Modes
So far in the series, any overlap between shapes hid the bottom shape completely. The only way to keep the bottom shape visible was to make all the shapes over it partially transparent.
Sometimes, you might want the final result after the overlap of different shapes to follow certain rules. For example, it is possible to only show the lighter or darker color in cases where the shapes overlap.
Konva allows you to specify some values to determine how the colors of overlapping shapes should blend together using the globalCompositeOperation
property. You can read the documentation on MDN to learn about the property and all its possible values in more detail.
In the following example, I have applied a different blend mode to each of the rectangles placed at the corner of the central rectangle.
var canvasWidth = 600; var canvasHeight = 400; var stage = new Konva.Stage({ container: "example", width: canvasWidth, height: canvasHeight }); var layerA = new Konva.Layer(); var rectCenter = new Konva.Rect({ x: 225, y: 125, width: 150, height: 150, fill: "rgb(255, 100, 0)" }); var rectA = new Konva.Rect({ x: 125, y: 25, width: 150, height: 150, fill: "rgb(0, 200, 100)", globalCompositeOperation: "lighten" }); var rectB = new Konva.Rect({ x: 325, y: 25, width: 150, height: 150, fill: "rgb(0, 200, 100)", globalCompositeOperation: "darken" }); var rectC = new Konva.Rect({ x: 125, y: 225, width: 150, height: 150, fill: "rgb(0, 200, 100)", globalCompositeOperation: "hue" }); var rectD = new Konva.Rect({ x: 325, y: 225, width: 150, height: 150, fill: "rgb(0, 255, 0)", globalCompositeOperation: "xor" }); layerA.add(rectCenter, rectA, rectB, rectC, rectD); stage.add(layerA);
The color of the top-left rectangle is rgb(0, 200, 100)
, and the color of the central rectangle is rgb(255, 100, 0)
. When the lighten
blend mode is applied, the rgb
components of both the colors are compared individually, and the higher values for each component are used to get the final color. In our case, the final color for the top-left corner becomes rgb(255, 200, 100)
.
When the darken
blend mode is applied, the rgb
components of both the colors are compared individually, and the lower values for each component are used to get the final color. In our case, the final color for the top-right corner becomes rgb(0, 100, 0)
.
When the hue
blend mode is applied, the luma and chroma of the bottom color are combined with the hue of the top color. This is why the final color still remains green but gets lighter. When the xor
blend mode is applied, the final color becomes transparent at all the places of overlap.
Final Thoughts
In this tutorial, we learned how to fill a shape with linear or radial gradients instead of solid colors. We also learned how to apply shadows to different shapes and make them partially transparent using the opacity
property. The final section showed you how to use blend modes in order to change the final color after two shapes overlap.
If you have any questions related to this tutorial, please let me know in the comments. The next and final tutorial of the series will teach you how to bind events to different shapes in Konva.
No comments:
Post a Comment