@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+114 -63
+8 -8
resources/celerity/map.php
··· 397 397 'rsrc/js/application/herald/PathTypeahead.js' => 'ad486db3', 398 398 'rsrc/js/application/herald/herald-rule-editor.js' => '0922e81d', 399 399 'rsrc/js/application/maniphest/behavior-batch-selector.js' => '139ef688', 400 - 'rsrc/js/application/maniphest/behavior-line-chart.js' => '11167911', 400 + 'rsrc/js/application/maniphest/behavior-line-chart.js' => '495cf14d', 401 401 'rsrc/js/application/maniphest/behavior-list-edit.js' => 'c687e867', 402 402 'rsrc/js/application/owners/OwnersPathEditor.js' => '2a8b62d9', 403 403 'rsrc/js/application/owners/owners-path-editor.js' => 'ff688a7a', ··· 625 625 'javelin-behavior-icon-composer' => '38a6cedb', 626 626 'javelin-behavior-launch-icon-composer' => 'a17b84f1', 627 627 'javelin-behavior-lightbox-attachments' => 'c7e748bf', 628 - 'javelin-behavior-line-chart' => '11167911', 628 + 'javelin-behavior-line-chart' => '495cf14d', 629 629 'javelin-behavior-linked-container' => '74446546', 630 630 'javelin-behavior-maniphest-batch-selector' => '139ef688', 631 631 'javelin-behavior-maniphest-list-editor' => 'c687e867', ··· 1007 1007 'javelin-workflow', 1008 1008 'phuix-icon-view', 1009 1009 ), 1010 - 11167911 => array( 1011 - 'javelin-behavior', 1012 - 'javelin-dom', 1013 - 'javelin-vector', 1014 - 'phui-chart-css', 1015 - ), 1016 1010 '111bfd2d' => array( 1017 1011 'javelin-install', 1018 1012 ), ··· 1324 1318 ), 1325 1319 '490e2e2e' => array( 1326 1320 'phui-oi-list-view-css', 1321 + ), 1322 + '495cf14d' => array( 1323 + 'javelin-behavior', 1324 + 'javelin-dom', 1325 + 'javelin-vector', 1326 + 'phui-chart-css', 1327 1327 ), 1328 1328 '4a7fb02b' => array( 1329 1329 'javelin-behavior',
+55 -11
src/applications/fact/controller/PhabricatorFactChartController.php
··· 55 55 } 56 56 } 57 57 58 - $x = array_keys($points); 59 - $y = array_values($points); 58 + $datasets = array(); 59 + 60 + $datasets[] = array( 61 + 'x' => array_keys($points), 62 + 'y' => array_values($points), 63 + 'color' => '#ff0000', 64 + ); 65 + 66 + 67 + // Add a dummy "y = x" dataset to prove we can draw multiple datasets. 68 + $x_min = min(array_keys($points)); 69 + $x_max = max(array_keys($points)); 70 + $x_range = ($x_max - $x_min) / 4; 71 + $linear = array(); 72 + foreach ($points as $x => $y) { 73 + $linear[$x] = count($points) * (($x - $x_min) / $x_range); 74 + } 75 + $datasets[] = array( 76 + 'x' => array_keys($linear), 77 + 'y' => array_values($linear), 78 + 'color' => '#0000ff', 79 + ); 80 + 60 81 61 82 $id = celerity_generate_unique_node_id(); 62 83 $chart = phutil_tag( ··· 70 91 71 92 require_celerity_resource('d3'); 72 93 73 - Javelin::initBehavior('line-chart', array( 74 - 'hardpoint' => $id, 75 - 'x' => array($x), 76 - 'y' => array($y), 77 - 'yMax' => max(0, max($y)), 78 - 'yMin' => min(0, min($y)), 79 - 'xformat' => 'epoch', 80 - 'colors' => array('#0000ff'), 81 - )); 94 + $y_min = 0; 95 + $y_max = 0; 96 + $x_min = null; 97 + $x_max = 0; 98 + foreach ($datasets as $dataset) { 99 + if (!$dataset['y']) { 100 + continue; 101 + } 102 + 103 + $y_min = min($y_min, min($dataset['y'])); 104 + $y_max = max($y_max, max($dataset['y'])); 105 + 106 + if ($x_min === null) { 107 + $x_min = min($dataset['x']); 108 + } else { 109 + $x_min = min($x_min, min($dataset['x'])); 110 + } 111 + 112 + $x_max = max($x_max, max($dataset['x'])); 113 + } 114 + 115 + Javelin::initBehavior( 116 + 'line-chart', 117 + array( 118 + 'hardpoint' => $id, 119 + 'datasets' => $datasets, 120 + 'xMin' => $x_min, 121 + 'xMax' => $x_max, 122 + 'yMin' => $y_min, 123 + 'yMax' => $y_max, 124 + 'xformat' => 'epoch', 125 + )); 82 126 83 127 $box = id(new PHUIObjectBoxView()) 84 128 ->setHeaderText(pht('Count of %s', $fact->getName()))
+51 -44
webroot/rsrc/js/application/maniphest/behavior-line-chart.js
··· 57 57 .attr('width', size.width) 58 58 .attr('height', size.height); 59 59 60 - var line = d3.svg.line() 61 - .x(function(d) { return x(d.date); }) 62 - .y(function(d) { return y(d.count); }); 60 + function as_date(value) { 61 + return new Date(value * 1000); 62 + } 63 63 64 - var data = []; 65 - for (var ii = 0; ii < config.x[0].length; ii++) { 66 - data.push( 67 - { 68 - date: new Date(config.x[0][ii] * 1000), 69 - count: +config.y[0][ii] 70 - }); 71 - } 64 + x.domain([as_date(config.xMin), as_date(config.xMax)]); 65 + y.domain([config.yMin, config.yMax]); 66 + 67 + for (var idx = 0; idx < config.datasets.length; idx++) { 68 + var dataset = config.datasets[idx]; 69 + 70 + var line = d3.svg.line() 71 + .x(function(d) { return x(d.xvalue); }) 72 + .y(function(d) { return y(d.yvalue); }); 73 + 74 + var data = []; 75 + for (var ii = 0; ii < dataset.x.length; ii++) { 76 + data.push( 77 + { 78 + xvalue: as_date(dataset.x[ii]), 79 + yvalue: dataset.y[ii] 80 + }); 81 + } 82 + 83 + g.append('path') 84 + .datum(data) 85 + .attr('class', 'line') 86 + .style('stroke', dataset.color) 87 + .attr('d', line); 88 + 89 + g.selectAll('dot') 90 + .data(data) 91 + .enter() 92 + .append('circle') 93 + .attr('class', 'point') 94 + .attr('r', 3) 95 + .attr('cx', function(d) { return x(d.xvalue); }) 96 + .attr('cy', function(d) { return y(d.yvalue); }) 97 + .on('mouseover', function(d) { 98 + var d_y = d.xvalue.getFullYear(); 72 99 73 - x.domain(d3.extent(data, function(d) { return d.date; })); 100 + // NOTE: Javascript months are zero-based. See PHI1017. 101 + var d_m = d.xvalue.getMonth() + 1; 74 102 75 - var yex = d3.extent(data, function(d) { return d.count; }); 76 - y.domain([config.yMin, config.yMax]); 103 + var d_d = d.xvalue.getDate(); 77 104 78 - g.append('path') 79 - .datum(data) 80 - .attr('class', 'line') 81 - .attr('d', line); 105 + div 106 + .html(d_y + '-' + d_m + '-' + d_d + ': ' + d.yvalue) 107 + .style('opacity', 0.9) 108 + .style('left', (d3.event.pageX - 60) + 'px') 109 + .style('top', (d3.event.pageY - 38) + 'px'); 110 + }) 111 + .on('mouseout', function() { 112 + div.style('opacity', 0); 113 + }); 114 + } 82 115 83 116 g.append('g') 84 117 .attr('class', 'x axis') ··· 94 127 .append('div') 95 128 .attr('class', 'chart-tooltip') 96 129 .style('opacity', 0); 97 - 98 - g.selectAll('dot') 99 - .data(data) 100 - .enter() 101 - .append('circle') 102 - .attr('class', 'point') 103 - .attr('r', 3) 104 - .attr('cx', function(d) { return x(d.date); }) 105 - .attr('cy', function(d) { return y(d.count); }) 106 - .on('mouseover', function(d) { 107 - var d_y = d.date.getFullYear(); 108 - 109 - // NOTE: Javascript months are zero-based. See PHI1017. 110 - var d_m = d.date.getMonth() + 1; 111 - 112 - var d_d = d.date.getDate(); 113 - 114 - div 115 - .html(d_y + '-' + d_m + '-' + d_d + ': ' + d.count) 116 - .style('opacity', 0.9) 117 - .style('left', (d3.event.pageX - 60) + 'px') 118 - .style('top', (d3.event.pageY - 38) + 'px'); 119 - }) 120 - .on('mouseout', function() { 121 - div.style('opacity', 0); 122 - }); 123 130 124 131 });