From dd46944488927d09e35d6cf0fea7dab3fc10b2b4 Mon Sep 17 00:00:00 2001
From: k-yokoishi <ss.xs.m713@gmail.com>
Date: Tue, 16 Apr 2019 23:26:50 +0900
Subject: [PATCH 1/2] Draw BarChart and LineChart from 0

---
 src/abstract-chart.js | 16 ++++++++++++++--
 src/bar-chart.js      | 14 +++++++-------
 src/line-chart.js     | 41 +++++++++++++++++------------------------
 3 files changed, 38 insertions(+), 33 deletions(-)

diff --git a/src/abstract-chart.js b/src/abstract-chart.js
index d7965e31..a0f460b5 100644
--- a/src/abstract-chart.js
+++ b/src/abstract-chart.js
@@ -3,7 +3,19 @@ import React, {Component} from 'react'
 import {LinearGradient, Line, Text, Defs, Stop} from 'react-native-svg'
 
 class AbstractChart extends Component {
-  calcScaler = data => Math.max(...data) - Math.min(...data) || 1
+  calcScaler = data => Math.max(...data, 0) - Math.min(...data, 0) || 1
+
+  calcBaseHeight = (data, height) => {
+    const min = Math.min(...data)
+    const max = Math.max(...data)
+    if (min >= 0 && max >= 0) {
+      return height
+    } else if (min < 0 && max <= 0) {
+      return 0
+    } else if (min < 0 && max > 0) {
+      return height * max / this.calcScaler(data)
+    }
+  }
 
   renderHorizontalLines = config => {
     const {count, width, height, paddingTop, paddingRight} = config
@@ -58,7 +70,7 @@ class AbstractChart extends Component {
         yLabel = `${yAxisLabel}${data[0].toFixed(decimalPlaces)}`
       } else {
         const label =
-          (this.calcScaler(data) / (count - 1)) * i + Math.min(...data)
+          (this.calcScaler(data) / (count - 1)) * i + Math.min(...data, 0)
         yLabel = `${yAxisLabel}${label.toFixed(decimalPlaces)}`
       }
 
diff --git a/src/bar-chart.js b/src/bar-chart.js
index 92a597f9..115c2ad6 100644
--- a/src/bar-chart.js
+++ b/src/bar-chart.js
@@ -8,9 +8,9 @@ const barWidth = 32
 class BarChart extends AbstractChart {
   renderBars = config => {
     const {data, width, height, paddingTop, paddingRight} = config
-    const baseHeight = (height / 4 * 3) * (Math.max(...data) / this.calcScaler(data)) + paddingTop
+    const baseHeight = this.calcBaseHeight(data, height)
     return data.map((x, i) => {
-      const barHeight = height / 4 * 3 * (x / this.calcScaler(data))
+      const barHeight = height * (x / this.calcScaler(data))
       const barWidth = 32
       return (
         <Rect
@@ -20,9 +20,9 @@ class BarChart extends AbstractChart {
             (i * (width - paddingRight)) / data.length +
             barWidth / 2
           }
-          y={baseHeight - barHeight}
+          y={(baseHeight - barHeight) / 4 * 3 + paddingTop}
           width={barWidth}
-          height={barHeight}
+          height={barHeight / 4 * 3}
           fill="url(#fillShadowGradient)"
         />
       )
@@ -31,9 +31,9 @@ class BarChart extends AbstractChart {
 
   renderBarTops = config => {
     const {data, width, height, paddingTop, paddingRight} = config
-    const baseHeight = (height / 4 * 3) * (Math.max(...data) / this.calcScaler(data)) + paddingTop
+    const baseHeight = this.calcBaseHeight(data, height)
     return data.map((x, i) => {
-      const barHeight = height / 4 * 3 * (x / this.calcScaler(data))
+      const barHeight = height * (x / this.calcScaler(data))
       return (
         <Rect
           key={Math.random()}
@@ -42,7 +42,7 @@ class BarChart extends AbstractChart {
             (i * (width - paddingRight)) / data.length +
             barWidth / 2
           }
-          y={baseHeight - barHeight}
+          y={(baseHeight - barHeight) / 4 * 3 + paddingTop}
           width={barWidth}
           height={2}
           fill={this.props.chartConfig.color(0.6)}
diff --git a/src/line-chart.js b/src/line-chart.js
index 2af2cb8d..d852f759 100644
--- a/src/line-chart.js
+++ b/src/line-chart.js
@@ -78,6 +78,7 @@ class LineChart extends AbstractChart {
     const {data, width, height, paddingRight, paddingTop} = config
     const output = []
     const datas = this.getDatas(data)
+    const baseHeight = this.calcBaseHeight(datas, height)
     config.data.map((dataset, index) => {
       output.push(
         <Polygon
@@ -85,14 +86,11 @@ class LineChart extends AbstractChart {
           points={
             dataset.data
               .map(
-                (x, i) =>
-                  paddingRight +
-                  (i * (width - paddingRight)) / dataset.data.length +
-                  ',' +
-                  ((height / 4) *
-                    3 *
-                    (1 - (x - Math.min(...datas)) / this.calcScaler(datas)) +
-                    paddingTop)
+                (d, i) => {
+                  const x = paddingRight + (i * (width - paddingRight)) / dataset.data.length
+                  const y = (baseHeight - height * (d / this.calcScaler(datas))) / 4 * 3 + paddingTop
+                  return `${x},${y}`
+                }
               )
               .join(' ') +
             ` ${paddingRight +
@@ -116,16 +114,14 @@ class LineChart extends AbstractChart {
     const {width, height, paddingRight, paddingTop, data} = config
     const output = []
     const datas = this.getDatas(data)
+    const baseHeight = this.calcBaseHeight(datas, height)
     data.forEach((dataset, index) => {
       const points = dataset.data.map(
-        (x, i) =>
-          paddingRight +
-          (i * (width - paddingRight)) / dataset.data.length +
-          ',' +
-          ((height / 4) *
-            3 *
-            (1 - (x - Math.min(...datas)) / this.calcScaler(datas)) +
-            paddingTop)
+        (d, i) => {
+          const x  = (i * (width - paddingRight)) / dataset.data.length + paddingRight
+          const y = (baseHeight - height * (d / this.calcScaler(datas))) / 4 * 3 + paddingTop
+          return `${x},${y}`
+        }
       )
 
       output.push(
@@ -153,14 +149,11 @@ class LineChart extends AbstractChart {
       Math.floor(
         paddingRight + (i * (width - paddingRight)) / dataset.data.length
       )
-    const y = i =>
-      Math.floor(
-        (height / 4) *
-          3 *
-          (1 -
-            (dataset.data[i] - Math.min(...datas)) / this.calcScaler(datas)) +
-          paddingTop
-      )
+    const baseHeight = this.calcBaseHeight(datas, height)
+    const y = i => {
+      const yHeight = height * (dataset.data[i] / this.calcScaler(datas))
+      return Math.floor((baseHeight - yHeight) / 4 * 3 + paddingTop)
+    }
 
     return [`M${x(0)},${y(0)}`]
       .concat(

From 1e425a9e3760c6374c3bd3964200637941c65558 Mon Sep 17 00:00:00 2001
From: k-yokoishi <ss.xs.m713@gmail.com>
Date: Tue, 23 Apr 2019 22:54:35 +0900
Subject: [PATCH 2/2] Add prop `fromZero`

Add prop `fromZero` to BarChart and LineChart to
render the charts from 0 not from the minimum value.
---
 README.md             |  4 +++-
 src/abstract-chart.js | 29 ++++++++++++++++++++++++++---
 src/bar-chart.js      |  4 ++--
 src/line-chart.js     |  6 +++---
 4 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md
index 3e52d44a..60ce098f 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,7 @@ const data = {
 | withShadow | boolean | Show shadow for line - default: True |
 | withInnerLines | boolean | Show inner dashed lines - default: True |
 | withOuterLines | boolean | Show outer dashed lines - default: True |
+| fromZero | boolean | Render charts from 0 not from the minimum value. - default: False |
 | yAxisLabel | string | Prepend text to horizontal labels -- default: '' |
 | chartConfig | Object | Configuration object for the chart, see example config object above |
 |decorator | Function | This function takes a [whole bunch](https://github.com/indiespirit/react-native-chart-kit/blob/master/src/line-chart.js#L266) of stuff and can render extra elements, such as data point info or additional markup. |
@@ -197,6 +198,7 @@ const data = {
 | data | Object | Data for the chart - see example above |
 | width | Number | Width of the chart, use 'Dimensions' library to get the width of your screen for responsive |
 | height | Number | Height of the chart |
+| fromZero | boolean | Render charts from 0 not from the minimum value. - default: False |
 | yAxisLabel | string | Prepend text to horizontal labels -- default: '' |
 | chartConfig | Object | Configuration object for the chart, see example config in the beginning of this file |
 
@@ -210,7 +212,7 @@ const data ={
   legend: ['L1', 'L2', 'L3'],
   data: [
     [60, 60, 60],
-    [30,30,60], 
+    [30,30,60],
   ],
   barColors: ['#dfe4ea', '#ced6e0', '#a4b0be'],
  }
diff --git a/src/abstract-chart.js b/src/abstract-chart.js
index a0f460b5..1408b984 100644
--- a/src/abstract-chart.js
+++ b/src/abstract-chart.js
@@ -3,7 +3,13 @@ import React, {Component} from 'react'
 import {LinearGradient, Line, Text, Defs, Stop} from 'react-native-svg'
 
 class AbstractChart extends Component {
-  calcScaler = data => Math.max(...data, 0) - Math.min(...data, 0) || 1
+  calcScaler = data => {
+    if (this.props.fromZero) {
+      return Math.max(...data, 0) - Math.min(...data, 0) || 1
+    } else {
+      return Math.max(...data) - Math.min(...data) || 1
+    }
+  }
 
   calcBaseHeight = (data, height) => {
     const min = Math.min(...data)
@@ -17,6 +23,22 @@ class AbstractChart extends Component {
     }
   }
 
+  calcHeight = (val, data, height) => {
+    const max = Math.max(...data)
+    const min = Math.min(...data)
+    if (min < 0 && max > 0) {
+       return height * (val / this.calcScaler(data))
+    } else if (min >= 0 && max >= 0) {
+      return this.props.fromZero ?
+        height * (val / this.calcScaler(data)) :
+        height * ((val - min) / this.calcScaler(data))
+    } else if (min < 0 && max <= 0) {
+      return this.props.fromZero ?
+        height * (val / this.calcScaler(data)) :
+        height * ((val - max) / this.calcScaler(data))
+    }
+  }
+
   renderHorizontalLines = config => {
     const {count, width, height, paddingTop, paddingRight} = config
     return [...new Array(count)].map((_, i) => {
@@ -69,8 +91,9 @@ class AbstractChart extends Component {
       if (count === 1) {
         yLabel = `${yAxisLabel}${data[0].toFixed(decimalPlaces)}`
       } else {
-        const label =
-          (this.calcScaler(data) / (count - 1)) * i + Math.min(...data, 0)
+        const label = this.props.fromZero ?
+          (this.calcScaler(data) / (count - 1)) * i + Math.min(...data, 0) :
+          (this.calcScaler(data) / (count - 1)) * i + Math.min(...data)
         yLabel = `${yAxisLabel}${label.toFixed(decimalPlaces)}`
       }
 
diff --git a/src/bar-chart.js b/src/bar-chart.js
index 115c2ad6..0efd4058 100644
--- a/src/bar-chart.js
+++ b/src/bar-chart.js
@@ -10,7 +10,7 @@ class BarChart extends AbstractChart {
     const {data, width, height, paddingTop, paddingRight} = config
     const baseHeight = this.calcBaseHeight(data, height)
     return data.map((x, i) => {
-      const barHeight = height * (x / this.calcScaler(data))
+      const barHeight = this.calcHeight(x, data, height)
       const barWidth = 32
       return (
         <Rect
@@ -33,7 +33,7 @@ class BarChart extends AbstractChart {
     const {data, width, height, paddingTop, paddingRight} = config
     const baseHeight = this.calcBaseHeight(data, height)
     return data.map((x, i) => {
-      const barHeight = height * (x / this.calcScaler(data))
+      const barHeight = this.calcHeight(x, data, height)
       return (
         <Rect
           key={Math.random()}
diff --git a/src/line-chart.js b/src/line-chart.js
index d852f759..01315314 100644
--- a/src/line-chart.js
+++ b/src/line-chart.js
@@ -88,7 +88,7 @@ class LineChart extends AbstractChart {
               .map(
                 (d, i) => {
                   const x = paddingRight + (i * (width - paddingRight)) / dataset.data.length
-                  const y = (baseHeight - height * (d / this.calcScaler(datas))) / 4 * 3 + paddingTop
+                  const y = (baseHeight -  this.calcHeight(d, datas, height)) / 4 * 3 + paddingTop
                   return `${x},${y}`
                 }
               )
@@ -119,7 +119,7 @@ class LineChart extends AbstractChart {
       const points = dataset.data.map(
         (d, i) => {
           const x  = (i * (width - paddingRight)) / dataset.data.length + paddingRight
-          const y = (baseHeight - height * (d / this.calcScaler(datas))) / 4 * 3 + paddingTop
+          const y = (baseHeight -  this.calcHeight(d, datas, height)) / 4 * 3 + paddingTop
           return `${x},${y}`
         }
       )
@@ -151,7 +151,7 @@ class LineChart extends AbstractChart {
       )
     const baseHeight = this.calcBaseHeight(datas, height)
     const y = i => {
-      const yHeight = height * (dataset.data[i] / this.calcScaler(datas))
+      const yHeight = this.calcHeight(dataset.data[i], datas, height)
       return Math.floor((baseHeight - yHeight) / 4 * 3 + paddingTop)
     }
 
