diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -397,7 +397,7 @@
     'rsrc/js/application/herald/PathTypeahead.js' => 'ad486db3',
     'rsrc/js/application/herald/herald-rule-editor.js' => '0922e81d',
     'rsrc/js/application/maniphest/behavior-batch-selector.js' => '139ef688',
-    'rsrc/js/application/maniphest/behavior-line-chart.js' => 'c8147a20',
+    'rsrc/js/application/maniphest/behavior-line-chart.js' => '11167911',
     'rsrc/js/application/maniphest/behavior-list-edit.js' => 'c687e867',
     'rsrc/js/application/owners/OwnersPathEditor.js' => '2a8b62d9',
     'rsrc/js/application/owners/owners-path-editor.js' => 'ff688a7a',
@@ -625,7 +625,7 @@
     'javelin-behavior-icon-composer' => '38a6cedb',
     'javelin-behavior-launch-icon-composer' => 'a17b84f1',
     'javelin-behavior-lightbox-attachments' => 'c7e748bf',
-    'javelin-behavior-line-chart' => 'c8147a20',
+    'javelin-behavior-line-chart' => '11167911',
     'javelin-behavior-linked-container' => '74446546',
     'javelin-behavior-maniphest-batch-selector' => '139ef688',
     'javelin-behavior-maniphest-list-editor' => 'c687e867',
@@ -1007,6 +1007,12 @@
       'javelin-workflow',
       'phuix-icon-view',
     ),
+    11167911 => array(
+      'javelin-behavior',
+      'javelin-dom',
+      'javelin-vector',
+      'phui-chart-css',
+    ),
     '111bfd2d' => array(
       'javelin-install',
     ),
@@ -1997,12 +2003,6 @@
       'phuix-icon-view',
       'phabricator-busy',
     ),
-    'c8147a20' => array(
-      'javelin-behavior',
-      'javelin-dom',
-      'javelin-vector',
-      'phui-chart-css',
-    ),
     'c9749dcd' => array(
       'javelin-install',
       'javelin-util',
diff --git a/resources/sql/autopatches/20190416.chart.01.storage.sql b/resources/sql/autopatches/20190416.chart.01.storage.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20190416.chart.01.storage.sql
@@ -0,0 +1,6 @@
+CREATE TABLE {$NAMESPACE}_fact.fact_chart (
+  id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+  chartKey BINARY(12) NOT NULL,
+  chartParameters LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+  UNIQUE KEY `key_chart` (chartKey)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3201,6 +3201,7 @@
     'PhabricatorFact' => 'applications/fact/fact/PhabricatorFact.php',
     'PhabricatorFactAggregate' => 'applications/fact/storage/PhabricatorFactAggregate.php',
     'PhabricatorFactApplication' => 'applications/fact/application/PhabricatorFactApplication.php',
+    'PhabricatorFactChart' => 'applications/fact/storage/PhabricatorFactChart.php',
     'PhabricatorFactChartController' => 'applications/fact/controller/PhabricatorFactChartController.php',
     'PhabricatorFactController' => 'applications/fact/controller/PhabricatorFactController.php',
     'PhabricatorFactCursor' => 'applications/fact/storage/PhabricatorFactCursor.php',
@@ -9229,6 +9230,10 @@
     'PhabricatorFact' => 'Phobject',
     'PhabricatorFactAggregate' => 'PhabricatorFactDAO',
     'PhabricatorFactApplication' => 'PhabricatorApplication',
+    'PhabricatorFactChart' => array(
+      'PhabricatorFactDAO',
+      'PhabricatorPolicyInterface',
+    ),
     'PhabricatorFactChartController' => 'PhabricatorFactController',
     'PhabricatorFactController' => 'PhabricatorController',
     'PhabricatorFactCursor' => 'PhabricatorFactDAO',
diff --git a/src/applications/fact/controller/PhabricatorFactChartController.php b/src/applications/fact/controller/PhabricatorFactChartController.php
--- a/src/applications/fact/controller/PhabricatorFactChartController.php
+++ b/src/applications/fact/controller/PhabricatorFactChartController.php
@@ -74,6 +74,8 @@
       'hardpoint' => $id,
       'x' => array($x),
       'y' => array($y),
+      'yMax' => max(0, max($y)),
+      'yMin' => min(0, min($y)),
       'xformat' => 'epoch',
       'colors' => array('#0000ff'),
     ));
@@ -82,8 +84,9 @@
       ->setHeaderText(pht('Count of %s', $fact->getName()))
       ->appendChild($chart);
 
-    $crumbs = $this->buildApplicationCrumbs();
-    $crumbs->addTextCrumb(pht('Chart'));
+    $crumbs = $this->buildApplicationCrumbs()
+      ->addTextCrumb(pht('Chart'))
+      ->setBorder(true);
 
     $title = pht('Chart');
 
diff --git a/src/applications/fact/storage/PhabricatorFactChart.php b/src/applications/fact/storage/PhabricatorFactChart.php
new file mode 100644
--- /dev/null
+++ b/src/applications/fact/storage/PhabricatorFactChart.php
@@ -0,0 +1,69 @@
+<?php
+
+final class PhabricatorFactChart
+  extends PhabricatorFactDAO
+  implements PhabricatorPolicyInterface {
+
+  protected $chartKey;
+  protected $chartParameters = array();
+
+  protected function getConfiguration() {
+    return array(
+      self::CONFIG_SERIALIZATION => array(
+        'chartParameters' => self::SERIALIZATION_JSON,
+      ),
+      self::CONFIG_COLUMN_SCHEMA => array(
+        'chartKey' => 'bytes12',
+      ),
+      self::CONFIG_KEY_SCHEMA => array(
+        'key_chart' => array(
+          'columns' => array('chartKey'),
+          'unique' => true,
+        ),
+      ),
+    ) + parent::getConfiguration();
+  }
+
+  public function setChartParameter($key, $value) {
+    $this->chartParameters[$key] = $value;
+    return $this;
+  }
+
+  public function getChartParameter($key, $default = null) {
+    return idx($this->chartParameters, $key, $default);
+  }
+
+  public function save() {
+    if ($this->getID()) {
+      throw new Exception(
+        pht(
+          'Chart configurations are not mutable. You can not update or '.
+          'overwrite an existing chart configuration.'));
+    }
+
+    $digest = serialize($this->chartParameters);
+    $digest = PhabricatorHash::digestForIndex($digest);
+
+    $this->chartKey = $digest;
+
+    return parent::save();
+  }
+
+/* -(  PhabricatorPolicyInterface  )----------------------------------------- */
+
+  public function getCapabilities() {
+    return array(
+      PhabricatorPolicyCapability::CAN_VIEW,
+    );
+  }
+
+  public function getPolicy($capability) {
+    return PhabricatorPolicies::getMostOpenPolicy();
+  }
+
+  public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+    return false;
+  }
+
+
+}
diff --git a/webroot/rsrc/js/application/maniphest/behavior-line-chart.js b/webroot/rsrc/js/application/maniphest/behavior-line-chart.js
--- a/webroot/rsrc/js/application/maniphest/behavior-line-chart.js
+++ b/webroot/rsrc/js/application/maniphest/behavior-line-chart.js
@@ -8,7 +8,7 @@
 
 JX.behavior('line-chart', function(config) {
 
-  function fn(n) {
+  function css_function(n) {
     return n + '(' + JX.$A(arguments).slice(1).join(', ') + ')';
   }
 
@@ -50,7 +50,7 @@
     .attr('class', 'chart');
 
   var g = svg.append('g')
-      .attr('transform', fn('translate', padding.left, padding.top));
+      .attr('transform', css_function('translate', padding.left, padding.top));
 
   g.append('rect')
       .attr('class', 'inner')
@@ -73,9 +73,7 @@
   x.domain(d3.extent(data, function(d) { return d.date; }));
 
   var yex = d3.extent(data, function(d) { return d.count; });
-  yex[0] = 0;
-  yex[1] = yex[1] * 1.05;
-  y.domain(yex);
+  y.domain([config.yMin, config.yMax]);
 
   g.append('path')
     .datum(data)
@@ -84,12 +82,12 @@
 
   g.append('g')
     .attr('class', 'x axis')
-    .attr('transform', fn('translate', 0, size.height))
+    .attr('transform', css_function('translate', 0, size.height))
     .call(xAxis);
 
   g.append('g')
     .attr('class', 'y axis')
-    .attr('transform', fn('translate', 0, 0))
+    .attr('transform', css_function('translate', 0, 0))
     .call(yAxis);
 
   var div = d3.select('body')