How to toggle style of element both on hover and on click? - javascript

I have 4 SVG circles and I want to toggle their style on hover and on click. I only want one circle at a time to have the style when clicked, i.e the style is removed from one circle when another one is clicked.
The hover works using CSS, but my JavaScript isn't quite correct.
It removes the style from one circle when another one is clicked but doesn't let you toggle the style class from the active target circle. Also how can I remove the style from a circle if anything outside the SVG circles is clicked?
var circles = document.querySelectorAll('.svgcircle')
circles = Array.prototype.slice.call(circles);
for (i = 0; i < circles.length; i++) {
(function(index) {
circles[index].addEventListener("click", function() {
var targetcircle = event.target;
for (var j = 0; j < circles.length; j++) {
circles[j].classList.remove("circleTarget");
}
targetcircle.classList.toggle("circleTarget");
})
})(i);
}
html,
body {
height: 100%;
width: 100%;
overflow: hidden;
}
svg {
position: absolute;
top: 35%;
left: 50%;
margin-left: -200px;
padding: 10px;
}
svg circle {
fill: #B5EF8A;
cursor: pointer;
stroke: #56CBF9;
stroke-width: 2px;
}
svg circle:hover {
fill: #fff;
stroke: #56CBF9;
}
.circleTarget {
fill: #fff;
stroke: #56CBF9;
}
<svg height="100" width="400" id="svg">
<circle class="svgcircle" cx="50" cy="50" r="40" />
<circle class="svgcircle" cx="150" cy="50" r="40" />
<circle class="svgcircle" cx="250" cy="50" r="40" />
<circle class="svgcircle" cx="350" cy="50" r="40" />
</svg>
Many Thanks.

Your code is clearing out the use of classes on all your circles and then toggling the class on the one that got clicked, but that will always lead to the clicked circle becoming active (because you just cleared out all the classes). You'll need to check to see if the circle being clicked was already active and act based on that.
By using event delegation, you can make the code much simpler. You won't have to set up event handlers on each circle and you can easily check for clicks that were not on circles. This is called event delegation.
Also, since you are converting your circles into an Array, use the Array.forEach() method to loop, which is much simpler than managing loop indexes.
See comments inline:
var circles = Array.prototype.slice.call(document.querySelectorAll('.svgcircle'));
// Setting the event listener on the document, kills two birds
// with one stone. It removes the need to set click event handlers
// on each circle and it allows for easy checking to see if you
// clicked on anything other than a circle.
document.addEventListener("click", function(evt){
// Check to see if the clicked element was one of the circles:
if(evt.target.classList.contains("svgcircle")){
// It was, so capture whether the clicked circle is active already
let active = evt.target.classList.contains("circleTarget");
removeClass(); // Reset the class usage on all the circles
// If the clicked circle was active, deactivate it.
// Otherwise, activate it:
if(active){
evt.target.classList.remove("circleTarget");
} else {
evt.target.classList.add("circleTarget");
}
} else {
// It wasn't, so clear all the styling from all the circles
removeClass();
}
});
function removeClass(){
// Loop over all the circles and remove the target class
circles.forEach(function(cir){
cir.classList.remove("circleTarget");
});
}
html,
body {
height: 100%;
width: 100%;
overflow: hidden;
}
svg {
position: absolute;
top: 35%;
left: 50%;
margin-left: -200px;
padding: 10px;
}
svg circle {
fill: #B5EF8A;
cursor: pointer;
stroke: #56CBF9;
stroke-width: 2px;
}
svg circle:hover {
fill: #fff;
stroke: #56CBF9;
}
.circleTarget {
fill: #fff;
stroke: #56CBF9;
}
<svg height="100" width="400" id="svg">
<circle class="svgcircle" cx="50" cy="50" r="40" />
<circle class="svgcircle" cx="150" cy="50" r="40" />
<circle class="svgcircle" cx="250" cy="50" r="40" />
<circle class="svgcircle" cx="350" cy="50" r="40" />
</svg>

This will perform how you expect it to:
let circles = Array.from(document.querySelectorAll('.svgcircle'));
circles.forEach(circle => {
circle.addEventListener("click", ({target}) => {
circles.forEach(c => target !== c && c.classList.remove("circleTarget"));
target.classList.toggle("circleTarget");
})
});
// Remove class if anything else is clicked
document.body.addEventListener('click', ({target}) =>
!Array.from(target.classList).includes('svgcircle')
&& circles.forEach(c => c.classList.remove("circleTarget")));
html,
body {
height: 100%;
width: 100%;
overflow: hidden;
}
svg {
position: absolute;
top: 35%;
left: 50%;
margin-left: -200px;
padding: 10px;
}
svg circle {
fill: #B5EF8A;
cursor: pointer;
stroke: #56CBF9;
stroke-width: 2px;
}
svg circle:hover {
fill: #fff;
stroke: #56CBF9;
}
.circleTarget {
fill: #fff;
stroke: #56CBF9;
}
<svg height="100" width="400" id="svg">
<circle class="svgcircle" cx="50" cy="50" r="40" />
<circle class="svgcircle" cx="150" cy="50" r="40" />
<circle class="svgcircle" cx="250" cy="50" r="40" />
<circle class="svgcircle" cx="350" cy="50" r="40" />
</svg>
Hope this helps,

Related

cannot make 3/4 circle and nest it with progress bar, far now only full circle and progress bar

i am going to do some circular charts and now i have full circle with progress bar but dont know why i cannot make it 3/4circle and progress bar.
code:
<!-- The HTML structure for the progress bar -->
<div class="progress-container">
<svg class="progress-bar" width="100%" height="100%" viewBox="0 0 42 42">
<circle class="progress-ring" cx="21" cy="21" r="15.91549430918954" fill="transparent"/>
<circle class="progress-value" cx="21" cy="21" r="15.91549430918954" fill="transparent"/>
</svg>
<div class="progress-text">0%</div>
</div>
/* The CSS styles for the progress bar */
.progress-container {
position: relative;
width: 200px;
height: 200px;
}
.progress-bar {
position: absolute;
top: 0;
left: 0;
}
.progress-ring {
stroke: #ddd;
stroke-width: 2;
fill: transparent;
}
.progress-value {
stroke: #3498db;
stroke-width: 2;
fill: transparent;
stroke-dasharray: 0 100;
transition: stroke-dasharray 0.3s;
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 18px;
font-weight: bold;
text-align: center;
color: #3498db;
}
// The JavaScript code to update the progress bar
const progressContainer = document.querySelector('.progress-container');
const progressBar = progressContainer.querySelector('.progress-bar');
const progressValue = progressBar.querySelector('.progress-value');
const progressText = progressContainer.querySelector('.progress-text');
const updateProgress = (value) => {
// Update the value of the progress bar
progressValue.style.strokeDasharray = `${value} 100`;
// Update the text inside the progress bar
progressText.textContent = `${value}%`;
}
updateProgress(50); // Set the progress bar to 50%
This is how it looks like:
but i want it to looks some similar to:
If someone know how to rebuild my code, please help me out.
You would need to draw the 3/4 arc segment with svg path,
<svg class="progress-bar" width="100%" height="100%" viewBox="0 0 42 42">
<!--
<circle class="progress-ring" cx="21" cy="21" r="15.91549430918954" fill="transparent"/>
<circle class="progress-value" cx="21" cy="21" r="15.91549430918954" fill="transparent"/>
-->
<path class="progress-ring" d="M21 21 m-11.254 11.254 a 15.91549430918954 15.91549430918954 135 1 1 22.508 0" fill="transparent" stroke-linecap="round"/>
<path class="progress-value" d="M21 21 m-11.254 11.254 a 15.91549430918954 15.91549430918954 135 1 1 22.508 0" fill="transparent" stroke-linecap="round"/>
</svg>
and adjust the length accordingly.
//progressValue.style.strokeDasharray = `${value} 100`;
progressValue.style.strokeDasharray = `${value * 3 / 4} 75`;

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!

equivalent in JS of the resize css applied to an SVG element

I recently discover the CSS resize:
`
div {
resize: both;
overflow: auto;
}
`
There is also a polyFill, but none of them won't work for a SVG element :/
Is it possible at least ?
Starting from your code and #ChrisG's comment, you might do the following.
When one clicks on svg, wrap this svg into a resizable div and set the svg width and height attributes to '100%' so the svg would get the wrapper's size.
Then, when one resizes the div, the svg would be resized as well.
When one clicks out of the div, set the svg width and height attributes explicitly and remove the div.
See the snippet below:
window.addEventListener('DOMContentLoaded', () => {
document.addEventListener('click', (e) => {
var r = document.getElementById('r');
if (r && r != e.target) {
var svg = r.querySelector('svg');
svg.setAttribute('width', r.offsetWidth + 'px');
svg.setAttribute('height', r.offsetHeight + 'px');
r.replaceWith(svg);
}
var svg = e.target;
while (!!svg && svg.nodeName != 'svg')
svg = svg.parentElement;
if (!svg) return;
var r = document.createElement('div');
r.id = 'r';
r.style.width = svg.width.baseVal.valueAsString;
r.style.height = svg.height.baseVal.valueAsString;
svg.setAttribute('width', '100%');
svg.setAttribute('height', '100%');
svg.parentElement.insertBefore(r, svg);
r.appendChild(svg.parentElement.removeChild(svg));
});
});
svg {
background: #cef
}
#r {
display: inline-block;
box-sizing: border-box;
border: solid 1px;
resize: both;
overflow: hidden;
}
<svg width="100px" height="100px" viewBox="0 0 100 100">
<circle stroke="navy" stroke-width="5" fill="pink" cx="50" cy="50" r="40"/>
</svg>
<svg width="100px" height="100px" viewBox="0 0 100 100">
<circle stroke="green" stroke-width="5" fill="gold" cx="50" cy="50" r="40"/>
</svg>

Print SVG HTML with Javascript

I have an SVG element in Angular 2+ code.
I want to give the user the possibility to print out the following SVG element.
<div class="floor-plan" id="printSectionId2"
(drop)="onDrop($event)"
(dragover)="onDragOverOrEnter($event)"
(dragenter)="onDragOverOrEnter($event)">
<svg id="svgObject" [attr.width]="svgWidth + 'px'" [attr.height]="svgHeight + 'px'">
<ng-container *ngIf="floorPlan && floorPlan.layout">
<rect [attr.x]="floorPlan.x"
[attr.y]="floorPlan.y"
[attr.width]="floorPlan.width"
[attr.height]="floorPlan.height"
class="boundary">
</rect>
<ng-container *ngFor="let t of floorPlan.layout.tables; trackBy: trackByTables">
<g class="dining-table"
[attr.transform]="'translate(' + t.x + ' ' + t.y + ')'"
[class.assigned]="t.isOccupied"
[class.arrival]="t.isArrival"
[class.hasSpecialInformation]="t.hasSpecialInformation"
[class.hasOnlyBreakfast]="t.hasOnlyBreakfast">
<rect *ngIf="t.shape === 'rectangle'"
[attr.width]="t.width"
[attr.height]="t.height"
[attr.transform]="'rotate(' + t.rotation + ' ' + (t.width/2) + ' ' + (t.height/2) + ')'"
[attr.data-tableId]="t.id">
<title>Tisch {{t.number}}</title>
</rect>
<image *ngIf="t.isArrival" xlink:href="http://kommis.net/wp-content/uploads/2018/07/arrival-white.png" x="5" y="25" height="25px" width="25px" opacity="50"></image>
<text *ngIf="t.shape === 'rectangle'"
[attr.x]="t.width * 0.05"
dominant-baseline="hanging"
[attr.data-tableId]="t.id">
<tspan x="5" class="table-number">{{t.number}}</tspan>
<tspan x="5" dy="15" class="guest-info">{{t.guestInfo}}</tspan>
</text>
<ellipse *ngIf="t.shape === 'circle'"
[attr.rx]="t.width / 2"
[attr.ry]="t.height / 2"
[attr.data-tableId]="t.id">
<title>Tisch {{t.number}}</title>
</ellipse>
<text *ngIf="t.shape === 'circle'"
[attr.dy]="t.width / 2 * -0.5"
text-anchor="middle"
[attr.data-tableId]="t.id">
<tspan x="0" class="table-number">{{t.number}}</tspan>
<tspan x="0" dy="15" class="guest-info">{{t.guestInfo}}</tspan>
</text>
</g>
</ng-container>
</ng-container>
</svg>
</div>
Here the CSS:
.floor-plan {
background-color: #eaf3f3;
border-radius: 2px;
}
.floor-plan svg {
/* Is needed because svg is by default inline-block and thus
the wrapping div would get higher by some extra pixels.
See https://stackoverflow.com/questions/24626908/*/
display: block;
}
.floor-plan .boundary {
fill: transparent;
stroke: #0A7A74;
stroke-width: 2px;
}
.dining-table rect,
.dining-table ellipse {
fill: transparent;
stroke: #0A7A74;
stroke-width: 2px;
}
.dining-table.assigned rect,
.dining-table.assigned ellipse {
fill: #0a7a74;
}
.dining-table.assigned tspan {
fill: #ffffff;
}
.dining-table.hasSpecialInformation rect,
.dining-table.hasSpecialInformation ellipse {
stroke: red;
}
.dining-table.hasOnlyBreakfast rect,
.dining-table.hasOnlyBreakfast ellipse {
fill: #0d2f2e;
}
.dining-table image {
opacity: 0.5;
}
tspan.table-number {
fill: #666;
}
tspan.guest-info {
fill: #333;
font-weight: bolder;
}
The element looks like this on the screen:
I wanted to ask, what is the best way to let users print out this SVG graphic?
At the moment I am trying it with the following JS code:
printToCart2(svgObject: string) {
let popupWinindow;
let innerContents = document.getElementById(svgObject).innerHTML;
console.log(innerContents);
popupWinindow = window.open('', '_blank', 'width=1000,height=1000,scrollbars=no,menubar=no,toolbar=no,location=no,status=no,titlebar=no');
popupWinindow.document.open();
popupWinindow.document.write('<html><head><style></style></head><body onload="window.print()">' + innerContents + '</html>');
popupWinindow.document.close();
}
Which gives me, unfortunately, this black square:
Update
The answer given by #KoshVery gives me the desired result:
Update
In order to make the CSS work, I had to add it in the line Popupwindow.document.write() like so:
popupWinindow.document.write('<html><head><style>.floor-plan { background-color: #eaf3f3; border-radius: 2px; } .floor-plan svg { /* Is needed because svg is by default inline-block and thusthe wrapping div would get higher by some extra pixels.See https://stackoverflow.com/questions/24626908/*/ display: block; } .floor-plan .boundary { fill: transparent; stroke: #0A7A74; stroke-width: 2px; } .dining-table rect, .dining-table ellipse { fill: transparent; stroke: #0A7A74; stroke-width: 2px; } .dining-table.assigned rect, .dining-table.assigned ellipse { fill: #0a7a74; } .dining-table.assigned tspan { fill: #ffffff; } .dining-table.hasSpecialInformation rect, .dining-table.hasSpecialInformation ellipse { stroke: red; } .dining-table.hasOnlyBreakfast rect, .dining-table.hasOnlyBreakfast ellipse { fill: #0d2f2e; } .dining-table image { opacity: 0.5; } tspan.table-number { fill: #666; } tspan.guest-info {fill: #333; font-weight: bolder; } </style></head><body onload="window.print()">' + innerContents + '</html>');
Which ends up in the final result:
You have to get outerHTML of your svg:
let innerContents = document.getElementById(svgObject).outerHTML;
OR
If you've got innerHTML wrap it into <svg> here:
popupWinindow.document.write('<html><head><style></style></head><body onload="window.print()"><svg>' + innerContents + '</svg></html>');
Update
You might simplify your print flow like this:
<div>
<svg onclick="window.print(this)" id="svgObject" width="100" height="100">
<circle fill="pink" cx="50" cy="50" r="45"/>
</svg>
</div>

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>

Categories

Resources