A tank is a visual representation of a container containing a fluid. It could be used for a rainwater tank or for the ink levels in printer cartridges or tanks.
This widget is the result of some experiments here, where I tried different techniques to make a widget for my Epson printer. @JustinG encouraged me to try different approaches. This was the best result. It is a dynamic svg image. It contains a path for the outline of the tank and a linear gradient for the fill. The fill element is controlled by the level item.
As it is an svg image, it can be scaled, including the text for level and label. I must admit that the scaling is not completely as I expected.
In responsive layout it is the layout itself that decides how wide the columns or cells will be. So the widget height could be to high. Therefore a property has been added to control the height in px.
In fixed canvas layout or fixed grid layout there is more control. But the height property has an influence too: it seems to be an upper limit: you can scale down, but not up.
Configuration:
- title: optional title for the card
- levelItem: Item that contains the level in %
- fillColor: Fill color: red, blue,… or rgb(200,10,65) or ‘#ff0066’
- tankLabel: optional text label under the tank
- height: height in px (default 200px). This is needed for responsive layout, but also affects the canvas layout.
- width: Width (no units, default: 80)
Screenshots
Examples in responsive layout. The columns have an equal width.
Examples in fixed canvas layout:
Changelog
Version 0.3
- added a width property
Version 0.2
- added animation (thanks to @JustinG)
- added preserveAspectRatio for better looking scaling in fixed Canvas mode
- explained the scaling in a bit more detail
Version 0.1
- initial release
Resources
uid: tankWidget
tags: []
props:
parameters:
- description: Title
label: Title
name: title
required: false
type: TEXT
- context: item
description: Item that contains the level in %
label: Level Item
name: levelItem
required: true
type: TEXT
- description: "Fill color: red, blue,... or rgb(200,10,65) or '#ff0066'"
label: Fill color
name: fillColor
required: false
type: TEXT
- description: Text label under the tank
label: Tank Label
name: tankLabel
required: false
type: TEXT
- default: 200px
description: "Height in px (needed for responsive layout, default: 200px)"
label: Height
name: height
required: false
type: TEXT
- default: 80
description: "Width (no units, default: 80)"
label: Width
name: width
required: false
type: TEXT
parameterGroups: []
timestamp: Mar 3, 2024, 9:50:32 AM
component: f7-card
config:
outline: true
title: =props.title
slots:
default:
- component: f7-block
config:
style:
display: flex
height: =props.height
justify-content: center
slots:
default:
- component: svg
config:
preserveAspectRatio: xMidYMin meet
viewBox: ='0 0 '+props.width+' 230'
xlmns: http://www.w3.org/2000/svg
slots:
default:
- component: text
config:
content: =items[props.levelItem].state+'%'
fill: =themeOptions.dark=='dark'?'white':'black'
text-anchor: middle
x: =props.width/2
y: 15
- component: defs
slots:
default:
- component: linearGradient
config:
comment: the id can only be used once in a page; so we have to make it unique if we want to use the widget more than once
id: ='Grad'+props.levelItem
x1: 0%
x2: 0%
y1: 100%
y2: 0%
slots:
default:
- component: stop
config:
comment: in order to have a hard line, both stops must use the same offset
offset: =items[props.levelItem].state+'%'
stop-color: =props.fillColor
- component: stop
config:
comment: the upper part is transparent
offset: =items[props.levelItem].state+'%'
stop-color: rgba(0,0,0,0)
- component: animate
config:
attributeName: y2
dur: 1s
from: 100%
repeatCount: 1
to: 0%
- component: path
config:
d: ='M 0,20 q 10,0 10,10 l 0 160 q 0,10 10,10 l '+(props.width-40)+',0 q 10,0 10,-10 l 0,-160 q 0,-10 10,-10 M 10,110 l 20,0 M 10,65 l 10,0 M 10,155 l 10,0'
fill: ='url(#Grad'+props.levelItem+')'
stroke: =themeOptions.dark=='dark'?'white':'black'
stroke-width: 2
- component: text
config:
content: =props.tankLabel
fill: =themeOptions.dark=='dark'?'white':'black'
text-anchor: middle
x: =props.width/2
y: 220