Merge pull request #2507 from vvlladd28/feature/digital-gauge/ticks

[2.5] Add support ticks to digital gauge
This commit is contained in:
Vladyslav 2020-03-13 12:28:55 +02:00 committed by GitHub
commit f57ed509fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 263 additions and 70 deletions

View File

@ -51,6 +51,10 @@ let defaultDigitalGaugeOptions = Object.assign({}, canvasGauges.GenericOptions,
neonGlowBrightness: 0, neonGlowBrightness: 0,
colorTicks: 'gray',
tickWidth: 4,
ticks: [],
isMobile: false isMobile: false
}); });
@ -133,6 +137,13 @@ export default class CanvasDigitalGauge extends canvasGauges.BaseGauge {
} }
} }
options.ticksValue = [];
for(let i = 0; i < options.ticks.length; i++){
if(options.ticks[i] !== null){
options.ticksValue.push(CanvasDigitalGauge.normalizeValue(options.ticks[i], options.minValue, options.maxValue))
}
}
if (options.neonGlowBrightness) { if (options.neonGlowBrightness) {
options.neonColorTitle = tinycolor(options.colorTitle).brighten(options.neonGlowBrightness).toHexString(); options.neonColorTitle = tinycolor(options.colorTitle).brighten(options.neonGlowBrightness).toHexString();
options.neonColorLabel = tinycolor(options.colorLabel).brighten(options.neonGlowBrightness).toHexString(); options.neonColorLabel = tinycolor(options.colorLabel).brighten(options.neonGlowBrightness).toHexString();
@ -729,6 +740,48 @@ function drawBarGlow(context, startX, startY, endX, endY, color, strokeWidth, is
context.stroke(); context.stroke();
} }
function drawTickArc(context, tickValues, Cx, Cy, Ri, Rm, Ro, startAngle, endAngle, color, tickWidth) {
if(!tickValues.length) {
return;
}
const strokeWidth = Ro - Ri;
context.beginPath();
context.lineWidth = tickWidth;
context.strokeStyle = color;
for (let i = 0; i < tickValues.length; i++) {
var angle = startAngle + tickValues[i] * endAngle;
var x1 = Cx + (Ri + strokeWidth) * Math.cos(angle);
var y1 = Cy + (Ri + strokeWidth) * Math.sin(angle);
var x2 = Cx + Ri * Math.cos(angle);
var y2 = Cy + Ri * Math.sin(angle);
context.moveTo(x1, y1);
context.lineTo(x2, y2);
}
context.stroke();
}
function drawTickBar(context, tickValues, startX, startY, distanceBar, strokeWidth, isVertical, color, tickWidth) {
if(!tickValues.length) {
return;
}
context.beginPath();
context.lineWidth = tickWidth;
context.strokeStyle = color;
for (let i = 0; i < tickValues.length; i++) {
let tickValue = tickValues[i] * distanceBar;
if (isVertical) {
context.moveTo(startX - strokeWidth / 2, startY + tickValue - distanceBar);
context.lineTo(startX + strokeWidth / 2, startY + tickValue - distanceBar);
} else {
context.moveTo(startX + tickValue, startY);
context.lineTo(startX + tickValue, startY + strokeWidth);
}
}
context.stroke();
}
function drawProgress(context, options, progress) { function drawProgress(context, options, progress) {
var neonColor; var neonColor;
if (options.neonGlowBrightness) { if (options.neonGlowBrightness) {
@ -759,6 +812,7 @@ function drawProgress(context, options, progress) {
if (options.neonGlowBrightness && !options.isMobile) { if (options.neonGlowBrightness && !options.isMobile) {
drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, true, options.donutStartAngle, options.donutEndAngle); drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, true, options.donutStartAngle, options.donutEndAngle);
} }
drawTickArc(context, options.ticksValue, Cx, Cy, Ri, Rm, Ro, options.donutStartAngle, options.donutEndAngle - options.donutStartAngle, options.colorTicks, options.tickWidth);
} else if (options.gaugeType === 'arc') { } else if (options.gaugeType === 'arc') {
if (options.neonGlowBrightness) { if (options.neonGlowBrightness) {
context.strokeStyle = neonColor; context.strokeStyle = neonColor;
@ -769,6 +823,7 @@ function drawProgress(context, options, progress) {
if (options.neonGlowBrightness && !options.isMobile) { if (options.neonGlowBrightness && !options.isMobile) {
drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, false); drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, false);
} }
drawTickArc(context, options.ticksValue, Cx, Cy, Ri, Rm, Ro, Math.PI, Math.PI, options.colorTicks, options.tickWidth);
} else if (options.gaugeType === 'horizontalBar') { } else if (options.gaugeType === 'horizontalBar') {
if (options.neonGlowBrightness) { if (options.neonGlowBrightness) {
context.strokeStyle = neonColor; context.strokeStyle = neonColor;
@ -781,6 +836,7 @@ function drawProgress(context, options, progress) {
drawBarGlow(context, barLeft, barTop + strokeWidth/2, barLeft + (barRight-barLeft)*progress, barTop + strokeWidth/2, drawBarGlow(context, barLeft, barTop + strokeWidth/2, barLeft + (barRight-barLeft)*progress, barTop + strokeWidth/2,
neonColor, strokeWidth, false); neonColor, strokeWidth, false);
} }
drawTickBar(context, options.ticksValue, barLeft, barTop, barRight - barLeft, strokeWidth, false, options.colorTicks, options.tickWidth);
} else if (options.gaugeType === 'verticalBar') { } else if (options.gaugeType === 'verticalBar') {
if (options.neonGlowBrightness) { if (options.neonGlowBrightness) {
context.strokeStyle = neonColor; context.strokeStyle = neonColor;
@ -793,6 +849,7 @@ function drawProgress(context, options, progress) {
drawBarGlow(context, baseX + width/2, barBottom, baseX + width/2, barBottom - (barBottom-barTop)*progress, drawBarGlow(context, baseX + width/2, barBottom, baseX + width/2, barBottom - (barBottom-barTop)*progress,
neonColor, strokeWidth, true); neonColor, strokeWidth, true);
} }
drawTickBar(context, options.ticksValue, baseX + width / 2, barTop, barTop - barBottom, strokeWidth, true, options.colorTicks, options.tickWidth);
} }
} }

View File

@ -62,6 +62,12 @@ export default class TbCanvasDigitalGauge {
this.localSettings.fixedLevelColors = settings.fixedLevelColors || []; this.localSettings.fixedLevelColors = settings.fixedLevelColors || [];
} }
this.localSettings.showTicks = settings.showTicks || false;
this.localSettings.ticks = [];
this.localSettings.ticksValue = settings.ticksValue || [];
this.localSettings.tickWidth = settings.tickWidth || 4;
this.localSettings.colorTicks = settings.colorTicks || '#666';
this.localSettings.decimals = angular.isDefined(dataKey.decimals) ? dataKey.decimals : this.localSettings.decimals = angular.isDefined(dataKey.decimals) ? dataKey.decimals :
((angular.isDefined(settings.decimals) && settings.decimals !== null) ((angular.isDefined(settings.decimals) && settings.decimals !== null)
? settings.decimals : ctx.decimals); ? settings.decimals : ctx.decimals);
@ -145,6 +151,10 @@ export default class TbCanvasDigitalGauge {
gaugeColor: this.localSettings.gaugeColor, gaugeColor: this.localSettings.gaugeColor,
levelColors: this.localSettings.levelColors, levelColors: this.localSettings.levelColors,
colorTicks: this.localSettings.colorTicks,
tickWidth: this.localSettings.tickWidth,
ticks: this.localSettings.ticks,
title: this.localSettings.title, title: this.localSettings.title,
fontTitleSize: this.localSettings.titleFont.size, fontTitleSize: this.localSettings.titleFont.size,
@ -204,9 +214,81 @@ export default class TbCanvasDigitalGauge {
if (this.localSettings.useFixedLevelColor) { if (this.localSettings.useFixedLevelColor) {
if (this.localSettings.fixedLevelColors && this.localSettings.fixedLevelColors.length > 0) { if (this.localSettings.fixedLevelColors && this.localSettings.fixedLevelColors.length > 0) {
this.localSettings.levelColors = this.settingLevelColorsSubscribe(this.localSettings.fixedLevelColors); this.localSettings.levelColors = this.settingLevelColorsSubscribe(this.localSettings.fixedLevelColors);
this.updateLevelColors(this.localSettings.levelColors);
} }
} }
if (this.localSettings.showTicks) {
if (this.localSettings.ticksValue && this.localSettings.ticksValue.length) {
this.localSettings.ticks = this.settingTicksSubscribe(this.localSettings.ticksValue);
}
}
this.updateSetting();
}
static generateDatasorce(ctx, datasources, entityAlias, attribute, settings){
let entityAliasId = ctx.aliasController.getEntityAliasId(entityAlias);
if (!entityAliasId) {
throw new Error('Not valid entity aliase name ' + entityAlias);
}
let datasource = datasources.filter((datasource) => {
return datasource.entityAliasId === entityAliasId;
})[0];
let dataKey = {
type: ctx.$scope.$injector.get('types').dataKeyType.attribute,
name: attribute,
label: attribute,
settings: [settings],
_hash: Math.random()
};
if (datasource) {
let findDataKey = datasource.dataKeys.filter((dataKey) => {
return dataKey.name === attribute;
})[0];
if (findDataKey) {
findDataKey.settings.push(settings);
} else {
datasource.dataKeys.push(dataKey)
}
} else {
datasource = {
type: ctx.$scope.$injector.get('types').datasourceType.entity,
name: entityAlias,
aliasName: entityAlias,
entityAliasId: entityAliasId,
dataKeys: [dataKey]
};
datasources.push(datasource);
}
return datasources;
}
settingTicksSubscribe(options) {
let ticksDatasource = [];
let predefineTicks = [];
for (let i = 0; i < options.length; i++) {
let tick = options[i];
if (tick.valueSource === 'predefinedValue' && isFinite(tick.value)) {
predefineTicks.push(tick.value)
} else if (tick.entityAlias && tick.attribute) {
try {
ticksDatasource = TbCanvasDigitalGauge.generateDatasorce(this.ctx, ticksDatasource, tick.entityAlias, tick.attribute, predefineTicks.length);
} catch (e) {
continue;
}
predefineTicks.push(null);
}
}
this.subscribeAttributes(ticksDatasource, 'ticks').then((subscription) => {
this.ticksSourcesSubscription = subscription;
});
return predefineTicks;
} }
settingLevelColorsSubscribe(options) { settingLevelColorsSubscribe(options) {
@ -220,50 +302,14 @@ export default class TbCanvasDigitalGauge {
color: color color: color
}) })
} else if (levelSetting.entityAlias && levelSetting.attribute) { } else if (levelSetting.entityAlias && levelSetting.attribute) {
let entityAliasId = this.ctx.aliasController.getEntityAliasId(levelSetting.entityAlias); try {
if (!entityAliasId) { levelColorsDatasource = TbCanvasDigitalGauge.generateDatasorce(this.ctx, levelColorsDatasource, levelSetting.entityAlias, levelSetting.attribute, {
return;
}
let datasource = levelColorsDatasource.filter((datasource) => {
return datasource.entityAliasId === entityAliasId;
})[0];
let dataKey = {
type: this.ctx.$scope.$injector.get('types').dataKeyType.attribute,
name: levelSetting.attribute,
label: levelSetting.attribute,
settings: [{
color: color, color: color,
index: predefineLevelColors.length index: predefineLevelColors.length
}], });
_hash: Math.random() } catch (e) {
}; return;
if (datasource) {
let findDataKey = datasource.dataKeys.filter((dataKey) => {
return dataKey.name === levelSetting.attribute;
})[0];
if (findDataKey) {
findDataKey.settings.push({
color: color,
index: predefineLevelColors.length
});
} else {
datasource.dataKeys.push(dataKey)
}
} else {
datasource = {
type: this.ctx.$scope.$injector.get('types').datasourceType.entity,
name: levelSetting.entityAlias,
aliasName: levelSetting.entityAlias,
entityAliasId: entityAliasId,
dataKeys: [dataKey]
};
levelColorsDatasource.push(datasource);
} }
predefineLevelColors.push(null); predefineLevelColors.push(null);
} }
} }
@ -278,49 +324,63 @@ export default class TbCanvasDigitalGauge {
} }
} }
this.subscribeLevelColorsAttributes(levelColorsDatasource); this.subscribeAttributes(levelColorsDatasource, 'levelColors').then((subscription) => {
this.levelColorSourcesSubscription = subscription;
});
return predefineLevelColors; return predefineLevelColors;
} }
updateLevelColors(levelColors) { subscribeAttributes(datasources, typeAttributes) {
this.gauge.options.levelColors = levelColors; if (!datasources.length) {
this.gauge.options = CanvasDigitalGauge.configure(this.gauge.options); return this.ctx.$scope.$injector.get('$q').when(null);
this.gauge.update(); }
}
subscribeLevelColorsAttributes(datasources) {
let TbCanvasDigitalGauge = this;
let levelColorsSourcesSubscriptionOptions = { let levelColorsSourcesSubscriptionOptions = {
datasources: datasources, datasources: datasources,
useDashboardTimewindow: false, useDashboardTimewindow: false,
type: this.ctx.$scope.$injector.get('types').widgetType.latest.value, type: this.ctx.$scope.$injector.get('types').widgetType.latest.value,
callbacks: { callbacks: {
onDataUpdated: (subscription) => { onDataUpdated: (subscription) => {
for (let i = 0; i < subscription.data.length; i++) { this.updateAttribute(subscription.data, typeAttributes);
let keyData = subscription.data[i];
if (keyData && keyData.data && keyData.data[0]) {
let attrValue = keyData.data[0][1];
if (isFinite(attrValue)) {
for (let i = 0; i < keyData.dataKey.settings.length; i++) {
let setting = keyData.dataKey.settings[i];
this.localSettings.levelColors[setting.index] = {
value: attrValue,
color: setting.color
};
}
}
}
}
this.updateLevelColors(this.localSettings.levelColors);
} }
} }
}; };
this.ctx.subscriptionApi.createSubscription(levelColorsSourcesSubscriptionOptions, true).then(
(subscription) => { return this.ctx.subscriptionApi.createSubscription(levelColorsSourcesSubscriptionOptions, true);
TbCanvasDigitalGauge.levelColorSourcesSubscription = subscription; }
updateAttribute(data, typeAttributes) {
for (let i = 0; i < data.length; i++) {
let keyData = data[i];
if (keyData && keyData.data && keyData.data[0]) {
let attrValue = keyData.data[0][1];
if (isFinite(attrValue)) {
for (let i = 0; i < keyData.dataKey.settings.length; i++) {
let setting = keyData.dataKey.settings[i];
switch (typeAttributes) {
case 'levelColors':
this.localSettings.levelColors[setting.index] = {
value: attrValue,
color: setting.color
};
break;
case 'ticks':
this.localSettings.ticks[setting] = attrValue;
break;
}
}
}
} }
); }
this.updateSetting();
}
updateSetting() {
this.gauge.options.ticks = this.localSettings.ticks;
this.gauge.options.levelColors = this.localSettings.levelColors;
this.gauge.options = CanvasDigitalGauge.configure(this.gauge.options);
this.gauge.update();
} }
update() { update() {
@ -526,6 +586,48 @@ export default class TbCanvasDigitalGauge {
} }
} }
}, },
"showTicks": {
"title": "Show ticks",
"type": "boolean",
"default": false
},
"tickWidth": {
"title": "Width ticks",
"type": "number",
"default": 4
},
"colorTicks": {
"title": "Color ticks",
"type": "string",
"default": "#666"
},
"ticksValue": {
"title": "The ticks predefined value",
"type": "array",
"items": {
"title": "tickValue",
"type": "object",
"properties": {
"valueSource": {
"title": "Value source",
"type": "string",
"default": "predefinedValue"
},
"entityAlias": {
"title": "Source entity alias",
"type": "string"
},
"attribute": {
"title": "Source entity attribute",
"type": "string"
},
"value": {
"title": "Value (if predefined value is selected)",
"type": "number"
}
}
}
},
"animation": { "animation": {
"title": "Enable animation", "title": "Enable animation",
"type": "boolean", "type": "boolean",
@ -771,6 +873,40 @@ export default class TbCanvasDigitalGauge {
} }
] ]
}, },
"showTicks",
{
"key": "tickWidth",
"condition": "model.showTicks === true"
},
{
"key": "colorTicks",
"condition": "model.showTicks === true",
"type": "color"
},
{
"key": "ticksValue",
"condition": "model.showTicks === true",
"items": [
{
"key": "ticksValue[].valueSource",
"type": "rc-select",
"multiple": false,
"items": [
{
"value": "predefinedValue",
"label": "Predefined value (Default)"
},
{
"value": "entityAttribute",
"label": "Value taken from entity attribute"
}
]
},
"ticksValue[].value",
"ticksValue[].entityAlias",
"ticksValue[].attribute"
]
},
"animation", "animation",
"animationDuration", "animationDuration",
{ {