<commit_before>
define [
  "underscore",
  "renderer/properties",
  "./glyph",
], (_, Properties, Glyph) ->

  glyph_properties = Properties.glyph_properties
  line_properties  = Properties.line_properties
  fill_properties  = Properties.fill_properties

  class RectView extends Glyph.View

    initialize: (options) ->
      super(options)
      ##duped in many classes
      @glyph_props = @init_glyph(@mget('glyphspec'))
      if @mget('selection_glyphspec')
        spec = _.extend({}, @mget('glyphspec'), @mget('selection_glyphspec'))
        @selection_glyphprops = @init_glyph(spec)
      if @mget('nonselection_glyphspec')
        spec = _.extend({}, @mget('glyphspec'), @mget('nonselection_glyphspec'))
        @nonselection_glyphprops = @init_glyph(spec)
        @nonselection_glyphprops.fill_properties.fill_alpha.value=.1
      if not @selection_glyphprops
        @selection_glyphprops = @glyph_props

      ##duped in many classes
      @do_fill   = @glyph_props.fill_properties.do_fill
      @do_stroke = @glyph_props.line_properties.do_stroke

    init_glyph: (glyphspec) ->
      fill_props = new fill_properties(@, glyphspec)
      line_props = new line_properties(@, glyphspec)
      glyph_props = new glyph_properties(
        @,
        glyphspec,
        ['x', 'y', 'width', 'height', 'angle'],
        {
          fill_properties: new fill_properties(@, glyphspec),
          line_properties: new line_properties(@, glyphspec)
        }
      )
      return glyph_props

    _map_data: () ->
      [sxi, syi] = @plot_view.map_to_screen(@x, @glyph_props.x.units, @y, @glyph_props.y.units)
      @sw = @distance_vector('x', 'width', 'center')
      @sh = @distance_vector('y', 'height', 'center')
      @sx = new Array(sxi.length)
      @sy = new Array(sxi.length)
      for i in [0..sxi.length-1]
        if Math.abs(sxi[i]-@sw[i]) < 2
          @sx[i] = Math.round(sxi[i])
        else
          @sx[i] = sxi[i]
        if Math.abs(syi[i]-@sh[i]) < 2
          @sy[i] = Math.round(syi[i])
        else
          @sy[i] = syi[i]

    set_data: (request_render=true) ->
      source = @mget_obj('data_source')
      if source.type == 'ColumnDataSource'
        @x = @source_v_select('x', @glyph_props, source)
        @y = @source_v_select('y', @glyph_props, source)
        angles = @source_v_select('angle', @glyph_props, source)
        @angle = (-angle for angle in angles)
        @mask = new Uint8Array(@x.length)
        @selected_mask = new Uint8Array(@x.length)
        for i in [0..@mask.length-1]
          @mask[i] = true
          @selected_mask[i] = false
        @have_new_data = true
  
      if request_render
        @request_render()

    source_v_select: (attrname, glyph_props, datasource) ->
      return glyph_props.source_v_select(attrname, glyph_props, datasource)

    _render: () ->
      @_map_data()
      ctx = @plot_view.ctx

      #duped
      selected = @mget_obj('data_source').get('selected')
      for idx in selected
        @selected_mask[idx] = true

      ctx.save()
      if @glyph_props.fast_path
        @_fast_path(ctx)
      else
        ##duped in many classes
        if selected and selected.length and @nonselection_glyphprops

          @_full_path(ctx, @selection_glyphprops, 'selected')
          @_full_path(ctx, @nonselection_glyphprops, 'unselected')
        else
          @_full_path(ctx)
        ##duped in many classes
      ctx.restore()

    _full_path: (ctx, glyph_props, use_selection) ->
      if not glyph_props
        glyph_props = @glyph_props
      source = @mget_obj('data_source')
      glyph_props.fill_properties.set_prop_cache(source)
      glyph_props.line_properties.set_prop_cache(source)

      for i in [0..@sx.length-1]
        if isNaN(@sx[i] + @sy[i] + @sw[i] + @sh[i] + @angle[i])
          continue
        if use_selection == 'selected' and not @selected_mask[i]
          continue
        if use_selection == 'unselected' and @selected_mask[i]
          continue

        ctx.translate(@sx[i], @sy[i])
        ctx.rotate(@angle[i])

        ctx.beginPath()
        ctx.rect(-@sw[i]/2, -@sh[i]/2, @sw[i], @sh[i])

        if @do_fill
          glyph_props.fill_properties.set_vectorize(ctx, i)
          ctx.fill()

        if @do_stroke
          glyph_props.line_properties.set_vectorize(ctx, i)
          ctx.stroke()

        ctx.rotate(-@angle[i])
        ctx.translate(-@sx[i], -@sy[i])


    _fast_path: (ctx) ->
      if @do_fill
        @glyph_props.fill_properties.set(ctx, @glyph_props)
        ctx.beginPath()
        for i in [0..@sx.length-1]
          if isNaN(@sx[i] + @sy[i] + @sw[i] + @sh[i] + @angle[i])
            continue

          if @angle[i]
            ctx.translate(@sx[i], @sy[i])
            ctx.rotate(@angle[i])
            ctx.rect(-@sw[i]/2, -@sh[i]/2, @sw[i], @sh[i])
            ctx.rotate(-@angle[i])
            ctx.translate(-@sx[i], -@sy[i])
          else
            ctx.rect(@sx[i]-@sw[i]/2, @sy[i]-@sh[i]/2, @sw[i], @sh[i])

        ctx.fill()

      if @do_stroke
        @glyph_props.line_properties.set(ctx, @glyph_props)
        ctx.beginPath()
        for i in [0..@sx.length-1]
          if isNaN(@sx[i] + @sy[i] + @sw[i] + @sh[i] + @angle[i])
            continue

          if @angle[i]
            ctx.translate(@sx[i], @sy[i])
            ctx.rotate(@angle[i])
            ctx.rect(-@sw[i]/2, -@sh[i]/2, @sw[i], @sh[i])
            ctx.rotate(-@angle[i])
            ctx.translate(-@sx[i], -@sy[i])
          else
            ctx.rect(@sx[i]-@sw[i]/2, @sy[i]-@sh[i]/2, @sw[i], @sh[i])

        ctx.stroke()

    draw_legend: (ctx, x1, x2, y1, y2) ->
      ## dummy legend function just draws a circle.. this way
      ## even if we have a differnet glyph shape, at least we get the
      ## right colors present
      glyph_props = @glyph_props
      line_props = glyph_props.line_properties
      fill_props = glyph_props.fill_properties<commit_msg> more performant plotting, removed fast_path because it's no longer necessary<commit_after>
define [
  "underscore",
  "renderer/properties",
  "./glyph",
], (_, Properties, Glyph) ->

  glyph_properties = Properties.glyph_properties
  line_properties  = Properties.line_properties
  fill_properties  = Properties.fill_properties

  class RectView extends Glyph.View

    initialize: (options) ->
      super(options)
      ##duped in many classes
      @glyph_props = @init_glyph(@mget('glyphspec'))
      if @mget('selection_glyphspec')
        spec = _.extend({}, @mget('glyphspec'), @mget('selection_glyphspec'))
        @selection_glyphprops = @init_glyph(spec)
      if @mget('nonselection_glyphspec')
        spec = _.extend({}, @mget('glyphspec'), @mget('nonselection_glyphspec'))
        @nonselection_glyphprops = @init_glyph(spec)
        @nonselection_glyphprops.fill_properties.fill_alpha.value=.1
      if not @selection_glyphprops
        @selection_glyphprops = @glyph_props

      ##duped in many classes
      @do_fill   = @glyph_props.fill_properties.do_fill
      @do_stroke = @glyph_props.line_properties.do_stroke

    init_glyph: (glyphspec) ->
      fill_props = new fill_properties(@, glyphspec)
      line_props = new line_properties(@, glyphspec)
      glyph_props = new glyph_properties(
        @,
        glyphspec,
        ['x', 'y', 'width', 'height', 'angle'],
        {
          fill_properties: new fill_properties(@, glyphspec),
          line_properties: new line_properties(@, glyphspec)
        }
      )
      return glyph_props

    _map_data: () ->
      [sxi, syi] = @plot_view.map_to_screen(@x, @glyph_props.x.units, @y, @glyph_props.y.units)
      @sw = @distance_vector('x', 'width', 'center')
      @sh = @distance_vector('y', 'height', 'center')
      @sx = new Array(sxi.length)
      @sy = new Array(sxi.length)
      for i in [0..sxi.length-1]
        if Math.abs(sxi[i]-@sw[i]) < 2
          @sx[i] = Math.round(sxi[i])
        else
          @sx[i] = sxi[i]
        if Math.abs(syi[i]-@sh[i]) < 2
          @sy[i] = Math.round(syi[i])
        else
          @sy[i] = syi[i]

    set_data: (request_render=true) ->
      source = @mget_obj('data_source')
      if source.type == 'ColumnDataSource'
        @x = @source_v_select('x', @glyph_props, source)
        @y = @source_v_select('y', @glyph_props, source)
        angles = @source_v_select('angle', @glyph_props, source)
        @angle = (-angle for angle in angles)
        @mask = new Uint8Array(@x.length)
        @selected_mask = new Uint8Array(@x.length)
        for i in [0..@mask.length-1]
          @mask[i] = true
          @selected_mask[i] = false
        @have_new_data = true
  
      if request_render
        @request_render()

    source_v_select: (attrname, glyph_props, datasource) ->
      return glyph_props.source_v_select(attrname, glyph_props, datasource)

    _render: () ->
      @_map_data()
      ctx = @plot_view.ctx

      #duped
      selected = @mget_obj('data_source').get('selected')
      for idx in selected
        @selected_mask[idx] = true

      ctx.save()
      if selected and selected.length and @nonselection_glyphprops
        @_full_path(ctx, @selection_glyphprops, 'selected')
        @_full_path(ctx, @nonselection_glyphprops, 'unselected')
      else
        @_full_path(ctx, @selection_glyphprops)

      ctx.restore()

    _full_path: (ctx, glyph_props, use_selection) ->
      if not glyph_props
        glyph_props = @glyph_props
      source = @mget_obj('data_source')
      if @do_fill
        glyph_props.fill_properties.set_prop_cache(source)
        for i in [0..@sx.length-1]
          if isNaN(@sx[i] + @sy[i] + @sw[i] + @sh[i] + @angle[i])
            continue
          if use_selection == 'selected' and not @selected_mask[i]
            continue
          if use_selection == 'unselected' and @selected_mask[i]
            continue

          #no need to test the return value, we call fillRect for every glyph anyway
          glyph_props.fill_properties.set_vectorize(ctx, i)
          
          if @angle[i]
            ctx.translate(@sx[i], @sy[i])
            ctx.rotate(@angle[i])
            ctx.fillRect(-@sw[i]/2, -@sh[i]/2, @sw[i], @sh[i])
            ctx.rotate(-@angle[i])
            ctx.translate(-@sx[i], -@sy[i])
          else
            ctx.fillRect(@sx[i]-@sw[i]/2, @sy[i]-@sh[i]/2, @sw[i], @sh[i])
            ctx.rect(@sx[i]-@sw[i]/2, @sy[i]-@sh[i]/2, @sw[i], @sh[i])

      if @do_stroke
        glyph_props.line_properties.set_prop_cache(source)
        ctx.beginPath()
        glyph_props.line_properties.set_vectorize(ctx, 0)
        for i in [0..@sx.length-1]
          if isNaN(@sx[i] + @sy[i] + @sw[i] + @sh[i] + @angle[i])
            continue
          if glyph_props.line_properties.set_vectorize(ctx, i)
            #only stroke if the line_properties have changed
            ctx.stroke()
            ctx.beginPath()
          if @angle[i]
            ctx.translate(@sx[i], @sy[i])
            ctx.rotate(@angle[i])
            ctx.rect(-@sw[i]/2, -@sh[i]/2, @sw[i], @sh[i])
            ctx.rotate(-@angle[i])
            ctx.translate(-@sx[i], -@sy[i])
          else
            ctx.rect(@sx[i]-@sw[i]/2, @sy[i]-@sh[i]/2, @sw[i], @sh[i])
        ctx.stroke()

    draw_legend: (ctx, x1, x2, y1, y2) ->
      ## dummy legend function just draws a circle.. this way
      ## even if we have a differnet glyph shape, at least we get the
      ## right colors present
      glyph_props = @glyph_props
      line_props = glyph_props.line_properties
      fill_props = glyph_props.fill_properties
{'fraction_non_alphanumeric': 0.1464813205907906, 'fraction_numerical': 0.0049522154648132055, 'mean_word_length': 2.3845927668332845, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 7, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1780010', 'n_tokens_mistral': 4084, 'n_tokens_neox': 3874, 'n_words': 760}