How to change parent view classname on child view load? - ember.js

I need to change the parent view classname on child view load the code would be like
var ChildView = Em.View.extend({
willInsertElement : function() {
this.get('parentView').set('classnames',['ChildView']);
},
template : Em.Handlebars.compile(template)
});
Regards
Chandru.

Use classNameBindings and send the event from the child view to update the property.
Consider this example:
{{#view App.AParentView}}
{{view App.AChildView}}
{{/view}}
The app:
App = Ember.Application.create();
App.AParentView = Em.View.extend({
bgColor: 'lightgray',
classNames: ['parent-view'],
classNameBindings: 'bgColor',
updateBg: function(bg) {
this.set('bgColor', bg);
}
});
App.AChildView = Em.View.extend({
classNames: ['child-view', 'blue'],
willInsertElement: function() {
this.get('parentView').send('updateBg', 'green');
}
});
The CSS to see it actually working:
html, body {
margin: 20px;
}
.parent-view {
padding: 4rem;
}
.child-view {
padding: 2rem;
}
.lightgray {
background-color: lightgray;
color: black;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
See the jsbin here.

Related

Google pie chart vs old flot chart

I have an old pie chart with jquery flot.
And if my series values are:
Apples: 1070
Bananas: 2127
And pie chart looks like
2127 / 1070
Currently, I have google pie chart. And, as i understand, counting happens other way:
(1070 + 2127) / 1070
and
(1070 + 2127) / 2127.
Thus chart looks different.
Is there any way to display values like in an old flot pie?
not sure how the data is being loaded,
but the following two examples look the same to me...
flot
$(document).ready(function() {
var data = [
{label: 'Apples', data: 1070, color: '#e1ab0b'},
{label: 'Bananas', data: 2127, color: '#fe0000'}
];
$.plot($("#chart-flot"), data, {
series: {
pie: {
show: true
}
}
});
});
body, html, .chart {
height: 100%;
margin: 0px;
padding: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.pie.min.js"></script>
<div id="chart-flot" class="chart"></div>
google
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Apples', 1070],
['Bananas', 2127]
]);
var options = {
chartArea: {
height: '100%',
width: '100%',
top: 16,
left: 16,
right: 16,
bottom: 16
},
colors: ['#e1ab0b', '#fe0000'],
height: '100%',
legend: {
position: 'top',
alignment: 'end'
},
width: '100%'
};
var chart = new google.visualization.PieChart(document.getElementById('chart-google'));
chart.draw(data, options);
});
body, html, .chart {
height: 100%;
margin: 0px;
padding: 0px;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart-google" class="chart"></div>

Ember: How to script with intervals

I have a span-area like this
<span class="blinky">I'm blinking</span>
and now I want it to blink.
In vanilla JS, I would write a simple piece of code using jQuery which starts an interval for this.
However: How can I implement this in ember in a proper way?
I write a full solution for blinking
First, let's create CSS for blinking
.blinky {
animation: changecolor 0.5s infinite;
-moz-animation: changecolor 0.5s infinite;
-webkit-animation: changecolor 0.5s infinite;
-ms-animation: changecolor 0.5s infinite;
-o-animation: changecolor 0.5s infinite;
}
#keyframes changecolortask {
0% {
color: #pre-text-color;
}
100% {
color: #pre-text-color;
border: 2px solid #blink-bg;
}
}
/* Mozilla Browser */
#-moz-keyframes changecolortask {
0% {
color: #pre-text-color;
}
100% {
color: #pre-text-color;
border: 4px solid #blink-bg;
}
}
/* WebKit browser Safari and Chrome */
#-webkit-keyframes changecolortask {
0% {
color: #pre-text-color;
}
100% {
color: #pre-text-color;
border: 4px solid #blink-bg;
}
}
/* IE 9,10*/
#-ms-keyframes changecolortask {
0% {
color: #pre-text-color;
}
100% {
color: #pre-text-color;
border: 4px solid #blink-bg;
}
}
/* Opera Browser*/
#-o-keyframes changecolortask {
0% {
color: #pre-text-color;
}
100% {
color: #pre-text-color;
border: 4px solid #blink-bg;
}
}
#keyframes changecolor {
0% {
color: #pre-text-color;
background: #pre-bg;
}
100% {
color: #pre-text-color;
background: #blink-bg;
}
}
/* Mozilla Browser */
#-moz-keyframes changecolor {
0% {
color: #pre-text-color;
background: #pre-bg;
}
100% {
color: #pre-text-color;
background: #blink-bg;
}
}
/* WebKit browser Safari and Chrome */
#-webkit-keyframes changecolor {
0% {
color: #pre-text-color;
background: #pre-bg;
}
100% {
color: #pre-text-color;
background: #blink-bg;
}
}
/* IE 9,10*/
#-ms-keyframes changecolor {
0% {
color: #pre-text-color;
background: #pre-bg;
}
100% {
color: #pre-text-color;
background: #blink-bg;
}
}
/* Opera Browser*/
#-o-keyframes changecolor {
0% {
color: #pre-text-color;
background: red;
}
100% {
color: #pre-text-color;
background: #blink-bg;
}
}
Then where you want to use this in the controller, route or Component declare
blinky: null,
now we need to have an action or you need to initialize it depends on how you want to use it, let's assume you want to add this Blinky class for 3seconds while clicking on a button so we would do the following code :
actions: {
myChangeColor: function() {
this.set('blinky', 'blinkery');//set your class to property
// remove blinker after 1 sec, it must be passed to reference for 'this' so easily we can bind that.
setTimeout(function() {
this.set('blink', ' ');
}.bind(this), 3000);
}
}
Now you need to use it in template for example in my example you simply add this property in your proper line of template like :
<div class="row well {{blinky}}"> //whatever </div>
now suppose you have a button which myChangeColor action
<button type="submit" class="btn btn-success btn-block" {{action "blinky"}}>make me blinky for 3 seconds !</button>
that's it.
Depends on what you want and how you want to use this action and class you can implement it in different ways, However, the way of implementation is the same.
Note: you can also use animation.css library to have more class either you can add your Vanilla javascript code in the action.
If you want to use this in a component depends on how you want to use, you may have to work with didInsertElement() {} and willDestroyElement() {} . As an example see the following code:
let blinker;
export default Ember.Component.extend({
tagName: 'span',
blink: null,
interval: 3000,
init() {
this._super(...arguments);
this.set('blink','');
},
didInsertElement() { // when you enter route
this._super(...arguments);
blinker = setInterval(function() {
this.set('blink', 'blinky');
}.bind(this), this.get('interval'));
},
willDestroyElement() { // when you leave route
this._super(...arguments);
clearInterval(blinker);
}
});
I hope this can help you.

Include Percentage In Legend

How would I add the segments percentage to the charts label?
Example
(Percentage values dont reflect the actual chart this is just an example.)
Here's my current template.
<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>
You could update the template to do a couple of extra things. 1 get the total number being represented and then in the loop which displays the label print the result of that labels value as a percentage of the total.
ugly string
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% var total = segments.reduce(function(previousValue, currentValue){ return previousValue + currentValue.value;},0); for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%> <%=Math.floor((segments[i].value/total)*100)%>%<%}%></li><%}%></ul>"
broken down
first get the total (here using reduce)
var total = segments.reduce(function(previousValue, currentValue){
return previousValue + currentValue;
},0);
and then when displaying use the total to work out the percentage (used floor here to just make sure we don't end up with a horrible number, could even add 0.5 to it before we floor to round to the nearest percent)
Math.floor((segments[i].value/total)*100)
Example (also fiddle)
$(function() {
var pieChartCanvas = $("#pieChart").get(0).getContext("2d");
var PieData = [{
value: 70000,
color: "#f56954",
highlight: "#f56954",
label: "Chrome"
}, {
value: 6000,
color: "#00a65a",
highlight: "#00a65a",
label: "IE"
}, {
value: 4000,
color: "#f39c12",
highlight: "#f39c12",
label: "FireFox"
}, {
value: 4000,
color: "#00c0ef",
highlight: "#00c0ef",
label: "Safari"
}, {
value: 3000,
color: "#3c8dbc",
highlight: "#3c8dbc",
label: "Opera"
}];
var pieOptions = {
segmentShowStroke: true,
segmentStrokeColor: "#fff",
segmentStrokeWidth: 2,
percentageInnerCutout: 50,
animationSteps: 100,
animationEasing: "easeOutBounce",
animateRotate: true,
animateScale: false,
responsive: true,
maintainAspectRatio: true,
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% var total = segments.reduce(function(previousValue, currentValue){ return previousValue + currentValue.value;},0); for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%> <%=Math.floor((segments[i].value/total)*100)%>%<%}%></li><%}%></ul>"
};
var pieChart = new Chart(pieChartCanvas).Doughnut(PieData, pieOptions);
var helpers = Chart.helpers;
var legendHolder = document.getElementById('graph-legend');
legendHolder.innerHTML = pieChart.generateLegend();
// Include a html legend template after the module doughnut itself
helpers.each(legendHolder.firstChild.childNodes, function(legendNode, index) {
helpers.addEvent(legendNode, 'mouseover', function() {
var activeSegment = pieChart.segments[index];
activeSegment.save();
pieChart.showTooltip([activeSegment]);
activeSegment.restore();
});
});
helpers.addEvent(legendHolder.firstChild, 'mouseout', function() {
pieChart.draw();
});
document.getElementById('graph-legend').appendChild(legendHolder.firstChild);
});
#graph-legend ul {
list-style: none;
}
#graph-legend ul li {
display: block;
padding-left: 30px;
position: relative;
margin-bottom: 4px;
border-radius: 5px;
padding: 2px 8px 2px 28px;
font-size: 14px;
cursor: default;
-webkit-transition: background-color 200ms ease-in-out;
-moz-transition: background-color 200ms ease-in-out;
-o-transition: background-color 200ms ease-in-out;
transition: background-color 200ms ease-in-out;
}
#graph-legend li span {
display: block;
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 100%;
border-radius: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.js"></script>
<div class="box-body">
<canvas id="pieChart" width="787" height="300"></canvas>
</div>
<div id="graph-legend"></div>
In Chart.js V3 you can use a custom generateLabels function for this:
const options = {
type: 'pie',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"]
}, ]
},
options: {
plugins: {
legend: {
labels: {
generateLabels: function(chart) {
const data = chart.data;
if (data.labels.length && data.datasets.length) {
const {
labels: {
pointStyle
}
} = chart.legend.options;
const max = data.datasets[0].data.reduce((a, b) => (a + b), 0);
return data.labels.map((label, i) => {
const meta = chart.getDatasetMeta(0);
const style = meta.controller.getStyle(i);
return {
text: `${label} (${(data.datasets[0].data[i] * 100 / max).toFixed(2)}%)`,
fillStyle: style.backgroundColor,
strokeStyle: style.borderColor,
lineWidth: style.borderWidth,
pointStyle: pointStyle,
hidden: !chart.getDataVisibility(i),
// Extra data used for toggling the correct item
index: i
};
});
}
return [];
}
},
}
}
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.js"></script>
</body>

Merge Jquery Knob Functionality in Chart Js

I am using Doughnut Chart of ChartJS, and here is my code
<!doctype html>
<html>
<head>
<title>Doughnut Chart</title>
<script src="jquery-1.11.3.min.js"></script>
<script src="jquery.knob.js"></script>
<script src="../Chart.js"></script>
<style>
body{
padding: 0;
margin: 0;
}
#canvas-holder{
width:30%;
}
</style>
</head>
<body>
<div id="canvas-holder">
<canvas id="chart-area" width="250" class="knob" height="250"/>
</div>
<script>
var doughnutData = [
{
value: 200,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red"
},
{
value: 200,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green"
},
{
value: 200,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow"
},
{
value: 200,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
},
{
value: 200,
color: "#4D5360",
highlight: "#616774",
label: "Dark Grey"
},
{
value: 200,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
},
{
value: 200,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
},
{
value: 200,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
},
{
value: 200,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
},
{
value: 200,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
},
{
value: 200,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
},
{
value: 200,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey"
}
];
var options = {
//Boolean - Whether we should show a stroke on each segment
segmentShowStroke : true,
//String - The colour of each segment stroke
segmentStrokeColor : "#fff",
//Number - The width of each segment stroke
segmentStrokeWidth : 0,
//Number - The percentage of the chart that we cut out of the middle
percentageInnerCutout : 80, // This is 0 for Pie charts
//Number - Amount of animation steps
animationSteps : 100,
//String - Animation easing effect
animationEasing : "easeOutBounce",
//Boolean - Whether we animate the rotation of the Doughnut
animateRotate : true,
//Boolean - Whether we animate scaling the Doughnut from the centre
animateScale : false,
showTooltips: false
}
window.onload = function(){
var ctx = document.getElementById("chart-area").getContext("2d");
var myDoughnut = new Chart(ctx).Doughnut(doughnutData, options);
$("#chart-area").click( function(evt){
var activePoints = myDoughnut.getSegmentsAtEvent(evt);
/* do something */
}
);
};
</script>
</body>
</html>
There is a requirement to update the value while clicking on the canvas, in the middle of doughnut chart (Just like in Jquery Knob http://anthonyterrien.com/knob/) i.e the value updates on sliding as well as clicking on the canvas. Is there any way to merge the functionality of these two libraries
It would be better to use that control. That said, you could do it Chart.js too. Here is a fair approximation (note that I've used jQuery for some parts, but you could do the same using plain javascript).
CSS
<style>
.myChartWrapper {
position: relative;
display: inline-block;
}
.myChartValue {
border: none;
font-family: 'Helvetica';
font-size: 20px;
overflow: visible;
width: 2em;
white-space: nowrap;
text-align: center;
position: absolute;
background-color: transparent;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.myChartValue::-ms-clear {
display: none;
}
</style>
HTML
<div class="myChartWrapper">
<canvas id="myChart"></canvas>
<input id="myChartValue" class="myChartValue" />
</div>
Javascript
var value = 20;
var MAX = 200;
var STEP = 1;
var HALFSETCOLOR = "rgba(154, 225, 254, 1)";
var SETCOLOR = "rgba(134, 205, 234, 1)";
var UNSETCOLOR = "rgba(237, 237, 237, 1)";
var data = [];
for (var i = 0; i < MAX; i = i + STEP) {
data.push({
value: STEP,
color: (i < value) ? SETCOLOR : UNSETCOLOR,
label: i
})
}
var canvas = document.getElementById("myChart");
var ctx = canvas.getContext("2d");
var myDoughnutChart = new Chart(ctx).Doughnut(data, {
animation: false,
segmentShowStroke: false,
showTooltips: false
});
$("#myChartValue").val(value);
// half set the sectors
canvas.onmousedown = function (evt) {
var activeSegments = myDoughnutChart.getSegmentsAtEvent(evt);
if (activeSegments.length) {
var value = Number(activeSegments[0].label);
var crossed = false;
myDoughnutChart.segments.forEach(function (segment) {
if (Number(segment.label) >= value)
crossed = true;
if (!crossed && segment.fillColor !== SETCOLOR)
segment.fillColor = HALFSETCOLOR;
else if (crossed && segment.fillColor !== UNSETCOLOR)
segment.fillColor = HALFSETCOLOR;
})
myDoughnutChart.update()
myDoughnutChart.value = value;
$("#myChartValue").val(value);
}
};
canvas.onmousemove = function (evt) {
if (myDoughnutChart.value !== undefined) {
canvas.onmousedown(evt)
}
}
// set / unset sectors
canvas.onmouseup = function () {
var value = myDoughnutChart.value;
if (value !== undefined) {
var crossed = false;
myDoughnutChart.segments.forEach(function (segment, i) {
if (Number(segment.label) >= value)
crossed = true;
if (!crossed)
segment.fillColor = SETCOLOR;
else if (crossed)
segment.fillColor = UNSETCOLOR;
})
myDoughnutChart.value = undefined;
myDoughnutChart.update()
}
};
$("#myChartValue").on("change", function () {
myDoughnutChart.value = Number($("#myChartValue").val());
canvas.onmouseup();
})
It could do with a bit of cleanup (like handling change in direction without lifting the mouse), but comes pretty close to the knob functionality without too much effort.
Fiddle - http://jsfiddle.net/rxrxLo33/

Changing the backface content on rotation

I'm currently rotating a Surface successfully, and made the backface visible by copying the starterkit:
.double-sided {
-webkit-backface-visibility: visible;
backface-visibility: visible;
}
The problem is, I want to change the back, as I'm rotating the image of a playing card, say the Queen of Spades, so the content on the backface needs to change to another image.
At the moment I'm using sprites, so it's mainly the css I'll be updating (changing the background image). I thought there may be a way of adding a class as the rotation goes past 90 degrees, but it seems like a messy approach:
.card {
width: 141px;
height: 191px;
background-image: url(/assets/images/playingCards.png);
background-repeat: no-repeat;
}
.card.display-back {
background-image: url(/assets/images/backofCard.png);
}
.double-sided {
-webkit-backface-visibility: visible;
backface-visibility: visible;
}
This seems quite messy and was wondering if there was a better approach? Even if I do use this approach, how do I add a class based on the current rotation?
I also tried shoving an element at the back of the surface using z-index, but the browser (chrome) seems to ignore the element sitting below:
.card {
width: 141px;
height: 191px;
background-image: url(/assets/images/playingCards.png);
background-repeat: no-repeat;
z-index: 2;
position: absolute;
}
.card[data-suit=spade][data-number=Q] { background-position: 0 0; }
.card[data-suit=spade][data-number=K] { background-position: 0px -190px; }
.card[data-suit=spade][data-number=J] { background-position: 0px -380px; }
.card.facedown {
background-image: url(/assets/images/playingCardBacks.png);
z-index: 1;
}
And the Surface:
var queen = new Surface({
content: '<div class="card" data-suit="spade" data-number="Q"></div><div class="card facedown"></div>',
overFlow: 'hidden',
size: [141, 191],
classes: ['double-sided']
});
This still only shows the first element, so even on a rotation of 180 degrees you see the playingCards.png instead of the playingBackCards.png
You could just use the Flipper View and change the back or front based on your case.
define('main',function(require, exports, module) {
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var Flipper = require("famous/views/Flipper");
var Modifier = require("famous/core/Modifier");
var mainContext = Engine.createContext();
mainContext.setPerspective(500);
var flipper = new Flipper();
var frontSurface = new Surface({
size : [200, 200],
content : 'front',
properties : {
background : 'red',
lineHeight : '200px',
textAlign : 'center'
}
});
var backSurface = new Surface({
size : [200, 200],
content : 'back',
properties : {
background : 'blue',
color : 'white',
lineHeight : '200px',
textAlign : 'center'
}
});
flipper.setFront(frontSurface);
flipper.setBack(backSurface);
var centerModifier = new Modifier({
align : [.5,.5],
origin : [.5,.5]
});
mainContext.add(centerModifier).add(flipper);
var toggle = false;
Engine.on('click', function(){
var angle = toggle ? 0 : Math.PI;
flipper.setAngle(angle, {curve : 'easeOutBounce', duration : 500});
toggle = !toggle;
});
});
require(['main']);
.double-sided {
-webkit-backface-visibility: visible;
backface-visibility: visible;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://requirejs.org/docs/release/2.1.16/minified/require.js"></script>
<script src="http://code.famo.us/lib/requestAnimationFrame.js"></script>
<script src="http://code.famo.us/lib/classList.js"></script>
<script src="http://code.famo.us/lib/functionPrototypeBind.js"></script>
<link rel="stylesheet" type="text/css" href="http://code.famo.us/famous/0.3.5/famous.css" />
<script src="http://code.famo.us/famous/0.3.5/famous.min.js"></script>