Angular graph适用于Chrome,但不适用于Firefox
我想用D3上的这个。我的问题是,我必须将JS中的代码传递给Angular2 Typescript应用程序,示例代码在D3V3中。我使用v4 我的代码在Chromium(Linux Chrome)上运行良好,但在Firefox上它不显示wave动画(显示方式与图像类似): 我已经创建了一个,在Plunker中,它可以使用Firefox正常工作 我的问题是,为什么它可以在Chromium上运行,而不能在Firefox上运行 该项目是使用创建的,D3V4库由Angular graph适用于Chrome,但不适用于Firefox,angular,d3.js,typescript,Angular,D3.js,Typescript,我想用D3上的这个。我的问题是,我必须将JS中的代码传递给Angular2 Typescript应用程序,示例代码在D3V3中。我使用v4 我的代码在Chromium(Linux Chrome)上运行良好,但在Firefox上它不显示wave动画(显示方式与图像类似): 我已经创建了一个,在Plunker中,它可以使用Firefox正常工作 我的问题是,为什么它可以在Chromium上运行,而不能在Firefox上运行 该项目是使用创建的,D3V4库由npm获取,在angular cli.js
npm
获取,在angular cli.json中引用,如下面的示例所示,并从“D3”中导入为D3代码>:
"scripts": [
"../node_modules/jquery/dist/jquery.min.js",
"../node_modules/bootstrap/dist/js/bootstrap.min.js",
"../node_modules/d3/build/d3.min.js"
],
代码:
从'angular2/core'导入{Component,OnInit};
从“d3”导入*作为d3;
@组成部分({
选择器:“我的应用程序”,
模板:`
`
})
导出类Angular2TutorialComponent实现OnInit{
配置={
minValue:0,//仪表最小值。
maxValue:100,//仪表最大值。
圆厚度:0.05,//外圆厚度占其半径的百分比。
circleFillGap:0.05,//外圈和波形圈之间的间隙大小占外圈半径的百分比。
圆环颜色:“#178BCA”,//外圈的颜色。
波高:0.05,//波高占波圆半径的百分比。
waveCount:1,//波圈每宽度的全波数。
waveRiseTime:1000,//波浪从0上升到最终高度的时间量(毫秒)。
waveAnimateTime:18000,//整个波浪进入波浪周期的时间量(以毫秒为单位)。
waveRise:true,//控制波浪是从0上升到其全高,还是从其全高开始。
waveHeightScaling:true,//控制低填充百分比和高填充百分比下的波浪大小缩放。如果为true,波浪高度在50%填充时达到最大值,在0%和100%填充时达到最小值。这有助于防止波浪在接近其最小或最大填充时使波浪圆看起来完全满或空。
waveAnimate:true,//控制波浪是滚动还是静止。
waveColor:#178BCA”,//填充波的颜色。
waveOffset:0,//初始偏移波浪的量。0=无偏移。1=一个完整波浪的偏移。
textVertPosition:.5,//显示带有波浪圆的百分比文本的高度。0=底部,1=顶部。
textSize:1,//要在波浪圈中显示的文本的相对高度。1=50%
valueCountUp:true,//如果为true,则在加载时显示的值从0向上计数到其最终值。如果为false,则显示最终值。
displayPercent:true,//如果为true,则在值后面显示一个%符号。
textColor:#045681“,//波形不重叠时值文本的颜色。
waveTextColor:#A4DBf8”//波浪重叠时值文本的颜色。
};
构造函数(){}
ngOnInit():void{
此.loadLiquidFillGauge('图表',50,空);
}
loadLiquidFillGauge(元素ID、值、配置):void{
如果(config==null)config=this.config;
让gauge=d3。选择(“#”+元素ID);
让半径=Math.min(parseInt(gauge.style(“宽度”)),parseInt(gauge.style(“高度”))/2;
设locationX=parseInt(规格样式(“宽度”)/2-半径;
设位置y=parseInt(规格样式(“高度”)/2-半径;
让fillPercent=Math.max(config.minValue,Math.min(config.maxValue,value))/config.maxValue;
让波高标度;
if(配置波高缩放){
波高标度=d3.scaleLinear()
.range([0,config.waveHeight,0])
.域([0,50,100]);
}否则{
波高标度=d3.scaleLinear()
.range([config.waveHeight,config.waveHeight])
.域([01100]);
}
设textPixels=(config.textSize*radius/2);
设textFinalValue=parseFloat(value).toFixed(2);
让textStartValue=config.valueCountUp?config.minValue:textFinalValue;
让percentText=config.displayPercent?“%:”;
设circleThickness=config.circleThickness*半径;
设circleFillGap=config.circleFillGap*半径;
设fillCircleMargin=圆环厚度+圆环间隙;
设fillCircleRadius=半径-fillcircleramgin;
设波高=fillCircleRadius*波高标度(fillPercent*100);
设波长=fillCircleRadius*2/config.waveCount;
设waveClipCount=1+config.waveCount;
设waveClipWidth=波长*waveClipCount;
//四舍五入功能,以便在值向上计数时始终显示正确的小数位数。
let textRounder:any=函数(值){
返回Math.round(值);
};
if(parseFloat(textFinalValue)!=(textRounder(textFinalValue))){
textRounder=函数(值){
返回parseFloat(值).toFixed(1);
};
}
if(parseFloat(textFinalValue)!=(textRounder(textFinalValue))){
textRounder=函数(值){
返回parseFloat(值).toFixed(2);
};
}
//用于构建剪辑波区域的数据。
让数据=[];
对于(设i=0;i函数(d){
返回waveScaleX(d.x);
})
.y0(函数(d){
返回waveScaleY(Math.sin(Math.PI*2*config.waveOffset*-1+Math.PI*2*(1-config.waveCount)+d.y*2*Math.PI));
})
.y1(功能(d){
返回(fillCircleRadius*2+波高);
});
设waveGroup=gaugeGroup.append(“defs”)
.append(“clipPath”)
.attr(“id”、“clipWave”+元素id);
让wave=waveGroup.append(“路径”)
.基准(数据)
.attr(“d”,clipArea)
.attr(“T”,0);
//附加削波的内圈。
设fillCircleGroup=gaugeGroup.append(“g”)
.attr(“剪辑路径”、“url(#clipWave”+elementId+”);
fillCircleGroup.append(“圆”)
.attr(“cx
import { Component, OnInit } from 'angular2/core';
import * as d3 from 'd3';
@Component({
selector: 'my-app',
template: `
<svg id="chart" width="97%" height="250">
</svg>
`
})
export class Angular2TutorialComponent implements OnInit {
config = {
minValue: 0, // The gauge minimum value.
maxValue: 100, // The gauge maximum value.
circleThickness: 0.05, // The outer circle thickness as a percentage of it's radius.
circleFillGap: 0.05, // The size of the gap between the outer circle and wave circle as a percentage of the outer circles radius.
circleColor: "#178BCA", // The color of the outer circle.
waveHeight: 0.05, // The wave height as a percentage of the radius of the wave circle.
waveCount: 1, // The number of full waves per width of the wave circle.
waveRiseTime: 1000, // The amount of time in milliseconds for the wave to rise from 0 to it's final height.
waveAnimateTime: 18000, // The amount of time in milliseconds for a full wave to enter the wave circle.
waveRise: true, // Control if the wave should rise from 0 to it's full height, or start at it's full height.
waveHeightScaling: true, // Controls wave size scaling at low and high fill percentages. When true, wave height reaches it's maximum at 50% fill, and minimum at 0% and 100% fill. This helps to prevent the wave from making the wave circle from appear totally full or empty when near it's minimum or maximum fill.
waveAnimate: true, // Controls if the wave scrolls or is static.
waveColor: "#178BCA", // The color of the fill wave.
waveOffset: 0, // The amount to initially offset the wave. 0 = no offset. 1 = offset of one full wave.
textVertPosition: .5, // The height at which to display the percentage text withing the wave circle. 0 = bottom, 1 = top.
textSize: 1, // The relative height of the text to display in the wave circle. 1 = 50%
valueCountUp: true, // If true, the displayed value counts up from 0 to it's final value upon loading. If false, the final value is displayed.
displayPercent: true, // If true, a % symbol is displayed after the value.
textColor: "#045681", // The color of the value text when the wave does not overlap it.
waveTextColor: "#A4DBf8" // The color of the value text when the wave overlaps it.
};
constructor() {}
ngOnInit(): void {
this.loadLiquidFillGauge('chart', 50, null);
}
loadLiquidFillGauge(elementId, value, config): void {
if (config == null) config = this.config;
let gauge = d3.select("#" + elementId);
let radius = Math.min(parseInt(gauge.style("width")), parseInt(gauge.style("height"))) / 2;
let locationX = parseInt(gauge.style("width")) / 2 - radius;
let locationY = parseInt(gauge.style("height")) / 2 - radius;
let fillPercent = Math.max(config.minValue, Math.min(config.maxValue, value)) / config.maxValue;
let waveHeightScale;
if (config.waveHeightScaling) {
waveHeightScale = d3.scaleLinear()
.range([0, config.waveHeight, 0])
.domain([0, 50, 100]);
} else {
waveHeightScale = d3.scaleLinear()
.range([config.waveHeight, config.waveHeight])
.domain([0, 100]);
}
let textPixels = (config.textSize * radius / 2);
let textFinalValue = parseFloat(value).toFixed(2);
let textStartValue = config.valueCountUp ? config.minValue : textFinalValue;
let percentText = config.displayPercent ? "%" : "";
let circleThickness = config.circleThickness * radius;
let circleFillGap = config.circleFillGap * radius;
let fillCircleMargin = circleThickness + circleFillGap;
let fillCircleRadius = radius - fillCircleMargin;
let waveHeight = fillCircleRadius * waveHeightScale(fillPercent * 100);
let waveLength = fillCircleRadius * 2 / config.waveCount;
let waveClipCount = 1 + config.waveCount;
let waveClipWidth = waveLength * waveClipCount;
// Rounding functions so that the correct number of decimal places is always displayed as the value counts up.
let textRounder: any = function(value) {
return Math.round(value);
};
if (parseFloat(textFinalValue) != (textRounder(textFinalValue))) {
textRounder = function(value) {
return parseFloat(value).toFixed(1);
};
}
if (parseFloat(textFinalValue) != (textRounder(textFinalValue))) {
textRounder = function(value) {
return parseFloat(value).toFixed(2);
};
}
// Data for building the clip wave area.
let data = [];
for (let i = 0; i <= 40 * waveClipCount; i++) {
data.push({
x: i / (40 * waveClipCount),
y: (i / (40))
});
}
// Scales for drawing the outer circle.
let gaugeCircleX = d3.scaleLinear().range([0, 2 * Math.PI]).domain([0, 1]);
let gaugeCircleY = d3.scaleLinear().range([0, radius]).domain([0, radius]);
// Scales for controlling the size of the clipping path.
let waveScaleX = d3.scaleLinear().range([0, waveClipWidth]).domain([0, 1]);
let waveScaleY = d3.scaleLinear().range([0, waveHeight]).domain([0, 1]);
// Scales for controlling the position of the clipping path.
let waveRiseScale = d3.scaleLinear()
// The clipping area size is the height of the fill circle + the wave height, so we position the clip wave
// such that the it will overlap the fill circle at all when at 0%, and will totally cover the fill
// circle at 100%.
.range([(fillCircleMargin + fillCircleRadius * 2 + waveHeight), (fillCircleMargin - waveHeight)])
.domain([0, 1]);
let waveAnimateScale = d3.scaleLinear()
.range([0, waveClipWidth - fillCircleRadius * 2]) // Push the clip area one full wave then snap back.
.domain([0, 1]);
// Scale for controlling the position of the text within the gauge.
let textRiseScaleY = d3.scaleLinear()
.range([fillCircleMargin + fillCircleRadius * 2, (fillCircleMargin + textPixels * 0.7)])
.domain([0, 1]);
// Center the gauge within the parent SVG.
let gaugeGroup = gauge.append("g")
.attr('transform', 'translate(' + locationX + ',' + locationY + ')');
// Draw the outer circle.
let gaugeCircleArc = d3.arc()
.startAngle(gaugeCircleX(0))
.endAngle(gaugeCircleX(1))
.outerRadius(gaugeCircleY(radius))
.innerRadius(gaugeCircleY(radius - circleThickness));
gaugeGroup.append("path")
.attr("d", gaugeCircleArc)
.style("fill", config.circleColor)
.attr('transform', 'translate(' + radius + ',' + radius + ')');
// Text where the wave does not overlap.
let text1 = gaugeGroup.append("text")
.text(textRounder(textStartValue) + percentText)
.attr("class", "liquidFillGaugeText")
.attr("text-anchor", "middle")
.attr("font-size", textPixels + "px")
.style("fill", config.textColor)
.attr('transform', 'translate(' + radius + ',' + textRiseScaleY(config.textVertPosition) + ')');
// The clipping wave area.
let clipArea = d3.area()
.x( < any > function(d) {
return waveScaleX(d.x);
})
.y0( < any > function(d) {
return waveScaleY(Math.sin(Math.PI * 2 * config.waveOffset * -1 + Math.PI * 2 * (1 - config.waveCount) + d.y * 2 * Math.PI));
})
.y1(function(d) {
return (fillCircleRadius * 2 + waveHeight);
});
let waveGroup = gaugeGroup.append("defs")
.append("clipPath")
.attr("id", "clipWave" + elementId);
let wave = waveGroup.append("path")
.datum(data)
.attr("d", clipArea)
.attr("T", 0);
// The inner circle with the clipping wave attached.
let fillCircleGroup = gaugeGroup.append("g")
.attr("clip-path", "url(#clipWave" + elementId + ")");
fillCircleGroup.append("circle")
.attr("cx", radius)
.attr("cy", radius)
.attr("r", fillCircleRadius)
.style("fill", config.waveColor);
// Text where the wave does overlap.
let text2 = fillCircleGroup.append("text")
.text(textRounder(textStartValue) + percentText)
.attr("class", "liquidFillGaugeText")
.attr("text-anchor", "middle")
.attr("font-size", textPixels + "px")
.style("fill", config.waveTextColor)
.attr('transform', 'translate(' + radius + ',' + textRiseScaleY(config.textVertPosition) + ')');
// Make the value count up.
if (config.valueCountUp) {
let textTween = function() {
let i = d3.interpolate(this.textContent, textFinalValue);
let temp = this;
return function(t) {
temp.textContent = textRounder(i(t)) + percentText;
}
};
text1.transition()
.duration(config.waveRiseTime)
.tween("text", textTween);
text2.transition()
.duration(config.waveRiseTime)
.tween("text", textTween);
}
// Make the wave rise. wave and waveGroup are separate so that horizontal and vertical movement can be controlled independently.
let waveGroupXPosition = fillCircleMargin + fillCircleRadius * 2 - waveClipWidth;
if (config.waveRise) {
waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(0) + ')')
.transition()
.duration(config.waveRiseTime)
.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fillPercent) + ')')
.on("start", function() {
wave.attr('transform', 'translate(1,0)');
}); // This transform is necessary to get the clip wave positioned correctly when waveRise=true and waveAnimate=false. The wave will not position correctly without this, but it's not clear why this is actually necessary.
} else {
waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fillPercent) + ')');
}
if (config.waveAnimate) animateWave();
function animateWave() {
wave.attr('transform', 'translate(' + waveAnimateScale(+wave.attr('T')) + ',0)');
wave.transition()
.duration(config.waveAnimateTime * (1 - +wave.attr('T')))
.ease(d3.easeLinear)
.attr('transform', 'translate(' + waveAnimateScale(1) + ',0)')
.attr('T', 1)
.on('end', function() {
wave.attr('T', 0);
animateWave();
});
}
}
}
add d3v4 script cdn like this in index.html:-
--------------------------------------------
index.html
-------------
<script src="https://d3js.org/d3.v4.min.js"></script>
beaker-chart.component.html
-------------------------------
<svg id="fillgauge1" width="97%" height="250"></svg>
beaker-chart.component.ts
------------------------------
import { AfterViewInit, Component, OnInit, Input, Renderer,ViewChildren, ElementRef, ViewEncapsulation, HostListener, EventEmitter, Injector, Output } from '@angular/core';
declare var d3:any;
@Component({
selector: 'app-beaker-chart',
templateUrl: './beaker-chart.component.html',
styleUrls: ['./beaker-chart.component.css'],
encapsulation: ViewEncapsulation.None
})
export class BeakerChartComponent implements OnInit {
gauge1: any;
config0: any;
jsonData: any;
errorMessage: any;
elemetsRef: any;
loadLiquidFillGauge: any;
liquidFillGaugeDefaultSettings: any;
constructor(public renderer: Renderer, public elementRef: ElementRef,public injector: Injector,public jsonDataService: JsonDataService) {
this.elemetsRef = ElementRef;
}
ngOnInit() {
this.beakerChart();
}
beakerChart(){
(function(d3) {
var idGenerator = (function() {
var count = 0;
return function(prefix) {
return prefix + "-" + count++;
};
})();
var defaultConfig = {
// Values
minValue: 0, // The gauge minimum value.
maxValue: 100, // The gauge maximum value.
// Styles
circleThickness: 0.05, // The outer circle thickness as a percentage of it's radius.
circleFillGap: 0.05, // The size of the gap between the outer circle and wave circle as a percentage of the outer circles radius.
circleColor: "#178BCA", // The color of the outer circle.
backgroundColor: null, // The color of the background
waveColor: "#178BCA", // The color of the fill wave.
width: 0, // You might want to set the width and height if it is not detected properly by the plugin
height: 0,
// Gradient
fillWithGradient: false, // Controls if the wave should be filled with gradient
gradientPoints: [0, 0, 1., 1.], // [x1, y1, x2, y2], coordinates for gradient start point(x1,y1) and final point(x2,y2)
gradientFromColor: "#FFF",
gradientToColor: "#000",
// Waves
waveHeight: 0.05, // The wave height as a percentage of the radius of the wave circle.
waveCount: 1, // The number of full waves per width of the wave circle.
waveOffset: 0, // The amount to initially offset the wave. 0 = no offset. 1 = offset of one full wave.
// Animations
waveRise: true, // Control if the wave should rise from 0 to it's full height, or start at it's full height.
waveRiseTime: 1000, // The amount of time in milliseconds for the wave to rise from 0 to it's final height.
waveRiseAtStart: true, // If set to false and waveRise at true, will disable only the initial animation
waveAnimate: true, // Controls if the wave scrolls or is static.
waveAnimateTime: 18000, // The amount of time in milliseconds for a full wave to enter the wave circle.
waveHeightScaling: true, // Controls wave size scaling at low and high fill percentages. When true, wave height reaches it's maximum at 50% fill, and minimum at 0% and 100% fill. This helps to prevent the wave from making the wave circle from appear totally full or empty when near it's minimum or maximum fill.
valueCountUp: true, // If true, the displayed value counts up from 0 to it's final value upon loading and updating. If false, the final value is displayed.
valueCountUpAtStart: true, // If set to false and valueCountUp at true, will disable only the initial animation
// Text
textVertPosition: 0.5, // The height at which to display the percentage text withing the wave circle. 0 = bottom, 1 = top.
textSize: 1, // The relative height of the text to display in the wave circle. 1 = 50%
displayPercent: true, // If true, a % symbol is displayed after the value.
textColor: "#045681", // The color of the value text when the wave does not overlap it.
waveTextColor: "#A4DBf8", // The color of the value text when the wave overlaps it.
};
d3.liquidfillgauge = function(g, value, settings) {
// Handle configuration
var config = d3.map(defaultConfig);
d3.map(settings).each(function(val, key) {
config.set(key, val);
});
g.each(function(d) {
var gauge = d3.select(this);
var width = config.get("width") !== 0 ? config.get("width") : parseInt(gauge.style("width"));
var height = config.get("height") !== 0 ? config.get("height") : parseInt(gauge.style("height"));
var radius = Math.min(width, height) / 2;
var locationX = width / 2 - radius;
var locationY = height / 2 - radius;
var fillPercent = Math.max(config.get("minValue"), Math.min(config.get("maxValue"), value)) / config.get("maxValue");
var waveHeightScale;
if (config.get("waveHeightScaling")) {
waveHeightScale = d3.scaleLinear()
.range([0, config.get("waveHeight"), 0])
.domain([0, 50, 100]);
} else {
waveHeightScale = d3.scaleLinear()
.range([config.get("waveHeight"), config.get("waveHeight")])
.domain([0, 100]);
}
var textPixels = (config.get("textSize") * radius / 2);
var textFinalValue = parseFloat(value).toFixed(2);
var textStartValue = config.get("valueCountUp") ? config.get("minValue") : textFinalValue;
var percentText = config.get("displayPercent") ? "%" : "";
var circleThickness = config.get("circleThickness") * radius;
var circleFillGap = config.get("circleFillGap") * radius;
var fillCircleMargin = circleThickness + circleFillGap;
var fillCircleRadius = radius - fillCircleMargin;
var waveHeight = fillCircleRadius * waveHeightScale(fillPercent * 100);
var waveLength = fillCircleRadius * 2 / config.get("waveCount");
var waveClipCount = 1 + config.get("waveCount");
var waveClipWidth = waveLength * waveClipCount;
// Rounding functions so that the correct number of decimal places is always displayed as the value counts up.
var textRounder = function(value) {
return Math.round(value);
};
if (parseFloat(textFinalValue) != parseFloat(textRounder(textFinalValue))) {
textRounder = function(value) {
return parseFloat(value).toFixed(1);
};
}
if (parseFloat(textFinalValue) != parseFloat(textRounder(textFinalValue))) {
textRounder = function(value) {
return parseFloat(value).toFixed(2);
};
}
// Data for building the clip wave area.
var data = [];
for (var i = 0; i <= 40 * waveClipCount; i++) {
data.push({
x: i / (40 * waveClipCount),
y: (i / (40))
});
}
// Scales for drawing the outer circle.
var gaugeCircleX = d3.scaleLinear().range([0, 2 * Math.PI]).domain([0, 1]);
var gaugeCircleY = d3.scaleLinear().range([0, radius]).domain([0, radius]);
// Scales for controlling the size of the clipping path.
var waveScaleX = d3.scaleLinear().range([0, waveClipWidth]).domain([0, 1]);
var waveScaleY = d3.scaleLinear().range([0, waveHeight]).domain([0, 1]);
// Scales for controlling the position of the clipping path.
var waveRiseScale = d3.scaleLinear()
// The clipping area size is the height of the fill circle + the wave height, so we position the clip wave
// such that the it will won't overlap the fill circle at all when at 0%, and will totally cover the fill
// circle at 100%.
.range([(fillCircleMargin + fillCircleRadius * 2 + waveHeight), (fillCircleMargin - waveHeight)])
.domain([0, 1]);
var waveAnimateScale = d3.scaleLinear()
.range([0, waveClipWidth - fillCircleRadius * 2]) // Push the clip area one full wave then snap back.
.domain([0, 1]);
// Scale for controlling the position of the text within the gauge.
var textRiseScaleY = d3.scaleLinear()
.range([fillCircleMargin + fillCircleRadius * 2, (fillCircleMargin + textPixels * 0.7)])
.domain([0, 1]);
// Center the gauge within the parent
var gaugeGroup = gauge.append("g")
.attr('transform', 'translate(' + locationX + ',' + locationY + ')');
// Draw the background circle
if (config.get("backgroundColor")) {
gaugeGroup.append("circle")
.attr("r", radius)
.style("fill", config.get("backgroundColor"))
.attr('transform', 'translate(' + radius + ',' + radius + ')');
}
// Draw the outer circle.
var gaugeCircleArc = d3.arc()
.startAngle(gaugeCircleX(0))
.endAngle(gaugeCircleX(1))
.outerRadius(gaugeCircleY(radius))
.innerRadius(gaugeCircleY(radius - circleThickness));
gaugeGroup.append("path")
.attr("d", gaugeCircleArc)
.style("fill", config.get("circleColor"))
.attr('transform', 'translate(' + radius + ',' + radius + ')');
// Text where the wave does not overlap.
var text1 = gaugeGroup.append("text")
.attr("class", "liquidFillGaugeText")
.attr("text-anchor", "middle")
.attr("font-size", textPixels + "px")
.style("fill", config.get("textColor"))
.attr('transform', 'translate(' + radius + ',' + textRiseScaleY(config.get("textVertPosition")) + ')');
// The clipping wave area.
var clipArea = d3.area()
.x(function(d) {
return waveScaleX(d.x);
})
.y0(function(d) {
return waveScaleY(Math.sin(Math.PI * 2 * config.get("waveOffset") * -1 + Math.PI * 2 * (1 - config.get("waveCount")) + d.y * 2 * Math.PI));
})
.y1(function(d) {
return (fillCircleRadius * 2 + waveHeight);
});
var gaugeGroupDefs = gaugeGroup.append("defs");
var clipId = idGenerator("clipWave");
var waveGroup = gaugeGroupDefs
.append("clipPath")
.attr("id", clipId);
var wave = waveGroup.append("path")
.datum(data)
.attr("d", clipArea);
// The inner circle with the clipping wave attached.
var fillCircleGroup = gaugeGroup.append("g")
.attr("clip-path", "url(#" + clipId + ")");
fillCircleGroup.append("circle")
.attr("cx", radius)
.attr("cy", radius)
.attr("r", fillCircleRadius);
if (config.get("fillWithGradient")) {
var points = config.get("gradientPoints");
var gradientId = idGenerator("linearGradient");
var grad = gaugeGroupDefs.append("linearGradient")
.attr("id", gradientId)
.attr("x1", points[0])
.attr("y1", points[1])
.attr("x2", points[2])
.attr("y2", points[3]);
grad.append("stop")
.attr("offset", "0")
.attr("stop-color", config.get("gradientFromColor"));
grad.append("stop")
.attr("offset", "1")
.attr("stop-color", config.get("gradientToColor"));
fillCircleGroup.style("fill", "url(#" + gradientId + ")");
} else {
fillCircleGroup.style("fill", config.get("waveColor"));
}
// Text where the wave does overlap.
var text2 = fillCircleGroup.append("text")
.attr("class", "liquidFillGaugeText")
.attr("text-anchor", "middle")
.attr("font-size", textPixels + "px")
.style("fill", config.get("waveTextColor"))
.attr('transform', 'translate(' + radius + ',' + textRiseScaleY(config.get("textVertPosition")) + ')');
// Make the wave rise. wave and waveGroup are separate so that horizontal and vertical movement can be controlled independently.
var waveGroupXPosition = fillCircleMargin + fillCircleRadius * 2 - waveClipWidth;
if (config.get("waveAnimate")) {
var animateWave = function() {
wave.transition()
.duration(config.get("waveAnimateTime"))
.ease(d3.easeLinear)
.attr('transform', 'translate(' + waveAnimateScale(1) + ',0)')
.on("end", function() {
wave.attr('transform', 'translate(' + waveAnimateScale(0) + ',0)');
animateWave();
});
};
animateWave();
}
var transition = function(from, to, riseWave, animateText) {
// Update texts and animate
if (animateText) {
var textTween = function() {
var that = d3.select(this);
var i = d3.interpolate(from, to);
return function(t) {
that.text(textRounder(i(t)) + percentText);
};
};
text1.transition()
.duration(config.get("waveRiseTime"))
.tween("text", textTween);
text2.transition()
.duration(config.get("waveRiseTime"))
.tween("text", textTween);
} else {
text1.text(textRounder(to) + percentText);
text2.text(textRounder(to) + percentText);
}
// Update the wave
toPercent = Math.max(config.get("minValue"), Math.min(config.get("maxValue"), to)) / config.get("maxValue");
fromPercent = Math.max(config.get("minValue"), Math.min(config.get("maxValue"), from)) / config.get("maxValue");
if (riseWave) {
waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fromPercent) + ')')
.transition()
.duration(config.get("waveRiseTime"))
.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(toPercent) + ')');
} else {
waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(toPercent) + ')');
}
};
transition(
textStartValue,
textFinalValue,
config.get("waveRise") && config.get("waveRiseAtStart"),
config.get("valueCountUp") && config.get("valueCountUpAtStart")
);
// Event to update the value
gauge.on("valueChanged", function(newValue) {
transition(value, newValue, config.get("waveRise"), config.get("valueCountUp"));
value = newValue;
});
gauge.on("destroy", function() {
// Stop all the transitions
text1.interrupt().transition();
text2.interrupt().transition();
waveGroup.interrupt().transition();
wave.interrupt().transition();
// Unattach events
gauge.on("valueChanged", null);
gauge.on("destroy", null);
});
});
};
})(d3);
d3.select("#fillgauge1").call(d3.liquidfillgauge, 55);
setInterval(function() {
d3.select("#fillgauge1").on("valueChanged")(Math.floor(Math.random() * 100));
}, 2000);
}
}