字幕列表 影片播放 列印英文字幕 BRAD GREEN: OK. Welcome everybody. Thanks for coming to the first Angular conference or Angular Meetup here in Mountain View in 2014. So we've got I think a really good start of the year tonight. I've got a couple of announcements, like I always do. Then Victor's going to come up and talk about Angular D3, and Igor will finish up with how will pull requests work in the Angular world. A couple of announcements before we get going. Like always, if you plan to talk, meaning ask a question, and we hope you do, you will need to sign one of the forms that Igor has right back there. And I think we give you a T-shirt if you do such a thing. Is that still true? Yeah. OK. I think that's still true. No pandering questions, just real questions. And I think that's it. With that, we'll get started. So, not a lot of things happened in the world of Angular in 2014, except we got a lot of releases out somehow. Apparently, we don't observe holidays. I think we've never gotten so many releases out as we did between last Meetup and this one. There's a couple of highlights in these four releases. There was 114 pull requests closed. A couple features got in, like we have multi-line NG options now. There's one jqLite feature for element dot one. A ton of performance things went in for injector, resource, compile, parse, broadcast, even in jqLite, some things got faster. And then a ton of bug fixes. A lot of things around IE8, a whole bunch of stuff in the animation bits, and across the rest of Angular. In the world of Angular Dart, we got out two releases. If you haven't been following along, Angular Dart are the ports to the Dart language. And it's kind of just getting started. We're working towards the 1.0 release. Some of the things that we added are getting parity with Angular JS side. So we're still adding a bunch of directives. There's new things that got added there. A lot of performance improvements to make it perform very well on Dart. This is still a bit of a new place for us. And then we have some experimental supports for this thing called shallow-repeat. One other announcement I'd like to make is that we have a conference going on in two days. On the 16th we start in Salt Lake City. Anybody coming there with us? A couple-- Just us. OK. Yes, one over here. Good. Great. So this is for everybody who's not coming. We're actually going to be live streaming the entire conference. You can tune into it live and you can watch me again, and some of the other folks, talk about other interesting things in the world of Angular. So please tune in. I think it starts at 9:00 in the morning, but that's maybe an hour off in Salt Lake time. And I'll see you guys there. One other announcement. If you are interested in Angular on Dart, the Dart team, along with us, we're running this thing called Flight School to get you up and running. So if you want to learn the Dart language and learn about Angular Dart on top of it. This is happening in many cities around the world, and really around the world. If you just search for-- Sorry I don't have a link for it. If you just search for Dart Flight School, you'll find it as the first result. And from Shanghai to Chicago you can find a local place where you can come tune in and learn Angular Dart. That's it for this month's announcements. We'll have Victor come up and talk to us about D3. VICTOR POWELL: Thanks Brad. Can you hear me? You're not supposed to see that. So I'm a freelance data visualization engineer, and I'm giving a talk, if you couldn't tell by the slides, a talk on visualizing data with Angular and D3. Also, all the slides are going to be online after the talk, so we'll pack out the link on the Meetup, so you shouldn't have to worry about taking notes furiously. We're going to be going over a lot. This is sort of the combination of D3 and Angular. So don't worry about that. But before I begin, could I just get a quick show of hands. Who's in some way at all familiar with Angular? And don't be shy if you're not. It's totally fine, because this is the cross-pollination of Meetups from the E3 [INAUDIBLE] area. OK, keep your hands up, though. Keep your hands up. Now, anyone that doesn't have their hand up, look at the person that does have their hand up and talk to them. But it's a good turnout. Nice hand raising for a D-- Not surprising for an Angular Meetup. Now anyone that has some familiarity with D3 go ahead and raise your hand. Cool. Now, if you're not familiar with D3, that's fine. Find someone who is and talk to them, shake their hand, say hello. OK, now we're going to get into the talk. So little about me, because I think it's important for you to know a little bit about who I am so you'll pay attention. You'll know why to listen in the first place. I visualize data, obviously. As a freelance developer, I've most recently worked with a company called Monsoon to help them build a dashboard for Hewlett Packard that helps them analyze their data center energy consumption across all of their data centers. I teach at a hacker school in San Francisco called Hack Reactor. We actually have a few students here today-- former students, not current students. Some of those, actually. OK. So I also really like to explain things. This is a visualization of the central limit theorem I did a while back. Here's also an explanation of the Monte Hall problem. If you're not familiar, you should Google it and find this explanation, and it'll tell you what it is and why it's interesting. Also, the Simpson's paradox, which is a really interesting statistical anomaly-- I'm not going to get too much into details because it'll probably just confuse you, but if you read this, hopefully you won't be confused anymore. I'm sorry. A lot of these data visualizations I've also done with my good friend Lewis-- he's here today. Lewis Lehe, or Le-- you don't pronounce the H-E. I'm also writing a book with Ari Lerner, who is in charge of ng-newsletter, or puts together ng-newsletter. And he's also written the book, the ng-book. This book is still in a peer release state, so it's not done completely, but if you buy it now you'll get a discount over the release price. And if you need help understanding your data, send me an email and maybe I can help, or the duo combination of me and Lewis. So no more ads. Let's start to get into the good parts. So just to give you a high level view, this talk's going to be on why and how you should use Angular and D3 for doing data visualizations. Before we do that, though, let's talk a little about why you should care about data visualization in the first place. And to do that, I'd like to show you one of my most favorite examples, Anscombe's quartet. This is a series of four data sets with x and y values for each. As a table it's kind of hard to understand, so maybe as a good idea, let's look at the summary statistics of that data set. But when we do that, unfortunately, they all happen to have exactly the same summary statistics. How is that possible? That's so frustrating. The mean of x and variance of x, the mean of y, the variance of y, correlation of x and y, and the linear regression is exactly the same. And if we just look at the summary statistics, that's very confusing, because all the data seem somewhat different. But it becomes immediately apparent when we visualize the data, and we can see clearly that the data sets represent completely different behavior. So, OK, we understand why data visualization is important, but why use Angular for doing data visualization? Chief among them all are directives. For those not familiar with directives, give us essentially custom HTML tags. It also allows our visualizations to stay modular and self-contained so that we can pick them up and drop them in to some other application fairly easily. But there's more reasons than just directives for doing data visualization. Some of those we'll get into, but for the most part it's directives. I like to think of directives as input fields. They're kind of like directives that the browser gives us automatically. They're not actual directives in an Angular sense. But they are like directives in that they encapsulate a lot of behavior and we're given a simple API to plug into them. So the one example right here is the range input. And I specify the min and the maximum value, and then the current value. And then it, the browser, handles creating the slider, and the knob, and watching for changes to that knob, and updating the value for me. I don't have to worry about the internals of that slider. It's just an input range. Same thing for the date input field. There's really a lot of complex user interaction here that the browser gives us for free, but it abstracts away all those concerns for us. Well, wouldn't it be nice if we could have something like a donut chart element, and then we wouldn't have to worry about the internals. We could just plug our data into it, and not have to, after having created our element, not have to worry about how it does all that it does. Well, directives make this possible. Beyond directives, some of the other interesting features that Angular gives us when we have our visualizations and directives are things like ng-switch for conditional templating. So let's say, for example, based on some criteria, we would like a pie chart to be displayed with our data, but maybe in some other condition we'd like a bar chart to be there instead. Another really great feature of Angular that blends well, that makes data visualization a lot easier is ng-repeat. Small multiples is this idea, a powerful data visualization tool, originally popularized by Edward Tufte, and it facilitates the comparisons of change across multiple charts side by side. So this is a classic example of-- I'm sorry-- of small multiples by Eadweard Muybridge, and it's called a Horse in Motion. You might be wondering, though, why can't we just use animation? Why can't we just play a video of a horse running? Wouldn't that convey all the information? Well, it turns out-- I'm sorry, here's a little graphic I forgot to show. Why can't we just have this? Well, there's a few limitations to this video. For one, we're stuck in the frame of the playback of the video. But say, as was the case in this original example, the horse is running so fast that we actually can't see whether or not it's lifting its legs up, or if all of its legs are in the air at the same time, which was the original bet between the two people that generated this visualization in the first place. But another drawback is that we're stuck to only getting an additional dimension, but with small multiples we can go over columns and rows to get an extra two dimensions of data. So take this example from Andrew Gelman, which would be impossible with simple animation. It shows support for school vouchers by race, income, and state. And we can really see some really interesting insights, if you look down towards the bottom. People with low income-- Sorry. Let me backtrack a little bit. Not surprisingly, rich, white people really like school vouchers. But surprisingly, so do poor blacks and Hispanics. Whereas, white evangelicals and white non-religions of low to medium economic status are the ones who oppose it. So the map itself only has two dimensions of information, but the whole visualization achieves four levels of dimensions, it's four dimensions of data, by repeating the graphic along the rows and columns. So this is actually really easy with Angular, just by using the ng-repeat. So this is a simple example of a chart, of iterating over several charts, and then creating the donut chart directive for all the charts that we have on our scope. We can even put ng-repeats inside of ng-repeats. Yo dog. Because no one ever made that joke at a program unit before. So I have a little demo of that. Hopefully it'll load. It did not in your window, it loaded in mine. So here's the visualization. It's life expectancy by sex, race, and state. And I'm just using the same Mac directive for all of those elements. Let me see if I can show you the Dom for this. The window is very tight. So this ends up being what the actual Dom looks like after Angular has gone and done its dirty work. And for every one of these ng-repeats there's an inner ng-repeat that iterates through all of the different columns. This example is also in the slide, so if you're interested in seeing more about how, in fact, this visualization was generated, just pull the slides after the talk. Also with Angular, it makes it pretty easy to do responsive design, which is useful just for web development in general. But is very handy, specifically for data visualizations. I'll reload this demo. And you can see that as I resize the window, the graph inside of it is changing dynamically in response to the changes in the window. Again, that demo is available in the slides repository. Another really great thing about Angular is it makes it easy to do interactivity, basically to hook up different visualizations so that they represent or are connected in some way. And so here is the previous example I showed you earlier that me and Lewis built to explain the Simpson's paradox. And see, when we drag the sliders, the table of bar charts and donut charts updates accordingly. And without Angular, this would be rather tedious. There's also another more involved example of interactivity across visualizations. This is the demo application you would need if you were creating a video game and you wanted to have non-playable characters. You could then add or remove certain attributes, in our case, web strength, speed, and agility for each of the different characters. So here I'll add a non-playable character, and that shows up down at the bottom. But so does its average appear at the top. And I can add multiple different characters, and it will affect the average. So if I click on one of the attributes, you'll see the averages above, updating accordingly. Or I could change the min and max of the different attributes. Or I could add additional attributes. And again, because Angular makes responsive design a lot easier, and rescale this window, and the radar charts will update accordingly. So I just have one radar chart directive that I'm using across all the different characters, and also in the averages. So I hope I've sufficiently convinced you to use directives when doing data visualization. And so, the next part of this talk will actually be us going through and taking an existing donut chart in D3 and converting it to an Angular directive. Before I do that, just for those in the room that may not be as familiar with D3, I'm just going to go through 1,000 foot view of what D3 is and why you would want to use it, pretty quickly. But just to get you motivated for learning more about it. Essentially, D3 is a way for you to manipulate the Dom based on data. That's where it gets its name, Data Driven Documents. So if we wanted to, say, add or remove different Dom elements that corresponded to pie chart heights, it would be very easy to do that in D3. D3's also very similar to jQuery in its syntax and the way it works, but it adds a lot of functionality that you would specifically need for doing data visualization. I also like to think of D3 of just being a collection of helper functions that make it easier to do data visualization. It's almost sort of like a meta library that you can use to create your own visualizations. It's not something you would use as just a way to include a bar chart or pie chart. It's really more for people wanting to create their own visualizations, not from some cookie cutter template. So just to give you an example of some of flexibility and power of D3, here's a really contrived example of just some data, the values 20, 50 and 80. I then select the body, kind of like in jQuery. I also select divs that don't exist yet. This is kind of the magic of D3. And then I pen divs for every one of the elements in the data and then set its width attribute to the value in the data. And this is what a Dom ends up looking like. There's three Dom elements, each of them have widths, 20%, 50% and 80%. So here's just a quick demo of that code, and the three different div bar charts. Another great thing about D3 is its collection of these sort of helper functions, and one in particular that I'll just skim over briefly because we'll be using it later, is the D3 layout pie generator. And so with it we can take data, create a generator, a pie generator, and then path our data to that pie generator, and it will give us all of the start and end angles that would create a donut chart. This is the code that would actually go and take that data, that pie chart data, and create the necessary SVG paths. And SVG is just another-- It's just like the Dom. I'm not going to get into for now, but just think about it like any other Dom components you'd like to manipulate. And we'll set some styles and I'll pull out the demo. And there it is. It's in the upper right-hand corner, so that's no good. So we'll have to translate it by some amount, so it's in the center, or so it just is not in the upper right-hand corner anymore. And there it is, and there's our donut chart. So we'll be using that code later on to create our directive. But just to give you some quick links, so if you want to pull it down, these slides later, and just learn more about how these work. There's an SVG primer, A Good SVG Primer, by Scott Murray. Let's Make a Bar Chart, by Mike Bostock. And Thinking with Joins, also by Mike Bostock. And I'll explain some of the magic that I went through earlier. So now we're really going to get into creating a directive. So I'm actually going to hop out of this mirrored mode. And so you'll be seeing what I see. So there's a donut chart, very similar like what we had before, except now we're giving it some color. We're also dynamically changing its size, depending on its container. In this case, it's just a div, but it's not responsive yet. So we'd like it to be in a directive. So how do we about doing that? Well, the first step, obviously, is we need to include Angular. After that, we'll also need to create our app. Give it a name. And it won't have any dependencies. We also need to tell Angular where our app begins, and also create our directive. And so we want it to be called donut chart, or donut.chart, but we have to specify donut, capital C, Chart. And the directive also needs to return an object that has on it a link function. And this link function you can think of as an constructor. It will be called for every time you press the stamp down to create new donut chart. And that gets called with few arguments-- scope, the elements, type it out, but really we're just going to call it EL for now. And attr, we won't worry about that for now, either. So I just want to test and make sure that everything's wired up correctly. Just do that. I'm going to add an SVG to the element inside of the directives, sort of the containing element. This'll be called donut chart. Element we access just like in jQuery, since it's sort of a jQuery wrapped object. It's not exactly jQuery, but it's like a jQuery wrapped object. So we'll need some way to reference that element directly. And then use D3 to select it, and then a penned and SVG to it. Oop. But we should comment out our D3 code first. Ah, but there's nothing there. That's because we don't actually have a donut chart element. Oh, but that doesn't work either. We actually need to specify to Angular that we'd like our directive to look like this. But this will be the type of directive that we'll be using. It will be donut-chart. Obviously, there was nothing there before, because we're just adding SVG. But now the SVG is inside of our donut chart element. I hope you all can see this. So great. Now we have everything we need to be able to just plug in our D3 code right inside of our directive to have what we had before. But instead of selecting the div directly on the Dom, we'll just pass the element to D3. Actually, we don't even need to do that. We'll just do EL equals EL0. But our width and height is zero, so why is that-- Oh, it's because we have absolute-- Oh, because we're not actually selecting our donut chart within our CSS. We're selecting a CSS class called donut chart. We're not actually selecting an element called donut chart. So we'll need to change the CSS. And there's our donut chart, inside of our directive. So already, we can now reuse that donut chart. So instead of giving it a width and height of 100% by 100%, I'll just give it 100 for now, and tell it to display like a block in block style. And then we'll add another donut chart. Great. So now we have two donut charts inside of Angular. But there's a problem. We have our data inside of our directive, and that's just not good. Because every time we create a donut chart, we don't want to always have that same data. We like to be able to configure our donut charts so it can have different data. Something like this would be really nice. The better example, maybe 10 and 3. It's hard to come up with random numbers on the spot. So that's actually a really easy change. We could just use scope.data to reference the data scoped variable on the donut chart. But there's one small little change we have to make to the object that we returned from our directive, and that is we have tell Angular that our directive will be receiving a property on its scope called data. Oops, that's not right. So there you have it. We'll make it a little bit bigger. Whoa. Maybe too big. So great. Now what would be really cool, though, if our donut chart was responsive so that we could resize the window, or we wouldn't have to always resize the window for the donut chart to fill the space. So let's actually change the CSS back to be 100% by 100%. Actually, I'm going to backtrack just a little bit. Instead of doing that, let's actually talk a little bit about ng-repeat, which is what I was talking about earlier, and it makes small multiples really easy. So let's throw an ng-repeat inside of here and see if that works. Also, set charts on the outer scope to be something like some array of data within another array of data. So now we have this array of arrays called charts, and we'll iterate through it instead of ng-repeat for all the different donut charts. And we'll pass chart to the data property of our donut chart directive. Sweet. So we have these two charts. Also, I just want to talk a little bit about using controller. Generally, you don't want to actually be putting all your data right in the Dom, although it does really make it easy to quickly create data visualization. We'll, right now, go through the process of creating a controller. We'll call it donut chart controller. I think that's long enough of a name. Also have it use the scope, and we'll create something on the scope called charts that it will use to pull the charts from. So we're no longer stuck inside of HTML world that's sticking with expressions. Angular allows, now we can actually throw in Vanilla JavaScript objects and code. So I'll be using D3 inside of here to create an array of 10 charts. Inside of each of those charts, each of those charts will have 10 elements of random data. This all right? OK. Sweet. Now we've got all these charts. They've all got their own random data. I'll also make these a little smaller. Cool. Maybe give them 100. Cool. So we're on a pretty good roll here. But now, wouldn't it be cool if actually all of our donut charts were responsive, so that whenever we resize the page, all the donut charts would update accordingly, and there would only always be, say, 10 donut charts on the line. So to do that first, we'll need ng-style, and this basically allows us to dynamically apply styles to our directives. Wow. maybe not 100. We'll just say 10 for now. OK, cool. And that's not so bad, but it's not great either. We'd really like it if they would all change their size, too, whenever we resize the window. Also change these to be percentages. So we need our directive to update in some way, whenever it's containing width and height changes. So to do that, we'll need to do scope.watch, and then give it a function that returns the width and height of the containing element. And whenever the return value inside of here changes, the second callback will be fired. And so this will handle resizing our donut chart. I see some closed eyes. What's up? Ah, where? Width, client, height. Thank you. Good call. So yeah, so inside of here we'll do everything that we'll need to change whenever the client width and height changes. We'll also need to update the width and height to be those new values. And now, we'll also need to take all the things in our donut chart that depend on the width and height and put them now inside of this callback, because all those things will need to be updated when the width and height changes. So just going down from the top it looks like min also depends on width and height. And the arc, the arc's inner and outer radius also depends on min, which in return, depends on width and height. It also looks like the SVG needs to be updated when the width and height changes. And also, this inner group that will translate the donut chart into the center needs to be updated whenever the width and height changes. So we'll give that a name right now. We'll call it G, and update it instead, inside of the scope.watch when with width and height changes. So I think that's everything. Whoa. What did we forget? Oh. So whenever it first loads, it looks like they're all set to 100 by 100. But the client width and height changes, and we never get those updates whenever it happens. So we actually need to also tell Angular, hey, the window resized. Someone resized the window. Go check if anything on the scope changed and run all of those associated watches for the client, width and height. So that's actually a simple fix. We can just do scope-- inside of the controller, we can do scope.-- Not scope. You can have it depend on the window, and watch for resize events on the window, and tell Angular, hey, check for changes. Whoa. How's the method on? Oh. So we forgot to wrap our window inside of the sort of Angular version of jQuery, and to do that we'll have to do Angular.element. Ah. There we go. So it's kind of working, but still, the radiis are not updating. So actually, we also forgot to apply the arc to the path. That was the other thing, that depended on something that depended on the width and height. So the arc depended on a min-- I'm sorry, the arc path depended on the arc generator, the arc generator depended on min, min depended on width and height. So we'll need to actually take that, you see this right here, and add it to our watch for the client, width and height. Also need to give it a name, if it doesn't have one yet. Cool. Now we have dynamically resized, responsive donut charts in Angular. [APPLAUSE] So the next thing you probably might want to do is have your data update. Maybe we're getting a live feed from some data source and we'd like the donut chart to always be adjusting or adding new data points. Well, to do that, we'll first need the arc function. And I've included the reference to Mike Bostock's original demo, which describes how this works. But for now, don't so much worry about the details. Just know that it will be responsible for transitioning our arc paths from one configuration to another. You also need to watch for changes to the data, and that's what this does. Any time the data changes, this functional will run. And in it, the arcs will be transitioned in or out, and so for arcs.enter, all of this will happen when there's more data in a pie chart than there was before. Similarly, for arcs.exit, all of this will run whenever there's less data in the donut chart than there was before. And these will be run for any past data pairs that will remain in the chart between the transitions. So that's good. But we also need some way to sort of test our little demo. We need some way for the data to update inside of the directive. So for that to happen, I just have this little snippet here. So any time anyone clicks on the SVG run, enter the Angular world, essentially saying, hey, after I do all these things inside of here, check for changes on the scope. And in this case, we'll be changing the data on the directive. Just some random new data. Oh. That didn't work. Why did it not work? Do we have an error. Ah. So I forgot to-- since now the piece of code that is responsible for adding or removing arc paths is inside of scope.watch data, we need to make sure that we don't do any of that outside of it. So, in this case, we have these arcs, this arc selector, and we're binding the data, when it really is not responsible for it outside of the scope.watch data. So I'll just remove it. And it may be somewhere else, but I think that's good. Sweet. So now we have these transitioning donut charts. They start out with no data, they get data, they animate in, and they look awesome because they're animated. People love things that move. So now, wouldn't it be cool if, for whatever reason, we wanted all of these donut charts to share the same data. We wanted it so that when clicking on one-- well, actually, let's press the test if we can click on one and update it. We haven't done that yet. So I can click on one donut chart. Its data is being updated from the code that I've just added. Every time I click, scope.data is being set to some new value. Whoa. That kind of looks cooler. So yeah, we would like the data to be shared, so just as a contrived example, I'll just add some new variable to the scope. I'll call it Our Data and just copy what we had up here. I'm creating a chart. And now they'll all just use that same shared object, Our Data. Sweet. They all have the same data. When I click on one, they all-- oh, they don't all update. So this is sort of a gotcha when using ng-repeat. ng-repeat will create a new scope for all of your different directives that use the ng-repeat. So if you're familiar with object-oriented programming, particularly in JavaScript using the prototype chain, if you have an object that is an instance of some parent class, if you set a variable on it to some new value, that property will be that new value, and it will not overwrite the parent. And that's exactly what's happening here. We need some way to prevent our data from being overwritten on the scope for the parent property. And so one trick to do that is to just use sort of a shared object, an additional object on the parent scope that will never get overwritten by us, on any of the child scopes. Also, you need to update it in our directive. Oh no. The worst error is no error at all. I called it charts now. Ah. I don't have it called charts. I deleted this. They had this up here. Charts, actually, will still be on the scope. Oh no. The demo gods will not allow. I'll just chart our Our Data. I'll leave that there for now. Our Data. Sweet. So now they all share the same data, so when I click on one, it'll be updated across all the donut charts, or however many we decide to have. Maybe we'll make them 140 high, and give them 100 of them. Whoa. So that concludes the talk. I went over a lot, so if you feel confused, that's OK. As long as you feel compelled to now combine D3 and Angular, I'm happy. I guess now, let me close and go back to my slides, if I can find them. So now it's time for Q&A, if anyone has any questions. Is now a good time for QA by the way? OK, what, I'm sorry. AUDIENCE: [INAUDIBLE]? VICTOR POWELL: So it's on GitHub if that's what you mean. It'll be after the talk. You can download all the demos and the ones we went over. AUDIENCE: [INAUDIBLE]? VICTOR POWELL: Oh yeah, I'm sorry. To repeat the question he asked-- Oh, I don't need the mic. Just to repeat the question, can I put up some of these directives on GitHub? They will all be available online after the talk. You can go and fork the repo or make contributions. I know that some people have been talking about putting together more comprehensive, a collection of Angular and D3 directives, and there are actually some already-- Brian, actually, put together a great tutorial that walks through all of this. But there are alternatives like Dangle-- I think Dangle, is that the right-- But I think a lot can be done, and a lot of improvement can be made. So I mean I don't know if I could stand up and volunteer to do that, but I definitely think there's a lot of value that could be added from doing that. Next question. AUDIENCE: So there appears to be some overlap between what Angular can do and what D3 does. So, for example, I saw the bar of the code that was in the link function was creating elements in the Dom and applying style to them. And [INAUDIBLE] attributes. And it appears to me that part of that can be created in Angular templates, but we can add those repeated G elements inside the template. So is it stuff that's been tried are the advantages of this [INAUDIBLE] to do that? VICTOR POWELL: --indicated doing so. I mean there's a million ways to skin a cat, as the cliche goes. If that's a cliche. I don't know. I prefer to use D3. It's where I have already a lot of domain experience, and I'd like to continue using it. But that's not to say it's the only way. But I don't think D3 will be able to be removed from the equation completely, because I think it adds so much in terms of additional functionality, helper functions that transform your data in a very convenient way. BRAD GREEN: Victor, we're actually going to hold off on Q&A and do a couple of lightening talks, and then do Q&A with you, Brian, Igor at the end. So Brian's going to come up, and I think he's talking about dependency injection. Is that right? So he'll be really quick, like lightening. Look how fast he's walking. He's already lightening. BRIAN FORD: Just a minute. So I'm Brian. I work at Google on the Angular team, and I'm giving a short talk about-- So this is going to be a really, really short talk. OK. So Angular uses DI, and one of the cool things that you can do in DI, or Dependency Injection, that you can get a hold of some components and then modify it and put it back in the system and let Angular do its thing with it. So here I have a really boring Angular app. It's just two forms, and it cotinates together, their output. But what we can do is we can use this configure function of an Angular module. We can ask for a dollar provide, and dollar provide has this method decorator where you can ask for a scope-- or sorry. You can ask for some service, so we can answer for, for instance, the root scope. It gives us this function where whatever we return back, Angular will use as the root scope. So what happens here is dollar delegate is root scope. They're equal. And we can now change root scope somehow. So what I'm going to do is I have this little helper function that I wrote down here called timerify. This takes a function and returns a new function that first starts the timer, then runs the original function, then stops the timer, and then logs the amount of time it took to do whatever it was that the original function was doing. So using this, we can actually time dollar apply on the root scope, and we can see how long the digest cycle takes, in effect. So let's see what this actually looks like here. So if I refresh this, we see 10 milliseconds, type stuff in. Angular's pretty fast. So that's kind of cool. And this is actually the same trick that battering, the Angular debugger extension uses to get into Angular internals and mess around with it. So that's actually the whole talk, the code and the short explanation is on GitHub, btford/-- Brian talks about decorators, doesn't he in the repo? And that's it. [APPLAUSE] IGOR MINAR: So hi everybody. My name is Igor. I'm from the Angular team. And what I would like to talk to you about is about the process we use to handle PRs, and kind of demystify what is happening when you send us a PR, and how is it being handled. So you work on the Angular application, and unfortunately, you come across a bug. Maybe it looks uglier than this one, or in a better case, you have an idea on how to make Angular better. Way better. And naturally, you go to GitHub, and what you notice there is that Octocat has only five legs. Like I drew eight, because I thought Octocat, eight, but it has only five. Go to GitHub and check it. You fork the project, you craft your change, and you send us a PR. And then you notice that the PR lands in our queue, and there is like a million other PRs there. And you start to wonder what's going on. Do these people handle those PRs? Does anybody ever look at them? Well, the good news is that we are looking at them. But there are so many of them that we have to develop the process on how to handle them. And I'm going to talk to you about this process a little bit. So step one of the process is you sending us the PR. We covered this already. The PR lands in our queue and there's a brand new shiny PR. The next step is triage. So what we do is once a day, we sit around a table and all of us just hammer on GitHub and look at the new stuff that just showed up, all the new issues, all the comments, all the PRs, and try to triage them. During the triage, we review things. We try to reproduce bugs or try to reproduce the bugs you're trying to fix. Label things into categories so that we have a better understanding of what is it that you're trying to do, and what the change is about. And then we move things to milestones, just so that we schedule when we're going to deal with this. What these milestones are? Well, ideally we try to merge things instantly. But it's not that common that the change is ready to be instantly merged. And it's going to be obvious why in a little bit. So it's more common that if it's an important backfix, we schedule it for the current iteration or for the next iteration. Otherwise, it goes into a midterm milestone, which we pull things out during our iteration planning. If we don't have enough information about what is it that you are trying to do, or if it's an issue and it's not clear what the issue is, we have a milestone called purgatory in which we try to gather more information before we decide what to do with the issue. If the pull request is trying to do something that we are not interested in just yet, and we know that it's going to take a lot of work to get it into the master, we put into ice box. And hopefully, we'll some time get to it. I'm not sure when, but we have this milestone because we try not to reject PRs that seem to be valid, but they are just not quite there yet and won't be for a long time. So Pro tip number one. If you are sending us a PR, aim for instant merge. What does this mean? Ideally, it should be a backfix. It should be a small change with good test coverage. You should sign the CLA. There is a script that bugs you if you don't sign the CLA, and the CLA process is super simple. And it should be obviously what you are trying to fix. Write a good description, write a good comment message. These are the best changes that we can easily get into master. If we can do an instant merge, then during iteration planning we schedule the PR to be handled during the week. And during the week we review it more thoroughly. We provide more feedback on what is it that it needs. And either wait for you to make the changes, or we make changes ourselves and merge the change in. This is done after all of our check boxes are checked. The tests have to be there, the documentation needs to be updated if necessary. We need the CLA, and many other things. All of these requirements are upline in the contributing documents. So this is on GitHub contributing.md. You can check it out. Pro tip number two. If you're making a big change and you're going to spend a lot of time crafting this PR, please open an issue first. This will allow us to look at it and give you instant feedback, if it even makes sense to send us a PR. Often people send us PRs, and they don't belong to the core. We want the core to stay focused on the things that only core can provide, and all this nice-to-have features, we provided it through extra modules. So, if you have something in mind and you know that it's going to take a lot of time, create an issue first. Step four, done. At least you think you're done, but the PR is far from being done. Step four is actually continuous integration. By now, we ran your tests already, because Travis-- we have this set up with Travis that will run the tests whenever you submit the PR. But once we merge, we run the test one more time just to send it and make sure that everything's OK, no tests are being broken. We actually currently run two set ups. We have Jenkins on our own CI server. And we have Travis with [INAUDIBLE] Labs that seems-- like that's something that we're trying to completely migrate to. But it's a complicated set up, and to right now, we run both just to be sure that we are not without the CI server. But hopefully, everything's going to go well. And we get step five, continuous delivery. Not many people know about this. But what happens is when the change gets merged into master, we create a build and we push the changes to the recommendation side. So if you are making changes to the documentation, those changes will be available right after the change is merged. We want this so that people can benefit from documentation changes as soon as they land in master, so that they don't have to wait for a release. Another thing that we also do is once a build is created, we push it to bower. We want people to start using the bleeding edge of Angular more, and that's why we push to bower after every comment. So every comment that lands in master, we create a build out of it, we push it to bower with a pre-release [INAUDIBLE] version, and you can fetch it very easily and start using it. This is not as crazy as it sounds because this is what we do at Google already. We take every comment that lands in master, we sync it into Google, and we run it against all of the applications that use Angular at Google. This gives us very fast feedback on whether there is a breaking change, or basically, if everything's fine. And if everything is fine, then we sync this change into the internal repository, where within a few hours, all of applications will pick it up and will start to use it, some even in production. Pro tip number three. Aim for greatest coverage. The sooner we can discover issues, the sooner we can fix them and can avoid issues in a later phase, which would mean like we wouldn't have to revert the comment, or fight those fires. So if we have a good coverage for all of the changes, this can avoid a lot of hassle later in the process. Pro tip number four. Be mindful of breaking changes. Like during stable releases, we really don't want breaking changes. And if we see that something has a breaking change, it's not going to make it in. We have an unstable branch which will be opening for 1 to 3 very soon. And we have a process for handling these breaking changes. But most commonly, we just don't want breaking changes. Step number six is at release. During the release, we generate a change log. And the way we generate it, we take the comment messages that landed in-- from comments that land in master, and we have a script that will just generate it. This is why we have this pretty strict format for the comment messages, so that we can just generate the change log, because otherwise, it's so much hassle to create release notes for every release, especially if we are trying to release once a week. Pro tip number five. When you write a comment message, write it in a way that you would love to read it, or you would love others to read it. This means describe the fix or the issue that you are doing. If it's a feature, make sure you describe what it does. But provide more in-depth explanation probably in the documentation that is associated with the PR. Next thing we do is we push the bits to code AngularJS. This is just an archive. It's not a CDN. I often see people use the code AngularJS in flunkers and and JS fiddles. Use the CDN URL better. This is really meant just for an archive, and it's not a CDN, but it contains all the artifacts, including the documentation. So if you want to see what the documentation looks like at some version, you can go there and see it. Next what we do is we take all the build artifacts and push them to bower, this time with the proper release versions so that you get whatever Angular 1 through 9, or whatever it is that we are releasing. And we also push the artifacts to Google CDN so that you can get them to clients as soon as possible. We have Angular-seed. We push the bits in there, and we have the tutorial which we keep up-to-day, so we also update that on every release. And that's it. Like now your PR is in Angular, it made it better, and we are very thankful. And we are hoping that you're going to send us more PRs that are really high quality. Thank you. [APPLAUSE] So I think we're going do Q&A now, right? And one more announcement. We have a bunch of food left over, and we have boxes, so if you want to take some food home, feel free to take some. Yeah, we'll take questions now. Victor and Brian. Sorry. AUDIENCE: Hey, thanks for all the talks guys. Quick question for Brian. Can I use your decorator for route provider and do something on [INAUDIBLE] change? Get a hold of providers, can you? IGOR MINAR: Get hold of providers, no. The providers are available only during the run phase. But for run changes, we have events. You can listen on run, change, start event, and just handle whatever you need to do there. AUDIENCE: This is in line with my question from last Meetup. On every oil change I want to select kill all the Ajax sequence from the previous page, and kill the timers, and all that. So I was wondering if this could be just a decorator that no one else has to-- BRIAN FORD: Oh, OK. Oh. AUDIENCE: Well, I'll continue with the events. But I was hoping this was handled without anyone else having to do anything. Thank you. AUDIENCE: [INAUDIBLE]. I just want you if there is a couple more ways to make sure what I'm doing is sufficient. More often than not, I see that I put a console log statement, I see too many things coming up late. Am I doing something might reduce efficiency or something? BRIAN FORD: Often, when you're trying to debug something, you see-- AUDIENCE: Yeah, let's say, for example, I was writing a validation event, and then I see that-- Yeah. Is it watching on too many changes or no? BRIAN FORD: We are working on better tools to answer that. I agree, right now it's not easy to diagnosis, for instance, why is something slow. We're working on it. And you can use techniques like that to count how many times. You wouldn't use-- decorator is more like of like a system. This you would probably want [INAUDIBLE]. Louder? There we go. I'll just steal this. So if you want to answer the question of is a specific watcher slow, you could use a similar technique where you're instrumenting the function and adding, and stopping a timer. But this technique of using decorator is more for like system-wide changes. Like if you want to change something in the entire DI system inside of Angular. Right now, it's perhaps a little bit hard to kind of drill down and decide which things are useful. But we're working on better tools for that as well. AUDIENCE: Thanks. BRIAN FORD: Sure. AUDIENCE: My question's about D3. So donut chart is really cool, and you can make as many donut charts as you want, and you can resize them. What is your preferred method for testing your D3 directives, because they can overlap, they might not update with data. A lot of things could happen to them. VICTOR POWELL: That's a good question, and it's a hard one to answer, but currently my CI environment is my eyeballs. For UI, it's very hard to come up with good testing, in my opinion. Maybe there could be better tools or better tools that I could become more aware of. But it's easier for me to just get immediate feedback just from seeing if it works or it doesn't. IGOR MINAR: I came across an interesting tool called Huxley, which is a web driver-based testing framework. And what it does, it take screenshots and compares them, so that you can use that for testing UI stuff. And actually, like it sounds crazy, but the more I think about it, it's pretty cool. Like Huxley, check it out. Huxley, yeah. I think it's done by Facebook. BRIAN FORD: So it's pretty easy to test to things like does this have a given width or height or some certain property. But really, if you want to test that something doesn't overlap or something that really looks like that, tools that take screenshots and [INAUDIBLE] them, or really, I think, the only-- AUDIENCE: Well, the way this tool works is that you take a screenshot that you're happy with, and then you take it every time you make changes. BRIAN FORD: Right. Yeah, precisely. AUDIENCE: And when there is a change that doesn't match the original screenshot, then it's something that you should look at. And the new updates of the screenshot's a part of the review process. So check it out. It's pretty cool. BRIAN FORD: I've seen it. And there are similar tools, though, like it's not a new idea. But you can do something like that in your CI environment. So that way you still would catch those sort of regressions. AUDIENCE: Huxley, yeah, with H. AUDIENCE: A question about data feeds. I'm still kind of new to Angular, and one thing that I learned early on is this idea of a promise, where basically you've got some data out there and it'll come sooner or later. Should I use Angular functionality to deal with data that might be coming sooner or later, or should I rely maybe more on D3, assuming D3 has that functionality to deal with data which might be coming sooner or later. BRIAN FORD: Or never. AUDIENCE: Or never. IGOR MINAR: I don't know. I don't know if D3 has promises. VICTOR POWELL: Mostly, that's an issue of getting your data before it goes into the visualization. And even though D3 does offer a suite of utilities for making that easier, like D3.CSV and TSV, I would recommend pulling all of your data in through a service, and then using that inside the controller, and then setting the data you got from the service on the controller, on the scope, and then your D3 directives will just plug into that. So your D3 directives shouldn't care where they're getting their data. Just that they have data. AUDIENCE: OK. Thanks. AUDIENCE: This is a question for Victor. Your comment about there's many ways to skin a cat. Just thinking that I'm more familiar with Angular than D3, but it's clear that there is overlap in the kind of binding area and things like that. And you said you came from your domain-specific kind of knowledge, that you went more with the D3 route. Have you run across anything where maybe in blending the two together it overrode your domain dominant mode of working, where you found, perhaps, for stylistic or performance reasons there was a good reason to change the way that you were working? VICTOR POWELL: I haven't really run into too many issues like that. I feel as long as you do a, if you're very explicit about keeping the boundaries, that whatever goes inside of your directive, your visualization directive should only be related to D3, then you don't really have to worry about them clashing too heavily. AUDIENCE: And again, just more on D3. Did you look at other things that are out there, or how do you compare it to other things that are out there, and why D3 versus-- VICTOR POWELL: So the good thing about all of what I just showed you is that you can replace the D3 parts with whatever you'd like. You could manipulate the Dom directly if you really wanted to, but I would advise against it, and instead using a library like D3. But it's not the only one out there that does what it does. So you're free to use whatever you'd like. My personal bias is towards D3. AUDIENCE: Why? VICTOR POWELL: Just because with D3 I can write less code, and code that I can come back to later and have a pretty good understanding of what I wrote earlier. BRIAN FORD: I would say one thing that I think D3 does better than similar like SVG libraries is that it has concepts that compose together well. Whereas other libraries are more draw me a bar chart. D3 gives you kind of these different layouts and these things and lets you build up something complicated out of smaller parts. VICTOR POWELL: I like to think about it as a meta library. I wouldn't use it to just give you an existing bar chart. You would-- [AUDIO DROP] AUDIENCE: So I have a question for Victor. I was wondering, I'm a big fan of D3, but have you found any limitations in using Angular for D3? And then my second question is using Angular, do you still find it's necessary to use NVD3 to have it modularized? VICTOR POWELL: Can you say that again? AUDIENCE: So have you found any limitations with using D3? So did you have the full suite of D3 library available to you? And then second question is there's NVD3 JS, which makes it so that you can modularize your D3. Do you find that Angular allows you the ability to modularize without the need of NVD3? VICTOR POWELL: I would say-- I don't actually have a whole lot of experience with NVD3. I prefer to have more flexibility, so I tend to avoid libraries, like NVD3, or what have you, or any other sort of collection of existing D3 libraries. When I want to use D3, it's not because I need a bar chart or pie chart. It's because I want to do something that hasn't been done yet. So it's not really a problem I can address. Coming back to Angular running into limitations, I mean I haven't really run into any major gotchas, except for the scope with ng-repeat that I mentioned earlier. I'm sure there are other areas. I haven't fully exhausted every possible combination of D3 and Angular, though. So there's probably those gotchas out there that I have yet to come across. AUDIENCE: I have a question about-- here-- the question is about Angular is about manipulating Dom structures, and D3 is also manipulating, but it's inside SVG. Have you ever tried to use Angular markups inside the SVG markup so that it can directly driven by the binding or the brackets inside SVG? VICTOR POWELL: Well, first off, I want to clarify that D3 is not only just for manipulating SVGs, even though that is commonly used with SVG. To address your second question, that was like the comment that was asked earlier at the end of the talk. There are other ways of creating data visualizations, but I think there is always going to be at least some need for D3 along the way. Maybe in the future, the features that D3 provide wouldn't be in some monolithic single framework as it is now. You can already do this in some extent when you compile it on your own. You could pick out the features you're interested in. But it does more than just manipulating the Dom. It gives you a whole suite of tools for manipulating data that are useful in data visualizations. AUDIENCE: So That is actually, it is possible directly using Angular to manipulate the SVG Dom so that you can change based on the data definition or data changes, right? VICTOR POWELL: I'm sorry. AUDIENCE: For example, I have some paths, some rectangle defining the SVG markup, and I have some of the property directly binded with Angular's property, like brackets, using brackets to bind with Angular property. So that when Angular's property got changed, the value in the SVG's definition got changed too, with it. So it is possible to do that without-- VICTOR POWELL: I think you just answered your own question. AUDIENCE: For example, I'm defining kind of a path in SVG. We are providing several coordinates in the D property of the path's element. Without using D3, are you directly referencing one property from a scope of the Angular. So that when the property, Angular's scope got changed, the paths got changed in the SVG, too. So that it doesn't have to actually use the D3 to manipulate the Dom without using-- I mean in your presentation you defined a directive, so do you watch the data change? And then using the D30 enter exit update to actually update the SVG Dom. I don't use this part. I directly referencing the data from the scope. VICTOR POWELL: Can you repeat that? BRAD GREEN: So he's just asking if there's anything special about the SVG element and the way it's rendered that would prevent you from interplating an Angular scope within that. VICTOR POWELL: Oh, OK. That's an easy question. No. Because the SVG inside of the Dom is just like any other Dom element. IGOR MINAR: We do have tests that verify that the data binding works with SVG notes. And if there are some issues, then please file them with all the bugs, and we definitely want to fix them. AUDIENCE: I had just a short idea that I can-- Is it common to use this other thing with like streaming data? Saying if some backended streams data to the front end to [INAUDIBLE]. VICTOR POWELL: You're saying is that possible, or? AUDIENCE: No. If this is like a common use case. VICTOR POWELL: Yeah. You could use it for doing that. If you do it the way I described, the directive shouldn't really care where it gets the data from. So it really shouldn't matter. You could have a service that's pulling data dynamically from some API that it's just updating. And then the controller would be responsible for updating the data on the scope and the directive will just update automatically. You could put the web sockets inside of a service or maybe there's already someone might have already written something that does that that allows Socket.IO to work in Angular. But I think the directive really should have no opinion where the data comes from. AUDIENCE: Thanks, first of all, for the talks. They were great. VICTOR POWELL: Thanks. AUDIENCE: My question's about interceptors. So what are some other examples where you would use it, besides the timing, either execution to run your code? The first thing that comes to mind, perhaps, is maybe role-based access control. Would that be appropriate use of interceptors in Angular? I'm very new to it, so I'm just kind of curious as to what else you could do with it. BRIAN FORD: Sure. It was decorators is what-- AUDIENCE: Right. BRIAN FORD: That's OK. But interceptor's actually a good way of thinking about it. I like that. AUDIENCE: Sorry, I always con-- IGOR MINAR: But we also have interceptors-- BRIAN FORD: Yes. But it's important, because there also is this thing called interceptors with HTTP so you can intercept responses and incoming and outgoing. But it's important to distinguish between those. So you probably wouldn't use this sort of technique for something like that. You probably have some custom service that you wrote that interacts with your model data. But if you wanted to, for instance, say I'm going to shut down all HTTP requests across the board if a user doesn't have this thing, like dollar HTTP doesn't have such an ability. But you could hack your own little API onto it by saying give me dollar HTTP, and we're going to change how it works so that way it does something else. The idea is that you can change existing services by kind of patching their properties. AUDIENCE: Wait. Can't you use the HTTP backend service, like you do in-- BRIAN FORD: There are a lot of ways you could do it. I was looking kind of for an example. Yeah. But that, perhaps, might not be the best way to do it. But yeah, certainly. IGOR MINAR: The important thing is that whenever you use decorators, ensure that the API stays compatible. Because as soon as you monkey patch the object in a way that is not compatible, then you might run into issues with components that expect whatever service it is that you are monkey patching to behave in originally. BRIAN FORD: Yes. It's a very powerful tool, and you have to be responsible and stuff. VICTOR POWELL: I just wanted to make one small point, especially with role-based access control. You really don't want to be relying on doing that on the client to begin with. I think you mentioned that a little bit, actually. Fair enough. So, responsible. AUDIENCE: So I'm interested in the book you're writing with Ari on D3 and Angular. Could you talk a little more about what you find that's interesting it it? You know, sell it, as it were. VICTOR POWELL: Well, the book isn't 100% done. Most of the book, as is, goes through an instruction to D3 and an introduction to Angular. But combining the two hasn't been fully worked out in the book. But it should be very soon. Some of things it'll be going over, I went over in the talk, or that will be going over in the book, I went over in the talk. But I don't want to give away all the secrets.
B1 中級 AngularJS & D3.NET可視化指令 (AngularJS & D3: Directives for Visualizations) 148 9 Chris Lyu 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字