well, I decided to keep them separate, so the graph bit is just that, the old card with all the rest deleted
and yet we can cutout even more, since not used. see all localizations eg.
All depends a bit on what you want to display or not.
- type: custom:weather-chart
weather: weather.buienradar
showing as
ready to be used as you like, standalone or concatenated. maybe even embedded on a button.
console.info(
`%c WEATHER-CHART \n%c Version 0.2`,
'color: orange; font-weight: bold; background: black',
'color: white; font-weight: bold; background: dimgray',
);
const locale = {
da: {
tempHi: "Temperatur",
tempLo: "Temperatur nat",
precip: "Nedbør",
uPress: "hPa",
uSpeed: "m/s",
uPrecip: "mm",
uVisib: "km",
cardinalDirections: [
'N', 'N-NØ', 'NØ', 'Ø-NØ', 'Ø', 'Ø-SØ', 'SØ', 'S-SØ',
'S', 'S-SV', 'SV', 'V-SV', 'V', 'V-NV', 'NV', 'N-NV', 'N'
]
},
en: {
tempHi: "Temperature",
tempLo: "Temperature night",
precip: "Precipitations",
uPress: "hPa",
uSpeed: "km/h",
uPrecip: "mm",
uVisib: "mi",
cardinalDirections: [
'N', 'N-NE', 'NE', 'E-NE', 'E', 'E-SE', 'SE', 'S-SE',
'S', 'S-SW', 'SW', 'W-SW', 'W', 'W-NW', 'NW', 'N-NW', 'N'
]
},
fr: {
tempHi: "Température",
tempLo: "Température nuit",
precip: "Précipitations",
uPress: "hPa",
uSpeed: "m/s",
uPrecip: "mm",
uVisib: "km",
cardinalDirections: [
'N', 'N-NE', 'NE', 'E-NE', 'E', 'E-SE', 'SE', 'S-SE',
'S', 'S-SO', 'SO', 'O-SO', 'O', 'O-NO', 'NO', 'N-NO', 'N'
]
},
nl: {
tempHi: "Max temperatuur",
tempLo: "Min temperatuur",
precip: "Neerslag",
uPress: "hPa",
uSpeed: "km/u",
uPrecip: "mm",
uVisib: "km",
cardinalDirections: [
'N', 'N-NO', 'NO', 'O-NO', 'O', 'O-ZO', 'ZO', 'Z-ZO',
'Z', 'Z-ZW', 'ZW', 'W-ZW', 'W', 'W-NW', 'NW', 'N-NW', 'N'
]
},
ru: {
tempHi: "Температура",
tempLo: "Температура ночью",
precip: "Осадки",
uPress: "гПа",
uSpeed: "м/с",
uPrecip: "мм",
uVisib: "км",
cardinalDirections: [
'С', 'С-СВ', 'СВ', 'В-СВ', 'В', 'В-ЮВ', 'ЮВ', 'Ю-ЮВ',
'Ю', 'Ю-ЮЗ', 'ЮЗ', 'З-ЮЗ', 'З', 'З-СЗ', 'СЗ', 'С-СЗ', 'С'
]
}
};
class WeatherChart extends Polymer.Element {
static get template() {
return Polymer.html`
<style>
ha-icon {
color: var(--paper-item-icon-color);
}
.card {
padding: 16px;
}
</style>
<ha-card header="[[title]]">
<div class="card">
<ha-chart-base data="[[ChartData]]" options="[[ChartOptions]]" ></ha-chart-base>
</div>
</ha-card>
`;
}
static get properties() {
return {
config: Object,
mode: String,
weatherObj: {
type: Object,
observer: 'dataChanged',
},
};
}
setConfig(config) {
this.config = config;
this.title = config.title;
this.weatherObj = config.weather;
this.mode = config.mode;
if (!config.weather) {
throw new Error('Please define "weather" entity in the card config');
}
}
set hass(hass) {
this._hass = hass;
this.lang = this.config.locale in hass.states ? hass.states[this.config.locale] : this._hass.language;
this.weatherObj = this.config.weather in hass.states ? hass.states[this.config.weather] : null;
this.forecast = this.weatherObj.attributes.forecast.slice(0,9);
}
dataChanged() {
this.drawChart();
}
ll(str) {
if (locale[this.lang] === undefined)
return locale.en[str];
return locale[this.lang][str];
}
drawChart() {
var data = this.weatherObj.attributes.forecast.slice(0,9);
var tempUnit = this._hass.config.unit_system.temperature;
var lengthUnit = this._hass.config.unit_system.length;
var precipUnit = lengthUnit === 'km' ? this.ll('uPrecip') : 'in';
var mode = this.mode;
var i;
if (!this.weatherObj.attributes.forecast) {
return [];
}
var dateTime = [];
var tempHigh = [];
var tempLow = [];
var precip = [];
for (i = 0; i < data.length; i++) {
var d = data[i];
dateTime.push(new Date(d.datetime));
tempHigh.push(d.temperature);
tempLow.push(d.templow);
precip.push(d.precipitation);
}
var style = getComputedStyle(document.body);
var textColor = style.getPropertyValue('--primary-text-color');
var dividerColor = style.getPropertyValue('--divider-color');
const chartData = {
labels: dateTime,
datasets: [
{
label: this.ll('tempHi'),
type: 'line',
data: tempHigh,
yAxisID: 'yTempAxis',
borderColor: 'red',
backgroundColor: 'orange',
borderWidth: 2.0,
lineTension: 0.4,
pointRadius: 1.0,
pointHitRadius: 5.0,
fill: false,
tooltip: {
callbacks: {
label: function(context) {
var label = context.dataset.label || '';
return label += ': ' + context.parsed.y + tempUnit;
}
}
}
},
{
label: this.ll('tempLo'),
type: 'line',
data: tempLow,
yAxisID: 'yTempAxis',
borderColor: 'green',
backgroundColor: 'purple',
borderWidth: 2.0,
lineTension: 0.4,
pointRadius: 0.0,
pointHitRadius: 5.0,
fill: false,
tooltip: {
callbacks: {
label: function(context) {
var label = context.dataset.label || '';
return label += ': ' + context.parsed.y + tempUnit;
}
}
}
},
{
label: this.ll('precip'),
type: 'bar',
data: precip,
yAxisID: 'yPrecipAxis',
borderColor: 'skyblue',
backgroundColor: 'steelblue',
maxBarThickness: 15,
barThickness: 8,
tooltip: {
callbacks: {
label: function(context) {
var label = context.dataset.label || '';
return label += ': ' + context.parsed.y + precipUnit;
}
}
}
},
]
}
const chartOptions = {
animation: {
duration: 300,
easing: 'linear',
onComplete: function (animation) {
var chartInstance = animation.chart,
ctx = chartInstance.ctx;
ctx.fillStyle = textColor;
var fontSize = 10;
var fontStyle = 'normal';
var fontFamily = 'Roboto';
ctx.font = fontStyle + ' ' + fontSize + 'px ' + fontFamily;
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
var meta = chartInstance.getDatasetMeta(2);
meta.data.forEach(function (bar, index) {
var data = (Math.round((chartInstance.data.datasets[2].data[index]) * 10) / 10).toFixed(1);
if (data > 0)
ctx.fillText(data, bar.x, bar.y - 5);
});
},
},
legend: {
display: false,
},
scales: {
xAxes: {
type: 'time',
adapters: {
date: {
locale: this._hass.locale,
},
},
// display: true,
ticks: {
display: false,
},
grid: {
display: false,
},
},
xDateAxis: {
type: 'time',
position: 'top',
adapters: {
date: {
locale: this._hass.locale,
},
},
grid: {
display: true,
drawBorder: false,
color: dividerColor,
},
ticks: {
display: true,
source: 'labels',
autoSkip: true,
color: textColor,
maxRotation: 0,
callback: function(value, index, values) {
var date = new Date(0);
date.setUTCMilliseconds(values[index].value);
if (mode == 'hourly') {
return date.toLocaleTimeString(locale, { hour: 'numeric' });
}
return date.toLocaleDateString(locale, { weekday: 'short' });;
},
},
},
yTempAxis: {
position: 'left',
adapters: {
date: {
locale: this._hass.locale,
},
},
grid: {
display: true,
drawBorder: false,
color: dividerColor,
borderDash: [1,3],
},
ticks: {
display: true,
color: textColor,
callback: function(value, index, values) {
return value + 'º';
},
},
afterFit: function(scaleInstance) {
scaleInstance.width = 37;
},
},
yPrecipAxis: {
display: false,
position: 'right',
suggestedMax: 20,
adapters: {
date: {
locale: this._hass.locale,
},
},
grid: {
display: false,
drawBorder: false,
color: dividerColor,
},
ticks: {
display: false,
min: 0,
color: textColor,
},
afterFit: function(scaleInstance) {
scaleInstance.width = 15;
},
},
},
plugins: {
tooltip: {
callbacks: {
title: function(context) {
return new Date(context[0].label).toLocaleDateString(locale, {
month: 'long',
day: 'numeric',
weekday: 'long',
// hour: 'numeric',
// minute: 'numeric',
});
}
}
}
},
}
this.ChartData = chartData;
this.ChartOptions = chartOptions;
/* this.ChartType = chartType;*/
}
_fire(type, detail, options) {
const node = this.shadowRoot;
options = options || {};
detail = (detail === null || detail === undefined) ? {} : detail;
const e = new Event(type, {
bubbles: options.bubbles === undefined ? true : options.bubbles,
cancelable: Boolean(options.cancelable),
composed: options.composed === undefined ? true : options.composed
});
e.detail = detail;
node.dispatchEvent(e);
return e;
}
}
customElements.define('weather-chart', WeatherChart);