HTML Clock to resize automatically keeping the proportion - javascript

Ok, So I've editing this clock for a day now, I managed to remove the background and centered date/time as intended, I also wanted to put it on the side of the frame, so when adding I don't waste space. Turns out that although this code is the way I wanted, when I try to resize it (clicking and resizing the frame) the clock keep its size. It has this script to enable it to be resized, but unfortunately it's not working. I have no clue how to fix this anymore. I tried using 100% instead of pxs, changeing references to auto, still no luck.
<style>
#import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,900|Dosis:300,400,600,700,800|Droid+Sans:400,700|Lato:300,400,700,900|PT+Sans:400,700|Ubuntu:300,400,500,700|Open+Sans:400,300,600,700|Roboto:400,300,500,700,900|Roboto+Condensed:400,300,700|Open+Sans+Condensed:300,700|Play:400,700|Maven+Pro:400,500,700,900&subset=latin,latin-ext);
body {
padding: 0;
margin: 0;
overflow: hidden;
}
svg {
position: auto;
width: 100%;
height: 100%;
}
.bgDot {
stroke: none;
fill: #215769;
}
.clockCircle {
fill: none;
stroke: #2a2a2a;
}
.clockArc {
fill: none;
stroke: #1bbccb;
}
.clockDot {
fill: #e9fafc;
}
.caption {
font-family: "Source Sans Pro";
font-weight: 300;
fill: White;
}
.dayText {
font-size: 1.7rem;
}
.dateText {
font-size: 2.5rem;
font-weight: 400;
}
.timeText {
font-family: "Open Sans";
font-size: 5rem;
font-weight: 600;
fill: White;
}
</style>
<script>
window.console = window.console || function(t) {};
</script>
<script>
if (document.location.search.match(/type=embed/gi)) {
window.parent.postMessage("resize", "*");
}
</script>
</head>
<body translate="no" >
<svg>
<defs>
<pattern id="dotPattern"
x="0" y="0" width="050" height="10"
patternUnits="userSpaceOnUse">
<circle class="bgDot" cx="5" cy="5" r="2" />
</pattern>
<radialGradient id="backHoleBelowClock" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="50%" style="stop-color:rgb(0,0,0);stop-opacity:0.7"/>
<stop offset="100%" style="stop-color:rgb(0,0,0);stop-opacity:0"/>
</radialGradient>
<radialGradient id="blackVignette" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="40%" style="stop-color:rgb(0,0,0);stop-opacity:0" />
<stop offset="100%" style="stop-color:rgb(0,0,0);stop-opacity:1" />
</radialGradient>
<filter id="glow">
<feGaussianBlur stdDeviation="2.5" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3" result="shadow"/>
<feOffset dx="1" dy="1"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<!-- Clock objects -->
<circle class="clockCircle hour" cx="190" cy="240" r="150" stroke-width="6" />
<path id="arcHour" class="clockArc hour" stroke-width="6" stroke-linecap="round" filter="url(#glow)" />
<circle class="clockDot hour" r="8" filter="url(#glow)" />
<circle class="clockCircle minute" cx="190" cy="240" r="170" stroke-width="3" />
<path id="arcMinute" class="clockArc minute" stroke-width="3" stroke-linecap="round" filter="url(#glow)" />
<circle class="clockDot minute" r="5" filter="url(#glow)" />
<!-- Caption objects -->
<text id="time" class="caption timeText" x="190" y="250" stroke-width="0" text-anchor="middle" alignment-baseline="middle" filter="url(#shadow)"></text>
<text id="day" class="caption dayText" x="190" y="189" stroke-width="0" text-anchor="end" alignment-baseline="middle" filter="url(#shadow)"></text>
<text id="date" class="caption dateText" x="85" y="300" stroke-width="0" alignment-baseline="middle" filter="url(#shadow)"></text>
</svg>
<script src="https://cpwebassets.codepen.io/assets/common/stopExecutionOnTimeout-1b93190375e9ccc259df3a57c1abc0e64599724ae30d7ea4c6877eb615f89387.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment-with-locales.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/1.16.1/TweenMax.min.js'></script>
<script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/DrawSVGPlugin.js?r=5'></script>
<script id="rendered-js" >
/*
Inspired by https://dribbble.com/shots/2004657-Alarm-Clock-concept
*/
var describeArc, polarToCartesian, setCaptions;
polarToCartesian = function (centerX, centerY, radius, angleInDegrees) {
var angleInRadians;
angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
return {
x: centerX + radius * Math.cos(angleInRadians),
y: centerY + radius * Math.sin(angleInRadians) };
};
describeArc = function (x, y, radius, startAngle, endAngle) {
var arcSweep, end, start;
start = polarToCartesian(x, y, radius, endAngle);
end = polarToCartesian(x, y, radius, startAngle);
arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
return ['M', start.x, start.y, 'A', radius, radius, 0, arcSweep, 0, end.x, end.y].join(' ');
};
setCaptions = function () {
var dot, hour, hourArc, minArc, minute, now, pos;
now = new Date();
hour = now.getHours() % 12;
minute = now.getMinutes();
hourArc = (hour * 60 + minute) / (12 * 60) * 360;
minArc = minute / 60 * 360;
$('.clockArc.hour').attr('d', describeArc(190, 240, 150, 0, hourArc));
$('.clockArc.minute').attr('d', describeArc(190, 240, 170, 0, minArc));
$('.clockDot.hour').attr('d', describeArc(190, 240, 150, hourArc - 3, hourArc));
$('.clockDot.minute').attr('d', describeArc(190, 240, 170, minArc - 1, minArc));
dot = $(".clockDot.hour");
pos = polarToCartesian(190, 240, 150, hourArc);
dot.attr("cx", pos.x);
dot.attr("cy", pos.y);
dot = $(".clockDot.minute");
pos = polarToCartesian(190, 240, 170, minArc);
dot.attr("cx", pos.x);
dot.attr("cy", pos.y);
return $('#time').text(moment().format('H:mm'));
};
$('#day').text(moment().format('dddd'));
$('#date').text(moment().format('MMMM D'));
setCaptions();
setInterval(function () {
return setCaptions();
}, 10 * 1000);
$(function () {
TweenMax.staggerFrom(".clockArc", .5, {
drawSVG: 0,
ease: Power3.easeOut },
0.3);
TweenMax.from("#time", 1.0, {
attr: {
y: 350 },
opacity: 0,
ease: Power3.easeOut,
delay: 0.5 });
TweenMax.from(".dayText", 1.0, {
attr: {
y: 310 },
opacity: 0,
delay: 1.0,
ease: Power3.easeOut });
return TweenMax.from(".dateText", 1.0, {
attr: {
y: 350 },
opacity: 0,
delay: 1.5,
ease: Power3.easeOut });
});
// ---
// generated by coffee-script 1.9.2
//# sourceURL=pen.js
</script>
</body>
</html>
(Sorry, I know it's a long code) This will be used as my new clock time for multiple applications from digital radios to Smart Screens and I really want to use this design as it will make it easy to combine with most of colours that we use.

You will most likely need a viewBox attribute like added to your svg element. E.g.
<svg viewBox="0 0 500 500" >
.resize{
position:relative;
resize:both;
width:100px;
border: 1px solid red;
overflow:hidden;
}
body {
padding: 0;
margin: 0;
overflow: hidden;
}
.bgDot {
stroke: none;
fill: #215769;
}
.clockCircle {
fill: none;
stroke: #2a2a2a;
}
.clockArc {
fill: none;
stroke: #1bbccb;
}
.clockDot {
fill: #e9fafc;
}
.caption {
font-family: "Source Sans Pro";
font-weight: 300;
fill: White;
}
.dayText {
font-size: 1.7rem;
}
.dateText {
font-size: 2.5rem;
font-weight: 400;
}
.timeText {
font-family: "Open Sans";
font-size: 5rem;
font-weight: 600;
fill: White;
}
<div class="resize">
<svg viewBox="0 0 500 500" >
<defs>
<pattern id="dotPattern"
x="0" y="0" width="50" height="10" patternUnits="userSpaceOnUse">
<circle class="bgDot" cx="5" cy="5" r="2" />
</pattern>
<radialGradient id="backHoleBelowClock" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="50%" style="stop-color:rgb(0,0,0);stop-opacity:0.7"/>
<stop offset="100%" style="stop-color:rgb(0,0,0);stop-opacity:0"/>
</radialGradient>
<radialGradient id="blackVignette" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="40%" style="stop-color:rgb(0,0,0);stop-opacity:0" />
<stop offset="100%" style="stop-color:rgb(0,0,0);stop-opacity:1" />
</radialGradient>
<filter id="glow">
<feGaussianBlur stdDeviation="2.5" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3" result="shadow"/>
<feOffset dx="1" dy="1"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<!-- Clock objects -->
<circle class="clockCircle hour" cx="190" cy="240" r="150" stroke-width="6" />
<path id="arcHour" class="clockArc hour" stroke-width="6" stroke-linecap="round" filter="url(#glow)" />
<circle class="clockDot hour" r="8" filter="url(#glow)" />
<circle class="clockCircle minute" cx="190" cy="240" r="170" stroke-width="3" />
<path id="arcMinute" class="clockArc minute" stroke-width="3" stroke-linecap="round" filter="url(#glow)" />
<circle class="clockDot minute" r="5" filter="url(#glow)" />
<!-- Caption objects -->
<text id="time" class="caption timeText" x="190" y="250" stroke-width="0" text-anchor="middle" alignment-baseline="middle" filter="url(#shadow)"></text>
<text id="day" class="caption dayText" x="190" y="189" stroke-width="0" text-anchor="end" alignment-baseline="middle" filter="url(#shadow)"></text>
<text id="date" class="caption dateText" x="85" y="300" stroke-width="0" alignment-baseline="middle" filter="url(#shadow)"></text>
</svg>
</div>

Related

Trying to calculate the value of a transform

I'm trying to make a function to calculate the value that I need to make the svg moving from a Point A to a Point B with an angle.
On this image, I have a flower
I would like to do that :
I'm trying to make a function to calculate the translateX, translateY and the degree of the rotation but that doesn't work and I don't know how to fix it, here's my code :
var texte = document.getElementsByClassName("texte");
//Here, the coordinates where I want each petal to arrive, I will try to make something to calculate it depending on the screen...
var arriveex = 1082.4940185546875;
var arriveey = 8.80517578125;
var arriveeright = 1402.2513427734375;
var arriveewidth = 319.75732421875;
var arriveeheight = 256.9661865234375;
//The function to calculate the distance between the starting point and the finishing point
function getDistanceX(x1, x2){
let x = x2 - x1;
return Math.sqrt(x*x);}
function getDistanceY(y1, y2) {
let y = y2 - y1;
return Math.sqrt(y*y);
}
//Here the loop for seeking the coordonate of each petal and add the animate function when I click on it
for (var i = 0 ; i < petale.length; i++) {
petale[i].addEventListener('click', function(){
var positions =this.getBoundingClientRect();
var xpetale = positions['x'];
var ypetale = positions['y'];
var bottompetale = positions['bottom'];
var rightpetale = positions['right'];
var distanceX = getDistanceX(xpetale,arriveex);
var distanceY = getDistanceY(ypetale, arriveey);
//Here, the function to calculate the angle with the Al Kashi formula
var adjx1 = Math.abs(arriveex-rightpetale);
var adjy1 = Math.abs(bottompetale-arriveey);
var adjx2 = Math.abs(xpetale-arriveex);
var adjy2 = Math.abs(arriveey-ypetale);
var adjx3 = Math.abs(xpetale-rightpetale);
var adjy3 = Math.abs(bottompetale-ypetale);
var side1 = Math.sqrt(adjx1*adjx1+adjy1*adjy1);
var side2 = Math.sqrt(adjx2*adjx2+adjy2*adjy2);
var side3 = Math.sqrt(adjx3*adjx3+adjy3*adjy3);
var angle = Math.acos(((side2*side2)+(side1*side1)-(side3*side3))/(2*side2*side1));
var deg = (angle*180/Math.PI);
this.animate([
// {transform : 'rotate(75deg) translateY(-1200px) translateX(150px) scale(1.3)'},
{transform :`rotate(${deg}deg)`+`translateX(${distanceX}px)` + `translateY(-${distanceY}px)`},
],
{
duration : 3000,
}
)
})
}
The animation doesn't work properly even if I move the rotation (because the order has an importance in CSS ! :p) so I don't know how to make it work for each petal.
I would like that each petal goes in the right place when I click on it so I need a function that can calculate the angle of the rotation and the translation that I need. I hope that it's clear, my english is maybe a little bad...
I can't put my svg because the code is too long even in answer.
Thank you !
I rather recommend to rebuild your petal group (flower) using transforms.
This way you can simplify the calculation of animated translate and rotate values significantly.
Example svg: rotated petals
let petals = document.querySelectorAll('.gPetal');
petals.forEach((petal)=>{
petal.addEventListener('click', (e)=>{
e.currentTarget.style.transform = 'rotate(0)'
})
})
svg {
width: 30em;
}
text {
font-family: "Segoe UI";
fill: #fff;
font-size: 6px;
user-select: none;
transform: translate(75%, 33%);
dominant-baseline: central;
text-anchor: middle;
}
.gPetal {
transition: 0.5s;
transform-box: fill-box;
transform-origin: center;
cursor:pointer
}
.gPetal[data-rotate="60"] {
transform: rotate(60deg);
}
.gPetal[data-rotate="120"] {
transform: rotate(120deg);
}
.gPetal[data-rotate="180"] {
transform: rotate(180deg);
}
.gPetal[data-rotate="240"] {
transform: rotate(240deg);
}
.gPetal[data-rotate="300"] {
transform: rotate(300deg);
}
<p>Click on a petal to reset rotation</p>
<svg x="0" y="0" width="400" viewBox="0 0 100 100" overflow="visible">
<defs>
<linearGradient id="gradient" gradientTransform="rotate(90)">
<stop offset="0%" stop-color="purple" />
<stop offset="90%" stop-color="red" />
</linearGradient>
</defs>
<symbol id="petal" viewBox="0 0 100 100">
<rect x="0" y="0" width="100%" height="100%" fill="none" stroke="green" stroke-width="0.5" />
<path fill="url(#gradient)" id="circle" d="M50 50 a25 25 0 1 1 50 0 z" />
</symbol>
<g class="gPetal gPetal6" data-rotate="300">
<use href="#petal" />
<text dy="5%" data-style="font-size:10px">Label 6</text>
</g>
<g class="gPetal gPetal5" data-rotate="240">
<use href="#petal" />
<text dy="5%" data-style="font-size:10px">Label 5</text>
</g>
<g class="gPetal gPetal4" data-rotate="180">
<use href="#petal" />
<text dy="5%">Label 4</text>
</g>
<g class="gPetal gPetal3" data-rotate="120">
<use href="#petal" />
<text dy="5%">Label 3</text>
</g>
<g class="gPetal gPetal2" data-rotate="60">
<use href="#petal" />
<text dy="5%">Label 2</text>
</g>
<g class="gPetal gPetal1" data-rotate="0">
<use href="#petal" />
<text dy="5%" data-style="font-size:10px">Label 1</text>
</g>
</svg>
Each petal is positioned in a square bounding box based on a reused <symbol> definition (for the petal's shape and fill).
They are rotated by an angle incremented by 60 degrees for each element.
This way we don't need additional translate transformations.
Admittedly some extra work, but it can also help to improve your apps performance by decreasing the svg's filesize.
Example: Highlighting/selecting petal
When a petal is selected, the rotation is reset to 0 degrees.
Besides you can add some x/y offsets to shift the element to the right.
The data-attribute data-rotate stores the initial rotation and helps to rewind the animation, when a petal gets clicked twice (so becomes deselected).
let svg = document.querySelector("svg");
let petals = svg.querySelectorAll(".gPetal");
petals.forEach((petal) => {
petal.addEventListener("click", (e) => {
let current = e.currentTarget;
let thisStyle = current.style.transform;
let baseRotation = current.getAttribute("data-rotate");
let ani = current.animate(
[
{ transform: "rotate(" + baseRotation + "deg)" },
{ transform: "rotate(0)", color: "#f00", offset: 0.5 },
{ transform: "rotate(0) translate(75%) scale(1.3)" }
],
{
duration: 500,
fill: "both"
}
);
//start animation + reset prevously animated
resetPetals(current, petals);
if (!current.classList.contains("active")) {
petal.classList.add("active");
ani.play();
}
//rewind animation
else {
petal.classList.remove("active");
ani.playbackRate = -1;
ani.play();
}
});
});
function resetPetals(current, petals) {
petals.forEach((petal, p) => {
let allAnimations = petal.getAnimations();
allAnimations.forEach((ani) => {
ani.playbackRate = 1;
ani.finish();
ani.cancel();
});
if (petal !== current) {
petal.classList.remove("active");
}
});
}
svg {
width: 30em;
border: 1px solid red;
}
text {
font-family: "Segoe UI";
fill: #fff;
font-size: 6px;
user-select: none;
transform: translate(75%, 33%);
dominant-baseline: central;
text-anchor: middle;
}
.gPetal {
transition: 0.5s;
transform-box: fill-box;
transform-origin: center;
cursor: pointer
}
.gPetal[data-rotate="60"] {
transform: rotate(60deg);
}
.gPetal[data-rotate="120"] {
transform: rotate(120deg);
}
.gPetal[data-rotate="180"] {
transform: rotate(180deg);
}
.gPetal[data-rotate="240"] {
transform: rotate(240deg);
}
.gPetal[data-rotate="300"] {
transform: rotate(300deg);
}
.active {
fill: red;
}
<svg viewBox="0 0 800 400">
<defs>
<linearGradient id="gradient" gradientTransform="rotate(90)">
<stop offset="0%" stop-color="purple" />
<stop offset="90%" stop-color="red" />
</linearGradient>
</defs>
<symbol id="petal" viewBox="0 0 100 100">
<rect x="0" y="0" width="100%" height="100%" fill="none" />
<path fill="url(#gradient)" id="circle" d="M50 50 a25 25 0 1 1 50 0 z" />
</symbol>
<svg x="0" y="0" width="400" viewBox="0 0 100 100" overflow="visible">
<g class="gPetal gPetal6" data-rotate="300">
<use href="#petal" />
<text dy="5%" data-style="font-size:10px">Label 6</text>
</g>
<g class="gPetal gPetal5" data-rotate="240">
<use href="#petal" />
<text dy="5%" data-style="font-size:10px">Label 5</text>
</g>
<g class="gPetal gPetal4" data-rotate="180">
<use href="#petal" />
<text dy="5%">Label 4</text>
</g>
<g class="gPetal gPetal3" data-rotate="120">
<use href="#petal" />
<text dy="5%">Label 3</text>
</g>
<g class="gPetal gPetal2" data-rotate="60">
<use href="#petal" />
<text dy="5%">Label 2</text>
</g>
<g class="gPetal gPetal1" data-rotate="0">
<use href="#petal" />
<text dy="5%" data-style="font-size:10px">Label 1</text>
</g>
</svg>
</svg>

zoom in SVG with place clicked remaining in the same place

For quite a while I have been dealing with this scenario where I want to zoom in on an SVG image by clicking on it (or tapping in case of a touch-screen device), having it so that where you have clicked stays in the same position on the page while zooming in.
What happens at the moment is that when zooming is done, the pivot is not the clicked point but another point. It seems I cannot get to think of the correct formula to translate the svg as zooming in is done. Preferably I would see a solution that doesn't use an external library as the code below is a simplified version of a bigger project that has quite complicated stuff that would propably not be as easy to refactor to another component.
let zoomedIn = false;
let svgViewboxWidth, svgViewboxHeight;
let factor = 1;
function init() {
svgViewboxWidth = 335.2262416700105;
svgViewboxHeight = 304.65863467997406;
let svgContainer = document.getElementById('svgContainer');
svgContainer.addEventListener('click', svgClick);
}
function svgClick(event) {
let newCalcX = 28, newCalcY = -86;
let gZoom = document.getElementById('zoomscale');
if (zoomedIn) {
// zoom out
factor = 1;
newCalcX = 0;
newCalcY = 0;
zoomedIn = false;
} else {
// zoom in
factor = 3;
newCalcX = (event.clientX - 86) * -1;
newCalcY = (event.clientY + 28) * -1;
zoomedIn = true;
}
let transformValue = `translate(${newCalcX}, ${newCalcY}) scale(${factor})`;
gZoom.setAttribute('transform', transformValue);
}
body {
margin: 0px;
padding: 0px;
}
.container {
width: 100%;
height: 100%;
}
<?xml version='1.0' encoding='UTF-8'?>
<html>
<head>
<title>SVG zoom issue</title>
</head>
<body onload="init()">
<div id="svgContainer" class="container">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="view" height="100%" width="100%" viewBox="0 0 335.2262416700105 304.65863467997406" preserveAspectRatio="xMidYMid meet" version="1.1" class="view">
<style>svg { background-color:rgba(64, 64, 64, 0.1); }</style>
<g id="zoomscale">
<line x1="20" x2="310" y1="150" y2="150" style="stroke: #000000; stroke-width: 1px" />
<line x1="165" x2="165" y1="20" y2="280" style="stroke: #000000; stroke-width: 1px" />
<circle cx="165" cy="150" r="20" style="stroke: #000000; stroke-width: 1px; fill: none" />
<circle cx="165" cy="150" r="40" style="stroke: #000000; stroke-width: 1px; fill: none" />
<circle cx="165" cy="150" r="60" style="stroke: #000000; stroke-width: 1px; fill: none" />
<circle cx="165" cy="150" r="90" style="stroke: #000000; stroke-width: 1px; fill: none" />
<circle cx="165" cy="150" r="120" style="stroke: #000000; stroke-width: 1px; fill: none" />
</g>
</svg>
</div>
</body>
<html>
I feel like I am missing something obvious, or maybe I am just not able to calculate the correct translate- values for zooming. Massive thanks to the one(s) who can help me with this!

Divide semi circle with stroke-dasharray and on active color fill

I'm working on an SVG gauge meter here I want to divide the semi-circle into parts when the range slider move on active stroke fill with gradient color. And want to add one more black color running track when the meter needle moves. I had tried using stroke-dasharray but after adding this all colors are coming at a time meter is not working properly.
I want to divide the semi-circle into parts when the range slider move on active stroke fill with gradient color
And I want to add one more black color running track when the meter needle moves.
My code here
/* set radius for all circles */
var r = 400;
var circles = document.querySelectorAll('.circle');
var total_circles = circles.length;
for (var i = 0; i < total_circles; i++) {
circles[i].setAttribute('r', r);
}
/* set meter's wrapper dimension */
var meter_dimension = (r * 2) + 100;
var wrapper = document.querySelector('#wrapper');
wrapper.style.width = meter_dimension + 'px';
wrapper.style.height = meter_dimension + 'px';
/* add strokes to circles */
var cf = 2 * Math.PI * r;
var semi_cf = cf / 2;
var semi_cf_1by3 = semi_cf / 3;
var semi_cf_2by3 = semi_cf_1by3 * 2;
document.querySelector('#outline_curves').setAttribute('stroke-dasharray', semi_cf + ',' + cf);
document.querySelector('#high').setAttribute('stroke-dasharray', semi_cf + ',' + cf);
document.querySelector('#avg').setAttribute('stroke-dasharray', semi_cf_2by3 + ',' + cf);
document.querySelector('#low').setAttribute('stroke-dasharray', semi_cf_1by3 + ',' + cf);
document.querySelector('#outline_ends').setAttribute('stroke-dasharray', 2 + ',' + (semi_cf - 2));
document.querySelector('#mask').setAttribute('stroke-dasharray', semi_cf + ',' + cf);
/*bind range slider event*/
var slider = document.querySelector('#slider');
var lbl = document.querySelector("#lbl");
var mask = document.querySelector('#mask');
var meter_needle = document.querySelector('#meter_needle');
function range_change_event() {
var percent = slider.value
var meter_value = semi_cf - ((percent * semi_cf) / 100);
mask.setAttribute('stroke-dasharray', meter_value + ',' + cf);
meter_needle.style.transform = 'rotate(' + (450 - ((percent * 180) / 100)) + 'deg)';
lbl.textContent = percent + '%';
}
slider.addEventListener('input', range_change_event);
#wrapper {
position: relative;
margin: auto;
}
#meter {
width: 100%;
height: 100%;
transform: rotate(180deg);
}
.circle {
fill: none;
}
.outline,
#mask {
stroke: #F1F1F1;
stroke-width: 65;
}
.range {
stroke-width: 60;
}
#slider,
#lbl {
position: absolute;
}
#slider {
position: absolute;
transform: rotate(180deg);
cursor: pointer;
left: 0;
margin: auto;
right: 0;
top: 58%;
width: 94%;
}
#lbl {
background-color: #4B4C51;
border-radius: 2px;
color: white;
font-family: 'courier new';
font-size: 15pt;
font-weight: bold;
padding: 4px 4px 2px 4px;
right: -48px;
top: 57%;
}
#meter_needle {
height: 40%;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 10%;
transform-origin: bottom center;
/*orientation fix*/
transform: rotate(450deg);
width: 5px;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div id="wrapper">
<svg id="meter">
<circle id="outline_curves" class="circle outline" cx="50%" cy="50%">
</circle>
<circle id="high" class="circle range" cx="50%" cy="50%" stroke="#FDE47F">
</circle>
<circle id="avg" class="circle range" cx="50%" cy="50%" stroke="#7CCCE5">
</circle>
<circle id="low" class="circle range" cx="50%" cy="50%" stroke="#E04644">
</circle>
<circle id="mask" class="circle" cx="50%" cy="50%" >
</circle>
<circle id="outline_ends" class="circle outline" cx="50%" cy="50%">
</circle>
</svg>
<svg version="1.1" id="meter_needle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16.721px" height="93.834px" viewBox="0 0 16.721 93.834" enable-background="new 0 0 16.721 93.834" xml:space="preserve">
<path fill="#464646" d="M13.886,84.243L2.83,83.875c0,0,3.648-70.77,3.956-74.981C7.104,4.562,7.832,0,8.528,0
c0.695,0,1.752,4.268,2.053,8.894C10.883,13.521,13.886,84.243,13.886,84.243z"/>
<path fill="#464646" d="M16.721,85.475c0,4.615-3.743,8.359-8.36,8.359S0,90.09,0,85.475c0-4.62,3.743-8.363,8.36-8.363
S16.721,80.855,16.721,85.475z"/>
<circle fill="#EEEEEE" cx="8.426" cy="85.471" r="2.691"/>
</svg>
<input id="slider" type="range" min="25" max="100" step="25" value="0" />
<label id="lbl" id="value" for="">0%</label>
</div>
<script src="script.js"></script>
</body>
Can anyone suggest to me how to achieve this output. Any help will be appreciate.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="65px" height="51.333px" viewBox="0 0 65 51.333" enable-background="new 0 0 65 51.333" xml:space="preserve">
<g>
<defs>
<rect id="SVGID_1_" x="-157.417" y="-176.417" width="648" height="864"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_2_)">
<defs>
<rect id="SVGID_3_" x="-157.417" y="-176.417" width="648" height="864"/>
</defs>
<clipPath id="SVGID_4_">
<use xlink:href="#SVGID_3_" overflow="visible"/>
</clipPath>
</g>
<g clip-path="url(#SVGID_2_)">
<defs>
<rect id="SVGID_5_" x="-157.417" y="-176.417" width="648" height="864"/>
</defs>
<clipPath id="SVGID_6_">
<use xlink:href="#SVGID_5_" overflow="visible"/>
</clipPath>
</g>
<g clip-path="url(#SVGID_2_)">
<defs>
<rect id="SVGID_7_" x="-157.417" y="-176.417" width="648" height="864"/>
</defs>
<clipPath id="SVGID_8_">
<use xlink:href="#SVGID_7_" overflow="visible"/>
</clipPath>
<path clip-path="url(#SVGID_8_)" fill="#FFFFFF" d="M19.527,44.274c-1.653,5.015-7.059,7.738-12.071,6.085
c-5.015-1.654-7.739-7.058-6.087-12.071c1.652-5.015,7.058-7.739,12.072-6.084C18.456,33.855,21.179,39.26,19.527,44.274"/>
<path clip-path="url(#SVGID_8_)" fill="#58595B" d="M19.514,44.289c-1.652,5.013-7.056,7.736-12.066,6.083
c-5.014-1.653-7.736-7.056-6.084-12.067c1.652-5.013,7.055-7.736,12.068-6.083C18.443,33.875,21.166,39.277,19.514,44.289"/>
<path clip-path="url(#SVGID_8_)" fill="#FFFFFF" d="M17.318,43.564c-1.253,3.801-5.35,5.865-9.15,4.612
c-3.797-1.253-5.863-5.35-4.609-9.148c1.254-3.8,5.349-5.865,9.148-4.612C16.506,35.67,18.57,39.766,17.318,43.564"/>
<path clip-path="url(#SVGID_8_)" fill="#58595B" d="M19.266,34.944c2.242,3.113,2.33,7.115,0.57,10.255l45.249-43.24L9.721,31.148
C13.256,30.475,17.023,31.828,19.266,34.944"/>
<defs>
<filter id="Adobe_OpacityMaskFilter" filterUnits="userSpaceOnUse" x="6.52" y="-11.184" width="62.369" height="60.661">
<feFlood style="flood-color:white;flood-opacity:1" result="back"/>
<feBlend in="SourceGraphic" in2="back" mode="normal"/>
</filter>
</defs>
<mask maskUnits="userSpaceOnUse" x="6.52" y="-11.184" width="62.369" height="60.661" id="SVGID_9_">
<g filter="url(#Adobe_OpacityMaskFilter)">
<g enable-background="new ">
<g enable-background="new ">
<g>
<defs>
<path id="SVGID_10_" d="M17.516,29.352c2.243,0.335,3.028,2.134,3.028,2.134L57.891,6.807L17.516,29.352z"/>
</defs>
<clipPath id="SVGID_11_" clip-path="url(#SVGID_8_)">
<use xlink:href="#SVGID_10_" overflow="visible"/>
</clipPath>
<defs>
<filter id="Adobe_OpacityMaskFilter_1_" filterUnits="userSpaceOnUse" x="6.52" y="-11.184" width="62.369" height="60.661">
<feFlood style="flood-color:white;flood-opacity:1" result="back"/>
<feBlend in="SourceGraphic" in2="back" mode="normal"/>
</filter>
</defs>
<mask maskUnits="userSpaceOnUse" x="6.52" y="-11.184" width="62.369" height="60.661" id="SVGID_9_">
<g filter="url(#Adobe_OpacityMaskFilter_1_)">
<g enable-background="new ">
</g>
</g>
</mask>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="-236.1787" y1="699.8169" x2="-235.1792" y2="699.8169" gradientTransform="matrix(36.5072 -22.3825 22.3825 36.5072 -7021.3823 -30804.627)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.0466" style="stop-color:#D5D7D8"/>
<stop offset="0.0983" style="stop-color:#B1B3B6"/>
<stop offset="0.1557" style="stop-color:#929497"/>
<stop offset="0.2174" style="stop-color:#797A7D"/>
<stop offset="0.2847" style="stop-color:#626366"/>
<stop offset="0.3595" style="stop-color:#4E4E50"/>
<stop offset="0.445" style="stop-color:#3B3B3C"/>
<stop offset="0.5476" style="stop-color:#202021"/>
<stop offset="0.6848" style="stop-color:#080809"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon clip-path="url(#SVGID_11_)" mask="url(#SVGID_9_)" fill="url(#SVGID_12_)" points="28.547,49.477 68.889,24.744
46.861,-11.184 6.52,13.549 "/>
</g>
</g>
</g>
</g>
</mask>
<g opacity="0.8" clip-path="url(#SVGID_8_)">
<g>
<defs>
<rect id="SVGID_13_" x="6.52" y="-11.184" width="62.369" height="60.661"/>
</defs>
<clipPath id="SVGID_14_">
<use xlink:href="#SVGID_13_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_14_)">
<defs>
<path id="SVGID_15_" d="M17.516,29.352c2.243,0.335,3.028,2.134,3.028,2.134L57.891,6.807L17.516,29.352z"/>
</defs>
<clipPath id="SVGID_16_">
<use xlink:href="#SVGID_15_" overflow="visible"/>
</clipPath>
<linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="-236.1787" y1="699.8169" x2="-235.1792" y2="699.8169" gradientTransform="matrix(36.5072 -22.3825 22.3825 36.5072 -7021.3823 -30804.627)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.1467" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#FFFFFF"/>
</linearGradient>
<polygon clip-path="url(#SVGID_16_)" fill="url(#SVGID_17_)" points="28.547,49.477 68.889,24.744 46.861,-11.184 6.52,13.549
"/>
</g>
</g>
</g>
<path clip-path="url(#SVGID_8_)" fill="#58595B" d="M12.709,42.044c-0.412,1.254-1.765,1.936-3.02,1.523
c-1.253-0.414-1.934-1.765-1.52-3.019c0.412-1.253,1.764-1.936,3.017-1.521C12.44,39.441,13.121,40.792,12.709,42.044"/>
</g>
</g>
</svg>
Here's a working SVG example, with a little bit of javascript.
It's not clear from your question what exactly you want the coloured divisions
to look like. For now I've just made them solid red. But you can make them look however you'd like by changing the fill of the <rect id="meter-colours" .../>.
let METER_DIVISIONS = 10;
let METER_DIVISIONS_GAP = 4;
// Initialise meter
let meterDivisionsElem = document.getElementById("meter-divisions");
// Calculate size of each meter division
let totalLen = meterDivisionsElem.getAttribute("r") * Math.PI;
let numGaps = METER_DIVISIONS - 1;
let divLen = (totalLen - METER_DIVISIONS_GAP * numGaps) / METER_DIVISIONS;
// Set meter divisions dash pattern
let pat = divLen + ' ' + METER_DIVISIONS_GAP + ' ';
meterDivisionsElem.setAttribute("stroke-dasharray", pat.repeat(numGaps) + ' ' + divLen + ' ' + totalLen);
// The slider form element
let sliderElem = document.getElementById("slider");
// The slider label element
let sliderLabelElem = document.getElementById("lbl");
// The needle element
let needleElem = document.getElementById("needle");
// The black bar element
let blackBarElem = document.getElementById("black-bar");
let blackBarLen = blackBarElem.getAttribute("r") * Math.PI;
// The meter colours element
let meterColoursElem = document.getElementById("meter-colours");
function setMeterTo(value)
{
// Update slider label
sliderLabelElem.textContent = value + '%';
// Update needle position
let rotation = value * 180 / 100;
needleElem.setAttribute("transform", "rotate(" + rotation + ")");
// Update black bar length
let barLen = value * blackBarLen / 100;
blackBarElem.setAttribute("stroke-dasharray", barLen + ' ' + (2 * blackBarLen));
// Update coloured division section of the meter
meterColoursElem.setAttribute("transform", "rotate(" + rotation + ")");
}
// Add an input change handler to the slider
sliderElem.addEventListener("input", function(evt) {
setMeterTo(evt.target.value);
});
// Initialise meter to start value
setMeterTo(25);
#wrapper {
width: 600px;
}
#slider {
width: 100%;
}
#needle {
stroke-linecap: round;
}
<div id="wrapper">
<svg id="meter" viewBox="0 0 200 110">
<defs>
<circle id="meter-divisions" r="90" stroke-width="20" stroke-dasharray="282.7"/>
<mask id="meter-divisions-mask">
<use xlink:href="#meter-divisions" stroke="white"/>
</mask>
</defs>
<g transform="translate(100,100) scale(1,-1)" fill="none">
<!-- The grey meter divisions -->
<use xlink:href="#meter-divisions" stroke="lightgrey"/>
<!-- The inner semicircular black bar -->
<circle id="black-bar" r="74" stroke="black" stroke-width="4" stroke-dasharray="232.5"/>
<!-- the needle -->
<line id="needle" x2="70" y2="0" stroke="black" stroke-width="2" stroke-dasharray="282.7"/>
<!-- The coloured form of the ,meter divisions that gets rotated into view with the needle.
It is initially off screen but gets revealed as it rotates. It is masked by using
a shape matching the gray divisions -->
<g mask="url(#meter-divisions-mask">
<rect id="meter-colours" x="-100" y="-100" width="200" height="100" fill="red"/>
</g>
</g>
</svg>
<input id="slider" type="range" min="25" max="100" step="25" value="25" />
<label id="lbl" id="value" for="">0%</label>
</div>
Update re new needle image
First let's simplify your needle image:
<svg width="650px" viewBox="0 0 65 51.333">
<g>
<path fill="#58595B" fill-rule="evenodd" d="M19.514,44.289c-1.652,5.013-7.056,7.736-12.066,6.083c-5.014-1.653-7.736-7.056-6.084-12.067c1.652-5.013,7.055-7.736,12.068-6.083C18.443,33.875,21.166,39.277,19.514,44.289 M17.318,43.564c-1.253,3.801-5.35,5.865-9.15,4.612c-3.797-1.253-5.863-5.35-4.609-9.148c1.254-3.8,5.349-5.865,9.148-4.612C16.506,35.67,18.57,39.766,17.318,43.564 M12.709,42.044c-0.412,1.254-1.765,1.936-3.02,1.523c-1.253-0.414-1.934-1.765-1.52-3.019c0.412-1.253,1.764-1.936,3.017-1.521C12.44,39.441,13.121,40.792,12.709,42.044"/>
<path fill="#58595B" d="M19.266,34.944c2.242,3.113,2.33,7.115,0.57,10.255l45.249-43.24L9.721,31.148C13.256,30.475,17.023,31.828,19.266,34.944"/>
<path fill="#FFFFFF" fill-opacity="0.8" d="M17.516,29.352c2.243,0.335,3.028,2.134,3.028,2.134L57.891,6.807L17.516,29.352z"/>
</g>
</svg>
To use this in your meter, we'll need to locate an accurate centre of rotation (the dot in the circle), and re-orient it so that it has zero angle. We may also need to adjust its scale to fit the meter.
By analysis and experimentation, the centre of rotation is at (10.44, 41.3) and the rotation needed to zero out the rotation is 35.8 deg.
Since the meter is centred at (0,0) we need to start by shifting and rotating the new needle by those amounts.
<svg width="650px" viewBox="0 0 65 51.333">
<g transform="rotate(35.8) translate(-10.44, -41.3)">
<path fill="#58595B" fill-rule="evenodd" d="M19.514,44.289c-1.652,5.013-7.056,7.736-12.066,6.083c-5.014-1.653-7.736-7.056-6.084-12.067c1.652-5.013,7.055-7.736,12.068-6.083C18.443,33.875,21.166,39.277,19.514,44.289 M17.318,43.564c-1.253,3.801-5.35,5.865-9.15,4.612c-3.797-1.253-5.863-5.35-4.609-9.148c1.254-3.8,5.349-5.865,9.148-4.612C16.506,35.67,18.57,39.766,17.318,43.564 M12.709,42.044c-0.412,1.254-1.765,1.936-3.02,1.523c-1.253-0.414-1.934-1.765-1.52-3.019c0.412-1.253,1.764-1.936,3.017-1.521C12.44,39.441,13.121,40.792,12.709,42.044"/>
<path fill="#58595B" d="M19.266,34.944c2.242,3.113,2.33,7.115,0.57,10.255l45.249-43.24L9.721,31.148C13.256,30.475,17.023,31.828,19.266,34.944"/>
<path fill="#FFFFFF" fill-opacity="0.8" d="M17.516,29.352c2.243,0.335,3.028,2.134,3.028,2.134L57.891,6.807L17.516,29.352z"/>
</g>
</svg>
The needle is now horizontal, and positioned at (0,0).
We can now integrate it into the previous solution:
let METER_DIVISIONS = 10;
let METER_DIVISIONS_GAP = 4;
// Initialise meter
let meterDivisionsElem = document.getElementById("meter-divisions");
// Calculate size of each meter division
let totalLen = meterDivisionsElem.getAttribute("r") * Math.PI;
let numGaps = METER_DIVISIONS - 1;
let divLen = (totalLen - METER_DIVISIONS_GAP * numGaps) / METER_DIVISIONS;
// Set meter divisions dash pattern
let pat = divLen + ' ' + METER_DIVISIONS_GAP + ' ';
meterDivisionsElem.setAttribute("stroke-dasharray", pat.repeat(numGaps) + ' ' + divLen + ' ' + totalLen);
// The slider form element
let sliderElem = document.getElementById("slider");
// The slider label element
let sliderLabelElem = document.getElementById("lbl");
// The needle element
let needleElem = document.getElementById("needle");
// The black bar element
let blackBarElem = document.getElementById("black-bar");
let blackBarLen = blackBarElem.getAttribute("r") * Math.PI;
// The meter colours element
let meterColoursElem = document.getElementById("meter-colours");
function setMeterTo(value)
{
// Update slider label
sliderLabelElem.textContent = value + '%';
// Update needle position
let rotation = value * 180 / 100;
needleElem.setAttribute("transform", "rotate(" + (-rotation) + ")");
// Update black bar length
let barLen = value * blackBarLen / 100;
blackBarElem.setAttribute("stroke-dasharray", barLen + ' ' + (2 * blackBarLen));
// Update coloured division section of the meter
meterColoursElem.setAttribute("transform", "rotate(" + rotation + ")");
}
// Add an input change handler to the slider
sliderElem.addEventListener("input", function(evt) {
setMeterTo(evt.target.value);
});
// Initialise meter to start value
setMeterTo(25);
#wrapper {
width: 600px;
}
#slider {
width: 100%;
}
#needle {
stroke-linecap: round;
}
<div id="wrapper">
<svg id="meter" viewBox="0 0 200 110">
<defs>
<circle id="meter-divisions" r="90" stroke-width="20" stroke-dasharray="282.7"/>
<mask id="meter-divisions-mask">
<use xlink:href="#meter-divisions" stroke="white"/>
</mask>
</defs>
<g transform="translate(100,100)">
<g transform="scale(1,-1)" fill="none">
<!-- The grey meter divisions -->
<use xlink:href="#meter-divisions" stroke="lightgrey"/>
<!-- The inner semicircular black bar -->
<circle id="black-bar" r="74" stroke="black" stroke-width="4" stroke-dasharray="232.5"/>
<!-- The coloured form of the ,meter divisions that gets rotated into view with the needle.
It is initially off screen but gets revealed as it rotates. It is masked by using
a shape matching the gray divisions -->
<g mask="url(#meter-divisions-mask">
<rect id="meter-colours" x="-100" y="-100" width="200" height="100" fill="red"/>
</g>
</g>
<!-- the needle -->
<g id="needle">
<g transform="rotate(35.8) translate(-10.44, -41.3)">
<path fill="#58595B" fill-rule="evenodd" d="M19.514,44.289c-1.652,5.013-7.056,7.736-12.066,6.083c-5.014-1.653-7.736-7.056-6.084-12.067c1.652-5.013,7.055-7.736,12.068-6.083C18.443,33.875,21.166,39.277,19.514,44.289 M17.318,43.564c-1.253,3.801-5.35,5.865-9.15,4.612c-3.797-1.253-5.863-5.35-4.609-9.148c1.254-3.8,5.349-5.865,9.148-4.612C16.506,35.67,18.57,39.766,17.318,43.564 M12.709,42.044c-0.412,1.254-1.765,1.936-3.02,1.523c-1.253-0.414-1.934-1.765-1.52-3.019c0.412-1.253,1.764-1.936,3.017-1.521C12.44,39.441,13.121,40.792,12.709,42.044"/>
<path fill="#58595B" d="M19.266,34.944c2.242,3.113,2.33,7.115,0.57,10.255l45.249-43.24L9.721,31.148C13.256,30.475,17.023,31.828,19.266,34.944"/>
<path fill="#FFFFFF" fill-opacity="0.8" d="M17.516,29.352c2.243,0.335,3.028,2.134,3.028,2.134L57.891,6.807L17.516,29.352z"/>
</g>
</g>
</g>
</svg>
<input id="slider" type="range" min="25" max="100" step="25" value="25" />
<label id="lbl" id="value" for="">0%</label>
</div>
My approach here is a pure CSS one ,i didn't use SVG and implementing JS code in this case is lot easier.
Output
var black = document.getElementsByClassName('black')[0];
var gradient = document.getElementsByClassName('gradient')[0]
var tick = document.getElementsByClassName('tick')[0];
var m = document.getElementById('m');
m.addEventListener('input', function() {
black.style.transform = gradient.style.transform = tick.style.transform = "translate(-50%,-50%)rotateZ(-" + (180 / 100) * m.value + "deg)"
});
* {
margin: 0px;
padding: 0px;
font-family: "arial";
}
.gauge_main,
.white,
.black,
.tick,
.gradient,
.chamber,
.meter {
position: absolute;
top: 50%;
left: 50%;
height: 280px;
width: 280px;
transform: translate(-50%, -50%);
transition: 0.4s;
}
.meter {
background-color: white;
height: 281px;
width: 281px;
border-radius: 50%;
clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%);
z-index: 1000;
}
.tick,
.chamber {
width: 160px;
height: 5px;
background: linear-gradient(to right, white 50%, black 50%);
z-index: 110;
transform-origin: 50%;
}
.tick {
z-index: 1001;
}
.chamber {
left: 50%;
background: white;
width: 280px;
height: 5px;
transform-origin: 50%;
transform: translate(-50%, -50%)rotateZ(calc(var(--i)*-20deg));
z-index: 20;
}
.white,
.black,
.gradient {
position: absolute;
background-color: black;
border-radius: 50%;
}
.white {
height: 180px;
width: 180px;
background-color: white;
z-index: 30;
}
.gradient {
height: 280px;
width: 280px;
background: linear-gradient(0deg, rgba(29, 216, 255, 1) 0%, rgba(4, 106, 255, 1) 50%, rgba(208, 212, 255, 1) 50%);
}
.black {
height: 200px;
width: 200px;
background: linear-gradient(to top, black 50%, rgba(208, 212, 255, 1) 50%);
box-shadow: 0px 0px 0px 5px white;
z-index: 25;
}
#keyframes load {
from {
transform: translate(-50%, -50%)rotateZ(0deg);
}
to {
transform: translate(-50%, -50%)rotateZ(-180deg);
}
}
input {
position: absolute;
top: 50%;
left: 50%;
width: 280px;
transform: translate(-50%, 50%);
}
<div class="gauge_main">
<div class="gradient"></div>
<div class="white"></div>
<div class="black"></div>
<div class="tick"></div>
<div style="--i:1" class="chamber"></div>
<div style="--i:2" class="chamber"></div>
<div style="--i:3" class="chamber"></div>
<div style="--i:4" class="chamber"></div>
<div style="--i:5" class="chamber"></div>
<div style="--i:6" class="chamber"></div>
<div style="--i:7" class="chamber"></div>
<div style="--i:8" class="chamber"></div>
<div style="--i:9" class="chamber"></div>
<div class="meter"></div>
</div>
<input type="range" id="m" name="meter" min="0" max="100" value="0">

Responsive hero image as background

Iam trying to get this codepen interactive SVG mask as one of my pages in a website. But what i want to do is put the whole thing in a 540px height box and the width to be 100% ( stretched to browser edges maintaining the width and height ratio aspect. ). But i cant seem to figure out a way to do this. thanks in advance.
Below are the HTML,CSS,JS files from codepen.
console.clear();
var svg = document.querySelector("#demo");
var tl = new TimelineMax({onUpdate:onUpdate});
var pt = svg.createSVGPoint();
var data = document.querySelector(".tlProgress");
var counter = document.querySelector("#counter");
var ratio = 0.5625;
TweenMax.set("#instructions, #dial", {xPercent: -50});
TweenMax.set("#progressRing", {drawSVG:0});
tl.to("#masker", 2, {attr:{r:2400}, ease:Power2.easeIn});
tl.reversed(true);
function mouseHandler() {
tl.reversed(!tl.reversed());
}
function getPoint(evt){
pt.x = evt.clientX;
pt.y = evt.clientY;
return pt.matrixTransform(svg.getScreenCTM().inverse());
}
function mouseMove(evt) {
var newPoint = getPoint(evt);
TweenMax.set("#dot", {attr:{cx:newPoint.x, cy:newPoint.y}});
TweenMax.to("#ring, #masker", 0.88, {attr:{cx:newPoint.x, cy:newPoint.y}, ease:Power2.easeOut});
}
function onUpdate() {
var prog = (tl.progress() * 100);
TweenMax.set("#progressRing", {drawSVG:prog + "%"});
counter.textContent = prog.toFixed();
}
function newSize() {
var w = window.innerWidth ;
var h = window.innerHeight;
if (w > h * (16/9) ) {
TweenMax.set("#demo", { attr: { width: w, height: w * ratio } });
} else {
TweenMax.set("#demo", { attr: { width: h / ratio, height: h } });
}
var data = svg.getBoundingClientRect();
TweenMax.set("#demo", {x:w/2 - data.width/2});
TweenMax.set("#demo", {y:h/2 - data.height/2});
}
window.addEventListener("mousedown", mouseHandler);
window.addEventListener("mouseup", mouseHandler);
window.addEventListener("mousemove", mouseMove);
newSize();
window.addEventListener("resize", newSize);
body {
padding: 0;
margin: 0;
font-family: "Signika", sans-serif;
background: #262626;
height: 100vh;
width: 100%;
overflow: hidden;
color: white;
}
p {
margin: 0;
text-align: center;
white-space: nowrap;
}
* {
box-sizing: border-box;
}
#demo {
cursor: none;
position: absolute;
}
#instructions {
position: absolute;
padding: 12px;
bottom: 20px;
background: rgba(0, 0, 0, 0.75);
left: 50%;
cursor: none;
padding-top: 100px;
user-select: none;
border-radius: 4px;
}
#dial {
position: absolute;
top: 0;
left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg id="demo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="1600" height="900" viewBox="0 0 1600 900">
<defs>
<radialGradient id="maskGradient">
<stop offset="50%" stop-color="#fff"/>
<stop offset="100%" stop-color="#000"/>
</radialGradient>
<mask id="theMask">
<circle id="masker" r="150" fill="url(#maskGradient)" cx="800" cy="450" />
</mask>
</defs>
<image id="lines" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/314556/roomSketch.jpg" x="0" y="0" width="1600" height="900" />
<g id="maskReveal" mask="url(#theMask)" >
<image id="regular" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/314556/roomColor.jpg" x="0" y="0" width="1600" height="900" />
</g>
<circle id="ring" r="20" fill="none" stroke="#dc143c" stroke-width="2" cx="800" cy="450" />
<circle id="dot" r="4" fill="#dc143c" cx="800" cy="450" />
</svg>
<div id="instructions">
<svg id="dial" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
<path id="progressRing" d="M50,10A40,40,0,1,1,10,50,40,40,0,0,1,50,10Z" fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="6"/>
<circle r="43" fill="none" stroke="#fff" cx="50" cy="50" stroke-width="2" opacity="0.5" />
<circle r="37" fill="none" stroke="#fff" cx="50" cy="50" stroke-width="2" opacity="0.5"/>
<text transform="translate(55 56)" text-anchor="start" font-size="20" fill="#fff">%</text>
<text id="counter" transform="translate(55 56)" text-anchor="end" font-size="20" fill="#fff">0</text>
</svg>
<p>Hover mouse to move mask around.</p>
<p>Hold & release mouse button to expand & contract mask.</p>
</div>
Is this what u want?
console.clear();
var svg = document.querySelector("#demo");
var tl = new TimelineMax({
onUpdate: onUpdate
});
var pt = svg.createSVGPoint();
var data = document.querySelector(".tlProgress");
var counter = document.querySelector("#counter");
var ratio = 0.5625;
TweenMax.set("#instructions, #dial", {
xPercent: -50
});
TweenMax.set("#progressRing", {
drawSVG: 0
});
tl.to("#masker", 2, {
attr: {
r: 2400
},
ease: Power2.easeIn
});
tl.reversed(true);
function mouseHandler() {
tl.reversed(!tl.reversed());
}
function getPoint(evt) {
pt.x = evt.clientX;
pt.y = evt.clientY;
return pt.matrixTransform(svg.getScreenCTM().inverse());
}
function mouseMove(evt) {
var newPoint = getPoint(evt);
TweenMax.set("#dot", {
attr: {
cx: newPoint.x,
cy: newPoint.y
}
});
TweenMax.to("#ring, #masker", 0.88, {
attr: {
cx: newPoint.x,
cy: newPoint.y
},
ease: Power2.easeOut
});
}
function onUpdate() {
var prog = (tl.progress() * 100);
TweenMax.set("#progressRing", {
drawSVG: prog + "%"
});
counter.textContent = prog.toFixed();
}
function newSize() {
var w = window.innerWidth;
var h = window.innerHeight;
if (w > h * (16 / 9)) {
TweenMax.set("#demo", {
attr: {
width: w,
height: w * ratio
}
});
} else {
TweenMax.set("#demo", {
attr: {
width: h / ratio,
height: h
}
});
}
var data = svg.getBoundingClientRect();
TweenMax.set("#demo", {
x: w / 2 - data.width / 2
});
TweenMax.set("#demo", {
y: h / 2 - data.height / 2
});
}
window.addEventListener("mousedown", mouseHandler);
window.addEventListener("mouseup", mouseHandler);
window.addEventListener("mousemove", mouseMove);
newSize();
window.addEventListener("resize", newSize);
body {
padding: 0;
margin: 0;
font-family: "Signika", sans-serif;
background: #262626;
height: 100vh;
width: 100%;
overflow: hidden;
color: white;
}
p {
margin: 0;
text-align: center;
white-space: nowrap;
}
* {
box-sizing: border-box;
}
#demo {
cursor: none;
position: absolute;
width: 100%;
height: 540px;
transform: matrix(2, 0, 0, 2, 0, 0);
}
#instructions {
position: absolute;
padding: 12px;
bottom: 20px;
background: rgba(0, 0, 0, 0.75);
left: 50%;
transform: translateX(-50%);
cursor: none;
padding-top: 100px;
user-select: none;
border-radius: 4px;
}
#dial {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
}
.main {
position: relative;
height: 540px;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
<svg id="demo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="1600" height="900" viewBox="0 0 1600 900">
<defs>
<radialGradient id="maskGradient">
<stop offset="50%" stop-color="#fff"/>
<stop offset="100%" stop-color="#000"/>
</radialGradient>
<mask id="theMask">
<circle id="masker" r="150" fill="url(#maskGradient)" cx="800" cy="450" />
</mask>
</defs>
<image id="lines" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/314556/roomSketch.jpg" x="0" y="0" width="1600" height="900" />
<g id="maskReveal" mask="url(#theMask)" >
<image id="regular" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/314556/roomColor.jpg" x="0" y="0" width="1600" height="900" />
</g>
<circle id="ring" r="20" fill="none" stroke="#dc143c" stroke-width="2" cx="800" cy="450" />
<circle id="dot" r="4" fill="#dc143c" cx="800" cy="450" />
</svg>
<div id="instructions">
<svg id="dial" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
<path id="progressRing" d="M50,10A40,40,0,1,1,10,50,40,40,0,0,1,50,10Z" fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="6"/>
<circle r="43" fill="none" stroke="#fff" cx="50" cy="50" stroke-width="2" opacity="0.5" />
<circle r="37" fill="none" stroke="#fff" cx="50" cy="50" stroke-width="2" opacity="0.5"/>
<text transform="translate(55 56)" text-anchor="start" font-size="20" fill="#fff">%</text>
<text id="counter" transform="translate(55 56)" text-anchor="end" font-size="20" fill="#fff">0</text>
</svg>
<p>Hover mouse to move mask around.</p>
<p>Hold & release mouse button to expand & contract mask.</p>
</div>
</div>

Invisble gwt chart when placed into an HTMLPanel

I'm experiencing a very weird issue and I honestly don't know what is going on...
I'm trying to load a dummy chart in a GWT project. While this works perfectly fine:
/**
* This is the entry point method.
*/
public void onModuleLoad() {
Window.enableScrolling(false);
Window.setMargin("0px");
RootLayoutPanel.get().add(getSimpleLayoutPanel());
// Create the API Loader
ChartLoader chartLoader = new ChartLoader(ChartPackage.CORECHART);
chartLoader.loadApi(new Runnable() {
#Override
public void run() {
getSimpleLayoutPanel().setWidget(getPieChart());
drawPieChart();
}
});
}
private SimpleLayoutPanel getSimpleLayoutPanel() {
if (layoutPanel == null) {
layoutPanel = new SimpleLayoutPanel();
}
return layoutPanel;
}
private Widget getPieChart() {
if (pieChart == null) {
pieChart = new PieChart();
}
return pieChart;
}
private void drawPieChart() {
// Prepare the data
DataTable dataTable = DataTable.create();
dataTable.addColumn(ColumnType.STRING, "Name");
dataTable.addColumn(ColumnType.NUMBER, "Donuts eaten");
dataTable.addRows(4);
dataTable.setValue(0, 0, "Michael");
dataTable.setValue(1, 0, "Elisa");
dataTable.setValue(2, 0, "Robert");
dataTable.setValue(3, 0, "John");
dataTable.setValue(0, 1, 5);
dataTable.setValue(1, 1, 7);
dataTable.setValue(2, 1, 3);
dataTable.setValue(3, 1, 2);
// Draw the chart
pieChart.draw(dataTable);
}
And I get the expected output:
When I try to place the chart inside a HTMLPanel:
/**
* This is the entry point method.
*/
public void onModuleLoad() {
Window.enableScrolling(false);
Window.setMargin("0px");
HTMLPanel html = new HTMLPanel("<div id='container'></div>");
html.add(getSimpleLayoutPanel(), "container");
RootPanel.get().add(html);
html.setVisible(true);
// RootLayoutPanel.get().add(getSimpleLayoutPanel());
// Create the API Loader
ChartLoader chartLoader = new ChartLoader(ChartPackage.CORECHART);
chartLoader.loadApi(new Runnable() {
#Override
public void run() {
getSimpleLayoutPanel().setWidget(getPieChart());
drawPieChart();
getSimpleLayoutPanel().setVisible(true);
getSimpleLayoutPanel().getWidget().setVisible(true);
}
});
}
Results in a white screen, weird enough, if I inspect the DOM with Firebug, I can see the "chart" there...I mean, the svg file that composes the chart:
<div aria-hidden="false"><div id="container"><div aria-hidden="false" style="position: relative;"><div aria-hidden="true" style="position: absolute; z-index: -32767; top: -20ex; width: 10em; height: 10ex; visibility: hidden;"> </div><div style="position: absolute; overflow: hidden; left: 0px; top: 0px; width: 100%; height: 100%;"><div aria-hidden="false" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px;"><div dir="ltr" style="position: relative; width: 1525px; height: 200px;"><div style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;"><svg style="overflow: hidden;" height="200" width="1525"><defs id="defs"></defs><rect fill="#ffffff" stroke-width="0" stroke="none" height="200" width="1525" y="0" x="0"></rect><g><rect fill="#ffffff" fill-opacity="0" stroke-width="0" stroke="none" height="87" width="453" y="38" x="934"></rect><g><rect fill="#ffffff" fill-opacity="0" stroke-width="0" stroke="none" height="15" width="453" y="38" x="934"></rect><g><text fill="#222222" stroke-width="0" stroke="none" font-size="15" font-family="Arial" y="50.75" x="955" text-anchor="start">Michael</text></g><rect fill="#3366cc" stroke-width="0" stroke="none" height="15" width="15" y="38" x="934"></rect></g><g><rect fill="#ffffff" fill-opacity="0" stroke-width="0" stroke="none" height="15" width="453" y="62" x="934"></rect><g><text fill="#222222" stroke-width="0" stroke="none" font-size="15" font-family="Arial" y="74.75" x="955" text-anchor="start">Elisa</text></g><rect fill="#dc3912" stroke-width="0" stroke="none" height="15" width="15" y="62" x="934"></rect></g><g><rect fill="#ffffff" fill-opacity="0" stroke-width="0" stroke="none" height="15" width="453" y="86" x="934"></rect><g><text fill="#222222" stroke-width="0" stroke="none" font-size="15" font-family="Arial" y="98.75" x="955" text-anchor="start">Robert</text></g><rect fill="#ff9900" stroke-width="0" stroke="none" height="15" width="15" y="86" x="934"></rect></g><g><rect fill="#ffffff" fill-opacity="0" stroke-width="0" stroke="none" height="15" width="453" y="110" x="934"></rect><g><text fill="#222222" stroke-width="0" stroke="none" font-size="15" font-family="Arial" y="122.75" x="955" text-anchor="start">John</text></g><rect fill="#109618" stroke-width="0" stroke="none" height="15" width="15" y="110" x="934"></rect></g></g><g><path fill="#3366cc" stroke-width="1" stroke="#ffffff" d="M525,100L525,38A62,62,0,0,1,584.6331898767148,116.96710538446915L525,100A0,0,0,0,0,525,100"></path></g><g><path fill="#109618" stroke-width="1" stroke="#ffffff" d="M525,100L483.23087009391344,54.181447132319164A62,62,0,0,1,525,38L525,100A0,0,0,0,0,525,100"></path></g><g><path fill="#ff9900" stroke-width="1" stroke="#ffffff" d="M525,100L465.36681012328523,116.96710538446915A62,62,0,0,1,483.2308700939135,54.18144713231911L525,100A0,0,0,0,0,525,100"></path></g><g><path fill="#dc3912" stroke-width="1" stroke="#ffffff" d="M525,100L584.6331898767148,116.96710538446915A62,62,0,0,1,465.36681012328523,116.96710538446918L525,100A0,0,0,0,0,525,100"></path><text fill="#ffffff" stroke-width="0" stroke="none" font-size="15" font-family="Arial" y="140.04361653961504" x="504.5" text-anchor="start">41.2%</text></g><g></g></svg></div></div><div style="display: none; position: absolute; top: 210px; left: 1535px; white-space: nowrap; font-family: Arial; font-size: 15px;">John</div><div></div></div></div></div></div></div>
Now as you can see, for some reason is set to "hidden"....any idea why???? Going nuts with this!
Thanks,
Alex
Try setting an explicit width and height to your HTMLPanel and to your SimpleLayoutPanel. Since HTMLPanel does not implement RequiresResize and ProvidesResize, you need to set an explicit size.
For resizing to work properly, you must have "an unbroken hierarchy between all widgets that implement RequiresResize and the RootLayoutPanel, which listens for any changes (such as the browser window resizing) that could affect the size of widgets in the hierarchy".
For more info see: http://www.gwtproject.org/doc/latest/DevGuideUiPanels.html#Resize

Categories

Resources