function update()

in src/core/configurableTL.ts [2250:3005]


function update(tl_layout, tl_scale, tl_representation, width, height, data, unit_width, prev_tl_layout, prev_tl_representation, prev_tl_scale, timeline_scale, selection) {
  selection.attr("id", d => `event_g${d.event_id}`);

  selection.select("rect.event_span")
    .attr("transform", function (d) {
      var offset_y = 0,
        offset_x = 0;
      if (tl_representation === "Linear") {
        switch (tl_layout) {

        case "Unified":
          offset_y = 0;
          break;

        case "Faceted":
          offset_y = (height / globals.num_facets) * globals.facets.domain().indexOf(d.facet);
          break;

        case "Segmented":
          var span_segment = calculateSpanSegment(data.min_start_date, d.start_date);
          offset_y = (height / globals.num_segments) * span_segment;
          break;

        default:
          offset_y = 0;
          break;
        }
      } else if (tl_representation === "Spiral" || tl_representation === "Radial") {
        var facet_dim_x = width / globals.num_facet_cols;
        var facet_dim_y = height / globals.num_facet_rows;
        if (tl_layout === "Unified") {
          offset_x = width / 2;
          offset_y = height / 2;
        } else if (tl_layout === "Faceted") {
          offset_x = globals.facets.domain().indexOf(d.facet) % globals.num_facet_cols * facet_dim_x + facet_dim_x / 2;
          if (tl_representation === "Radial") { offset_y = Math.floor(globals.facets.domain().indexOf(d.facet) / globals.num_facet_cols - 1) * facet_dim_y + facet_dim_y + facet_dim_y / 2 + globals.buffer; } else if (tl_representation === "Spiral") { offset_y = Math.floor(globals.facets.domain().indexOf(d.facet) / globals.num_facet_cols) * globals.spiral_dim + (globals.spiral_dim / 2); }
        }
      } else if (tl_representation === "Curve") {
        offset_x = d.curve_x;
        offset_y = d.curve_y;
      } else {
        offset_x = 0;
        offset_y = 0;
      }
      d.rect_offset_x = offset_x;
      d.rect_offset_y = offset_y;
      return "translate(" + unNaN(offset_x) + "," + unNaN(offset_y) + ")";
    });

  // update rects for linear timelines
  selection.select("rect.event_span")
    .attr("height", () => unit_width)
    .attr("width", function (d) {
      if (tl_layout !== "Segmented" && tl_representation === "Linear") {
        if (tl_scale === "Chronological" && d.start_date !== d.end_date) {
          return d3.max([timeline_scale(d.end_date) - timeline_scale(d.start_date), unit_width]);
        } else if (tl_scale === "Relative" && d.start_age !== d.end_age) {
          return d3.max([timeline_scale(d.end_age) - timeline_scale(d.start_age), unit_width]);
        }
      }
      return unit_width;
    })
    .attr("x", function (d) {
      var rect_x = 0;
      if (tl_representation === "Linear") {
        if (tl_layout === "Segmented") {
          switch (globals.segment_granularity) {
          case "days":
            rect_x = timeline_scale(moment(time.utcHour.floor(d.start_date)).hour());
            break;
          case "weeks":
            rect_x = timeline_scale(moment(time.day.floor(d.start_date)).day());
            break;
          case "months":
            rect_x = timeline_scale(moment(time.day.floor(d.start_date)).date());
            break;
          case "years":
            if (moment(time.utcWeek.floor(d.start_date)).week() === 53) {
              rect_x = timeline_scale(1);
            } else {
              rect_x = timeline_scale(moment(time.utcWeek.floor(d.start_date)).week());
            }
            break;
          case "decades":
            rect_x = timeline_scale(moment(time.month.floor(d.start_date)).month() + (time.month.floor(d.start_date).getUTCFullYear() - Math.floor(time.month.floor(d.start_date).getUTCFullYear() / 10) * 10) * 12);
            break;
          case "centuries":
            if (d.start_date.getUTCFullYear() < 0) {
              rect_x = timeline_scale(d.start_date.getUTCFullYear() % 100 + 100);
            } else {
              rect_x = timeline_scale(d.start_date.getUTCFullYear() % 100);
            }
            break;
          case "millenia":
            if (d.start_date.getUTCFullYear() < 0) {
              rect_x = timeline_scale(d.start_date.getUTCFullYear() % 1000 + 1000);
            } else {
              rect_x = timeline_scale(d.start_date.getUTCFullYear() % 1000);
            }
            break;
          case "epochs":
            rect_x = timeline_scale(d.start_date);
            break;
          default:
            break;
          }
        } else {
          switch (tl_scale) {

          case "Chronological":
            rect_x = timeline_scale(d.start_date);
            break;

          case "Relative":
            rect_x = d3.max([0, timeline_scale(d.start_age)]);
            break;

          case "Log":
            switch (globals.segment_granularity) {
            case "days":
              rect_x = timeline_scale(time.hour.count(d.start_date, data.max_end_date) * -1 - 1);
              break;
            case "weeks":
              rect_x = timeline_scale(time.day.count(d.start_date, data.max_end_date) * -1 - 1);
              break;
            case "months":
              rect_x = timeline_scale(time.week.count(d.start_date, data.max_end_date) * -1 - 1);
              break;
            case "years":
              rect_x = timeline_scale(time.month.count(d.start_date, data.max_end_date) * -1 - 1);
              break;
            case "decades":
              rect_x = timeline_scale(Math.abs(data.max_end_date.getUTCFullYear() - d.start_date.getUTCFullYear()) * -1 - 1);
              break;
            case "centuries":
              rect_x = timeline_scale(Math.abs(data.max_end_date.getUTCFullYear() - d.start_date.getUTCFullYear()) * -1 - 1);
              break;
            case "millenia":
              rect_x = timeline_scale(Math.abs(data.max_end_date.getUTCFullYear() - d.start_date.getUTCFullYear()) * -1 - 1);
              break;
            default:
              rect_x = timeline_scale(Math.abs(data.max_end_date.valueOf() - d.start_date.valueOf()) * -1 - 1);
              break;
            }
            break;

          case "Collapsed":
            rect_x = timeline_scale(d.seq_index) * unit_width + 0.5 * unit_width;
            break;

          case "Sequential":
            rect_x = timeline_scale(d.seq_index) * unit_width + 0.5 * unit_width;
            break;
          default:
            break;
          }
        }
      } else if (tl_representation === "Radial") {
        switch (tl_scale) {

        case "Chronological":
          rect_x = (globals.centre_radius + d.track * globals.track_height + 0.5 * unit_width) * Math.sin(timeline_scale(d.start_date));
          break;

        case "Relative":
          rect_x = (globals.centre_radius + d.track * globals.track_height + 0.5 * unit_width) * Math.sin(timeline_scale(d.start_age));
          break;

        case "Sequential":
          rect_x = (globals.centre_radius + d.seq_track * globals.track_height + 0.5 * unit_width) * Math.sin(timeline_scale(d.seq_index));
          break;

        default:
          rect_x = 0;
          break;
        }
      } else if (tl_representation === "Spiral" && tl_scale === "Sequential") {
        rect_x = d.spiral_x;
      } else {
        rect_x = 0;
      }
      d.rect_x_pos = rect_x;
      return rect_x;
    })
    .attr("y", function (d) {
      var rect_y = 0;
      if (tl_representation === "Linear") {
        switch (tl_layout) {

        case "Unified":
          switch (tl_scale) {

          case "Chronological":
            rect_y = height - (globals.track_height * d.track + globals.track_height);
            break;

          case "Log":
            rect_y = height - (globals.track_height * d.track + globals.track_height);
            break;

          case "Collapsed":
            rect_y = height - (d.seq_track * globals.track_height + globals.track_height + (4 * unit_width));
            break;

          case "Sequential":
            rect_y = height - (d.seq_track * globals.track_height + globals.track_height);
            break;

          default:
            rect_y = 0;
            break;
          }
          break;

        case "Faceted":
          switch (tl_scale) {

          case "Chronological":
            rect_y = (height / globals.num_facets) - (globals.track_height * d.track + globals.track_height);
            break;

          case "Relative":
            rect_y = (height / globals.num_facets) - (globals.track_height * d.track + globals.track_height);
            break;

          case "Log":
            rect_y = (height / globals.num_facets) - (globals.track_height * d.track + globals.track_height);
            break;

          case "Sequential":
            rect_y = (height / globals.num_facets) - (globals.track_height * d.seq_track + globals.track_height);
            break;

          default:
            rect_y = 0;
            break;
          }
          break;

        case "Segmented":
          rect_y = (height / globals.num_segments) - (globals.track_height * d.track + globals.track_height);
          break;
        default:
          break;
        }
      } else if (tl_representation === "Radial") {
        switch (tl_scale) {

        case "Chronological":
          rect_y = -1 * (globals.centre_radius + d.track * globals.track_height + 0.5 * unit_width) * Math.cos(timeline_scale(d.start_date));
          break;

        case "Relative":
          rect_y = -1 * (globals.centre_radius + d.track * globals.track_height + 0.5 * unit_width) * Math.cos(timeline_scale(d.start_age));
          break;

        case "Sequential":
          rect_y = -1 * (globals.centre_radius + d.seq_track * globals.track_height + 0.5 * unit_width) * Math.cos(timeline_scale(d.seq_index));
          break;

        default:
          rect_y = 0;
          break;
        }
      } else if (tl_representation === "Spiral" && tl_scale === "Sequential") {
        rect_y = d.spiral_y + globals.buffer;
      } else {
        rect_y = 0;
      }
      d.rect_y_pos = rect_y;
      return rect_y;
    });

  selection.select(".time_elapsed")
    .attr("x", function (d) {
      if (tl_scale === "Chronological") {
        return d3.max([0, timeline_scale(d.start_date) * unit_width - unit_width]);
      }
      if (tl_scale === "Log") {
        return 0;
      } else if (tl_scale === "Relative") {
        return 0;
      }

      return timeline_scale(d.seq_index) * unit_width - 0.5 * unit_width;
    })
    .attr("y", function (d) {
      if (globals.date_granularity === "epochs" && d.time_elapsed === 0) {
        return height;
      }

      return height - (unit_width * 4);
    })
    .text(function (d) {
      return d.time_elapsed_label;
    });
  selection.select("path.event_span")
    .attr("transform", function (d) {
      var offset_y = 0;
      var offset_x = 0;
      switch (tl_layout) {

      case "Unified":
        offset_x = width / 2;
        offset_y = height / 2;
        break;

      case "Faceted":
        var facet_dim_x = width / globals.num_facet_cols;
        var facet_dim_y = height / globals.num_facet_rows;
        offset_x = globals.facets.domain().indexOf(d.facet) % globals.num_facet_cols * facet_dim_x + facet_dim_x / 2;
        offset_y = Math.floor(globals.facets.domain().indexOf(d.facet) / globals.num_facet_cols - 1) * facet_dim_y + facet_dim_y + facet_dim_y / 2 + globals.buffer;
        break;

      case "Segmented":
        const span_segment = calculateSpanSegment(data.min_start_date, d.start_date);
        var segment_dim_x = width / globals.num_segment_cols;
        var segment_dim_y = height / globals.num_segment_rows;
        offset_x = span_segment % globals.num_segment_cols * segment_dim_x + segment_dim_x / 2;
        offset_y = Math.floor(span_segment / globals.num_segment_cols) * segment_dim_y + segment_dim_y / 2 + globals.buffer;
        break;
      default:
        break;
      }
      d.path_offset_x = offset_x;
      d.path_offset_y = offset_y;

      if (tl_representation === "Radial") {
        switch (tl_scale) {

        case "Chronological":
          d.path_x_pos = (globals.centre_radius + d.track * globals.track_height + 0.25 * globals.track_height) * Math.sin(timeline_scale(d.start_date));
          d.path_y_pos = -1 * (globals.centre_radius + d.track * globals.track_height + 0.25 * globals.track_height) * Math.cos(timeline_scale(d.start_date));
          break;

        case "Relative":
          d.path_x_pos = (globals.centre_radius + d.track * globals.track_height + 0.25 * globals.track_height) * Math.sin(timeline_scale(d.start_age));
          d.path_y_pos = -1 * (globals.centre_radius + d.track * globals.track_height + 0.25 * globals.track_height) * Math.cos(timeline_scale(d.start_age));
          break;

        case "Sequential":
          d.path_x_pos = (globals.centre_radius + d.seq_track * globals.track_height + 0.25 * globals.track_height) * Math.sin(timeline_scale(d.seq_index));
          d.path_y_pos = -1 * (globals.centre_radius + d.seq_track * globals.track_height + 0.25 * globals.track_height) * Math.cos(timeline_scale(d.seq_index));
          break;
        default:
          break;
        }
      }

      return "translate(" + unNaN(offset_x) + "," + unNaN(offset_y) + ")";
    });

  if (tl_representation !== "Radial") {
    selection.selectAll("path.event_span")
      .style("display", "none");
  }

  selection.selectAll("rect.event_span_component")
    .attr("transform", function (dataItem) {
      const dateTime = dataItem.dateTime;
      var offset_y = 0,
        offset_x = 0;

      if (tl_layout === "Faceted") {
        offset_y = (height / globals.num_facets) * globals.facets.domain().indexOf(d3.select(this.parentNode).datum().facet);
      } else if (tl_layout === "Segmented") {
        if (tl_representation === "Linear" && tl_scale === "Chronological") {
          switch (globals.segment_granularity) {
          case "days":
            offset_y = d3.max([0, (time.day.count(time.utcDay.floor(data.min_start_date), dateTime) - 1) * (height / globals.num_segments)]);
            break;
          case "weeks":
            offset_y = d3.max([0, (time.week.count(time.utcWeek.floor(data.min_start_date), dateTime) - 1) * (height / globals.num_segments)]);
            break;
          case "months":
            offset_y = d3.max([0, (time.month.count(time.utcMonth.floor(data.min_start_date), dateTime) - 1) * (height / globals.num_segments)]);
            break;
          case "years":
            offset_y = d3.max([0, (dateTime.getUTCFullYear() - data.min_start_date.getUTCFullYear()) * (height / globals.num_segments)]);
            break;
          case "decades":
            offset_y = d3.max([0, (Math.floor(dateTime.getUTCFullYear() / 10) - Math.floor(data.min_start_date.getUTCFullYear() / 10)) * (height / globals.num_segments)]);
            break;
          case "centuries":
            offset_y = d3.max([0, (Math.floor(dateTime / 100) - Math.floor(data.min_start_date.getUTCFullYear() / 100)) * (height / globals.num_segments)]);
            break;
          case "millenia":
            offset_y = d3.max([0, (Math.floor(dateTime / 1000) - Math.floor(data.min_start_date.getUTCFullYear() / 1000)) * (height / globals.num_segments)]);
            break;
          case "epochs":
            offset_y = 0;
            break;
          default:
            break;
          }
        } else if (tl_representation === "Radial" && tl_scale === "Chronological") {
          var span_segment = calculateSpanSegment(data.min_start_date, dateTime);
          var segment_dim_x = width / globals.num_segment_cols;
          var segment_dim_y = height / globals.num_segment_rows;
          offset_x = span_segment % globals.num_segment_cols * segment_dim_x + segment_dim_x / 2;
          offset_y = Math.floor(span_segment / globals.num_segment_cols) * segment_dim_y + segment_dim_y / 2 + globals.track_height;
        }
      }
      return "translate(" + unNaN(offset_x) + "," + unNaN(offset_y) + ")";
    });

  function getTimelineScaleValue(dateTime, checkNegative) {
    let value = 0;
    switch (globals.segment_granularity) {
    case "days":
      value = d3.max([0, timeline_scale(moment(dateTime).hour())]);
      break;
    case "weeks":
      value = d3.max([0, timeline_scale(moment(dateTime).day())]);
      break;
    case "months":
      value = d3.max([0, timeline_scale(moment(dateTime).date())]);
      break;
    case "years":
      if (moment(dateTime).week() === 53) {
        value = d3.max([0, timeline_scale(1)]);
      } else {
        value = d3.max([0, timeline_scale(moment(dateTime).week())]);
      }
      break;
    case "decades":
      value = d3.max([0, timeline_scale(moment(dateTime).month() + (dateTime.getUTCFullYear() - Math.floor(dateTime.getUTCFullYear() / 10) * 10) * 12)]);
      break;
    case "centuries":
      if (checkNegative && dateTime < 0) {
        value = d3.max([0, timeline_scale(dateTime % 100 + 100)]);
      } else {
        value = d3.max([0, timeline_scale(dateTime % 100)]);
      }
      break;
    case "millenia":
      if (checkNegative && dateTime < 0) {
        value = d3.max([0, timeline_scale(dateTime % 1000 + 1000)]);
      } else {
        value = d3.max([0, timeline_scale(dateTime % 1000)]);
      }
      break;
    case "epochs":
      value = d3.max([0, timeline_scale(dateTime)]);
      break;
    default:
      break;
    }
    return value;
  }

  selection.selectAll("rect.event_span_component")
    .attr("height", function () {
      var span_height = unit_width;
      if (tl_layout === "Segmented" && tl_representation === "Calendar" && tl_scale === "Chronological") {
        span_height = 20;
      } else if (tl_layout === "Segmented" && tl_representation === "Grid" && tl_scale === "Chronological") {
        span_height = 37.5;
      }
      return span_height;
    })
    .attr("width", function () {
      var span_width = unit_width;
      if (tl_layout === "Segmented" && tl_representation === "Linear" && tl_scale === "Chronological") {
        span_width = globals.segment_granularity !== "epochs" ?
          d3.max([0, width / getNumberOfSegmentsForGranularity(globals.segment_granularity)]) :
          d3.max([0, unit_width]);
      } else if (tl_layout === "Segmented" && tl_representation === "Radial" && tl_scale === "Chronological" && prev_tl_representation !== "Radial") {
        span_width = unit_width;
      } else if (tl_layout === "Segmented" && tl_representation === "Grid" && tl_scale === "Chronological") {
        span_width = 50;
      } else if (tl_layout === "Segmented" && tl_representation === "Calendar" && tl_scale === "Chronological") {
        span_width = 10;
      }
      return span_width;
    })
    .attr("y", function (dataItem) {
      const dateTime = dataItem.dateTime;
      var y_pos = 0;
      if (tl_layout === "Unified") {
        if (tl_representation === "Linear" && tl_scale === "Chronological") {
          y_pos = d3.max([0, height - (globals.track_height * d3.select(this.parentNode).datum().track + globals.track_height)]);
        }
      } else if (tl_layout === "Faceted") {
        if (tl_representation === "Linear" && tl_scale === "Chronological") {
          y_pos = d3.max([0, (height / globals.num_facets) - (globals.track_height * d3.select(this.parentNode).datum().track + globals.track_height)]);
        }
      } else if (tl_layout === "Segmented") {
        if (tl_representation === "Linear" && tl_scale === "Chronological") {
          y_pos = d3.max([0, (height / globals.num_segments) - (globals.track_height * d3.select(this.parentNode).datum().track + globals.track_height)]);
        } else if (tl_representation === "Radial" && tl_scale === "Chronological") {
          var y_cos = getTimelineScaleValue(dateTime, false);
          y_pos = -1 * (globals.centre_radius + d3.select(this.parentNode).datum().track * globals.track_height + globals.track_height) * Math.cos(y_cos);
        } else if (tl_layout === "Segmented" && tl_representation === "Grid" && tl_scale === "Chronological") {
          if (["decades", "centuries", "millenia"].indexOf(globals.segment_granularity) !== -1) {
            var grid_year;

            if (globals.isNumber(dateTime)) {
              grid_year = dateTime;
            } else {
              grid_year = dateTime.getUTCFullYear();
            }

            y_pos = getYGridPosition(grid_year, Math.floor(data.min_start_date.getUTCFullYear() / 100) * 100, unit_width);
          } else if (globals.segment_granularity === "epochs") {
            y_pos = 0;
          } else {
            y_pos = 0;
          }
        } else if (tl_layout === "Segmented" && tl_representation === "Calendar" && tl_scale === "Chronological") {
          var cell_size = 20,
            year_height = cell_size * 8;
          let range_floor = data.min_start_date.getUTCFullYear();
          if (globals.segment_granularity === "centuries" || globals.segment_granularity === "millenia" || globals.segment_granularity === "epochs") {
            y_pos = 0;
          } else {
            const year_offset = year_height * (dateTime.getUTCFullYear() - range_floor);
            y_pos = d3.max([0, dateTime.getDay() * cell_size + year_offset]);
          }
        }
      }
      return y_pos;
    })
    .attr("x", function (dataItem) {
      const dateTime = dataItem.dateTime;
      var x_pos = 0;
      if (tl_layout === "Unified" || tl_layout === "Faceted") {
        if (tl_representation === "Linear" && tl_scale === "Chronological") {
          x_pos = d3.max([0, timeline_scale(d3.select(this.parentNode).datum().start_date)]);
        }
      } else if (tl_layout === "Segmented") {
        if (tl_representation === "Linear" && tl_scale === "Chronological") {
          x_pos = getTimelineScaleValue(dateTime, true);
        } else if (tl_representation === "Radial" && tl_scale === "Chronological") {
          var x_sin = getTimelineScaleValue(dateTime, false);
          x_pos = (globals.centre_radius + d3.select(this.parentNode).datum().track * globals.track_height + globals.track_height) * Math.sin(x_sin);
        } else if (tl_layout === "Segmented" && tl_representation === "Grid" && tl_scale === "Chronological") {
          var grid_year;

          if (globals.isNumber(dateTime)) {
            grid_year = dateTime;
          } else {
            grid_year = dateTime.getUTCFullYear();
          }

          if (["decades", "centuries", "millenia"].indexOf(globals.segment_granularity) !== -1) {
            x_pos = d3.max([0, getXGridPosition(grid_year)]);
          } else if (globals.segment_granularity === "epochs") {
            x_pos = 0;
          } else {
            x_pos = d3.max([0, getXGridPosition(grid_year)]);
          }
        } else if (tl_layout === "Segmented" && tl_representation === "Calendar" && tl_scale === "Chronological") {
          if (globals.segment_granularity === "centuries" || globals.segment_granularity === "millenia" || globals.segment_granularity === "epochs") {
            x_pos = 0;
          } else {
            x_pos = d3.max([0, d3.time.weekOfYear(dateTime) * 20]);
          }
        }
      }
      return x_pos;
    });

  selection.selectAll("path.event_span_component")
    .attr("transform", function (dataItem) {
      const dateTime = dataItem.dateTime;
      var offset_x = 0,
        offset_y = 0,
        span_segment = 0;
      if (tl_layout === "Segmented" && tl_scale === "Chronological") {
        span_segment = calculateSpanSegment(data.min_start_date, dateTime);
        var segment_dim_x = width / globals.num_segment_cols;
        var segment_dim_y = height / globals.num_segment_rows;
        offset_x = span_segment % globals.num_segment_cols * segment_dim_x + segment_dim_x / 2;
        offset_y = Math.floor(span_segment / globals.num_segment_cols - 1) * segment_dim_y + segment_dim_y + segment_dim_y / 2 + globals.buffer;
      } else if (tl_layout === "Unified") {
        offset_x = width / 2;
        offset_y = height / 2;
      } else if (tl_layout === "Faceted") {
        var facet_dim_x = width / globals.num_facet_cols;
        var facet_dim_y = height / globals.num_facet_rows;
        offset_x = globals.facets.domain().indexOf(d3.select(this.parentNode).datum().facet) % globals.num_facet_cols * facet_dim_x + facet_dim_x / 2;
        offset_y = Math.floor(globals.facets.domain().indexOf(d3.select(this.parentNode).datum().facet) / globals.num_facet_cols - 1) * facet_dim_y + facet_dim_y + facet_dim_y / 2 + globals.buffer;
      }
      return "translate(" + unNaN(offset_x) + "," + unNaN(offset_y) + ")";
    });

  if (tl_representation !== "Radial") {
    selection.selectAll("path.event_span_component")
      .style("display", "none");
  }

  // update terminal span indicators
  selection.select(".path_end_indicator")
    .attr("transform", function (d) {
      var x_pos = 0,
        y_pos = 0,
        span_segment = 0,
        rotation = 0,
        rect_x = 0; // eslint-disable-line no-unused-vars

      if (tl_layout === "Segmented") {
        if (tl_representation === "Linear") {
          rotation = 90;
          switch (globals.segment_granularity) {
          case "days":
            x_pos = d3.max([0, timeline_scale(moment(d.start_date).hour())]);
            y_pos = d3.max([0, time.day.count(time.utcDay.floor(data.min_start_date), d.start_date) - 1]);
            break;
          case "weeks":
            x_pos = d3.max([0, timeline_scale(moment(d.start_date).day())]);
            y_pos = d3.max([0, time.week.count(time.utcWeek.floor(data.min_start_date), d.start_date) - 1]);
            break;
          case "months":
            x_pos = d3.max([0, timeline_scale(moment(d.start_date).date())]);
            y_pos = d3.max([0, time.month.count(time.utcMonth.floor(data.min_start_date), d.start_date) - 1]);
            break;
          case "years":
            if (moment(d.start_date).week() === 53) {
              x_pos = d3.max([0, timeline_scale(1)]);
            } else {
              d3.max([0, x_pos = timeline_scale(moment(d.start_date).week() - 1)]);
            }
            y_pos = d3.max([0, d.start_date.getUTCFullYear() - data.min_start_date.getUTCFullYear()]);
            break;
          case "decades":
            if (moment(d.start_date).month() === 11 && moment(d.start_date).date() === 31) {
              x_pos = d3.max([0, timeline_scale(-1 + (d.start_date.getUTCFullYear() - Math.floor(d.start_date.getUTCFullYear() / 10) * 10) * 12)]);
            } else {
              x_pos = d3.max([0, timeline_scale(moment(d.start_date).month() + (d.start_date.getUTCFullYear() - Math.floor(d.start_date.getUTCFullYear() / 10) * 10) * 12)]);
            }
            y_pos = d3.max([0, Math.floor(d.start_date.getUTCFullYear() / 10) - Math.floor(data.min_start_date.getUTCFullYear() / 10)]);
            break;
          case "centuries":
            if (d.start_date.getUTCFullYear() < 0) {
              x_pos = d3.max([0, timeline_scale(d.start_date.getUTCFullYear() % 100 + 100)]);
            } else {
              x_pos = d3.max([0, timeline_scale(d.start_date.getUTCFullYear() % 100)]);
            }
            y_pos = d3.max([0, Math.floor(d.start_date.getUTCFullYear() / 100) - Math.floor(data.min_start_date.getUTCFullYear() / 100)]);
            break;
          case "millenia":
            if (d.start_date.getUTCFullYear() < 0) {
              x_pos = d3.max([0, timeline_scale(d.start_date.getUTCFullYear() % 1000 + 1000)]);
            } else {
              x_pos = d3.max([0, timeline_scale(d.start_date.getUTCFullYear() % 1000)]);
            }
            y_pos = d3.max([0, Math.floor(d.start_date.getUTCFullYear() / 1000) - Math.floor(data.min_start_date.getUTCFullYear() / 1000)]);
            break;
          case "epochs":
            x_pos = d3.max([0, timeline_scale(d.start_date)]);
            y_pos = 0;
            break;
          default:
            break;
          }
          x_pos = x_pos + unit_width * 0.33;
          y_pos = (y_pos + 1) * (height / globals.num_segments) - (globals.track_height * d.track + globals.track_height) + unit_width * 0.5;
        } else if (tl_representation === "Radial") {
          var pos;
          span_segment = calculateSpanSegment(data.min_start_date, d.start_date);
          switch (globals.segment_granularity) {
          case "days":
            pos = timeline_scale(moment(d.start_date).hour() + 0.5);
            break;
          case "weeks":
            pos = timeline_scale(moment(d.start_date).day() + 0.5);
            break;
          case "months":
            pos = timeline_scale(moment(d.start_date).date() + 0.5);
            break;
          case "years":
            if (moment(d.start_date).isoWeek() === 53) {
              pos = timeline_scale(1);
            } else {
              pos = timeline_scale(moment(d.start_date).isoWeek() - 1);
            }
            break;
          case "decades":
            if (moment(d.start_date).month() === 11 && moment(d.start_date).date() === 31) {
              pos = timeline_scale(-1 + (d.start_date.getUTCFullYear() - Math.floor(d.start_date.getUTCFullYear() / 10) * 10) * 12 + 0.5);
            } else {
              pos = timeline_scale(moment(d.start_date).month() + (d.start_date.getUTCFullYear() - Math.floor(d.start_date.getUTCFullYear() / 10) * 10) * 12 + 0.5);
            }
            break;
          case "centuries":
            if (d.start_date.getUTCFullYear() < 0) {
              pos = timeline_scale(d.start_date.getUTCFullYear() % 100 + 100 + 0.5);
            } else {
              pos = timeline_scale(d.start_date.getUTCFullYear() % 100 + 0.5);
            }
            break;
          case "millenia":
            if (d.start_date.getUTCFullYear() < 0) {
              pos = timeline_scale(d.start_date.getUTCFullYear() % 1000 + 1000 + 0.5);
            } else {
              pos = timeline_scale(d.start_date.getUTCFullYear() % 1000 + 0.5);
            }
            break;
          case "epochs":
            pos = timeline_scale(d.start_date.valueOf() + 0.5);
            break;
          default:
            break;
          }
          var segment_dim_x = width / globals.num_segment_cols;
          var segment_dim_y = height / globals.num_segment_rows;
          var segment_x = span_segment % globals.num_segment_cols * segment_dim_x + segment_dim_x / 2;
          var segment_y = Math.floor(span_segment / globals.num_segment_cols - 1) * segment_dim_y + segment_dim_y + segment_dim_y / 2 + globals.buffer;
          var x_offset = ((globals.centre_radius + d.track * globals.track_height + 0.25 * globals.track_height) * Math.sin(pos));
          var y_offset = -1 * ((globals.centre_radius + d.track * globals.track_height + 0.25 * globals.track_height) * Math.cos(pos));
          x_pos = segment_x + x_offset;
          y_pos = segment_y + y_offset;
          rotation = pos * 360 / (Math.PI * 2) + 90;
        } else if (tl_representation === "Grid" && tl_scale === "Chronological" && globals.date_granularity !== "epochs") {
          rotation = 90;
          x_pos = d3.max([0, getXGridPosition(d.start_date.getUTCFullYear()) + unit_width * 0.33]);
          y_pos = getYGridPosition(d.start_date.getUTCFullYear(), data.min_start_date.getUTCFullYear(), unit_width) + unit_width * 0.5;
        } else if (tl_representation === "Calendar" && tl_scale === "Chronological") {
          var cell_size = 20,
            year_height = cell_size * 8;
          const range_floor = data.min_start_date.getUTCFullYear();
          const year_offset = year_height * (d.start_date.getUTCFullYear() - range_floor);
          rotation = 180;
          x_pos = d3.max([0, d3.time.weekOfYear(d.start_date) * 20 + 0.33 * unit_width]);
          y_pos = d3.max([0, d.start_date.getDay() * cell_size + year_offset + unit_width * 0.33]);
        }
      } else if (tl_layout === "Unified" && tl_scale === "Chronological") {
        if (tl_representation === "Linear") {
          rotation = 90;
          x_pos = d3.max([0, rect_x = timeline_scale(d.start_date) + unit_width * 0.33]);
          y_pos = d3.max([0, height - (globals.track_height * d.track + unit_width)]);
        } else if (tl_representation === "Radial") {
          rotation = timeline_scale(d.start_date) * 360 / (Math.PI * 2) + 90;
          x_pos = (globals.centre_radius + d.track * globals.track_height) * Math.sin(timeline_scale(d.start_date));
          y_pos = -1 * (globals.centre_radius + d.track * globals.track_height) * Math.cos(timeline_scale(d.start_date));
        }
      } else if (tl_layout === "Faceted" && tl_scale === "Chronological") {
        if (tl_representation === "Linear") {
          var facet_offset = (height / globals.num_facets) * globals.facets.domain().indexOf(d.facet);
          rotation = 90;
          x_pos = d3.max([0, rect_x = timeline_scale(d.start_date) + unit_width * 0.33]);
          y_pos = d3.max([0, (height / globals.num_facets) - (globals.track_height * d.track + unit_width) + facet_offset]);
        } else if (tl_representation === "Radial") {
          var facet_dim_x = width / globals.num_facet_cols;
          var facet_dim_y = height / globals.num_facet_rows;
          var x_facet_offset = globals.facets.domain().indexOf(d.facet) % globals.num_facet_cols * facet_dim_x + facet_dim_x / 2;
          var y_facet_offset = Math.floor(globals.facets.domain().indexOf(d.facet) / globals.num_facet_cols - 1) * facet_dim_y + facet_dim_y + facet_dim_y / 2;
          rotation = timeline_scale(d.start_date) * 360 / (Math.PI * 2) + 90;
          x_pos = (globals.centre_radius + d.track * globals.track_height) * Math.sin(timeline_scale(d.start_date)) + x_facet_offset;
          y_pos = -1 * (globals.centre_radius + d.track * globals.track_height) * Math.cos(timeline_scale(d.start_date)) + y_facet_offset;
        }
      }
      return "translate(" + unNaN(x_pos) + "," + unNaN(y_pos) + ")rotate(" + unNaN(rotation) + ")";
    });
}