I have a progress semicircle and try to work dynamically with vue 3. I want a help because I dont know why it doesnt work. I change the progress variable but nothing change. Need to calculate of stroke-dashoffset but the calculation is wrong?
<template>
<svg class="circle" viewBox="2 -2 28 36" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="gradient">
<stop class="stop1" offset="0%" />
<stop class="stop2" offset="100%" />
</linearGradient>
<circle class="circle-background" r="16" cx="16" cy="16" shape-rendering="geometricPrecision"></circle>
<circle class="circle-progress" style="stroke-dashoffset: 75;" r="16" cx="16" cy="16" shape-rendering="geometricPrecision"></circle>
</svg>
</template>
<script setup>
import { ref, computed } from 'vue'
const progress = ref(50);
const strokeDashoffset = computed(() => (100 - (100 - progress.value)));
const background = computed(() => {
const angle = 360 * progress.value;
return `
radial-gradient(white 50%, transparent 51%),
conic-gradient(transparent 0deg ${angle}deg, gainsboro ${angle}deg 360deg),
conic-gradient(orange 0deg, yellow 90deg, lightgreen 180deg, green)
`;
});
</script>
<style>
/* svg {
filter: drop-shadow(0 0 10px rgb(0 0 0 / 0.4));
} */
.circle {
width: 200px;
height: 200px;
transform: rotate(-225deg);
fill: none;
stroke: white;
stroke-dasharray: 75 100;
stroke-linecap: round;
}
.circle-background {
fill: none;
stroke: gainsboro;
stroke-width: 3px;
stroke-dasharray: 75 100;
stroke-linecap: round;
}
.circle-progress {
fill: none;
stroke-linecap: round;
stroke: url(#gradient);
stroke-dasharray: 75 100;
stroke-dashoffset: 20;
stroke-linecap: round;
stroke-width: 3px;
transition: stroke-dashoffset 1s ease-in-out;
}
.stop1 {
stop-color: #e66465;
}
.stop2 {
stop-color: #9198e5;
}
#progress-circle {
background: v-bind(background);
}
.circle-progress {
stroke-dashoffset: v-bind(strokeDashoffset);
}
</style>
I'm trying to create a circle that has small pins around (like seconds in a clock) to be like 60 of them (to count a minute)
here is a picture to describe what I mean
https://www.123rf.com/photo_91759207_stock-vector-close-up-of-digital-timer-showing-time-that-is-running-out-only-25-seconds-left-clock-on-vector-illu.html
I'm using React, javascript, css,
how can I make a loop that each pin would be stack to the circle 'corner' to fit his place ?
I'm having really hard time to find a way how to arrange them to look like it.
my final goal is to create a component that will receive a fill as prop that will represent the number of pins that needs to be in a different color, so I need a way to be able to control the background-color of each pin.
any advice would be awesome. thanks!
Do you mean something like the following? The code will create 60 "pins" for all tags with the class clock.
window.onload = function() {
var clocks = document.getElementsByClassName('clock'),
r = 0, i, j, d, clock;
for(j=0;j<clocks.length;j++) {
clock = clocks[j]
for(i=0;i<60;i++) {
d = document.createElement('div');
d.style.transform = "rotate("+ r +"deg)";
clock.appendChild(d);
r += 6;
}
}
}
.clock {
position:relative;
width:180px;
height:180px;
background:#eee;
}
.clock > div {
position:absolute;
margin-left:87px;
width:6px;
height:160px;
bottom:10px;
background: linear-gradient(to bottom, #491 16px, transparent 16px);
}
<div class="clock"></div>
Drawing the 'clock face' itself is easily done with SVG and stroke-dasharray.
Animating the clock can be done with an SVG mask, and some javascript to change the stroke-dashoffset.
An explanation of the maths for coming up with the values for the stroke-dasharray can be found in this answer.
const maskCircle = document.querySelector(".mask");
const clockText = document.querySelector(".clock-text");
const r = 50;
const c = 2 * r * Math.PI;
let secondsLeft = 60;
window.setInterval(function() {
if (secondsLeft > 0) {
secondsLeft--;
clockText.innerText = secondsLeft;
maskCircle.style.strokeDashoffset =
maskCircle.style.strokeDashoffset - c / 60 * -1;
} else {
clearInterval();
}
}, 1000);
body {
background: black;
}
.clock {
margin: 0 auto;
position: relative;
width: 200px;
height: 200px;
border-radius: 50%;
overflow: hidden;
}
.clock-face {
stroke-width: 15;
stroke-linecap: butt;
fill: transparent;
stroke-dasharray: 2.236 3;
}
.grey {
stroke: #333;
}
.white {
stroke: white;
}
.mask {
stroke-dasharray: 314.15 314.15;
stroke-dashoffset: 0;
}
.clock-text {
width: 100%;
margin: 0 auto;
color: white;
text-align: center;
position: absolute;
top: 50%;
font-size: 6em;
transform: translateY(-50%);
}
<div class="clock">
<svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="mask">
<circle class="clock-face white mask" cx="50" cy="50" r="50" transform="rotate(-90.5 50 50)" />
</mask>
</defs>
<circle class="clock-face grey" cx="50" cy="50" r="50" />
<circle class="clock-face white" cx="50" cy="50" r="50" mask="url(#mask)" />
</svg>
<div class="clock-text">60</div>
</div>
I am making a game in HTML/JavaScript and as part of this there is a "special ability" that can only be triggered every x seconds. I have created a GUI element that displays whether the ability is yet ready for use. Because I am using CSS animations, I want to check if, on a keypress, the element has finished animating (indicating that it is ready).
I want to do this in a simple if statement, rather than using addEventListener but I am not sure if this is possible.
My code so far is:
var keystate = {};
window.addEventListener("keydown", function(e) {
keystate[e.keycode || e.which] = true;
}, true);
window.addEventListener("keyup", function(e) {
keystate[e.keycode || e.which] = false;
}, true);
window.setInterval(function() {
if (keystate[87]) { //w key, THIS is where I want to check if the animation has completed as well
//do stuff
document.getElementById("circle_flash_glow").classList.add("circle_flash_use");
}
}, 16.666666666666667);
#svg_circle_loader {
position: absolute;
right: 0;
bottom: 0;
background: none;
border: none;
margin: none;
padding: none;
}
#circle_flash_loader {
fill: none;
stroke: #F00;
stroke-width: 10px;
stroke-dashoffset: 80;
animation-fill-mode: forwards;
}
.circle_loader_load {
animation: circle_flash_loading linear;
animation-duration: 2.5s;
}
#keyframes circle_flash_loading {
0% {
stroke-dasharray: 0, 314;
}
100% {
stroke-dasharray: 314, 0;
}
}
#circle_flash_glow {
fill: none;
stroke: #F00;
stroke-width: 0px;
animation-fill-mode: forwards;
opacity: 1;
}
.circle_flash_use {
animation: circle_flash_pulse 0.6s ease-out;
}
#keyframes circle_flash_pulse {
0% {
opacity: 1;
stroke-width: 0px;
}
100% {
opacity: 0;
stroke-width: 70px;
}
}
<svg id="svg_circle_loader" width="200" height="200">
<defs>
<filter id="f1" x="-50" y="-50" width="200" height="200">
<feGaussianBlur stdDeviation="5"></feGaussianBlur>
</filter>
</defs>
<circle cx="100" cy="100" r="50" id="circle_flash_glow" class="" filter="url(#f1)"></circle>
<circle cx="100" cy="100" r="50" id="circle_flash_loader" class="circle_loader_load"></circle>
</svg>
Add a variable to set the current state, and set it with setTimeout() for checking whether it is animating or not. also add window.onload to get its state by adding
window.onload=function(){
animating=true;
sts.value=animating;
window.setTimeout(function() {
animating=false;
sts.value=animating;
}, 2500);
};
where I am using 2500. because your css animation property has
2.5s=2500ms
var animating = false;
var keystate = {};
window.addEventListener("keydown", function(e) {
keystate[e.keycode || e.which] = true;
}, true);
window.addEventListener("keyup", function(e) {
keystate[e.keycode || e.which] = false;
}, true);
window.setInterval(function() {
if (keystate[87]) { //w key, THIS is where I want to check if the animation has completed as well
//do stuff
if (!animating) {
alert("animation finished");
document.getElementById("circle_flash_glow").classList.add("circle_flash_use");
}
}
}, 16.666666666666667);
window.onload = function() {
animating = true;
sts.value = animating;
window.setTimeout(function() {
animating = false;
sts.value = animating;
}, 2500);
};
#svg_circle_loader {
position: absolute;
right: 0;
bottom: 0;
background: none;
border: none;
margin: none;
padding: none;
}
#circle_flash_loader {
fill: none;
stroke: #F00;
stroke-width: 10px;
stroke-dashoffset: 80;
animation-fill-mode: forwards;
}
.circle_loader_load {
animation: circle_flash_loading linear;
animation-duration: 2.5s;
}
#keyframes circle_flash_loading {
0% {
stroke-dasharray: 0, 314;
}
100% {
stroke-dasharray: 314, 0;
}
}
#circle_flash_glow {
fill: none;
stroke: #F00;
stroke-width: 0px;
animation-fill-mode: forwards;
opacity: 1;
}
.circle_flash_use {
animation: circle_flash_pulse 0.6s ease-out;
}
#keyframes circle_flash_pulse {
0% {
opacity: 1;
stroke-width: 0px;
}
100% {
opacity: 0;
stroke-width: 70px;
}
}
<svg id="svg_circle_loader" width="200" height="200">
<defs>
<filter id="f1" x="-50" y="-50" width="200" height="200">
<feGaussianBlur stdDeviation="5"></feGaussianBlur>
</filter>
</defs>
<circle cx="100" cy="100" r="50" id="circle_flash_glow" class="" filter="url(#f1)"></circle>
<circle cx="100" cy="100" r="50" id="circle_flash_loader" class="circle_loader_load"></circle>
</svg>
<input id="sts" value="" />
Problem
Mobile only fires a mouseover event on touch start, I need to replicate the desktop mouseover event on mobile for all the elements that a user drags over.
Desired Behaviour
I need to detect which element is underneath a users finger after touch move (After touchstart but before touchend).
What actually happens on mobile
What I want to happen on mobile
What I've tried
$('polygon').mouseover(function() {
$(this).css({color:"red"});
})
polygon {
fill: currentColor;
}
polygon:hover {
color: red;
}
svg {
width:100vw;
height:100vh;
touch-action:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<meta charset="utf-8">
<title>SVG Test</title>
</head>
<body>
<svg id="s" version="1.1" width="100vw" height="100vh" xmlns="http://www.w3.org/2000/svg">
<polygon points="40,90 83.30127018922192,65 83.30127018922194,15.00000000000001 40.00000000000001,-10 -3.301270189221917,14.999999999999979 -3.3012701892219525,64.99999999999997 39.99999999999994,90" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="83.30127018922192,165 126.60254037844385,140 126.60254037844386,90.00000000000001 83.30127018922192,65 40.00000000000001,89.99999999999997 39.99999999999997,139.99999999999997 83.30127018922187,165" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="40,240 83.30127018922192,215 83.30127018922194,165 40.00000000000001,140 -3.301270189221917,164.99999999999997 -3.3012701892219525,214.99999999999997 39.99999999999994,240" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="83.30127018922192,315 126.60254037844385,290 126.60254037844386,240 83.30127018922192,215 40.00000000000001,239.99999999999997 39.99999999999997,289.99999999999994 83.30127018922187,315" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="126.60254037844386,90 169.9038105676658,65 169.9038105676658,15.00000000000001 126.60254037844386,-10 83.30127018922195,14.999999999999979 83.30127018922191,64.99999999999997 126.6025403784438,90" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="169.9038105676658,165 213.20508075688772,140 213.20508075688775,90.00000000000001 169.9038105676658,65 126.60254037844388,89.99999999999997 126.60254037844385,139.99999999999997 169.90381056766574,165" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="126.60254037844386,240 169.9038105676658,215 169.9038105676658,165 126.60254037844386,140 83.30127018922195,164.99999999999997 83.30127018922191,214.99999999999997 126.6025403784438,240" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="169.9038105676658,315 213.20508075688772,290 213.20508075688775,240 169.9038105676658,215 126.60254037844388,239.99999999999997 126.60254037844385,289.99999999999994 169.90381056766574,315" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="213.20508075688772,90 256.50635094610965,65 256.50635094610965,15.00000000000001 213.20508075688772,-10 169.9038105676658,14.999999999999979 169.90381056766577,64.99999999999997 213.20508075688767,90" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="256.50635094610965,165 299.8076211353316,140 299.8076211353316,90.00000000000001 256.50635094610965,65 213.20508075688772,89.99999999999997 213.2050807568877,139.99999999999997 256.5063509461096,165" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="213.20508075688772,240 256.50635094610965,215 256.50635094610965,165 213.20508075688772,140 169.9038105676658,164.99999999999997 169.90381056766577,214.99999999999997 213.20508075688767,240" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="256.50635094610965,315 299.8076211353316,290 299.8076211353316,240 256.50635094610965,215 213.20508075688772,239.99999999999997 213.2050807568877,289.99999999999994 256.5063509461096,315" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="299.8076211353316,90 343.10889132455355,65 343.10889132455355,15.00000000000001 299.8076211353316,-10 256.5063509461097,14.999999999999979 256.50635094610965,64.99999999999997 299.80762113533154,90" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="343.10889132455355,165 386.4101615137755,140 386.4101615137755,90.00000000000001 343.10889132455355,65 299.80762113533166,89.99999999999997 299.8076211353316,139.99999999999997 343.1088913245535,165" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="299.8076211353316,240 343.10889132455355,215 343.10889132455355,165 299.8076211353316,140 256.5063509461097,164.99999999999997 256.50635094610965,214.99999999999997 299.80762113533154,240" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon><polygon points="343.10889132455355,315 386.4101615137755,290 386.4101615137755,240 343.10889132455355,215 299.80762113533166,239.99999999999997 299.8076211353316,289.99999999999994 343.1088913245535,315" style="fill: currentcolor; stroke: black; stroke-width: 4px;"></polygon>
</svg>
</body>
</html>
This solution works for me with jQuery version 2.x and with including jQuery mobile.
JSFiddle: https://jsfiddle.net/1423g4o3/
HTML
<head>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
</head>
<body>
<svg id="s" version="1.1" width="100vw" height="100vh" xmlns="http://www.w3.org/2000/svg">
<!-- Your polygons here -->
</svg>
</body>
CSS
polygon {
color: #333;
}
polygon:hover {
color: red;
}
svg {
width: 100vw;
height: 100vh;
touch-action: none;
}
jQuery
$(document).on("pagecreate", "body", function() {
$("polygon")
.on("touchmove", function(e) {
var xPos = e.originalEvent.touches[0].pageX;
var yPos = e.originalEvent.touches[0].pageY;
$(document.elementFromPoint(xPos, yPos)).css('color', 'red');
}).end()
.on("touchend", function() {
$("polygon").css('color', '#333'); // Reset color when let go
});
});
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1069" height="575" xml:space="preserve">
<desc>Created with Fabric.js 1.4.13</desc>
<defs></defs>
<rect x="-20" y="-20" rx="10" ry="10" width="40" height="40" style="stroke: black; stroke-width: 0.3; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: DarkSalmon; fill-rule: nonzero; opacity: 1;"
transform="translate(461.15 451.15)" id="0"></rect>
<rect x="-20" y="-20" rx="10" ry="10" width="40" height="40" style="stroke: black; stroke-width: 0.3; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: DarkSalmon; fill-rule: nonzero; opacity: 1;" transform="translate(429.15 310.15)"
id="1"></rect>
<rect x="-20" y="-20" rx="10" ry="10" width="40" height="40" style="stroke: black; stroke-width: 0.3; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: DarkSalmon; fill-rule: nonzero; opacity: 1;" transform="translate(351.15 177.15)"
id="2"></rect>
this code has generated by fabricjs.1st added rect object is placed in first line in svg code.before genarate the svg code i change the positions of rect object by dragging.but the svg code has not changed acording to that.what i want to do is set the ID to every rect in svg code acording to displaying order.displaying order means top to bottom or bottom to top on screen.is it possible to do?thank you.
You can use this JS to give each 'rect' tag an id based on its location.
var SVG = document.getElementsByTagName('svg')[0];
var children = SVG.childNodes;
var ID = 0;
[].forEach.call(children, function (child) {
if(child.nodeType === 1 && child.tagName == "rect"){
child.setAttribute('id', ID);
ID++;
}
});
This will give the id 0 to the first 'rect' 1 to the next and so on.