navigate site menu

Start learning with our library of video tutorials taught by experts. Get started

HTML5 Projects: Interactive Charts

HTML5 Projects: Interactive Charts

with Joseph Lowery

 


Spice up dry data presentations with interactive and visually engaging charts. This installment of HTML5 Projects shows how to build interactive bar charts, dynamically drawn with HTML5 Canvas. The user-friendly chart elements allow visitors to record different data scenarios by dragging bars. Author Joseph Lowery also shows how to automatically save the data from day to day. Altogether, this course offers a great introduction to HTML5 form elements with Canvas, integrated drag and drop, and local storage technologies.
Topics include:
  • Crafting the HTML
  • Initializing the stage
  • Adding a legend and labels
  • Drawing the bars in the bar chart
  • Adding anchors for interactivity
  • Connecting the feedback
  • Storing user progress

show more

author
Joseph Lowery
subject
Design, Web, User Experience, Web Design, Projects
software
HTML , JavaScript , CSS
level
Intermediate
duration
1h 7m
released
May 23, 2013

Share this course

Ready to join? get started


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



Introduction
Welcome
00:00 (music playing).
00:04 Hello, thanks for checking out HTML5
00:06 Projects, Interactive Charts. I'm Joe Lowery and I'll be your guide to
00:10 building an online interactive bar chart. This project is great for web apps where
00:15 you want to enable the user to easily chart their own progress in a task.
00:19 And then save it for a future reference, sharing, or just bragging rights.
00:23 We'll put the powerhouse HTML5 Feature Canvas to work and I'll show you how to
00:27 import background images, add text, draw primitive shapes, integrate anchor points
00:33 for single direction dragging, display continuously updated numeric feedback and
00:38 much more. You'll see how to incorporate an HTML5
00:42 Web Storage Solution to effortlessly keep track of the chart progress from day to
00:46 day, as well as how to save the entire chart to admire or share.
00:50 Sound good, then let's get going with HTML5 Projects, Interactive Charts.
00:55
Collapse this transcript
About the exercise files
00:00 I'm very happy to announce that any member of lynda.com now has access to the
00:05 exercise files used throughout this title.
00:08 Naturally the information in this course is ultimately intended to be applied to
00:12 your own webpages. However, you may find it helpful to work
00:16 with these supplied exercise files to practice the steps safely and without
00:21 creating your own examples. To begin using the files from the site,
00:25 download them, extract them, and then store those files in a convenient
00:29 location, such as your desktop. Or, if you're using a local web server
00:34 like I am, your web server root. (SOUND) I've got Map running, so my files
00:41 are located in the htdocs folder found in the Map Application folder.
00:46 The exercise files folder is organized by chapter and the chapters are broken down
00:52 into its various lessons. Within the lessons chapters there are a
00:57 series of items. Typically HTML, CSS, images, and so forth.
01:02 All of which make up the practice file. For most lessons, you'll also find a
01:07 folder named final, which contains the completed lesson file.
01:12 You're free to explore this at your leisure, of course.
01:15 Now you can either follow the whole course, chapter by chapter, or jump in at
01:20 any point. If you'd rather not use the exercise
01:23 files, you can definitely follow along with your own assets.
01:27
Collapse this transcript
Course and browser requirements
00:00 To follow along with this course, the requirements are pretty straightforward.
00:04 From a tools perspective, you'll just need a code editor, and a number of
00:08 browsers for testing. You can use whichever code editor you prefer.
00:13 I'm going to be working with Aptana on the Mac.
00:16 A free editor for both Mac and Windows. Most of our browser demonstrations and
00:21 testing will be done using pretty current versions of standard base browsers like
00:25 Google Chrome or Firefox. As the focus in this course is on some of
00:30 the most recently released technologies you probably shouldn't depend on the
00:34 techniques demonstrated if your client needs to support legacy browsers like
00:39 Internet Explorer 6. That's it for tools.
00:41 From a knowledge perspective you should be pretty familiar with both HTML and CSS
00:47 with a general understanding of Java Script.
00:50 I'll walk through any advanced Java Script we use, block by block so you can
00:54 understand what's going on under the hood.
00:57 Oh, and one last item. The absolute best thing you can bring to
01:00 this course is your imagination. Although, I'm going to be going through
01:04 all the details of applying HTML5 technologies to a specific project,
01:09 you'll get the most benefit if you keep your mind open for other ways you can
01:13 apply the same lessons to your own work.
01:15
Collapse this transcript
1. Understanding the Project
What we're going to build
00:00 In this lesson, I'm going to run through the completed interactive charts project,
00:04 so you can see what we'll be building. If you're the type who likes to dive
00:09 right into the code, and you've already downloaded the exercise files, you'll
00:13 find the completed project in the Chapter 1 01_01 folder.
00:19 So, welcome to the fictional Trans Planet Airlines website, where folks planning
00:23 their trip to the moon can record their Lunar Leaping Training progress.
00:28 As the instructions say, the idea is to drag the bar up to show how high you
00:32 jumped in your training that day. So, if I move my mouse over the corner of
00:38 day 1, a handle appears, and I can drag that bar up.
00:44 When I do, a number value appears showing the relative progress.
00:49 Let's say I just made it to 4 today, whether it's inches, feet, yards or
00:54 meters, that can be specified later. The relative number and its relationship
00:58 to the height of the bar, is what's important.
01:00 So, here's where a little bit of behind the scenes techno magic takes place.
01:06 Let's say, I've close my browser, and then come back the next day after a
01:11 rigorous session in the lunar leaping simulator.
01:13 I want to mark my progress for day two. I'll simulate that experience by copying
01:21 my URL, and then opening up a new tab, and pasting it in.
01:27 When I scroll down to see the chart, low and behold, the day one value is
01:34 displayed correctly. We'll use the HTML5 technology Local
01:39 Storage to achieve that effect. Okay, let's bring up the bar for Day 2.
01:49 Doing better, made it to 9 this time. Again, the value is automatically stored
01:53 for later. Alright, let's go for Day 3.
01:58 Woah, got up to 17, excellent work, I think I'm ready to go lunar leaping.
02:06 Now, if I want to show everyone how great I did, I can click the Training Complete
02:11 button, and the entire chart, bars, values, and background, is merged into a
02:15 single image, which I can save locally and then share to my hearts desire.
02:21 So, that's the project, and now you're ready to peek under the hood, so you can
02:25 get a better understanding of the various technologies that are driving this app.
02:29
Collapse this transcript
Highlighted HTML5, CSS3, and JavaScript technologies
00:00 Before we start the actual creation of the project, let's talk about each of the
00:04 key technologies being used. There are two main technologies brought
00:08 into play in this project, Canvas and Local Storage.
00:11 Let's take a quick look at Canvas first. Canvas brings run-time graphics to the
00:16 web, with a terrific degree of control. Stroke and fill are independently controlled.
00:21 It can handle all primitive shapes, like line, circle, and rectangles.
00:26 As well as text and images, perhaps Canvas' best feature,to my mind anyway,
00:30 is that it enables interactive graphics. You can, as we will in this project,
00:35 combine layers of graphic elements, apply graphic filters, and animate any graphic
00:40 element, including moving, resizing, and rotating.
00:44 Happily, Canvas has great browser support.
00:47 As you can see, on it's page on caniuse.com.
00:49 To make the most of Canvas, we're going to be using a dedicated library called KineticJS.
00:55 KineticJS was developed by Eric Rowell and really brings a lot of advanced
01:00 functionality within easy reach. You can learn more about KineticJS by
01:04 going to it's site. Next, let's take a look at local storage.
01:08 You'll find local storage very easy to use.
01:10 One of the primary benefits of Local Storage is that it provides a much needed
01:14 state to websites. So you can carry variables from one web
01:18 page to the next, all without server-side coding.
01:21 Local Storage is browser specific and provides a much larger storage space, 5MB
01:27 vs 40kb for cookies. Local Storage is set up as a name/value
01:32 pair structure, so you'll need to convert any non-string formats you use.
01:36 The two most common commands are setItem and getItem.
01:40 Set item takes two arguments, the item name and its value, while get item only
01:45 needs the name of the item to retrieve it.
01:47 As caniuse.com shows us, browser support for local storage is really rocking.
01:53 As you'll see in the remaining lessons, the technologies involved in this project
01:57 are full featured and pretty well supported in the browser.
02:00
Collapse this transcript
2. Setting the Stage
Crafting the HTML
00:00 Before we launch into the canvas oriented JavaScript, where we'll spend the vast
00:05 majority of the course. Let's bring in the essential HTML, and
00:09 include the neccessary JavaScript files. So I have open, index.htm from the
00:16 chapter 2 > 02_01 folder of the excersise files.
00:21 Let's look down at the body section where we can insert a couple of key HTML elements.
00:28 First, we're going to need to add a DIV with an I.D of container.
00:32 This DIV will eventually hold the canvas tag that will be inserted at runtime by
00:39 our JavaScript. I'm going to put this DIV tag right below
00:43 the steps DIV that has some instructions for the site visitor.
00:52 We'll give it an I.D of container, and antenna automatically provides the
01:01 closing DIV tag. Now, right below that, I'm going to add
01:05 another DIV to hold the complete training button.
01:09 So, I'll move my cursor to the end, hit Enter and then put in my DIV tag.
01:15 We don't need to give this one an I.D. Next, I'll enter button, give that an I.D
01:22 of save image. And then the text within the button will
01:27 say, Training Complete, exclamation mark. Now let's go back up to the Head section
01:36 so we can link in our JavaScript files. I've already downloaded the file and
01:41 stored it in my script folder, so we'll put in a script tag.
01:46 Give it a type equal to text JavaScript. And then set the source equal to
01:55 scripts/kinetic-v4.40.js, and then, close the script tag.
02:09 Now I've also created a shell file for our custom canvas code named canvas_chart.js.
02:14 Let's add the script tag for that code next.
02:18 Script type, text slash javascript and the source for this one, also in the
02:34 script folder, and it's canvas_chart.js. Okay we close that tag, and that's really
02:44 all the HTML we'll need. In the next lesson we'll start working
02:48 with our custom JavaScript file.
02:49
Collapse this transcript
Initializing the stage
00:00 Our first task in the custom JavaScript is to get an overview of the modules needed.
00:07 The second is to initialize the stage. Relatively speaking, this is a very
00:11 simple process, but I wanted to start out slow, so we can ease into the coding.
00:16 I have opened canvas_chart.js from the chapter 2 02_02 folder in my code editor.
00:24 As you can see, all that's in it are a series of Javascript comments.
00:28 Each comment denotes a major section, typically a function.
00:32 There are six sections in all, but don't let that low number lull you a sense of security.
00:38 Some of the functions are quite lengthy. On the other hand don't let the length
00:42 scare you. Because we're ultimately going to build
00:45 three different bars in our bar chart much of the work is copy, paste alter.
00:51 The first function I want to set up is in it stage.
00:54 We'll take advantage of the kinetic js syntax to create our stage and point it
01:00 toward our container DIV. So, let's begin by naming it function initStage.
01:07 Put in an open and curly closing brace, and we'll declare our first variable,
01:17 named stage, and set that equal to new Kinetic.stage.
01:22 So, this is a kinetic stage object. And within the parentheses we'll put a
01:26 set of curly braces, and then I'll hit Enter to make a little room.
01:34 And this is the first of our array elements, container, colon and then
01:41 single quotes, container, which is the ID of the DIV that's going to hold the
01:47 canvas tag. Next, we're going to give it a width and height.
01:52 So, enter a comma with 600 height, 400. Now let's put a semicolon here to close
02:03 off that line. I'm going to leave an empty line before I
02:05 close off the function, as a reminder of code to come.
02:08 And because this function is quite lengthy, I'm also going to add a comment
02:17 Indicating where it ends. Just good coding practice.
02:23 Now that's all the coding we're going to do in this lesson, but I do want to point
02:27 out one thing. Note that the parentheses following the
02:31 initStage function on line 4 are empty. That's typical for a function that
02:37 doesn't accept any arguments. But watch that space, because in the next
02:43 lesson we'll insert code to load the needed images.
02:48 Which will call the initStage function when it's done.
02:51 And we'll need to insert a parenthetical argument at that time.
02:55
Collapse this transcript
Loading the background image
00:00 Our project uses a nice background image of Apollo 16 on the moon, courtesy of NASA.
00:05 In this lesson, I'll show you a routine that will load that image, so that it can
00:10 be used by canvas. And the routine is so robust, you can use
00:15 it to load any number of images. After we set that up, we'll add the code
00:20 to display the background image on the canvas.
00:24 I have the canvas_chart.js file from the Chapter 2 02_03 folder open, and we'll go
00:30 down towards the bottom of the page where it says Set Image Sources.
00:36 First I need to define a variable for our image sources.
00:41 And I'll call it Sources. And I'll set the equal to an array.
00:48 We'll use the array for the variable, so that you can load multiple images if you
00:51 need to. We're going to use just one image, and
00:55 I'll give that a name of moonSurface, follow that with a colon, and then our
01:03 path needs to be set because it's a string, in quotes.
01:08 So, images/plum_apollo16_big.jpg. Put a semicolon after var sources.
01:24 Next, let's call the function to load the images, cleverly called, Load Images.
01:35 We'll pass two arguments in the parentheses.
01:38 The first is called Sources, and that passes in the image name and path, or source.
01:46 The second argument, after the comma, defines the callback function, or what
01:53 happens next after all the images are loaded.
01:57 The code is set up this way to make sure that the images are loaded completely
02:00 before the stage is initialized and tries to use those images.
02:04 So, the function we're going to call is, of course, initStage.
02:11 Okay, now it's time to build the load images function, and that's at the top of
02:17 the page. Essentially, we're going to create a new
02:20 canvas image object for each element in the sources array, using the name and the
02:26 SRC attribute. Then, after all the images have been
02:30 looped through, we'll call the initStage's function, and pass in our
02:35 image array. So, we enter the keyword function,
02:39 followed by the name of our function, loadImages, open and close parentheses,
02:45 and the two arguments, sources, comma, callback.
02:50 After the closing parentheses, put in an open and closing curly brace.
02:56 And we'll declare our first variable, which is var images, and set that equal
03:04 to an empty array, or an open and closed curly brace.
03:10 The next variable is called Loaded Images.
03:12 And because we're just starting out, that will be set to 0.
03:23 Now we need a counter, and we'll call that numImages, and also set that to 0.
03:34 Next comes a for loop. For, open and close parenthesis, var src
03:42 in sources, for every src that's in the sources array.
03:48 And then, after your parenthesis, put in another open and close curly brace.
03:55 Then what we're going to do is we're going to create a new image object for
03:59 each one of those, so as part of the array's images square brackets src equal
04:05 to new Image. Next we'll use an on load function for
04:15 each of those images. So, after the square bracket, dot onload
04:24 and set that equal to a function, open and close parenthesis, curly brace.
04:32 Now we want to check and see if we're done, basically.
04:36 So, we'll put in an if statement with an open and close parenthesis, and then the
04:42 incremented indicator, dot dot loadedImages is greater than or equal to
04:53 the number of images, numImages, open and close curly brace.
05:00 And if that's the case, we're done, so call the call back, and pass in the
05:07 images argument. Okay, I need to put a closing semicolon
05:13 after that second curly brace there, and one more line of code and this is where
05:18 we actually set the source of the file. So images, square bracket src, dot src,
05:25 and set that equal to sources, square bracket src, close it all off with a
05:27 semicolon and we're done. Now, I want to make the modification to
05:29 initStage's, I mentioned in the previous lesson.
05:43 I'll add the argument Images to my initStage's function call.
05:50 Next, we're ready to begin populating the stage.
05:54 So, I'm going to scroll down a little bit, bring this up to the center.
06:00 Now we're ready to start populating the stage.
06:02 The first thing we'll need to do is to create a background layer.
06:05 So, I'm going to put this on it's own line here, and we do that by declaring a
06:10 var bgLayer, and set that equal to new kinetic.Layer, open and close parenthesis
06:20 and a semi colon. Now we can create our background image object.
06:25 Just put in a little comment here, background image, and a new var bgImg,
06:33 background image. And this will be a new Kinetic.Image,
06:44 parenthesis, curly brace. We want our image to be placed in our
06:49 upper left corner of the canvas. So, my coordinates are going to be 0,0.
06:53 So x, colon, 0, followed by a comma. y, colon, zero, followed by a comma.
07:02 Now, we get to say what the image is. Image colon, and this is where we're
07:08 going to reference our images array. Images dot, you'll recall the name of the
07:15 image of my source file was Moon Surface, follow that with a comma.
07:21 Let's give the width, something equal to 600, and the height, which is 476.
07:34 One last parameter and that's the name, colon and we'll set that to image.
07:39 All right, a semicolon to close off that var declaration.
07:44 And now, things are really getting exciting.
07:48 So, let's add the background image to the background layer.
07:52 And you do that by declaring bgLayer.add. And then in parentheses, the name of
08:02 whatever it is you're adding to the layer.
08:03 In this case, it's bg image. And now I'll add that layer to the stage,
08:12 Stage.add bgLayer. Finally we're all set to draw the stage.
08:24 Now that's a simple function stage.draw. So, let's save the page and check our
08:32 progress in the browser. I have the page loaded here.
08:36 All I have to do is hit refresh to see the latest code.
08:42 And our background loads. I'll refrain from making it a one small
08:46 step for coders comments, but just barely.
08:51 So, now the stage is set, to start adding the chart elements in the next chapter.
08:55
Collapse this transcript
3. Drawing the Chart
Adding the legend area and labels
00:00 This lesson is dedicated to the legend area.
00:03 That part below the bars with the labels day one, day two, and day three.
00:09 I'm going to start by creating a new legend area out of a white rectangle.
00:13 We're going to put this code below the initial stage declatation here.
00:19 Create a new line, hit Tab so everything lines up, enter var legendArea, and we'll
00:30 set that equal to a new Kinetic.Rect, short for rectangle, parenthesis and
00:38 within those curly braces. Now i want this to appear at the bottom
00:43 of the page stretched all the way across. So, our x coordinate is going to be 0, so
00:49 it'll be flush left, follow that with a comma, and the y coordinate we're going
00:55 to calculate. So I want to get the height of the stage,
00:59 and then make it minus 20. Because I'm moving it down to 20 pixels
01:05 above the bottom. Now I could have just put in 380, but
01:09 this is more generic, and I wanted to show you a way to calculate it, so that
01:15 you could use this routine over and over. So, get height, parenthesis, minus 20, comma.
01:24 And then we'll set the height to 20, and the width, again we'll use a function
01:29 stage.getWidth comma, and we'll fill it with the color white.
01:37 Let's close that all with a semi-colon. Next we're going to create the labels.
01:44 Each label will be it's own text object with very similar properties.
01:48 So, once we code one, we can copy, paste, alter the other two.
01:53 So, this will be my dayOneLabel, and I'll set up a variable with that name, dayOneLabel.
01:59 new Kinetic.text, parenthesis and curly braces.
02:06 So, our first parameter is text, colon, and this is a sting, so I'll put that in
02:11 quotes Day 1, comma. Next let's set the font size to 12, comma.
02:22 Next we need to give the coordinates, so I'm going to move this in a little bit on
02:25 the left, x colon 40 comma. And then y, I'm going to use a calculation.
02:32 I'll take the stage, get height minus 18. So, it moves it down a little bit from
02:40 the 20, that's the top of the rectangle. fontFamily, I'll set to sans-serif, and
02:50 let's fill it with a greyish color. If you're specifying a hexadecimal value,
02:56 you need to put in the hash sign. So, 333333, okay let's scroll it down a
03:02 little bit. Now before I leave this, let me put in my
03:06 closing semicolon. And now I'm just going to, as I said,
03:10 copy this code block, and then, paste it in once.
03:15 Now let's change the variable name from dayOneLabel to dayTwoLabel, and change
03:20 the text from Day 1 to Day 2. So, we also want to move it over.
03:27 So, I'll change the x value to 170 a 130 pixels over.
03:34 Let me copy that one, and then paste it in for my day Three, which I'll change
03:39 the variable name from dayTwoLabel to dayThreeLabel.
03:45 Change the text to day 3, of course, and the x value gets bumped up to 300.
03:51 So, where on the stage do the legend area and the labels go?
03:55 Certainly not the background layer. Let's create a new layer to hold them,
03:59 and I'm going to put it just above the background layer declaration here.
04:06 var Layer equals new Kinetic Layer. All that's left is specifying what goes
04:15 where, and where you put your code is critical, because the order of the code
04:20 determines the stacking order or z index. So, I'm going to move down to where I
04:27 have bg layer add bg image, and in-between these two, I'm going to put in
04:33 my four objects. The first one will be the legend area.
04:37 And I'm going to add it to not the bg layer, but layer.
04:40 So, Layer.add legendArea semicolon, Layer.add, dayOneLabel.
04:51 Layer.add dayTwoLabel, and layer add dayThreeLabel.
05:06 Finally, I want to add the layer itself, and I don't want to put it before
05:10 bgLayer, because otherwise it would be behind the background layer.
05:15 I want to have it appear after that. So, I'll make a new line after stage add
05:19 bgLayer and enter stage add Layer. Okay, let's save this page and see what's what.
05:30 Let me refresh the page, and we have labels in the house.
05:34 Now, I know that sometimes it seems like it's a lot of work for a small result,
05:39 but that's pretty much the nature of the canvas beasts at this point in time.
05:42 And structuring your canvas bit by bit is the best way to get it done.
05:47
Collapse this transcript
Drawing the bars
00:00 It's time to bring the bars onto the stage.
00:02 Again we'll define three new objects, each similar to each other.
00:08 So, it should go pretty quickly and smoothly.
00:10 I'm going to define the bars right after the initial stage declaration, and once
00:15 we define one, it'll be a snap to copy past alter the other two.
00:19 So, first variable dayOneBar. And we're creating these out of
00:27 rectangles, so this will be a new Kinetic.Rect object.
00:36 Now the bars are going to be part of a larger group.
00:40 So, our x and y coordinates can be 0, for both.
00:47 The width for all bars will be 100. And the height, when they first start
00:53 out, will be 10. We'll name them all bar, and this first
01:01 one, I'll give a fill of hashtag b20000. And that's a hexadecimal color code for
01:10 the red that's in our logo. And with a semicolon at the end, this
01:14 one's done. So, I'll copy it, as well as the line
01:19 after it. Paste it in again, change the variable
01:23 name to dayTwoBar. And we'll change the color, which is the
01:29 only parameter we need to change, to green.
01:32 Okay, I'll copy dayTwoBar and paste in a copy of that.
01:37 And then we'll change the variable name to dayThreeBar and give it a different color.
01:45 Let's make this one blue, that's it for this section, but there's nothing to
01:51 preview yet. You'll have to wait until we add the bar
01:54 groups, which comes up in the next lesson.
01:57
Collapse this transcript
Creating bar groups
00:00 You may be asking yourself, didn't we just create the bars?
00:03 What's all this about bar groups? Well, we need to create the bar groups,
00:10 so we can attach anchors to each bar, that will allow the bar to be dragged and
00:15 rescaled by the user. So what we'll do in this lesson, is
00:19 define each of the bar groups, one for each bar.
00:22 And then attach the bars to the bar groups and the bar groups to the canvas layer.
00:29 Sounds like fun? Let's do it.
00:32 We're going to put our bar groups right below the bars so let me scroll down,
00:37 past those, day one bar, day two bar, day three 3 bar.
00:45 (SOUND). And I'll add a couple extra lines there.
00:47 Now, before we can define the first group, we're going to have to set up some variables.
00:52 These variables are really only temporary.
00:54 But we need to use them in the bar group. And they'll figure in our coding later.
00:59 So the variables are bar oneY, as in y coordinate, bar twoY, and bar threeY.
01:07 They're all set to 370. Var, barOneY equals 370, semicolon, var,
01:21 barTwoY, equals 370 and var, barThreeY. You guessed it, equals a 370.
01:34 Now we're all set to create the bar groups.
01:36 KineticJS includes a group object that we can take advantage of.
01:41 So my first variable name is barOneGroup. I think you see a method for my madness
01:47 here and, we'll create a new Kinetic dot Group, parenthesis and curly braces.
01:57 We'll set the x coordinate to 10, the y coordinate to the variable we just set up
02:08 barOneY, comma and draggable false. Now we want to make sure that the bar
02:15 groups are not draggable because all the dragging will be done by the anchors.
02:22 Alright I'll put a closing semicolon after my curly braces and parentheses.
02:28 And this code block is ready to be Copied and Pasted and altered, so, barTwoGroup.
02:38 We'll need to change the x coordinate, add 130 pixels to it, so that becomes 140.
02:47 We also need to change the y-coordinate to barTwoY.
02:54 Now we're setting these up as variables rather than as static values, because
02:59 once the user drags the bar to a new location, the y value will change.
03:06 Okay, let's do our final bar group and we'll make this one barThreeGroup.
03:16 It's 270 pixels away and it uses the y of barThreeY.
03:25 Cool, now with our bar groups ready to rock, let's go ahead and add them to the
03:30 stages layer. So let me scroll down to that section.
03:34 I'm going to put them between the background layer and the legend area, so
03:40 that they're on top of the background but behind the legend.
03:45 Because we're actually using the legend area to mask the bottom two anchors that
03:50 we'll be adding. So I'll put my cursor at the end of the
03:53 bgLayer.add bgimage line, hit Return, and enter layer.add(barOneGroup), semicolon
04:03 at the end, and two more times. This time, barTwoGroup.
04:13 And finally, layer.add, barThreeGroup. Our last task in this lesson is to add
04:26 each bar to its respective bar group. For this to render properly, we need to
04:31 place this code below the stage set up. So we'll specify barOneGroup.add(dayOneBar).
04:45 (SOUND). Now I'm going to leave an extra line
04:49 between each of these declarations. Because there's some additional code,
04:54 adding the anchors in, to be specific, that's coming up a little bit later.
04:57 BarTwoGroup.add(dayTwoBar). Finally, barThreeGroup,add(dayThreeBar).
05:21 Time to save the page and see if our bars are where they should be.
05:27 Let me refresh the page, and there they are, at their initial height.
05:32 They're not terribly exciting but their perfectly positioned to integrate the
05:37 anchors, which is coming up in the next lesson.
05:40
Collapse this transcript
Adding anchors for interactivity
00:00 Anchors are a concept in KineticJS that allow canvas objects to be resized in any
00:06 direction and even rotated. In this lesson, we'll add four anchors to
00:11 each bar, one for each corner. With a free floating object, this
00:15 placement would allow a rectangle to be stretched every which way.
00:18 We're going to hide two of the anchors behind the legend area, so users will
00:23 only be able to grab the top two to resize the bar.
00:27 The code for manipulating the anchors, attaching them and then updating them
00:30 when moved, is pretty complex. So we are going to take a break from hand coding.
00:34 I've already included the code in the canvas chart.js file found in the chapter
00:41 3>03_04>scripts folder. I will however walk through both
00:45 functions to explain how everything works.
00:48 But before we get to that, let's put in the code to call the at anchor functions.
00:53 Again, it's fairly repetitive code, which will allow us to copy, paste and modify.
00:59 The code we're going to insert into the section that we entered in the last lesson.
01:04 And that's located towards the bottom of the init stage group.
01:10 So here's my bar one group, add, so after that I'm going to add anchor, parenthesis.
01:20 The add anchor function takes four arguments the first is the name of the
01:25 group that you're adding to. Bar one group.
01:29 Next are the x and y coordinates, and well start with the top left, 0, 0.
01:34 And then, the name of that anchor, which we're just going to call top left.
01:44 Now we need to add an anchor to the top right.
01:46 The x coordinates here will be 100 and the y still 0, and the name, top right.
02:01 Now let's move to the bottom right, and add another anchor there for the bar one group.
02:09 The x coordinate here will be 100. And the y coordinate 20.
02:15 The name of course will be bottom right. Finally, for this group, add anchor bar
02:24 one group 0, 20. And that would be the bottom left.
02:35 Okay, now that we have those four done, let's just copy them, and then I'll paste
02:41 them right below the bar two group. And all we really need to do is to just
02:46 change the name for those. So I'm just going to select and copy bar
02:50 two group there and then for each anchor, I'll select and paste in contents of my clipboard.
02:59 Let's get rid of that extra line I mistakenly put in.
03:06 Now let's add the add anchors for the bar 3 group.
03:10 Again, I'll copy my add anchor routines, paste those in, copy the bar 3 group
03:21 name, and then paste it over bar 2 group 4 times.
03:28 Okay, our coding is done. Now, we're going to take a tour of the
03:32 add anchor function that we just referenced.
03:35 It's located after init stage. There's the two functions.
03:39 There's function update, and then below that, is function add anchor.
03:44 You'll find it on line 190. The first two variables you see var stage
03:49 and var layer, get the respective objects as it relates to the specific bar group.
03:55 Then, online 194 an anchor is created from a circle object.
04:02 Initially, the stroke width is set to 0 so it's hidden.
04:07 We also want it to be draggable. As you can see by draggable equals true
04:11 on line 200. But not just anywhere.
04:14 The drag bound function that starts on line 202 constraints the movement to the
04:21 y axis. The next set of routines all starting
04:26 with anchor on, tell the anchors what to do when a particular event happens.
04:31 It's kind of like the Java script add event listener function.
04:35 The first one is key. It calls the update function we'll
04:38 discuss shortly, whenever the anchor is moved.
04:42 This allows for smooth interaction. The first argument for each of the anchor
04:47 on routines is the event that's fired. So you can easily see what's happening.
04:53 The code block that starts on line 214, actually incorporates two events, so that
04:58 computers that use a mouse or a touch pad would benefit from the mouse down event.
05:04 Whereas devices that use touchscreens could use touch start.
05:09 The last two anchor on functions, starting on line 227, are used to show
05:14 and hide the anchor circles on mouse over and mouse out.
05:18 This happens by changing the stroke width.
05:22 And if we scroll down just a little bit more, the last line in this routine
05:25 completes the functionality by actually adding the anchor to the group.
05:29 Okay, let's take a quick look at the update function and we'll scroll up above
05:34 add anchor. And there you see update function
05:40 starting on line 156. As I said, this comes into play whenever
05:44 an anchor is moved. The function opens by defining a series
05:48 of variables that basically establish which anchor goes on which corner, and is
05:54 attached to which bar? It also gets the current anchor x and y.
05:59 Then, around line 169, the x and y coordinates are updated according to
06:06 whether the top left or top right anchor are involved.
06:09 There's no need to specify bottom left and bottom right, because we won't be
06:14 using those. Then on line 180, the entire bar is
06:18 placed at it's new position. And finally, starting around 182, the
06:25 width and height are adjusted. Well, that's certainly a lot of info, so,
06:30 why don't we see it in action? I'm going to save the page, and then go
06:34 to the browser. Let me refresh the page.
06:37 And no apparent change, but I move my mouse over the corner of one of the bars,
06:44 you'll see the circle appear. This is the anchor.
06:48 My pointer change to a hand, so and if I drag it up, the bar in the bar chart rises.
06:58 Let's try it on another end. Here's my Day 1, and just to be complete,
07:04 let's try Day 3. All right, that's working quite well.
07:08 I know it's not quite magic, but pretty close.
07:11 The next step is to display some number values that relate to the dragged bar height.
07:17 So I'll see you in the next lesson.
07:19
Collapse this transcript
Connecting the feedback
00:00 In the previous lesson, we got the interactive bars working, where the user
00:04 can drag them to any height. But the project needs corresponding
00:08 numbers to convey exact values. We'll put those much needed numbers on
00:13 screen in this lesson. And even hook them up to the bar height
00:16 for real time updating. Let's start by creating three text
00:20 objects for the numbers. We're going to put this code after the
00:24 bar groups are defined and before legend area.
00:28 That's around line 74, so let's scroll down there.
00:32 And we want to put it right in front of legendArea here.
00:37 So again, we can create one object, and then Copy, Paste, Alter.
00:45 Only the x and y coordinate values will vary for these different objects.
00:49 So it's var, dayOneText, and this is a new Kinetic.Text.object.
01:01 The content for it, I'm actually going to put in as an empty string.
01:05 Because I don't want to have any values there until people actually move the bars
01:10 so we'll follow that with a comma. Let's make the font pretty big its a font
01:15 size of 48 and again the x and y values will be specific for each bar.
01:22 So for the day one bar its going to be x 35 y 338.
01:28 I should have said earlier that only actually the x value changes, the y is consistent.
01:36 Font family is sans-serif. And, one of the nice things about Canvas
01:47 is that you can independently control the stroke and the fill of text.
01:52 So you can get outlined letters, if you want, or either with or without a fill.
01:56 In order to make the numbers stand out a little bit more, let's add a black stroke.
02:01 So, stroke, colon black, and we'll make the letters white, with fill, white.
02:10 Let me add a semicolon at the end here, and now we're ready to Copy that code,
02:16 Paste it in. Change dayOneText to dayTwoText and then
02:24 change the x value from 35 to 165. Let's scroll down and make a little more
02:33 room and we'll still have that on the clipboard, so we'll just paste it in again.
02:43 DayThreeText, will be 295 as the x value. So let's go down to that section.
02:52 And there it is, and we're going to put these right after the label.
02:56 They could go before, but it doesn't really matter, as long as they're on top
03:02 or after the bar groups. That's really the only thing that does matter.
03:06 And we'll add these to, so layer add dayOneText, layer add dayTwoText, layer
03:20 add dayThreeText. One last chore to take care of in this
03:26 lesson, and that's to make these text objects, interactive.
03:29 We'll insert three functions after the addAnchor function calls.
03:35 So, scroll down, and go, right in front of, stage draw, and we'll target the
03:42 dayOneBar first. This is a event-driven function so we use
03:48 the on syntax. And it takes two arguments.
03:53 First is the name of the event, and the event that we're going to use is heightChange.
03:59 Which is an event specific to kineticJS, follow that with a comma and then we are
04:05 going to tell it what to do and for that we we will set up a function.
04:10 After the opening and closing parenthesis put a curly brace.
04:14 We're going to create a variable called the Height, and we'll get that using the
04:23 get height function. But I want to make sure it doesn't come
04:26 in as a floating number, so I'm going to use parseInt, a JavaScript function, to
04:31 change it to an integer. And we want to get the height of the
04:36 dayOneBar, open and close parenthesis, divided by 12.
04:44 Now I have to admit this is a rather arbitrary number.
04:47 I wanted to have a value returned from the pixel measurements, as the bar is
04:52 changing height, that seem to have some sort of general sense to it.
04:57 So, I tried a bunch of different division numbers, 12 was one that I liked, and
05:02 that's the back story behind that particular value.
05:05 So now that we have the height, let's set the text to that height.
05:10 (SOUND). This will display whatever the number
05:17 value is in our text object. Okay, time to Copy that function.
05:25 So we'll change this to dayTwoBar and parseInt dayTwoBar also and dayTwoText,
05:38 setText to height, okay? Just to be consistent, I'll go ahead and
05:44 Copy that, Paste it in. And now, we'll change the Two's to
05:52 Three's, dayThreebar on, dayThreeBar getHeight, and dayThreeText.
06:03 Okay I'm ready to see some action how about you?
06:05 Let's save that page and power up that browser.
06:10 Okay I've loaded the page in my browser and now let me hover over the anchor on
06:15 day one. I'll pull it up and there's my text value.
06:19 If I continue it all the way it goes all the way up to the top which is 32.
06:25 Not bad, lets check the other two to make sure that they're working.
06:28 There's that value for day two and day three is good to go as well.
06:34 Alright our bar chart is no officially interactive, nice.
06:39 The next chapter will finish up the project with ways to save the chart selections.
06:43
Collapse this transcript
4. Keeping Track of the Data
Storing the user's progress
00:00 In the last chapter, the bar chart went interactive.
00:04 Users can now drag the daily bars to indicate their progress, and see the
00:08 related numeric value. But since the app is intended to be used
00:12 over a period of days, the only way to retain their progress would be to keep
00:17 the browser window open and avoid moving the bars.
00:21 In this lesson, we're going to use a very handy HTML5 technology called local
00:26 storage to automatically record the height of the bar every time it moves.
00:31 And then, display that same height whenever the user revisits the page in
00:36 the same browser. Cool, eh?
00:38 Let's go do it. First, let's set it up so our app
00:43 automatically stores the height values. Because we want this value stored every
00:48 time the height of the bar is changed, we'll add our code to the height change
00:53 routines we previously inserted. These routines are the second to last
00:58 code chunks in the init stage function right above Stage Draw.
01:03 So let's head on down to around line 184. There's the first of our three routines,
01:10 right at line 184. And we're going to insert a single line
01:13 of code in each function that creates a local storage item with the current
01:18 height value. If the item already exists, it overwrites
01:22 the old value with the new one. So I'm going to put this first one in the
01:28 DayOneBar on code block, right after dayOneText set Text.
01:34 And we'll use the local storage set item functionality.
01:38 So it's local Storage, capital S. Dot setItem, capital I, parentheses, and
01:49 you'll recall from our introduction to local storage in chapter 1 that it takes
01:53 two arguments. The first is the name that you want to
01:58 set for your local storage item, and I'm going to call this DayOneScore.
02:03 So DayOneScore. And then a comma after the single quotes.
02:09 And a value you want to store in DayOneScore and that's going to be the
02:14 variable we declared in this function the height.
02:19 Close out everything with a semi-colon. And now it's basically the same line for
02:24 the other two co chunks that we have here.
02:26 So let me just copy that and I'll paste it in the same relative location but I'll
02:34 change the name of the local storage item, from DayOneScore to day Two score.
02:41 and let's do that one more time for the third item.
02:43 Put my cursor in the correct place, paste it in, and change DayOneScore to day
02:50 Three score. Now that we've put something in local
02:53 storage, we can take it out again and use it.
02:56 So right below these three functions, we're going to add another series of code blocks.
03:02 These we'll check to see if the local storage has been created and if it has,
03:06 set the height of the bar to that value. If it hasn't, it will use the default
03:11 height, 10. So I'll put my cursor after the last of
03:16 the 3 and hit return a couple times while we're at why don't we scroll down so
03:23 bring that cursor. First I'll set up my variable var the DayOneHeight.
03:29 And I'm going to set that equal to 10 that's my default value.
03:36 Now I'll write out an if statement that will check to see if the DayOneScore
03:42 local storage item exists. And if it does, we'll add our code.
03:46 So, if parentheses localstorage.getitem parentheses, single quotes, the name of
03:58 the item we're getting, DayOneScore. Then after those ends of parentheses, a
04:07 curly brace pair. And now we're ready to set the
04:11 DayOneHeight variable. So, the DayOneHeight.
04:17 And we're going to set that equal to the value we retrieve from the DayOne Score.
04:23 Now you may recall, from my introduction to the local storage, that it only
04:28 handles strings. So because we want to multiply whatever
04:33 the value is by 12 to restore it to its pixel height, we're going to use a
04:37 standard Javascript function, parseInt to convert the string that's in the DayOne
04:44 score local storage to a number. So parseInt parenthesis theDayOneScore
04:48 times 12, and now that we have our variable declared, let's put it to use.
05:01 So I'll enter DayOneBar.setheight parenthesis and then the value that we
05:09 want to set the height to which is, of course the variable we just calculated
05:14 the Day OneHeight, okay. Let's go ahead and copy that function and
05:22 then paste it in and change the initial variable from the day one height to the DayTwoHeight.
05:32 Basically we're changing wherever we see a one to a two.
05:40 So, the day two height equals parse in the DayTwoScore times 12.
05:47 And now, DayTwoBar.setHeight, TheDayTwoHeight.
05:54 And lets do that one more time. I'll paste in my copied code form the
05:59 clipboard and change the ones to threes so the variable becomes the DayThreeHeight.
06:07 We're getting the local storage item, DayThreeScore.
06:11 The DayOneHeight, again we change to DayThreeHeight.
06:19 And again change the DayOneScore to the DayThreeScore.
06:22 Now let's change day one bar or DayThreeBar.
06:26 And finally, one last time we'll modify the DayOneHeight and make it the DayThreeHeight.
06:35 One more task to go and that is to remove the temporary variables we inserted up on
06:41 line 52. Let's go up there and check em out.
06:46 This is the bar 1y, bar 2y, and bar 3y. And we're going to replace them with code
06:53 that retrieves the local stored values. So I'll delete these and put in my new
07:01 variables, which is var the DayOneScore equals local storage dot get item.
07:13 And in single quotes, DayOneScore. Close that off with a semicolon, and
07:23 let's do our copy paste routine again. So I'm just going to paste it in quickly
07:27 two more times and then change the Day OneScore on the first item I pasted into
07:33 day two. And dayOneScore of the local storage item
07:38 name to dayTwoScore. On the third line of course we're
07:43 going to change the ones to threes. Finally, we need to handle the initial
07:50 refreshing of the browser, and establish some related variables, depending on
07:55 whether local storage exists or not. So I'm going to make a little space and
08:01 then put in an if else statement that checks to see if there is a DayOneScore
08:08 local storage item. So if parenthesis localStorage dot
08:14 getItem parenthesis single quote dayOneScore.
08:20 At the end of the line after the closing parenthesis put in a curly brace pair.
08:25 So if the local storage exists we're going to set up three variables.
08:30 The first one is the dayOneScore. Where we'll get that local storage value,
08:35 var the DayOneScore equals local storage dot get item, parenthesis dayOneScore.
08:51 Next we want to calculate the day one number.
08:57 And this is using the parseInt function again.
09:07 Finally, we'll use the day one number as we set the bar one y variable.
09:13 Which you recall is one of the variables that we had just deleted but that we used
09:18 as place holders for awhile. So var bar one y equals 370 minus and
09:28 then in parentheses, you all remember your math order of operation don't you?
09:34 The day one number times 12. Again, bringing the value that's stored
09:41 back to its pixel measurement. Plus 20, which is the offset value.
09:47 After the closing curly brace, put in else.
09:51 And then another curly braced pair. If we don't have local storage, let's go
09:55 ahead and set up some default variables. So far, the day one score is going to be
10:02 equal to zero. Var, bar 1y is equal to 370.
10:10 And var dayOneBarHeight is equal to 10. So that's the initial values that they
10:19 would see. Okay, we've got our basic code chunk done.
10:23 I'll select, copy it, and paste it in the first time.
10:28 You've seen this dance before where we change our ones to twos.
10:35 So day one score becomes day two score. The variable the day one score now is the
10:40 day two score. We'll be getting the local storage item
10:44 day two score now. The day one number is converted to the
10:50 day two number, we'll parse in the day two score, and bar 1y becomes bar 2y.
11:00 And then the day one number, again we'll change.
11:04 Okay so I'm just going to do these last default values the day two score bar 2y.
11:11 dayTwoBarHeight. Alright one last time aren't you glad we
11:21 don't have ten different bars? Okay, our twos becomes threes.
11:29 Day three score, v day three score, the day three number for day three score
11:49 parse int, bar 3y and the day three number.
11:59 And now for our default values, the day three score.
12:03 The bar three y, day three bar height. Okay, it's that one wonderful and
12:08 somewhat terrifying time to save and test.
12:11 My page is saved. Let's go to the browser, and now I'll
12:24 refresh the browser. Alright, let's try out our new bars.
12:29 There's our values changing. Let's say the first day, we go up to six.
12:34 Day two and not much progress, let's go up to a seven.
12:38 And then oh my goodness, can you believe it?
12:41 He's going all the way. No, he stops at 23.
12:43 Still, very good progress. Okay.
12:47 So, let's test it by clicking Refresh again.
12:51 And sometimes, you'll see a slight height change in the bars when you refresh the
12:56 page, as we just did. That's just a rounding adjustment,
12:59 nothing to worry about. Okay, the hard part of the project is done.
13:03 Can I hear a woot? All that's left is a simple function to
13:07 save the complete chart as an image, and we'll tackle that in the next lesson.
13:12
Collapse this transcript
Saving the chart
00:00 The final element to add is a routine to create an image from the merged layers
00:05 and objects of the canvas. Once that image is created, it can be
00:08 saved, emailed, printed out, shared, however the user chooses.
00:12 This function which uses the JavaScript function Add Event Listener, is placed
00:17 within the init stage routine at the very end after stage draw.
00:21 So let's go down there. Stage draw is located on line 250, so
00:28 I'll just put in a comment here, save canvas to image.
00:36 And the first thing we want to do is get the training complete button object.
00:41 So, the code for that is document getElementById.
00:48 And the ID of the button is saveImage. After that dot, addEventListener, parentheses.
00:58 addEventListener takes 3 arguments. The first is the event.
01:04 We're listening for the click event. Next is the function that you want to
01:08 have happen. So, let me enter some function code here.
01:15 And now we're going to use a canvas API function called to data URL.
01:20 So we want to take the entire stage to data URL.
01:24 So stage.toDataURL all cap parenthesis and curly brace then we enter the
01:34 callback parameter followed by a colon. And that is a function passing the data
01:45 URL Notice the difference in the capitalization between to data URL, where
01:51 URL is all capital letters and data url, in the function argument, is just an
01:57 uppercase U. Outside the parentheses, we put a pair of
02:02 curly braces. And what we want to have happen is
02:05 window.open data URL. Close that out with a semicolon and then
02:12 a semicolon to close out the stage to data URL line.
02:19 And we actually want to go in between the last curly brace and the closing
02:25 parentheses there. Put a comma because we have a third
02:29 argument for add Event Listener. The third argument is a boolean, true or
02:35 false, which determines whether to use capture or not.
02:40 The default and the setting we're going to use is false.
02:43 Basically Use Capture determines the firing order if we had multiple, add even
02:50 to listener functions. Okay, that's all the code we need, I'll
02:53 save and go on over to the browser. Let me click Refresh.
02:59 And because we already have our local storage routines in place, our numbers
03:03 stay the same as that additional code is added.
03:07 Now, let's go down to Training Complete. I'll click Training Complete, and there's
03:12 our PNG or PNG file. I can right-click on the image and copy
03:17 it, save it, email it, what-have-you. I want to note that the routine that
03:22 we're using generates a new window which some browsers interpret as a popup.
03:29 To see the image in those browsers, the user would need to allow popups for your
03:33 application site as I've done here.
03:36
Collapse this transcript
Conclusion
Next steps
00:00 Thanks for joining me for HTML5 Projects, Interactive Charts.
00:04 Canvas is such a rich technology that I had to create a number of other HTML5
00:10 project courses to explore it. You can check out all of the available
00:13 titles by visiting my authors page on lynda.com.
00:17
Collapse this transcript


Suggested courses to watch next:


HTML5 Projects: Customized Photo Cards (44m 20s)
Joseph Lowery

Create an Animated Bar Chart with jQuery (39m 36s)
Chris Converse


Are you sure you want to delete this bookmark?

cancel

Bookmark this Tutorial

Name

Description

{0} characters left

Tags

Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading
cancel

bookmark this course

{0} characters left Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading

Error:

go to playlists »

Create new playlist

name:
description:
save cancel

You must be a lynda.com member to watch this video.

Every course in the lynda.com library contains free videos that let you assess the quality of our tutorials before you subscribe—just click on the blue links to watch them. Become a member to access all 104,069 instructional videos.

get started learn more

If you are already an active lynda.com member, please log in to access the lynda.com library.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Access to lynda.com videos

Your organization has a limited access membership to the lynda.com library that allows access to only a specific, limited selection of courses.

You don't have access to this video.

You're logged in as an account administrator, but your membership is not active.

Contact a Training Solutions Advisor at 1 (888) 335-9632.

How to access this video.

If this course is one of your five classes, then your class currently isn't in session.

If you want to watch this video and it is not part of your class, upgrade your membership for unlimited access to the full library of 2,024 courses anytime, anywhere.

learn more upgrade

You can always watch the free content included in every course.

Questions? Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com.

You don't have access to this video.

You're logged in as an account administrator, but your membership is no longer active. You can still access reports and account information.

To reactivate your account, contact a Training Solutions Advisor at 1 1 (888) 335-9632.

Need help accessing this video?

You can't access this video from your master administrator account.

Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com for help accessing this video.

preview image of new course page

Try our new course pages

Explore our redesigned course pages, and tell us about your experience.

If you want to switch back to the old view, change your site preferences from the my account menu.

Try the new pages No, thanks

site feedback

Thanks for signing up.

We’ll send you a confirmation email shortly.


By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

   
submit Lightbox submit clicked