Three-Hand Bezier Curve Offsets Control Points

I managed to draw four different curves with examples from the Raphael library. Now I would like to create one curve with several handles in it. How to add more descriptors to this example.

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Bezier curve</title> <style> #holder { height: 100%; left: 100%; margin: -100% 0 0 -100%; position: absolute; top: 100%; width: 100%; } </style> <script src='jquery.js'></script> <script src="raphael.js"></script> <script> $('document').ready(function () { var r = Raphael("holder", window.innerWidth, window.innerHeight) function curve(x, y, ax, ay, bx, by, zx, zy, color) { var path = [["M", x, y], ["C", ax, ay, bx, by, zx, zy]], path2 = [["M", x, y], ["L", ax, ay], ["M", bx, by], ["L", zx, zy]], curve = r.path(path).attr({stroke: color || Raphael.getColor(), "stroke-width": 4, "stroke-linecap": "round"}), controls = r.set( r.path(path2).attr({stroke: "#ccc", "stroke-dasharray": ". ","stroke-width":2}), r.circle(x, y, 5).attr({fill: "#9F2200", stroke: "none"}), r.circle(ax, ay, 5).attr({fill: "#9F2200", stroke: "none"}), r.circle(bx, by, 5).attr({fill: "#9F2200", stroke: "none"}), r.circle(zx, zy, 5).attr({fill: "#9F2200", stroke: "none"}) ); controls[1].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[0][1] = X; path[0][2] = Y; path2[0][2] = X; path2[0][2] = Y; controls[2].update(x, y); }; controls[2].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[1][3] = X; path[1][2] = Y; path2[1][4] = X; path2[1][2] = Y; curve.attr({path: path}); controls[0].attr({path: path2}); }; controls[3].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[1][3] = X; path[1][4] = Y; path2[2][5] = X; path2[2][2] = Y; curve.attr({path: path}); controls[0].attr({path: path2}); }; controls[4].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[1][5] = X; path[1][6] = Y; path2[3][6] = X; path2[3][2] = Y; controls[3].update(x, y); }; controls.drag(move, up); } function move(dx, dy) { this.update(dx - (this.dx || 0), dy - (this.dy || 0)); console.log(this.dx,this.dy); this.dx = dx; this.dy = dy; } function up() { this.dx = this.dy = 0; } curve(70, 100, 110, 100, 130, 200, 170, 200, "hsb(0, 0, 0)"); curve(800, 200, 800, 100, 600, 100, 600, 200, "hsb(0, 0, 0)"); // xp1,yp1, , , , , xp2,yp2 where (xp1,xp2) & (xp2,yp2) are two end points curve(500, 200,500, 300, 300, 300, 300, 200, "hsb(0, 0, 0)"); // xp1,yp1, , , , , xp2,yp2 where (xp1,xp2) & (xp2,yp2) are two end points curve(920, 100,880, 100, 1020, 200, 980, 200, "hsb(0, 0, 0)"); }); </script> </head> <body> <div id="holder"></div> </body> </html> </body> 

Link for demo http://jsfiddle.net/insane36/fddGJ/1/

I edited the code and tried again to put some descriptors to show the main descriptor in the middle, but it has some problems, and I don’t know if I understood the concept behind it. I wanted to create a figure with a handle, as shown in the figure below, and be able to manipulate the handles;

enter image description here

Code for the three descriptors:

 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Bezier curve</title> <style> #holder { height: 100%; left: 100%; margin: -100% 0 0 -100%; position: absolute; top: 100%; width: 100%; } </style> <script src="raphael.js"></script> <script> window.onload=function () { var r = Raphael("holder", window.innerWidth, window.innerHeight) function curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2,cx3,cy3,cx4,cy4, color) { //zx --x1 var path = [["M", x1, y1], ["C", cx1, cy1, cx2, cy2, x2, y2,"S",cx3,cy3,cx4,cy4]], path2 = [["M", x1, y1], ["L", cx1, cy1], ["M", cx2, cy2], ["L", x2, y2],["M", cx3,cy3],['L',cx4,cy4]], curve = r.path(path).attr({stroke: color || Raphael.getColor(), "stroke-width": 4, "stroke-linecap": "round"}), controls = r.set( r.path(path2).attr({stroke: "#ccc", "stroke-dasharray": ". ","stroke-width":2}), r.circle(x1, y1, 5).attr({fill: "#9F2200", stroke: "none"}), r.circle(cx1, cy1, 5).attr({fill: "#9F2200", stroke: "none"}), r.circle(cx2, cy2, 5).attr({fill: "#9F2200", stroke: "none"}), r.circle(x2, y2, 5).attr({fill: "#9F2200", stroke: "none"}), r.circle(cx3, cy3, 5).attr({fill: "#9F2200", stroke: "none"}), r.circle(cx4, cy4, 5).attr({fill: "#9F2200", stroke: "none"}) ); controls[1].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[0][9] = X; path[0][2] = Y; path2[0][10] = X; path2[0][2] = Y; controls[2].update(x, y); }; controls[2].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[1][11] = X; path[1][2] = Y; path2[1][12] = X; path2[1][2] = Y; curve.attr({path: path}); controls[0].attr({path: path2}); }; controls[3].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[1][3] = X; path[1][4] = Y; path2[2][13] = X; path2[2][2] = Y; curve.attr({path: path}); controls[0].attr({path: path2}); }; controls[4].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[1][5] = X; path[1][6] = Y; path2[3][14] = X; path2[3][2] = Y; controls[3].update(x, y); }; controls[5].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[1][8] = X; path[1][9] = Y; path2[4][15] = X; path2[4][2] = Y; controls[4].update(x, y); }; controls[6].update = function (x, y) { var X = this.attr("cx") + x, Y = this.attr("cy") + y; this.attr({cx: X, cy: Y}); path[1][10] = X; path[1][11] = Y; path2[5][16] = X; path2[5][2] = Y; controls[5].update(x, y); }; controls.drag(move, up); } function move(dx, dy) { this.update(dx - (this.dx || 0), dy - (this.dy || 0)); console.log(this.dx,this.dy); this.dx = dx; this.dy = dy; } function up() { this.dx = this.dy = 0; } curve(10, 80, 40, 10, 65,10,150,150,95, 80, 180,180, "hsb(0, 0, 0)"); }; </script> </head> <body> <div id="holder"></div> </body> </html> </body> </html> 

I think that I missed and did not correctly arrange the breakpoints and values

+4
source share
1 answer

Take a look at this fiddle - I think I'm doing what you are looking for. ( Edit: this script is fixed, so you do not need to specify a reflected breakpoint in the curve() constructor)

I think the key is that the second control point of the midpoint on the curve is just a reflection of the first control point (for the SVG documentation ), so you need to select a "fake" of this control. (Your code had some problems when your update () functions tried to update the values ​​of arrays that do not exist, for example path[1][6] = Y; ... path[1] have only three elements)

If you want the two control points to behave independently (so that the curve is not necessarily smooth through this point), I think you need to remove the "S" from your path and change part of the code (here is one )

If you want the two control points to be allowed to travel different distances from the point, but hold the curve smoothly through the point, I think you should do it manually. You can start with the second example, but you will have to programmatically reflect the angle of the moving control point at the opposite control point, allowing you to remain at a distance from the opposite control point to the point on the curve in order to remain fixed.

+1
source

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


All Articles