I am trying to make a game like online bowling, and I cannot get the ball to launch correctly in js. when I click on it the ball goes the wrong way or off the screen. I have been trying to fix this for a while.
var xup
var yup
var x = 50;
var y = 95
document.onmouseup = function(e){
xup = -(e.pageX/screen.width)
yup = -(e.pageY/screen.height)
let d = setInterval(function(){
x += xup
y += yup
document.getElementById("player").innerHTML = '<circle id="ball" cx="'+x+'%" cy="'+y+'%" r="1%" fill="url(#ball)" />'
if(y<=20){
d=null
}
},10)
}
<svg style='position: absolute;left: 0;top: 1%;' width='100%' height='100%'>
<defs>
<radialGradient id="ball" cx="50%" cy="25%" r="50%" fx="50%" fy="50%">
<stop offset="0%" style="stop-color:#ff00ff;stop-opacity:1" />
<stop offset="100%" style="stop-color:#800080;stop-opacity:1" />
</radialGradient>
</defs>
<g id="player">
<circle id="ball" cx="50%" cy="95%" r="1%" fill="url(#ball)" />
</g>
</svg>
Below is the code that works great in Firefox, but any attempts to animate the linear gradient's offset attribute in Chrome ended in nothing.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="50%" height="50%" viewBox="0 0 900 900" >
<defs>
<linearGradient id="bgg" x1="0" y1="0" x2="900" y2="900" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="dodgerblue"/>
<stop offset="52%" stop-color="white">
<animate
attributeName="offset"
values="100%;0%;100%"
dur="4s"
repeatCount="indefinite">
</animate>
</stop>
<stop offset="100%" stop-color="gold">
<animate
attributeName="offset"
values="100%;50%;100%"
dur="4s"
repeatCount="indefinite">
</animate>
</stop>
</linearGradient>
</defs>
<rect x="50" y="50" width="50%" height="50%" rx="5%" fill="url(#bgg)" />
</svg>
Also tried using gradientUnits =" objectBoundingBox "
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="50%" height="50%" viewBox="0 0 900 900" >
<defs>
<linearGradient id="bgg" x1="0%" y1="0%" x2="100%" y2="100%" gradientUnits="objectBoundingBox">
<stop offset="0%" stop-color="dodgerblue"/>
<stop offset="52%" stop-color="white">
<animate
attributeName="offset"
values="100%;0%;100%"
dur="4s"
repeatCount="indefinite">
</animate>
</stop>
<stop offset="100%" stop-color="gold">
<animate
attributeName="offset"
values="100%;50%;100%"
dur="4s"
repeatCount="indefinite">
</animate>
</stop>
</linearGradient>
</defs>
<rect x="50" y="50" width="50%" height="50%" rx="5%" fill="url(#bgg)" />
</svg>
Any solution to this problem will do with: SVG,css, javascript
One solution to this would be using floating numbers instead of percentages, i.e values="1;0;1" instead of values="100%;0%;100%"
svg{border:1px solid}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="50%" height="50%" viewBox="0 0 900 900" >
<defs>
<linearGradient id="bgg" x1="0" y1="0" x2="50%" y2="50%" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="dodgerblue"/>
<stop offset=".52" stop-color="white">
<animate
attributeName="offset"
values="1;0;1"
dur="4s"
repeatCount="indefinite">
</animate>
</stop>
<stop offset="1" stop-color="gold">
<animate
attributeName="offset"
values="1;.5;1"
dur="4s"
repeatCount="indefinite">
</animate>
</stop>
</linearGradient>
</defs>
<rect x="50" y="50" width="50%" height="50%" rx="5%" fill="url(#bgg)" />
</svg>
Here is an idea with CSS only where you can rely on two gradients and a translation/opacity animation to approximate it. I also considered a little blur effect to have a better transition between gradient.
.box {
border-radius:20px;
width:200px;
height:200px;
position:relative;
z-index:0;
overflow:hidden;
}
.box:before,
.box:after{
content:"";
position:absolute;
bottom:0;
right:0;
width:220%;
height:220%;
animation:translate 2s infinite linear alternate;
}
.box:after {
background:
linear-gradient(to bottom right,dodgerblue 0%,white 40%,gold 60%);
animation-name:translate,show;
opacity:0;
}
.box:before {
background:
linear-gradient(to bottom right,dodgerblue,white 50%,gold 50%);
animation-name:translate,fade;
}
#keyframes translate{
from {
transform:translate(48%,48%);
}
}
#keyframes show{
30%,85% {
opacity:1;
}
}
#keyframes fade{
30%,85% {
filter:blur(8px);
}
}
<div class="box">
</div>
You can always use javascript for that:
requestAnimationFrame(animateOffsets);
// if this function called as callback of requestAnimationFrame,
// so there are first argument is the time from beginning from scene start
function animateOffsets(t) {
requestAnimationFrame(animateOffsets);
t = t%5000/5000; // will change from 0 to 1 (5 sec)
t = Math.sin(t*Math.PI*2); // will change from -1 to 1
stop1.setAttribute('offset', `${50 + t*50}%`);
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="50%" height="50%" viewBox="0 0 900 900" >
<defs>
<linearGradient id="bgg" x1="0" y1="0" x2="60%" y2="60%" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="dodgerblue"/>
<stop offset="50%" stop-color="white" id="stop1"/>
<stop offset="100%" stop-color="gold"/>
</linearGradient>
</defs>
<rect x="50" y="50" width="50%" height="50%" rx="5%" fill="url(#bgg)" />
</svg>
Gradient attribute offset animation as background image
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="50%" height="50%" viewBox="0 0 900 900" >
<linearGradient id="bgg" x1="479" y1="-345" x2="479" y2="853" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#fff">
<animate
attributeName="offset"
values="0;1;1;0;0"
dur="5s"
repeatCount="indefinite"
></animate>
</stop>
<stop offset="100%" stop-color="gold">
<animate
attributeName="offset"
values="0;1;1;0;0"
dur="5s"
repeatCount="indefinite"
></animate>
</stop>
</linearGradient>
<rect x="-45" y="0" width="70%" height="70%" rx="5%" fill="#ACA900" />
<rect x="65" y="80" width="50%" height="50%" rx="5%" fill="url(#bgg)" />
<image x="30" y="100" xlink:href="https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg" width="50%" height="50%" />
</svg>
Radial gradient effects
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="50%" height="50%" viewBox="0 0 900 900" >
<radialGradient id="myRadial"
fx="50%" fy="50%" r="80%">
<stop offset="0%" stop-color="gold">
<animate
attributeName="offset"
values="0;1.3;0"
dur="5s"
repeatCount="indefinite"
></animate>
</stop>
<stop offset="100%" stop-color="#EDEDED">
<animate
attributeName="offset"
values="0;1.3;1.3;0;0"
dur="5s"
repeatCount="indefinite"
></animate>
</stop>
</radialGradient>
<rect x="0" y="0" width="70%" height="70%" rx="5%" fill="#ACC400" />
<rect x="85" y="80" width="50%" height="50%" rx="5%" fill="url(#myRadial)" />
</svg>
Please check it out the gist bellow. I'm confused I would expect the same output but without the parentheses and ,. Any clue what I'm doing wrong?
https://astexplorer.net/#/gist/7f499680fcd4aaaba9af215afe42de80/c91228b082de80ef2c57e9c1960b22f884d1e694
E.g
Babel plugin:
export default function (babel) {
const { types: t } = babel;
return {
name: "ast-transform", // not required
visitor: {
JSXElement(path) {
if (path.node.openingElement.name.name === "defs") {
path.replaceWithMultiple(
path.node.children.filter(t.isJSXElement)
);
}
},
}
};
}
Actual:
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="72" height="72" fill="white" />
<path d="M68.81 0H34.23C34.23 4.14003 35.8746 8.11049 38.8021 11.0379C40.2516 12.4875 41.9724 13.6373 43.8663 14.4218C45.7602 15.2062 47.7901 15.61 49.84 15.61H56.21V21.76C56.2127 25.8966 57.8571 29.8629 60.7821 32.7879C63.7071 35.7129 67.6734 37.3574 71.81 37.36V3C71.81 2.20435 71.4939 1.44129 70.9313 0.87868C70.3687 0.31607 69.6057 0 68.81 0V0Z" fill="#2684FF" />
<path d="M51.7 17.23H17.12C17.1226 21.3666 18.7671 25.3329 21.6921 28.2579C24.617 31.1829 28.5834 32.8273 32.72 32.83H39.09V39C39.0953 43.1366 40.7423 47.1019 43.6691 50.025C46.596 52.9481 50.5634 54.59 54.7 54.59V20.23C54.7 19.4343 54.3839 18.6713 53.8213 18.1087C53.2587 17.5461 52.4956 17.23 51.7 17.23V17.23Z" fill="url(#paint0_linear)" />
<path d="M34.58 34.45H0C0 38.59 1.64462 42.5605 4.57206 45.4879C7.49951 48.4154 11.47 50.06 15.61 50.06H22V56.21C22.0026 60.3431 23.6443 64.3065 26.565 67.2309C29.4857 70.1553 33.4469 71.8021 37.58 71.81V37.45C37.58 36.6543 37.2639 35.8913 36.7013 35.3287C36.1387 34.7661 35.3757 34.45 34.58 34.45Z" fill="url(#paint1_linear)" />
(
<linearGradient id="paint0_linear" x1="53.96" y1="17.29" x2="39.25" y2="32.46" gradientUnits="userSpaceOnUse">
<stop offset="0.18" stop-color="#0052CC" />
<stop offset="1" stop-color="#2684FF" />
</linearGradient>,
<linearGradient id="paint1_linear" x1="1421.65" y1="1327.85" x2="786.064" y2="1949.52" gradientUnits="userSpaceOnUse">
<stop offset="0.18" stop-color="#0052CC" />
<stop offset="1" stop-color="#2684FF" />
</linearGradient>)
</svg>;
Expected:
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="72" height="72" fill="white" />
<path d="M68.81 0H34.23C34.23 4.14003 35.8746 8.11049 38.8021 11.0379C40.2516 12.4875 41.9724 13.6373 43.8663 14.4218C45.7602 15.2062 47.7901 15.61 49.84 15.61H56.21V21.76C56.2127 25.8966 57.8571 29.8629 60.7821 32.7879C63.7071 35.7129 67.6734 37.3574 71.81 37.36V3C71.81 2.20435 71.4939 1.44129 70.9313 0.87868C70.3687 0.31607 69.6057 0 68.81 0V0Z" fill="#2684FF" />
<path d="M51.7 17.23H17.12C17.1226 21.3666 18.7671 25.3329 21.6921 28.2579C24.617 31.1829 28.5834 32.8273 32.72 32.83H39.09V39C39.0953 43.1366 40.7423 47.1019 43.6691 50.025C46.596 52.9481 50.5634 54.59 54.7 54.59V20.23C54.7 19.4343 54.3839 18.6713 53.8213 18.1087C53.2587 17.5461 52.4956 17.23 51.7 17.23V17.23Z" fill="url(#paint0_linear)" />
<path d="M34.58 34.45H0C0 38.59 1.64462 42.5605 4.57206 45.4879C7.49951 48.4154 11.47 50.06 15.61 50.06H22V56.21C22.0026 60.3431 23.6443 64.3065 26.565 67.2309C29.4857 70.1553 33.4469 71.8021 37.58 71.81V37.45C37.58 36.6543 37.2639 35.8913 36.7013 35.3287C36.1387 34.7661 35.3757 34.45 34.58 34.45Z" fill="url(#paint1_linear)" />
<linearGradient id="paint0_linear" x1="53.96" y1="17.29" x2="39.25" y2="32.46" gradientUnits="userSpaceOnUse">
<stop offset="0.18" stop-color="#0052CC" />
<stop offset="1" stop-color="#2684FF" />
</linearGradient>
<linearGradient id="paint1_linear" x1="1421.65" y1="1327.85" x2="786.064" y2="1949.52" gradientUnits="userSpaceOnUse">
<stop offset="0.18" stop-color="#0052CC" />
<stop offset="1" stop-color="#2684FF" />
</linearGradient>
</svg>;
Cheers,
EDIT: One idea I got is to use the Fragments
path.replaceWith(
t.jsxFragment(
t.jsxOpeningFragment(),
t.jsxClosingFragment(),
path.node.children.filter(t.isJSXElement)
)
);
with the result
<>
<linearGradient
id="prefix__paint0_linear"
x1={53.96}
y1={17.29}
x2={39.25}
y2={32.46}
gradientUnits="userSpaceOnUse"
>
<stop offset={0.18} stopColor="#0052CC" />
<stop offset={1} stopColor="#2684FF" />
</linearGradient>
<linearGradient
id="prefix__paint1_linear"
x1={1421.65}
y1={1327.85}
x2={786.064}
y2={1949.52}
gradientUnits="userSpaceOnUse"
>
<stop offset={0.18} stopColor="#0052CC" />
<stop offset={1} stopColor="#2684FF" />
</linearGradient>
</>
Better, but not entirety what I want.
You could try to use replaceInline instead; it doesn't add any parentheses or comma's in your AST Explorer example.
My guess is that this is caused by the leading and trailing comments that are added when using replaceWithMultiple. Check out the source code here:
https://github.com/babel/babel/blob/0345c1bc1ded6af8d66f8605e6fdbeeb9b70c5b3/packages/babel-traverse/src/path/replacement.js#L50
and compare it to the source of replaceInline:
https://github.com/babel/babel/blob/0345c1bc1ded6af8d66f8605e6fdbeeb9b70c5b3/packages/babel-traverse/src/path/replacement.js#L266
Hey I am trying to build a joystick which is well understood and can be used by elders. The joystick need to have 4 directions: Left,Right,Top and Down and also has a pause button in the middle.
This joystick is need to be used for moving a camera.
I have found a code in the web which create for me an svg joystick.
The problem is that this joystick isn't easy to used ,and when you pressed on a direction you don't know if you click on it or not.
Also when you click on the center for stop action you don't have a feedeback for clicking.
I am looking for alternative or improvement for my current joystick.
How can I improve my current controller so I will have a feedback for clicking in svg. Can I create a stick in svg so I will know to which direction I am pointing right now?
I would be happy if someone can help me with this controller,
thanks in advance.
Edit:
I need a real visual feedback for each arrow and the stop button. If any changes are required for current svg, it is welcome.
#arrowRight:hover,
#arrowLeft:hover,
#arrowDown:hover,
#arrowUp:hover{
fill:blue;
}
<div id="joystick" style="width:20%">
<svg width="100%" height="100%" viewBox="0 0 100 100">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgb(16,16,16);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(240,240,240);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad2" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgb(240,240,240);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(16,16,16);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad3" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgb(168,168,168);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(239,239,239);stop-opacity:1" />
</linearGradient>
</defs>
<circle cx="50" cy="50" r="50" fill="url(#grad1)" />
<circle cx="50" cy="50" r="47" fill="url(#grad2)" stroke="black" stroke-width="1.5px" />
<circle cx="50" cy="50" r="44" fill="url(#grad3)" />
<circle cx="50" cy="50" r="20" fill="#cccccc" stroke="black" stroke-width="1px" />
<path id="arrowUp" d="M50,14 54,22 46,22Z" fill="rgba(0,0,0,0.8)" />
<path id="arrowDown" d="M50,86 54,78 46,78Z" fill="rgba(0,0,0,0.8)" />
<path id="arrowLeft" d="M14,50 22,54 22,46Z" fill="rgba(0,0,0,0.8)" />
<path id="arrowRight" d="M86,50 78,54 78,46Z" fill="rgba(0,0,0,0.8)" />
</svg>
</div>
You can add an onclick function to each path. Send the direction as a parameter to this function.
function click(elem, direction) {
var arrows = document.getElementsByClassName("arrow");
//reset all arrows
for (let i = 0; i < arrows.length; i++) {
arrows[i].style.fill = "rgba(0,0,0,0.8)";
}
//Set the clicked arrow to red
elem.style.fill = "red";
};
#arrowRight:hover,
#arrowLeft:hover,
#arrowDown:hover,
#arrowUp:hover {
fill: blue;
}
<div id="joystick" style="width:20%">
<svg width="100%" height="100%" viewBox="0 0 100 100">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgb(16,16,16);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(240,240,240);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad2" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgb(240,240,240);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(16,16,16);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad3" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgb(168,168,168);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(239,239,239);stop-opacity:1" />
</linearGradient>
</defs>
<circle cx="50" cy="50" r="50" fill="url(#grad1)" />
<circle cx="50" cy="50" r="47" fill="url(#grad2)" stroke="black" stroke-width="1.5px" />
<circle cx="50" cy="50" r="44" fill="url(#grad3)" />
<circle cx="50" cy="50" r="20" fill="#cccccc" stroke="black" stroke-width="1px" />
<path id="arrowUp" class="arrow" d="M50,14 54,22 46,22Z" fill="rgba(0,0,0,0.8)" onclick="click(this, 'up')" />
<path id="arrowDown" class="arrow" d="M50,86 54,78 46,78Z" fill="rgba(0,0,0,0.8)" onclick="click(this,'down')" />
<path id="arrowLeft" class="arrow" d="M14,50 22,54 22,46Z" fill="rgba(0,0,0,0.8)" onclick="click(this,'left')" />
<path id="arrowRight" class="arrow" d="M86,50 78,54 78,46Z" fill="rgba(0,0,0,0.8)" onclick="click(this,'right')" />
</svg>
</div>
I want to replace a gradient for another in a svg so I need to iterate (probably recursively) over each svg item to get
I looked at the svg doc # MDN
https://developer.mozilla.org/fr/SVG/Element/ellipse
but it is broken (access denied, no exemple, lots of broken links)
and quite different of the one at MSDN
http://msdn.microsoft.com/en-us/library/ie/ff972071%28v=vs.85%29.aspx
so I search for any pointer on how to access fill property of a svg element however it has been defined.
something like a getComputedFill function
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
>
<defs>
<script>
<![CDATA[
function infothis(ref)
{
alert(ref + " " + ref.fill + " " + ref.fillOpacity); // why can't I get "url(#grad1)" and 0.5 when clicking ellipse1
//alert(ref.style.getPropertyValue("fill")); // somewhat okwhy can't I get "url(#grad2)" when clicking ellipse2
}
]]>
</script>
<linearGradient
dc:title="red black filter"
dc:rights="CC-BY"
dc:description="basic filter ranging from black to red"
id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(0,0,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(0,0,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,255);stop-opacity:1" />
</linearGradient>
<ellipse id="ellipse0" cx="150" cy="170" rx="85" ry="55" fill="url(#grad2)" />
</defs>
<ellipse id="ellipse1" cx="200" cy="70" rx="85" ry="55" fill="url(#grad1)" fill-opacity="0.5" onclick="infothis(this)" />
<ellipse id="ellipse2" cx="100" cy="70" rx="85" ry="55" style="fill:url(#grad2)" onclick="infothis(this)" />
<use xlink:href="#ellipse0"/>
</svg>
How about this...
alert(document.defaultView.getComputedStyle(ref, null).getPropertyValue("fill"));