I have the following SVG:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="900" height="800">
<path d="M 650,750 L 50,750 L 100,350 L 850,50 L 850,550 L 650,750" fill="none" stroke="black" stroke-width="3" />
</svg>
When I try to render it with ExtrudeGeometry, I get the following:
The filling is set to none, so it should only have borders (at least this is what I am trying to achieve).
This is what I'm using to load it:
const svgResult = loader.parse(svgTxt);
svgResult.paths.forEach((path) => {
const shapes = SVGLoader.createShapes(path);
shapes.forEach((shape) => {
const geom = new THREE.ExtrudeGeometry(shape, {
bevelEnabled: true,
bevelSize: 14,
bevelThickness: 5,
bevelSegments: 15,
depth: 20,
});
const mesh = new THREE.Mesh(
geom,
new THREE.MeshPhysicalMaterial({
color: "white",
})
);
...
}
}
I have such an element made in SVG:
import Svg, { Path, Circle } from "react-native-svg"
function CloseIcon(props) {
return (
<Svg
viewBox="0 0 1000 1000"
fillRule="evenodd"
clipRule="evenodd"
strokeLinejoin="round"
strokeMiterlimit={2}
style={styles.shadow}
>
<Path
d="M500 420.886L781.42 139.464c19.297-19.28 50.622-19.28 69.919 0l9.179 9.195c19.296 19.28 19.296 50.623 0 69.903L579.097 499.983l281.438 281.455c19.296 19.28 19.296 50.622 0 69.902l-9.179 9.195c-19.296 19.28-50.622 19.28-69.918 0L500 579.081 218.562 860.535c-19.297 19.28-50.623 19.28-69.919 0l-9.179-9.195c-19.296-19.28-19.296-50.622 0-69.902l281.438-281.455-281.421-281.421c-19.297-19.28-19.297-50.623 0-69.903l9.178-9.195c19.297-19.28 50.623-19.28 69.92 0l281.42 281.422z"
fill="#fff"
/>
</Svg>
)
};
Is it possible to add a shadow to it?
These types of options do not work: (this solution treats the path as a rectangle)
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.23,
shadowRadius: 2.62,
elevation: 4,
I'm creating a component in my application built with Vue. This componet is a countdown, ranging from X minutes to 00:00.
I know it's possible to animate svg to achieve the desired result, but I do not have the necessary knowledge. I have never used any svg library.
I need to create the following animation in my progress component:
The animation need to follow the path according to the weather in a smooth way. The path nodes should be inserted / updated based on time.
This is my actual countdown component:
var app = new Vue({
el: '#app',
data: {
date: moment(2 * 60 * 1000)
},
computed: {
time: function(){
return this.date.format('mm:ss');
}
},
mounted: function(){
var timer = setInterval(() => {
this.date = moment(this.date.subtract(1, 'seconds'));
if(this.date.diff(moment(0)) === 0){
clearInterval(timer);
alert('Done!');
}
}, 1000);
}
});
<script src="https://momentjs.com/downloads/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">{{ time }}</div>
This is the svg for the progress circle:
<svg x="0px" y="0px" viewBox="0 0 90 90">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:none;stroke:#B5B5B5;stroke-miterlimit:10;}
.st2{fill:none;stroke:#408EFF;stroke-linecap:round;stroke-miterlimit:10;}
.st3{fill:#408EFF;}
</style>
<rect class="st0" width="90" height="90"/>
<circle class="st1" cx="45" cy="45" r="40"/>
<path class="st2" d="M45,5c22.1,0,40,17.9,40,40S67.1,85,45,85S5,67.1,5,45S22.9,5,45,5"/>
<circle class="st3" cx="45" cy="5" r="3"/>
</svg>
How can I achieve the desired result?
All help would be welcome.
You'll need to familiarize yourself with SVG shapes, in particular <path> in order to make the arc.
Here's an example:
Vue.component('progress-ring', {
template: '#progress-ring',
props: {
value: {
type: Number,
default: 0,
},
min: {
type: Number,
default: 0,
},
max: {
type: Number,
default: 1,
},
text: {
type: null,
default: '',
},
},
computed: {
theta() {
const frac = (this.value - this.min) / (this.max - this.min) || 0;
return frac * 2 * Math.PI;
},
path() {
const large = this.theta > Math.PI;
return `M0,-46 A46,46,0,${large ? 1 : 0},1,${this.endX},${this.endY}`;
},
endX() {
return Math.cos(this.theta - Math.PI * 0.5) * 46;
},
endY() {
return Math.sin(this.theta - Math.PI * 0.5) * 46;
},
},
});
new Vue({
el: '#app',
});
body {
font-family: sans-serif;
}
.progress-ring {
width: 100px;
height: 100px;
}
.progress-ring-circle {
stroke: rgba(0, 0, 0, 0.1);
stroke-width: 1;
fill: none;
}
.progress-ring-ring {
stroke: #007fff;
stroke-width: 2;
fill: none;
}
.progress-ring-end {
fill: #007fff;
}
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>
<div id="app">
<progress-ring :min="0" :max="100" :value="40" text="12:34"></progress-ring>
</div>
<template id="progress-ring">
<svg class="progress-ring" viewBox="-50,-50,100,100">
<circle class="progress-ring-circle" r="46"/>
<path class="progress-ring-ring" :d="path"/>
<circle class="progress-ring-end" :cx="endX" :cy="endY" r="4"/>
<text alignment-baseline="middle" text-anchor="middle">{{ text }}</text>
</svg>
</template>
As for animating it, you just need to use JavaScript to change the value prop by using, for example, setInterval or some other means.
Follow your template, one solution is pre-define the path into one array (each path node is one element of the array). Then push the path node to current progress path for each interval.
Like below demo:
var app = new Vue({
el: '#app',
data: {
date: moment(2 * 60 * 1000),
pathRoute: ['M45 5', 'c22.1 0 40 17.9 40 40','S67.1 85 45 85','S5 67.1 5 45','S22.9 5 45 5'],
pathProgess: [],
stepIndex: 0
},
computed: {
time: function(){
return this.date.format('mm:ss');
},
computedProgress: function () {
return this.pathProgess.join(' ')
}
},
mounted: function(){
var timer = setInterval(() => {
this.date = moment(this.date.subtract(1, 'seconds'));
this.$set(this.pathProgess, this.stepIndex, this.pathRoute[this.stepIndex])
this.stepIndex++
if(this.date.diff(moment(0)) === 0){
clearInterval(timer);
}
}, 1000);
}
});
.st0{fill:#FFFFFF;}
.st1{fill:none;stroke:#B5B5B5;stroke-miterlimit:10;}
.st2{fill:none;stroke:#408EFF;stroke-linecap:round;stroke-miterlimit:10;}
.st3{fill:#408EFF;}
<script src="https://momentjs.com/downloads/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<p>{{computedProgress}}</p>
<svg x="0px" y="0px" viewBox="0 0 90 90">
<rect class="st0" width="90" height="90"/>
<circle class="st1" cx="45" cy="45" r="40"/>
<text class="circle-chart-percent" x="20.91549431" y="40.5" font-size="8">{{time}}</text>
<path class="st2" :d="computedProgress"/>
<circle class="st3" cx="45" cy="5" r="3"/>
</svg>
</div>
Or you can use the approach Answered at another question, to real time calculate the path.
var app = new Vue({
el: '#app',
data: {
date: moment(2 * 60 * 1000),
pathProgess: ''
},
computed: {
time: function(){
return this.date.format('mm:ss');
}
},
mounted: function(){
let maxValue = this.date.diff(moment(0), 'seconds') //total seconds
var timer = setInterval(() => {
this.date = moment(this.date.subtract(1, 'seconds'))
let curValue = this.date.diff(moment(0), 'seconds') // current seconds
this.pathProgess = this.describeArc(45, 45, 40, 0, (maxValue-curValue)*360/maxValue)
if(this.date.diff(moment(0)) === 0){
clearInterval(timer);
}
}, 1000);
},
methods: {
//copy from https://stackoverflow.com/a/18473154/5665870
polarToCartesian: function (centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
},
//copy from https://stackoverflow.com/a/18473154/5665870
describeArc: function (x, y, radius, startAngle, endAngle){
var start = this.polarToCartesian(x, y, radius, endAngle);
var end = this.polarToCartesian(x, y, radius, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");
return d;
}
}
});
.st0{fill:#FFFFFF;}
.st1{fill:none;stroke:#B5B5B5;stroke-miterlimit:10;}
.st2{fill:none;stroke:#408EFF;stroke-linecap:round;stroke-miterlimit:10;}
.st3{fill:#408EFF;}
<script src="https://momentjs.com/downloads/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<p>{{pathProgess}}</p>
<svg x="0px" y="0px" viewBox="0 0 90 90">
<rect class="st0" width="90" height="90"/>
<circle class="st1" cx="45" cy="45" r="40"/>
<text class="circle-chart-percent" x="20.91549431" y="40.5" font-size="8">{{time}}</text>
<path class="st2" :d="pathProgess"/>
<circle class="st3" cx="45" cy="5" r="3"/>
</svg>
</div>
I have JSON data that looks like the following.
var data = [
{ animal: 'dog', names: [ 'mark', 'cooper', 'pooch' ] },
{ animal: 'cat', names: [ 'mary', 'kitty' ]
];
From this data I need to generate SVG elements using d3 in the following way.
<svg id="mysvg" width="500" height="500">
<g data-animal="dog" transform="translate(0,0)">
<text x="10" y="10" fill="black">dog</text>
<text x="10" y="25" fill="black">mark</text>
<text x="10" y="40" fill="black">cooper</text>
<text x="10" y="55" fill="black">pooch</text>
</g>
<g data-animal="cat" transform="translate(0, 100)">
<text x="10" y="10" fill="black">cat</text>
<text x="10" y="25" fill="black">mary</text>
<text x="10" y="40" fill="black">kitty</text>
</g>
</svg>
To create the g element I do something like the following. I keep the g variable around to append more elements.
var g = d3.select('#mysvg')
.selectAll('g')
.data(data)
.enter().append('g')
.attr({
'data-animal': function(d) { return d.animal; },
transform: function(d) { return 'translate(' + ... + ')'; }
});
Now I can append the first text element as follows.
g.append('text')
.attr({ x: '10', y: '10', fill: 'black' })
.text(function(d) { return d.animal; });
How do I append more elements to each g by iterating over each data[i].names array?
One way is to use the .each function to operate on each data point. Note that we used d3.select(this) to get the current g.
g.each(function(d) {
for(var i = 0; i < d.names.length; i++) {
d3.select(this).append('text')
.attr({ x: '10', y: '10', fill: 'black' })
.text(function(d) { return d.names[i]; });
}
});
This is the code generated by highcharts for lines and point. I'm using inspect element and points are where they should be but they seem to be transparent or something like behind he chart. but the code looks right.
<g class="highcharts-series-group" zIndex="3">
<g class="highcharts-series" clip-path="url(http://localhost:63540/admin/reports.aspx?type=like#highcharts-1)" visibility="visible" transform="translate(40,10)">
<path d="M 244 50.4 L 732 302.6" fill="none" stroke="rgb(0, 0, 0)" stroke-width="5" isShadow="true" stroke-opacity="0.05" transform="translate(1,1)"></path>
<path d="M 244 50.4 L 732 302.6" fill="none" stroke="rgb(0, 0, 0)" stroke-width="3" isShadow="true" stroke-opacity="0.1" transform="translate(1,1)"></path>
<path d="M 244 50.4 L 732 302.6" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1" isShadow="true" stroke-opacity="0.15000000000000002" transform="translate(1,1)"></path>
<path d="M 244 50.4 L 732 302.6" fill="none" stroke="#4D4D4D" stroke-width="2"></path><path d="M 732 298.6 C 737.328 298.6 737.328 306.6 732 306.6 C 726.672 306.6 726.672 298.6 732 298.6 Z" fill="#4D4D4D" stroke="#FFFFFF" stroke-width="0.000001" zIndex="2000"></path>
<path d="M 244 46.4 C 249.328 46.4 249.328 54.4 244 54.4 C 238.672 54.4 238.672 46.4 244 46.4 Z" fill="#4D4D4D" stroke="#FFFFFF" stroke-width="0.000001"></path></g></g>
What can be wrong with it?
It's funny that I have copied the code from my other project (that is working) and only have changed the data.
this is the compiled js code:
var dates = ['1394/12/06','1394/12/11'];
after.push(function () {
chart = new Highcharts.Chart({
chart: {
height: 500,
backgroundColor:'#eee',
renderTo: 'chart',
defaultSeriesType: 'line',
// marginRight: 130,
//marginBottom: 150,
// marginTop: 20,
// events: { click: function () { startWait($('html')); document.location = 'price.aspx' } }
},
title: {
text: '',
x: -20 //center
},
subtitle: {
text: '',
x: -20
},
xAxis: {
categories: dates,
labels: {
rotation: 90,
formatter: function () {
return this.value;
},
y:40
}
},
yAxis: {
title: {
text: ''
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}],
labels: {
formatter: function () {
// return toFarsi(virgulize(this.value)) ;
}
}
},
tooltip: {
formatter: function () {
return "<b>" + this.y + "</b>";
}
},
legend: {
//enabled: false
},
series: [
{
name:' likes',
color:'#4D4D4D',
data: [2,1]
},
]
});
});
Well after disabling css, javascript, and many other tests nothing worked.
Thanks to jlbriggs his fiddle gave me the idea of testing the code with older version of jquery.
It worked with older version of jquery.
Update:
New version of Highcharts works with the latest version of jquery.