Left: | ||
Right: |
OLD | NEW |
---|---|
1 'use strict'; | 1 'use strict'; |
2 | 2 |
3 /** | 3 /** |
4 * IMPORTANT | 4 * IMPORTANT |
5 * | 5 * |
6 * This module represents a single step in the refactor of the environment | 6 * This module represents a single step in the refactor of the environment |
7 * view. This module is THROW AWAY CODE. Each forthcoming branch should | 7 * view. This module is THROW AWAY CODE. Each forthcoming branch should |
8 * begin by moving relevant code to the proper module, binding that | 8 * begin by moving relevant code to the proper module, binding that |
9 * module to Topo and removing code from here. | 9 * module to Topo and removing code from here. |
10 * | 10 * |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
355 | 355 |
356 // enter | 356 // enter |
357 node | 357 node |
358 .enter().append('g') | 358 .enter().append('g') |
359 .attr('class', function(d) { | 359 .attr('class', function(d) { |
360 return (d.subordinate ? 'subordinate ' : '') + 'service'; | 360 return (d.subordinate ? 'subordinate ' : '') + 'service'; |
361 }) | 361 }) |
362 .call(drag) | 362 .call(drag) |
363 .attr('transform', function(d) { | 363 .attr('transform', function(d) { |
364 return d.translateStr(); | 364 return d.translateStr(); |
365 }) | |
366 .call(function() { | |
367 // Create new nodes. | |
368 self.createServiceNode(this); | |
365 }); | 369 }); |
366 | 370 |
367 // Update | 371 // Update all nodes. |
368 this.drawService(node); | 372 self.updateServiceNodes(node); |
369 | 373 |
370 // Exit | 374 // Remove old nodes. |
371 node.exit() | 375 node.exit() |
372 .remove(); | 376 .remove(); |
373 }, | 377 }, |
374 | 378 |
375 // Called to draw a service in the 'update' phase | 379 /** |
376 drawService: function(node) { | 380 * @method createServiceNode fills a service node with empty structures |
381 * that will be filled out in the update stage. | |
382 * @param {object} node the node to construct. | |
383 * @return {null} side effects only. | |
384 */ | |
385 createServiceNode: function(node) { | |
386 node.append('image') | |
387 .attr('class', 'service-block-image'); | |
388 | |
389 node.append('text').append('tspan') | |
390 .attr('class', 'name') | |
391 .text(function(d) {return d.id; }); | |
392 | |
393 node.append('text').append('tspan') | |
394 .attr('class', 'charm-label') | |
395 .attr('dy', '3em') | |
396 .text(function(d) { return d.charm; }); | |
397 | |
398 // Append status charts to service nodes. | |
399 var status_chart = node.append('g') | |
400 .attr('class', 'service-status'); | |
401 | |
402 // Add a mask svg | |
403 status_chart.append('image') | |
404 .attr('xlink:href', '/juju-ui/assets/svgs/service_health_mask.svg') | |
405 .attr('class', 'service-health-mask'); | |
406 | |
407 // Add the unit counts, visible only on hover. | |
408 status_chart.append('text') | |
409 .attr('class', 'unit-count hide-count'); | |
410 }, | |
411 | |
412 /** | |
413 * @method updateServiceNodes fills the empty structures within a service | |
414 * node such that they match the db. | |
415 * @param {object} node the collection of nodes to update. | |
416 * @return {null} side effects only. | |
417 */ | |
418 updateServiceNodes: function(node) { | |
377 var self = this, | 419 var self = this, |
378 topo = this.get('component'), | 420 topo = this.get('component'), |
379 service_scale = this.service_scale, | 421 service_scale = this.service_scale, |
380 service_scale_width = this.service_scale_width, | 422 service_scale_width = this.service_scale_width, |
381 service_scale_height = this.service_scale_height; | 423 service_scale_height = this.service_scale_height; |
382 | 424 |
383 // Size the node for drawing. | 425 // Size the node for drawing. |
384 node | 426 node |
385 .attr('width', function(d) { | 427 .attr('width', function(d) { |
386 // NB: if a service has zero units, as is possible with | 428 // NB: if a service has zero units, as is possible with |
387 // subordinates, then default to 1 for proper scaling, as | 429 // subordinates, then default to 1 for proper scaling, as |
388 // a value of 0 will return a scale of 0 (this does not | 430 // a value of 0 will return a scale of 0 (this does not |
389 // affect the unit count, just the scale of the service). | 431 // affect the unit count, just the scale of the service). |
390 var w = service_scale(d.unit_count || 1); | 432 var w = service_scale(d.unit_count || 1); |
391 d.w = w; | 433 d.w = w; |
392 return w; | 434 return w; |
393 }) | 435 }) |
394 .attr('height', function(d) { | 436 .attr('height', function(d) { |
395 var h = service_scale(d.unit_count || 1); | 437 var h = service_scale(d.unit_count || 1); |
396 d.h = h; | 438 d.h = h; |
397 return h; | 439 return h; |
398 }); | 440 }); |
399 | 441 node.select('.service-block-image') |
400 // Draw subordinate services | 442 .attr('xlink:href', function(d) { |
401 node.filter(function(d) { | 443 return d.subordinate ? |
402 return d.subordinate; | 444 '/juju-ui/assets/svgs/sub_module.svg' : |
403 }) | 445 '/juju-ui/assets/svgs/service_module.svg'; |
404 .append('image') | 446 }) |
405 .attr('xlink:href', '/juju-ui/assets/svgs/sub_module.svg') | |
406 .attr('width', function(d) { | 447 .attr('width', function(d) { |
407 return d.w; | 448 return d.w; |
408 }) | 449 }) |
gary.poster
2013/01/08 02:57:11
FWIW, this indentation looked nicer to me.
| |
409 .attr('height', function(d) { | 450 .attr('height', function(d) { |
410 return d.h; | 451 return d.h; |
411 }); | 452 }); |
412 | 453 |
413 // Draw a subordinate relation indicator. | 454 // Draw a subordinate relation indicator. |
414 var sub_relation = node.filter(function(d) { | 455 var subRelationIndicator = node.filter(function(d) { |
415 return d.subordinate; | 456 return d.subordinate && |
457 d3.select(this) | |
458 .select('.sub-rel-block').empty(); | |
416 }) | 459 }) |
417 .append('g') | 460 .append('g') |
418 .attr('class', 'sub-rel-block') | 461 .attr('class', 'sub-rel-block') |
419 .attr('transform', function(d) { | 462 .attr('transform', function(d) { |
420 // Position the block so that the relation indicator will | 463 // Position the block so that the relation indicator will |
421 // appear at the right connector. | 464 // appear at the right connector. |
422 return 'translate(' + [d.w, d.h / 2 - 26] + ')'; | 465 return 'translate(' + [d.w, d.h / 2 - 26] + ')'; |
423 }); | 466 }); |
424 | 467 |
425 sub_relation.append('image') | 468 subRelationIndicator.append('image') |
426 .attr('xlink:href', '/juju-ui/assets/svgs/sub_relation.svg') | 469 .attr('xlink:href', '/juju-ui/assets/svgs/sub_relation.svg') |
427 .attr('width', 87) | 470 .attr('width', 87) |
428 .attr('height', 47); | 471 .attr('height', 47); |
429 sub_relation.append('text').append('tspan') | 472 subRelationIndicator.append('text').append('tspan') |
430 .attr('class', 'sub-rel-count') | 473 .attr('class', 'sub-rel-count') |
431 .attr('x', 64) | 474 .attr('x', 64) |
432 .attr('y', 47 * 0.8); | 475 .attr('y', 47 * 0.8); |
433 // Draw non-subordinate services services | |
434 node.filter(function(d) { | |
435 return !d.subordinate; | |
436 }) | |
437 .append('image') | |
438 .attr('xlink:href', '/juju-ui/assets/svgs/service_module.svg') | |
439 .attr('width', function(d) { | |
440 return d.w; | |
441 }) | |
442 .attr('height', function(d) { | |
443 return d.h; | |
444 }); | |
445 | 476 |
446 // The following are sizes in pixels of the SVG assets used to | 477 // The following are sizes in pixels of the SVG assets used to |
447 // render a service, and are used to in calculating the vertical | 478 // render a service, and are used to in calculating the vertical |
448 // positioning of text down along the service block. | 479 // positioning of text down along the service block. |
449 var service_height = 224, | 480 var service_height = 224, |
450 name_size = 22, | 481 name_size = 22, |
451 charm_label_size = 16, | 482 charm_label_size = 16, |
452 name_padding = 26, | 483 name_padding = 26, |
453 charm_label_padding = 118; | 484 charm_label_padding = 118; |
454 | 485 |
455 var service_labels = node.append('text').append('tspan') | 486 node.select('.name') |
456 .attr('class', 'name') | |
457 .attr('style', function(d) { | 487 .attr('style', function(d) { |
458 // Programmatically size the font. | 488 // Programmatically size the font. |
459 // Number derived from service assets: | 489 // Number derived from service assets: |
460 // font-size 22px when asset is 224px. | 490 // font-size 22px when asset is 224px. |
461 return 'font-size:' + d.h * | 491 return 'font-size:' + d.h * |
462 (name_size / service_height) + 'px'; | 492 (name_size / service_height) + 'px'; |
463 }) | 493 }) |
gary.poster
2013/01/08 02:57:11
nicer indent here.
| |
464 .attr('x', function(d) { | 494 .attr('x', function(d) { |
465 return d.w / 2; | 495 return d.w / 2; |
466 }) | 496 }) |
gary.poster
2013/01/08 02:57:11
this indentation is nicer here too, I think.
| |
467 .attr('y', function(d) { | 497 .attr('y', function(d) { |
468 // Number derived from service assets: | 498 // Number derived from service assets: |
469 // padding-top 26px when asset is 224px. | 499 // padding-top 26px when asset is 224px. |
470 return d.h * (name_padding / service_height) + d.h * | 500 return d.h * (name_padding / service_height) + d.h * |
471 (name_size / service_height) / 2; | 501 (name_size / service_height) / 2; |
472 }) | 502 }); |
473 .text(function(d) {return d.id; }); | 503 node.select('.charm-label') |
474 | |
475 var charm_labels = node.append('text').append('tspan') | |
476 .attr('class', 'charm-label') | |
477 .attr('style', function(d) { | 504 .attr('style', function(d) { |
478 // Programmatically size the font. | 505 // Programmatically size the font. |
479 // Number derived from service assets: | 506 // Number derived from service assets: |
480 // font-size 16px when asset is 224px. | 507 // font-size 16px when asset is 224px. |
481 return 'font-size:' + d.h * | 508 return 'font-size:' + d.h * |
482 (charm_label_size / service_height) + 'px'; | 509 (charm_label_size / service_height) + 'px'; |
483 }) | 510 }) |
gary.poster
2013/01/08 02:57:11
nicer indent before
| |
484 .attr('x', function(d) { | 511 .attr('x', function(d) { |
485 return d.w / 2; | 512 return d.w / 2; |
486 }) | 513 }) |
gary.poster
2013/01/08 02:57:11
nicer indent before
| |
487 .attr('y', function(d) { | 514 .attr('y', function(d) { |
488 // Number derived from service assets: | 515 // Number derived from service assets: |
489 // padding-top: 118px when asset is 224px. | 516 // padding-top: 118px when asset is 224px. |
490 return d.h * (charm_label_padding / service_height) - d.h * | 517 return d.h * (charm_label_padding / service_height) - d.h * |
491 (charm_label_size / service_height) / 2; | 518 (charm_label_size / service_height) / 2; |
492 }) | 519 }); |
493 .attr('dy', '3em') | |
494 .text(function(d) { return d.charm; }); | |
495 | 520 |
496 // Show whether or not the service is exposed using an | 521 // Show whether or not the service is exposed using an indicator. |
497 // indicator (currently a simple circle). | 522 node.filter(function(d) { |
498 // TODO this will likely change to an image with UI uodates. | |
499 var exposed_indicator = node.filter(function(d) { | |
500 return d.exposed; | 523 return d.exposed; |
501 }) | 524 }) |
502 .append('image') | 525 .append('image') |
526 .attr('class', 'exposed-indicator on') | |
503 .attr('xlink:href', '/juju-ui/assets/svgs/exposed.svg') | 527 .attr('xlink:href', '/juju-ui/assets/svgs/exposed.svg') |
504 .attr('width', function(d) { | 528 .attr('width', function(d) { |
505 return d.w / 6; | 529 return d.w / 6; |
506 }) | 530 }) |
507 .attr('height', function(d) { | 531 .attr('height', function(d) { |
508 return d.w / 6; | 532 return d.w / 6; |
509 }) | 533 }) |
510 .attr('x', function(d) { | 534 .attr('x', function(d) { |
511 return d.w / 10 * 7; | 535 return d.w / 10 * 7; |
512 }) | 536 }) |
513 .attr('y', function(d) { | 537 .attr('y', function(d) { |
514 return d.getRelativeCenter()[1] - (d.w / 6) / 2; | 538 return d.getRelativeCenter()[1] - (d.w / 6) / 2; |
515 }) | 539 }) |
516 .attr('class', 'exposed-indicator on'); | 540 .append('title') |
517 exposed_indicator.append('title') | |
518 .text(function(d) { | 541 .text(function(d) { |
519 return d.exposed ? 'Exposed' : ''; | 542 return d.exposed ? 'Exposed' : ''; |
520 }); | 543 }); |
521 | 544 |
545 // Remove exposed indicator from nodes that are no longer exposed. | |
546 node.filter(function(d) { | |
547 return !d.exposed && | |
548 !d3.select(this) | |
549 .select('.exposed-indicator').empty(); | |
550 }).select('.exposed-indicator').remove(); | |
551 | |
522 // Add the relative health of a service in the form of a pie chart | 552 // Add the relative health of a service in the form of a pie chart |
523 // comprised of units styled appropriately. | 553 // comprised of units styled appropriately. |
524 var status_chart_arc = d3.svg.arc() | 554 var status_chart_arc = d3.svg.arc() |
525 .innerRadius(0) | 555 .innerRadius(0) |
526 .outerRadius(function(d) { | 556 .outerRadius(function(d) { |
527 // Make sure it's exactly as wide as the mask with a bit | 557 // Make sure it's exactly as wide as the mask with a bit |
528 // of leeway for the border. | 558 // of leeway for the border. |
529 return parseInt( | 559 return parseInt( |
530 d3.select(this.parentNode) | 560 d3.select(this.parentNode) |
531 .select('image') | 561 .select('image') |
532 .attr('width'), 10) / 2.05; | 562 .attr('width'), 10) / 2.05; |
533 }); | 563 }); |
534 | 564 |
535 var status_chart_layout = d3.layout.pie() | 565 var status_chart_layout = d3.layout.pie() |
536 .value(function(d) { return (d.value ? d.value : 1); }) | 566 .value(function(d) { return (d.value ? d.value : 1); }) |
537 .sort(function(a, b) { | 567 .sort(function(a, b) { |
538 // Ensure that the service health graphs will be renders in | 568 // Ensure that the service health graphs will be renders in |
539 // the correct order: error - pending - running. | 569 // the correct order: error - pending - running. |
540 var states = {error: 0, pending: 1, running: 2}; | 570 var states = {error: 0, pending: 1, running: 2}; |
541 return states[a.name] - states[b.name]; | 571 return states[a.name] - states[b.name]; |
542 }); | 572 }); |
543 | 573 |
544 // Append to status charts to non-subordinate services | 574 node.select('.service-status') |
545 var status_chart = node.append('g') | |
546 .attr('class', 'service-status') | |
547 .attr('transform', function(d) { | 575 .attr('transform', function(d) { |
548 return 'translate(' + d.getRelativeCenter() + ')'; | 576 return 'translate(' + d.getRelativeCenter() + ')'; |
549 }); | 577 }); |
550 | 578 node.select('.service-health-mask') |
551 // Add a mask svg | |
552 status_chart.append('image') | |
553 .attr('xlink:href', '/juju-ui/assets/svgs/service_health_mask.svg') | |
554 .attr('width', function(d) { | 579 .attr('width', function(d) { |
555 return d.w / 3; | 580 return d.w / 3; |
556 }) | 581 }) |
557 .attr('height', function(d) { | 582 .attr('height', function(d) { |
558 return d.h / 3; | 583 return d.h / 3; |
559 }) | 584 }) |
560 .attr('x', function() { | 585 .attr('x', function() { |
561 return -d3.select(this).attr('width') / 2; | 586 return -d3.select(this).attr('width') / 2; |
562 }) | 587 }) |
563 .attr('y', function() { | 588 .attr('y', function() { |
564 return -d3.select(this).attr('height') / 2; | 589 return -d3.select(this).attr('height') / 2; |
565 }); | 590 }); |
566 | 591 |
567 // Add the path after the mask image (since it requires the mask's | 592 // Add the path after the mask image (since it requires the mask's |
568 // width to set its own). | 593 // width to set its own). |
569 var status_arcs = status_chart.selectAll('path') | 594 node.select('.service-status') |
595 .selectAll('path') | |
570 .data(function(d) { | 596 .data(function(d) { |
571 var aggregate_map = d.aggregated_status, | 597 var aggregate_map = d.aggregated_status, |
572 aggregate_list = []; | 598 aggregate_list = []; |
573 Y.Object.each(aggregate_map, function(count, state) { | 599 Y.Object.each(aggregate_map, function(count, state) { |
574 aggregate_list.push({name: state, value: count}); | 600 aggregate_list.push({name: state, value: count}); |
575 }); | 601 }); |
576 | 602 |
577 return status_chart_layout(aggregate_list); | 603 return status_chart_layout(aggregate_list); |
578 }).enter().insert('path', 'image') | 604 }).enter().insert('path', 'image') |
579 .attr('d', status_chart_arc) | 605 .attr('d', status_chart_arc) |
580 .attr('class', function(d) { return 'status-' + d.data.name; }) | 606 .attr('class', function(d) { return 'status-' + d.data.name; }) |
581 .attr('fill-rule', 'evenodd') | 607 .attr('fill-rule', 'evenodd') |
582 .append('title').text(function(d) { | 608 .append('title').text(function(d) { |
583 return d.data.name; | 609 return d.data.name; |
584 }); | 610 }); |
585 | 611 |
586 // Add the unit counts, visible only on hover. | 612 node.select('.unit-count') |
587 var unit_count = status_chart.append('text') | |
588 .attr('class', 'unit-count hide-count') | |
589 .text(function(d) { | 613 .text(function(d) { |
590 return utils.humanizeNumber(d.unit_count); | 614 return utils.humanizeNumber(d.unit_count); |
591 }); | 615 }); |
gary.poster
2013/01/08 02:57:11
indent was nicer before I think.
| |
592 | |
593 | |
594 }, | 616 }, |
595 | 617 |
596 | 618 |
597 /* | 619 /* |
598 * Show/hide/fade selection. | 620 * Show/hide/fade selection. |
599 */ | 621 */ |
600 show: function(evt) { | 622 show: function(evt) { |
601 var selection = evt.selection; | 623 var selection = evt.selection; |
602 selection.attr('opacity', '1.0') | 624 selection.attr('opacity', '1.0') |
603 .style('display', 'block'); | 625 .style('display', 'block'); |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
871 requires: [ | 893 requires: [ |
872 'd3', | 894 'd3', |
873 'd3-components', | 895 'd3-components', |
874 'juju-templates', | 896 'juju-templates', |
875 'node', | 897 'node', |
876 'event', | 898 'event', |
877 'juju-models', | 899 'juju-models', |
878 'juju-env' | 900 'juju-env' |
879 ] | 901 ] |
880 }); | 902 }); |
OLD | NEW |