ArtsAutosBooksBusinessEducationEntertainmentFamilyFashionFoodGamesGenderHealthHolidaysHomeHubPagesPersonal FinancePetsPoliticsReligionSportsTechnologyTravel

Animating Bezier Curves with SVG and jQuery (finished) - part 5 in a series

Updated on April 28, 2011

the reconsituted Bezier Curve animation

Doesn't look much different than before, just different innards; curve is a little cleaner looking, draws a little faster.
Doesn't look much different than before, just different innards; curve is a little cleaner looking, draws a little faster.

Wrapping up the experiment with SVG and jQuery

I have been writing a series of hubs to show some techniques for programming in Javascript.  I first used native javascript to implement a graphing calculator.  Next, I used the jQuery library to animate the design of Bezier Curves.  In my last Hub, I started an experiment to adapt my previous work to use SVG.  When I left off, it was admittedly a work in progress.

The main thing that needed cleaning up, was to mesh up my coordinate system with that of SVG. SVG uses two sets of coordinates. One is the positioning of the tag (top, left, height, width). The other is the viewBox, basically where coordinates specified in svg tag elements appear with its screen area.

You could think of the viewBox as a virtual screen that is scaled to fit into the screen area of the SVG element. Since I am already using real screen coordinates, I set the viewBox to be an identity mapping.

Once the coordinates were meshed up, there was basically no change to the function that animates the drawing of the Bezier Curve while the control points are dragged around. So, SVG tags are indeed part of the repertoire that jQuery can manipulate.

The other change I needed to make was to assign the SVG element a class name that I could use to remove previous curves as the control points are moved about during animation.

meshing SVG with my coordinate system

function drawcurve( curvefn, coord, fnstart, fnstop, delta ) {
	var pt;
	var fofpt;
	var screenpt, newscreenpt;
	var top;
	var left;
	var width;
	var height;

	if( coord.screenx0 < coord.screenx1 ) {
		left = coord.screenx0;
		width = coord.screenx1 - coord.screenx0;
	} else {
		left = coord.screenx1;
		width = coord.screenx0 - coord.screenx1;
	}
	if( coord.screeny0 < coord.screeny1 ) {
		top = coord.screeny0;
		height = coord.screeny1 - coord.screeny0;
	} else {
		top = coord.screeny1;
		height = coord.screeny0 - coord.screeny1;
	}	

	var path="<svg class='newrectangle' style='position:absolute;" +
		"height:" + height + "px; width:" + width + "px; top:" + top + "px; left:" + left +
		"px;' viewBox='" + left + " " + top + " " + width + " " + height + 
		"' >" +
  		"<path stroke=black stroke-width=4 fill=none stroke-linejoin=round d='";
	var op = "M ";

	fofpt = curvefn( fnstart );
	screenpt = coord.pointToScreenCoordinates( fofpt.x, fofpt.y );
	for( pt = fnstart + delta ; pt < fnstop ; pt += delta ) {
		fofpt = curvefn( pt );
		newscreenpt = coord.pointToScreenCoordinates( fofpt.x, fofpt.y );
		if( screenpt.x != newscreenpt.x || screenpt.y != newscreenpt.y ) {
			if( op == "M " ) {
				path += op + screenpt.x + "," + screenpt.y;
				op = " L ";	
			}
			path += op + newscreenpt.x + "," + newscreenpt.y;
			screenpt = newscreenpt;	
		}
	}
	path += "'/></svg>";
	$( path ).appendTo( "body" );
}

no changes to the animation function

I added one line that reads,     $( ".newrectangle" ).attr( "myclass", "oldrectangle" );
This is a result of a bit of experimenting, because I ran into a problem with using jQuery to change the class of an SVG element.  I probably just need to get an even later version of the jQuery library, or maybe there is some rule that I am still unaware of.  In the worst case, I could use another attribute to tag SVG elements.  As it is, a previously drawn graph, will be erased when the animation starts.  I am not really trying to rival Adobe Illustrator, here, just demonstrate some techniques.  So, I think this is an acceptable bug, and I left it.

recalling the function that animated bezier curves

function jgbezier ( drawarea ) {
	var bpoints = new Array();
	var bpointcnt = 0;
	unitsquare.dontscale = true;
	$( ".newrectangle" ).attr( "myclass", "oldrectangle" );
	$( "#mousetarget" ).bind( "click", function (e) {
		if( bpointcnt < 4 ) {
			var rect = drawrectangle( "blackrectangle", e.pageY + 2, e.pageX - 2, 4, 4 

);
			$( rect ).attr( "id", "bcctl_" + bpointcnt );
			bpoints[bpointcnt] = drawarea.screenCoordinatesToPoint( e.pageX, e.pageY );
			++bpointcnt;
			if( bpointcnt == 4 ) {
				// mark what is already here
				$( ".blackrectangle" ).addClass( "oldrectangle" );
				// attach mouse handlers
				$( "#mousetarget" ).remove();
				var drawing = false;
				$( ".blackrectangle" ).bind( "mousedown", function ( e ) {
					var movetarget = this;
					$( "body" ).bind( "mousemove", function ( e ) {
						$( movetarget ).css( "top", e.pageY + 2 );
						$( movetarget ).css( "left", e.pageX - 2 );
						var myid = $( movetarget ).attr( "id" );
						var myindex = parseInt( myid.substr( 6 ) );
						bpoints[ myindex ] = 

drawarea.screenCoordinatesToPoint( e.pageX, e.pageY );
						if( !drawing ) {
							drawing = true;
							drawbcurve();
							// mark the new points
							drawing = false;
						}
					} );
				});
				$( "body" ).bind( "mouseup", function ( e ) {
					$( "body" ).unbind( "mousemove" );
					drawbcurve();
				});
				//draw curve
				var drawbcurve = function () {
					// remove old curve
					$( ".newrectangle" ).remove();
					var xpath = genbezierequation( bpoints[0].x, bpoints[1].x - 

bpoints[0].x, bpoints[2].x, bpoints[2].x - bpoints[3].x );
					var ypath = genbezierequation( bpoints[0].y, bpoints[1].y - 

bpoints[0].y, bpoints[2].y, bpoints[2].y - bpoints[3].y );	
					$( "#xformula" ).attr( "value", xpath );
					$( "#yformula" ).attr( "value", ypath );
					$( "#jgmeshstart" ).attr( "value", '0' );
					$( "#jgmeshend" ).attr( "value", '1' );
					$( "#start_calc" ).trigger( "click" );
					// mark the new points
					$( ".blackrectangle" ).addClass( "newrectangle" );
					$( ".oldrectangle" ).removeClass( "newrectangle" );
				}
				drawbcurve();
				// mark the new points
				$( ".blackrectangle" ).addClass( "newrectangle" );
				$( ".oldrectangle" ).removeClass( "newrectangle" );
			}
		}
	});
}

Summary

As long as you are willing to forgo users that may be using older browsers, SVG is a good alternative to the div based mechanism that I started with.  jQuery is quite able to manipulate SVG elements, and they interact well with the display of other DOM elements.  The SVG based rendering performs better and renders better than the div based implementation.

The techniques of of using divs in my previous hubs are still quite useful for developing UI widgets for Web pages.  Also, only a small portion of my code needed to change to accommodate using SVG.

Perhaps, next I will try a similar experiment with HTML 5 canvas elements.

Comments

    0 of 8192 characters used
    Post Comment

    No comments yet.

    working

    This website uses cookies

    As a user in the EEA, your approval is needed on a few things. To provide a better website experience, hubpages.com uses cookies (and other similar technologies) and may collect, process, and share personal data. Please choose which areas of our service you consent to our doing so.

    For more information on managing or withdrawing consents and how we handle data, visit our Privacy Policy at: https://hubpages.com/privacy-policy#gdpr

    Show Details
    Necessary
    HubPages Device IDThis is used to identify particular browsers or devices when the access the service, and is used for security reasons.
    LoginThis is necessary to sign in to the HubPages Service.
    Google RecaptchaThis is used to prevent bots and spam. (Privacy Policy)
    AkismetThis is used to detect comment spam. (Privacy Policy)
    HubPages Google AnalyticsThis is used to provide data on traffic to our website, all personally identifyable data is anonymized. (Privacy Policy)
    HubPages Traffic PixelThis is used to collect data on traffic to articles and other pages on our site. Unless you are signed in to a HubPages account, all personally identifiable information is anonymized.
    Amazon Web ServicesThis is a cloud services platform that we used to host our service. (Privacy Policy)
    CloudflareThis is a cloud CDN service that we use to efficiently deliver files required for our service to operate such as javascript, cascading style sheets, images, and videos. (Privacy Policy)
    Google Hosted LibrariesJavascript software libraries such as jQuery are loaded at endpoints on the googleapis.com or gstatic.com domains, for performance and efficiency reasons. (Privacy Policy)
    Features
    Google Custom SearchThis is feature allows you to search the site. (Privacy Policy)
    Google MapsSome articles have Google Maps embedded in them. (Privacy Policy)
    Google ChartsThis is used to display charts and graphs on articles and the author center. (Privacy Policy)
    Google AdSense Host APIThis service allows you to sign up for or associate a Google AdSense account with HubPages, so that you can earn money from ads on your articles. No data is shared unless you engage with this feature. (Privacy Policy)
    Google YouTubeSome articles have YouTube videos embedded in them. (Privacy Policy)
    VimeoSome articles have Vimeo videos embedded in them. (Privacy Policy)
    PaypalThis is used for a registered author who enrolls in the HubPages Earnings program and requests to be paid via PayPal. No data is shared with Paypal unless you engage with this feature. (Privacy Policy)
    Facebook LoginYou can use this to streamline signing up for, or signing in to your Hubpages account. No data is shared with Facebook unless you engage with this feature. (Privacy Policy)
    MavenThis supports the Maven widget and search functionality. (Privacy Policy)
    Marketing
    Google AdSenseThis is an ad network. (Privacy Policy)
    Google DoubleClickGoogle provides ad serving technology and runs an ad network. (Privacy Policy)
    Index ExchangeThis is an ad network. (Privacy Policy)
    SovrnThis is an ad network. (Privacy Policy)
    Facebook AdsThis is an ad network. (Privacy Policy)
    Amazon Unified Ad MarketplaceThis is an ad network. (Privacy Policy)
    AppNexusThis is an ad network. (Privacy Policy)
    OpenxThis is an ad network. (Privacy Policy)
    Rubicon ProjectThis is an ad network. (Privacy Policy)
    TripleLiftThis is an ad network. (Privacy Policy)
    Say MediaWe partner with Say Media to deliver ad campaigns on our sites. (Privacy Policy)
    Remarketing PixelsWe may use remarketing pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to advertise the HubPages Service to people that have visited our sites.
    Conversion Tracking PixelsWe may use conversion tracking pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to identify when an advertisement has successfully resulted in the desired action, such as signing up for the HubPages Service or publishing an article on the HubPages Service.
    Statistics
    Author Google AnalyticsThis is used to provide traffic data and reports to the authors of articles on the HubPages Service. (Privacy Policy)
    ComscoreComScore is a media measurement and analytics company providing marketing data and analytics to enterprises, media and advertising agencies, and publishers. Non-consent will result in ComScore only processing obfuscated personal data. (Privacy Policy)
    Amazon Tracking PixelSome articles display amazon products as part of the Amazon Affiliate program, this pixel provides traffic statistics for those products (Privacy Policy)