Extjs4 changing each bar color in bar chart - extjs4

I have a bar chart and i want each bar to render in different color. So i tried using thems,
sample code is:
Ext.define('Ext.chart.theme.FancyTheme',{
extend : 'Ext.chart.theme.Base',
constructor : function(config){
this.callParent([Ext.apply({
colors : ['#9CC5C9','#D5544F','#D5544F','#5288DB']
},config)])
}
});
and my chart code is:
var tc = Ext.create('Ext.chart.Chart',{
renderTo: Ext.getBody(),
width: 500,
height: 300,
animate : true,
insetPadding : 20,
theme: 'FancyTheme',
But all the bar colors are changing to same color i.e, to '#9cc5c9' in above example.
But i want bars to render in differnt colors as mentioned in theme. One more thing i dont want to use render function to render coloirs.
So wat is the soln to get different colors. Can anyone help me out!!

Sorry, but using a renderer is the correct solution. The colors property is used for successive series in a chart, such as multiple areas in the same plot space.
I don't understand why you don't want to use a renderer, but here's all you would need to do:
renderer: function(sprite, record, attr, index, store) {
var colors = ['#9CC5C9','#D5544F','#D5544F','#5288DB'];
return Ext.apply(attr, {
fill: colors[index % colors.length]
});
}

You can also extend Ext.chart.series.Bar. For example:
Ext.define('Ext.chart.series.MyBar', {
extend: 'Ext.chart.series.Bar',
//type: 'mybar',
alias: 'series.mybar',
getPaths: function() {
this.callParent(arguments);
var items = this.items,
i, iLen = items.length,
colors = this.colorArrayStyle,
colorsLength = colors && colors.length || 0;
for (var i = 0; i < iLen; ++i) {
items[i].attr.fill = colors[i % colorsLength];
}
}
});
Then in series you should use mybar instead of bar.

Related

dc.js composite chart toggle legend loses its translucence upon filtering

I have used this solution to get a toggle legend for a composite line chart and it works perfectly fine.
However, after i added a range chart to this composite chart, the deselected legend loses its translucence and becomes normal.
How can i keep the deselected legend object in faded state while filtering?
Here are screenshots for reference:
Before filter:
After filter:
This is the code I'm using for charts:
multiLineChart
.width(1000)
.height(300)
.transitionDuration(1000)
.margins({top: 30, right: 50, bottom: 40, left: 40})
.x(d3.time.scale().domain([startDate,endDate]))
.yAxisLabel("Data (Scaled)")
.xAxisLabel("Date And Time")
.rangeChart(timeSlider)
.legend(dc.legend().x(800).y(20).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
//.dimension(DateDim)
.compose([
dc.lineChart(multiLineChart)
.dimension(DateDim)
.colors('red')
.group(Line1Grp, 'Line1'),
dc.lineChart(multiLineChart)
.dimension(DateDim)
.colors('blue')
.group(Line2Grp, 'Line2')
])
.brushOn(false)
.on('pretransition.hideshow', function(chart) {
chart.selectAll('g.dc-legend .dc-legend-item')
.on('click.hideshow', function(d, i) {
var subchart = chart.select('g.sub._' + i);
var visible = subchart.style('visibility') !== 'hidden';
subchart.style('visibility', function() {
return visible ? 'hidden' : 'visible';
});
d3.select(this).style('opacity', visible ? 0.2 : 1);
});
});
//.xAxis().tickFormat(d3.time.format("%b %d %H:%M"));
timeSlider
.width(1000)
.height(50)
.margins({top: 0, right: 50, bottom: 20, left: 40})
.dimension(DateDim)
.group(Line1Grp)
.x(d3.time.scale().domain([startDate, endDate]))
.on("filtered", function (chart) {
dc.events.trigger(function () {
multiLineChart.focus(chart.filter());
dc.redrawAll(chart.chartGroup());
});
})
.xAxis().tickFormat(d3.time.format("%b %d"));
Here is a fiddle for the same.
Any help is appreciated.
Thanks for pointing this out - there was a bad practice in my earlier answer, and I went back and corrected it.
It's always better style, and more robust, to separate event handling and drawing, and always draw everything based on the data, not some event that is in flight.
If you follow these practices, then the code looks more like this:
function drawLegendToggles(chart) {
chart.selectAll('g.dc-legend .dc-legend-item')
.style('opacity', function(d, i) {
var subchart = chart.select('g.sub._' + i);
var visible = subchart.style('visibility') !== 'hidden';
return visible ? 1 : 0.2;
});
}
function legendToggle(chart) {
chart.selectAll('g.dc-legend .dc-legend-item')
.on('click.hideshow', function(d, i) {
var subchart = chart.select('g.sub._' + i);
var visible = subchart.style('visibility') !== 'hidden';
subchart.style('visibility', function() {
return visible ? 'hidden' : 'visible';
});
drawLegendToggles(chart);
})
drawLegendToggles(chart);
}
multiLineChart
.on('pretransition.hideshow', legendToggle);
Now, whenever we redraw the composite chart and its legend - no matter what the cause - all of the items in the legend will be updated based on whether the corresponding child chart has been hidden.
And the event handler is only concerned with hiding and showing charts, not drawing.
Fork of your fiddle.

canvasOverlay show in jqplot

How do I trigger on the overlays in jqplot only after I click a checkbox (not when the html loads). When I first set overlay option show to false the overlays are not displayed on plot at 1st and when I used my trigger function the overlays do not appear.
Here is the code I use for the plot :
<div id="fastest" style="margin-top:20px; margin-left:20px; margin-right:200px; width:800px; height:400px;">
<script class="code" type="text/javascript">
$(document).ready(function(){
var dataset="too long to be displayed here"
plot1 = $.jqplot('fastest', dataset, {
title: 'Test_figs',
legend: {show:false},
series: [{
showMarker: false,
color: '#ED0E0E',
label: 'R spectrum',
neighborThreshold: -1
}],
axes:{
xaxis:{
label:'Restframe Wavelength'
},
yaxis:{
label:'Flux',
tickOptions:{formatString:'%.3e'}
}
},
cursor:{
show:true,
zoom:true,
tooltipLocation:'sw'
},
Canvasoverlay: {
show: false,
objects: [
{verticalLine: {
name: 'Na-ID',
x: 5893.000000,
lineWidth: 2,
color: '#F0630C',
lineCap:'butt',
yOffset:0,
shadow: true
}}
]
}
});
});
function NaID_trigger() {
var co = plot1.plugins.canvasOverlay;
var line = co.get('Na-ID');
if (line.options.show==false) line.options.show = true;
else line.options.show = false;
co.draw(plot1);
}
</script>
I then use :
<button onclick="NaID_trigger()">Na-ID</button>
to trigger the overlay on or off for instance.
PS: I tried replacing draw by replot as advised didn't work when show=false in overlays options.
I finally found the solution myself :
to not display the overlays when the jqplot loads I set the overall overlays "show" option to true.
Then within each object I set show to false.
Instead of the external to the plot function I used before I switched to an even handler of the form:
$("input[type=checkbox][name=Na-ID]").change(function(){
plot1.plugins.canvasOverlay.get('Na-ID').options.show = this.checked;
plot1.replot();
});
Now the plot display the selected overlay when checkbox is ticked and not at the beginning.
Hope this will help someone who has the same issues.

Center buttons in a view horizontally

I have buttons I want to center horizontally in a view. There are three, and all I can seem to get is:
[button1-button2-button3------------------------------]
What I really want is
[--------button1--------button2--------button3--------]
These buttons are dynamic widths too. The amount of buttons will change, some views have 1, others have 2 or 3. Depending on an action, the number of buttons can change. I need this support both iOS and android.
Try splitting the screen into n different columns using percentage layout. Then add your buttons to their respective invisible container.
var n = // Your number of buttons horizontal
var container = Ti.UI.createView({width : "100%", layout: "horizontal" });
for(var i=0;i<n;i++) {
var column = Ti.UI.createView({
width : (100/n)+"%",
});
// Create your button here
// .....
// .....
// Now add it to the column
column.add(yourNthButton);
// Now add the column to the container
container.add(column);
}
How about wrapping your buttons in a view with layout set to 'horizontal'?
var wrapperView = Ti.UI.createView({
layout : 'horizontal',
...
});
// In a view with horizontal layout,
// the positioning is relative to the preceding element
var buttonOne = Ti.UI.createButton({
right : 10,
...
});
wrapperView.add(buttonOne);
Untested, but give it a try!
UPDATE
Ok, the above code alone won't do what you wanted. I wrote a more complete example here.
Seems a bit clumsy, so if someone has a better solution, please let us know!
// Create our window
var win = Ti.UI.createWindow();
// Our wrapper view
var wrapperView = Ti.UI.createView({
width : Ti.UI.FILL,
height : 40,
top : 0,
layout : 'horizontal',
});
// Add some test buttons to our wrapper
for(var i=0; i<3; i++) {
wrapperView.add(Ti.UI.createButton({
title : 'Test ' + i,
height : 30,
}));
}
// Add wrapperView to our window and open it
win.add(wrapperView);
win.open();
// Wait until "size" becomes available
win.addEventListener('postlayout', distributeButtons);
// Distribute buttons evenly
function distributeButtons() {
if(wrapperView.children) {
// Get the width of the wrapper view
var wrapperWidth = wrapperView.size.width;
var buttonWidths = 0;
var buttonSpacer;
var childrenLength = wrapperView.children.length;
// Get the button sizes
for(var i=0; i<childrenLength; i++) {
buttonWidths += wrapperView.children[i].size.width;
};
// Calculate the spaces between the buttons
buttonSpacer = (wrapperWidth - buttonWidths) / (childrenLength + 2);
// Set the buttons left value
for(var i=0; i<childrenLength; i++) {
wrapperView.children[i].left = buttonSpacer;
};
}
}
If you can put a toolbar, you can use the "flexspace" button, which will create a space necessary to fill the gap between other buttons. Here's the syntax from simple toolbar example in titanium docs:
var send = Titanium.UI.createButton({
title: 'Send',
style: Titanium.UI.iPhone.SystemButtonStyle.DONE,
});
var camera = Titanium.UI.createButton({
systemButton: Titanium.UI.iPhone.SystemButton.CAMERA,
});
var cancel = Titanium.UI.createButton({
systemButton: Titanium.UI.iPhone.SystemButton.CANCEL
});
flexSpace = Titanium.UI.createButton({
systemButton:Titanium.UI.iPhone.SystemButton.FLEXIBLE_SPACE
});
var toolbar = Titanium.UI.iOS.createToolbar({
items:[send, flexSpace, camera, flexSpace, cancel],
bottom:0,
borderTop:true,
borderBottom:false
});
win.add(toolbar)
try this
var yourView = Ti.UI.createView({ layout:"horizontal"});
var buttonsHolder = Ti.UI.createView({ width:"100%" });
// this view will hold the buttons
var button1 = Ti.UI.createButton({title:"button1 , left:0"}); // the left button
var button2 = Ti.UI.createButton({title:"button2"}); // the middle button
var button3 = Ti.UI.createButton({title:"button3",right:0}); // the right button
buttonsHolder(button1);
buttonsHolder(button2);
buttonsHolder(button3);
yourView.add(buttonsHolder);
Hieyy bro
If you are want achieve this using titanium alloy in xml. in that case you can use %.
Container ------------width 100%-----layout horizontal---------
first child--------left 10%------- width 20%
second child--------left 10%------- width 20%
third child--------left 10%------- width 20%-----right 10%
if you don't get your answer please let me know
Spartacus Thanks:)
If using Alloy, then I recommend using percentages to control width and position. Here's an example that centers three small images below a larger image, also centered:
<TableViewRow selectionStyle="Ti.UI.iPhone.TableViewCellSelectionStyle.NONE" backgroundColor="white" layout="vertical">
<ImageView id="detailsFeaturedImage" top="10"/>
<View height="60">
<View layout="horizontal">
<View left="25%" width="10%"><ImageView image="images/thumb-up-7#2x.png" onClick="thumb_up" /></View>
<View left="10%" width="10%"><ImageView image="images/thumb-down-7#2x.png" onClick="thumb_down"/></View>
<View left="10%" width="10%"><ImageView image="images/flag-7#2x.png" onClick="flag_for_review"/></View>
</View>
</View>
</TableViewRow>

Updating a chart with new data in App SDK 2.0

I am using a chart to visualize data in a TimeboxScopedApp, and I want to update the data when scope changes. The more brute-force approach of using remove() then redrawing the chart as described here leaves me with an overlaid "Loading..." mask, but otherwise works. The natural approach of using the Highchart native redraw() method would be my preference, only I don't know how to access the actual Highchart object and not the App SDK wrapper.
Here's the relevant part of the code:
var chart = Ext.getCmp('componentQualityChart');
if (chart) {
var chartCfg = chart.getChartConfig();
chartCfg.xAxis.categories = components;
chart.setChartConfig(chartCfg);
chart.setChartData(data);
chart.redraw(); // this doesn't work with the wrapper object
} else { // draw chart for the first time
How do I go about redrawing the chart with the new data?
Assuming chart (componentQualityChart) is an instance of Rally.ui.chart.Chart, you can access the HighCharts instance like this:
var highcharts = chart.down('highchart').chart;
// Now you have access to the normal highcharts interface, so
// you could change the xAxis
highcharts.xAxis[0].setCategories([...], true);
// Or you could change the series data
highcharts.series[0].data.push({ ... }); //Add a new data point
// Or pretty much anything else highcharts lets you do
Using _unmask() removes the overlaid "Loading.." mask
if (this.down('#myChart')) {
this.remove('myChart');
}
this.add(
{
xtype: 'rallychart',
height: 400,
itemId: 'myChart',
chartConfig: {
//....
},
chartData: {
categories: scheduleStateGroups,
series: [
{
//...
}
]
}
}
);
this.down('#myChart')._unmask();

How to add background-color to text navigation on image slider?

I have an image slider that is controlled by text navigation. The text is highlighted orange when it's relative slide is current in the gallery. I would like the other text to have an inactive state with a black background but cannot get this to work!
(In case that didn't make much sense! Basically, I want background-color orange when current, background-color black when inactive.) THANKS
$(document).ready(function(){
$('.slider').each(function(e){
if(e == 0){
$(this).addClass('current');
}
$(this).attr('id', 'handle' + e);
})
$('.tabs li').each(function(e){
if(e == 0){
$(this).addClass('current'); //adds class current to 1st li
}
$(this).wrapInner('<a class="title"></a>'); //wraps list items in anchor tag
$(this).children('a').attr('href', '#handle' + e);//adds href to the anchors
t = $(this).children('a').text();
$('#handle' + e).append('<h2>' + t + '</h2>'); //adds h2 and text to big images
})
$('.tabs li a').click(function(){
c = $(this).attr('href');
if($(c).hasClass('current')){
return false;
}else{
showImage($(c), 20);
$('.tabs li').removeClass('current');
$(this).parent().addClass('current');
return false;
}
})
runRotateImages();
$("#featured").hover(
function(){
clearTimeout(xx);
},
function(){
runRotateImages();
}
)
})
function showImage(img, duration){
$('.slider').removeClass('current').css({
"opacity" : 0.0,
"zIndex" : 2
});
img.animate({opacity:1.0}, duration, function(){
$(this).addClass('current').css({zIndex:1});
});
}
function rotateImages(){
var curPhoto = $("div.current");
var nxtPhoto = curPhoto.next();
var curTab = $(".tabs li.current");
var nxtTab = curTab.next();
if (nxtPhoto.length == 0) {
nxtPhoto = $('#featured div:first');
nxtTab = $('.tabs li:first-child');
}
curTab.removeClass('current');
nxtTab.addClass('current');
showImage(nxtPhoto, 300);
}
function runRotateImages(){
xx = setInterval("rotateImages()", 5000);
}
I have added a jsfiddle - http://jsfiddle.net/n5EPM/3/
However, on jsfiddle it does not seem to automatically cycle through the images, not sure why, have no problems in browser.
Try using not() method: http://api.jquery.com/not/
Basically, you need to create a new class disabled
.disabled{
background-color:#000000;
}
Then, add the following line to your tabs.li's each loop:
$(".tabs li").not(".current").addClass('disabled'); //add disabled class for non-current tabs
At last you need to remove disabled class in the rotateimage() function before assigning current and then disable non-current again. like this:
curTab.removeClass('current');
nxtTab.removeClass('disabled'); //remove diabled class
nxtTab.addClass('current');
$(".tabs li").not(".current").addClass('disabled'); // disable non-current again
Working jsfiddle here: http://jsfiddle.net/n5EPM/9/
This might not be the perfect solution but you will need to tweak it a little bit.
Hope this helps.