HEX
Server: Apache
System: Linux webm010.cluster127.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
User: alloesb (202139)
PHP: 8.3.31
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/alloesb/www/escapeometre.html
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
	<title>Donut Chart - Flipped Labels</title>

	<!-- D3.js -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
	
	<!-- Month names -->
	<link href='http://fonts.googleapis.com/css?family=Pacifico' rel='stylesheet' type='text/css'>
	
	<style>

		body {
			font-family: 'Josefin Sans', sans-serif;
			fill: #333333;
			font-weight: 500;
			font-size: 16px;
			text-align: center;
			letter-spacing: -0.08em;
		}

		#jauge-immersion {
			position: relative;
			top: 47px;
		}

		#donut {
			position: absolute;
			top: 0;
			left: 50%;
			margin-left: -150px;
			transition: transform 0.5s 0s;
			border: 1px solid #eee;
		}

		#line1, #line2 {
			position: fixed;
			height: 100%;
			box-sizing: border-box;
			border-left: 1px solid red;
		}

		#line1 {
			left: 50%;
			margin-left: -105px;
		}

		#line2 {
			right: 50%;
			margin-right: -105px;
		}

		svg * {
			overflow: visible!important;
		}

	</style>
  </head>
  <body>

	<div id="log" style="display: none; position: fixed; top: 100px; left: 30px; background: #fff; padding: 20px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.23); z-index: 99999;"></div>
	<!-- <div id="line1"></div>
	<div id="line2"></div> -->
  	<div id="jauge-immersion"><svg id="fillgauge2" height="190" onclick=""></svg></div>
	<div id="donut"></div>

	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

	<script>
		
	jQuery(document).ready(function($) {

		// Debug : Affiche son paramètre sur le front
		function log(log) { 
		    $('#log').show()
		    $('#log').html(log) 
		}

	    $('#donut').click(function(){
	    	$(this).animate({
		        duration: 2000,
		        step: function(){
		            $elem.css({
		                transform: 'rotate(90deg)'
		            });
	        	}
	        })
	    });

	});

	</script>
	
    <script>
	
		////////////////////////////////////////////////////////////
		//////////////////////// Set-up ////////////////////////////
		////////////////////////////////////////////////////////////

		var screenWidth = window.innerWidth;

		var margin = {left: 20, top: 20, right: 20, bottom: 20},
			width = Math.min(screenWidth, 300) - margin.left - margin.right,
			height = Math.min(screenWidth, 300) - margin.top - margin.bottom;
					
		var svg = d3.select("#donut").append("svg")
					.attr("width", (width + margin.left + margin.right))
					.attr("height", (height + margin.top + margin.bottom))
				   .append("g").attr("class", "wrapper")
					.attr("transform", "translate(" + (width / 2 + margin.left) + "," + (height / 2 + margin.top) + ")");

		////////////////////////////////////////////////////////////// 
		///////////////////// Data &  Scales ///////////////////////// 
		////////////////////////////////////////////////////////////// 

function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min)) + min;
}

value1 = getRandomInt(2, 11) * 10; // 60 
value2 = getRandomInt(2, 11) * 10; // 80 
value3 = getRandomInt(2, 11) * 10; // 60 
value4 = getRandomInt(2, 11) * 10; // 70 

		//Some random data
		var donutData = [
			{name: "Fouille",	value: value1 },
			{name: "Manipulation", 	value: value2 },
			{name: "Énigmes", 	value: value3 },
		];

console.log('Fouille : ' + value1)
console.log('Manipulation : ' + value2)
console.log('Énigmes : ' + value3)
console.log('Immersion : ' + value4)


		//Create a color scale
		var colorScale = d3.scale.linear()
		   .domain([0,1,2])
		   .range(["#ed709e", "#23b2a4", "#6cc8e2"])
		   .interpolate(d3.interpolateHcl);

		//Create an arc function   
		var arc = d3.svg.arc()
			.innerRadius(width*0.75/2 -7) 
			.outerRadius(width*0.75/2 + 5);

		//Turn the pie donut 90 degrees counter clockwise, so it starts at the left	
		var pie = d3.layout.pie()
			.startAngle(-90 * Math.PI/180)
			.endAngle(-90 * Math.PI/180 + 2*Math.PI)
			.value(function(d) { return d.value; })
			.padAngle(.01)
			.sort(null);
		 
		////////////////////////////////////////////////////////////// 
		//////////////////// Create Donut Chart ////////////////////// 
		////////////////////////////////////////////////////////////// 

		//Create the donut slices and also the invisible arcs for the text 
		svg.selectAll(".donutArcs")
			.data(pie(donutData))
		  .enter().append("path")
			.attr("class", "donutArcs")
			.attr("d", arc)
			.style("fill", function(d,i) {
				if(i === 7) return "#CCCCCC"; //Other
				else return colorScale(i); 
			})
		.each(function(d,i) {
			//Search pattern for everything between the start and the first capital L
			var firstArcSection = /(^.+?)L/; 	

			//Grab everything up to the first Line statement
			var newArc = firstArcSection.exec( d3.select(this).attr("d") )[1];
			//Replace all the comma's so that IE can handle it
			newArc = newArc.replace(/,/g , " ");
			
			//If the end angle lies beyond a quarter of a circle (90 degrees or pi/2) 
			//flip the end and start position
			if (d.endAngle > 360 * Math.PI/180) {
				var startLoc 	= /M(.*?)A/,		//Everything between the first capital M and first capital A
					middleLoc 	= /A(.*?)0 0 1/,	//Everything between the first capital A and 0 0 1
					endLoc 		= /0 0 1 (.*?)$/;	//Everything between the first 0 0 1 and the end of the string (denoted by $)
				//Flip the direction of the arc by switching the start en end point (and sweep flag)
				//of those elements that are below the horizontal line
				var newStart = endLoc.exec( newArc )[1];
				var newEnd = startLoc.exec( newArc )[1];
				var middleSec = middleLoc.exec( newArc )[1];
				
				//Build up the new arc notation, set the sweep-flag to 0
				newArc = "M" + newStart + "A" + middleSec + "0 0 0 " + newEnd;
			}//if
			
			//Create a new invisible arc that the text can flow along
			svg.append("path")
				.attr("class", "hiddenDonutArcs")
				.attr("id", "donutArc"+i)
				.attr("d", newArc)
				.style("fill", "none");
		});
			
		//Append the label names on the outside
		svg.selectAll(".donutText")
			.data(pie(donutData))
		   .enter().append("text")
		   //.enter().append("value")
			.attr("class", "donutText")
			//Move the labels below the arcs for those slices with an end angle greater than 90 degrees
			.attr("dy", function(d,i) { return (d.endAngle > 360 * Math.PI/180 ? 18 : -8); })
		   .append("textPath")
			.attr("startOffset","50%")
			.style({
				"text-anchor" : "middle"
			})
			.attr("xlink:href",function(d,i){return "#donutArc"+i;})
			.text(function(d){return d.data.name;});


	</script>
	<script>

var config_immersion = liquidFillGaugeDefaultSettings();

config_immersion.circleColor = "#fff"
config_immersion.textColor = "#6f9fa3"
config_immersion.waveTextColor = "#6fc3bb"
config_immersion.waveColor = "#a4f1d6"
config_immersion.waveCount = 1.8;
config_immersion.waveRiseTime = 10;
config_immersion.waveAnimateTime = 5000;
config_immersion.displayPercent = true;
config_immersion.valueCountUp = false;
config_immersion.textSize = 0.4;

var gauge2 = loadLiquidFillGauge("fillgauge2", value4, config_immersion);

/*!
 * @license Open source under BSD 2-clause (http://choosealicense.com/licenses/bsd-2-clause/)
 * Copyright (c) 2015, Curtis Bratton
 * All rights reserved.
 *
 * Liquid Fill Gauge v1.1
 */
function liquidFillGaugeDefaultSettings() {
  return {
    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: false, // 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.
  };
}

function loadLiquidFillGauge(elementId, value, config) {
  if (config == null) config = liquidFillGaugeDefaultSettings();

  var gauge = d3.select("#" + elementId);
  var radius = Math.min(parseInt(gauge.style("width")), parseInt(gauge.style("height"))) / 2;
  var locationX = parseInt(gauge.style("width")) / 2 - radius;
  var locationY = parseInt(gauge.style("height")) / 2 - radius;
  var fillPercent = Math.max(config.minValue, Math.min(config.maxValue, value)) / config.maxValue;

  var waveHeightScale;
  if (config.waveHeightScaling) {
    waveHeightScale = d3.scale.linear()
      .range([0, config.waveHeight, 0])
      .domain([0, 50, 100]);
  } else {
    waveHeightScale = d3.scale.linear()
      .range([config.waveHeight, config.waveHeight])
      .domain([0, 100]);
  }

  var textPixels = (config.textSize * radius / 2);
  var textFinalValue = parseFloat(value).toFixed(2);
  var textStartValue = config.valueCountUp ? config.minValue : textFinalValue;
  var percentText = config.displayPercent ? "%" : "";
  var circleThickness = config.circleThickness * radius;
  var circleFillGap = config.circleFillGap * radius;
  var fillCircleMargin = circleThickness + circleFillGap;
  var fillCircleRadius = radius - fillCircleMargin;
  var waveHeight = fillCircleRadius * waveHeightScale(fillPercent * 100);

  var waveLength = fillCircleRadius * 2 / config.waveCount;
  var waveClipCount = 1 + config.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.scale.linear().range([0, 2 * Math.PI]).domain([0, 1]);
  var gaugeCircleY = d3.scale.linear().range([0, radius]).domain([0, radius]);

  // Scales for controlling the size of the clipping path.
  var waveScaleX = d3.scale.linear().range([0, waveClipWidth]).domain([0, 1]);
  var waveScaleY = d3.scale.linear().range([0, waveHeight]).domain([0, 1]);

  // Scales for controlling the position of the clipping path.
  var waveRiseScale = d3.scale.linear()
    // 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]);
  var waveAnimateScale = d3.scale.linear()
    .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.scale.linear()
    .range([fillCircleMargin + fillCircleRadius * 2, (fillCircleMargin + textPixels * 0.7)])
    .domain([0, 1]);

  // Center the gauge within the parent SVG.
  var gaugeGroup = gauge.append("g")
    .attr('transform', 'translate(' + locationX + ',' + locationY + ')');

  // Draw the outer circle.
  var gaugeCircleArc = d3.svg.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.
  var text1 = gaugeGroup.append("text")
	.text("Immersion")
	.attr("dy", "0em")
  //.append("text")
    .text("Immersion : " + textRounder(textStartValue) + percentText)
    .attr("class", "liquidFillGaugeText")
    //.attr("dy", "1em")
    .attr("text-anchor", "middle")
    .attr("font-size", textPixels + "px")
    .style("fill", config.textColor)
    .attr('transform', 'translate(' + radius + ',' + textRiseScaleY(config.textVertPosition) + ')');

  // The clipping wave area.
  var clipArea = d3.svg.area()
    .x(function(d) {
      return waveScaleX(d.x);
    })
    .y0(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);
    });
  var waveGroup = gaugeGroup.append("defs")
    .append("clipPath")
    .attr("id", "clipWave" + elementId);
  var wave = waveGroup.append("path")
    .datum(data)
    .attr("d", clipArea)
    .attr("T", 0);

  // The inner circle with the clipping wave attached.
  var 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.
  var text2 = fillCircleGroup.append("text")
	.text("Immersion")  	
	.attr("dy", "0em")
  //.append("text")
    .text("Immersion : " + textRounder(textStartValue) + percentText)
    .attr("class", "liquidFillGaugeText")
    //.attr("dy", "1em")
    .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) {
    var textTween = function() {
      var i = d3.interpolate(this.textContent, textFinalValue);
      return function(t) {
        this.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.
  var 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) + ')')
      .each("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('linear')
      .attr('transform', 'translate(' + waveAnimateScale(1) + ',0)')
      .attr('T', 1)
      .each('end', function() {
        wave.attr('T', 0);
        animateWave(config.waveAnimateTime);
      });
  }

  function GaugeUpdater() {
    this.update = function(value) {
      var newFinalValue = parseFloat(value).toFixed(2);
      var textRounderUpdater = function(value) {
        return Math.round(value);
      };
      if (parseFloat(newFinalValue) != parseFloat(textRounderUpdater(newFinalValue))) {
        textRounderUpdater = function(value) {
          return parseFloat(value).toFixed(1);
        };
      }
      if (parseFloat(newFinalValue) != parseFloat(textRounderUpdater(newFinalValue))) {
        textRounderUpdater = function(value) {
          return parseFloat(value).toFixed(2);
        };
      }

      var textTween = function() {
        var i = d3.interpolate(this.textContent, parseFloat(value).toFixed(2));
        return function(t) {
          this.textContent = textRounderUpdater(i(t)) + percentText;
        }
      };

      text1.transition()
        .duration(config.waveRiseTime)
        .tween("text", textTween);
      text2.transition()
        .duration(config.waveRiseTime)
        .tween("text", textTween);

      var fillPercent = Math.max(config.minValue, Math.min(config.maxValue, value)) / config.maxValue;
      var waveHeight = fillCircleRadius * waveHeightScale(fillPercent * 100);
      var waveRiseScale = d3.scale.linear()
        // 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]);
      var newHeight = waveRiseScale(fillPercent);
      var waveScaleX = d3.scale.linear().range([0, waveClipWidth]).domain([0, 1]);
      var waveScaleY = d3.scale.linear().range([0, waveHeight]).domain([0, 1]);
      var newClipArea;
      if (config.waveHeightScaling) {
        newClipArea = d3.svg.area()
          .x(function(d) {
            return waveScaleX(d.x);
          })
          .y0(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);
          });
      } else {
        newClipArea = clipArea;
      }

      var newWavePosition = config.waveAnimate ? waveAnimateScale(1) : 0;
      wave.transition()
        .duration(0)
        .transition()
        .duration(config.waveAnimate ? (config.waveAnimateTime * (1 - wave.attr('T'))) : (config.waveRiseTime))
        .ease('linear')
        .attr('d', newClipArea)
        .attr('transform', 'translate(' + newWavePosition + ',0)')
        .attr('T', '1')
        .each("end", function() {
          if (config.waveAnimate) {
            wave.attr('transform', 'translate(' + waveAnimateScale(0) + ',0)');
            animateWave(config.waveAnimateTime);
          }
        });
      waveGroup.transition()
        .duration(config.waveRiseTime)
        .attr('transform', 'translate(' + waveGroupXPosition + ',' + newHeight + ')')
    }
  }

var insertLinebreaks = function (d) {
    var el = d3.select(this);
    var words = d.split(' ');
    el.text('');

    for (var i = 0; i < words.length; i++) {
        var tspan = el.append('tspan').text(words[i]);
        if (i > 0)
            tspan.attr('x', 0).attr('dy', '15');
    }
};

svg.selectAll('.liquidFillGaugeText').each(insertLinebreaks);


  return new GaugeUpdater();
}

	</script>


	
  </body>
</html>