Source

model / model_app / views.coffee

Full commit
class ClassView extends Backbone.View

  initialize: =>
    @model.on "change", @render
    @model.on "destroy", @remove

  set_container: (svg) =>
    @svg = svg

  set_dimensions: (dimensions) =>
    @offset = dimensions.offset
    @default_class_width = dimensions.default_class_width
    @default_member_height = dimensions.default_member_height
    @default_member_spacing = dimensions.default_member_spacing

  render: =>
    data = @model.get_all_members()
    if data.length < 2
      data.push(" ")
      data.push(" ")
    level = "l0"
    if @model.has_super()
      y = 200
      level = "l1"
    else
      y = 50
      level = "l0"
    x = @offset[level]
    h = data.length * @default_member_height
    w = @default_class_width
    margin = 10
    @el = @svg.append("g")
      .attr("x", x)
      .attr("y", y)

    @el.append("rect")
      .attr("x", x)
      .attr("y", y)
      .attr("rx", 5)
      .attr("ry", 5)
      .attr("width", w)
      .attr("height", h)
    @el.selectAll("text")
      .data(data)
      .enter()
      .append("text")
      .attr("x", x + margin)
      .attr("y", (d, i) => y + margin + i * @default_member_height)
      .attr("dy", ".35em")
      .text String
    @el.append("line")
      .attr("x1", x)
      .attr("y1", y + @default_member_height)
      .attr("x2", x + @default_class_width)
      .attr("y2", y + @default_member_height)
    @offset[level] += @default_class_width + @default_member_spacing

    @top_connect_point =
        x: x + w/2
        y: y

    @bottom_connect_point =
        x: x + w/2
        y: y + h

    if @model.has_super()
      for sc in @model.get "super_classes"
        super_view = @class_views_by_name[sc]
        points = []
        points[0] = x: @top_connect_point.x, y: @top_connect_point.y
        points[1] = x: super_view.bottom_connect_point.x, y: super_view.bottom_connect_point.y
        path_d = "M" + points[0].x + "," + points[0].y
        path_d += " C" + points[0].x + "," + (points[0].y-50)
        path_d += " " + points[1].x + "," + (points[1].y+50)
        path_d += " " + points[1].x + "," + points[1].y
        # TODO use d3.js helper functions
        @el.append("path")
          .attr("d", path_d)
          .attr("stroke", "black")
          .attr("fill", "none")

    return @


class ClassDiagramView extends Backbone.View
  svg: null
  class_views_by_name: {}
  current_offset: l0: 0, l1: 0
  default_class_width: 150
  default_member_height: 20
  default_member_spacing: 20

  initialize: =>
    @render()
    current_diagram.on "add", @add_class

  render: =>
    w = 675
    h = 360
    pack = d3.layout.pack()
      .size([ w - 4, h - 4 ])
      .value((d) -> d.size)
    @svg = d3.select("#chart")
      .append("svg")
      .attr("width", w)
      .attr("height", h)
      .attr("class", "pack")
      .append("g")
      .attr("transform", "translate(2, 2)")

  add_class: (model) =>
    class_view = new ClassView(model: model)
    class_view.set_container @svg
    class_view.set_dimensions(
      offset:                 @current_offset
      default_class_width:    @default_class_width,
      default_member_height:  @default_member_height,
      default_member_spacing: @default_member_spacing,
    )
    class_view.class_views_by_name = @class_views_by_name
    class_view.render()
    @current_offset = class_view.offset
    @class_views_by_name[model.get "name"] = class_view

view = new ClassDiagramView