Trying to draw a pattern divided into several parts with html5 canvas

I need to draw using html5 canvas of this form, I can draw it as one canvas.

http://postimg.org/image/li5mpoot3/

I need to treat each part as a unique object - listen to the mouse over each part, determine which part the user hovers over, and also allows the user to fill out the corresponding part of the form.

var canvas = document.getElementById('shape'); var context = canvas.getContext('2d'), width = $('#shape').width(), part_width = width / parts_num; context.beginPath(); var start_x = 17, end_x = 17 + part_width; for (var i = 0; i < parts_num; i++) { context.moveTo(start_x, 0); context.lineTo(end_x,0); context.moveTo(start_x, 0); context.bezierCurveTo(50+start_x, 30, 40+start_x, 45, 13+start_x, 89); context.moveTo(13+start_x, 89); context.bezierCurveTo(0+start_x, 110, 0+start_x, 126, 27+start_x, 174); context.moveTo(28+start_x, 174); context.lineTo(85+start_x,174); start_x += part_width;//80 is x starting point }; context.lineWidth = 5; context.strokeStyle = "red"; context.stroke(); 
+4
source share
2 answers

I would suggest using CreateJS . This would make your life a lot easier with your canvas.

Here is a Demo on how you could treat each shape as an object using CreateJS.

Click on a separate shape to see how each of them starts its own handler.

 function curveShape(index, start_x, end_x) { var shape = new createjs.Shape(); var context = shape.graphics.beginStroke("red").beginFill("#ffffee"); context.moveTo(start_x, 0); context.bezierCurveTo(start_x + 10, 30, start_x + 10, 45, start_x - 15, 90); context.bezierCurveTo(start_x - 30, 120, start_x - 30, 135, start_x, 180); context.lineTo(end_x, 180); context.bezierCurveTo(end_x - 30, 135, end_x - 30, 120, end_x - 15, 90); context.bezierCurveTo(end_x + 10, 45, end_x + 10, 30, end_x, 0); context.lineTo(start_x, 0); shape.name = "shape " + index; shape.x = shape.y = 30; shape.addEventListener("mousedown", function () { alert("I am " + shape.name); }); return shape; } var stage = new createjs.Stage("shape"); for(var i = 0; i < 4; i++) stage.addChild(new curveShape(i+1, i * 80, (i + 1) * 80)); stage.update(); 
+3
source

Solution Using Vanilla JavasScript and Canvas

You can embed a complex shape in an object that processes the position and validates. An object might look like this:

Full working demo here

Extract:

The main object is

 function wave(ctx, offset, width) { /// the check function which checks point x, y in last path this.isInPath = function(x, y) { getPath(); return ctx.isPointInPath(x, y); } /// this render the object with the set fill color this.draw = function(color) { getPath(); ctx.fillStyle = color; ctx.fill(); ctx.lineWidth = 5; ctx.strokeStyle = "red"; ctx.stroke(); } /// common function to generate just the path. function getPath() { ctx.beginPath(); ctx.moveTo(offset, 0); ctx.bezierCurveTo(50 + offset, 30, 40 + offset, 45, 13 + offset, 89); ctx.bezierCurveTo(offset, 110, offset, 126, 27 + offset, 174); ctx.lineTo(27 + offset + width, 174); ctx.bezierCurveTo(offset + width, 100, offset + width + 0, 126, 27 + offset + width, 65); ctx.bezierCurveTo(43 + offset + width, 40, 40 + offset + width, 25, offset + width, 0); ctx.closePath(); } this.draw('white'); return this; } 

Make sure that the path is autonomous, which means that it is a complete form independent of adjacent parts (i.e. without using adjacent lines). This is basically all you need to handle complex shapes.

Render

To make it simple:

 for(;i < parts_num; i++) { parts.push( new wave(context, i * part_width, part_width) ); } 

Check

How to check if a point is in a part, you can do this:

 /// check mouse move in this example canvas.addEventListener('mousemove', hover, false); /// the function to check parts function hover(e) { ///get mouse coord relative to canvas var r = canvas.getBoundingClientRect(); var x = e.clientX - r.left; var y = e.clientY - r.top; ///optimize so we only clear last selected part if (lastPart > -1) { parts[lastPart].draw('white'); lastPart = -1; } for(i = 0 ;i < parts_num; i++) { if (parts[i].isInPath(x, y) === true) { parts[i].draw('green'); lastPart = i; break; //don't need to check more } } } 

There is room for optimization (reusing the last path inside an object, caching the form as images, the range of verification of the segment as such), but it shows that in fact it is not so difficult to deal with the use of vanilla canvas and JavaScript.

With this base you can handle clicks, etc.

(Note. I am not too precise with the closing end on the bezier - I will leave it for fine tuning if you decide to use this solution ..).

+3
source

Source: https://habr.com/ru/post/1490110/


All Articles