ExtJS 4 Chart - Change with Ajax store - extjs

I have some trouble with my app. I have a chart and the data are loaded from a store who make an Ajax connection.
The first time I load my page it work fine but I have three buttons and my goal is to load a new chart to replace the previous when someone click on a button but this doesn't work like I want. I have some bugs and I want to know if there a "official" way to do what I want to do.
I have an error:
Error : TypeError: me.labels[inflections.length - 1] is undefined
Source File : extjs-4.1.0/ext-all-debug.js
Ligne : 58728
When someone click on a button I do this:
var el = Ext.get('GraphVolumeBar03');
if(!el) {
var elem = Ext.create('Axiastats.view.GraphVolumeBar03');
Ext.create('Ext.panel.Panel', {
id : 'GraphVolumeBar03',
renderTo: 'graphContainer-body',
height : 300,
border: false,
items: elem,
});
}
else {
el.show();
Ext.getCmp('GraphVolumeBar03-chart').redraw(true);
}
And I hide the old charts but I don't think it's the right solution:
var el2 = Ext.get('GraphVolumeBar01');
if(el2) { el2.hide(); }
var el3 = Ext.get('GraphVolumeBar02');
if(el3) { el3.hide(); }

Related

How to make a custom legend in angular-chart.js Pie Chart

I used angular-chart.js in my website to create a Pie chart, and I would like to customize the legend. By default, the legend shows the color and the label. (As shown in the picture below) I would like to add the value/data of that label, like what it shown in the tooltip of the chart.
This is my HTML code:
<canvas id="pie" class="chart chart-pie"
chart-data="chartData" chart-labels="chartLabels" chart-options="chartOptions">
</canvas>
Based on the angular-chart.js documentation, legend is now a Chart.js option so the chart-legend attribute has been removed.
That is why, in my JS code I've tried to add generateLabels, just in case this is what I need to customize the legend:
$scope.chartOptions = {
legend: {
display: true,
labels: {
generateLabels: function(chart){
console.log(chart.config);
}
}
}
};
But whenever I add this lines, it will not show the chart. I think it is an error or something. And I'm not sure, if generateLabels is the right option that I needed.
Can somebody teach me the right way to customize the legend to achieve what I wanted?
Thanks in advance!
Let me try shedding some light/answering your question:
generateLabels: does make custom labels,and replaces templates from v1 but in order to use it you have to get your chart information and reimplement legend labels adhering to the Legend Item Interface found in the docs and code. Sounds a bit cryptic, but in practice is somehow simple and goes like this:
var theHelp = Chart.helpers;
// You need this for later
// Inside Options:
legend: {
display: true,
// generateLabels changes from chart to chart, check the source,
// this one is from the doughnut :
// https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.doughnut.js#L42
labels: {
generateLabels: function(chart) {
var data = chart.data;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
var meta = chart.getDatasetMeta(0);
var ds = data.datasets[0];
var arc = meta.data[i];
var custom = arc && arc.custom || {};
var getValueAtIndexOrDefault = theHelp.getValueAtIndexOrDefault;
var arcOpts = chart.options.elements.arc;
var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
return {
// And finally :
text: ds.data[i] + "% of the time " + label,
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
index: i
};
});
}
return [];
}
}
}
Result:
Codepen: Chart.js Pie Chart Custom Legend Labels
There are other alternatives, if you notice on the pen/pie, the slices also have data information, that is from a plugin (check the pen)
Still another option, is to render the legend labels off canvas,for instance:
myPieChart.generateLegend();
Which gives you this Html:
"<ul class='0-legend'><li><span style='background-color:black'> </span>she returns it </li><li><span style='background-color:white'></span>she keeps it</li></ul>"
I haven't tried it, but I think you can modify it with the global method for your data Legend on the callback an it will give you a block of Html you can insert off canvas.

Multiple call to back-end (By curresponding backbone model) on clicking on pie-legend highcharts

I am using a highchart pie-legend graph in a backbone application.If i click on a portion of pie chart,it calls back-end for only 1 time. If I click again on a portion without getting chart redrawn,even then only 1 call to back end is there. But if I cause chart to be redrawn by clicking on a legend and then I click on a portion of pie-chart, it calls two times for back end. I can see it on console of firebug debugger. And if I again make chart to be redrawn by any change, calls to the back-end increase accordingly. How can I restrict these unwanted multiple calls on clicking pie-legend chart.
The click on legent is also captured and kept. And when I click on pie chart,it accumulates the number of clicks and send multiple calls to back-end through model.
Thanks is advance.
The code is as follows:
chart: {
backgroundColor: null,
events:{
redraw: function() {
var dataObj = this.series[0].data;
$.each(dataObj, function( index ) {
var pathObj = dataObj[index].graphic.element;
pathObj['contentValue']=dataObj[index].name;
$(pathObj).popoverClosable({
container:'div#chart-donut',
html: true,
trigger:'click',
placement: 'top',
content:'<div class="popover-dummy"></div>'
});
$(pathObj).on('click', function () {
//render the corresponding popover content
var spinner = new Spinner().spin();
$('div.popover-dummy').html(spinner.el);
var contentCategory=pathObj.point.name;
var model = Backbone.model;
if(!that.brandDetailsPopoverView || that.brandDetailsPopoverView == null){
that.brandDetailsPopoverView = new BrandDetailsPopoverView({model:model,brandName:that.selectedBrandName,topicId:that.curTopicId,brandId:that.brandId,contentCategory:contentCategory,groupId: that.selectedGroupId,el:"#discover-popover-content"});
}
that.brandDetailsPopoverView.render(contentCategory);
$('div.popover-dummy').html($('#discover-popover-content').html());
});
});
}
},
margin: [10,20,10,10]
},

jQuery UI Draggable / Sortable 4 column w/ CSS Transitions - Erratic Behavior

I am creating a simple drag and drop layout that incorporates 4 columns with the use of CSS easing effects when positioning. I have tried multiple solutions but nothing solves the problem. Eventually this will be an angularjs app.
Heres the JSfiddle (this is four columns so spread your browser to view the whole layout)
You will notice when you drag a module that sometimes it will let you snap to the grid and show the "placeholder" and some times it won't.
Sometimes the ".placeholder" which is the ".marker" in my example will randomly place the .marker div above the containing li elements causing this to happen.
Link to marker image
Is there a way to force the element to always be on the bottom element of all the li items of a parent ul?
Any help would be greatly appreciated!
var stylesheet = $('style[name=impostor_size]')[0].sheet;
var rule = stylesheet.rules ? stylesheet.rules[0].style : stylesheet.cssRules[0].style;
var setPadding = function(atHeight) {
rule.cssText = 'border-top-width: '+atHeight+'px';
};
$('.button-up').click(function(){
updateWidgetData();
});
$('.main-area ul').sortable({
connectWith: '.column',
cursor: 'move',
placeholder: 'marker',
forcePlaceholderSize: true,
opacity: 0.4,
start: function(event, ui){
setPadding(ui.item.height());
},
stop: function(event, ui){
ui.item.css({'top':'0','left':'0'}); //Opera fix
if(!$.browser.mozilla && !$.browser.safari)
updateWidgetData();
var next = ui.item.next();
next.css({'-moz-transition':'none', '-webkit-transition':'none', 'transition':'none'});
setTimeout(next.css.bind(next, {'-moz-transition':'border-top-width 0.1s ease-in', '-webkit-transition':'border-top-width 0.1s ease-in', 'transition':'border-top-width 0.1s ease-in'}));
}
}).disableSelection();
function updateWidgetData() {
var items = [];
$('.column').each(function() {
var columnId=$(this).attr('id');
$('.dragbox', this).each(function(i) {
var item = {
id: $(this).attr('id'),
order : i,
column: columnId
};
items.push(item);
});
});
var sortorder = { items: items };
//Pass sortorder variable to server using ajax to save state
$.post('updatePanels.php', 'data='+$.toJSON(sortorder), function(response) {
if(response=="success")
$("#console").html('<div class="success">Saved</div>').hide().fadeIn(1000);
setTimeout(function() {
$('#console').fadeOut(1000);
}, 2000);
});
}

ExtJS Carousel Implementation

I'm trying to make a carousel for displaying images, I got most of the functionality from a solution someone in sencha forums came up with. I made a few adjustments to the code and got it working at first glance.
Here's the original code on sencha forums...
http://www.sencha.com/forum/showthread.php?256456-an-Ext-JS-4-carousel-component&p=938789#post938789
This didn't work on ExtJS 4 so I made a few modifications for it to work and also to make it look better (to my eyes). Here's how it looks
I do have a problem or two though...
First off I can't figure out how to add a text over the images I'm displaying, I managed to add that line of text in the center but I also want to add a date to the images and that should display on top of each image container. I think it's pretty basic, but I can't figure out how... I don't have a full understanding of HTML, so that's not helping.
Secondly, and most important, I'm getting some weird behaviour when I close and reopen the window containing this carousel. I've seen this kind of behaviour before when using the same ID in multiple instances of a view in ExtJS, but I have changed all IDs to generate a new one whenever a new carousel window opens and still experience the same problem.
Here's what happens when I close and reopen the window...
And that happens with every window I open after closing the carousel
And last but not least!! I can't get the keydown event to work on this window, I have no clue why. I've tried setting the listener on the carousel container instead of the window but still get no firing whatsoever.
This is the code I'm using to create the carousel window...
var win = Ext.create('Ext.view.CarouselWindow');
win.show();
Ext.createWidget('carousel',{
xPos: win.getSize().width/2,
yPos: win.getSize().height/4,
FPS: 70,
reflHeight: 56,
height:'100%',
width:'100%',
reflGap:2,
bringToFront:true,
store:store,
images:store,
altBox:'imageNameLabel',
autoRotate: 'no',
renderTo: 'carousel-div',
listeners:{
keydown:function(){
console.log('asdasd')
}
}
});
This is the initComponent of the carousel component, which is rendered in the window.
initComponent: function(config) {
this.callParent(arguments);
this.container = this.renderTo ? Ext.get(this.renderTo) : this.up('container');
if (this.xRadius === 0){
this.xRadius = (this.container.getWidth()/2.3);
}
if (this.yRadius === 0){
this.yRadius = (this.container.getHeight()/6);
}
this.xCentre = this.xPos;
this.yCentre = this.yPos;
// Start with the first item at the front.
this.rotation = this.destRotation = Math.PI/2;
this.timeDelay = 1000/this.FPS;
// Turn on the infoBox
if(this.altBox !== '')
// Ext.get(this.altBox).applyStyles({display: 'block'});
if(this.titleBox !== '')
Ext.get(this.titleBox).applyStyles({display: 'block'});
//
// Turn on relative position for container to allow absolutely positioned elements
// within it to work.
this.container.applyStyles({ position:'relative', overflow:'hidden'});
// Setup the store.
this.initStore();
this.setUpContainerListener();
this.innerWrapper = this.container.createChild({
tag: 'div',
style: 'position:absolute;width:100%;height:100%;'
});
this.checkImagesLoaded();
},
And here's the Image component that the carousel uses...
/**
* #author Aymen ABDALLAH <aymen.abdallah#gmail.com>
* #docauthor Aymen ABDALLAH
*/
Ext.define('Ext.component.Image', {
config: {
orgWidth: 400,
orgHeight: 400,
reflHeight: 0,
reflOpacity: 0,
itemIndex: 0,
image: null,
reflection: null,
container: null,
alt: '',
title: '',
imageSrc: '',
imageOK: false
},
// id: '',
constructor: function(config){
this.initConfig(config);
this.imageOK = true;
this.image = new Ext.Element(document.createElement('img'));
this.image.set({
// id: this.id,
src: this.imageSrc,
class : 'carousel-image',
alt: this.alt,
title: this.title
});
this.image.setStyle({position : 'absolute'}); // This seems to reset image width to 0 on webkit!
},
setUpReflection: function(){
if (this.reflHeight > 0)
{
this.reflection = Ext.create('Ext.component.Reflection', {
imageHeight: this.orgHeight,
imageWidth: this.orgWidth,
image: this.image,
parent: this.container,
reflHeight: this.reflHeight,
reflOpacity: this.reflOpacity
});
}
},
generateId: function(){
// return Ext.data.UuidGenerator.create().generate();
},
getImage: function(){
return this.image;
}
});
I didn't want to flood this with code so I restricted to what I think might be useful, there might be some missing though, in that case just tell me and I'll update the post with the portion of the code you need.
EDIT
Here's a link to sencha fiddle showing the carousel and the error. To see the second error open the carousel by clicking the button, close it with ESC and then try to open it once again. You'll notice it either doesn't show or it shows like the screenshot I posted.
https://fiddle.sencha.com/#fiddle/2iu
EDIT 2
Just found out the problem comes from the images, if I comment these lines:
this.image = new Ext.Element(document.createElement('img'));
this.image.set({
id: this.id,
src: this.imageSrc,
class : 'carousel-image',
alt: this.alt,
title: this.title
});
the second error I listed disappears. Of course this is not a solution as the carousel won't display any image this way, but I thought this could be a useful piece of data for anyone interested in helping.
For those who visit this page (I know it's an old post),
The issue isn't actually with the second view, the first view causes a layout error.
The Ext.component.Image class is missing a render function, to fix this add
render: function () {
return;
}
to the class.
Not sure how to fix the other issue entirely, but you could change the image component to be a form/panel and have text, or use the caption tags.

How to apply seriesStyles to piechart in ExtJs dynamically

Am trying to set 'seriesstyles' to piechart dynamically from the JSON data. When the 'oneWeekStore' loads the JSON data, I wish to iterate through the 'color' of each record and setSeriesStyles dynamically to PieChart. Below is the snippet.
var oneWeekStore = new Ext.data.JsonStore({
id:'jsonStore',
fields: ['appCount','appName'],
autoLoad: true,
root: 'rows',
proxy:storeProxy,
baseParams:{
'interval':'oneWeek',
'fromDate':frmDt.getValue()
},
listeners: {load: {
fn:function(store,records,options) {
/*I wish iterate through each record,fetch 'color'
and setSeriesStyles. I tried passing sample arrays
as paramater to setSeriesStyles like
**colors= new Array('0x08E3FE','0x448991','0x054D56');
Ext.getCmp('test12').setSeriesStyles(colors)**
But FF throws error "this.swf is undefined". Could
you please let me know the right format to pass as
parameter. */
}
});
var panel = new Ext.Panel{
id: '1week', title:'1 week',
items : [
{ id:'test12',
xtype : 'piechart',
store : oneWeekStore,
dataField : 'appCount',
categoryField : 'appName',
extraStyle : {
legend:{
display : 'right',
padding : 5,
spacing: 2, font :color:0x000000,family:
'Arial', size:9},
border:{size :1,color :0x999999},
background:{color: 0xd6e1cc}
} } } ] }
My JSON data looks below:
{"success":true,"rows":[{"appCount":"9693814","appName":"GED","color":"0xFB5D0D"},{"appCount":"5731","appName":"SGEF"","color":"0xFFFF6B"}]}
Your guidance is highly appreciated
You have a classic race condition there - your setting an event in motion that relies on a Component who's status is unknown.
The event your setting off is the loading of the data Store, when that has finished loading it is trying to interact with the Panel, but at that point we don't know if the Panel has been rendered yet.
Your best bet is to make one of those things happen in reaction to the other, for example:
1 ) load the store
2 ) on load event fired, create the panel
var oneWeekStore = new Ext.data.JsonStore({
id:'jsonStore',
...,
listeners: {
load:function(store,records,options) {
var panel = new Ext.Panel({
...,
seriesStyles: colors,
...
});
}
}
});
or
1 ) create the panel (chart)
2 ) on render event of the panel, load the store (remove autoLoad:true)
var panel = new Ext.Panel({
id: '1week',
...,
listeners: {
render: function(pnl){
oneWeekStore.load();
}
}
});
Hope that helps.

Resources