How to randomise background colour and svg - javascript

I'm trying to make a basic landing page which randomises the background colour each time the page loads and also changes each time you click on the svg icon.
This is working okay so far, however is it possible to also randomise the colour of the icon rather than it just being white? I'm having trouble integrating the colour property of the svg into the javascript. Here is the code I'm currently using:
$(function() {
var randomColor = Math.floor(Math.random() * 16777215).toString(16);
$("body").css({
backgroundColor: '#' + randomColor
});
$("#colorcode").text("#" + randomColor);
});
var safeColors = ['00', '33', '66', '99', 'cc', 'ff'];
var rand = function() {
return Math.floor(Math.random() * 6);
};
var randomColor = function() {
var r = safeColors[rand()];
var g = safeColors[rand()];
var b = safeColors[rand()];
return "#" + r + g + b;
};
$("body").css({
backgroundColor: '#' + randomColor
});
$(document).ready(function() {
$('#Layer_1').click(function() {
$('body').each(function() {
$(this).css('background', randomColor());
});
});
});
.cls-1 {
fill: #fff;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js">
</script>
<div style="width:400px; position:absolute; left:50%; top:50%; margin:-200px 0 0 -200px; cursor: pointer">
<svg data-name="Layer 1" id="Layer_1" viewbox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
<title>Artboard 1</title>
<polygon class="cls-1" points="276 124 276 0 124 0 124 124 0 124 0 276 124 276 124 400 276 400 276 276 400 276 400 124 276 124"></polygon>
</svg>
Many thanks for your help. I'm quite new to Javascript so this is a bit of a learning curve for me.

You can change the color of svg by applying the fill CSS property to the svg element (in your case, the polygon)
$('#Layer_1 polygon').css('fill', randomColor());
$(function() {
var randomColor = Math.floor(Math.random() * 16777215).toString(16);
$("body").css({
backgroundColor: '#' + randomColor
});
$("#colorcode").text("#" + randomColor);
});
var safeColors = ['00', '33', '66', '99', 'cc', 'ff'];
var rand = function() {
return Math.floor(Math.random() * 6);
};
var randomColor = function() {
var r = safeColors[rand()];
var g = safeColors[rand()];
var b = safeColors[rand()];
return "#" + r + g + b;
};
$("body").css({
backgroundColor: '#' + randomColor
});
$(document).ready(function() {
$('#Layer_1').click(function() {
$('body').css('background', randomColor());
$('#Layer_1 polygon').css('fill', randomColor());
});
});
#svgdiv {
width: 400px;
position: absolute;
left: 50%;
top: 50%;
margin: -200px 0 0 -200px;
cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="svgdiv">
<svg data-name="Layer 1" id="Layer_1" viewbox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
<polygon class="cls-1" points="276 124 276 0 124 0 124 124 0 124 0 276 124 276 124 400 276 400 276 276 400 276 400 124 276 124"></polygon>
</svg>
</div>

Sure, you Jquery can be simplified too.
just need to change the fill of.cls-1
var safeColors = ['00', '33', '66', '99', 'cc', 'ff'];
var rand = function() {
return Math.floor(Math.random() * 6);
};
var randomColor = function() {
var r = safeColors[rand()];
var g = safeColors[rand()];
var b = safeColors[rand()];
return "#" + r + g + b;
};
$(document).ready(function() {
$('.cls-1').css('fill', randomColor());
$('body').css('background', randomColor());
$('#Layer_1').click(function() {
$('.cls-1').css('fill', randomColor());
$('body').css('background', randomColor());
});
});
.cross {
width: 400px;
position: absolute;
left: 50%;
top: 50%;
margin: -200px 0 0 -200px;
cursor: pointer;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js">
</script>
<div class="cross">
<svg data-name="Layer 1" id="Layer_1" viewbox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
<title>Artboard 1</title>
<polygon class="cls-1" points="276 124 276 0 124 0 124 124 0 124 0 276 124 276 124 400 276 400 276 276 400 276 400 124 276 124"></polygon>
</svg>

you can target your svg icon the same as the background, but you need to use "fill" instead of "background-color"
try replacing with this:
$(document).ready(function() {
$(".cls-1").css("fill",randomColor())
$('#Layer_1').click(function() {
$('body').each(function() {
$(this).css('background',randomColor());
$(".cls-1").css("fill",randomColor())
});
});
});

The smallest code!Enjoy it!
function changecolor() {
var colors = ["red", "blue", "yellow"];
Shuffle(colors);
document.body.style.backgroundColor = colors[0];
}
function Shuffle(o) {
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
<body onload="changecolor()">
<h1>Hello World!</h1>
</body>

Related

SVG path created with JS doesnt show

I want to create/draw paths (lines) in a SVG using Javascript. But for some reason the lines don't show, even though the html is generated. Is there something i am missing, can you have a look at my code and tell me why it doesn't show?
This is mz JS code
//add lines from layerborderbot to ldescborderbot
var _Ldesc = document.createElement('svg');
_Ldesc.style.cssText = `position:absolute;left:calc(26vw + 3px);top:calc(66mm + 2px);width:calc(2.1vw + 1px);height:${scaleLength(Math.ceil(layerTotalLengthN)*100)}cm;`;
for (x = 0; layer_anzahl > x; x++) {
var _lineLdesc = document.createElementNS("http://www.w3.org/2000/svg", 'path'); //Create a path in SVG's namespace
var tempPos; var tempHeight; var tY; var tH;
if(typeof positionLith[x+1] === 'undefined' && dHdesc[x] < 0) {tY = cm2px(parseFloat(scaleLength(layerTotalLengthN*100))); tH = cm2px(dHdesc[x]);}
else { tY = cm2px(scaleLength(parseFloat(lith_to[x+1])*100));}
if(dHdesc[x] > 0) { tY = cm2px(scaleLength(parseFloat(lith_to[x])*100)); tH = cm2px(getlayersize(x));}
else { if (x==0 && dHdesc[0]<0) { tH = cm2px(realHeightLdesc[x] - getlayersize(x));}
else if (x==0 && dHdesc[0]>0) { tH = cm2px(getlayersize(x));}
else {
if(occupyDesc[x] > 0) { tH = cm2px(occupyDesc[x]-getlayersize(x));}
else { tH = cm2px(realHeightLdesc[x]-getlayersize(x));}
}
}
_lineLdesc.setAttribute("d",`M 0 ${tY} L ${vw2px(2.1)} ${tH}`); //Set path's data
_lineLdesc.style.stroke = "#000"; //Set stroke colour
_lineLdesc.style.strokeWidth = "1"; //Set stroke width
_Ldesc.appendChild(_lineLdesc);
This is the HTML output (from chrome console)
<svg style="position: absolute; left: calc(26vw + 3px); top: calc(251.449px); width: calc(2.1vw + 1px); height: 12cm;">
<path d="M 0 151.18110426684856 L 33 151.18110426684856" style="stroke: rgb(0, 0, 0); stroke-width: 1;"></path>
<path d="M 0 434.64567476718963 L 33 15.807083450280626" style="stroke: rgb(0, 0, 0); stroke-width: 1;"></path>
<path d="M 0 434.64567476718963 L 33 226.77165640027278" style="stroke: rgb(0, 0, 0); stroke-width: 1;"></path>
</svg>
You don't specify a viewBox, so it defaults to 300x150.
Yet the 3 Lines you draw require a viewBox="0 0 34 435" to show all of those Lines:
<style>
svg{
height:180px;
background:pink;
}
</style>
<svg viewBox="0 0 34 435" stroke-width="3">
<path d="M 0 151.1 L 33 151.1" stroke="blue"></path>
<path d="M 0 434.6 L 33 15.8" stroke="red"></path>
<path d="M 0 434.6 L 33 226.7" stroke="green"></path>
</svg>

JQuery draggable element controlling a SVG object jumping for the first time

I have to adjust a SVG's position and scale using DIV having handles.
Everything is working as expected except SVG is jumping the first time at the time of dragging the div handles. Only the SVG is jumping.
See here that the class "selection" is a DIV controlling the selected SVG with attribute ("[selection=true]")
$( ".selector" ).resizable({
aspectRatio: false,
handles: {
'nw': '#nwgrip',
'ne': '#negrip',
'sw': '#swgrip',
'se': '#segrip' },
resize: function(event, ui) {
console.log(ui.size.width);
$('#posW').text('Width: ' + Math.round(ui.size.width) );
$('#posH').text('Height: ' + Math.round(ui.size.height) );
$("[selection=true]").attr("width", Math.round(ui.size.width) );
$("[selection=true]").attr("height", Math.round(ui.size.height) );
$("[selection=true]").attr("x", Math.round(ui.position.left) );
$("[selection=true]").attr("y", Math.round(ui.position.top) );
}
}).draggable({
drag: function(event, ui) {
var offset = $(this).offset();
var xPos = offset.left;
var yPos = offset.top;
$("[selection=true]").attr("x", Math.round(xPos) );
$("[selection=true]").attr("y", Math.round(yPos) );
$('#posX').text('x: ' + xPos);
$('#posY').text('y: ' + yPos);
}
}
);
Please check jsfiddle link
Is this a bug that can be fixed?
Here's a working version of your original. It handles all clicking, dragging, and selector box behaviour within the "canvas" SVG.
It uses pure JS and manipulates the badge <svg> and selector box elements using DOM methods.
Hopefully it is fairly easily to follow what is going on.
let selectedBadge = null;
let isDraggingRect = null;
let isDraggingHandle = null;
let dragOffsetX = 0;
let dragOffsetY = 0;
// Event handlers for the badges
let badges = document.querySelectorAll(".canvas > .badge");
badges.forEach(b => b.addEventListener("click", select));
// Event handlers for selector box and handles
let selectorRect = document.querySelector("#selector rect");
selectorRect.addEventListener("mousedown", selectorMouseDown);
let handleNW = document.getElementById("nwgrip");
let handleNE = document.getElementById("negrip");
let handleSW = document.getElementById("swgrip");
let handleSE = document.getElementById("segrip");
let grips = document.querySelectorAll("#selector > circle");
grips.forEach(g => {
g.addEventListener("mousedown", gripMouseDown);
});
// Attach mousemove and mouseup events to SVG for dragging purposes
// We attach to the parent SVG because mouse events on small elements
// will be missed if you move the mouse outside the element.
let canvasSVG = document.querySelector("#svg_obj > .canvas");
canvasSVG.addEventListener("mousemove", mouseMove);
canvasSVG.addEventListener("mouseup", mouseUp);
// select a badge
function select(evt) {
hideSelector(selectedBadge);
selectedBadge = evt.target.ownerSVGElement;
showSelector(selectedBadge)
}
function showSelector(badge) {
setSelectorDimensionsTo({x: badge.x.baseVal.value,
y: badge.y.baseVal.value,
width: badge.width.baseVal.value,
height: badge.height.baseVal.value});
document.getElementById("selector").classList.add("show");
}
function hideSelector(badge) {
if (selectedBadge) {
document.getElementById("selector").classList.remove("show");
selectedBadge = null;
}
}
function setSelectorDimensionsTo(bounds) {
selectorRect.x.baseVal.value = bounds.x;
selectorRect.y.baseVal.value = bounds.y;
selectorRect.width.baseVal.value = bounds.width;
selectorRect.height.baseVal.value = bounds.height;
handleNW.cx.baseVal.value = bounds.x;
handleNW.cy.baseVal.value = bounds.y;
handleNE.cx.baseVal.value = bounds.x + bounds.width;
handleNE.cy.baseVal.value = bounds.y;
handleSW.cx.baseVal.value = bounds.x;
handleSW.cy.baseVal.value = bounds.y + bounds.height;
handleSE.cx.baseVal.value = bounds.x + bounds.width;
handleSE.cy.baseVal.value = bounds.y + bounds.height;
}
function moveSelectorTo(x, y) {
selectorRect.x.baseVal.value = x;
selectorRect.y.baseVal.value = y;
let w = selectorRect.width.baseVal.value;
let h = selectorRect.height.baseVal.value;
handleNW.cx.baseVal.value = x;
handleNW.cy.baseVal.value = y;
handleNE.cx.baseVal.value = x + w;
handleNE.cy.baseVal.value = y;
handleSW.cx.baseVal.value = x;
handleSW.cy.baseVal.value = y + h;
handleSE.cx.baseVal.value = x + w;
handleSE.cy.baseVal.value = y + h;
}
function moveSelectedBadgeTo(x, y) {
selectedBadge.x.baseVal.value = x;
selectedBadge.y.baseVal.value = y;
}
function selectorMouseDown(evt) {
isDraggingRect = selectedBadge;
let mousePos = mouseCoordsToSVGCoords(evt.offsetX, evt.offsetY);
dragOffsetX = mousePos.x - selectedBadge.x.baseVal.value;
dragOffsetY = mousePos.y - selectedBadge.y.baseVal.value;
}
function mouseUp(evt) {
isDraggingRect = null;
isDraggingHandle = null;
}
// Handles both:
// - dragging selector rect
// - dragging selector grip/handle
function mouseMove(evt) {
if (isDraggingRect)
{
// Move selector
let mousePos = mouseCoordsToSVGCoords(evt.offsetX, evt.offsetY);
moveSelectorTo(mousePos.x - dragOffsetX, mousePos.y - dragOffsetY);
// Move badge
moveSelectedBadgeTo(mousePos.x - dragOffsetX, mousePos.y - dragOffsetY);
}
else if (isDraggingHandle)
{
gripMouseMove(evt);
}
}
// Convert page mouse coords to SVG coords.
// Takes into account any scaling due to the presence of a viewBox.
function mouseCoordsToSVGCoords(mouseX, mouseY) {
var pt = canvasSVG.createSVGPoint();
pt.x = mouseX;
pt.y = mouseY;
return pt.matrixTransform(canvasSVG.getScreenCTM().inverse());
}
function gripMouseDown(evt) {
isDraggingHandle = evt.target;
let mousePos = mouseCoordsToSVGCoords(evt.offsetX, evt.offsetY);
dragOffsetX = mousePos.x - isDraggingHandle.cx.baseVal.value;
dragOffsetY = mousePos.y - isDraggingHandle.cy.baseVal.value;
}
function gripMouseUp(evt) {
isDraggingHandle = null;
}
function gripMouseMove(evt) {
// Move handle thus resizing selector
let mousePos = mouseCoordsToSVGCoords(evt.offsetX, evt.offsetY);
mousePos.x -= dragOffsetX;
mousePos.y -= dragOffsetY;
let bounds = {};
let oldX = selectorRect.x.baseVal.value;
let oldY = selectorRect.y.baseVal.value;
let oldW = selectorRect.width.baseVal.value;
let oldH = selectorRect.height.baseVal.value;
switch (isDraggingHandle.id) {
case "nwgrip":
bounds = {x: mousePos.x, y: mousePos.y, width: oldX + oldW - mousePos.x, height: oldY + oldH - mousePos.y};
break;
case "negrip":
bounds = {x: oldX, y: mousePos.y, width: mousePos.x - oldX, height: oldY + oldH - mousePos.y};
break;
case "swgrip":
bounds = {x: mousePos.x, y: oldY, width: oldX + oldW - mousePos.x, height: mousePos.y - oldY};
break;
case "segrip":
bounds = {x: oldX, y: oldY, width: mousePos.x - oldX, height: mousePos.y - oldY};
break;
}
setSelectorDimensionsTo(bounds);
// Resize badge
resizeBadgeTo(bounds);
}
function resizeBadgeTo(bounds) {
selectedBadge.x.baseVal.value = bounds.x;
selectedBadge.y.baseVal.value = bounds.y;
selectedBadge.width.baseVal.value = bounds.width;
selectedBadge.height.baseVal.value = bounds.height;
}
.canvas {
background-color: #cecece;
border: 2px solid #cecece;
width: 400px;
height: 400px;
position: relative;
}
#svg_obj {
position: absolute;
width: 100px;
height: 100px;
background: yellow;
}
#selector {
display: none;
}
#selector.show {
display: block;
}
#selector rect {
fill: transparent;
stroke: #f50;
stroke-width: 1px;
}
#nwgrip, #negrip, #swgrip, #segrip, #ngrip, #egrip, #sgrip, #wgrip {
fill: #ffffff;
stroke: #000000;
stroke-width: 1px;
}
<div id='svg_obj'>
<svg class="canvas" viewBox="0 0 400 400" width="400" height="400" >
<svg class="badge" width="200" height="200" viewBox="0 0 400 400">
<g>
<polygon fill="#21574B" points="342.6,0 324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 57.3,308.3 200,400
342.6,308.3 "/>
<polygon fill="#578677" points="342.6,0 324.1,19.8 75.8,19.8 75.8,294.2 57.3,308.3 57.3,0 "/>
<polygon fill="#8CB2B0" points="324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 75.8,19.8 "/>
</g>
</svg>
<svg class="badge" width="200" height="200" viewBox="0 0 400 400">
<g>
<polygon fill="#F1F74B" points="342.6,0 324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 57.3,308.3 200,400
342.6,308.3 "/>
<polygon fill="#578677" points="342.6,0 324.1,19.8 75.8,19.8 75.8,294.2 57.3,308.3 57.3,0 "/>
<polygon fill="#8CB2B0" points="324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 75.8,19.8 "/>
</g>
</svg>
<svg class="badge" width="200" height="200" viewBox="0 0 400 400">
<g>
<polygon fill="#81579B" points="342.6,0 324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 57.3,308.3 200,400
342.6,308.3 "/>
<polygon fill="#578677" points="342.6,0 324.1,19.8 75.8,19.8 75.8,294.2 57.3,308.3 57.3,0 "/>
<polygon fill="#8CB2B0" points="324.1,19.8 324.1,294.2 302.3,308.3 200,374.1 97.7,308.3 75.8,294.2 75.8,19.8 "/>
</g>
</svg>
<g id="selector">
<rect width="20" height="20"/>
<circle cx="0" cy="0" r="5" id="nwgrip"/>
<circle cx="20" cy="0" r="5" id="negrip"/>
<circle cx="0" cy="20" r="5" id="swgrip"/>
<circle cx="20" cy="20" r="5" id="segrip"/>
</g>
</svg>
</div>

Why won't this text animation code work when I copy it into PHPStorm from Pen?

I'm trying to get https://codepen.io/alticreation/pen/ZYdopE to work in my project on PHPStorm but it only partially works.
The main logo portion - Alticreation in the Pen - does not appear at all while the Made with .... portion does.
Why is this?
I copied the three sets of code into separate HTML, CSS and Javascript files in PHPStorm.
My code is:
window.onload = function () {
var blue = '#2980b9';
var l = Snap('#logo');
var p = l.select('path');
l.append(p);
p.attr({
fill: blue,
stroke: '#0066CC',
});
setTimeout( function() {
// modify this one line below, and see the result !
var logoTitle = 'alticreation';
var logoRandom = '';
var logoTitleContainer = l.text(0, '98%', '');
var possible = "-+*/|}{[]~\\\":;?/.><=+-_)(*&^%$##!)}";
logoTitleContainer.attr({
fontSize: 280,
fontFamily: 'Dosis',
fontWeight: '600'
});
function generateRandomTitle(i, logoRandom) {
setTimeout( function() {
logoTitleContainer.attr({ text: logoRandom });
}, i*70 );
}
for( var i=0; i < logoTitle.length+1; i++ ) {
logoRandom = logoTitle.substr(0, i);
for( var j=i; j < logoTitle.length; j++ ) {
logoRandom += possible.charAt(Math.floor(Math.random() * possible.length));
}
generateRandomTitle(i, logoRandom);
logoRandom = '';
}
}, 500 );
}
#container {
left: 50%;
top: 50%;
position: absolute;
transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<head>
<link rel="stylesheet" style="text/css" href="words.css">
</head>
<body>
<div id="container">
<svg xmlns="http://www.w3.org/2000/svg" id="logo" viewBox="0 0 1252 600" width="250px">
<path fill="none" d="M531.3 11.2S520.6.5 509.5.5c-11 0-25.4 11.3-25.4 11.3L11 360s-16 12-7.4 24c8.8 12.2 25.5 1.5 25.5 1.5L499 112s6.6-4.2 10.3-4c3 .2 7.7 4 7.7 4l283 229s4 3 6 3c2.7.2 7.4-3.3 7.4-3.3l210-145.4s2.2-1.7 3.6-1.7c1 0 3.4 1.7 3.4 1.7l189.3 144.5s15.8 12.8 27.2.3c11-12-4-27-4-27l-196.7-181s-7.3-7.5-15.8-8c-8.6-.4-19.8 7.8-19.8 7.8l-196.2 122s-5.5 4-8.6 4c-2.6-.3-6.5-4-6.5-4z"/>
</svg>
</div>
<div style="font-family:'Dosis'; font-weight:bold; color:#888; text-align:center;margin-top:20px">made with <span style="color:rgb(199, 59, 84)">♥</span> by <a style="color:#999;text-decoration:none;border-bottom:1px dashed #555" href="http://www.alticreation.com/en" title="front end developer" target="_blank">alexis blondin</a></div>
</div>
</body>
</html>
Aaah, I just realised the proper way to use the code is to export it from Pen. It now works on my machine. Thanks all.

controling svg clock with setInterval

I made an svg clock :
<svg baseProfile="basic" viewBox="0 0 200 200" preserveAspectRatio="xMidYMin" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="aiguilles">
<g id="heures" visibility="hidden">
<path fill="#555" d="M94.9,38.8v11l-6,8.2l6.3,9.3L95,92.9c-2.2,1.6-3.7,4.2-3.7,7.1s1.4,5.5,3.6,7l-0.1,12.7l5.3,3.5v-14.5 c0-4.6,0-13.1,0-17.5V33.9L94.9,38.8z"/>
<path fill="#bbb" d="M105,92.9l-0.2-25.6l6.3-9.3l-6-8.2v-11l-5.1-5v57.4c0,5.7,0,12,0,17.5v14.5l5.3-3.5l-0.1-12.7 c2.2-1.6,3.6-4.1,3.6-7C108.7,97.1,107.3,94.5,105,92.9z"/>
<polygon fill="#fff" points="100,69.7 92.6,58.1 100,47.5 107.4,58.1 "/>
</g>
<g id="minutes" visibility="hidden">
<path fill="#777" d="M95.6,9.7v84.9c-1.6,1.3-2.5,3.2-2.5,5.4s1,4.1,2.5,5.4v14.8l4.4,2.6V5.3L95.6,9.7z"/>
<path fill="#ddd" d="M106.9,100c0-2.1-1-4.1-2.5-5.3v-85L100,5.3V93l0,0c0,3,0,10.4,0,13.9l0,0v15.9l4.4-2.6v-14.9 C105.9,104.1,106.9,102.2,106.9,100z"/>
<polygon fill="#fff" points="97.7,17.5 97.7,69.4 100,71.9 102.3,69.4 102.3,17.5 100,15.4 "/>
</g>
<g id="secondes" visibility="hidden">
<path fill="#bbb" d="M101,95.5c0-33.1,0-54.1,0-67.4c2.5-0.5,4.4-2.7,4.4-5.3s-1.9-4.8-4.4-5.3c0-12.4,0-12.7,0-13.3 c0-0.8-0.5-1.8-1-2c-0.6,0.3-1,1.2-1,2c0,0.6,0,0.9,0,13.3c-2.5,0.5-4.4,2.7-4.4,5.3s1.9,4.8,4.4,5.3c0,13.3,0,34.3,0,67.4 c-2.2,0.5-3.8,2.4-3.8,4.7c0,1.2,0.5,2.3,1.2,3.1V122l3.7,3.3l3.7-3.3v-18.7c0.7-0.8,1.2-1.9,1.2-3.1 C104.8,97.9,103.2,95.9,101,95.5z"/>
<circle fill="#FFF" cx="100" cy="22.7" r="3.7"/>
</g>
</g>
</svg>
and I suceeded in animating the hands so that they first go from 12:00 to the current time with the "toTimeNow" function and then show the time continuously with the "timeNow" function :
var tailleAiguilles = 2;
var aiguillesGauche = 250;
var aiguillesHaut = 250;
var aiguilles = document.getElementById("aiguilles");
function transformSvg() {
aiguilles.setAttribute("transform", "matrix(" + tailleAiguilles + " 0 0 " + tailleAiguilles + " " + aiguillesGauche + " " + aiguillesHaut + ")");
}
function toTimeNow() {
var hr = 0;
var mn = 0;
var sc = 0;
var interval = setInterval(function() {
var maintenant = new Date();
var heures = maintenant.getHours();
var minutes = maintenant.getMinutes();
var secondes = maintenant.getSeconds();
var milliSecondes = maintenant.getMilliseconds();
var secondes2 = 6 * secondes;
if (heures * 30 + minutes * 0.5 > 359) {
var angleHeures = heures * 30 + minutes * 0.5 - 359;
}
else {
var angleHeures = heures * 30 + minutes * 0.5;
}
var angleMinutes = minutes * 6 + (0.1 * secondes);
var angleSecondes = secondes2 += 0.006 * milliSecondes;
var max = Math.max(angleHeures, angleMinutes, angleSecondes)
if (hr < angleHeures) {
hr += angleHeures / max * 2;
rotation('heures', hr, 100);
}
if (mn < angleMinutes) {
mn += angleMinutes / max * 2;
rotation('minutes', mn, 100);
}
if (sc < angleSecondes) {
sc += angleSecondes / max * 2;
rotation('secondes', sc, 100);
}
else {
clearInterval(interval);
timeNow();
}
}, 5);
}
function timeNow() {
setInterval(function() {
var maintenant = new Date();
var heures = maintenant.getHours();
var minutes = maintenant.getMinutes();
var secondes = maintenant.getSeconds();
var milliSecondes = maintenant.getMilliseconds();
var secondes2 = 6 * secondes;
rotation('heures', heures * 30 + minutes * 0.5, 100);
rotation('minutes', minutes * 6 + (0.1 * secondes), 100);
rotation('secondes', secondes2 += 0.006 * milliSecondes, 100);
}, 50);
}
function rotation(id, angle, centre) {
var element = document.getElementById(id);
if (element) {
element.setAttribute('transform', 'rotate(' + angle + ', ' + centre + ', ' + centre + ')');
if (element.getAttribute('visibility') == 'hidden') {
element.setAttribute('visibility', 'visible');
}
}
}
window.addEventListener('load', toTimeNow, false);
But I noticed that just before the 2nd function takes over the hands move slightly backwards. If somebody could tell me why I'd appreciate it.
It is almost certainly because of this code:
if (mn < angleMinutes) {
mn += angleMinutes / max * 2;
rotation('minutes', mn, 100);
}
If mn is slightly less than angleMinutes, then this code can result in it stepping well past it. You should check mn after you increment it.
if (mn < angleMinutes) {
mn = Math.min(angleMinutes, mn + angleMinutes / max * 2);
rotation('minutes', mn, 100);
}

Interactive Doughnut Web Chart

I have a chart that i'm trying to make more user friendly and I keep running into issues trying to add one thing, something else goes wrong.
what im trying to accomplish is: Chart starts with one in 'hovered' state. When one is hovered on, it has a border as well as the text in the middle of the chart updates with the label and percentage. I would also like the background to be a SVG image (not important if not possible) .
I've made a fiddle - I would like to remove the tooltip too.
Any help would be greatly appreciated!
IMG of what im trying to accomplish:
my HTML code:
<div id="doughnutChart" class="chart"></div>
jQuery
jQuery(function(){
jQuery("#doughnutChart").drawDoughnutChart([
{ title: "Holiday Fund", value : 5, color: "#2C3E50" },
{ title: "Emergencies", value: 20, color: "#FC4349" },
{ title: "Loans", value: 20, color: "#6DBCDB" },
{ title: "Widows", value : 27, color: "#F7E248" },
{ title: "Medical Support", value : 28, color: "#D7DADB" },
]);
});
/*!
* jquery.drawDoughnutChart.js
* Version: 0.4.1(Beta)
* Inspired by Chart.js(http://www.chartjs.org/)
*
* Copyright 2014 hiro
* https://github.com/githiro/drawDoughnutChart
* Released under the MIT license.
*
*/
;(function($, undefined) {
$.fn.drawDoughnutChart = function(data, options) {
var $this = this,
W = $this.width(),
H = $this.height(),
centerX = W/2,
centerY = H/2,
cos = Math.cos,
sin = Math.sin,
PI = Math.PI,
settings = $.extend({
segmentShowStroke : true,
segmentStrokeColor : "#0C1013",
segmentStrokeWidth : 1,
baseColor: "rgba(0,0,0,0.5)",
baseOffset: 4,
edgeOffset : 10,//offset from edge of $this
percentageInnerCutout : 75,
animation : true,
animationSteps : 90,
animationEasing : "easeInOutExpo",
animateRotate : true,
tipOffsetX: -8,
tipOffsetY: -45,
tipClass: "doughnutTip",
summaryClass: "doughnutSummary",
summaryTitle: "",
summaryTitleClass: "doughnutSummaryTitle",
summaryNumberClass: "doughnutSummaryNumber",
beforeDraw: function() { },
afterDrawed : function() { },
onPathEnter : function(e,data) { },
onPathLeave : function(e,data) { }
}, options),
animationOptions = {
linear : function (t) {
return t;
},
easeInOutExpo: function (t) {
var v = t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t;
return (v>1) ? 1 : v;
}
},
requestAnimFrame = function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
}();
settings.beforeDraw.call($this);
var $svg = $('<svg width="' + W + '" height="' + H + '" viewBox="0 0 ' + W + ' ' + H + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>').appendTo($this),
$paths = [],
easingFunction = animationOptions[settings.animationEasing],
doughnutRadius = Min([H / 2,W / 2]) - settings.edgeOffset,
cutoutRadius = doughnutRadius * (settings.percentageInnerCutout / 100),
segmentTotal = 0;
//Draw base doughnut
var baseDoughnutRadius = doughnutRadius + settings.baseOffset,
baseCutoutRadius = cutoutRadius - settings.baseOffset;
$(document.createElementNS('http://www.w3.org/2000/svg', 'path'))
.attr({
"d": getHollowCirclePath(baseDoughnutRadius, baseCutoutRadius),
"fill": settings.baseColor
})
.appendTo($svg);
//Set up pie segments wrapper
var $pathGroup = $(document.createElementNS('http://www.w3.org/2000/svg', 'g'));
$pathGroup.attr({opacity: 0}).appendTo($svg);
//Set up tooltip
var $tip = $('<div class="' + settings.tipClass + '" />').appendTo('body').hide(),
tipW = $tip.width(),
tipH = $tip.height();
for (var i = 0, len = data.length; i < len; i++) {
segmentTotal += data[i].value;
$paths[i] = $(document.createElementNS('http://www.w3.org/2000/svg', 'path'))
.attr({
"stroke-width": settings.segmentStrokeWidth,
"stroke": settings.segmentStrokeColor,
"fill": data[i].color,
"data-order": i,
"class": 'counter-'+i
})
.appendTo($pathGroup)
.on("mouseenter", pathMouseEnter)
.on("mouseleave", pathMouseLeave)
.on("mousemove", pathMouseMove);
}
//Set up center text area
var summarySize = (cutoutRadius - (doughnutRadius - cutoutRadius)) * 2,
$summary = $('<div class="' + settings.summaryClass + '" />')
.appendTo($this)
.css({
width: summarySize + "px",
height: summarySize + "px",
"margin-left": -(summarySize / 2) + "px",
"margin-top": -(summarySize / 2) + "px"
});
var $summaryTitle = $('<p class="' + settings.summaryTitleClass + '">' + data[0].title + "<br />" + data[0].value + '%' + '</p>').appendTo($summary);
//var $summaryNumber = $('<p class="' + settings.summaryNumberClass + '"></p>').appendTo($summary).css({opacity: 0});
//Animation start
animationLoop(drawPieSegments);
//Functions
function getHollowCirclePath(doughnutRadius, cutoutRadius) {
//Calculate values for the path.
//We needn't calculate startRadius, segmentAngle and endRadius, because base doughnut doesn't animate.
var startRadius = -1.570,// -Math.PI/2
segmentAngle = 6.2831,// 1 * ((99.9999/100) * (PI*2)),
endRadius = 4.7131,// startRadius + segmentAngle
startX = centerX + cos(startRadius) * doughnutRadius,
startY = centerY + sin(startRadius) * doughnutRadius,
endX2 = centerX + cos(startRadius) * cutoutRadius,
endY2 = centerY + sin(startRadius) * cutoutRadius,
endX = centerX + cos(endRadius) * doughnutRadius,
endY = centerY + sin(endRadius) * doughnutRadius,
startX2 = centerX + cos(endRadius) * cutoutRadius,
startY2 = centerY + sin(endRadius) * cutoutRadius;
var cmd = [
'M', startX, startY,
'A', doughnutRadius, doughnutRadius, 0, 1, 1, endX, endY,//Draw outer circle
'Z',//Close path
'M', startX2, startY2,//Move pointer
'A', cutoutRadius, cutoutRadius, 0, 1, 0, endX2, endY2,//Draw inner circle
'Z'
];
cmd = cmd.join(' ');
return cmd;
};
function pathMouseEnter(e) {
var order = $(this).data().order;
$tip.text(data[order].title + ": " + data[order].value)
.fadeIn(200);
settings.onPathEnter.apply($(this),[e,data]);
$('.doughnutSummaryTitle').html(data[order].title + "<br />" + data[order].value + '%')
}
function pathMouseLeave(e) {
$tip.hide();
settings.onPathLeave.apply($(this),[e,data]);
}
function pathMouseMove(e) {
$tip.css({
top: e.pageY + settings.tipOffsetY,
left: e.pageX - $tip.width() / 2 + settings.tipOffsetX
});
}
function drawPieSegments (animationDecimal) {
var startRadius = -PI / 2,//-90 degree
rotateAnimation = 1;
if (settings.animation && settings.animateRotate) rotateAnimation = animationDecimal;//count up between0~1
//drawDoughnutText(animationDecimal, segmentTotal);
$pathGroup.attr("opacity", animationDecimal);
//If data have only one value, we draw hollow circle(#1).
if (data.length === 1 && (4.7122 < (rotateAnimation * ((data[0].value / segmentTotal) * (PI * 2)) + startRadius))) {
$paths[0].attr("d", getHollowCirclePath(doughnutRadius, cutoutRadius));
return;
}
for (var i = 0, len = data.length; i < len; i++) {
var segmentAngle = rotateAnimation * ((data[i].value / segmentTotal) * (PI * 2)),
endRadius = startRadius + segmentAngle,
largeArc = ((endRadius - startRadius) % (PI * 2)) > PI ? 1 : 0,
startX = centerX + cos(startRadius) * doughnutRadius,
startY = centerY + sin(startRadius) * doughnutRadius,
endX2 = centerX + cos(startRadius) * cutoutRadius,
endY2 = centerY + sin(startRadius) * cutoutRadius,
endX = centerX + cos(endRadius) * doughnutRadius,
endY = centerY + sin(endRadius) * doughnutRadius,
startX2 = centerX + cos(endRadius) * cutoutRadius,
startY2 = centerY + sin(endRadius) * cutoutRadius;
var cmd = [
'M', startX, startY,//Move pointer
'A', doughnutRadius, doughnutRadius, 0, largeArc, 1, endX, endY,//Draw outer arc path
'L', startX2, startY2,//Draw line path(this line connects outer and innner arc paths)
'A', cutoutRadius, cutoutRadius, 0, largeArc, 0, endX2, endY2,//Draw inner arc path
'Z'//Cloth path
];
$paths[i].attr("d", cmd.join(' '));
startRadius += segmentAngle;
}
}
//function drawDoughnutText(animationDecimal, segmentTotal) {
// $summaryNumber
// .css({opacity: animationDecimal})
// .text((segmentTotal * animationDecimal).toFixed(1));
//}
function animateFrame(cnt, drawData) {
var easeAdjustedAnimationPercent =(settings.animation)? CapValue(easingFunction(cnt), null, 0) : 1;
drawData(easeAdjustedAnimationPercent);
}
function animationLoop(drawData) {
var animFrameAmount = (settings.animation)? 1 / CapValue(settings.animationSteps, Number.MAX_VALUE, 1) : 1,
cnt =(settings.animation)? 0 : 1;
requestAnimFrame(function() {
cnt += animFrameAmount;
animateFrame(cnt, drawData);
if (cnt <= 1) {
requestAnimFrame(arguments.callee);
} else {
settings.afterDrawed.call($this);
}
});
}
function Max(arr) {
return Math.max.apply(null, arr);
}
function Min(arr) {
return Math.min.apply(null, arr);
}
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function CapValue(valueToCap, maxValue, minValue) {
if (isNumber(maxValue) && valueToCap > maxValue) return maxValue;
if (isNumber(minValue) && valueToCap < minValue) return minValue;
return valueToCap;
}
return $this;
};
})(jQuery);
CSS
.chart {
position: absolute;
width: 450px;
height: 450px;
top: 50%;
left: 50%;
margin: -225px 0 0 -225px;
}
.doughnutTip {
position: absolute;
min-width: 30px;
max-width: 300px;
padding: 5px 15px;
border-radius: 1px;
background: rgba(0,0,0,.8);
color: #ddd;
font-size: 17px;
text-shadow: 0 1px 0 #000;
text-transform: uppercase;
text-align: center;
line-height: 1.3;
letter-spacing: .06em;
box-shadow: 0 1px 3px rgba(0,0,0,0.5);
pointer-events: none;
&::after {
position: absolute;
left: 50%;
bottom: -6px;
content: "";
height: 0;
margin: 0 0 0 -6px;
border-right: 5px solid transparent;
border-left: 5px solid transparent;
border-top: 6px solid rgba(0,0,0,.7);
line-height: 0;
}
}
.doughnutSummary {
position: absolute;
top: 50%;
left: 50%;
color: #000;
text-align: center;
text-shadow: 0 -1px 0 #111;
cursor: default;
}
.doughnutSummaryTitle {
position: absolute;
top: 50%;
width: 100%;
margin-top: -27%;
font-size: 22px;
letter-spacing: .06em;
}
.doughnutSummaryNumber {
position: absolute;
top: 50%;
width: 100%;
margin-top: -15%;
font-size: 55px;
}
.chart path:hover { opacity: 0.65; }
JSFIDDLE
Without modifying the original plugin drawDoughnutChart, you could overwrite the default settings.
For the out stroke you could draw an other chart, hide it, and use afterDrawed, onPathEnter, onPathLeave callbacks exposed by the plugin to do the logic.
And for the background of each pie segment, you could use svg pattern.
Javascript:
var firstSelected = 0;
var seed = [
{ title: "Holiday Fund", value : 5, color: "url(#dots2)" },
{ title: "Emergencies", value: 20, color: "url(#diagonal1)" },
{ title: "Loans", value: 20, color: "url(#dots1)" },
{ title: "Widows", value : 27, color: "url(#diagonal2)" },
{ title: "Medical Support", value : 28, color: "url(#hatch1)" },
];
var seed2 = [
{ value : 5, color: "#9fa1ac" },
{ value: 20, color: "#ef5123" },
{ value: 20, color: "#ef5123" },
{ value : 27, color: "#9fa1ac" },
{ value : 28, color: "#ef5123" },
];
var chartOptions = {
baseOffset: 0,
segmentShowStroke : false,
segmentStrokeColor : 'transparent',
baseColor: 'transparent',
percentageInnerCutout : 60,
onPathEnter: function (e, data) {
var order = $(this).data().order;
$('#doughnutChart .doughnutSummaryTitle').html(data[order].title);
$('#doughnutChart .doughnutSummaryNumber').html(data[order].value + '%');
$('#doughnutChart .doughnutSummary').show();
$('#doughnutBg g').find('path').fadeOut(300);
$('#doughnutBg g').find('path:eq('+(order)+')').fadeIn(500)
},
onPathLeave: function (e, data) {
$('#doughnutBg g').find('path').fadeOut(300);
$('#doughnutChart .doughnutSummary').hide();
},
afterDrawed : function () {
$('#doughnutChart .doughnutSummaryTitle').html(seed[firstSelected].title);
$('#doughnutChart .doughnutSummaryNumber').html(seed[firstSelected].value + '%');
$('#doughnutChart .doughnutSummary').css({width: '160px', height: '60px', marginLeft: '-80px', marginTop: '-30px'});
$('#doughnutChart .doughnutSummary').show();
$('#doughnutBg g').find('path:eq('+firstSelected+')').fadeIn(500);
}
} ;
var chartOptions2 = {
baseOffset: 0,
segmentStrokeColor : 'transparent',
segmentShowStroke : false,
percentageInnerCutout : 95
} ;
jQuery("#doughnutChart").drawDoughnutChart(seed, chartOptions);
jQuery("#doughnutBg").drawDoughnutChart(seed2, chartOptions2);
CSS:
.chart {
position: absolute;
width: 400px;
height: 400px;
top: 50%;
left: 50%;
margin: -200px 0 0 -200px;
}
.bgchart {
position: absolute;
width: 430px;
height: 430px;
top: 50%;
left: 50%;
margin: -215px 0 0 -215px;
}
.chart .doughnutSummary,
.bgchart .doughnutSummary{
display: none;
}
.chart path:hover { opacity: 0.65; }
.bgchart path { display: none }
HTML:
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="hatch1" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10">
<g style="fill:none; stroke:#ef5123; stroke-width:1">
<path d="M0,0 l10,10"/><path d="M10,0 l-10,10"/>
</g>
</pattern>
<pattern id="hatch2" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10">
<g style="fill:none; stroke:#9fa1ac; stroke-width:1">
<path d="M0,0 l10,10"/><path d="M10,0 l-10,10"/>
</g>
</pattern>
<pattern id="diagonal1" x="0" y="0" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(130)">
<rect x="0" y="0" width="2" height="6" style="stroke:none; fill:#ef5123;" />
</pattern>
<pattern id="diagonal2" x="0" y="0" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(130)">
<rect x="0" y="0" width="2" height="6" style="stroke:none; fill:#9fa1ac;" />
</pattern>
<pattern id="dots1" x="0" y="0" width="5" height="5" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<circle cx="2" cy="2" r="1" style="stroke:none; fill:#ef5123;" />
</pattern>
<pattern id="dots2" x="0" y="0" width="5" height="5" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<circle cx="2" cy="2" r="1" style="stroke:none; fill:#9fa1ac;" />
</pattern>
</defs>
</svg>
<div class="bgchart" id="doughnutBg"></div>
<div class="chart" id="doughnutChart"></div>
DEMO

Categories