Statistics circles in CSS - javascript

I would like to do something like this but I don't know how.
I have an idea but it doesn't work.
<div id="stats">
<div id="men" class="circle"></div>
<div id="women" class="circle"></div>
<div id="white-circle" class="small-circle"></div>
</div>
<style>
#stats {
width: 100px;
height: 100px;
background: white;
position: relative;
}
.circle {
border-radius: 100px;
background: #CCC;
width: 100px;
height: 100px;
position: absolute;
}
.circle#men {
background: #27ae60;
}
.circle#women {
background: #f26646;
}
.small-circle {
border-radius: 100px;
background: white;
width: 65px;
height: 65px;
position: absolute;
top: 0; bottom: 0; left: 0; right: 0;
margin: auto;
}
</style>

It is actually called as donut chart. It will be difficult for you to just use a div tag. Instead use canvas or just use a javascript framework for charting. Here are few examples.
<canvas></canvas>
Example1
Example2
Example3
Example4
markup
<canvas width="500px" height="250px"></canvas>
javascript
$(document).ready(function() {
var context = $("canvas")[0].getContext("2d");
var values = '24,43,43,45';
var segments = values.split(",");
var segmentColor = 50;
var total = 0;
//Reset the canvas
context.restore();
context.save();
context.clearRect(0,0,500,250);
for (i=0;i<segments.length;i++) {
total = total + parseFloat(segments[i]);
}
var parts = 360/total;
var startAngle=0
context.translate(100,100)
context.rotate(270*(Math.PI/180)); //Turn the chart around so the segments start from 12 o'clock
for (i=0;i<segments.length;i++) {
//Draw the segments
context.fillStyle ="rgb(" + segmentColor + "," + segmentColor + "," + segmentColor + ")";
context.beginPath();
context.moveTo(0,0);
context.arc(0,0,100,startAngle*(Math.PI/180),(startAngle + parseFloat(segments[i]*parts))*(Math.PI/180),false);
context.lineTo(0,0);
context.closePath();
context.fill();
startAngle = startAngle + parseFloat(segments[i]*parts);
segmentColor = segmentColor + 20;
}
//Turn into a donut!!
context.fillStyle = "White";
context.beginPath();
context.arc(0,0,60,0,Math.PI*2,false);
context.closePath();
context.fill();
});
Notice: var values = '24,43,43,45'; // This will basicall divide the circle into 4 parts
Demo: http://jsfiddle.net/Zgfb6/

One method would be to just use a chart framework which supports donut charts like d3js.
Examples made with d3js:
http://bl.ocks.org/mbostock/3887193
http://bl.ocks.org/mbostock/3888852
http://www.visualizing.org/visualizations/uk-olympic-sentiment-analysis

Here's how to make circles in css:
If you know how to make square in css you only need to add border-radius: 100% in css. That will convert a square into circle. Here is some more code which to address your question:
<html>
<head>
<title> Disappering Circles </title>
<link rel="stylesheet" type="text/css" href="css.css">
</head>
<body>
<div id="red"></div>
<div id="blue"></div>
<div id="yellow"></div>
<script type="text/javascript"></script>
</body>
</html>
Here is the CSS:
#red {
width: 100px;
height: 100px;
background-color: red;
display: inline-block;
border-radius: 100%
}
#blue{
width: 100px;
height: 100px;
background-color: blue;
display: inline-block;
}
#yellow{
width: 100px;
height: 100px;
background-color: yellow;
display: inline-block;
}

You could also use Highcharts, and more specifically highcharts-chart (web-component of Highcharts) to get a chart like this:
Implementation:
chart.data = [{
name: 'Clients',
size: "100%",
innerSize: "60%",
showInLegend: true,
dataLabels: {enabled: false},
data: [
{name: "Men", y: 2258, color: '#20ad61'},
{name: "Women", y: 5023, color: '#f26645'},
],
}]
chart.legendOptions = {
enabled: true,
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
labelFormatter: function() {return Math.round(this.y/7281*100)+"% "+this.name},
}
chart.chartOptions = {spacingLeft: 0,}
chart.highchartOptions = {
title: {
verticalAlign: 'middle',
y: -2
},
subtitle: {
verticalAlign: 'middle'
},
}
#chart {
width: 23em;
height: 10em
}
#chart .highcharts-point {rx: initial; ry: initial}
<base href="https://user-content-dot-custom-elements.appspot.com/avdaredevil/highcharts-chart/v2.0.1/highcharts-chart/">
<link rel="import" href="highcharts-chart.html">
<highcharts-chart id='chart' title='<b>7,281</b>' subtitle='CLIENTS' type="pie" title="" label="Gender" legend height-responsive></highcharts-chart>
Note: Click Run Code Snippet to see the chart.

Related

Try to do a progress bar in javascript

I'm starting to code this year and sorry if my english is not good enough,
I have a problem with a progress bar with JS,
I have on my console an "uncaught TypeError who charge infinitly and say to me that we can charge the properties on style...
The first step was working but when the bar is supposed to become interactive it's not working
const tll = gasp.timeline({
paused: true
});
tll.to("#percent", "#bar", {
duration: .2,
opacity: 0,
zIndex: -1
});
tll.to("#preloader", {
duration: .8,
width: "0%"
});
tll.from(".container", {
duration: 1.5,
y: "-150%"
}, "-=.2");
tll.to("container h1", {
opacity: 1,
textShadow: "12px 20px rgba(255, 255, 255,0.23)",
skewY: 10,
y: "10%",
stagger: {
amount: .4
}
});
var width = 1;
var bar = document.getElementById("barconfirm");
var id;
function move() {
id = setInterval(frame, 10);
}
function frame() {
if (width > 100) {
clearInterval(id);
tll.play();
} else {
width++;
bar.style.width = width + "%";
document.getElementById("percent").innerHTML = width + "%";
}
}
* {
margin: 0;
padding: 0;
overflow: hidden;
}
#preloader {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
z-index: 100;
background-color: #0f0f0f;
flex-direction: column;
}
#percent {
color: white;
font-family: "Neutral Face";
}
#bar {
width: 60%;
margin-top: 20%;
}
#barconfirm {
width: 1%;
padding: 1px 0px;
background-color: white;
}
.container {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
background-color: gray;
}
.container h1 {
font-family: 'Monument';
text-transform: uppercase;
font-size: 40px;
opacity: 0;
}
<body onload="move()">
<div id="preloader">
<div id="percent">1%</div>
<div id="bar">
<div id="barconfirm"></div>
</div>
</div>
<div class="container">
<h1>Leo Clemente</h1>
</div>
Thanks to you all for your help, I want if you can an explanation more than just a code because I'm here to learn too and have a great day!
The issue in passing the selector to the tll.to method, it accepts ONE selector, so choose one of yours for tll.to("#percent", "#bar", {...}).
It will work as well whether you choose percent or bar. Also, according to the document, the dependency variable name is gsap.
You can check out an online snippet from here

Chart.js inside popup on leaflet?

Maybe this is a silly question but I am unable to include a chart for each point on a map.
I am collecting the data from a JSON, this data I print it in the popup, each one with its class .scoreA, .scoreB... I would like from this data to create a chart for each point like the one I have. I would prefer to take them from the content of the popup (.scoreA, .scoreB) rather than from the JSON in case the structure changes. is it possible?
var mymap = L.map('mapid').setView([39.46975, -0.37739], 8 );
L.tileLayer('https://api.mapbox.com/styles/v1/jamaldols/cktwljkom0vzo18l9ggtnky83/tiles/256/{z}/{x}/{y}#2x?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors, Imagery © Mapbox',
maxZoom: 12,
minZoom: 8,
id: 'mapbox/standard',
tileSize: 512,
zoomOffset: -1,
// maxNativeZoom: 16,
accessToken: ''
}).addTo(mymap);
$.getJSON('data.geo.json', function (geojson) {
L.geoJson(geojson, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng);
},
onEachFeature: function (feature, layer) {
const coordinates = feature.geometry.coordinates;
const normalizedCoordinates = feature.geometry.coordinates.sort(function(a,b){return a.typeid-b.typeid});
console.log( `Coordinates: ${coordinates}`);
console.log( `Coordinates N: ${normalizedCoordinates}`);
const content =
`
<p id="heading">${feature.properties.name}</p>
<p class="scoreA"><strong>ScoreA: </strong>${feature.properties.scoreA}</p>
<p class="scoreB"><strong>ScoreB: </strong>${feature.properties.scoreB}</p>
<p class="scoreC"><strong>ScoreC: </strong>${feature.properties.scoreC}</p>
<p class="scoreD"><strong>ScoreD: </strong>${feature.properties.scoreD}</p>
<div class="popup__chart">chart</div>
`;
layer.on('click', function (e) {
document.getElementById("popup__content").innerHTML = content;
$(".popup").fadeOut(10);
$(".popup").fadeIn("slow");
console.log( `Click on ${feature.properties.name}`);
const maxZoom = mymap.getMaxZoom();
console.log(maxZoom)
mymap.flyTo(this.getLatLng(), maxZoom, {easeLinearity: 0.12, duration:1});
});
}
}).addTo(mymap);
});
//Chart
var marksCanvas = document.getElementById("marksChart");
var marksData = {
labels: ["Score A", "Score B", "Score C", "Score D"],
datasets: [{
label: "City",
backgroundColor: "rgba(200,0,0,1)",
data: [65, 60, 90, 80]
},]
};
var radarChart = new Chart(marksCanvas, {
type: 'radar',
data: marksData
});
$(document).ready(function(){
$(".popup__bar__close").click(function(){
$('.popup').css('display', 'none');
mymap.flyTo([39.46975, -0.37739], 8, {easeLinearity: 0.12, duration:1});
});
});
html,
body {
height: 100%;
font-family: 'Montserrat', sans-serif;
}
.popup-fixed {
position: fixed;
top: auto;
bottom: 0 !important;
left: 0 !important;
right: 0 !important;
transform: none !important;
margin: 0;
border-radius: 0;
}
.leaflet-popup-tip-container {
display: none;
}
.leaflet-popup-content-wrapper {
border-radius: 0;
}
.popup {
width: 300px;
padding-bottom: 50px;
background: white;
position: absolute;
top: 50px;
right: 50px;
border: none;
display:none;
z-index: 1000;
}
#heading {
font-size: 35px;
color:black;
text-transform: uppercase;
margin: 15px 0;
}
#main {
display: flex;
overflow: hidden;
}
.popup {
}
.popup__bar {
width: 100%;
height: 50px;
position: relative;
display: flex;
align-items: center;
background: black;
}
.popup__bar__close {
background-image: url(img/close.svg);
background-size: 30px;
background-repeat: no-repeat;
background-position: center;
position: absolute;
height: 30px;
width: 30px;
right: 15px;
transform: rotate(45deg);
cursor: pointer;
}
.popup__chart {
}
.popup__chart img{
max-width: 100%;
height: auto;
}
#popup__content {
padding: 0 30px;
}
#info {
}
#footer {
font-family: 'Roboto Condensed', sans-serif;
display: flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
letter-spacing: 6px;
height: 70px;
position: absolute;
background: white;
bottom: 0;
width: calc(100% - 90px);
right: 0;
}
#marksChart {
display: block;
box-sizing: border-box;
height: 250px;
width: 250px;
position: absolute;
top: 100px;
left: 90px;
background: white;
z-index: 200000;
border-radius: 12px;
padding: 20px;
}
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js" integrity="sha512-Wt1bJGtlnMtGP0dqNFH1xlkLBNpEodaiQ8ZN5JLA5wpc1sUlk/O5uuOMNgvzddzkpvZ9GLyYNa8w2s7rqiTk5Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<style>
#mapid {
height: calc(100vh - 70px);
width: calc(100vw - 90px);
}
body {
padding: 0;
margin: 0;
}
</style>
<main id="main">
<div id="mapid"></div>
</main>
<div class="chart-container" style="max-width: 200px;">
<canvas id="marksChart" width="200" height="400"></canvas>
</div>
<script>
</script>
<div class="popup">
<div class="popup__bar">
<div class="popup__bar__close"></div>
</div>
<div id="popup__content"></div>
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
<!-- <script type="text/javascript" src="data.geo.json"></script> -->
<script type="text/javascript" src="main.js"></script>
</body>
Change your javascript to following:
$.getJSON('data.geo.json', function (geojson) {
L.geoJson(geojson, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng);
},
onEachFeature: function (feature, layer) {
const coordinates = feature.geometry.coordinates;
const normalizedCoordinates = feature.geometry.coordinates.sort(function(a,b){return a.typeid-b.typeid});
console.log( `Coordinates: ${coordinates}`);
console.log( `Coordinates N: ${normalizedCoordinates}`);
const content =
`
<p id="heading">${feature.properties.name}</p>
<p class="scoreA"><strong>ScoreA: </strong><span>${feature.properties.scoreA}</span></p>
<p class="scoreB"><strong>ScoreB: </strong><span>${feature.properties.scoreB}</span></p>
<p class="scoreC"><strong>ScoreC: </strong><span>${feature.properties.scoreC}</span></p>
<p class="scoreD"><strong>ScoreD: </strong><span>${feature.properties.scoreD}</span></p>
<div class="popup__chart">chart</div>
`;
layer.on('click', function (e) {
var popupElm = document.getElementById("popup__content");
popupElm.innerHTML = content;
$(".popup").fadeOut(10);
$(".popup").fadeIn("slow");
console.log( `Click on ${feature.properties.name}`);
const maxZoom = mymap.getMaxZoom();
console.log(maxZoom)
mymap.flyTo(this.getLatLng(), maxZoom, {easeLinearity: 0.12, duration:1});
var marksData = {
labels: ["Score A", "Score B", "Score C", "Score D"],
datasets: [{
label: "City",
backgroundColor: "rgba(200,0,0,1)",
data: [
popupElm.querySelectorAll('.scoreA span')[0].innerHTML,
popupElm.querySelectorAll('.scoreB span')[0].innerHTML,
popupElm.querySelectorAll('.scoreC span')[0].innerHTML,
popupElm.querySelectorAll('.scoreD span')[0].innerHTML
],
},]
};
if(radarChart){
radarChart.destroy();
}
radarChart = new Chart(marksCanvas, {
type: 'radar',
data: marksData
});
});
}
}).addTo(mymap);
});
//Chart
var marksCanvas = document.getElementById("marksChart");
var radarChart = null;
$(document).ready(function(){
$(".popup__bar__close").click(function(){
$('.popup').css('display', 'none');
mymap.flyTo([39.46975, -0.37739], 8, {easeLinearity: 0.12, duration:1});
});
});
What changed:
Add in the Popup around the score value a span, so it can easily read out
<p class="scoreA"><strong>ScoreA: </strong><span>${feature.properties.scoreA}</span></p>
Move the chart generation into the click function but keep the global variables
Destroy the existing chart, else an error is thrown radarChart.destroy();
Get the valus from popup and use it in the data array. It searches for the class .scoreA and then it get the child span element
popupElm.querySelectorAll('.scoreA span')[0].innerHTML,
Btw. you can also get the values from the clicked layer:
data: [
layer.feature.properties.scoreA,
layer.feature.properties.scoreB,
layer.feature.properties.scoreC,
layer.feature.properties.scoreD,
]

How to Add Custom Increment and decrements Counter in jQuery Ui Slider

I am trying to increase the width of an element (.inner) using jQuery Ui slider. This is somehow working fine but I need to keep the center of the inner always in the center of .wrapper. so I think I need to add negative values for top and left but I do not know how to achieve them. Do I have to create two custom counter there or is there any better way to achieve this?
$(function() {
$("#slider").slider({
range: "max",
min: 300,
max: 1000,
value: 1,
slide: function(event, ui) {
$(".inner").css({
"width": ui.value,
"height": ui.value
});
}
});
});
body,
html {
height: 100%;
width: 100%
}
.wrapper {
position: relative;
height: 300px;
width: 300px;
border: 2px solid #999;
border-radius: 4px;
overflow:hidden;
}
.inner {
position: absolute;
width: 100%;
height: 100%;
display: -webkit-flex;
-webkit-align-items: center;
display: flex;
align-items: center;
justify-content: center;
background: #eee;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="wrapper ">
<div class="inner"> Center </div>
</div>
<br />
<div id="slider"></div>
Since the width of the div and the range of the slider were the same, I used the slider value to change the left and top positions of the inner div.
This was of course possible because it was in position absolute.
Only half the value of the slider is applied, because to be centered you should split the change on left/right and top/bottom. Obviously adding the right or bottom css property would be pointless, since one is enough to properly position your element.
$(function() {
var $inner = $(".inner");
var lastValue = 300;
$("#slider").slider({
range: "max",
min: 300,
max: 1000,
value: 300,
slide: function(event, ui) {
var curLeft = $inner.position().left;
var curTop = $inner.position().top;
var toAdd = (lastValue - ui.value) /2;
$inner.css({
"width": ui.value,
"height": ui.value,
"top": curTop + toAdd,
"left": curLeft + toAdd,
});
lastValue = ui.value;
}
});
});
body,
html {
height: 100%;
width: 100%
}
.wrapper {
position: relative;
height: 300px;
width: 300px;
border: 2px solid #999;
border-radius: 4px;
overflow:hidden;
}
.inner {
position: absolute;
width: 100%;
height: 100%;
display: -webkit-flex;
-webkit-align-items: center;
display: flex;
align-items: center;
justify-content: center;
background: #eee;
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="wrapper ">
<div class="inner"> Center </div>
</div>
<br />
<div id="slider"></div>

build semi circle progress bar with round corners and shadow in java script and CSS

I searched a lot and finding nothing on it. I want to make a progress bar with round corners.progress bar need to have shadow. All I did as of now is here :
$(".progress-bar").each(function(){
var bar = $(this).find(".bar");
var val = $(this).find("span");
var per = parseInt( val.text(), 10);
$({p:0}).animate({p:per}, {
duration: 3000,
easing: "swing",
step: function(p) {
bar.css({
transform: "rotate("+ (45+(p*1.8)) +"deg)"
});
val.text(p|0);
}
});
});
body{
background-color:#3F63D3;
}
.progress-bar{
position: relative;
margin: 4px;
float:left;
text-align: center;
}
.barOverflow{
position: relative;
overflow: hidden;
width: 150px; height: 70px;
margin-bottom: -14px;
}
.bar{
position: absolute;
top: 0; left: 0;
width: 150px; height: 150px;
border-radius: 50%;
box-sizing: border-box;
border: 15px solid gray;
border-bottom-color: white;
border-right-color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="progress-bar">
<div class="barOverflow">
<div class="bar"></div>
</div>
<span>100</span>%
</div>
I want to make corners round and having shadow. below given image represent what actually i want. Shadow is missing because i don't know to draw. :
I have tried Progressbar.js also, but I don't have much knowledge about SVG. Any answer would be appreciated.
#jaromanda for suggestion of learning SVG.
Yes is looks very hard to achieve from border-radius. So i looked into SVG and find it pretty handy. Here is my snippet:
// progressbar.js#1.0.0 version is used
// Docs: http://progressbarjs.readthedocs.org/en/1.0.0/
var bar = new ProgressBar.SemiCircle(container, {
strokeWidth: 10,
color: 'red',
trailColor: '#eee',
trailWidth: 10,
easing: 'easeInOut',
duration: 1400,
svgStyle: null,
text: {
value: '',
alignToBottom: false
},
// Set default step function for all animate calls
step: (state, bar) => {
bar.path.setAttribute('stroke', state.color);
var value = Math.round(bar.value() * 100);
if (value === 0) {
bar.setText('');
} else {
bar.setText(value+"%");
}
bar.text.style.color = state.color;
}
});
bar.text.style.fontFamily = '"Raleway", Helvetica, sans-serif';
bar.text.style.fontSize = '2rem';
bar.animate(0.45); // Number from 0.0 to 1.0
#container {
width: 200px;
height: 100px;
}
svg {
height: 120px;
width: 200px;
fill: none;
stroke: red;
stroke-width: 10;
stroke-linecap: round;
-webkit-filter: drop-shadow( -3px -2px 5px gray );
filter: drop-shadow( -3px -2px 5px gray );
}
<script src="https://rawgit.com/kimmobrunfeldt/progressbar.js/1.0.0/dist/progressbar.js"></script>
<link href="https://fonts.googleapis.com/css?family=Raleway:400,300,600,800,900" rel="stylesheet" type="text/css">
<div id="container"></div>
I want to suggest some stupid but quick solution since you're already using position: absolute. You can add background color to the circles when your animation starts.
html:
<div class="progress-bar">
<div class="left"></div>
<div class="right"><div class="back"></div></div>
<div class="barOverflow">
<div class="bar"></div>
</div>
<span>0</span>%
</div>
css:
/** all your css here **/
body{
background-color:#3F63D3;
}
.progress-bar{
position: relative;
margin: 4px;
float: left;
text-align: center;
}
.barOverflow{
position: relative;
overflow: hidden;
width: 150px; height: 70px;
margin-bottom: -14px;
}
.bar{
position: absolute;
top: 0; left: 0;
width: 150px; height: 150px;
border-radius: 50%;
box-sizing: border-box;
border: 15px solid gray;
border-bottom-color: white;
border-right-color: white;
transform: rotate(45deg);
}
.progress-bar > .left {
position: absolute;
background: white;
width: 15px;
height: 15px;
border-radius: 50%;
left: 0;
bottom: -4px;
overflow: hidden;
}
.progress-bar > .right {
position: absolute;
background: white;
width: 15px;
height: 15px;
border-radius: 50%;
right: 0;
bottom: -4px;
overflow: hidden;
}
.back {
width: 15px;
height: 15px;
background: gray;
position: absolute;
}
jquery:
$(".progress-bar").each(function(){
var bar = $(this).find(".bar");
var val = $(this).find("span");
var per = parseInt( val.text(), 10);
var $right = $('.right');
var $back = $('.back');
$({p:0}).animate({p:per}, {
duration: 3000,
step: function(p) {
bar.css({
transform: "rotate("+ (45+(p*1.8)) +"deg)"
});
val.text(p|0);
}
}).delay( 200 );
if (per == 100) {
$back.delay( 2600 ).animate({'top': '18px'}, 200 );
}
if (per == 0) {
$('.left').css('background', 'gray');
}
});
https://jsfiddle.net/y86qs0a9/7/
Same as the answers above, I found it much easier to implement using SVG instead of pure CSS.
However I couldn't find a single simplistic implementation using only HTML and CSS, or at least with no libraries, no external scripts or no dependencies. I found that given the math that needs to be calculated to make the SVG transformations to represent the percentage, JS needs to be included (if someone knows how to achieve this with only HTML and CSS I'd love to learn how). But what the JS script does is not long or complex enough to justify the overhead of adding yet another dependency to my codebase.
The JS calculations are pretty easy once you read through. You need to calculate the coordinate for the end point of the gauge in the coordinate system of the SVG. so basic trig.
Most of the CSS is not even needed and I added just to style it and to make it pretty. You can add shadow or gradients same as you could with any HTML pure shape.
Here is the codePen https://codepen.io/naticaceres/pen/QWQeyGX
You can easily tinker with this code to achieve any kind of shape of circular gauge (full circle, lower half of the semi-circle, or any variation including ellipsis).
Hope this is helpful.
// # Thanks to mxle for the first rounded corner CSS only solution https://stackoverflow.com/a/42478006/4709712
// # Thanks to Aniket Naik for the styling and the basic idea and implementation https://codepen.io/naikus/pen/BzZoLL
// - Aniket Naik has a library, linked to that codepen you should check out if you don't want to copy-paste or implement yourself
// the arc radius in the meter-value needs to stay the same, and must always be x=y, not lower than the possible circle that can connect the two points (otherwise the ratio is not preserved and the curvature doesn't match the background path).
// to style the gauge, make it bigger or smaller, play with its parent element and transform scale. don't edit width and height of SVG directly
function percentageInRadians(percentage) {
return percentage * (Math.PI / 100);
}
function setGaugeValue(gaugeElement, percentage, color) {
const gaugeRadius = 65;
const startingY = 70;
const startingX = 10;
const zeroBasedY = gaugeRadius * Math.sin(percentageInRadians(percentage));
const y = -zeroBasedY + startingY;
const zeroBasedX = gaugeRadius * Math.cos(percentageInRadians(percentage));
const x = -zeroBasedX + gaugeRadius + startingX;
// # uncomment this to log the calculations of the coordinates for the final point of the gauge value path.
//console.log(
// `percentage: ${percentage}, zeroBasedY: ${zeroBasedY}, y: ${y}, zeroBasedX: ${zeroBasedX}, x: ${x}`
//);
gaugeElement.innerHTML = `<path d="M ${startingX} ${startingY}
A ${gaugeRadius} ${gaugeRadius} 0 0 1 ${x} ${y}
" stroke="${color}" stroke-width="10" stroke-linecap="round" />`;
}
percentageChangedEvent = (gauge, newPercentage, color) => {
const percentage =
newPercentage > 100 ? 100 : newPercentage < 0 ? 0 : newPercentage;
setGaugeValue(gauge, percentage, color);
};
function initialGaugeSetup(gaugeElementId, inputId, meterColor, initialValue) {
const gaugeElement = document.getElementById(gaugeElementId);
setGaugeValue(gaugeElement, 0, meterColor);
const inputElement = document.getElementById(inputId);
inputElement.value = initialValue;
setGaugeValue(gaugeElement, initialValue, meterColor);
inputElement.addEventListener("change", (event) =>
percentageChangedEvent(gaugeElement, event.target.value, meterColor)
);
}
// Gauge Initial Config
initialGaugeSetup(
"svg-graph-meter-value",
"svg-gauge-percentage-2",
"rgb(227 127 215)",
40
);
body {
background-color: rgba(0, 0, 0, 0.8);
color: #999;
font-family: Hevletica, sans-serif;
}
/* SVG Path implementation */
.svg-container {
margin: 20px auto 10px;
height: 80px;
width: 150px;
}
svg {
fill: transparent;
}
.input-percent-container {
text-align: center;
}
.input-percent-container>* {
display: inline;
}
input {
text-align: right;
width: 40px;
margin: auto;
background-color: #5d5d5d;
color: white;
border-radius: 6px;
border: black;
}
<div class="svg-container">
<svg width="150" height="80" xmlns="http://www.w3.org/2000/svg">
<path d="M 10 70
A 65 65 0 1 1 140 70
" stroke="grey" stroke-width="3" stroke-linecap="round" />
<g id="svg-graph-meter-value">
</g>
</svg>
</div>
<div class="input-percent-container"><input id="svg-gauge-percentage-2" /><span>%<span/></div>

Download whole canvas with background image when download button pressed

i use the sketch.js plugin to draw a diagram in my site and i need to user to change the background as his/her wish and after when click download button i need get the whole image with drawn contents as a png/jpg my basic code as follows.
i can download the drawn things but not the background image any idea or guide how to achieve this???Any suggestions than sketch.js?
/*jquery scripts*/
var canvas;
$(function() {
$.each(['#f00', '#ff0', '#0f0', '#0ff', '#00f', '#f0f', '#000', '#fff'], function() {
$('#colors_demo .tools .brushes').append("<a class='color_box' href='#colors_sketch' data-color='" + this + "'style='width:25px; background:" + this + ";'></a> ");
});
$.each([3, 5, 10, 15], function() {
$('#colors_demo .tools .brushes').append("<a href='#colors_sketch' data-size='" + this + "' style='background: #ccc'>" + this + "</a> ");
});
$('#colors_sketch').sketch();
$("#sel1").change(function() {
if ($(this).val() === '1') {
var img = 'image/plans/plan1.jpg';
}
if ($(this).val() === '2') {
var img = 'image/plans/plan2.jpg';
}
/// set size
$('#colors_sketch').globalCompositeOperation = "destination-over";
$('#colors_sketch').css("background-image", "url(" + img + ")");
$('#colors_sketch').height = $('#colors_sketch').width * (img.height / img.width);
$('#colors_sketch').drawImage(backgroundImage, 0, 0);
});
$('#downloadlink').click(function() {
var canvas = $('#colors_sketch')[0];
var ctx = canvas.getContext('2d');
var img = new Image;
img.onload = function() {
ctx.drawImage(this, 0, 0);
};
this.href = $('#colors_sketch')[0].toDataURL(); // Change here
this.download = 'design.png';
});
});
.demo {
margin-top: 10px;
}
#colors_sketch {
float: right;
width: 75%;
height: 90%;
border: 2px solid #dede22;
border-radius: 10px;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: 10px;
display: block;
}
a.color_box {
height: 25px;
display: inline-block;
border: 2px solid #000;
}
#plans {
border: 2px solid #2ee;
width: 20%;
/*height:90%;*/
float: left;
}
.tools {
width: 50%;
height: 25%;
padding-left: 0;
padding-right: 0;
margin: 0 auto;
display: block;
}
.downloadbtn {
background
}
.dragable_plans {
width: 200px;
height: 100px;
}
#sel1 {
width: 10%;
display: inline-block;
}
#container {
width: 100%;
height: 90%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsxgraph/0.99.3/sketch.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<body>
<div class="demo" id="colors_demo">
<div class="form-group">
<div class="tools" style="margin-bottom:10px">
<label for="color tools">Pen Colors and Sizes:</label>
<div class="brushes"></div>
<label for="sel1">Select Diagram Type:</label>
<select class="form-control" id="sel1">
<option value='1'>Plan1</option>
<option value='2'>Plan2</option>
</select>
<a id="downloadlink" href="#colors_sketch" type="button" class="btn btn-success form-control" style="float: right; width: 100px;">Download</a>
</div>
</div>
<div id="container">
<div id="plans">
</div>
<canvas id="colors_sketch"></canvas>
</div>
</div>
</body>
If I understand you right you want to have a png dump out of a JSXGraph construction?
In the nightly builds of JSXGraph there is the method dumpToCanvas available - if you use the SVG renderer. That means, if you have a JSXGraph construction like this
<div id='box1' class='jxgbox' style='width:500px; height:500px;'></div>
<canvas id='pngoutput' style='width:500px; height:500px;'></canvas>
<script type='text/javascript'>
var board = JXG.JSXGraph.initBoard('box1', {
axis: true, boundingbox: [-1, 1, 1, -1]
});
you can write a png of the JSXGraph in box1 to the canvas element pngoutput by calling
board.renderer.dumpToCanvas('pngoutput');

Categories

Resources