<commit_before>'use strict';

angular.module('chronontology.directives', [])

  .directive('timeline', function($location) {
    return {
      restrict: 'EA',
      scope: {
          periods: '=',
          selectedPeriodId: '=',
          height: '@'
      },
      templateUrl: 'partials/timeline.html',
      link: function(scope, element, attrs) {

          const barHeight = 20;
          const minYear = -10000;
          const maxYear = new Date().getFullYear();
          var bars, barRects, barTexts;
          var tooltip;
          var x, y;
          var totalXDomain = [];
          var startXDomain = [];
          var startYDomain = [];
          var timeline;
          var canvas;
          var axis, axisElement;
          var zoom, drag;
          var rowMax = -1;

          scope.width = element[0].parentNode.clientWidth - 15;

          scope.$watch('periods', function() {
             if (scope.periods) initialize();
          });

          function initialize() {
              y = d3.scale.linear()
                  .domain([0, barHeight * 20])
                  .range([0, parseInt(scope.height) - 30]);

              var periodsData = prepareData();
              adjustStartXDomain();

              x = d3.scale.linear()
                  .domain(startXDomain)
                  .range([0, parseInt(scope.width)]);

              y.domain(startYDomain);

              timeline = d3.select('#timeline').append('svg')
                  .attr('width', parseInt(scope.width))
                  .attr('height', parseInt(scope.height))
                  .classed('timeline', true);

              canvas = timeline.append('svg')
                  .attr('width', parseInt(scope.width))
                  .attr('height', parseInt(scope.height) - 30);

              axis = d3.svg.axis()
                  .scale(x)
                  .orient("bottom")
                  .ticks(7)
                  .tickSize(10, 0);

              axisElement = timeline.append('svg')
                  .attr('y', parseInt(scope.height) - 30)
                  .attr('width', parseInt(scope.width))
                  .classed('axis', true)
                  .call(axis);

              var minZoom = (startXDomain[1] - startXDomain[0]) / (totalXDomain[1] - totalXDomain[0]);
              var maxZoom = startXDomain[1] - startXDomain[0];

              zoom = d3.behavior.zoom()
                  .x(x)
                  .scaleExtent([minZoom, maxZoom])
                  .on("zoom", function () {
                      axisElement.call(axis);
                      updateBars();
                  });

              drag = d3.behavior.drag()
                  .on("drag", function() {
                      var domain = y.domain();
                      domain[0] -= d3.event.dy;
                      domain[1] -= d3.event.dy;
                      y.domain(domain);
                      axisElement.call(axis);
                      updateBars();
                  });

              timeline.call(zoom).call(drag);

              tooltip = d3.select('body')
                  .append('div')
                  .classed('timeline-tooltip', true);

              bars = canvas.selectAll('g').data(periodsData).enter();
              barRects = bars.append('g')
                  .attr("class", function(d) { return "bar group" + d.colorGroup + " level" + (d.groupRow + 1) })
                  .append('rect')
                  .classed('bar', true)
                  .attr('rx','5')
                  .attr('ry','5')
                  .on('click', showPeriod);
              addTooltipBehavior(barRects);

              if (scope.selectedPeriodId) {
                  barRects.filter(function (d) {
                          return d.id == scope.selectedPeriodId;
                      })
                      .classed('selected', true);
              }

              barTexts = canvas.selectAll('g')
                  .append('text')
                  .classed('text', true)
                  .on('click', showPeriod);
              addTooltipBehavior(barTexts, tooltip);

              updateBars();
          }

          function updateBars() {
              barRects.attr('width', function(data) {
                      return x(data.to) - x(data.from);
                  })
                  .attr('height', barHeight)
                  .attr('x', function(data) {
                      return x(data.from);
                  })
                  .attr('y', function(data) {
                      return y(data.row) + data.row * (barHeight + 5);
                  });

              barTexts.attr('x', function(data) {
                      return x(data.from) + (x(data.to) - x(data.from)) / 2;
                  })
                  .attr('y', function(data) {
                      return y(data.row) + data.row * (barHeight + 5) + barHeight / 2 + 5;
                  })
                  .text(function(data) {
                      return data.name;
                  })
                  .text(function(data) {
                      if (this.getComputedTextLength() > x(data.to) - x(data.from)) {
                          data.textVisible = false;
                          return "";
                      }
                      else {
                          data.textVisible = true;
                          return data.name;
                      }
                  });

              axisElement.selectAll('.tick text')
                  .text(function() { return formatTickText(d3.select(this).text()); });

              removeOverlappingTicks(axisElement.selectAll('.tick'));
          }

          function showPeriod(period) {
              tooltip.style("visibility", "hidden");
              $location.path(period.id);
              scope.$apply();
          }

          function prepareData() {
              var periodsToDisplay = [];
              var periodsMap = {};

              for (var i in scope.periods) {
                  if (validatePeriod(scope.periods[i])) {
                      var label = "";
                      if (scope.periods[i].resource.prefLabel && scope.periods[i].resource.prefLabel.de)
                        label = scope.periods[i].resource.prefLabel.de;
                      var period = {
                          id: scope.periods[i]['@id'],
                          name: label,
                          from: parseInt(scope.periods[i].resource.hasTimespan[0].begin.at),
                          to: parseInt(scope.periods[i].resource.hasTimespan[0].end.at),
                          successor: scope.periods[i].resource.follows
                              ? scope.periods[i].resource.follows[0] : undefined,
                          children: scope.periods[i].resource.contains,
                          row: -1
                      };
                      if (!totalXDomain[0] || period.from < totalXDomain[0]) totalXDomain[0] = period.from;
                      if (!totalXDomain[1] || period.to > totalXDomain[1]) totalXDomain[1] = period.to;
                      periodsToDisplay.push(period);
                      periodsMap[period.id] = period;
                  }
              }

              determinePeriodRows(periodsToDisplay, periodsMap);

              var selectedPeriod;
              if (scope.selectedPeriodId && (selectedPeriod = periodsMap[scope.selectedPeriodId]))
                  setStartDomains(selectedPeriod);
              else {
                  startXDomain[0] = totalXDomain[0];
                  startXDomain[1] = totalXDomain[1];
                  startYDomain = [0, barHeight * 20];
              }

              return periodsToDisplay;
          }

          function validatePeriod(period) {
              // Check if the timespan of the period is defined
              if (!period.resource.hasTimespan || !period.resource.hasTimespan[0])
                  return false;<commit_msg>fixed children bug in timeline<commit_after>'use strict';

angular.module('chronontology.directives', [])

  .directive('timeline', function($location) {
    return {
      restrict: 'EA',
      scope: {
          periods: '=',
          selectedPeriodId: '=',
          height: '@'
      },
      templateUrl: 'partials/timeline.html',
      link: function(scope, element, attrs) {

          const barHeight = 20;
          const minYear = -10000;
          const maxYear = new Date().getFullYear();
          var bars, barRects, barTexts;
          var tooltip;
          var x, y;
          var totalXDomain = [];
          var startXDomain = [];
          var startYDomain = [];
          var timeline;
          var canvas;
          var axis, axisElement;
          var zoom, drag;

          scope.width = element[0].parentNode.clientWidth - 15;

          scope.$watch('periods', function() {
             if (scope.periods) initialize();
          });

          function initialize() {
              y = d3.scale.linear()
                  .domain([0, barHeight * 20])
                  .range([0, parseInt(scope.height) - 30]);

              var periodsData = prepareData();
              adjustStartXDomain();

              x = d3.scale.linear()
                  .domain(startXDomain)
                  .range([0, parseInt(scope.width)]);

              y.domain(startYDomain);

              timeline = d3.select('#timeline').append('svg')
                  .attr('width', parseInt(scope.width))
                  .attr('height', parseInt(scope.height))
                  .classed('timeline', true);

              canvas = timeline.append('svg')
                  .attr('width', parseInt(scope.width))
                  .attr('height', parseInt(scope.height) - 30);

              axis = d3.svg.axis()
                  .scale(x)
                  .orient("bottom")
                  .ticks(7)
                  .tickSize(10, 0);

              axisElement = timeline.append('svg')
                  .attr('y', parseInt(scope.height) - 30)
                  .attr('width', parseInt(scope.width))
                  .classed('axis', true)
                  .call(axis);

              var minZoom = (startXDomain[1] - startXDomain[0]) / (totalXDomain[1] - totalXDomain[0]);
              var maxZoom = startXDomain[1] - startXDomain[0];

              zoom = d3.behavior.zoom()
                  .x(x)
                  .scaleExtent([minZoom, maxZoom])
                  .on("zoom", function () {
                      axisElement.call(axis);
                      updateBars();
                  });

              drag = d3.behavior.drag()
                  .on("drag", function() {
                      var domain = y.domain();
                      domain[0] -= d3.event.dy;
                      domain[1] -= d3.event.dy;
                      y.domain(domain);
                      axisElement.call(axis);
                      updateBars();
                  });

              timeline.call(zoom).call(drag);

              tooltip = d3.select('body')
                  .append('div')
                  .classed('timeline-tooltip', true);

              bars = canvas.selectAll('g').data(periodsData).enter();
              barRects = bars.append('g')
                  .attr("class", function(d) { return "bar group" + d.colorGroup + " level" + (d.groupRow + 1) })
                  .append('rect')
                  .classed('bar', true)
                  .attr('rx','5')
                  .attr('ry','5')
                  .on('click', showPeriod);
              addTooltipBehavior(barRects);

              if (scope.selectedPeriodId) {
                  barRects.filter(function (d) {
                          return d.id == scope.selectedPeriodId;
                      })
                      .classed('selected', true);
              }

              barTexts = canvas.selectAll('g')
                  .append('text')
                  .classed('text', true)
                  .on('click', showPeriod);
              addTooltipBehavior(barTexts, tooltip);

              updateBars();
          }

          function updateBars() {
              barRects.attr('width', function(data) {
                      return x(data.to) - x(data.from);
                  })
                  .attr('height', barHeight)
                  .attr('x', function(data) {
                      return x(data.from);
                  })
                  .attr('y', function(data) {
                      return y(data.row) + data.row * (barHeight + 5);
                  });

              barTexts.attr('x', function(data) {
                      return x(data.from) + (x(data.to) - x(data.from)) / 2;
                  })
                  .attr('y', function(data) {
                      return y(data.row) + data.row * (barHeight + 5) + barHeight / 2 + 5;
                  })
                  .text(function(data) {
                      return data.name;
                  })
                  .text(function(data) {
                      if (this.getComputedTextLength() > x(data.to) - x(data.from)) {
                          data.textVisible = false;
                          return "";
                      }
                      else {
                          data.textVisible = true;
                          return data.name;
                      }
                  });

              axisElement.selectAll('.tick text')
                  .text(function() { return formatTickText(d3.select(this).text()); });

              removeOverlappingTicks(axisElement.selectAll('.tick'));
          }

          function showPeriod(period) {
              tooltip.style("visibility", "hidden");
              $location.path(period.id);
              scope.$apply();
          }

          function prepareData() {
              var periodsToDisplay = [];
              var periodsMap = {};

              for (var i in scope.periods) {
                  if (validatePeriod(scope.periods[i])) {
                      var label = "";
                      if (scope.periods[i].resource.prefLabel && scope.periods[i].resource.prefLabel.de)
                        label = scope.periods[i].resource.prefLabel.de;
                      var period = {
                          id: scope.periods[i]['@id'],
                          name: label,
                          from: parseInt(scope.periods[i].resource.hasTimespan[0].begin.at),
                          to: parseInt(scope.periods[i].resource.hasTimespan[0].end.at),
                          successor: scope.periods[i].resource.follows
                              ? scope.periods[i].resource.follows[0] : undefined,
                          children: scope.periods[i].resource.hasPart,
                          row: -1
                      };
                      if (!totalXDomain[0] || period.from < totalXDomain[0]) totalXDomain[0] = period.from;
                      if (!totalXDomain[1] || period.to > totalXDomain[1]) totalXDomain[1] = period.to;
                      periodsToDisplay.push(period);
                      periodsMap[period.id] = period;
                  }
              }

              determinePeriodRows(periodsToDisplay, periodsMap);

              var selectedPeriod;
              if (scope.selectedPeriodId && (selectedPeriod = periodsMap[scope.selectedPeriodId]))
                  setStartDomains(selectedPeriod);
              else {
                  startXDomain[0] = totalXDomain[0];
                  startXDomain[1] = totalXDomain[1];
                  startYDomain = [0, barHeight * 20];
              }

              return periodsToDisplay;
          }

          function validatePeriod(period) {
              // Check if the timespan of the period is defined
              if (!period.resource.hasTimespan || !period.resource.hasTimespan[0])
                  return false;
{'fraction_non_alphanumeric': 0.12491321088177744, 'fraction_numerical': 0.008773590860316859, 'mean_word_length': 1.18176810795924, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, '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': '1627904', 'n_tokens_mistral': 4184, 'n_tokens_neox': 3917, 'n_words': 698}