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`;
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!
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>
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>
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>