I display a google map on a bootstrap modal when the modal is shown, and I set the center of the map to be a latLong location:
$('#result-details-modal').on('shown.bs.modal', (e) => {
this.canGetAddress = true;
this.setMapCenter(
this.selectedResult.result.place.geometry.location.lat(),
this.selectedResult.result.place.geometry.location.lng()
);
this.resizeMap();
//this.addMarkersToMap();
//this.bindAutoCompleteToMap();
})
And the map initially starts with the location of the latitude and longitude (should be in the center) being in the top left corner of the map. Then when I close the modal and reopen it, the latlong location is centered correctly in the map. So it is to do with timing. How come the latlong location starts off in the top left corner of the map, rather than the center?
Here is all my relevant code. Try not to be put off if you haven't done angular 2. The question isn't really about angular 2:
html:
<div id="map" #map></div>
css:
#map {
height: 400px;
width:400px;
max-width: none !important;
-webkit-transform: translate3d(0px, 0px, 0px);
-webkit-mask-image: -webkit-radial-gradient(white, black);
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
}
#map > div {
border-radius: 10px;
-webkit-transform: translate3d(0px, 0px, 0px);
-webkit-mask-image: -webkit-radial-gradient(white, black);
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
}
.controls {
margin-top: 10px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
typescript:
selectedResult;
subscription: Subscription;
#ViewChild('areaInput') areaInput;
#ViewChild('map') mapInput;
map;
autocomplete;
zoom: number = 8;
options = {
center: { lat: -33.8688, lng: 151.2195 },
zoom: 13
};
canGetAddress: boolean;
constructor(private resultSelectionService: ResultSelectionService) {
resultSelectionService.resultSelected$.subscribe(
result => {
this.selectedResult = { result };
$('#result-details-modal').modal('show');
$('#result-details-modal').on('shown.bs.modal', (e) => {
this.canGetAddress = true;
this.setMapCenter(
this.selectedResult.result.place.geometry.location.lat(),
this.selectedResult.result.place.geometry.location.lng()
);
this.resizeMap();
//this.addMarkersToMap();
//this.bindAutoCompleteToMap();
})
console.log(this.selectedResult.result);
});
}
ngAfterViewInit() {
this.initMap();
}
resizeMap() {
google.maps.event.trigger(this.map, "resize");
}
initMap() {
this.map = new google.maps.Map(document.getElementById('map'), this.options);
this.resizeMap();
}
setMapCenter(lat: number, lng: number) {
var myLatLng = {lat: lat, lng: lng};
this.map.setCenter(myLatLng);
}
The solution was to simply change the order of resizing the map and setting the map center.
THIS:
this.setMapCenter(
this.selectedResult.result.place.geometry.location.lat(),
this.selectedResult.result.place.geometry.location.lng()
);
this.resizeMap();
BECOMES:
this.resizeMap();
this.setMapCenter(
this.selectedResult.result.place.geometry.location.lat(),
this.selectedResult.result.place.geometry.location.lng()
);
Related
My goal is to (upon clicking a button) spin a wheel multiple times, then end on a specific rotation value (0...360) while easing out the animation. I can currently 'smoothly' spin to a specific point on the wheel without any full revolutions. My problem is trying to spin the wheel multiple times and then landing on a specific point to make it look more realistic. Is this achievable with the CSS animaton property or anything else?
Here is my code...
const wheelEl = document.getElementById("wheel");
const sliceSize = 360 / 3;
function spinWheel(index) {
// Reset animation
wheelEl.style.transition = "none";
wheelEl.style.transform = "rotate(0deg)";
// Play animation on the next frame
setTimeout(() => {
wheelEl.style.transition = "all ease 1s";
// Target rotation margin
let rotMin = (sliceSize * (index))+(sliceSize/15);
let rotMax = (sliceSize * (index + 1))-(sliceSize/15);
// Target rotation
let rot = Math.floor(Math.random() * (rotMax - rotMin + 1) + rotMin);
wheelEl.style.transform = `rotate(-${rot}deg)`;
}, 0);
}
#container {
position: absolute;
text-align: center;
}
#arrow {
position: absolute;
top: -5px;
left: 50%;
transform: translateX(-50%);
border-top: 10px solid black;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
z-index: 1;
}
#wheel {
width: 100px;
height: 100px;
border-radius: 50%;
background-image: conic-gradient(lightpink 0 120deg, lightblue 0 240deg, lightsalmon 0 360deg);
}
<div id="container">
<div id="arrow"></div>
<div id="wheel"></div>
<br />
<button onclick="spinWheel(2)">Spin wheel</button>
</div>
You can stick to using transform.
This snippet does two things: adds a random (within bounds) number of 360 degrees to the rotation value and sets the easing function to ease-out so that the rotation slows down towards the end only.
So that the effect can be seen, the time of the full rotation is set to 5 seconds but of course alter this to whatever you want. You could for example make that random within some bounds too if desired.
You could also play with the Beziere function that represents ease-out if say you wanted a longer stretch of it seeming to slow down.
const wheelEl = document.getElementById("wheel");
const sliceSize = 360 / 3;
function spinWheel(index) {
// Reset animation
wheelEl.style.transition = "none";
wheelEl.style.transform = "rotate(0deg)";
// Play animation on the next frame
setTimeout(() => {
wheelEl.style.transition = "all ease-out 5s";
// Target rotation margin
const rotMin = (sliceSize * (index)) + (sliceSize / 15);
const rotMax = (sliceSize * (index + 1)) - (sliceSize / 15);
// Target rotation
const fullRots = Math.floor(Math.random() * 5) + 5; // minimum 5 rotations max 9
const rot = (fullRots * 360) + Math.floor(Math.random() * (rotMax - rotMin + 1) + rotMin);
wheelEl.style.transform = `rotate(-${rot}deg)`;
}, 0);
}
#container {
position: absolute;
text-align: center;
}
#arrow {
position: absolute;
top: -5px;
left: 50%;
transform: translateX(-50%);
border-top: 10px solid black;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
z-index: 1;
}
#wheel {
width: 100px;
height: 100px;
border-radius: 50%;
background-image: conic-gradient(lightpink 0 120deg, lightblue 0 240deg, lightsalmon 0 360deg);
}
<div id="container">
<div id="arrow"></div>
<div id="wheel"></div>
<br />
<button onclick="spinWheel(2)">Spin wheel</button>
</div>
I'm completely flummoxed by the rootMargin property of intersection observer.
My goal is to add a class to an element when half it's height has crossed the vertical center of the viewport.
In my current project, nothing I do seems to impact the "root intersection rectangle" and the class is always added immediately. I've tested in latest Chrome and Firefox.
Here's the reduced test case:
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
const options = {
root: null, // default, use viewport
rootMargin: '0px 0px -50% 0px',
threshold: 0.5 // half of item height
}
const circle = document.getElementById('circle');
const observerCallback = function(entries, observer) {
console.log('intersected');
circle.classList.add('intersected');
}
window.addEventListener('load', function(event) {
const observer = new IntersectionObserver(observerCallback, options);
observer.observe(circle);
}, false);
.circle {
margin: 100vh auto;
width: 200px;
height: 200px;
background-color: tomato;
border-radius: 50%;
transition: background-color 2s ease-in-out;
}
.circle.intersected {
background-color: mediumseagreen;
}
<div class="circle" id="circle"></div>
I am quite perplexed by IntersectionObserver myself sometimes, but referring to this post, it was a lot easier to grasp for me.
What was probably giving you trouble was checking for if it actually was intersecting or not. So I added an if-statement along with the property isIntersecting that is found on IntersectionObserver entries.
I also added a check for IntersectionObserver if it is available on the client and removed root: null from the options as it should default to the viewport anyway.
If you only use this IntersectionObserver for adding a class once, don't forget to observer.unobserve(circle) or observer.disconnect() when it isn't needed anymore to prevent memory leaks.
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
const options = {
rootMargin: '0px 0px -50% 0px',
threshold: 0.5 // half of item height
}
const circle = document.getElementById('circle');
const observer = new IntersectionObserver(entries => {
const [{ isIntersecting }] = entries
if (isIntersecting) {
console.log('intersected');
circle.classList.add('intersected');
} else {
console.log('not-intersecting');
}
}, options);
window.addEventListener('load', () => {
if ('IntersectionObserver' in window) observer.observe(circle);
}, false);
.circle {
margin: 100vh auto;
width: 200px;
height: 200px;
background-color: tomato;
border-radius: 50%;
transition: background-color 2s ease-in-out;
}
.circle.intersected {
background-color: mediumseagreen;
}
<div class="circle" id="circle"></div>
I'd like to make both .quote-container and #new-quote elements in the same line even if the window width is very small. For example 83pixels. Using min-width on the .quote-container element worked, however, using the same technique on the #new-quote element didn't work.
Maybe that's because #new-quote isn't the children of .quote-container? I even tried to make it a child and it was even worse (picture was taken on the desktop window size):
What I'd like to achieve in visual:
var getNewQuote = function(callback) {
var quote = {};
quote.text = 'Example';
quote.author = 'Example';
$(".loading").hide();
callback(quote);
};
var quoteContainerStartingPadding,
quoteContainerEndingPadding,
newQuoteEndingPadding;
if ($(window).width() > 648) {
quoteContainerStartingPadding = "0 2.5rem";
quoteContainerEndingPadding = "2.5rem";
newQuoteEndingPadding = "2.5rem .75rem";
} else {
quoteContainerStartingPadding = "0 1.5em";
quoteContainerEndingPadding = "1.5rem";
newQuoteEndingPadding = "1.5rem .75rem";
}
$(".quote-container").css("padding", quoteContainerStartingPadding);
getNewQuote(function(quote) {
var getRandomColor = function() {
var colors = ["#ff9966", "#7f00ff", "#396afc", "#0cebeb", "#06beb6", "#642b73", "#36d1dc", "#cb356b", "#3a1c71", "#ef3b36", "#159957", "#000046", "#007991", "#56ccf2", "#f2994a", "#e44d26", "#4ac29a", "#f7971e", "#34e89e", "#6190e8", "#3494e6", "#ee0979"],
randomNumber = Math.floor(Math.random() * colors.length);
return colors[randomNumber];
};
var updateText = function($t) {
var twitter = "https://twitter.com/intent/tweet?hashtags=quotes&related=freecodecamp&text=";
twitter += '"' + quote.text + '" ';
twitter += quote.author;
var tumblr = "https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes,freecodecamp&caption=";
tumblr += quote.author;
tumblr += "&content=";
tumblr += quote.text;
tumblr += "&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fbuttons&shareSource=tumblr_share_button";
var $icon = $("<i class='fa fa-quote-left'>").prop("aria-hidden", true);
$t.find(".quote-text").html("").append($icon, quote.text);
$t.find(".quote-author").html("- " + quote.author);
$("#tweet-quote").attr("href", twitter);
$("#tumblr-quote").attr("href", tumblr);
};
var calcNewHeight = function(q) {
var $temp = $("<div>", {
class: "quote-container temp",
}).appendTo($("body"));
$temp.append($("<div>", {
class: "quote-text"
}), $("<div>", {
class: "quote-author"
}));
updateText($temp, q);
var h = $temp.height() + 40;
$temp.remove();
return h;
};
var changeColor = function(newColor) {
$("body, .button:not(#new-quote)").animate({
backgroundColor: newColor
});
$("#new-quote").animate({
color: newColor
});
$(".quote-text, .quote-author").css("color", newColor);
if ($("#modStyle").length === 0) {
$("head").append("<style id='modStyle'>#new-quote:before {background:" + newColor + ";} .lds-eclipse {box-shadow: 0 .25rem 0 0 " + newColor + ";}</style>");
} else {
$("head style#modStyle").html("#new-quote:before {background:" + newColor + ";} .lds-eclipse {box-shadow: 0 .25rem 0 0 " + newColor + ";}");
}
};
var getQuote = function() {
var nc, nh = 0;
nc = getRandomColor();
nh = calcNewHeight(quote);
changeColor(nc);
$(".quote-container, #new-quote").animate({
height: nh / 16 + "rem",
}, {
duration: 1000,
queue: false
});
$(".quote-container").animate({
padding: quoteContainerEndingPadding
}, {
duration: 1000,
queue: false
});
$("#new-quote").animate({
padding: newQuoteEndingPadding
}, {
duration: 1000,
queue: false
});
updateText($(".quote-container"), quote);
$(".quote-container").children().not($(".loading")).fadeTo(750, 1);
};
$(".quote-container, #new-quote").css({
visibility: "visible",
height: 0
});
$("#new-quote").css("padding", "0 .75rem");
getQuote();
}
);
var two = function() {
$(".quote-container").children().not($(".loading")).hide();
$(".loading").show();
getNewQuote(function(quote) {
var getRandomColor = function() {
var colors = ["#ff9966", "#7f00ff", "#396afc", "#0cebeb", "#06beb6", "#642b73", "#36d1dc", "#cb356b", "#3a1c71", "#ef3b36", "#159957", "#000046", "#007991", "#56ccf2", "#f2994a", "#e44d26", "#4ac29a", "#f7971e", "#34e89e", "#6190e8", "#3494e6", "#ee0979"],
randomNumber = Math.floor(Math.random() * colors.length);
return colors[randomNumber];
};
var updateText = function($t) {
var twitter = "https://twitter.com/intent/tweet?hashtags=quotes&related=freecodecamp&text=";
twitter += '"' + quote.text + '" ';
twitter += quote.author;
var tumblr = "https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes,freecodecamp&caption=";
tumblr += quote.author;
tumblr += "&content=";
tumblr += quote.text;
tumblr += "&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fbuttons&shareSource=tumblr_share_button";
var $icon = $("<i class='fa fa-quote-left'>").prop("aria-hidden", true);
$t.find(".quote-text").html("").append($icon, quote.text);
$t.find(".quote-author").html("- " + quote.author);
$("#tweet-quote").attr("href", twitter);
$("#tumblr-quote").attr("href", tumblr);
};
var calcNewHeight = function(q) {
var $temp = $("<div>", {
class: "quote-container temp",
}).appendTo($("body"));
$temp.append($("<div>", {
class: "quote-text"
}), $("<div>", {
class: "quote-author"
}));
updateText($temp, q);
var h = $temp.height() + 40;
$temp.remove();
return h;
};
var changeColor = function(newColor) {
$("body, .button:not(#new-quote)").animate({
backgroundColor: newColor
});
$("#new-quote").animate({
color: newColor
});
$(".quote-text, .quote-author").css("color", newColor);
if ($("#modStyle").length === 0) {
$("head").append("<style id='modStyle'>#new-quote:before {background:" + newColor + ";} .lds-eclipse {box-shadow: 0 .25rem 0 0 " + newColor + ";}</style>");
} else {
$("head style#modStyle").html("#new-quote:before {background:" + newColor + ";} .lds-eclipse {box-shadow: 0 .25rem 0 0 " + newColor + ";}");
}
};
var getQuote = function() {
var nc = getRandomColor(),
nh = calcNewHeight(quote);
$(".quote-container").children().not($(".loading")).css("opacity", 0);
changeColor(nc);
$(".quote-container, #new-quote").animate({
height: nh / 16 + "rem",
}, {
duration: 1000,
queue: false
});
updateText($(".quote-container"), quote);
$(".quote-container").children().not($(".loading")).fadeTo(750, 1);
};
getQuote();
});
}
;
html,
body {
height: 100%;
width: 100%;
}
body {
margin: 0;
padding: 0;
background: #333;
color: #333;
font-family: sans-serif;
}
.quote-container {
width: 35%;
background: #fff;
margin: 0;
display: inline-block;
vertical-align: middle;
border-radius: 0.1875rem;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
visibility: hidden;
min-width: 15rem;
}
.quote-text {
font-size: 1.625rem;
}
.quote-text i {
margin-right: 0.6rem;
}
.quote-text p {
display: inline;
}
.quote-author {
font-size: 1rem;
margin: 0 0.4rem 2rem 0;
text-align: right;
}
.button {
padding: 0.75rem;
text-align: center;
font-size: 1rem;
color: #fff;
border-radius: 0.1875rem;
display: inline-block;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
}
.button:not(#new-quote):hover {
opacity: 0.8 !important;
}
.button:not(#new-quote) {
min-width: 1rem;
min-height: 1rem;
}
.button i {
vertical-align: middle;
}
#new-quote {
white-space: nowrap;
writing-mode: vertical-lr;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
vertical-align: middle;
background: #fff !important;
margin: 0;
position: relative;
right: 0.25625rem;
color: #333;
visibility: hidden;
}
#new-quote:before {
content: "";
position: absolute;
height: 100%;
width: 0.0625rem;
bottom: 0;
left: 0;
visibility: hidden;
-webkit-transform: scaleY(0);
transform: scaleY(0);
-webkit-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
#new-quote:hover:before {
visibility: visible;
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
.v-align {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.text-center {
text-align: center;
}
footer {
font-size: 0.85rem;
margin-bottom: 1rem;
}
footer a {
text-decoration: none;
color: #fff;
position: relative;
}
footer a:before {
content: "";
position: absolute;
width: 100%;
height: 0.0625rem;
bottom: 0;
left: 0;
background: #fff;
visibility: hidden;
-webkit-transform: scaleX(0);
transform: scaleX(0);
-webkit-transition: all 0.3s ease-in-out 0s;
transition: all 0.3s ease-in-out 0s;
}
footer a:hover:before {
visibility: visible;
-webkit-transform: scaleX(1);
transform: scaleX(1);
}
/* Loading animation */
#keyframes lds-eclipse {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
50% {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
#-webkit-keyframes lds-eclipse {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
50% {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.loading {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.lds-eclipse {
-webkit-animation: lds-eclipse 1s linear infinite;
animation: lds-eclipse 1s linear infinite;
width: 10rem;
height: 10rem;
border-radius: 50%;
margin: auto;
}
#media (max-width: 62.5em) {
.quote-container {
width: 50%;
}
}
#media (max-width: 50em) {
.quote-container {
width: 65%;
}
}
#media (max-width: 17.96875em) {
.quote-container {
width: 40%;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="v-align text-center">
<div class="quote-container">
<div class="quote-text">
</div>
<div class="quote-author"></div>
<a id="tweet-quote" class="button"><i class="fa fa-twitter"></i></a>
<a id="tumblr-quote" class="button"><i class="fa fa-tumblr"></i></a>
<div class="loading">
<div class="lds-eclipse"></div>
</div>
</div>
<div id="new-quote" class="button">New quote</div>
<footer>
Created by LukasLSC
</footer>
</div>
EDIT 1: Codepen: https://codepen.io/Kestis500/pen/KZvXgB?editors=0110
If you want to align things in CSS you usually have two different positioning concepts you can use for this purpose:
display (flex)
float
Usually it is a good idea to put all elements you want to align in a wrapping container like a div. In this manner you can just focus on your aligning issue and forget about the general layout - means where you want to have your aligned elements in the layout eventually. You can later on just position the wrapper and do not have to worry about the elements inside.
Another best practice is to give all your elements that this container inherits from a dimension (at least width). A common mistake is that elements that should be aligned break just because the parent element does not have enough space to fit all elements on one line. If you want to know why I provide an example at the end, just follow the *.
But lets go back to the two concepts that you can use. Which one you should use depends on one hand what other attributes you need to give the respective elements and what browsers you need to support. If you only want to support newer browser versions you can go with flexbox, the more secure way to do this is use percentages for widths and float.
Flexbox
.container {
display: flex;
flex-direction: row; // this makes your elements align horizontally
}
.child1 {
flex: 1 1 auto;
}
.child2 {
flex: 0 1 auto;
}
The flex attribute determines the dimension of a child. So consider the parent as width: 100%; and the numbers you give as a first parameter to flex is the ratio of the child's dimension compared to the other children.
Float
.container {
overflow: hidden;
width: 100%; // this must be relative to the containers parent of course
}
.child1 {
width: 75%;
float: left;
}
.child2 {
width: 25%;
float: left;
}
Mind that float takes effect on the elements following in the document flow AFTER the element that you give the float attribute. Also take into account that you might need to calculate margins, paddings or borders in additionally to the elements' widths (except for paddings when using box-sizing: border-box) and that elements containing only floated elements lose their "automatic" dimensions as floated elements lose their information about height and width as well. (overflow: hidden on the container solves this issue for you)
*In a responsive design e.g. you should give the highest parent a width of 100%. If you provide to a child width: 50%; it will now have exactly 50% of the entire width. If you now give the child of the child width: 50% it will be 25% of the entire width. This is less error prone then giving the child's child directly 25%. Let's assume later on you give the child a width of 50% the width of the child's child (25%) will relate to the childs width instead of the parent. So you will end up with a width of 12.5% for the child's child relative to the entire width.
I really like this element,
but how to create it? I am not sure what's the correct designation of the element...
Thank you very much.
This effect can be achieved by layering a couple arc()s:
// bright blue full circle
d.beginPath();
d.arc(50, 50, 50, 0, 2 * Math.PI, false);
d.fillStyle = "#aaeeff";
d.fill();
// dark blue percentage circle
d.beginPath();
d.moveTo(50, 50);
d.arc(50, 50, 50, -0.5 * Math.PI, 0.78 * 2 * Math.PI - 0.5 * Math.PI, false);
d.fillStyle = "#00aaff";
d.fill();
// white inner filler
d.beginPath();
d.moveTo(50, 50);
d.arc(50, 50, 25, 0, 2 * Math.PI, false);
d.fillStyle = "#ffffff";
d.fill();
and finally rendering the text:
d.moveTo(50, 50);
d.fillStyle = "#606060";
d.font = "12pt sans-serif";
d.fillText("78%", 36, 56);
Fiddle: http://jsfiddle.net/j6NVg/
Instead of using the <canvas> element, I have chosen to construct the pie chart relying on CSS and JS entirely. The HTML markup is as follow:
<div class="pie" data-percent="78">
<div class="left">
<span></span>
</div>
<div class="right">
<span></span>
</div>
</div>
The CSS is as follow. The trick is to split the circle into two halves (the nested .left and .right elements). The halves will have their overflowing content hidden, and contain nested <span> that we will manipulate with JS for rotation later. Add vendor prefixes when appropriate :)
.pie {
background-color: #eee;
border-radius: 50%;
width: 200px;
height: 200px;
overflow: hidden;
position: relative;
}
.pie > div {
float: left;
width: 50%;
height: 100%;
position: relative;
overflow: hidden;
}
.pie span {
background-color: #4a7298;
display: block;
width: 100%;
height: 100%;
}
.pie .left span {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
-webkit-transform-origin: 100% 50%;
transform-origin: 100% 50%;
}
.pie .right span {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
-webkit-transform-origin: 0% 50%;
transform-origin: 0% 50%;
}
.pie:before,
.pie:after {
border-radius: 50%;
display: block;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
.pie:before {
background-color: #fff;
content: "";
width: 75%;
height: 75%;
z-index: 100;
}
.pie:after {
content: attr(data-percent) "%";
z-index: 200;
text-align: center;
}
I have used the following with jQuery:
$(function() {
$(".pie").each(function() {
var percent = $(this).data("percent").slice(0,-1), // Removes '%'
$left = $(this).find(".left span"),
$right = $(this).find(".right span"),
deg;
if(percent<=50) {
// Hide left
$left.hide();
// Adjust right
deg = 180 - (percent/100*360)
$right.css({
"transform": "rotateZ(-"+deg+"deg)"
});
} else {
// Adjust left
deg = 180 - ((percent-50)/100*360)
$left.css({
"transform": "rotateZ(-"+deg+"deg)"
});
}
});
});
Here is the fiddle: http://jsfiddle.net/Aw5Rf/7/
Check the below links for more info (not an exact one.But you can get some idea).
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Canvas Test</title>
</head>
<body>
<section>
<div>
<canvas id="canvas" width="400" height="300">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
</div>
<script type="text/javascript">
var myColor = ["#ECD078","#D95B43","#C02942","#542437","#53777A"];
var myData = [10,30,20,60,40];
function getTotal(){
var myTotal = 0;
for (var j = 0; j < myData.length; j++) {
myTotal += (typeof myData[j] == 'number') ? myData[j] : 0;
}
return myTotal;
}
function plotData() {
var canvas;
var ctx;
var lastend = 0;
var myTotal = getTotal();
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < myData.length; i++) {
ctx.fillStyle = myColor[i];
ctx.beginPath();
ctx.moveTo(200,150);
ctx.arc(200,150,150,lastend,lastend+
(Math.PI*2*(myData[i]/myTotal)),false);
ctx.lineTo(200,150);
ctx.fill();
lastend += Math.PI*2*(myData[i]/myTotal);
}
}
plotData();
</script>
</section>
</body>
</html>
For more info :Graphing Data in the HTML5 Canvas Element Simple Pie Charts
Another Link : Pure CSS3 Pie Charts effect
This is an online demo: http://jsbin.com/uFaSOwO/1/
First of all what you need can be done exactly using jQuery knob plugin. Still interested in a CSS Solution, than here's what I have done
<div class="load_me"></div>
.load_me {
margin: 100px;
height: 50px;
width: 50px;
border: 5px solid #f00;
border-radius: 50%;
border-top-color: transparent;
}
Demo
Animating the Knob Credits
If you want to prevent the mouse alteration, you can simply add readOnly
$this.knob({
readOnly: true
});
Demo
FIDDLE with ANIMATION
Here's my approach:
var ctx = canvas.getContext('2d');
/*
* in canvas, 0 degrees angle is on the right edge of a circle,
* while we want to start at the top edge of the circle.
* We'll use this variable to compensate the difference.
*/
var relativeAngle = 270;
function drawCanvas() {
ctx.clearRect(0, 0, 90, 90);
//light blue circle
ctx.lineWidth = 20;
ctx.strokeStyle = '#D8E8F7';
ctx.beginPath();
ctx.arc(45, 45, 35, 0, 2*Math.PI);
ctx.stroke();
//dark blue circle
ctx.strokeStyle = '#66ADF4';
ctx.beginPath();
//notice the angle conversion from degrees to radians in the 5th argument
ctx.arc(45, 45, 35, 1.5*Math.PI, ((angle + relativeAngle) / 180) * Math.PI);
ctx.stroke();
//text
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillStyle = '#666';
ctx.font = 'bold 14px serif';
// angle conversion to percentage value
ctx.fillText(parseInt(100 * angle / 360).toString() + '%', 45, 45);
}
var angle;
function timeout() {
angle = parseInt(360 * percent / 100);
drawCanvas();
if (angle > 360) {
document.getElementById('run').disabled = false;
percent = 0;
return;
}
percent++;
setTimeout(timeout, 10);
};
var percent = 0;
/* START the ANIMATION */
timeout();
At the bottom of the code you'll find a self evaluating function timeout which calls the drawCanvas function every 10 miliseconds and increments the blue circle angle. I hope everything is clear here. If not, feel free to ask!
Enjoy it!
I used a plugin called embedit to use custom html, javascript and CSS in my wordpress. The original code look like:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/ui-darkness/jquery-ui.css" />
<style>
.calculator>td{
border-bottom: 0px;
border-top: 0px;
}
input.dark[type=text] {
transition: all 0.25s ease-in-out;
-webkit-transition: all 0.25s ease-in-out;
-moz-transition: all 0.25s ease-in-out;
border-radius:8px;
-webkit-border-radius:8px;
-moz-border-radius:8px;
border:1px solid rgba(31, 161, 5, 1);
text-align: center;
background: #000000;
behavior: url(/pie/PIE.htc);
color: #10c90d;
height: 20px;
width: 35px;
}
#container {
width:300px;
height:320px;
z-index:4;
-webkit-transform: rotate(10deg) skew(0,0) translate(0%,-5px);
-moz-transform: rotate(10deg) skew(0,0) translate(0%,-5px);
-o-transform: rotate(10deg) skew(0,0) translate(0%,-5px);
transform: rotate(10deg) skew(0,0) translate(0%,-5px);
font-family: 'Oxygen Mono', Tahoma, Arial, sans-serif;
}
input[type=text].dark:focus {
box-shadow: 0 0 9px rgba(31, 161, 5, 1);
-webkit-box-shadow: 0 0 9px rgba(31, 161, 5, 1);
-moz-box-shadow: 0 0 9px rgba(31, 161, 5, 1);
}
.report{
margin-top:-100px;
margin-left:70%;
}
.main{
background: rgb(0,155,5); /* Old browsers */
/* IE9 SVG, needs conditional override of 'filter' to 'none' */
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwOWIwNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwNDY4MTkiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
background: -moz-linear-gradient(#9BD91A, #54750E); /* FF3.6+ */
background: -webkit-gradient(#9BD91A, #54750E); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(#9BD91A, #54750E); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(#9BD91A, #54750E); /* Opera 11.10+ */
background: -ms-linear-gradient(#9BD91A, #54750E); /* IE10+ */
background: linear-gradient(#9BD91A, #54750E); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#9BD91A', endColorstr='#54750E',GradientType=0 ); /* IE6-8 */
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
color:#ffffff;
border-color: #000000;
border-width: 100px;
-webkit-box-shadow: inset 2px 2px 21px 21px rgba(0, 0, 0, .4);
box-shadow: inset 2px 2px 21px 21px rgba(0, 0, 0, .4);
-moz-box-shadow: inset 2px 2px 21px 21px rgba(0, 0, 0, .4);
width: 100%;
}
.pointer{
cursor: pointer;
}
.half{
width: 50%;
}
.full{
width: 100%;
}
.tape{
position: relative;
top:-40px;
left:50px;
width: 130px;
height: 35px;
background-color:#fff;
opacity:0.6;
border-left: 1px dashed rgba(0, 0, 0, 0.1);
border-right: 1px dashed rgba(0, 0, 0, 0.1);
-webkit-box-shadow: 0px 0px 1px 0px #cccccc;
-moz-box-shadow: 0px 0px 1px 0px #cccccc;
box-shadow: 0px 0px 1px 0px #cccccc;
-webkit-transform: rotate(-2deg) skew(0,0) translate(0%,-5px);
-moz-transform: rotate(-2deg) skew(0,0) translate(0%,-5px);
-o-transform: rotate(-2deg) skew(0,0) translate(0%,-5px);
transform: rotate(-2deg) skew(0,0) translate(0%,-5px);
}
.paper {
padding:25px 25px 40px;
margin:0 auto 20px auto;
align:center;
line-height:1.5;
border:0;
border-radius:3px;
background: #F9EFAF;
background: -webkit-linear-gradient(#F9EFAF, #F7E98D);
background: -moz-linear-gradient(#F9EFAF, #F7E98D);
background: -o-linear-gradient(#F9EFAF, #F7E98D);
background: -ms-linear-gradient(#F9EFAF, #F7E98D);
background: linear-gradient(#F9EFAF, #F7E98D);
box-shadow:0 4px 6px rgba(0,0,0,0.1);
transition:box-shadow 0.5s ease;
font-smoothing:subpixel-antialiased;
width:220px;
height:260px;
}
.calculator{
font-family: 'Oxygen Mono', Tahoma, Arial, sans-serif;
height: 700px;
}
</style>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
</head>
<body>
<div class="calculator">
<div class="main">
<h1>Solar Payback Calculator</h1>
<table>
<form><tr><td colspan="9"><h2>Roof Size</h2></td></tr><tr><td>
Width: </td><td class="pointer" onclick="subtractwidth();">- </td><td colspan="2" width="500"><div id="slider1"></div></td><td class="pointer" onclick="addwidth();"> + </td><td>
Length: </td><td class="pointer" onclick="subtractlength();">- </td><td colspan="2" width="500"><div id="slider2"></div></td><td class="pointer" onclick="addlength();">
+</td></tr><tr><td></td><td></td><td>
<input type="text" id="roof_width" onKeyUp="calculate();" class="slider_input1 dark" value="0"/>m</td><td></td><td></td><td></td><td></td><td>
<input type="text" id="roof_length" onKeyUp="calculate();" class="slider_input2 dark" value="0"/>m</td></tr>
<tr><td>
Electricity Bill: </td><td class="pointer" onclick="subtractbill();">- </td><td colspan="7" width="500"><div id="slider3"></div></td><td onclick="addbill();" class="pointer">
+</td></tr><tr><td></td><td></td><td>
£<input type="text" id="electricity_bill" onKeyUp="calculate();" class="slider_input3 dark" value="0"/></td></tr>
</form>
</table>
<table class="full"><tr><td>
<table class="half">
<tr><td>Area of the roof: </td><td></td><td><span id="roof_area"></span><span id="unit_area"></span></td></tr>
<tr><td>Number of Solar Panels: </td><td></td><td><span id="no_solar_panel"></span></td></tr>
<tr><td>System Cost: </td><td></td><td><span id="system_cost"></span></td></tr>
<tr><td>Annual System Output: </td><td></td><td><span id="system_output"></span></td></tr>
<tr><td>FIT Estimate: </td><td></td><td><span id="fit_estimate"></span></td></tr>
</table></td>
<td><table class="half">
<tr><td>Export FiT: </td><td></td><td><span id="export_fit"></span></td></tr>
<tr><td>Savings from using Solar Energy: </td><td></td><td><span id="savings"></span></td></tr>
<tr><td>Total Annual Yields: </td><td></td><td><span id="total_annual_yield"></span></td></tr>
<tr><td>Payback time in years: </td><td></td><td><span id="payback_time"></span></td></tr>
<tr><td>Profit over 20 years: </td><td></td><td><span id="profit"></span></td></tr>
</table></td></tr>
</table>
<script>
$("#slider1").slider({
range: "min",
value: 0,
step: 0.01,
min: 0,
animate: true,
max: 10,
slide: function( event, ui ) {
$( ".slider_input1" ).val( ui.value );
calculate();
//$( ".slider_input" ).val( ui.value );
}
});
$(".slider_input1").change(function () {
var value = this.value
$("#slider1").slider("value", parseInt(value));
calculate();
});
$("#slider2").slider({
range: "min",
value: 0,
step: 0.01,
min: 0,
animate: true,
max: 10,
slide: function( event, ui ) {
$( ".slider_input2" ).val( ui.value );
calculate();
//$( ".slider_input" ).val( ui.value );
}
});
$(".slider_input2").change(function () {
var value = this.value
$("#slider2").slider("value", parseInt(value));
calculate();
});
$(".slider_input2").change(function () {
var value = this.value
$("#slider2").slider("value", parseInt(value));
calculate();
});
$("#slider3").slider({
range: "min",
value: 0,
step: 1,
min: 0,
animate: true,
max: 3000,
slide: function( event, ui ) {
$( ".slider_input3" ).val( ui.value );
calculate();
//$( ".slider_input" ).val( ui.value );
}
});
$(".slider_input3").change(function () {
var value = this.value
$("#slider3").slider("value", parseInt(value));
calculate();
});
var calculate = function(){
var roof_length = document.getElementById('roof_length').value;
var roof_width = document.getElementById('roof_width').value;
var electricity_bill= document.getElementById('electricity_bill').value;
roof_length = parseInt(roof_length);
roof_width = parseInt(roof_width);
electricity_bill = parseInt(electricity_bill);
if (roof_length<0 || roof_width<0 || electricity_bill<0){
roof_length = Math.abs(roof_length);
roof_width = Math.abs(roof_width);
electricity_bill = Math.abs(electricity_bill);
document.getElementById('roof_length').value=roof_length;
document.getElementById('roof_width').value=roof_width;
document.getElementById('electricity_bill').value=electricity_bill;
}
var roof_area = roof_length*roof_width;
roof_area = roof_area.toFixed(2);
if(isNaN(roof_area)){
document.getElementById('roof_area').innerHTML="Invalid Input";
document.getElementById('unit_area').innerHTML="";
}else{
document.getElementById('roof_area').innerHTML=roof_area;
document.getElementById('unit_area').innerHTML=" m<sup>2</sup>";
}
var no_solar_panel = roof_area/1.676675;
no_solar_panel = Math.floor(no_solar_panel);
if(isNaN(no_solar_panel)){
document.getElementById('no_solar_panel').innerHTML="Invalid Input";
}else if(no_solar_panel<16){
document.getElementById('no_solar_panel').innerHTML=no_solar_panel;
}else{
var no_solar_panel = 16;
document.getElementById('no_solar_panel').innerHTML=no_solar_panel;
}
var system_cost = no_solar_panel*500;
if(isNaN(system_cost)){
document.getElementById('system_cost').innerHTML="Invalid Input";
}else{
document.getElementById('system_cost').innerHTML="£" + system_cost;
}
var system_output = no_solar_panel*256;
if(isNaN(system_output)){
document.getElementById('system_output').innerHTML="Invalid Input";
}else{
document.getElementById('system_output').innerHTML=system_output + " kWh";
}
var fit_estimate = (system_output*0.1544);
fit_estimate = fit_estimate.toFixed(2);
if(isNaN(fit_estimate)){
document.getElementById('fit_estimate').innerHTML="Invalid Input";
}else{
document.getElementById('fit_estimate').innerHTML="£" + fit_estimate;
}
var annual_electricity_used = electricity_bill/0.18;
if(system_output>annual_electricity_used){
var left_over = system_output-annual_electricity_used;
left_over = left_over.toFixed(2);
}else{
var left_over = 0;
}
var export_fit = left_over*0.045;
export_fit = export_fit.toFixed(2);
if(isNaN(export_fit)){
document.getElementById('export_fit').innerHTML="Invalid Input";
}else{
document.getElementById('export_fit').innerHTML="£" + export_fit;
}
if(left_over>0){
var savings = annual_electricity_used*0.18;
savings = savings.toFixed(2);
}else if(left_over<=0){
var savings = system_output*0.18;
savings = savings.toFixed(2);
}
if(isNaN(savings)){
document.getElementById('savings').innerHTML="Invalid Input";
}else{
document.getElementById('savings').innerHTML="£" + savings;
}
savings = parseInt(savings);
fit_estimate = parseInt(fit_estimate);
export_fit = parseInt(export_fit);
var total_annual_yield = (savings+fit_estimate)+export_fit;
if(isNaN(total_annual_yield)){
document.getElementById('total_annual_yield').innerHTML="Invalid Input";
}else{
document.getElementById('total_annual_yield').innerHTML="£" + total_annual_yield;
}
var payback_time = system_cost/total_annual_yield;
payback_time = Math.ceil(payback_time);
if(isNaN(payback_time)){
document.getElementById('payback_time').innerHTML="Invalid Input";
}else{
document.getElementById('payback_time').innerHTML=payback_time + " Years";
}
var profit = (total_annual_yield*20)-system_cost;
if(isNaN(profit)){
document.getElementById('profit').innerHTML="Invalid Input";
}else{
document.getElementById('profit').innerHTML="£" + profit;
}
if(isNaN(roof_width) || isNaN(roof_length) || isNaN(electricity_bill)){
document.getElementById('report').innerHTML='<h1>Invalid Input</h1>';
}else{
document.getElementById('report').innerHTML='<div id="container"><div class="paper"><div class="tape"></div><h1>Report:</h1><span class="report-content">With your roof size of <span id="report_roof_area">_____</span> m<sup>2</sup>, you can fit <span id="report_no_solar_panel">_____</span> solar panels for £<span id="report_system_cost">_____</span>.<br />Saving you £<span id="report_savings">____</span> each year on your bill!<br />Making £<span id="report_total_annual_yield">_____</span> each year and £<span id="report_profit">____</span> profit over 20 years.</span></div><!--end paper--></div><!--end container-->';
document.getElementById('report_roof_area').innerHTML=roof_area;
document.getElementById('report_no_solar_panel').innerHTML=no_solar_panel;
document.getElementById('report_system_cost').innerHTML=system_cost;
document.getElementById('report_savings').innerHTML=savings;
document.getElementById('report_total_annual_yield').innerHTML=total_annual_yield;
document.getElementById('report_profit').innerHTML=profit;
}
}
var subtractwidth = function(){
var roof_width = document.getElementById('roof_width').value;
roof_width = parseInt(roof_width);
var roof_width = roof_width-1;
document.getElementById('roof_width').value=roof_width;
}
var addwidth = function(){
var roof_width = document.getElementById('roof_width').value;
roof_width = parseInt(roof_width);
var roof_width = roof_width+1;
document.getElementById('roof_width').value=roof_width;
calculate();
}
var subtractlength = function(){
var roof_length = document.getElementById('roof_length').value;
roof_length = parseInt(roof_length);
var roof_length = roof_length-1;
document.getElementById('roof_length').value=roof_length;
calculate();
}
var addlength = function(){
var roof_length = document.getElementById('roof_length').value;
roof_length = parseInt(roof_length);
var roof_length = roof_length+1;
document.getElementById('roof_length').value=roof_length;
calculate();
}
var subtractbill = function(){
var electricity_bill= document.getElementById('electricity_bill').value;
electricity_bill = parseInt(electricity_bill);
var electricity_bill = electricity_bill-10;
document.getElementById('electricity_bill').value=electricity_bill;
calculate();
}
var addbill = function(){
var electricity_bill= document.getElementById('electricity_bill').value;
electricity_bill = parseInt(electricity_bill);
var electricity_bill = electricity_bill+10;
document.getElementById('electricity_bill').value=electricity_bill;
calculate();
}
document.getElementById('roof_length').value=0;
document.getElementById('roof_width').value=0;
document.getElementById('electricity_bill').value=0;
</script>
</div>
<div class="report" id="report">
<div id="container"><div class="paper"><div class="tape"></div><h1>Please Input Values</h1></div><!--end paper--></div><!--end container-->
</div>
</div>
</body>
</html>
Without wordpress it looks like: http://www.asifslab.com/solarpanel.html
But when I add it to wordpress it looks like: bit.ly/Yvn2vv
The jquery-ui slider unfortunately does not work, and the style is in a complete mess.
Moreover the html do not fit into the content area(the report covers the footer).
How to fix this problem. Can anyone help?
The CSS of your wordpress site is applying to the custom HTML code you added using the plugin, that's why the styles are all messed up, and also probably why the sliders are not working (i didn't verify that point).
Instead of using a plugin, use an iframe.
<iframe src="http://www.asifslab.com/solarpanel.html">
And apply some styling. (Adjust these to fit your needs.)
iframe {
width: 100%;
margin: auto;
height: 600px;
display: block;
}
demo
To clarify what your problem is; you have two sets of styles that weren't made with each other in mind. So there are issues with Wordpress overriding the styles on your widget. Putting it in an iframe keeps everything separate, so that the widget doesn't affect the blog styles, and the blog doesn't affect the widget. Harmony.
AS gotson said, the css from your wordpress theme overrides some of the things on your custom page. You may want to use a unique class with a prefix instead of using a general tag and create it in a fix width container that is the same with the wordpress template that you're using.
#sp_Container{ //apply style }
Instead of
#container{ //apply style }
also, make sure to target every declaration inside that container.
#sp_Container .class1{ //apply style }
#sp_Container .class2{ //apply style }
#sp_Container .class3{ //apply style }
P.S. The container needs a position:relative; so you can make sure that the result note won't get too far from it(if it was set on a position:absolute;).