summaryrefslogtreecommitdiff
path: root/priv/static/js/metricsgraphics/common/zoom.js
blob: eb877f292079e6a23366de2d54133d7396951da9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
{

const filter_in_range_data = (args, range) => {
  const is_data_in_range = (data, range) => {
    return data > Math.min(range[0], range[1]) && data < Math.max(range[0], range[1]);
  };
  // if range without this axis return true, else judge is data in range or not.
  return d => ['x', 'y'].every(dim => !(dim in range) || is_data_in_range(d[args[`${dim}_accessor`]], range[dim]));
};

// the range here is the range of data
// range is an object with two optional attributes of x,y, respectively represent ranges on two axes
const zoom_to_data_domain = (args, range) => {
  const raw_data = args.processed.raw_data || args.data;
  // store raw data and raw domain to in order to zoom back to the initial state
  if (!('raw_data' in args.processed)) {
    args.processed.raw_domain = {
      x: args.scales.X.domain(),
      y: args.scales.Y.domain()
    };
    args.processed.raw_data = raw_data;
  }
  if (['x', 'y'].some(dim => range[dim][0] === range[dim][1])) return;
  // to avoid drawing outside the chart in the point chart, unnecessary in line chart.
  if (args.chart_type === 'point') {
    if (is_array_of_arrays(raw_data)) {
      args.data = raw_data.map(function(d) {
        return d.filter(filter_in_range_data(args, range));
      });
    } else {
      args.data = raw_data.filter(filter_in_range_data(args, range));
    }
    if (mg_flatten_array(args.data).length === 0) return;
  }
  ['x', 'y'].forEach(dim => {
    if (dim in range) args.processed[`zoom_${dim}`] = range[dim];
    else delete args.processed[`zoom_${dim}`];
  });
  if (args.processed.subplot) {
    if (range !== args.processed.raw_domain) {
      MG.create_brushing_pattern(args.processed.subplot, convert_domain_to_range(args.processed.subplot, range));
    } else {
      MG.remove_brushing_pattern(args.processed.subplot);
    }
  }
  new MG.charts[args.chart_type || defaults.chart_type].descriptor(args);
};

const zoom_to_raw_range = args => {
  if (!('raw_domain' in args.processed)) return;
  zoom_to_data_domain(args, args.processed.raw_domain);
  delete args.processed.raw_domain;
  delete args.processed.raw_data;
};

// converts the range of selection into the range of data that we can use to
// zoom the chart to a particular region
const convert_range_to_domain = (args, range) =>
  ['x', 'y'].reduce((domain, dim) => {
    if (!(dim in range)) return domain;
    domain[dim] = range[dim].map(v => +args.scales[dim.toUpperCase()].invert(v));
    if (dim === 'y') domain[dim].reverse();
    return domain;
  }, {});

const convert_domain_to_range = (args, domain) =>
  ['x', 'y'].reduce((range, dim) => {
    if (!(dim in domain)) return range;
    range[dim] = domain[dim].map(v => +args.scales[dim.toUpperCase()](v));
    if (dim === 'y') range[dim].reverse();
    return range;
  }, {});

// the range here is the range of selection
const zoom_to_data_range = (args, range) => {
  const domain = convert_range_to_domain(args, range);
  zoom_to_data_domain(args, domain);
};

MG.convert_range_to_domain = convert_range_to_domain;
MG.zoom_to_data_domain = zoom_to_data_domain;
MG.zoom_to_data_range = zoom_to_data_range;
MG.zoom_to_raw_range = zoom_to_raw_range;

}