@@ -35,6 +35,7 @@ import type { HomeAssistant } from "../../types";
3535import { getPeriodicAxisLabelConfig } from "./axis-label" ;
3636import type { CustomLegendOption } from "./ha-chart-base" ;
3737import "./ha-chart-base" ;
38+ import { fillDataGapsAndRoundCaps } from "./round-caps" ;
3839
3940export const supportedStatTypeMap : Record < StatisticType , StatisticType > = {
4041 mean : "mean" ,
@@ -67,7 +68,11 @@ export class StatisticsChart extends LitElement {
6768 @property ( { attribute : false } )
6869 public statTypes : StatisticType [ ] = [ "sum" , "min" , "mean" , "max" ] ;
6970
70- @property ( { attribute : false } ) public chartType : "line" | "bar" = "line" ;
71+ @property ( { attribute : false } ) public chartType :
72+ | "line"
73+ | "line-stack"
74+ | "bar"
75+ | "bar-stack" = "line" ;
7176
7277 @property ( { attribute : false } ) public minYAxis ?: number ;
7378
@@ -326,7 +331,7 @@ export class StatisticsChart extends LitElement {
326331 } ,
327332 position : computeRTL ( this . hass ) ? "right" : "left" ,
328333 scale :
329- this . chartType !== "bar" ||
334+ this . chartType . startsWith ( "line" ) ||
330335 this . logarithmicScale ||
331336 minYAxis !== undefined ||
332337 maxYAxis !== undefined ,
@@ -386,6 +391,8 @@ export class StatisticsChart extends LitElement {
386391 ( await this . _getStatisticsMetaData ( Object . keys ( this . statisticsData ) ) ) ;
387392
388393 let colorIndex = 0 ;
394+ const chartType = this . chartType . startsWith ( "line" ) ? "line" : "bar" ;
395+ const chartStacked = this . chartType . endsWith ( "stack" ) ;
389396 const statisticsData = Object . entries ( this . statisticsData ) ;
390397 const totalDataSets : typeof this . _chartData = [ ] ;
391398 const legendData : {
@@ -471,19 +478,17 @@ export class StatisticsChart extends LitElement {
471478 }
472479 statDataSets . forEach ( ( d , i ) => {
473480 if (
474- this . chartType === "line" &&
481+ chartType === "line" &&
475482 prevEndTime &&
476483 prevValues &&
477484 prevEndTime . getTime ( ) !== start . getTime ( )
478485 ) {
479486 // if the end of the previous data doesn't match the start of the current data,
480487 // we have to draw a gap so add a value at the end time, and then an empty value.
481- d . data ! . push (
482- this . _transformDataValue ( [ prevEndTime , ...prevValues [ i ] ! ] )
483- ) ;
488+ d . data ! . push ( [ prevEndTime , ...prevValues [ i ] ! ] ) ;
484489 d . data ! . push ( [ prevEndTime , null ] ) ;
485490 }
486- d . data ! . push ( this . _transformDataValue ( [ start , ...dataValues [ i ] ! ] ) ) ;
491+ d . data ! . push ( [ start , ...dataValues [ i ] ! ] ) ;
487492 } ) ;
488493 prevValues = dataValues ;
489494 prevEndTime = end ;
@@ -503,7 +508,8 @@ export class StatisticsChart extends LitElement {
503508 this . statTypes . includes ( "max" ) && statisticsHaveType ( stats , "max" ) ;
504509 const hasMin =
505510 this . statTypes . includes ( "min" ) && statisticsHaveType ( stats , "min" ) ;
506- const drawBands = [ hasMean , hasMax , hasMin ] . filter ( Boolean ) . length > 1 ;
511+ const drawBands =
512+ ! chartStacked && [ hasMean , hasMax , hasMin ] . filter ( Boolean ) . length > 1 ;
507513
508514 const hasState = this . statTypes . includes ( "state" ) ;
509515
@@ -535,8 +541,8 @@ export class StatisticsChart extends LitElement {
535541 const backgroundColor = band ? color + "3F" : color + "7F" ;
536542 const series : LineSeriesOption | BarSeriesOption = {
537543 id : `${ statistic_id } -${ type } ` ,
538- type : this . chartType ,
539- smooth : this . chartType === "line" ? 0.4 : false ,
544+ type : chartType ,
545+ smooth : chartType === "line" ? 0.4 : false ,
540546 cursor : "default" ,
541547 data : [ ] ,
542548 name : name
@@ -555,16 +561,23 @@ export class StatisticsChart extends LitElement {
555561 width : 1.5 ,
556562 } ,
557563 itemStyle :
558- this . chartType === "bar"
564+ chartType === "bar"
559565 ? {
560- borderRadius : [ 4 , 4 , 0 , 0 ] ,
561566 borderColor,
562567 borderWidth : 1.5 ,
563568 }
564569 : undefined ,
565- color : this . chartType === "bar" ? backgroundColor : borderColor ,
570+ color : chartType === "bar" ? backgroundColor : borderColor ,
566571 } ;
567- if ( band && this . chartType === "line" ) {
572+ if ( chartStacked ) {
573+ series . stack = `band-stacked` ;
574+ series . stackStrategy = "samesign" ;
575+ if ( chartType === "line" ) {
576+ ( series as LineSeriesOption ) . areaStyle = {
577+ color : color + "3F" ,
578+ } ;
579+ }
580+ } else if ( band && chartType === "line" ) {
568581 series . stack = `band-${ statistic_id } ` ;
569582 series . stackStrategy = "all" ;
570583 if ( this . _hiddenStats . has ( `${ statistic_id } -${ bandBottom } ` ) ) {
@@ -621,7 +634,7 @@ export class StatisticsChart extends LitElement {
621634 }
622635 } else if (
623636 type === bandTop &&
624- this . chartType === "line" &&
637+ chartType === "line" &&
625638 drawBands &&
626639 ! this . _hiddenStats . has ( `${ statistic_id } -${ bandBottom } ` )
627640 ) {
@@ -645,18 +658,17 @@ export class StatisticsChart extends LitElement {
645658 // For line charts, close out the last stat segment at prevEndTime
646659 const lastEndTime = prevEndTime ;
647660 const lastValues = prevValues ;
648- if ( this . chartType === "line" && lastEndTime && lastValues ) {
661+ if ( chartType === "line" && lastEndTime && lastValues ) {
649662 statDataSets . forEach ( ( d , i ) => {
650- d . data ! . push (
651- this . _transformDataValue ( [ lastEndTime , ...lastValues [ i ] ! ] )
652- ) ;
663+ d . data ! . push ( [ lastEndTime , ...lastValues [ i ] ! ] ) ;
653664 } ) ;
654665 }
655666
656667 // Show current state if required, and units match (or are unknown)
657668 const statisticUnit = getDisplayUnit ( this . hass , statistic_id , meta ) ;
658669 if (
659670 displayCurrentState &&
671+ ! chartStacked &&
660672 ( ! this . unit || ! statisticUnit || this . unit === statisticUnit )
661673 ) {
662674 // Skip external statistics
@@ -677,7 +689,7 @@ export class StatisticsChart extends LitElement {
677689 const val : ( number | null ) [ ] = [ ] ;
678690 if (
679691 type === bandTop &&
680- this . chartType === "line" &&
692+ chartType === "line" &&
681693 drawBands &&
682694 ! this . _hiddenStats . has ( `${ statistic_id } -${ bandBottom } ` )
683695 ) {
@@ -687,9 +699,7 @@ export class StatisticsChart extends LitElement {
687699 } else {
688700 val . push ( currentValue ) ;
689701 }
690- statDataSets [ i ] . data ! . push (
691- this . _transformDataValue ( [ now , ...val ] )
692- ) ;
702+ statDataSets [ i ] . data ! . push ( [ now , ...val ] ) ;
693703 } ) ;
694704 }
695705 }
@@ -701,6 +711,13 @@ export class StatisticsChart extends LitElement {
701711 Array . prototype . push . apply ( legendData , statLegendData ) ;
702712 } ) ;
703713
714+ if ( chartType === "bar" ) {
715+ fillDataGapsAndRoundCaps (
716+ totalDataSets as BarSeriesOption [ ] ,
717+ chartStacked
718+ ) ;
719+ }
720+
704721 legendData . forEach ( ( { id, name, color, borderColor } ) => {
705722 // Add an empty series for the legend
706723 totalDataSets . push ( {
@@ -710,7 +727,7 @@ export class StatisticsChart extends LitElement {
710727 itemStyle : {
711728 borderColor,
712729 } ,
713- type : this . chartType ,
730+ type : chartType ,
714731 data : [ ] ,
715732 xAxisIndex : 1 ,
716733 } ) ;
@@ -728,13 +745,6 @@ export class StatisticsChart extends LitElement {
728745 this . _statisticIds = statisticIds ;
729746 }
730747
731- private _transformDataValue ( val : [ Date , ...( number | null ) [ ] ] ) {
732- if ( this . chartType === "bar" && val [ 1 ] && val [ 1 ] < 0 ) {
733- return { value : val , itemStyle : { borderRadius : [ 0 , 0 , 4 , 4 ] } } ;
734- }
735- return val ;
736- }
737-
738748 private _clampYAxis ( value ?: number | ( ( values : any ) => number ) ) {
739749 if ( this . logarithmicScale ) {
740750 // log(0) is -Infinity, so we need to set a minimum value
0 commit comments