"use strict";
(globalThis["webpackChunksuperset"] = globalThis["webpackChunksuperset"] || []).push([[1243],{

/***/ 31243:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);

// EXPORTS
__webpack_require__.d(__webpack_exports__, {
  "default": () => (/* binding */ ReactParallelCoordinates)
});

// EXTERNAL MODULE: ./node_modules/react/index.js
var react = __webpack_require__(67294);
// EXTERNAL MODULE: ./node_modules/@superset-ui/core/esm/chart/components/reactify.js
var reactify = __webpack_require__(73834);
// EXTERNAL MODULE: ./node_modules/@superset-ui/core/esm/style/index.js
var style = __webpack_require__(37840);
// EXTERNAL MODULE: ./node_modules/prop-types/index.js
var prop_types = __webpack_require__(45697);
var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
// EXTERNAL MODULE: ./node_modules/d3/d3.js
var d3_d3 = __webpack_require__(15078);
var d3_default = /*#__PURE__*/__webpack_require__.n(d3_d3);
// EXTERNAL MODULE: ./node_modules/@superset-ui/core/esm/color/SequentialSchemeRegistrySingleton.js
var SequentialSchemeRegistrySingleton = __webpack_require__(67542);
;// CONCATENATED MODULE: ./node_modules/@superset-ui/legacy-plugin-chart-parallel-coordinates/esm/vendor/parcoords/d3.parcoords.js
/* [LICENSE TBD] */

/* eslint-disable */
/* harmony default export */ function d3_parcoords(config) {
  var __ = {
    data: [],
    highlighted: [],
    dimensions: [],
    dimensionTitles: {},
    dimensionTitleRotation: 0,
    types: {},
    brushed: false,
    brushedColor: null,
    alphaOnBrushed: 0.0,
    mode: 'default',
    rate: 20,
    width: 600,
    height: 300,
    margin: {
      top: 24,
      right: 0,
      bottom: 12,
      left: 0
    },
    nullValueSeparator: 'undefined',
    // set to "top" or "bottom"
    nullValueSeparatorPadding: {
      top: 8,
      right: 0,
      bottom: 8,
      left: 0
    },
    color: '#069',
    composite: 'source-over',
    alpha: 0.7,
    bundlingStrength: 0.5,
    bundleDimension: null,
    smoothness: 0.0,
    showControlPoints: false,
    hideAxis: []
  };
  extend(__, config);

  var pc = function (selection) {
    selection = pc.selection = d3.select(selection);
    __.width = selection[0][0].clientWidth;
    __.height = selection[0][0].clientHeight; // canvas data layers

    ['marks', 'foreground', 'brushed', 'highlight'].forEach(function (layer) {
      canvas[layer] = selection.append('canvas').attr('class', layer)[0][0];
      ctx[layer] = canvas[layer].getContext('2d');
    }); // svg tick and brush layers

    pc.svg = selection.append('svg').attr('width', __.width).attr('height', __.height).append('svg:g').attr('transform', 'translate(' + __.margin.left + ',' + __.margin.top + ')');
    return pc;
  };

  var events = d3.dispatch.apply(this, ['render', 'resize', 'highlight', 'brush', 'brushend', 'axesreorder'].concat(d3.keys(__))),
      w = function () {
    return __.width - __.margin.right - __.margin.left;
  },
      h = function () {
    return __.height - __.margin.top - __.margin.bottom;
  },
      flags = {
    brushable: false,
    reorderable: false,
    axes: false,
    interactive: false,
    debug: false
  },
      xscale = d3.scale.ordinal(),
      yscale = {},
      dragging = {},
      line = d3.svg.line(),
      axis = d3.svg.axis().orient('left').ticks(5),
      g,
      // groups for axes, brushes
  ctx = {},
      canvas = {},
      clusterCentroids = []; // side effects for setters


  var side_effects = d3.dispatch.apply(this, d3.keys(__)).on('composite', function (d) {
    ctx.foreground.globalCompositeOperation = d.value;
    ctx.brushed.globalCompositeOperation = d.value;
  }).on('alpha', function (d) {
    ctx.foreground.globalAlpha = d.value;
    ctx.brushed.globalAlpha = d.value;
  }).on('brushedColor', function (d) {
    ctx.brushed.strokeStyle = d.value;
  }).on('width', function (d) {
    pc.resize();
  }).on('height', function (d) {
    pc.resize();
  }).on('margin', function (d) {
    pc.resize();
  }).on('rate', function (d) {
    brushedQueue.rate(d.value);
    foregroundQueue.rate(d.value);
  }).on('dimensions', function (d) {
    xscale.domain(__.dimensions);

    if (flags.interactive) {
      pc.render().updateAxes();
    }
  }).on('bundleDimension', function (d) {
    if (!__.dimensions.length) pc.detectDimensions();
    if (!(__.dimensions[0] in yscale)) pc.autoscale();

    if (typeof d.value === 'number') {
      if (d.value < __.dimensions.length) {
        __.bundleDimension = __.dimensions[d.value];
      } else if (d.value < __.hideAxis.length) {
        __.bundleDimension = __.hideAxis[d.value];
      }
    } else {
      __.bundleDimension = d.value;
    }

    __.clusterCentroids = compute_cluster_centroids(__.bundleDimension);
  }).on('hideAxis', function (d) {
    if (!__.dimensions.length) pc.detectDimensions();
    pc.dimensions(without(__.dimensions, d.value));
  }); // expose the state of the chart

  pc.state = __;
  pc.flags = flags; // create getter/setters

  getset(pc, __, events); // expose events

  d3.rebind(pc, events, 'on'); // getter/setter with event firing

  function getset(obj, state, events) {
    d3.keys(state).forEach(function (key) {
      obj[key] = function (x) {
        if (!arguments.length) {
          return state[key];
        }

        var old = state[key];
        state[key] = x;
        side_effects[key].call(pc, {
          value: x,
          previous: old
        });
        events[key].call(pc, {
          value: x,
          previous: old
        });
        return obj;
      };
    });
  }

  function extend(target, source) {
    for (var key in source) {
      target[key] = source[key];
    }

    return target;
  }

  function without(arr, item) {
    return arr.filter(function (elem) {
      return item.indexOf(elem) === -1;
    });
  }
  /** adjusts an axis' default range [h()+1, 1] if a NullValueSeparator is set */


  function getRange() {
    if (__.nullValueSeparator == 'bottom') {
      return [h() + 1 - __.nullValueSeparatorPadding.bottom - __.nullValueSeparatorPadding.top, 1];
    } else if (__.nullValueSeparator == 'top') {
      return [h() + 1, 1 + __.nullValueSeparatorPadding.bottom + __.nullValueSeparatorPadding.top];
    }

    return [h() + 1, 1];
  }

  pc.autoscale = function () {
    // yscale
    var defaultScales = {
      date: function (k) {
        var extent = d3.extent(__.data, function (d) {
          return d[k] ? d[k].getTime() : null;
        }); // special case if single value

        if (extent[0] === extent[1]) {
          return d3.scale.ordinal().domain([extent[0]]).rangePoints(getRange());
        }

        return d3.time.scale().domain(extent).range(getRange());
      },
      number: function (k) {
        var extent = d3.extent(__.data, function (d) {
          return +d[k];
        }); // special case if single value

        if (extent[0] === extent[1]) {
          return d3.scale.ordinal().domain([extent[0]]).rangePoints(getRange());
        }

        return d3.scale.linear().domain(extent).range(getRange());
      },
      string: function (k) {
        var counts = {},
            domain = []; // Let's get the count for each value so that we can sort the domain based
        // on the number of items for each value.

        __.data.map(function (p) {
          if (p[k] === undefined && __.nullValueSeparator !== 'undefined') {
            return; // null values will be drawn beyond the horizontal null value separator!
          }

          if (counts[p[k]] === undefined) {
            counts[p[k]] = 1;
          } else {
            counts[p[k]] = counts[p[k]] + 1;
          }
        });

        domain = Object.getOwnPropertyNames(counts).sort(function (a, b) {
          return counts[a] - counts[b];
        });
        return d3.scale.ordinal().domain(domain).rangePoints(getRange());
      }
    };

    __.dimensions.forEach(function (k) {
      yscale[k] = defaultScales[__.types[k]](k);
    });

    __.hideAxis.forEach(function (k) {
      yscale[k] = defaultScales[__.types[k]](k);
    }); // xscale


    xscale.rangePoints([0, w()], 1); // canvas sizes

    pc.selection.selectAll('canvas').style('margin-top', __.margin.top + 'px').style('margin-left', __.margin.left + 'px').attr('width', w() + 2).attr('height', h() + 2); // default styles, needs to be set when canvas width changes

    ctx.foreground.strokeStyle = __.color;
    ctx.foreground.lineWidth = 1.4;
    ctx.foreground.globalCompositeOperation = __.composite;
    ctx.foreground.globalAlpha = __.alpha;
    ctx.brushed.strokeStyle = __.brushedColor;
    ctx.brushed.lineWidth = 1.4;
    ctx.brushed.globalCompositeOperation = __.composite;
    ctx.brushed.globalAlpha = __.alpha;
    ctx.highlight.lineWidth = 3;
    return this;
  };

  pc.scale = function (d, domain) {
    yscale[d].domain(domain);
    return this;
  };

  pc.flip = function (d) {
    //yscale[d].domain().reverse();         // does not work
    yscale[d].domain(yscale[d].domain().reverse()); // works

    return this;
  };

  pc.commonScale = function (global, type) {
    var t = type || 'number';

    if (typeof global === 'undefined') {
      global = true;
    } // scales of the same type


    var scales = __.dimensions.concat(__.hideAxis).filter(function (p) {
      return __.types[p] == t;
    });

    if (global) {
      var extent = d3.extent(scales.map(function (p, i) {
        return yscale[p].domain();
      }).reduce(function (a, b) {
        return a.concat(b);
      }));
      scales.forEach(function (d) {
        yscale[d].domain(extent);
      });
    } else {
      scales.forEach(function (k) {
        yscale[k].domain(d3.extent(__.data, function (d) {
          return +d[k];
        }));
      });
    } // update centroids


    if (__.bundleDimension !== null) {
      pc.bundleDimension(__.bundleDimension);
    }

    return this;
  };

  pc.detectDimensions = function () {
    pc.types(pc.detectDimensionTypes(__.data));
    pc.dimensions(d3.keys(pc.types()));
    return this;
  }; // a better "typeof" from this post: http://stackoverflow.com/questions/7390426/better-way-to-get-type-of-a-javascript-variable


  pc.toType = function (v) {
    return {}.toString.call(v).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
  }; // try to coerce to number before returning type


  pc.toTypeCoerceNumbers = function (v) {
    if (parseFloat(v) == v && v != null) {
      return 'number';
    }

    return pc.toType(v);
  }; // attempt to determine types of each dimension based on first row of data


  pc.detectDimensionTypes = function (data) {
    var types = {};
    d3.keys(data[0]).forEach(function (col) {
      types[col] = pc.toTypeCoerceNumbers(data[0][col]);
    });
    return types;
  };

  pc.render = function () {
    // try to autodetect dimensions and create scales
    if (!__.dimensions.length) pc.detectDimensions();
    if (!(__.dimensions[0] in yscale)) pc.autoscale();

    pc.render[__.mode]();

    events.render.call(this);
    return this;
  };

  pc.renderBrushed = function () {
    if (!__.dimensions.length) pc.detectDimensions();
    if (!(__.dimensions[0] in yscale)) pc.autoscale();

    pc.renderBrushed[__.mode]();

    events.render.call(this);
    return this;
  };

  function isBrushed() {
    if (__.brushed && __.brushed.length !== __.data.length) return true;
    var object = brush.currentMode().brushState();

    for (var key in object) {
      if (object.hasOwnProperty(key)) {
        return true;
      }
    }

    return false;
  }

  pc.render.default = function () {
    pc.clear('foreground');
    pc.clear('highlight');
    pc.renderBrushed.default();

    __.data.forEach(path_foreground);
  };

  var foregroundQueue = d3.renderQueue(path_foreground).rate(50).clear(function () {
    pc.clear('foreground');
    pc.clear('highlight');
  });

  pc.render.queue = function () {
    pc.renderBrushed.queue();
    foregroundQueue(__.data);
  };

  pc.renderBrushed.default = function () {
    pc.clear('brushed');

    if (isBrushed()) {
      __.brushed.forEach(path_brushed);
    }
  };

  var brushedQueue = d3.renderQueue(path_brushed).rate(50).clear(function () {
    pc.clear('brushed');
  });

  pc.renderBrushed.queue = function () {
    if (isBrushed()) {
      brushedQueue(__.brushed);
    } else {
      brushedQueue([]); // This is needed to clear the currently brushed items
    }
  };

  function compute_cluster_centroids(d) {
    var clusterCentroids = d3.map();
    var clusterCounts = d3.map(); // determine clusterCounts

    __.data.forEach(function (row) {
      var scaled = yscale[d](row[d]);

      if (!clusterCounts.has(scaled)) {
        clusterCounts.set(scaled, 0);
      }

      var count = clusterCounts.get(scaled);
      clusterCounts.set(scaled, count + 1);
    });

    __.data.forEach(function (row) {
      __.dimensions.map(function (p, i) {
        var scaled = yscale[d](row[d]);

        if (!clusterCentroids.has(scaled)) {
          var map = d3.map();
          clusterCentroids.set(scaled, map);
        }

        if (!clusterCentroids.get(scaled).has(p)) {
          clusterCentroids.get(scaled).set(p, 0);
        }

        var value = clusterCentroids.get(scaled).get(p);
        value += yscale[p](row[p]) / clusterCounts.get(scaled);
        clusterCentroids.get(scaled).set(p, value);
      });
    });

    return clusterCentroids;
  }

  function compute_centroids(row) {
    var centroids = [];
    var p = __.dimensions;
    var cols = p.length;
    var a = 0.5; // center between axes

    for (var i = 0; i < cols; ++i) {
      // centroids on 'real' axes
      var x = position(p[i]);
      var y = yscale[p[i]](row[p[i]]);
      centroids.push($V([x, y])); // centroids on 'virtual' axes

      if (i < cols - 1) {
        var cx = x + a * (position(p[i + 1]) - x);
        var cy = y + a * (yscale[p[i + 1]](row[p[i + 1]]) - y);

        if (__.bundleDimension !== null) {
          var leftCentroid = __.clusterCentroids.get(yscale[__.bundleDimension](row[__.bundleDimension])).get(p[i]);

          var rightCentroid = __.clusterCentroids.get(yscale[__.bundleDimension](row[__.bundleDimension])).get(p[i + 1]);

          var centroid = 0.5 * (leftCentroid + rightCentroid);
          cy = centroid + (1 - __.bundlingStrength) * (cy - centroid);
        }

        centroids.push($V([cx, cy]));
      }
    }

    return centroids;
  }

  function compute_control_points(centroids) {
    var cols = centroids.length;
    var a = __.smoothness;
    var cps = [];
    cps.push(centroids[0]);
    cps.push($V([centroids[0].e(1) + a * 2 * (centroids[1].e(1) - centroids[0].e(1)), centroids[0].e(2)]));

    for (var col = 1; col < cols - 1; ++col) {
      var mid = centroids[col];
      var left = centroids[col - 1];
      var right = centroids[col + 1];
      var diff = left.subtract(right);
      cps.push(mid.add(diff.x(a)));
      cps.push(mid);
      cps.push(mid.subtract(diff.x(a)));
    }

    cps.push($V([centroids[cols - 1].e(1) + a * 2 * (centroids[cols - 2].e(1) - centroids[cols - 1].e(1)), centroids[cols - 1].e(2)]));
    cps.push(centroids[cols - 1]);
    return cps;
  }

  pc.shadows = function () {
    flags.shadows = true;
    pc.alphaOnBrushed(0.1);
    pc.render();
    return this;
  }; // draw dots with radius r on the axis line where data intersects


  pc.axisDots = function (r) {
    var r = r || 0.1;
    var ctx = pc.ctx.marks;
    var startAngle = 0;
    var endAngle = 2 * Math.PI;
    ctx.globalAlpha = d3.min([1 / Math.pow(__.data.length, 1 / 2), 1]);

    __.data.forEach(function (d) {
      __.dimensions.map(function (p, i) {
        ctx.beginPath();
        ctx.arc(position(p), yscale[p](d[p]), r, startAngle, endAngle);
        ctx.stroke();
        ctx.fill();
      });
    });

    return this;
  }; // draw single cubic bezier curve


  function single_curve(d, ctx) {
    var centroids = compute_centroids(d);
    var cps = compute_control_points(centroids);
    ctx.moveTo(cps[0].e(1), cps[0].e(2));

    for (var i = 1; i < cps.length; i += 3) {
      if (__.showControlPoints) {
        for (var j = 0; j < 3; j += 1) {
          ctx.fillRect(cps[i + j].e(1), cps[i + j].e(2), 2, 2);
        }
      }

      ctx.bezierCurveTo(cps[i].e(1), cps[i].e(2), cps[i + 1].e(1), cps[i + 1].e(2), cps[i + 2].e(1), cps[i + 2].e(2));
    }
  } // draw single polyline


  function color_path(d, ctx) {
    ctx.beginPath();

    if (__.bundleDimension !== null && __.bundlingStrength > 0 || __.smoothness > 0) {
      single_curve(d, ctx);
    } else {
      single_path(d, ctx);
    }

    ctx.stroke();
  } // draw many polylines of the same color


  function paths(data, ctx) {
    ctx.clearRect(-1, -1, w() + 2, h() + 2);
    ctx.beginPath();
    data.forEach(function (d) {
      if (__.bundleDimension !== null && __.bundlingStrength > 0 || __.smoothness > 0) {
        single_curve(d, ctx);
      } else {
        single_path(d, ctx);
      }
    });
    ctx.stroke();
  } // returns the y-position just beyond the separating null value line


  function getNullPosition() {
    if (__.nullValueSeparator == 'bottom') {
      return h() + 1;
    } else if (__.nullValueSeparator == 'top') {
      return 1;
    } else {
      console.log("A value is NULL, but nullValueSeparator is not set; set it to 'bottom' or 'top'.");
    }

    return h() + 1;
  }

  function single_path(d, ctx) {
    __.dimensions.map(function (p, i) {
      if (i == 0) {
        ctx.moveTo(position(p), typeof d[p] == 'undefined' ? getNullPosition() : yscale[p](d[p]));
      } else {
        ctx.lineTo(position(p), typeof d[p] == 'undefined' ? getNullPosition() : yscale[p](d[p]));
      }
    });
  }

  function path_brushed(d, i) {
    if (__.brushedColor !== null) {
      ctx.brushed.strokeStyle = d3.functor(__.brushedColor)(d, i);
    } else {
      ctx.brushed.strokeStyle = d3.functor(__.color)(d, i);
    }

    return color_path(d, ctx.brushed);
  }

  function path_foreground(d, i) {
    ctx.foreground.strokeStyle = d3.functor(__.color)(d, i);
    return color_path(d, ctx.foreground);
  }

  function path_highlight(d, i) {
    ctx.highlight.strokeStyle = d3.functor(__.color)(d, i);
    return color_path(d, ctx.highlight);
  }

  pc.clear = function (layer) {
    ctx[layer].clearRect(0, 0, w() + 2, h() + 2); // This will make sure that the foreground items are transparent
    // without the need for changing the opacity style of the foreground canvas
    // as this would stop the css styling from working

    if (layer === 'brushed' && isBrushed()) {
      ctx.brushed.fillStyle = pc.selection.style('background-color');
      ctx.brushed.globalAlpha = 1 - __.alphaOnBrushed;
      ctx.brushed.fillRect(0, 0, w() + 2, h() + 2);
      ctx.brushed.globalAlpha = __.alpha;
    }

    return this;
  };

  d3.rebind(pc, axis, 'ticks', 'orient', 'tickValues', 'tickSubdivide', 'tickSize', 'tickPadding', 'tickFormat');

  function flipAxisAndUpdatePCP(dimension) {
    var g = pc.svg.selectAll('.dimension');
    pc.flip(dimension);
    d3.select(this.parentElement).transition().duration(1100).call(axis.scale(yscale[dimension]));
    pc.render();
  }

  function rotateLabels() {
    var delta = d3.event.deltaY;
    delta = delta < 0 ? -5 : delta;
    delta = delta > 0 ? 5 : delta;
    __.dimensionTitleRotation += delta;
    pc.svg.selectAll('text.label').attr('transform', 'translate(0,-5) rotate(' + __.dimensionTitleRotation + ')');
    d3.event.preventDefault();
  }

  function dimensionLabels(d) {
    return d in __.dimensionTitles ? __.dimensionTitles[d] : d; // dimension display names
  }

  pc.createAxes = function () {
    if (g) pc.removeAxes(); // Add a group element for each dimension.

    g = pc.svg.selectAll('.dimension').data(__.dimensions, function (d) {
      return d;
    }).enter().append('svg:g').attr('class', 'dimension').attr('transform', function (d) {
      return 'translate(' + xscale(d) + ')';
    }); // Add an axis and title.

    g.append('svg:g').attr('class', 'axis').attr('transform', 'translate(0,0)').each(function (d) {
      d3.select(this).call(axis.scale(yscale[d]));
    }).append('svg:text').attr({
      'text-anchor': 'middle',
      y: 0,
      transform: 'translate(0,-5) rotate(' + __.dimensionTitleRotation + ')',
      x: 0,
      class: 'label'
    }).text(dimensionLabels).on('dblclick', flipAxisAndUpdatePCP).on('wheel', rotateLabels);

    if (__.nullValueSeparator == 'top') {
      pc.svg.append('line').attr('x1', 0).attr('y1', 1 + __.nullValueSeparatorPadding.top).attr('x2', w()).attr('y2', 1 + __.nullValueSeparatorPadding.top).attr('stroke-width', 1).attr('stroke', '#777').attr('fill', 'none').attr('shape-rendering', 'crispEdges');
    } else if (__.nullValueSeparator == 'bottom') {
      pc.svg.append('line').attr('x1', 0).attr('y1', h() + 1 - __.nullValueSeparatorPadding.bottom).attr('x2', w()).attr('y2', h() + 1 - __.nullValueSeparatorPadding.bottom).attr('stroke-width', 1).attr('stroke', '#777').attr('fill', 'none').attr('shape-rendering', 'crispEdges');
    }

    flags.axes = true;
    return this;
  };

  pc.removeAxes = function () {
    g.remove();
    return this;
  };

  pc.updateAxes = function () {
    var g_data = pc.svg.selectAll('.dimension').data(__.dimensions); // Enter

    g_data.enter().append('svg:g').attr('class', 'dimension').attr('transform', function (p) {
      return 'translate(' + position(p) + ')';
    }).style('opacity', 0).append('svg:g').attr('class', 'axis').attr('transform', 'translate(0,0)').each(function (d) {
      d3.select(this).call(axis.scale(yscale[d]));
    }).append('svg:text').attr({
      'text-anchor': 'middle',
      y: 0,
      transform: 'translate(0,-5) rotate(' + __.dimensionTitleRotation + ')',
      x: 0,
      class: 'label'
    }).text(dimensionLabels).on('dblclick', flipAxisAndUpdatePCP).on('wheel', rotateLabels); // Update

    g_data.attr('opacity', 0);
    g_data.select('.axis').transition().duration(1100).each(function (d) {
      d3.select(this).call(axis.scale(yscale[d]));
    });
    g_data.select('.label').transition().duration(1100).text(dimensionLabels).attr('transform', 'translate(0,-5) rotate(' + __.dimensionTitleRotation + ')'); // Exit

    g_data.exit().remove();
    g = pc.svg.selectAll('.dimension');
    g.transition().duration(1100).attr('transform', function (p) {
      return 'translate(' + position(p) + ')';
    }).style('opacity', 1);
    pc.svg.selectAll('.axis').transition().duration(1100).each(function (d) {
      d3.select(this).call(axis.scale(yscale[d]));
    });
    if (flags.brushable) pc.brushable();
    if (flags.reorderable) pc.reorderable();

    if (pc.brushMode() !== 'None') {
      var mode = pc.brushMode();
      pc.brushMode('None');
      pc.brushMode(mode);
    }

    return this;
  }; // Jason Davies, http://bl.ocks.org/1341281


  pc.reorderable = function () {
    if (!g) pc.createAxes();
    g.style('cursor', 'move').call(d3.behavior.drag().on('dragstart', function (d) {
      dragging[d] = this.__origin__ = xscale(d);
    }).on('drag', function (d) {
      dragging[d] = Math.min(w(), Math.max(0, this.__origin__ += d3.event.dx));

      __.dimensions.sort(function (a, b) {
        return position(a) - position(b);
      });

      xscale.domain(__.dimensions);
      pc.render();
      g.attr('transform', function (d) {
        return 'translate(' + position(d) + ')';
      });
    }).on('dragend', function (d) {
      // Let's see if the order has changed and send out an event if so.
      var i = 0,
          j = __.dimensions.indexOf(d),
          elem = this,
          parent = this.parentElement;

      while ((elem = elem.previousElementSibling) != null) ++i;

      if (i !== j) {
        events.axesreorder.call(pc, __.dimensions); // We now also want to reorder the actual dom elements that represent
        // the axes. That is, the g.dimension elements. If we don't do this,
        // we get a weird and confusing transition when updateAxes is called.
        // This is due to the fact that, initially the nth g.dimension element
        // represents the nth axis. However, after a manual reordering,
        // without reordering the dom elements, the nth dom elements no longer
        // necessarily represents the nth axis.
        //
        // i is the original index of the dom element
        // j is the new index of the dom element

        if (i > j) {
          // Element moved left
          parent.insertBefore(this, parent.children[j - 1]);
        } else {
          // Element moved right
          if (j + 1 < parent.children.length) {
            parent.insertBefore(this, parent.children[j + 1]);
          } else {
            parent.appendChild(this);
          }
        }
      }

      delete this.__origin__;
      delete dragging[d];
      d3.select(this).transition().attr('transform', 'translate(' + xscale(d) + ')');
      pc.render();
    }));
    flags.reorderable = true;
    return this;
  }; // Reorder dimensions, such that the highest value (visually) is on the left and
  // the lowest on the right. Visual values are determined by the data values in
  // the given row.


  pc.reorder = function (rowdata) {
    var dims = __.dimensions.slice(0);

    __.dimensions.sort(function (a, b) {
      var pixelDifference = yscale[a](rowdata[a]) - yscale[b](rowdata[b]); // Array.sort is not necessarily stable, this means that if pixelDifference is zero
      // the ordering of dimensions might change unexpectedly. This is solved by sorting on
      // variable name in that case.

      if (pixelDifference === 0) {
        return a.localeCompare(b);
      } // else


      return pixelDifference;
    }); // NOTE: this is relatively cheap given that:
    // number of dimensions < number of data items
    // Thus we check equality of order to prevent rerendering when this is the case.


    var reordered = false;
    dims.some(function (val, index) {
      reordered = val !== __.dimensions[index];
      return reordered;
    });

    if (reordered) {
      xscale.domain(__.dimensions);

      var highlighted = __.highlighted.slice(0);

      pc.unhighlight();
      g.transition().duration(1500).attr('transform', function (d) {
        return 'translate(' + xscale(d) + ')';
      });
      pc.render(); // pc.highlight() does not check whether highlighted is length zero, so we do that here.

      if (highlighted.length !== 0) {
        pc.highlight(highlighted);
      }
    }
  }; // pairs of adjacent dimensions


  pc.adjacent_pairs = function (arr) {
    var ret = [];

    for (var i = 0; i < arr.length - 1; i += 1) {
      ret.push([arr[i], arr[i + 1]]);
    }

    return ret;
  };

  var brush = {
    modes: {
      None: {
        install: function (pc) {},
        // Nothing to be done.
        uninstall: function (pc) {},
        // Nothing to be done.
        selected: function () {
          return [];
        },
        // Nothing to return
        brushState: function () {
          return {};
        }
      }
    },
    mode: 'None',
    predicate: 'AND',
    currentMode: function () {
      return this.modes[this.mode];
    }
  }; // This function can be used for 'live' updates of brushes. That is, during the
  // specification of a brush, this method can be called to update the view.
  //
  // @param newSelection - The new set of data items that is currently contained
  //                       by the brushes

  function brushUpdated(newSelection) {
    __.brushed = newSelection;
    events.brush.call(pc, __.brushed);
    pc.renderBrushed();
  }

  function brushPredicate(predicate) {
    if (!arguments.length) {
      return brush.predicate;
    }

    predicate = String(predicate).toUpperCase();

    if (predicate !== 'AND' && predicate !== 'OR') {
      throw 'Invalid predicate ' + predicate;
    }

    brush.predicate = predicate;
    __.brushed = brush.currentMode().selected();
    pc.renderBrushed();
    return pc;
  }

  pc.brushModes = function () {
    return Object.getOwnPropertyNames(brush.modes);
  };

  pc.brushMode = function (mode) {
    if (arguments.length === 0) {
      return brush.mode;
    }

    if (pc.brushModes().indexOf(mode) === -1) {
      throw 'pc.brushmode: Unsupported brush mode: ' + mode;
    } // Make sure that we don't trigger unnecessary events by checking if the mode
    // actually changes.


    if (mode !== brush.mode) {
      // When changing brush modes, the first thing we need to do is clearing any
      // brushes from the current mode, if any.
      if (brush.mode !== 'None') {
        pc.brushReset();
      } // Next, we need to 'uninstall' the current brushMode.


      brush.modes[brush.mode].uninstall(pc); // Finally, we can install the requested one.

      brush.mode = mode;
      brush.modes[brush.mode].install();

      if (mode === 'None') {
        delete pc.brushPredicate;
      } else {
        pc.brushPredicate = brushPredicate;
      }
    }

    return pc;
  }; // brush mode: 1D-Axes


  (function () {
    var brushes = {};

    function is_brushed(p) {
      return !brushes[p].empty();
    } // data within extents


    function selected() {
      var actives = __.dimensions.filter(is_brushed),
          extents = actives.map(function (p) {
        return brushes[p].extent();
      }); // We don't want to return the full data set when there are no axes brushed.
      // Actually, when there are no axes brushed, by definition, no items are
      // selected. So, let's avoid the filtering and just return false.
      //if (actives.length === 0) return false;
      // Resolves broken examples for now. They expect to get the full dataset back from empty brushes


      if (actives.length === 0) return __.data; // test if within range

      var within = {
        date: function (d, p, dimension) {
          if (typeof yscale[p].rangePoints === 'function') {
            // if it is ordinal
            return extents[dimension][0] <= yscale[p](d[p]) && yscale[p](d[p]) <= extents[dimension][1];
          } else {
            return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1];
          }
        },
        number: function (d, p, dimension) {
          if (typeof yscale[p].rangePoints === 'function') {
            // if it is ordinal
            return extents[dimension][0] <= yscale[p](d[p]) && yscale[p](d[p]) <= extents[dimension][1];
          } else {
            return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1];
          }
        },
        string: function (d, p, dimension) {
          return extents[dimension][0] <= yscale[p](d[p]) && yscale[p](d[p]) <= extents[dimension][1];
        }
      };
      return __.data.filter(function (d) {
        switch (brush.predicate) {
          case 'AND':
            return actives.every(function (p, dimension) {
              return within[__.types[p]](d, p, dimension);
            });

          case 'OR':
            return actives.some(function (p, dimension) {
              return within[__.types[p]](d, p, dimension);
            });

          default:
            throw 'Unknown brush predicate ' + __.brushPredicate;
        }
      });
    }

    function brushExtents(extents) {
      if (typeof extents === 'undefined') {
        var extents = {};

        __.dimensions.forEach(function (d) {
          var brush = brushes[d];

          if (brush !== undefined && !brush.empty()) {
            var extent = brush.extent();
            extent.sort(d3.ascending);
            extents[d] = extent;
          }
        });

        return extents;
      } else {
        //first get all the brush selections
        var brushSelections = {};
        g.selectAll('.brush').each(function (d) {
          brushSelections[d] = d3.select(this);
        }); // loop over each dimension and update appropriately (if it was passed in through extents)

        __.dimensions.forEach(function (d) {
          if (extents[d] === undefined) {
            return;
          }

          var brush = brushes[d];

          if (brush !== undefined) {
            //update the extent
            brush.extent(extents[d]); //redraw the brush

            brush(brushSelections[d]); //fire some events

            brush.event(brushSelections[d]);
          }
        }); //redraw the chart


        pc.renderBrushed();
      }
    }

    function brushFor(axis) {
      var brush = d3.svg.brush();
      brush.y(yscale[axis]).on('brushstart', function () {
        if (d3.event.sourceEvent !== null) {
          d3.event.sourceEvent.stopPropagation();
        }
      }).on('brush', function () {
        brushUpdated(selected());
      }).on('brushend', function () {
        events.brushend.call(pc, __.brushed);
      });
      brushes[axis] = brush;
      return brush;
    }

    function brushReset(dimension) {
      __.brushed = false;

      if (g) {
        g.selectAll('.brush').each(function (d) {
          d3.select(this).call(brushes[d].clear());
        });
        pc.renderBrushed();
      }

      return this;
    }

    function install() {
      if (!g) pc.createAxes(); // Add and store a brush for each axis.

      g.append('svg:g').attr('class', 'brush').each(function (d) {
        d3.select(this).call(brushFor(d));
      }).selectAll('rect').style('visibility', null).attr('x', -15).attr('width', 30);
      pc.brushExtents = brushExtents;
      pc.brushReset = brushReset;
      return pc;
    }

    brush.modes['1D-axes'] = {
      install: install,
      uninstall: function () {
        g.selectAll('.brush').remove();
        brushes = {};
        delete pc.brushExtents;
        delete pc.brushReset;
      },
      selected: selected,
      brushState: brushExtents
    };
  })(); // brush mode: 2D-strums
  // bl.ocks.org/syntagmatic/5441022


  (function () {
    var strums = {},
        strumRect;

    function drawStrum(strum, activePoint) {
      var svg = pc.selection.select('svg').select('g#strums'),
          id = strum.dims.i,
          points = [strum.p1, strum.p2],
          line = svg.selectAll('line#strum-' + id).data([strum]),
          circles = svg.selectAll('circle#strum-' + id).data(points),
          drag = d3.behavior.drag();
      line.enter().append('line').attr('id', 'strum-' + id).attr('class', 'strum');
      line.attr('x1', function (d) {
        return d.p1[0];
      }).attr('y1', function (d) {
        return d.p1[1];
      }).attr('x2', function (d) {
        return d.p2[0];
      }).attr('y2', function (d) {
        return d.p2[1];
      }).attr('stroke', 'black').attr('stroke-width', 2);
      drag.on('drag', function (d, i) {
        var ev = d3.event;
        i = i + 1;
        strum['p' + i][0] = Math.min(Math.max(strum.minX + 1, ev.x), strum.maxX);
        strum['p' + i][1] = Math.min(Math.max(strum.minY, ev.y), strum.maxY);
        drawStrum(strum, i - 1);
      }).on('dragend', onDragEnd());
      circles.enter().append('circle').attr('id', 'strum-' + id).attr('class', 'strum');
      circles.attr('cx', function (d) {
        return d[0];
      }).attr('cy', function (d) {
        return d[1];
      }).attr('r', 5).style('opacity', function (d, i) {
        return activePoint !== undefined && i === activePoint ? 0.8 : 0;
      }).on('mouseover', function () {
        d3.select(this).style('opacity', 0.8);
      }).on('mouseout', function () {
        d3.select(this).style('opacity', 0);
      }).call(drag);
    }

    function dimensionsForPoint(p) {
      var dims = {
        i: -1,
        left: undefined,
        right: undefined
      };

      __.dimensions.some(function (dim, i) {
        if (xscale(dim) < p[0]) {
          var next = __.dimensions[i + 1];
          dims.i = i;
          dims.left = dim;
          dims.right = next;
          return false;
        }

        return true;
      });

      if (dims.left === undefined) {
        // Event on the left side of the first axis.
        dims.i = 0;
        dims.left = __.dimensions[0];
        dims.right = __.dimensions[1];
      } else if (dims.right === undefined) {
        // Event on the right side of the last axis
        dims.i = __.dimensions.length - 1;
        dims.right = dims.left;
        dims.left = __.dimensions[__.dimensions.length - 2];
      }

      return dims;
    }

    function onDragStart() {
      // First we need to determine between which two axes the sturm was started.
      // This will determine the freedom of movement, because a strum can
      // logically only happen between two axes, so no movement outside these axes
      // should be allowed.
      return function () {
        var p = d3.mouse(strumRect[0][0]),
            dims,
            strum;
        p[0] = p[0] - __.margin.left;
        p[1] = p[1] - __.margin.top;
        dims = dimensionsForPoint(p), strum = {
          p1: p,
          dims: dims,
          minX: xscale(dims.left),
          maxX: xscale(dims.right),
          minY: 0,
          maxY: h()
        };
        strums[dims.i] = strum;
        strums.active = dims.i; // Make sure that the point is within the bounds

        strum.p1[0] = Math.min(Math.max(strum.minX, p[0]), strum.maxX);
        strum.p2 = strum.p1.slice();
      };
    }

    function onDrag() {
      return function () {
        var ev = d3.event,
            strum = strums[strums.active]; // Make sure that the point is within the bounds

        strum.p2[0] = Math.min(Math.max(strum.minX + 1, ev.x - __.margin.left), strum.maxX);
        strum.p2[1] = Math.min(Math.max(strum.minY, ev.y - __.margin.top), strum.maxY);
        drawStrum(strum, 1);
      };
    }

    function containmentTest(strum, width) {
      var p1 = [strum.p1[0] - strum.minX, strum.p1[1] - strum.minX],
          p2 = [strum.p2[0] - strum.minX, strum.p2[1] - strum.minX],
          m1 = 1 - width / p1[0],
          b1 = p1[1] * (1 - m1),
          m2 = 1 - width / p2[0],
          b2 = p2[1] * (1 - m2); // test if point falls between lines

      return function (p) {
        var x = p[0],
            y = p[1],
            y1 = m1 * x + b1,
            y2 = m2 * x + b2;

        if (y > Math.min(y1, y2) && y < Math.max(y1, y2)) {
          return true;
        }

        return false;
      };
    }

    function selected() {
      var ids = Object.getOwnPropertyNames(strums),
          brushed = __.data; // Get the ids of the currently active strums.

      ids = ids.filter(function (d) {
        return !isNaN(d);
      });

      function crossesStrum(d, id) {
        var strum = strums[id],
            test = containmentTest(strum, strums.width(id)),
            d1 = strum.dims.left,
            d2 = strum.dims.right,
            y1 = yscale[d1],
            y2 = yscale[d2],
            point = [y1(d[d1]) - strum.minX, y2(d[d2]) - strum.minX];
        return test(point);
      }

      if (ids.length === 0) {
        return brushed;
      }

      return brushed.filter(function (d) {
        switch (brush.predicate) {
          case 'AND':
            return ids.every(function (id) {
              return crossesStrum(d, id);
            });

          case 'OR':
            return ids.some(function (id) {
              return crossesStrum(d, id);
            });

          default:
            throw 'Unknown brush predicate ' + __.brushPredicate;
        }
      });
    }

    function removeStrum() {
      var strum = strums[strums.active],
          svg = pc.selection.select('svg').select('g#strums');
      delete strums[strums.active];
      strums.active = undefined;
      svg.selectAll('line#strum-' + strum.dims.i).remove();
      svg.selectAll('circle#strum-' + strum.dims.i).remove();
    }

    function onDragEnd() {
      return function () {
        var brushed = __.data,
            strum = strums[strums.active]; // Okay, somewhat unexpected, but not totally unsurprising, a mousclick is
        // considered a drag without move. So we have to deal with that case

        if (strum && strum.p1[0] === strum.p2[0] && strum.p1[1] === strum.p2[1]) {
          removeStrum(strums);
        }

        brushed = selected(strums);
        strums.active = undefined;
        __.brushed = brushed;
        pc.renderBrushed();
        events.brushend.call(pc, __.brushed);
      };
    }

    function brushReset(strums) {
      return function () {
        var ids = Object.getOwnPropertyNames(strums).filter(function (d) {
          return !isNaN(d);
        });
        ids.forEach(function (d) {
          strums.active = d;
          removeStrum(strums);
        });
        onDragEnd(strums)();
      };
    }

    function install() {
      var drag = d3.behavior.drag(); // Map of current strums. Strums are stored per segment of the PC. A segment,
      // being the area between two axes. The left most area is indexed at 0.

      strums.active = undefined; // Returns the width of the PC segment where currently a strum is being
      // placed. NOTE: even though they are evenly spaced in our current
      // implementation, we keep for when non-even spaced segments are supported as
      // well.

      strums.width = function (id) {
        var strum = strums[id];

        if (strum === undefined) {
          return undefined;
        }

        return strum.maxX - strum.minX;
      };

      pc.on('axesreorder.strums', function () {
        var ids = Object.getOwnPropertyNames(strums).filter(function (d) {
          return !isNaN(d);
        }); // Checks if the first dimension is directly left of the second dimension.

        function consecutive(first, second) {
          var length = __.dimensions.length;
          return __.dimensions.some(function (d, i) {
            return d === first ? i + i < length && __.dimensions[i + 1] === second : false;
          });
        }

        if (ids.length > 0) {
          // We have some strums, which might need to be removed.
          ids.forEach(function (d) {
            var dims = strums[d].dims;
            strums.active = d; // If the two dimensions of the current strum are not next to each other
            // any more, than we'll need to remove the strum. Otherwise we keep it.

            if (!consecutive(dims.left, dims.right)) {
              removeStrum(strums);
            }
          });
          onDragEnd(strums)();
        }
      }); // Add a new svg group in which we draw the strums.

      pc.selection.select('svg').append('g').attr('id', 'strums').attr('transform', 'translate(' + __.margin.left + ',' + __.margin.top + ')'); // Install the required brushReset function

      pc.brushReset = brushReset(strums);
      drag.on('dragstart', onDragStart(strums)).on('drag', onDrag(strums)).on('dragend', onDragEnd(strums)); // NOTE: The styling needs to be done here and not in the css. This is because
      //       for 1D brushing, the canvas layers should not listen to
      //       pointer-events.

      strumRect = pc.selection.select('svg').insert('rect', 'g#strums').attr('id', 'strum-events').attr('x', __.margin.left).attr('y', __.margin.top).attr('width', w()).attr('height', h() + 2).style('opacity', 0).call(drag);
    }

    brush.modes['2D-strums'] = {
      install: install,
      uninstall: function () {
        pc.selection.select('svg').select('g#strums').remove();
        pc.selection.select('svg').select('rect#strum-events').remove();
        pc.on('axesreorder.strums', undefined);
        delete pc.brushReset;
        strumRect = undefined;
      },
      selected: selected,
      brushState: function () {
        return strums;
      }
    };
  })(); // brush mode: 1D-Axes with multiple extents
  // requires d3.svg.multibrush


  (function () {
    if (typeof d3.svg.multibrush !== 'function') {
      return;
    }

    var brushes = {};

    function is_brushed(p) {
      return !brushes[p].empty();
    } // data within extents


    function selected() {
      var actives = __.dimensions.filter(is_brushed),
          extents = actives.map(function (p) {
        return brushes[p].extent();
      }); // We don't want to return the full data set when there are no axes brushed.
      // Actually, when there are no axes brushed, by definition, no items are
      // selected. So, let's avoid the filtering and just return false.
      //if (actives.length === 0) return false;
      // Resolves broken examples for now. They expect to get the full dataset back from empty brushes


      if (actives.length === 0) return __.data; // test if within range

      var within = {
        date: function (d, p, dimension, b) {
          if (typeof yscale[p].rangePoints === 'function') {
            // if it is ordinal
            return b[0] <= yscale[p](d[p]) && yscale[p](d[p]) <= b[1];
          } else {
            return b[0] <= d[p] && d[p] <= b[1];
          }
        },
        number: function (d, p, dimension, b) {
          if (typeof yscale[p].rangePoints === 'function') {
            // if it is ordinal
            return b[0] <= yscale[p](d[p]) && yscale[p](d[p]) <= b[1];
          } else {
            return b[0] <= d[p] && d[p] <= b[1];
          }
        },
        string: function (d, p, dimension, b) {
          return b[0] <= yscale[p](d[p]) && yscale[p](d[p]) <= b[1];
        }
      };
      return __.data.filter(function (d) {
        switch (brush.predicate) {
          case 'AND':
            return actives.every(function (p, dimension) {
              return extents[dimension].some(function (b) {
                return within[__.types[p]](d, p, dimension, b);
              });
            });

          case 'OR':
            return actives.some(function (p, dimension) {
              return extents[dimension].some(function (b) {
                return within[__.types[p]](d, p, dimension, b);
              });
            });

          default:
            throw 'Unknown brush predicate ' + __.brushPredicate;
        }
      });
    }

    function brushExtents() {
      var extents = {};

      __.dimensions.forEach(function (d) {
        var brush = brushes[d];

        if (brush !== undefined && !brush.empty()) {
          var extent = brush.extent();
          extents[d] = extent;
        }
      });

      return extents;
    }

    function brushFor(axis) {
      var brush = d3.svg.multibrush();
      brush.y(yscale[axis]).on('brushstart', function () {
        if (d3.event.sourceEvent !== null) {
          d3.event.sourceEvent.stopPropagation();
        }
      }).on('brush', function () {
        brushUpdated(selected());
      }).on('brushend', function () {
        // d3.svg.multibrush clears extents just before calling 'brushend'
        // so we have to update here again.
        // This fixes issue #103 for now, but should be changed in d3.svg.multibrush
        // to avoid unnecessary computation.
        brushUpdated(selected());
        events.brushend.call(pc, __.brushed);
      }).extentAdaption(function (selection) {
        selection.style('visibility', null).attr('x', -15).attr('width', 30);
      }).resizeAdaption(function (selection) {
        selection.selectAll('rect').attr('x', -15).attr('width', 30);
      });
      brushes[axis] = brush;
      return brush;
    }

    function brushReset(dimension) {
      __.brushed = false;

      if (g) {
        g.selectAll('.brush').each(function (d) {
          d3.select(this).call(brushes[d].clear());
        });
        pc.renderBrushed();
      }

      return this;
    }

    function install() {
      if (!g) pc.createAxes(); // Add and store a brush for each axis.

      g.append('svg:g').attr('class', 'brush').each(function (d) {
        d3.select(this).call(brushFor(d));
      }).selectAll('rect').style('visibility', null).attr('x', -15).attr('width', 30);
      pc.brushExtents = brushExtents;
      pc.brushReset = brushReset;
      return pc;
    }

    brush.modes['1D-axes-multi'] = {
      install: install,
      uninstall: function () {
        g.selectAll('.brush').remove();
        brushes = {};
        delete pc.brushExtents;
        delete pc.brushReset;
      },
      selected: selected,
      brushState: brushExtents
    };
  })(); // brush mode: angular
  // code based on 2D.strums.js


  (function () {
    var arcs = {},
        strumRect;

    function drawStrum(arc, activePoint) {
      var svg = pc.selection.select('svg').select('g#arcs'),
          id = arc.dims.i,
          points = [arc.p2, arc.p3],
          line = svg.selectAll('line#arc-' + id).data([{
        p1: arc.p1,
        p2: arc.p2
      }, {
        p1: arc.p1,
        p2: arc.p3
      }]),
          circles = svg.selectAll('circle#arc-' + id).data(points),
          drag = d3.behavior.drag(),
          path = svg.selectAll('path#arc-' + id).data([arc]);
      path.enter().append('path').attr('id', 'arc-' + id).attr('class', 'arc').style('fill', 'orange').style('opacity', 0.5);
      path.attr('d', arc.arc).attr('transform', 'translate(' + arc.p1[0] + ',' + arc.p1[1] + ')');
      line.enter().append('line').attr('id', 'arc-' + id).attr('class', 'arc');
      line.attr('x1', function (d) {
        return d.p1[0];
      }).attr('y1', function (d) {
        return d.p1[1];
      }).attr('x2', function (d) {
        return d.p2[0];
      }).attr('y2', function (d) {
        return d.p2[1];
      }).attr('stroke', 'black').attr('stroke-width', 2);
      drag.on('drag', function (d, i) {
        var ev = d3.event,
            angle = 0;
        i = i + 2;
        arc['p' + i][0] = Math.min(Math.max(arc.minX + 1, ev.x), arc.maxX);
        arc['p' + i][1] = Math.min(Math.max(arc.minY, ev.y), arc.maxY);
        angle = i === 3 ? arcs.startAngle(id) : arcs.endAngle(id);

        if (arc.startAngle < Math.PI && arc.endAngle < Math.PI && angle < Math.PI || arc.startAngle >= Math.PI && arc.endAngle >= Math.PI && angle >= Math.PI) {
          if (i === 2) {
            arc.endAngle = angle;
            arc.arc.endAngle(angle);
          } else if (i === 3) {
            arc.startAngle = angle;
            arc.arc.startAngle(angle);
          }
        }

        drawStrum(arc, i - 2);
      }).on('dragend', onDragEnd());
      circles.enter().append('circle').attr('id', 'arc-' + id).attr('class', 'arc');
      circles.attr('cx', function (d) {
        return d[0];
      }).attr('cy', function (d) {
        return d[1];
      }).attr('r', 5).style('opacity', function (d, i) {
        return activePoint !== undefined && i === activePoint ? 0.8 : 0;
      }).on('mouseover', function () {
        d3.select(this).style('opacity', 0.8);
      }).on('mouseout', function () {
        d3.select(this).style('opacity', 0);
      }).call(drag);
    }

    function dimensionsForPoint(p) {
      var dims = {
        i: -1,
        left: undefined,
        right: undefined
      };

      __.dimensions.some(function (dim, i) {
        if (xscale(dim) < p[0]) {
          var next = __.dimensions[i + 1];
          dims.i = i;
          dims.left = dim;
          dims.right = next;
          return false;
        }

        return true;
      });

      if (dims.left === undefined) {
        // Event on the left side of the first axis.
        dims.i = 0;
        dims.left = __.dimensions[0];
        dims.right = __.dimensions[1];
      } else if (dims.right === undefined) {
        // Event on the right side of the last axis
        dims.i = __.dimensions.length - 1;
        dims.right = dims.left;
        dims.left = __.dimensions[__.dimensions.length - 2];
      }

      return dims;
    }

    function onDragStart() {
      // First we need to determine between which two axes the arc was started.
      // This will determine the freedom of movement, because a arc can
      // logically only happen between two axes, so no movement outside these axes
      // should be allowed.
      return function () {
        var p = d3.mouse(strumRect[0][0]),
            dims,
            arc;
        p[0] = p[0] - __.margin.left;
        p[1] = p[1] - __.margin.top;
        dims = dimensionsForPoint(p), arc = {
          p1: p,
          dims: dims,
          minX: xscale(dims.left),
          maxX: xscale(dims.right),
          minY: 0,
          maxY: h(),
          startAngle: undefined,
          endAngle: undefined,
          arc: d3.svg.arc().innerRadius(0)
        };
        arcs[dims.i] = arc;
        arcs.active = dims.i; // Make sure that the point is within the bounds

        arc.p1[0] = Math.min(Math.max(arc.minX, p[0]), arc.maxX);
        arc.p2 = arc.p1.slice();
        arc.p3 = arc.p1.slice();
      };
    }

    function onDrag() {
      return function () {
        var ev = d3.event,
            arc = arcs[arcs.active]; // Make sure that the point is within the bounds

        arc.p2[0] = Math.min(Math.max(arc.minX + 1, ev.x - __.margin.left), arc.maxX);
        arc.p2[1] = Math.min(Math.max(arc.minY, ev.y - __.margin.top), arc.maxY);
        arc.p3 = arc.p2.slice();
        drawStrum(arc, 1);
      };
    } // some helper functions


    function hypothenuse(a, b) {
      return Math.sqrt(a * a + b * b);
    }

    var rad = function () {
      var c = Math.PI / 180;
      return function (angle) {
        return angle * c;
      };
    }();

    var deg = function () {
      var c = 180 / Math.PI;
      return function (angle) {
        return angle * c;
      };
    }(); // [0, 2*PI] -> [-PI/2, PI/2]


    var signedAngle = function (angle) {
      var ret = angle;

      if (angle > Math.PI) {
        ret = angle - 1.5 * Math.PI;
        ret = angle - 1.5 * Math.PI;
      } else {
        ret = angle - 0.5 * Math.PI;
        ret = angle - 0.5 * Math.PI;
      }

      return -ret;
    };
    /**
     * angles are stored in radians from in [0, 2*PI], where 0 in 12 o'clock.
     * However, one can only select lines from 0 to PI, so we compute the
     * 'signed' angle, where 0 is the horizontal line (3 o'clock), and +/- PI/2
     * are 12 and 6 o'clock respectively.
     */


    function containmentTest(arc) {
      var startAngle = signedAngle(arc.startAngle);
      var endAngle = signedAngle(arc.endAngle);

      if (startAngle > endAngle) {
        var tmp = startAngle;
        startAngle = endAngle;
        endAngle = tmp;
      } // test if segment angle is contained in angle interval


      return function (a) {
        if (a >= startAngle && a <= endAngle) {
          return true;
        }

        return false;
      };
    }

    function selected() {
      var ids = Object.getOwnPropertyNames(arcs),
          brushed = __.data; // Get the ids of the currently active arcs.

      ids = ids.filter(function (d) {
        return !isNaN(d);
      });

      function crossesStrum(d, id) {
        var arc = arcs[id],
            test = containmentTest(arc),
            d1 = arc.dims.left,
            d2 = arc.dims.right,
            y1 = yscale[d1],
            y2 = yscale[d2],
            a = arcs.width(id),
            b = y1(d[d1]) - y2(d[d2]),
            c = hypothenuse(a, b),
            angle = Math.asin(b / c); // rad in [-PI/2, PI/2]

        return test(angle);
      }

      if (ids.length === 0) {
        return brushed;
      }

      return brushed.filter(function (d) {
        switch (brush.predicate) {
          case 'AND':
            return ids.every(function (id) {
              return crossesStrum(d, id);
            });

          case 'OR':
            return ids.some(function (id) {
              return crossesStrum(d, id);
            });

          default:
            throw 'Unknown brush predicate ' + __.brushPredicate;
        }
      });
    }

    function removeStrum() {
      var arc = arcs[arcs.active],
          svg = pc.selection.select('svg').select('g#arcs');
      delete arcs[arcs.active];
      arcs.active = undefined;
      svg.selectAll('line#arc-' + arc.dims.i).remove();
      svg.selectAll('circle#arc-' + arc.dims.i).remove();
      svg.selectAll('path#arc-' + arc.dims.i).remove();
    }

    function onDragEnd() {
      return function () {
        var brushed = __.data,
            arc = arcs[arcs.active]; // Okay, somewhat unexpected, but not totally unsurprising, a mousclick is
        // considered a drag without move. So we have to deal with that case

        if (arc && arc.p1[0] === arc.p2[0] && arc.p1[1] === arc.p2[1]) {
          removeStrum(arcs);
        }

        if (arc) {
          var angle = arcs.startAngle(arcs.active);
          arc.startAngle = angle;
          arc.endAngle = angle;
          arc.arc.outerRadius(arcs.length(arcs.active)).startAngle(angle).endAngle(angle);
        }

        brushed = selected(arcs);
        arcs.active = undefined;
        __.brushed = brushed;
        pc.renderBrushed();
        events.brushend.call(pc, __.brushed);
      };
    }

    function brushReset(arcs) {
      return function () {
        var ids = Object.getOwnPropertyNames(arcs).filter(function (d) {
          return !isNaN(d);
        });
        ids.forEach(function (d) {
          arcs.active = d;
          removeStrum(arcs);
        });
        onDragEnd(arcs)();
      };
    }

    function install() {
      var drag = d3.behavior.drag(); // Map of current arcs. arcs are stored per segment of the PC. A segment,
      // being the area between two axes. The left most area is indexed at 0.

      arcs.active = undefined; // Returns the width of the PC segment where currently a arc is being
      // placed. NOTE: even though they are evenly spaced in our current
      // implementation, we keep for when non-even spaced segments are supported as
      // well.

      arcs.width = function (id) {
        var arc = arcs[id];

        if (arc === undefined) {
          return undefined;
        }

        return arc.maxX - arc.minX;
      }; // returns angles in [-PI/2, PI/2]


      angle = function (p1, p2) {
        var a = p1[0] - p2[0],
            b = p1[1] - p2[1],
            c = hypothenuse(a, b);
        return Math.asin(b / c);
      }; // returns angles in [0, 2 * PI]


      arcs.endAngle = function (id) {
        var arc = arcs[id];

        if (arc === undefined) {
          return undefined;
        }

        var sAngle = angle(arc.p1, arc.p2),
            uAngle = -sAngle + Math.PI / 2;

        if (arc.p1[0] > arc.p2[0]) {
          uAngle = 2 * Math.PI - uAngle;
        }

        return uAngle;
      };

      arcs.startAngle = function (id) {
        var arc = arcs[id];

        if (arc === undefined) {
          return undefined;
        }

        var sAngle = angle(arc.p1, arc.p3),
            uAngle = -sAngle + Math.PI / 2;

        if (arc.p1[0] > arc.p3[0]) {
          uAngle = 2 * Math.PI - uAngle;
        }

        return uAngle;
      };

      arcs.length = function (id) {
        var arc = arcs[id];

        if (arc === undefined) {
          return undefined;
        }

        var a = arc.p1[0] - arc.p2[0],
            b = arc.p1[1] - arc.p2[1],
            c = hypothenuse(a, b);
        return c;
      };

      pc.on('axesreorder.arcs', function () {
        var ids = Object.getOwnPropertyNames(arcs).filter(function (d) {
          return !isNaN(d);
        }); // Checks if the first dimension is directly left of the second dimension.

        function consecutive(first, second) {
          var length = __.dimensions.length;
          return __.dimensions.some(function (d, i) {
            return d === first ? i + i < length && __.dimensions[i + 1] === second : false;
          });
        }

        if (ids.length > 0) {
          // We have some arcs, which might need to be removed.
          ids.forEach(function (d) {
            var dims = arcs[d].dims;
            arcs.active = d; // If the two dimensions of the current arc are not next to each other
            // any more, than we'll need to remove the arc. Otherwise we keep it.

            if (!consecutive(dims.left, dims.right)) {
              removeStrum(arcs);
            }
          });
          onDragEnd(arcs)();
        }
      }); // Add a new svg group in which we draw the arcs.

      pc.selection.select('svg').append('g').attr('id', 'arcs').attr('transform', 'translate(' + __.margin.left + ',' + __.margin.top + ')'); // Install the required brushReset function

      pc.brushReset = brushReset(arcs);
      drag.on('dragstart', onDragStart(arcs)).on('drag', onDrag(arcs)).on('dragend', onDragEnd(arcs)); // NOTE: The styling needs to be done here and not in the css. This is because
      //       for 1D brushing, the canvas layers should not listen to
      //       pointer-events.

      strumRect = pc.selection.select('svg').insert('rect', 'g#arcs').attr('id', 'arc-events').attr('x', __.margin.left).attr('y', __.margin.top).attr('width', w()).attr('height', h() + 2).style('opacity', 0).call(drag);
    }

    brush.modes['angular'] = {
      install: install,
      uninstall: function () {
        pc.selection.select('svg').select('g#arcs').remove();
        pc.selection.select('svg').select('rect#arc-events').remove();
        pc.on('axesreorder.arcs', undefined);
        delete pc.brushReset;
        strumRect = undefined;
      },
      selected: selected,
      brushState: function () {
        return arcs;
      }
    };
  })();

  pc.interactive = function () {
    flags.interactive = true;
    return this;
  }; // expose a few objects


  pc.xscale = xscale;
  pc.yscale = yscale;
  pc.ctx = ctx;
  pc.canvas = canvas;

  pc.g = function () {
    return g;
  }; // rescale for height, width and margins
  // TODO currently assumes chart is brushable, and destroys old brushes


  pc.resize = function () {
    // selection size
    pc.selection.select('svg').attr('width', __.width).attr('height', __.height);
    pc.svg.attr('transform', 'translate(' + __.margin.left + ',' + __.margin.top + ')'); // FIXME: the current brush state should pass through

    if (flags.brushable) pc.brushReset(); // scales

    pc.autoscale(); // axes, destroys old brushes.

    if (g) pc.createAxes();
    if (flags.brushable) pc.brushable();
    if (flags.reorderable) pc.reorderable();
    events.resize.call(this, {
      width: __.width,
      height: __.height,
      margin: __.margin
    });
    return this;
  }; // highlight an array of data


  pc.highlight = function (data) {
    if (arguments.length === 0) {
      return __.highlighted;
    }

    __.highlighted = data;
    pc.clear('highlight');
    d3.selectAll([canvas.foreground, canvas.brushed]).classed('faded', true);
    data.forEach(path_highlight);
    events.highlight.call(this, data);
    return this;
  }; // clear highlighting


  pc.unhighlight = function () {
    __.highlighted = [];
    pc.clear('highlight');
    d3.selectAll([canvas.foreground, canvas.brushed]).classed('faded', false);
    return this;
  }; // calculate 2d intersection of line a->b with line c->d
  // points are objects with x and y properties


  pc.intersection = function (a, b, c, d) {
    return {
      x: ((a.x * b.y - a.y * b.x) * (c.x - d.x) - (a.x - b.x) * (c.x * d.y - c.y * d.x)) / ((a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x)),
      y: ((a.x * b.y - a.y * b.x) * (c.y - d.y) - (a.y - b.y) * (c.x * d.y - c.y * d.x)) / ((a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x))
    };
  };

  function position(d) {
    var v = dragging[d];
    return v == null ? xscale(d) : v;
  }

  pc.version = '0.7.0'; // this descriptive text should live with other introspective methods

  pc.toString = function () {
    return 'Parallel Coordinates: ' + __.dimensions.length + ' dimensions (' + d3.keys(__.data[0]).length + ' total) , ' + __.data.length + ' rows';
  };

  return pc;
}

d3.renderQueue = function (func) {
  var _queue = [],
      // data to be rendered
  _rate = 10,
      // number of calls per frame
  _clear = function () {},
      // clearing function
  _i = 0; // current iteration


  var rq = function (data) {
    if (data) rq.data(data);
    rq.invalidate();

    _clear();

    rq.render();
  };

  rq.render = function () {
    _i = 0;
    var valid = true;

    rq.invalidate = function () {
      valid = false;
    };

    function doFrame() {
      if (!valid) return true;
      if (_i > _queue.length) return true; // Typical d3 behavior is to pass a data item *and* its index. As the
      // render queue splits the original data set, we'll have to be slightly
      // more carefull about passing the correct index with the data item.

      var end = Math.min(_i + _rate, _queue.length);

      for (var i = _i; i < end; i += 1) {
        func(_queue[i], i);
      }

      _i += _rate;
    }

    d3.timer(doFrame);
  };

  rq.data = function (data) {
    rq.invalidate();
    _queue = data.slice(0);
    return rq;
  };

  rq.rate = function (value) {
    if (!arguments.length) return _rate;
    _rate = value;
    return rq;
  };

  rq.remaining = function () {
    return _queue.length - _i;
  }; // clear the canvas


  rq.clear = function (func) {
    if (!arguments.length) {
      _clear();

      return rq;
    }

    _clear = func;
    return rq;
  };

  rq.invalidate = function () {};

  return rq;
};
;// CONCATENATED MODULE: ./node_modules/@superset-ui/legacy-plugin-chart-parallel-coordinates/esm/vendor/parcoords/divgrid.js
/* [LICENSE TBD] */

/* eslint-disable */
// from http://bl.ocks.org/3687826
/* harmony default export */ function divgrid(config) {
  var columns = [];

  var dg = function (selection) {
    if (columns.length == 0) columns = d3.keys(selection.data()[0][0]); // header

    selection.selectAll('.header').data([true]).enter().append('div').attr('class', 'header');
    var header = selection.select('.header').selectAll('.cell').data(columns);
    header.enter().append('div').attr('class', function (d, i) {
      return 'col-' + i;
    }).classed('cell', true);
    selection.selectAll('.header .cell').text(function (d) {
      return d;
    });
    header.exit().remove(); // rows

    var rows = selection.selectAll('.row').data(function (d) {
      return d;
    });
    rows.enter().append('div').attr('class', 'row');
    rows.exit().remove();
    var cells = selection.selectAll('.row').selectAll('.cell').data(function (d) {
      return columns.map(function (col) {
        return d[col];
      });
    }); // cells

    cells.enter().append('div').attr('class', function (d, i) {
      return 'col-' + i;
    }).classed('cell', true);
    cells.exit().remove();
    selection.selectAll('.cell').text(function (d) {
      return d;
    });
    return dg;
  };

  dg.columns = function (_) {
    if (!arguments.length) return columns;
    columns = _;
    return this;
  };

  return dg;
}
;// CONCATENATED MODULE: ./node_modules/@superset-ui/legacy-plugin-chart-parallel-coordinates/esm/vendor/parcoords/d3.parcoords.css
// extracted by mini-css-extract-plugin

;// CONCATENATED MODULE: ./node_modules/@superset-ui/legacy-plugin-chart-parallel-coordinates/esm/ParallelCoordinates.js
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* eslint-disable react/sort-prop-types */






const propTypes = {
  // Standard tabular data [{ fieldName1: value1, fieldName2: value2 }]
  data: prop_types_default().arrayOf((prop_types_default()).object),
  width: (prop_types_default()).number,
  height: (prop_types_default()).number,
  colorMetric: (prop_types_default()).string,
  includeSeries: (prop_types_default()).bool,
  linearColorScheme: (prop_types_default()).string,
  metrics: prop_types_default().arrayOf((prop_types_default()).string),
  series: (prop_types_default()).string,
  showDatatable: (prop_types_default()).bool
};

function ParallelCoordinates(element, props) {
  const {
    data,
    width,
    height,
    colorMetric,
    includeSeries,
    linearColorScheme,
    metrics,
    series,
    showDatatable
  } = props;
  const cols = includeSeries ? [series].concat(metrics) : metrics;
  const ttypes = {};
  ttypes[series] = 'string';
  metrics.forEach(v => {
    ttypes[v] = 'number';
  });
  const colorScale = colorMetric ? (0,SequentialSchemeRegistrySingleton/* default */.Z)().get(linearColorScheme).createLinearScale(d3_default().extent(data, d => d[colorMetric])) : () => 'grey';

  const color = d => colorScale(d[colorMetric]);

  const container = d3_default().select(element).classed('superset-legacy-chart-parallel-coordinates', true);
  container.selectAll('*').remove();
  const effHeight = showDatatable ? height / 2 : height;
  const div = container.append('div').style('height', `${effHeight}px`).classed('parcoords', true);
  const chart = d3_parcoords()(div.node()).width(width).color(color).alpha(0.5).composite('darken').height(effHeight).data(data).dimensions(cols).types(ttypes).render().createAxes().shadows().reorderable().brushMode('1D-axes');

  if (showDatatable) {
    // create data table, row hover highlighting
    const grid = divgrid();
    container.append('div').style('height', `${effHeight}px`).datum(data).call(grid).classed('parcoords grid', true).selectAll('.row').on({
      mouseover(d) {
        chart.highlight([d]);
      },

      mouseout: chart.unhighlight
    }); // update data table on brush event

    chart.on('brush', d => {
      d3_default().select('.grid').datum(d).call(grid).selectAll('.row').on({
        mouseover(dd) {
          chart.highlight([dd]);
        },

        mouseout: chart.unhighlight
      });
    });
  }
}

ParallelCoordinates.displayName = 'ParallelCoordinates';
ParallelCoordinates.propTypes = propTypes;
/* harmony default export */ const esm_ParallelCoordinates = (ParallelCoordinates);
// EXTERNAL MODULE: ./node_modules/@emotion/react/dist/emotion-react.browser.esm.js + 1 modules
var emotion_react_browser_esm = __webpack_require__(11965);
;// CONCATENATED MODULE: ./node_modules/@superset-ui/legacy-plugin-chart-parallel-coordinates/esm/ReactParallelCoordinates.js
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */





const ReactComponent = (0,reactify/* default */.Z)(esm_ParallelCoordinates);

const ParallelCoordianes = ({
  className,
  ...otherProps
}) => (0,emotion_react_browser_esm.jsx)("div", {
  className: className
}, (0,emotion_react_browser_esm.jsx)(ReactComponent, otherProps));

ParallelCoordianes.propTypes = {
  className: (prop_types_default()).string.isRequired
};
/* harmony default export */ const ReactParallelCoordinates = ((0,style/* styled */.iK)(ParallelCoordianes)`
  .superset-legacy-chart-parallel-coordinates {
    div.grid {
      overflow: auto;
      div.row {
        &:hover {
          background-color: #ccc;
        }
      }
    }
  }
`);

/***/ })

}]);