WIP #120 History chart based on attributes
This commit is contained in:
parent
c20200b609
commit
91db34badb
@ -4,6 +4,13 @@ class ClimateEntity extends Entity {
|
|||||||
@override
|
@override
|
||||||
double widgetHeight = 38.0;
|
double widgetHeight = 38.0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
EntityHistoryConfig historyConfig = EntityHistoryConfig(
|
||||||
|
chartType: EntityHistoryWidgetType.numericAttributes,
|
||||||
|
numericState: false,
|
||||||
|
numericAttributesToShow: ["temperature", "current_temperature"]
|
||||||
|
);
|
||||||
|
|
||||||
static const SUPPORT_TARGET_TEMPERATURE = 1;
|
static const SUPPORT_TARGET_TEMPERATURE = 1;
|
||||||
static const SUPPORT_TARGET_TEMPERATURE_HIGH = 2;
|
static const SUPPORT_TARGET_TEMPERATURE_HIGH = 2;
|
||||||
static const SUPPORT_TARGET_TEMPERATURE_LOW = 4;
|
static const SUPPORT_TARGET_TEMPERATURE_LOW = 4;
|
||||||
|
@ -38,7 +38,9 @@ class Entity {
|
|||||||
|
|
||||||
List<Entity> childEntities = [];
|
List<Entity> childEntities = [];
|
||||||
List<String> attributesToShow = ["all"];
|
List<String> attributesToShow = ["all"];
|
||||||
int historyWidgetType = EntityHistoryWidgetType.simple;
|
EntityHistoryConfig historyConfig = EntityHistoryConfig(
|
||||||
|
chartType: EntityHistoryWidgetType.simple
|
||||||
|
);
|
||||||
|
|
||||||
String get displayName =>
|
String get displayName =>
|
||||||
attributes["friendly_name"] ?? (attributes["name"] ?? "_");
|
attributes["friendly_name"] ?? (attributes["name"] ?? "_");
|
||||||
@ -136,7 +138,7 @@ class Entity {
|
|||||||
|
|
||||||
Widget buildHistoryWidget() {
|
Widget buildHistoryWidget() {
|
||||||
return EntityHistoryWidget(
|
return EntityHistoryWidget(
|
||||||
type: historyWidgetType,
|
config: historyConfig,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,10 @@ class SunEntity extends Entity {
|
|||||||
class SensorEntity extends Entity {
|
class SensorEntity extends Entity {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int historyWidgetType = EntityHistoryWidgetType.valueToTime;
|
EntityHistoryConfig historyConfig = EntityHistoryConfig(
|
||||||
|
chartType: EntityHistoryWidgetType.numericState,
|
||||||
|
numericState: true
|
||||||
|
);
|
||||||
|
|
||||||
SensorEntity(Map rawData) : super(rawData);
|
SensorEntity(Map rawData) : super(rawData);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class EntityColors {
|
|||||||
charts.Color c1 = charts.MaterialPalette.getOrderedPalettes(id + 1)[id].shadeDefault;
|
charts.Color c1 = charts.MaterialPalette.getOrderedPalettes(id + 1)[id].shadeDefault;
|
||||||
return Color.fromARGB(c1.a, c1.r, c1.g, c1.b);
|
return Color.fromARGB(c1.a, c1.r, c1.g, c1.b);
|
||||||
} else {
|
} else {
|
||||||
return _stateColors["default"];
|
return _stateColors["on"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
264
lib/entity_widgets/history_chart/combined_history_chart.dart
Normal file
264
lib/entity_widgets/history_chart/combined_history_chart.dart
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
part of '../../main.dart';
|
||||||
|
|
||||||
|
class CombinedHistoryChartWidget extends StatefulWidget {
|
||||||
|
final rawHistory;
|
||||||
|
final EntityHistoryConfig config;
|
||||||
|
|
||||||
|
const CombinedHistoryChartWidget({Key key, @required this.rawHistory, @required this.config}) : super(key: key);
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() {
|
||||||
|
return new _CombinedHistoryChartWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CombinedHistoryChartWidgetState extends State<CombinedHistoryChartWidget> {
|
||||||
|
|
||||||
|
int _selectedId = -1;
|
||||||
|
List<charts.Series<CombinedEntityStateHistoryMoment, DateTime>> _parsedHistory;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
_parsedHistory = _parseHistory();
|
||||||
|
DateTime selectedTime;
|
||||||
|
List<String> selectedStates = [];
|
||||||
|
List<int> colorIndexes = [];
|
||||||
|
if ((_selectedId > -1) && (_parsedHistory != null) && (_parsedHistory.first.data.length >= (_selectedId + 1))) {
|
||||||
|
selectedTime = _parsedHistory.first.data[_selectedId].time;
|
||||||
|
_parsedHistory.where((item) { return item.id == "value"; }).forEach((item) {
|
||||||
|
selectedStates.add("${item.data[_selectedId].value}");
|
||||||
|
colorIndexes.add(item.data[_selectedId].colorId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
CombinedHistoryControlWidget(
|
||||||
|
selectedTimeStart: selectedTime,
|
||||||
|
selectedStates: selectedStates,
|
||||||
|
onPrevTap: () => _selectPrev(),
|
||||||
|
onNextTap: () => _selectNext(),
|
||||||
|
colorIndexes: colorIndexes,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 150.0,
|
||||||
|
child: charts.TimeSeriesChart(
|
||||||
|
_parsedHistory,
|
||||||
|
animate: false,
|
||||||
|
primaryMeasureAxis: new charts.NumericAxisSpec(
|
||||||
|
tickProviderSpec:
|
||||||
|
new charts.BasicNumericTickProviderSpec(zeroBound: false)),
|
||||||
|
dateTimeFactory: const charts.LocalDateTimeFactory(),
|
||||||
|
defaultRenderer: charts.LineRendererConfig(includeArea: false),
|
||||||
|
customSeriesRenderers: [
|
||||||
|
new charts.PointRendererConfig(
|
||||||
|
// ID used to link series to this renderer.
|
||||||
|
customRendererId: 'valuePoints')
|
||||||
|
],
|
||||||
|
/*primaryMeasureAxis: charts.NumericAxisSpec(
|
||||||
|
renderSpec: charts.NoneRenderSpec()
|
||||||
|
),*/
|
||||||
|
selectionModels: [
|
||||||
|
new charts.SelectionModelConfig(
|
||||||
|
type: charts.SelectionModelType.info,
|
||||||
|
listener: (model) => _onSelectionChanged(model),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
behaviors: [
|
||||||
|
charts.PanAndZoomBehavior(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
double _parseToDouble(temp1) {
|
||||||
|
if (temp1 is int) {
|
||||||
|
return temp1.toDouble();
|
||||||
|
} else if (temp1 is double) {
|
||||||
|
return temp1;
|
||||||
|
} else {
|
||||||
|
return double.tryParse("$temp1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<charts.Series<CombinedEntityStateHistoryMoment, DateTime>> _parseHistory() {
|
||||||
|
TheLogger.debug(" parsing history...");
|
||||||
|
Map<String, List<CombinedEntityStateHistoryMoment>> dataList = {};
|
||||||
|
int colorIdCounter = 0;
|
||||||
|
widget.config.numericAttributesToShow.forEach((String attrName) {
|
||||||
|
TheLogger.debug(" parsing attribute $attrName");
|
||||||
|
List<CombinedEntityStateHistoryMoment> data = [];
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
for (var i = 0; i < widget.rawHistory.length; i++) {
|
||||||
|
var stateData = widget.rawHistory[i];
|
||||||
|
DateTime time = DateTime.tryParse(stateData["last_updated"])?.toLocal();
|
||||||
|
if (stateData["attributes"] != null) {
|
||||||
|
data.add(CombinedEntityStateHistoryMoment(_parseToDouble(stateData["attributes"]["$attrName"]), stateData["state"], time, i, colorIdCounter));
|
||||||
|
} else {
|
||||||
|
data.add(CombinedEntityStateHistoryMoment(null, stateData["state"], time, i, colorIdCounter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.add(CombinedEntityStateHistoryMoment(data.last.value, data.last.state, now, widget.rawHistory.length, colorIdCounter));
|
||||||
|
dataList.addAll({attrName: data});
|
||||||
|
colorIdCounter += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
if ((_selectedId == -1) && (dataList.isNotEmpty)) {
|
||||||
|
_selectedId = 0;
|
||||||
|
}
|
||||||
|
List<charts.Series<CombinedEntityStateHistoryMoment, DateTime>> result = [];
|
||||||
|
dataList.forEach((attrName, dataItem) {
|
||||||
|
TheLogger.debug(" adding ${dataItem.length} data values");
|
||||||
|
result.addAll([
|
||||||
|
new charts.Series<CombinedEntityStateHistoryMoment, DateTime>(
|
||||||
|
id: "value",
|
||||||
|
colorFn: (CombinedEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("_", historyMoment.colorId),
|
||||||
|
domainFn: (CombinedEntityStateHistoryMoment historyMoment, _) => historyMoment.time,
|
||||||
|
measureFn: (CombinedEntityStateHistoryMoment historyMoment, _) => historyMoment.value,
|
||||||
|
data: dataItem,
|
||||||
|
),
|
||||||
|
new charts.Series<CombinedEntityStateHistoryMoment, DateTime>(
|
||||||
|
id: "points",
|
||||||
|
radiusPxFn: (CombinedEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 5.0 : 1.0,
|
||||||
|
colorFn: (CombinedEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("_", historyMoment.colorId),
|
||||||
|
domainFn: (CombinedEntityStateHistoryMoment historyMoment, _) => historyMoment.time,
|
||||||
|
measureFn: (CombinedEntityStateHistoryMoment historyMoment, _) => historyMoment.value,
|
||||||
|
data: dataItem,
|
||||||
|
)..setAttribute(charts.rendererIdKey, 'valuePoints')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _selectPrev() {
|
||||||
|
if (_selectedId > 0) {
|
||||||
|
setState(() {
|
||||||
|
_selectedId -= 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _selectNext() {
|
||||||
|
if (_selectedId < (_parsedHistory.first.data.length - 1)) {
|
||||||
|
setState(() {
|
||||||
|
_selectedId += 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onSelectionChanged(charts.SelectionModel model) {
|
||||||
|
final selectedDatum = model.selectedDatum;
|
||||||
|
|
||||||
|
int selectedId;
|
||||||
|
|
||||||
|
if (selectedDatum.isNotEmpty) {
|
||||||
|
selectedId = selectedDatum.first.datum.id;
|
||||||
|
setState(() {
|
||||||
|
_selectedId = selectedId;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CombinedHistoryControlWidget extends StatelessWidget {
|
||||||
|
|
||||||
|
final Function onPrevTap;
|
||||||
|
final Function onNextTap;
|
||||||
|
final DateTime selectedTimeStart;
|
||||||
|
final DateTime selectedTimeEnd;
|
||||||
|
final List<String> selectedStates;
|
||||||
|
final List<int> colorIndexes;
|
||||||
|
|
||||||
|
const CombinedHistoryControlWidget({Key key, this.onPrevTap, this.onNextTap, this.selectedTimeStart, this.selectedTimeEnd, this.selectedStates, @ required this.colorIndexes}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (selectedTimeStart != null) {
|
||||||
|
return
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.chevron_left),
|
||||||
|
padding: EdgeInsets.all(0.0),
|
||||||
|
iconSize: 40.0,
|
||||||
|
onPressed: onPrevTap,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(right: 10.0),
|
||||||
|
child: _buildStates(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_buildTime(),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.chevron_right),
|
||||||
|
padding: EdgeInsets.all(0.0),
|
||||||
|
iconSize: 40.0,
|
||||||
|
onPressed: onNextTap,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return Container(height: 48.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildStates() {
|
||||||
|
List<Widget> children = [];
|
||||||
|
for (int i = 0; i < selectedStates.length; i++) {
|
||||||
|
children.add(
|
||||||
|
Text(
|
||||||
|
"${selectedStates[i]}",
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: EntityColors.historyStateColor(selectedStates[i], colorIndexes[i]),
|
||||||
|
fontSize: 22.0
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTime() {
|
||||||
|
List<Widget> children = [];
|
||||||
|
children.add(
|
||||||
|
Text("${formatDate(selectedTimeStart, [M, ' ', d, ', ', HH, ':', nn, ':', ss])}", textAlign: TextAlign.left,)
|
||||||
|
);
|
||||||
|
if (selectedTimeEnd != null) {
|
||||||
|
children.add(
|
||||||
|
Text("${formatDate(selectedTimeEnd, [M, ' ', d, ', ', HH, ':', nn, ':', ss])}", textAlign: TextAlign.left,)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class CombinedEntityStateHistoryMoment {
|
||||||
|
final DateTime time;
|
||||||
|
final double value;
|
||||||
|
final int id;
|
||||||
|
final int colorId;
|
||||||
|
final String state;
|
||||||
|
|
||||||
|
CombinedEntityStateHistoryMoment(this.value, this.state, this.time, this.id, this.colorId);
|
||||||
|
}
|
@ -2,15 +2,24 @@ part of '../../main.dart';
|
|||||||
|
|
||||||
class EntityHistoryWidgetType {
|
class EntityHistoryWidgetType {
|
||||||
static const int simple = 0;
|
static const int simple = 0;
|
||||||
static const int valueToTime = 1;
|
static const int numericState = 1;
|
||||||
static const int randomColors = 2;
|
static const int numericAttributes = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EntityHistoryConfig {
|
||||||
|
final int chartType;
|
||||||
|
final List<String> numericAttributesToShow;
|
||||||
|
final bool numericState;
|
||||||
|
|
||||||
|
EntityHistoryConfig({this.chartType, this.numericAttributesToShow, this.numericState: true});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class EntityHistoryWidget extends StatefulWidget {
|
class EntityHistoryWidget extends StatefulWidget {
|
||||||
|
|
||||||
final int type;
|
final EntityHistoryConfig config;
|
||||||
|
|
||||||
const EntityHistoryWidget({Key key, @required this.type}) : super(key: key);
|
const EntityHistoryWidget({Key key, @required this.config}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_EntityHistoryWidgetState createState() {
|
_EntityHistoryWidgetState createState() {
|
||||||
@ -74,7 +83,7 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> {
|
|||||||
}
|
}
|
||||||
children.add(Divider());
|
children.add(Divider());
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.fromLTRB(0.0, Entity.rowPadding, 0.0, Entity.rowPadding),
|
padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, Entity.rowPadding),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: children,
|
children: children,
|
||||||
),
|
),
|
||||||
@ -82,20 +91,34 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _selectChartWidget() {
|
Widget _selectChartWidget() {
|
||||||
switch (widget.type) {
|
TheLogger.debug(" selecting history widget (${widget.config.chartType})");
|
||||||
|
switch (widget.config.chartType) {
|
||||||
|
|
||||||
case EntityHistoryWidgetType.simple: {
|
case EntityHistoryWidgetType.simple: {
|
||||||
|
TheLogger.debug(" Simple selected");
|
||||||
return SimpleStateHistoryChartWidget(
|
return SimpleStateHistoryChartWidget(
|
||||||
rawHistory: _history,
|
rawHistory: _history,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
case EntityHistoryWidgetType.valueToTime: {
|
case EntityHistoryWidgetType.numericState: {
|
||||||
|
TheLogger.debug(" EntityHistory selected");
|
||||||
return NumericStateHistoryChartWidget(
|
return NumericStateHistoryChartWidget(
|
||||||
rawHistory: _history,
|
rawHistory: _history,
|
||||||
|
config: widget.config,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
case EntityHistoryWidgetType.numericAttributes: {
|
||||||
|
TheLogger.debug(" NumericAttributes selected");
|
||||||
|
return CombinedHistoryChartWidget(
|
||||||
|
rawHistory: _history,
|
||||||
|
config: widget.config,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
TheLogger.debug(" Simple selected as default");
|
||||||
return SimpleStateHistoryChartWidget(
|
return SimpleStateHistoryChartWidget(
|
||||||
rawHistory: _history,
|
rawHistory: _history,
|
||||||
);
|
);
|
||||||
|
@ -2,8 +2,9 @@ part of '../../main.dart';
|
|||||||
|
|
||||||
class NumericStateHistoryChartWidget extends StatefulWidget {
|
class NumericStateHistoryChartWidget extends StatefulWidget {
|
||||||
final rawHistory;
|
final rawHistory;
|
||||||
|
final EntityHistoryConfig config;
|
||||||
|
|
||||||
const NumericStateHistoryChartWidget({Key key, this.rawHistory}) : super(key: key);
|
const NumericStateHistoryChartWidget({Key key, @required this.rawHistory, @required this.config}) : super(key: key);
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -86,15 +87,15 @@ class _NumericStateHistoryChartWidgetState extends State<NumericStateHistoryChar
|
|||||||
return [
|
return [
|
||||||
new charts.Series<NumericEntityStateHistoryMoment, DateTime>(
|
new charts.Series<NumericEntityStateHistoryMoment, DateTime>(
|
||||||
id: 'State',
|
id: 'State',
|
||||||
colorFn: (NumericEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("unavailable", historyMoment.id),
|
colorFn: (NumericEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("on", -1),
|
||||||
domainFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.time,
|
domainFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.time,
|
||||||
measureFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.value,
|
measureFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.value,
|
||||||
data: data,
|
data: data,
|
||||||
),
|
),
|
||||||
new charts.Series<NumericEntityStateHistoryMoment, DateTime>(
|
new charts.Series<NumericEntityStateHistoryMoment, DateTime>(
|
||||||
id: 'State',
|
id: 'State',
|
||||||
radiusPxFn: (NumericEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 5.0 : 2.0,
|
radiusPxFn: (NumericEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 5.0 : 1.0,
|
||||||
colorFn: (NumericEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("off", historyMoment.id),
|
colorFn: (NumericEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("on", -1),
|
||||||
domainFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.time,
|
domainFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.time,
|
||||||
measureFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.value,
|
measureFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.value,
|
||||||
data: data,
|
data: data,
|
||||||
@ -111,7 +112,7 @@ class _NumericStateHistoryChartWidgetState extends State<NumericStateHistoryChar
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _selectNext() {
|
void _selectNext() {
|
||||||
if (_selectedId < (_parsedHistory.first.data.length - 2)) {
|
if (_selectedId < (_parsedHistory.first.data.length - 1)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedId += 1;
|
_selectedId += 1;
|
||||||
});
|
});
|
||||||
|
@ -39,7 +39,7 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW
|
|||||||
selectedState: selectedState,
|
selectedState: selectedState,
|
||||||
onPrevTap: () => _selectPrev(),
|
onPrevTap: () => _selectPrev(),
|
||||||
onNextTap: () => _selectNext(),
|
onNextTap: () => _selectNext(),
|
||||||
colorIndex: _selectedId,
|
colorIndex: _parsedHistory.first.data[_selectedId].colorId,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 70.0,
|
height: 70.0,
|
||||||
@ -68,6 +68,7 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW
|
|||||||
List<charts.Series<SimpleEntityStateHistoryMoment, DateTime>> _parseHistory() {
|
List<charts.Series<SimpleEntityStateHistoryMoment, DateTime>> _parseHistory() {
|
||||||
List<SimpleEntityStateHistoryMoment> data = [];
|
List<SimpleEntityStateHistoryMoment> data = [];
|
||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
|
Map<String, int> cachedStates = {};
|
||||||
for (var i = 0; i < widget.rawHistory.length; i++) {
|
for (var i = 0; i < widget.rawHistory.length; i++) {
|
||||||
var stateData = widget.rawHistory[i];
|
var stateData = widget.rawHistory[i];
|
||||||
DateTime startTime = DateTime.tryParse(stateData["last_updated"])?.toLocal();
|
DateTime startTime = DateTime.tryParse(stateData["last_updated"])?.toLocal();
|
||||||
@ -77,9 +78,12 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW
|
|||||||
} else {
|
} else {
|
||||||
endTime = now;
|
endTime = now;
|
||||||
}
|
}
|
||||||
data.add(SimpleEntityStateHistoryMoment(stateData["state"], startTime, endTime, i));
|
if (cachedStates[stateData["state"]] == null) {
|
||||||
|
cachedStates.addAll({"${stateData["state"]}": cachedStates.length});
|
||||||
}
|
}
|
||||||
data.add(SimpleEntityStateHistoryMoment(data.last.state, now, null, widget.rawHistory.length));
|
data.add(SimpleEntityStateHistoryMoment(stateData["state"], startTime, endTime, i, cachedStates[stateData["state"]]));
|
||||||
|
}
|
||||||
|
data.add(SimpleEntityStateHistoryMoment(data.last.state, now, null, widget.rawHistory.length, data.last.colorId));
|
||||||
if (_selectedId == -1) {
|
if (_selectedId == -1) {
|
||||||
_selectedId = 0;
|
_selectedId = 0;
|
||||||
}
|
}
|
||||||
@ -87,7 +91,7 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW
|
|||||||
new charts.Series<SimpleEntityStateHistoryMoment, DateTime>(
|
new charts.Series<SimpleEntityStateHistoryMoment, DateTime>(
|
||||||
id: 'State',
|
id: 'State',
|
||||||
strokeWidthPxFn: (SimpleEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 70.0 : 40.0,
|
strokeWidthPxFn: (SimpleEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 70.0 : 40.0,
|
||||||
colorFn: (SimpleEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor(historyMoment.state, historyMoment.id),
|
colorFn: (SimpleEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor(historyMoment.state, historyMoment.colorId),
|
||||||
domainFn: (SimpleEntityStateHistoryMoment historyMoment, _) => historyMoment.startTime,
|
domainFn: (SimpleEntityStateHistoryMoment historyMoment, _) => historyMoment.startTime,
|
||||||
measureFn: (SimpleEntityStateHistoryMoment historyMoment, _) => 0,
|
measureFn: (SimpleEntityStateHistoryMoment historyMoment, _) => 0,
|
||||||
data: data,
|
data: data,
|
||||||
@ -205,6 +209,7 @@ class SimpleEntityStateHistoryMoment {
|
|||||||
final DateTime endTime;
|
final DateTime endTime;
|
||||||
final String state;
|
final String state;
|
||||||
final int id;
|
final int id;
|
||||||
|
final int colorId;
|
||||||
|
|
||||||
SimpleEntityStateHistoryMoment(this.state, this.startTime, this.endTime, this.id);
|
SimpleEntityStateHistoryMoment(this.state, this.startTime, this.endTime, this.id, this.colorId);
|
||||||
}
|
}
|
@ -41,6 +41,7 @@ part 'entity_widgets/entity_page_container.dart';
|
|||||||
part 'entity_widgets/history_chart/entity_history.dart';
|
part 'entity_widgets/history_chart/entity_history.dart';
|
||||||
part 'entity_widgets/history_chart/simple_state_history_chart.dart';
|
part 'entity_widgets/history_chart/simple_state_history_chart.dart';
|
||||||
part 'entity_widgets/history_chart/numeric_state_history_chart.dart';
|
part 'entity_widgets/history_chart/numeric_state_history_chart.dart';
|
||||||
|
part 'entity_widgets/history_chart/combined_history_chart.dart';
|
||||||
part 'entity_widgets/state/switch_state.dart';
|
part 'entity_widgets/state/switch_state.dart';
|
||||||
part 'entity_widgets/state/slider_state.dart';
|
part 'entity_widgets/state/slider_state.dart';
|
||||||
part 'entity_widgets/state/text_input_state.dart';
|
part 'entity_widgets/state/text_input_state.dart';
|
||||||
|
Reference in New Issue
Block a user