mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42:41 +01:00
Support drawing multiple functions on the same chart
Summary: Depends on D20438. Ref T13279. Widgets produced vs widgets sold, etc. Test Plan: {F6381609} Reviewers: amckinley Reviewed By: amckinley Subscribers: yelirekim Maniphest Tasks: T13279 Differential Revision: https://secure.phabricator.com/D20439
This commit is contained in:
parent
02981f0add
commit
044c6fbc19
3 changed files with 114 additions and 63 deletions
|
@ -397,7 +397,7 @@ return array(
|
||||||
'rsrc/js/application/herald/PathTypeahead.js' => 'ad486db3',
|
'rsrc/js/application/herald/PathTypeahead.js' => 'ad486db3',
|
||||||
'rsrc/js/application/herald/herald-rule-editor.js' => '0922e81d',
|
'rsrc/js/application/herald/herald-rule-editor.js' => '0922e81d',
|
||||||
'rsrc/js/application/maniphest/behavior-batch-selector.js' => '139ef688',
|
'rsrc/js/application/maniphest/behavior-batch-selector.js' => '139ef688',
|
||||||
'rsrc/js/application/maniphest/behavior-line-chart.js' => '11167911',
|
'rsrc/js/application/maniphest/behavior-line-chart.js' => '495cf14d',
|
||||||
'rsrc/js/application/maniphest/behavior-list-edit.js' => 'c687e867',
|
'rsrc/js/application/maniphest/behavior-list-edit.js' => 'c687e867',
|
||||||
'rsrc/js/application/owners/OwnersPathEditor.js' => '2a8b62d9',
|
'rsrc/js/application/owners/OwnersPathEditor.js' => '2a8b62d9',
|
||||||
'rsrc/js/application/owners/owners-path-editor.js' => 'ff688a7a',
|
'rsrc/js/application/owners/owners-path-editor.js' => 'ff688a7a',
|
||||||
|
@ -625,7 +625,7 @@ return array(
|
||||||
'javelin-behavior-icon-composer' => '38a6cedb',
|
'javelin-behavior-icon-composer' => '38a6cedb',
|
||||||
'javelin-behavior-launch-icon-composer' => 'a17b84f1',
|
'javelin-behavior-launch-icon-composer' => 'a17b84f1',
|
||||||
'javelin-behavior-lightbox-attachments' => 'c7e748bf',
|
'javelin-behavior-lightbox-attachments' => 'c7e748bf',
|
||||||
'javelin-behavior-line-chart' => '11167911',
|
'javelin-behavior-line-chart' => '495cf14d',
|
||||||
'javelin-behavior-linked-container' => '74446546',
|
'javelin-behavior-linked-container' => '74446546',
|
||||||
'javelin-behavior-maniphest-batch-selector' => '139ef688',
|
'javelin-behavior-maniphest-batch-selector' => '139ef688',
|
||||||
'javelin-behavior-maniphest-list-editor' => 'c687e867',
|
'javelin-behavior-maniphest-list-editor' => 'c687e867',
|
||||||
|
@ -1007,12 +1007,6 @@ return array(
|
||||||
'javelin-workflow',
|
'javelin-workflow',
|
||||||
'phuix-icon-view',
|
'phuix-icon-view',
|
||||||
),
|
),
|
||||||
11167911 => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-vector',
|
|
||||||
'phui-chart-css',
|
|
||||||
),
|
|
||||||
'111bfd2d' => array(
|
'111bfd2d' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
@ -1325,6 +1319,12 @@ return array(
|
||||||
'490e2e2e' => array(
|
'490e2e2e' => array(
|
||||||
'phui-oi-list-view-css',
|
'phui-oi-list-view-css',
|
||||||
),
|
),
|
||||||
|
'495cf14d' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-vector',
|
||||||
|
'phui-chart-css',
|
||||||
|
),
|
||||||
'4a7fb02b' => array(
|
'4a7fb02b' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
|
|
@ -55,8 +55,29 @@ final class PhabricatorFactChartController extends PhabricatorFactController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$x = array_keys($points);
|
$datasets = array();
|
||||||
$y = array_values($points);
|
|
||||||
|
$datasets[] = array(
|
||||||
|
'x' => array_keys($points),
|
||||||
|
'y' => array_values($points),
|
||||||
|
'color' => '#ff0000',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Add a dummy "y = x" dataset to prove we can draw multiple datasets.
|
||||||
|
$x_min = min(array_keys($points));
|
||||||
|
$x_max = max(array_keys($points));
|
||||||
|
$x_range = ($x_max - $x_min) / 4;
|
||||||
|
$linear = array();
|
||||||
|
foreach ($points as $x => $y) {
|
||||||
|
$linear[$x] = count($points) * (($x - $x_min) / $x_range);
|
||||||
|
}
|
||||||
|
$datasets[] = array(
|
||||||
|
'x' => array_keys($linear),
|
||||||
|
'y' => array_values($linear),
|
||||||
|
'color' => '#0000ff',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
$id = celerity_generate_unique_node_id();
|
$id = celerity_generate_unique_node_id();
|
||||||
$chart = phutil_tag(
|
$chart = phutil_tag(
|
||||||
|
@ -70,15 +91,38 @@ final class PhabricatorFactChartController extends PhabricatorFactController {
|
||||||
|
|
||||||
require_celerity_resource('d3');
|
require_celerity_resource('d3');
|
||||||
|
|
||||||
Javelin::initBehavior('line-chart', array(
|
$y_min = 0;
|
||||||
'hardpoint' => $id,
|
$y_max = 0;
|
||||||
'x' => array($x),
|
$x_min = null;
|
||||||
'y' => array($y),
|
$x_max = 0;
|
||||||
'yMax' => max(0, max($y)),
|
foreach ($datasets as $dataset) {
|
||||||
'yMin' => min(0, min($y)),
|
if (!$dataset['y']) {
|
||||||
'xformat' => 'epoch',
|
continue;
|
||||||
'colors' => array('#0000ff'),
|
}
|
||||||
));
|
|
||||||
|
$y_min = min($y_min, min($dataset['y']));
|
||||||
|
$y_max = max($y_max, max($dataset['y']));
|
||||||
|
|
||||||
|
if ($x_min === null) {
|
||||||
|
$x_min = min($dataset['x']);
|
||||||
|
} else {
|
||||||
|
$x_min = min($x_min, min($dataset['x']));
|
||||||
|
}
|
||||||
|
|
||||||
|
$x_max = max($x_max, max($dataset['x']));
|
||||||
|
}
|
||||||
|
|
||||||
|
Javelin::initBehavior(
|
||||||
|
'line-chart',
|
||||||
|
array(
|
||||||
|
'hardpoint' => $id,
|
||||||
|
'datasets' => $datasets,
|
||||||
|
'xMin' => $x_min,
|
||||||
|
'xMax' => $x_max,
|
||||||
|
'yMin' => $y_min,
|
||||||
|
'yMax' => $y_max,
|
||||||
|
'xformat' => 'epoch',
|
||||||
|
));
|
||||||
|
|
||||||
$box = id(new PHUIObjectBoxView())
|
$box = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Count of %s', $fact->getName()))
|
->setHeaderText(pht('Count of %s', $fact->getName()))
|
||||||
|
|
|
@ -57,28 +57,61 @@ JX.behavior('line-chart', function(config) {
|
||||||
.attr('width', size.width)
|
.attr('width', size.width)
|
||||||
.attr('height', size.height);
|
.attr('height', size.height);
|
||||||
|
|
||||||
var line = d3.svg.line()
|
function as_date(value) {
|
||||||
.x(function(d) { return x(d.date); })
|
return new Date(value * 1000);
|
||||||
.y(function(d) { return y(d.count); });
|
|
||||||
|
|
||||||
var data = [];
|
|
||||||
for (var ii = 0; ii < config.x[0].length; ii++) {
|
|
||||||
data.push(
|
|
||||||
{
|
|
||||||
date: new Date(config.x[0][ii] * 1000),
|
|
||||||
count: +config.y[0][ii]
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
x.domain(d3.extent(data, function(d) { return d.date; }));
|
x.domain([as_date(config.xMin), as_date(config.xMax)]);
|
||||||
|
|
||||||
var yex = d3.extent(data, function(d) { return d.count; });
|
|
||||||
y.domain([config.yMin, config.yMax]);
|
y.domain([config.yMin, config.yMax]);
|
||||||
|
|
||||||
g.append('path')
|
for (var idx = 0; idx < config.datasets.length; idx++) {
|
||||||
.datum(data)
|
var dataset = config.datasets[idx];
|
||||||
.attr('class', 'line')
|
|
||||||
.attr('d', line);
|
var line = d3.svg.line()
|
||||||
|
.x(function(d) { return x(d.xvalue); })
|
||||||
|
.y(function(d) { return y(d.yvalue); });
|
||||||
|
|
||||||
|
var data = [];
|
||||||
|
for (var ii = 0; ii < dataset.x.length; ii++) {
|
||||||
|
data.push(
|
||||||
|
{
|
||||||
|
xvalue: as_date(dataset.x[ii]),
|
||||||
|
yvalue: dataset.y[ii]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
g.append('path')
|
||||||
|
.datum(data)
|
||||||
|
.attr('class', 'line')
|
||||||
|
.style('stroke', dataset.color)
|
||||||
|
.attr('d', line);
|
||||||
|
|
||||||
|
g.selectAll('dot')
|
||||||
|
.data(data)
|
||||||
|
.enter()
|
||||||
|
.append('circle')
|
||||||
|
.attr('class', 'point')
|
||||||
|
.attr('r', 3)
|
||||||
|
.attr('cx', function(d) { return x(d.xvalue); })
|
||||||
|
.attr('cy', function(d) { return y(d.yvalue); })
|
||||||
|
.on('mouseover', function(d) {
|
||||||
|
var d_y = d.xvalue.getFullYear();
|
||||||
|
|
||||||
|
// NOTE: Javascript months are zero-based. See PHI1017.
|
||||||
|
var d_m = d.xvalue.getMonth() + 1;
|
||||||
|
|
||||||
|
var d_d = d.xvalue.getDate();
|
||||||
|
|
||||||
|
div
|
||||||
|
.html(d_y + '-' + d_m + '-' + d_d + ': ' + d.yvalue)
|
||||||
|
.style('opacity', 0.9)
|
||||||
|
.style('left', (d3.event.pageX - 60) + 'px')
|
||||||
|
.style('top', (d3.event.pageY - 38) + 'px');
|
||||||
|
})
|
||||||
|
.on('mouseout', function() {
|
||||||
|
div.style('opacity', 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
g.append('g')
|
g.append('g')
|
||||||
.attr('class', 'x axis')
|
.attr('class', 'x axis')
|
||||||
|
@ -95,30 +128,4 @@ JX.behavior('line-chart', function(config) {
|
||||||
.attr('class', 'chart-tooltip')
|
.attr('class', 'chart-tooltip')
|
||||||
.style('opacity', 0);
|
.style('opacity', 0);
|
||||||
|
|
||||||
g.selectAll('dot')
|
|
||||||
.data(data)
|
|
||||||
.enter()
|
|
||||||
.append('circle')
|
|
||||||
.attr('class', 'point')
|
|
||||||
.attr('r', 3)
|
|
||||||
.attr('cx', function(d) { return x(d.date); })
|
|
||||||
.attr('cy', function(d) { return y(d.count); })
|
|
||||||
.on('mouseover', function(d) {
|
|
||||||
var d_y = d.date.getFullYear();
|
|
||||||
|
|
||||||
// NOTE: Javascript months are zero-based. See PHI1017.
|
|
||||||
var d_m = d.date.getMonth() + 1;
|
|
||||||
|
|
||||||
var d_d = d.date.getDate();
|
|
||||||
|
|
||||||
div
|
|
||||||
.html(d_y + '-' + d_m + '-' + d_d + ': ' + d.count)
|
|
||||||
.style('opacity', 0.9)
|
|
||||||
.style('left', (d3.event.pageX - 60) + 'px')
|
|
||||||
.style('top', (d3.event.pageY - 38) + 'px');
|
|
||||||
})
|
|
||||||
.on('mouseout', function() {
|
|
||||||
div.style('opacity', 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue