PDA

View Full Version : Ext.ux.chart (non-flash version,pure js)



cdj
2 Aug 2009, 7:21 PM
hi ~my friends
i'd like to share my extension,
there was a Ext.chart already available,but it goes along with the adobe flash.my solution is totally pure javascript(thanks to google iecanvas).so ~if you don't want use flash in application,you can use my extension instead.:>
wish you have interesting with it.:D
below is the constructor code:


Ext.ns("Ext.ux.chart");

/**
* @class Ext.ux.chart ??????
* @author cdj
* @version beta1.4.4
*/

Ext.ux.chart = Ext.extend(Ext.Component, {
/**
* @cfg ?????
*/
width:300,
/**
* @cfg ?????
*/
height:160,
/**
* @cfg ?????????????
*/
offsets:'5,40,5,5',
/**
* @cfg ??css?
*/
baseCls:'ux-chart',
/**
* @cfg ?????
*/
borderWidth:1,
/**
* @cfg store
*/
store:{},
initComponent:function(){
Ext.ux.chart.superclass.initComponent.call(this);
this.addEvents(
//supported event list here
);
this.ds = this.store;
},

onRender:function(ct,pos){
this.preCreateSkeleton();
this.createSkeleton(ct,pos);
this.createXHandler();//behavior

this.romCVX.init();
this.ramCVX.init();
this.ds.on('load',this.onLoad,this);
},

/**
* ????????????????
*/
preCreateSkeleton:function(){
var _off = this.offsets.split(',');
Ext.applyIf(this,{
nOffset:Ext.isGecko?new Number(_off[0])+1:new Number(_off[0]),//?????????
eOffset:new Number(_off[1]),
sOffset:new Number(_off[2]),
wOffset:Ext.isGecko?new Number(_off[3])+7:new Number(_off[3])
});
this.chartHeight = this.height + this.sOffset + this.nOffset;//??
this.chartWidth = this.width + this.wOffset + this.eOffset;

},

/**
* ???????????,???????????
* @param ct ?????????
* @param pos
*/
createSkeleton:function(ct,pos){
var ramLayerId = Ext.id("","ui2-chart-ram-cvs-");
var romLayerId = Ext.id("","ui2-chart-rom-cvs-");
var labelLayerId = Ext.id("","ui2-chart-label-");//???
var evLayerId = Ext.id("","ui2-chart-ev-");//???
var tl = "position:absolute;left:0px;top:0px;";
this.style += "position:relative;";
var tpl = new Ext.XTemplate(
'<div>',
'<canvas id ='+romLayerId+' width = "'+this.chartWidth+'" height = "'+this.chartHeight+'" style='+tl+'background:'+this.bgColor+'></canvas>',//things that wouldn't be changed
'<div id = "'+labelLayerId+'" style = "position:absolute;left:0px;top:0px;"></div>',//?????
'<canvas id ='+ramLayerId+' width = "'+this.chartWidth+'" height = "'+this.chartHeight+'" style='+tl+'></canvas>',//things that would be changed in run-time
'<div id = "'+evLayerId+'" style = "position:absolute;left:0px;top:0px;"></div>',//?????
'</div>'
);
this.el = tpl.append(ct,"",true);
if(this.baseCls){
this.el.addClass(this.baseCls);
}
if(this.cls){
this.el.addClass(this.cls);
}
if(this.id){
this.el.dom.id = this.el.id = this.id;
}
this.evct = Ext.get(evLayerId);
var ramCV = this.el.child("#"+ramLayerId,true);
this.lbct = Ext.get(labelLayerId);
var romCV = this.el.child("#"+romLayerId,true);
if(Ext.isIE){
ramCV = Ext.get(window.G_vmlCanvasManager.initElement(ramCV)).dom;
romCV = Ext.get(window.G_vmlCanvasManager.initElement(romCV)).dom;
}
this.ramCVX = ramCV.getContext('2d');
this.romCVX = romCV.getContext('2d');

},

/**
* rom?????? override it
*/
romLayerInitial:Ext.emptyFn,

/**
* ram?????? override it
*/
ramLayerInitial:Ext.emptyFn,

/**
* ram????? override it
*/
draw:Ext.emptyFn,

/**
* ram????? override it
*/
redraw:Ext.emptyFn,

createXHandler:function(){
Ext.applyIf(this,{
gridBgColor:this.colors.gridbg,
gridColor:this.colors.grid,
frameColor:this.colors.frame,
lineColor:this.colors.line
});

this.romCVX.init = this.romLayerInitial.createDelegate(this.romCVX,[this]);
delete this.romLayerInitial;

Ext.apply(this.ramCVX,{
init :this.ramLayerInitial.createDelegate(this.ramCVX,[this]),
draw :this.draw.createDelegate(this.ramCVX,[this]),
redraw:this.redraw.createDelegate(this.ramCVX,[this])
});

delete this.romLayerInitial;
delete this.draw;
delete this.redraw;
},

addLabel:function(conf){
var lbf = {};
Ext.apply(lbf,conf,{
id:Ext.id('','ui2-monitor-label-'),
position:[0,0],
tag:'span'
});
if(typeof lbf.style != "undefined"){
lbf.style += ";font-size:12px;white-space:nowrap";
}else {
lbf.style = "font-size:12px;white-space:nowrap";
}
if(typeof lbf.p == "undefined"){
lbf.p = lbf.position;
}
//?????font-family???????‘??’ie???????
lbf.style += (";font-family:tahoma,arial,helvetica,sans-serif;position:absolute;left:"+lbf.p[0]+"px;top:"+lbf.p[1]+"px");
delete lbf.p;
delete lbf.position;
if(lbf.vmode){
lbf.style += ';writing-mode:tb-rl;';
delete lbf.vmode;
}

if(typeof lbf.background != "undefined"){
lbf.style += (";background:"+lbf.background);
}
var label = this.lbct.createChild(lbf,'',false);
return label;
},
getStore:function(){
return this.store;
},
/**
* override it
*/
onLoad:Ext.emptyFn
})

/**
* ??????
* @author cdj
* @usage:
* var histogram = new Ext.ux.chart.Histogram({
//renderTo:cdjel,
width:300,
height:200,
colSize:20,
gapSize:0.9,
_coloffset:30,
offsets:'10,0,80,10',
valueField:'value',
nameField:'name',
store:new Ext.data.SimpleStore({
fields:["name","value"],
autoLoad:true,
url:'res.json'
}),
colors:{
gridbg:'rgb(241,233,196)',
grid:'rgb(196,196,196)',
frame:'rgb(0,0,0)',
line:'rgb(0,0,0)'
},
yAxis:[{
text:'10K',
value:10*1024
},{
text:'1K',
value:1*1024
},{
text:'500bytes',
value:500
},{
text:'100bytes',
value:100
},{
text:'10bytes',
value:10
}]
});
*/
Ext.ux.chart.Histogram = Ext.extend(Ext.ux.chart, {
xfontSize:12,
gapScale:0.2,
colsLeftOffset:20,//????
xTickTpl:"",
/**
* @cfg ??
*/
colors:{
gridbg:'rgb(241,233,196)',
grid:'rgb(196,196,196)',
frame:'rgb(0,0,0)',
line:'rgb(0,0,0)'
},

/**
* rom??????
*/
romLayerInitial:function(chart){
chart.xScale = (chart.width - 2*chart.borderWidth)/chart.xAxisN;
chart.yScale = (chart.height - 2*chart.borderWidth)/chart.yAxis.length;
this.save();
this.translate(chart.wOffset,chart.nOffset);
this.fillStyle = chart.gridBgColor;
this.fillRect(0,0,chart.width,chart.height);
this.fill();
this.strokeStyle = chart.frameColor;
this.moveTo(0,0);
this.lineTo(0,chart.height);
this.lineTo(chart.width,chart.height);
this.lineTo(chart.width,0);
this.lineTo(0,0);
this.stroke();
// draw the grid and ticks

this.strokeWidth = chart.borderWidth;//add by cj

this.strokeStyle = chart.gridColor;
var _p = [];// position for label
var _s;// scale for each tick
for(var i = 0;i < chart.yAxis.length;i++){
_s = i*chart.yScale;
this.moveTo(0,_s);
this.lineTo(chart.width+5,_s);// this '5' is the small line for tick
_p[0] = chart.chartWidth - chart.eOffset + 6; // this '4' is just for adjust the tick's position
_p[1] = _s +3;
chart.addLabel({
position:_p,
//vmode:true,
html:chart.yAxis[i].text
})
}
this.stroke();
//eof draw
},
ramLayerInitial:function(chart){
this.save();
this.translate(chart.wOffset,chart.nOffset);
this.lineStyle = chart.lineColor;
},
/**
* @override ??onload
*/
onLoad:function(){
this.doDataConvert();
this.ramCVX.clearRect(0,0,10000,10000);
if(this.evct.first()){
var id = this.evct.id;
Ext.destroy(this.evct);//reconstruct evct layer
this.evct = Ext.DomHelper.append(this.el,{
id:id
},true);
}else {
//do nothing
}
this.ramCVX.draw();
Ext.ux.chart.Histogram.superclass.onLoad.call(this);
},
/**
* @private ????
* ?????column modal??????????????
* ????????store??????????????????????
* ???????????????????????draw???store??????
*/
doDataConvert:function(){
this.pd = {};//???????,data for paint
var sow = (this.width-this.colsLeftOffset)/this.ds.getCount();//self owned width

//calculate gapWidth
var gw = sow*this.gapScale;

//calculate every ColumnWidth
var cw = sow - gw;
var cols = [];
for(var i=0,cm = this.columnModal;i<cm.length;i++){
//Ext.log(cm[i].width)
var _tpl = new Ext.XTemplate(cm[i].tipTpl||"{"+cm[i].dataIndex+"}");
_tpl.compile();
var c = {
width:cm[i].width*cw,
tipTpl:_tpl,
dataIndex:cm[i].dataIndex,
color:cm[i].color || "#000"
//,color:"rgba()"
};
cols.push(c);
}
var _xpl = new Ext.XTemplate(this.xTickTpl);
_xpl.compile();
Ext.apply(this.pd,{
gapWidth:gw,
xTpl:_xpl,
selfOwnedWidth:sow,
columnsWidth:cw,
colCfgs:cols
})
},
/**
* @override ???????
*/
draw:function(chart){
var pd = chart.pd;
var cf = pd.colCfgs;
this.beginPath();
this.save();
this.translate(chart.colsLeftOffset+chart.borderWidth,chart.borderWidth);
var parseColor = Ext.ux.chart.ColorManager.parseColor.createDelegate(Ext.ux.chart.ColorManager);
chart.ds.each(function(r,i){
var _off = 0;//??????????
for(var ii = 0;ii<cf.length;ii++){

var _x = i*pd.selfOwnedWidth+_off;
var _y = chart.getYPixelByValue(r.get(cf[ii].dataIndex));
var _w = cf[ii].width;
var _h = chart.height-2*chart.borderWidth-_y;
var _clor = parseColor(cf[ii].color);
//begin render column
var gradient = this.createLinearGradient(_x,_y,_x+_w,_y);
gradient.addColorStop(0, _clor.s);
gradient.addColorStop(1, _clor.e);
this.fillStyle = gradient;
this.fillRect(_x,_y,_w,_h);
this.fill();

//???
var m = parseInt(cf[ii].width*0.5);
var gradient2 = this.createLinearGradient(_x+m,_y,_x+_w,_y);
gradient2.addColorStop(0, 'rgba(235,245,235,0.2)');
gradient2.addColorStop(1, 'rgba(235,245,235,0.6)');
this.fillStyle = gradient2;
this.fillRect(_x+m,_y,_w-m,_h);
this.fill();
//eof render column

//add tip
var _ev = chart.addBlankImage({
p:[chart.wOffset+chart.colsLeftOffset+_x,_y+chart.nOffset],
height:_h,
width:_w,
background:''
});
new Ext.ToolTip({
target: _ev,
title: cf[ii].title || pd.xTpl.apply(r.data),
width:200,
html: cf[ii].tipTpl.apply(r.data),
trackMouse:true
});
//eof add tip

_off += _w;
}//eof pd cols

var tx= i*pd.selfOwnedWidth+0.5*pd.columnsWidth;
//TODO ???
if(Ext.isGecko){
this.save();
this.fillStyle = chart.lineColor;
this.translate(tx-parseInt(chart.xfontSize/6),chart.height+5);
this.rotate(90 * Math.PI / 180);
this.mozTextStyle = chart.xfontSize+"px simsun";
this.mozDrawText(pd.xTpl.apply(r.data));
this.restore();
}else {
//ie
chart.addLabel({
html:pd.xTpl.apply(r.data),
p:[chart.colsLeftOffset + tx-parseInt(chart.xfontSize/6)+chart.wOffset,chart.height+chart.nOffset+5],
vmode:true
})
}
},this);
this.closePath();
this.stroke();
this.restore();
},
/**
* ??????
*/
reconstruct:function(config){
Ext.apply(this,config);
//clear up rom and ram layer
//this.ramCVX.restore();
this.ramCVX.restore();
//this.ramCVX.restore();
this.ramCVX.clearRect(0,0,10000,10000);

if(this.evct.first()){
var id = this.evct.id;
Ext.destroy(this.evct);//reconstruct evct layer
this.evct = Ext.DomHelper.append(this.el,{
id:id
},true);
}else {
//do nothing
}
this.romCVX.restore();
this.romCVX.clearRect(0,0,10000,10000);

if(this.lbct.first()){
var id = this.lbct.id;
Ext.destroy(this.lbct);//reconstruct evct layer
this.lbct = Ext.DomHelper.append(this.el,{
id:id
},true);
}else {
//do nothing
}
this.romCVX.init();
this.ramCVX.init();


},
/**
* ????
*/
redraw:function(){
this.ramCVX.clearRect(0,0,10000,10000);
if(this.evct.first()){
var id = this.evct.id;
Ext.destroy(this.evct);//reconstruct evct layer
this.evct = Ext.DomHelper.append(this.el,{
id:id
},true);
}else {
//do nothing
}
this.ramCVX.draw();
},
/**
* @private
* @describe addBlankImage
*/
addBlankImage:function(conf){
var lbf = {};
Ext.apply(lbf,conf,{
position:[0,0],
src:Ext.BLANK_IMAGE_URL,
tag:'img',
width:10,
height:10
});
if(lbf.style){
lbf.style += ';font-size:12px;white-space:nowrap';
}else {
lbf.style = 'font-size:12px;white-space:nowrap';
}
if(!lbf.p){
lbf.p = lbf.position;
}
lbf.style += (";position:absolute;left:"+lbf.p[0]+"px;top:"+lbf.p[1]+"px;height:"+lbf.height+"px;width:"+lbf.width);
delete lbf.p;
delete lbf.position;
if(lbf.vmode){
lbf.style += ';writing-mode:tb-rl';
delete lbf.vmode;
}
if(lbf.background){
lbf.style += (";background:"+lbf.background);
}
var label = this.evct.createChild(lbf,'',false);
return label;
},
/**
* @private
* @describe ??Y??????????????????
* @returns Y???
*/
getYPixelByValue:function(v){
var max,min;
for(var i = 0;i < this.yAxis.length;i++){
if(v >= this.yAxis[i].value){
max = i==0?v:this.yAxis[i-1].value;
min = this.yAxis[i].value;
break;
}else {
continue;
}
}
var i = i-1;
if(typeof min == 'undefined'){
min = 0;
max = this.yAxis[i].value;
}
var result;
if(max == min){
result = 0;
}else{
result = (1-(v - min)/(max - min) + i)*this.yScale;
}
return result;
}
});

Ext.ux.chart.ColorManager = {
parseColor: function(str){

var result;

// rgb(num,num,num)
if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str)))
return this.getColor(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]));

// rgba(num,num,num,num)
if((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)))
return this.getColor(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]), parseFloat(result[4]));

// rgb(num%,num%,num%)
if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str)))
return this.getColor(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55);

// rgba(num%,num%,num%,num)
if((result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)))
return this.getColor(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4]));

// #a0b1c2
if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str)))
return this.getColor(parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16));

// #fff
if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str)))
return this.getColor(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16));

// Otherwise, we're most likely dealing with a named color.
var name = str.trim().toLowerCase();
if(name == 'transparent'){
return this.getColor(255, 255, 255, 0);
}
return ((result = this.colors[name])) ? this.getColor(result[0], result[1], result[2]) : false;
},
getColor: function(r, g, b, a){
this.rgba = ['r','g','b','a'];
var x = 4;
while(-1<--x){
this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0);
}
return this.normalize();
},
normalize: function(){
var limit = this.limit;
this.r = limit(parseInt(this.r), 0, 255);
this.g = limit(parseInt(this.g), 0, 255);
this.b = limit(parseInt(this.b), 0, 255);
this.a = limit(this.a, 0, 1);
return {s:"rgba("+this.r+","+this.g+","+this.b+","+this.a+")",e:"rgba("+this.r+","+this.g+","+this.b+","+(this.a-0.5)+")"};
//return "rgba("+this.r+","+this.g+","+this.b+","+this.a+")";
},
limit: function(val,minVal,maxVal){
return Math.max(Math.min(val, maxVal), minVal);
},
colors : {
aqua:[0,255,255],
azure:[240,255,255],
beige:[245,245,220],
black:[0,0,0],
blue:[0,0,255],
brown:[165,42,42],
cyan:[0,255,255],
darkblue:[0,0,139],
darkcyan:[0,139,139],
darkgrey:[169,169,169],
darkgreen:[0,100,0],
darkkhaki:[189,183,107],
darkmagenta:[139,0,139],
darkolivegreen:[85,107,47],
darkorange:[255,140,0],
darkorchid:[153,50,204],
darkred:[139,0,0],
darksalmon:[233,150,122],
darkviolet:[148,0,211],
fuchsia:[255,0,255],
gold:[255,215,0],
green:[0,128,0],
indigo:[75,0,130],
khaki:[240,230,140],
lightblue:[173,216,230],
lightcyan:[224,255,255],
lightgreen:[144,238,144],
lightgrey:[211,211,211],
lightpink:[255,182,193],
lightyellow:[255,255,224],
lime:[0,255,0],
magenta:[255,0,255],
maroon:[128,0,0],
navy:[0,0,128],
olive:[128,128,0],
orange:[255,165,0],
pink:[255,192,203],
purple:[128,0,128],
violet:[128,0,128],
red:[255,0,0],
silver:[192,192,192],
white:[255,255,255],
yellow:[255,255,0]
}
};
Ext.reg('ux-chart-histogram', Ext.ux.chart.Histogram);
and below is the usage example:



Ext.BLANK_IMAGE_URL = 'lib/ext/resources/images/default/s.gif';

Ext.onReady(function(){
//????
//new a chart
var histogram = new Ext.ux.chart.Histogram({
width:700,
height:300,
//renderTo:cdjel,
offsets:'10,40,80,10',
store:new Ext.data.SimpleStore({
fields:["name","value1","value2"],
autoLoad:true,
url:'res.json'
}),
xTickTpl:"2009 ?{name}",
columnModal:[{
dataIndex:'value1',
width:0.5,
tipTpl:"??????{value1}",
color:'olive'
//color:"rgba(0,0,0,1)"
},{
dataIndex:'value2',
//tipTpl:"??????{value1}",
//color:'purple',
width:0.2
},{
dataIndex:'value2',
width:0.3,
tipTpl:"??????{value2}",
color:'navy'
}],
colors:{
gridbg:'rgb(241,233,196)',
grid:'rgb(196,196,196)',
frame:'rgb(0,0,0)',
line:'rgb(0,0,0)'
},
yAxis:[{
text:'10K',
value:10*1024
},{
text:'1K',
value:1*1024
},{
text:'500bytes',
value:500
},{
text:'100bytes',
value:100
},{
text:'10bytes',
value:10
}],
listeners:{
render:function(){
//Ext.log("my chart rendered");
}
}
});


var win = new Ext.Window({
width:800,
height:460,
title:'????',
items:[histogram]
})
win.show();

})

in this example,your data from the server should looked like this :


[
['??','1020','100'],
['??','300','500'],
['??','500','200'],
['??','200','400'],
['??','200','700'],
['??','300','100'],
['??','500','600'],
['??','1000','100']
]
there is a screenshot and a demo in the attachment.

to run this demo,you just need to take four steps.
1.download it.
2.decompress all files to the web application deployment folder(suppose you named"app").
your folder structure under the "app" should be :
/lib/mylib/excanvas.js
/lib/mylib/UI2.chart.Histogram.js
histogram.js
histogram.html
3.mkdir /lib/ext ,and copy the ext lib files to it
/lib/ext/resources/* (css and image files)
/lib/ext/ext-base.js
/lib/ext/ext-all.js
4.launch your server --> view the histogram.html.

you can modify my code as you wish, and use the modified code in your products.
notice that :
you must include the "google iecanvas" (which named excanvas.js) in your page,otherwise it won't work.
you can download it from my attachment or http://excanvas.sourceforge.net/


<!--[if IE]><script type="text/javascript" src="lib/mylib/excanvas.js"></script><![endif]-->
.its size is just 27k.

I'd appreciate comments and/or suggestions.

sorry for my broken english,i couldn't express my thinking very well,hope you could understand what i wrote:">

cdj
2 Aug 2009, 7:28 PM
???????????

lzhengkang
2 Aug 2009, 7:38 PM
???????????????????:D

cdj
2 Aug 2009, 7:41 PM
?? ?????

Komes
3 Aug 2009, 5:24 AM
????????? !!
??

lxfliu
25 Oct 2009, 6:40 PM
????

?? Flash ????

Scorpie
25 Oct 2009, 11:59 PM
Nice, looks alot like Ext Flot !

Matthias_WB
31 Oct 2009, 10:57 AM
Why the conversation is not in english??? Many people can read english posts, but smal count of people can understand chinese.

==============

?????????????????????????????????????

loverofdream
3 Nov 2009, 7:46 PM
??????

cdj
14 Nov 2009, 3:42 AM
????

?? Flash ????

??;)

cdj
14 Nov 2009, 3:47 AM
Nice, looks alot like Ext Flot !

yep,actually i use the same technology as Flotr does

cdj
14 Nov 2009, 4:00 AM
Why the conversation is not in english??? Many people can read english posts, but smal count of people can understand chinese.

==============

?????????????????????????????????????
:Dsorry ,my friend.i'm just poor in english.

BTW,1,300,000,000 is not a small count

cdj
14 Nov 2009, 4:14 AM
??????
??

379548695
14 Dec 2009, 12:11 AM
?????????2.x???????

zyzlsg
14 Dec 2009, 9:59 AM
???,??,?????????,???????,????????,????,????????????.??

realjax
14 Dec 2009, 12:34 PM
I dunno..


It's all chinese to me.


:D

379548695
14 Dec 2009, 4:31 PM
??
????????????????:)

sexy22
11 Jan 2010, 9:38 PM
?????

jarrednicholls
13 Jan 2010, 10:53 AM
BTW,1,300,000,000 is not a small count

Haha, that made me laugh...

eff844
30 Jan 2010, 4:32 AM
??,,,?? extjs ?flash chart ?????????????

?????line chart ??????????????????????

?......?????

xiaotot
3 Feb 2010, 7:43 AM
CDJ??????????

ice42
10 Feb 2010, 7:35 PM
Why the conversation is not in english??? Many people can read english posts, but smal count of people can understand chinese.

==============

?????????????????????????????????????

Because were are chinese people.:)

ice42
10 Feb 2010, 7:39 PM
By the way,do not translation english to chinese via google.It is rubbish.:D

cdj
11 Mar 2010, 7:19 AM
?????????2.x???????
??????????2.0??

cdj
11 Mar 2010, 7:20 AM
???,??,?????????,???????,????????,????,????????????.??
????????????????????????

cdj
11 Mar 2010, 7:21 AM
????????????????:)
???????????Ext.ux.chart.Pie???????

cdj
11 Mar 2010, 7:22 AM
?????
??

cdj
11 Mar 2010, 7:23 AM
Haha, that made me laugh...
:D

cdj
11 Mar 2010, 7:24 AM
??,,,?? extjs ?flash chart ?????????????

?????line chart ??????????????????????

?......?????
?????????????????????????flash??????

cdj
11 Mar 2010, 7:29 AM
CDJ??????????
????

lj2008
27 Apr 2010, 11:27 PM
???????????????????????