mirror of
https://github.com/jlengrand/d3-progress-meter.git
synced 2026-03-10 08:11:18 +00:00
260 lines
6.7 KiB
HTML
260 lines
6.7 KiB
HTML
<!doctype html>
|
|
<link rel="import" href="../polymer/polymer.html">
|
|
|
|
<script src="../d3/d3.min.js"></script>
|
|
|
|
<!--
|
|
An animated chart that shows the progress as a meter
|
|
|
|
### Styling
|
|
|
|
The following custom properties are available for styling:
|
|
|
|
Custom property | Description | Default
|
|
----------------|-------------|----------
|
|
`--progress-meter-background-color` | Color of the background circle | `#e0e0e0`
|
|
`--progress-meter-color-low` | Color of the progress bar for low values | `#f44336`
|
|
`--progress-meter-color-medium` | Color of the progress bar for medium values | `#ffeb3b`
|
|
`--progress-meter-color-high` | Color of the progress bar for high values | `#4caf50`
|
|
`--progress-meter-current-font-size-scale` | Controls font size of `current-text` | `0.5`
|
|
`--progress-meter-goal-font-size-scale` | Controls font size of `goal-text` | `0.2`
|
|
`--progress-meter-type-font-size-scale` | Controls font size of `type-text` | `0.25`
|
|
`--progress-meter-type-width-scale` | Controls width of `type-text` | `2`
|
|
`--progress-meter-caption-font-size-scale` | Controls font size of `caption` | `0.2`
|
|
`--progress-meter-caption-width-scale` | Controls width of `caption` | `2`
|
|
|
|
All the `-scale` properties are used to set the sizes proportionally to the element's `radius`. For example, by default
|
|
the `current-text` font size is half that of the `radius`.
|
|
|
|
### Example
|
|
|
|
```html
|
|
<d3-progress-meter radius="100" percentage="0.35" current-text="70" goal-text="Goal: 200" type-text="transactions"></d3-progress-meter>
|
|
```
|
|
|
|
|
|
@demo demo/index.html
|
|
-->
|
|
<dom-module id="d3-progress-meter">
|
|
|
|
<template>
|
|
<style>
|
|
:host {
|
|
display: inline-block;
|
|
--progress-meter-current-font-size-scale: 0.5;
|
|
--progress-meter-goal-font-size-scale: 0.2;
|
|
--progress-meter-type-font-size-scale: 0.25;
|
|
--progress-meter-type-width-scale: 4;
|
|
--progress-meter-caption-font-size-scale: 0.2;
|
|
--progress-meter-caption-width-scale: 2;
|
|
}
|
|
#background {
|
|
/* var(--paper-grey-300) */
|
|
fill: var(--progress-meter-background-color, #e0e0e0);
|
|
}
|
|
#progress.low {
|
|
/* var(--paper-red-500) */
|
|
fill: var(--progress-meter-color-low, #f44336);
|
|
}
|
|
#progress.medium {
|
|
/* var(--paper-yellow-500) */
|
|
fill: var(--progress-meter-color-medium, #ffeb3b);
|
|
}
|
|
#progress.high {
|
|
/* var(--paper-green-500) */
|
|
fill: var(--progress-meter-color-high, #4caf50);
|
|
}
|
|
#current,#goal,#type,#caption {
|
|
font-family: Arial, sans-serif;
|
|
}
|
|
#type {
|
|
font-size: calc(var(--radius) * var(--progress-meter-type-font-size-scale));
|
|
width: calc(var(--radius) * var(--progress-meter-type-width-scale));
|
|
}
|
|
#caption {
|
|
font-size: calc(var(--radius) * var(--progress-meter-caption-font-size-scale));
|
|
width: calc(var(--radius) * var(--progress-meter-caption-width-scale));
|
|
}
|
|
#goal {
|
|
font-size: calc(var(--radius) * var(--progress-meter-goal-font-size-scale));
|
|
}
|
|
#current {
|
|
font-weight: bold;
|
|
font-size: calc(var(--radius) * var(--progress-meter-current-font-size-scale));
|
|
}
|
|
#type {
|
|
margin-top: 5px;
|
|
text-align: center;
|
|
text-transform: uppercase;
|
|
white-space: nowrap;
|
|
overflow-x: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
#caption {
|
|
/*var(--secondary-text-color)*/
|
|
color: #737373;
|
|
text-align: center;
|
|
}
|
|
</style>
|
|
|
|
<svg width$="[[_diameter]]" height$="[[_diameter]]">
|
|
<g transform$="[[_transform]]">
|
|
<g>
|
|
<path id="background"></path>
|
|
<path id="progress" class$="[[_progressLevel]]"></path>
|
|
<text id="current" dy="-.2em" text-anchor="middle">[[currentText]]</text>
|
|
<text id="goal" dy="1.5em" text-anchor="middle">[[goalText]]</text>
|
|
</g>
|
|
</g>
|
|
</svg>
|
|
<div id="type">[[typeText]]</div>
|
|
<div hidden$="[[!caption]]" id="caption">[[caption]]</div>
|
|
</template>
|
|
|
|
</dom-module>
|
|
|
|
<script>
|
|
(function() {
|
|
|
|
Polymer({
|
|
is: 'd3-progress-meter',
|
|
properties: {
|
|
/**
|
|
* Radius of the meter. The element will have twice the size of the radius
|
|
*/
|
|
radius: {
|
|
type: Number,
|
|
value: 100,
|
|
observer: '_radiusChanged'
|
|
},
|
|
|
|
/**
|
|
* Progress in percent
|
|
*/
|
|
percentage: {
|
|
type: Number,
|
|
observer: '_percentageChanged'
|
|
},
|
|
|
|
/**
|
|
* Large number showing current progress
|
|
*/
|
|
currentText: String,
|
|
|
|
/**
|
|
* Small text indicating when progress will be 100%
|
|
*/
|
|
goalText: String,
|
|
|
|
/**
|
|
* Bottom text describing for what progress is measured
|
|
*/
|
|
typeText: String,
|
|
|
|
/**
|
|
* Optional secondary text displayed under the type text
|
|
*/
|
|
caption: String,
|
|
|
|
/**
|
|
* Lower bound of progress, below which the indicator turns red
|
|
*/
|
|
lowThreshold: {
|
|
type: Number,
|
|
value: 0.33
|
|
},
|
|
|
|
/**
|
|
* Higher bound of progress, above which the indicator turns green
|
|
*/
|
|
highThreshold: {
|
|
type: Number,
|
|
value: 0.66
|
|
},
|
|
|
|
/**
|
|
* Amount of progress made (absolute number)
|
|
*/
|
|
_progress: {
|
|
type: Number,
|
|
value: 0
|
|
},
|
|
|
|
_diameter: {
|
|
type: Number,
|
|
computed: '_computeDiameter(radius)'
|
|
},
|
|
_transform: {
|
|
type: String,
|
|
computed: '_computeTransform(radius)'
|
|
},
|
|
_progressLevel: {
|
|
type: Number,
|
|
computed: '_computeProgressLevel(percentage)'
|
|
}
|
|
},
|
|
_computeDiameter: function(radius) {
|
|
return 2 * radius;
|
|
},
|
|
_computeTransform: function(radius) {
|
|
return "translate(" + radius + ", " + radius + ")";
|
|
},
|
|
_computeProgressLevel: function(percentage) {
|
|
if (percentage <= this.lowThreshold) {
|
|
return 'low';
|
|
}
|
|
|
|
if (percentage <= this.highThreshold) {
|
|
return 'medium';
|
|
}
|
|
|
|
return 'high';
|
|
},
|
|
_radiusChanged: function(oldVal, newVal) {
|
|
this._onRadiusChanged();
|
|
this._onPercentageChanged();
|
|
},
|
|
_percentageChanged: function(oldVal, newVal) {
|
|
this._onPercentageChanged();
|
|
},
|
|
_onRadiusChanged: function() {
|
|
this.progressArc = d3.svg.arc()
|
|
.startAngle(0)
|
|
.innerRadius(9/10 * this.radius)
|
|
.outerRadius(this.radius);
|
|
|
|
this.backgroundArc = d3.svg.arc()
|
|
.startAngle(0)
|
|
.innerRadius(0.825 * this.radius)
|
|
.outerRadius(0.85 * this.radius);
|
|
|
|
if (this.customStyle) {
|
|
// Polymer 1.x
|
|
this.customStyle['--radius'] = this.radius + 'px';
|
|
this.updateStyles();
|
|
} else {
|
|
// Polymer 2.0+
|
|
this.updateStyles({'--radius': this.radius + 'px'});
|
|
}
|
|
|
|
this.$.background.setAttribute('d', this.backgroundArc.endAngle(2 * Math.PI)());
|
|
},
|
|
_onPercentageChanged: function() {
|
|
if (typeof this.percentage == 'undefined') {
|
|
return;
|
|
}
|
|
this.percentage = Math.min(1, Math.max(0, this.percentage));
|
|
|
|
var i = d3.interpolate(this._progress, this.percentage);
|
|
d3.select(this).transition().tween(this.$.progress, function() {
|
|
return function(t) {
|
|
this._progress = i(t);
|
|
this.$.progress.setAttribute('d', this.progressArc.endAngle(2 * Math.PI * this._progress)());
|
|
}.bind(this);
|
|
}.bind(this));
|
|
}
|
|
});
|
|
|
|
})();
|
|
</script>
|