marmstrong
02-06-2007, 05:41 PM
I have been working with vector graphics for a mapping app and thought it might be useful to include some of the functionality in Ext. I'm also a big fan how clean Ext is so I threw together some base objects and a rough line graph. I tried to follow the patterns and approach that Jack uses.
The current implementation of the base objects targets vml but svg support could be added relatively easily. (ie always seems to be a corporate standard...)
Here are the base classes:
/**
* @class YAHOO.ext.Line
* @extends YAHOO.ext.util.Observable
* Simple Vector Line class
* @cfg {Function} handler A function called when the Line is hovered
* @cfg {Object} scope The scope of the handler
* @cfg {String} Id optional to identify the line
* @cfg {Coord} from beginning point of line
* @cfg (Coord} to end point of line
* @cfg {Number} strokeweight width of line
* @cfg {String} strokecolor color of line
* @constructor
* Create a new line
* @param {String/HTMLElement/Element} renderTo The element to append the button to
* @param {Object} config The config object
*/
YAHOO.ext.Vector.Line = function(renderTo,config){
this.id = YAHOO.util.Dom.generateId();
YAHOO.ext.util.Config.apply(this,config);
this.events = {
};
if(renderTo){
this.render(renderTo);
}
}
YAHOO.extendX(YAHOO.ext.Vector.Line, YAHOO.ext.util.Observable, {
render : function(renderTo){
this.lineTemplate = new YAHOO.ext.DomHelper.Template('<v:line id="' + this.id + '" ' +
'stroke=true strokecolor="' + this.strokecolor + '" strokeweight="' + this.strokeweight + '"' +
' style="position:relative;left:0px;top0px" ' + 'coordorigin="0,0"' +
' to="' + this.to.x + ' ' + this.to.y + '" from="' + this.from.x + ' ' + this.from.y + '"></v:line>');
this.el = this.lineTemplate.append(getEl(renderTo).dom, [''], true);
},
/**
* Returns the line element
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
}
});
/**
* @class YAHOO.ext.Polyline
* @extends YAHOO.ext.util.Observable
* Simple Vector Line class
* @cfg {Function} handler A function called when the Line is hovered
* @cfg {Object} scope The scope of the handler
* @cfg {Number} strokeweight width of line
* @cfg {Array} pts x and y pairs
* @cfg {String} strokecolor color of line
* @constructor
* Create a new line
* @param {String/HTMLElement/Element} renderTo The element to append the button to
* @param {Object} config The config object
*/
YAHOO.ext.Vector.Polyline = function(renderTo,config){
YAHOO.ext.util.Config.apply(this,config);
this.events = {
/**
* @event hover
* Fires when line is hovered over
* @param {Line} this
* @param {EventObject} e The hover event
*/
'hover' : true
};
if(renderTo){
this.render(renderTo);
}
}
YAHOO.extendX(YAHOO.ext.Vector.Polyline, YAHOO.ext.util.Observable, {
render : function(renderTo){
var s = "";
for(var i=0; i<this.pts.length; i++) {
s += this.pts[i].x + ' ' + this.pts[i].y + ' ';
}
this.polyTemplate = new YAHOO.ext.DomHelper.Template('<v:polyline id="' + YAHOO.util.Dom.generateId() + '" ' +
'filled=false stroke=true strokecolor="' + this.strokecolor + '" strokeweight="' + this.strokeweight +
'" Points="' + s + '"></v:polyline>');
this.el = this.polyTemplate.append(getEl(renderTo).dom, [''], true);
},
/**
* Returns the polyline element
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
}
});
/**
* @class YAHOO.ext.Box
* @extends YAHOO.ext.util.Observable
* Simple Vector Rectangle class
* @cfg {Number} strokeweight width of line
* @cfg {String} strokecolor color of line
* @constructor
* Create a new line
* @param {String/HTMLElement/Element} renderTo The element to append the button to
* @param {Object} config The config object
*/
YAHOO.ext.Vector.Box = function(renderTo,config){
this.shadow = 'true';
this.strokecolor = 'black';
this.strokweight = '1';
this.cls ='graph-box';
YAHOO.ext.util.Config.apply(this,config);
this.events = {
};
if(renderTo){
this.render(renderTo);
}
}
YAHOO.extendX(YAHOO.ext.Vector.Box, YAHOO.ext.util.Observable, {
render : function(renderTo){
this.boxTemplate = new YAHOO.ext.DomHelper.Template('<v:rect id="' +
YAHOO.util.Dom.generateId() + '" ' +
' class=' + this.cls + ' style="position:relative;width:' + this.width + ';height:' + this.height + ';' +
'left:0px;top:0px;"' +
' strokecolor=' + this.strokecolor + ' strokeweight=' + this.strokeweight +
'><v:shadow on=' + this.shadow + ' />' +
'</v:rect>');
this.el = this.boxTemplate.append(getEl(renderTo).dom, [''], true);
},
/**
* Returns the line element
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
}
});
YAHOO.ext.Vector.Group = function(renderTo, config){
YAHOO.ext.util.Config.apply(this,config);
this.groupTemplate = new YAHOO.ext.DomHelper.Template('<v:group ' +
'style="position:relative;left:0px;top:0px;width:' + this.width +
'; height:' + this.height + ';" ' +
'coordsize="' + this.width + ',' + this.height + '" coordorigin="0,0">');
this.el = this.groupTemplate.append(getEl(renderTo).dom, [''], true);
this.getEl = function(){
return this.el;
}
}
The line graph class:
YAHOO.namespace('ext.Graph');
/**
* @class YAHOO.ext.Graph.LineGraph
* @extends YAHOO.ext.util.Observable
* Simple Vector Line Graph class
* @cfg {Object} graphData array of array object
* Example: [[{x:0,y:5},{x:1,y:10}],[{x:0,y:8},{x:1,y:13}]]
* @constructor
* Create a new line
* @param {Object} config The config object
*/
YAHOO.ext.Graph.LineGraph = function(renderTo,config){
YAHOO.ext.util.Config.apply(this,config);
if(renderTo){
this.render(renderTo);
}
}
YAHOO.extendX(YAHOO.ext.Graph.LineGraph, YAHOO.ext.util.Observable, {
render : function(renderTo){
this.graphTemplate = new YAHOO.ext.DomHelper.Template('<div></div>');
this.container = getEl(renderTo);
this.width = this.container.getWidth();
this.height = this.container.getHeight();
this.el = this.graphTemplate.append(this.container.dom, [''], true);
this.el.addClass('graph-main');
this.el.setHeight(this.height);
this.el.setWidth(this.width);
this.mainX = 25;
this.mainY = this.height -25;
this.lengthY = this.height - this.mainY;
this.lengthX = this.width - this.mainX;
var x = this.getMaxX(this.graphData);
var y = this.getMaxY(this.graphData);
this.scaleX = parseFloat(x/(this.lengthX-this.mainX));
this.scaleY = parseFloat(y/(this.mainY-this.lengthY));
Log.log('max x: ' + x + ' max y: ' + y);
this.rescaleData();
this.adjustData();
this.group = YAHOO.ext.Vector.VectorManager.getGroup(this.el,
{
height: this.height,
width: this.width
});
this.graphBox = YAHOO.ext.Vector.VectorManager.getBox(this.group.getEl(),
{
strokecolor: 'gray',
height: this.height,
width: this.width
});
this.xAxis = YAHOO.ext.Vector.VectorManager.getLine(this.group.getEl(),
{
id: 'xLine',
strokecolor: 'steelblue',
strokeweight: '1px',
from:{x:this.mainX,y:this.mainY},
to:{x:this.lengthX,y:this.mainY}
});
this.yAxis = YAHOO.ext.Vector.VectorManager.getLine(this.group.getEl(),
{
id: 'yLine',
strokecolor: 'steelblue',
strokeweight: '1px',
from:{x:this.mainX,y:this.mainY},
to:{x:this.mainX,y:this.lengthY}
});
for(var i=0; i<this.graphData.length; i++) {
Log.log('graph line: ' + i);
YAHOO.ext.Vector.VectorManager.getPoly(this.group.getEl(),
{
strokecolor: 'blue',
strokeweight: '1px',
pts: this.graphData[i]
});
}
// Log.log(getEl('yLine').dom.from + ' and to: ' + getEl('yLine').dom.to);
},
rescaleData : function(){
for(var i=0; i<this.graphData.length; i++) {
for(var j=0; j<this.graphData[i].length; j++) {
this.graphData[i][j].x = this.graphData[i][j].x / this.scaleX;
this.graphData[i][j].y = this.graphData[i][j].y / this.scaleY;
}
}
},
adjustData : function(){
for(var i=0; i<this.graphData.length; i++) {
for(var j=0; j<this.graphData.length; j++) {
this.graphData[i][j].x = this.graphData[i][j].x + this.mainX;
this.graphData[i][j].y = this.mainY - this.graphData[i][j].y;
}
}
},
getMaxX : function(obj){
var m = 0;
for(var i=0; i<obj.length; i++) {
for(var j=0; j<obj[i].length; j++) {
(m<obj[i][j].x)?m=obj[i][j].x:'';
}
}
this.maxX = m;
return m;
},
getMaxY : function(obj){
var m = 0;
for(var i=0; i<obj.length; i++) {
for(var j=0; j<obj[i].length; j++) {
(m<obj[i][j].y)?m=obj[i][j].y:'';
}
}
this.maxY = m;
return m;
},
/**
* Returns the line element
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
}
});
I almost forgot, there is also a vector manager class. My thought is that this class would handle vml/svg decision. Kind of like a factory pattern.
YAHOO.namespace('ext.Vector');
/**
* @class YAHOO.ext.Vector.VectorManager
* This class is a singleton that manages vector objects
*/
YAHOO.ext.Vector.VectorManager = new function(){
var brows = YAHOO.ext.util.Browser;
var vectorType = 'vml'; //vml or svg
/**
* Sets up required vector graphics options per browser
*/
this.setupVector = function(){
if(brows.isIE||brows.isIE7){
var baseHtml = document.getElementsByTagName('html')[0];
baseHtml.setAttribute("xmlns:v","urn:schemas-microsoft-com:vml");
var h = YAHOO.ext.Element.get(baseHtml, true);
vectorType = 'vml';
}else{
vectorType = 'svg';
}
}
this.getLine = function(renderTo, config){
if(vectorType == 'vml'){
return new YAHOO.ext.Vector.Line(renderTo, config);
}
}
this.getPoly = function(renderTo, config){
if(vectorType == 'vml'){
return new YAHOO.ext.Vector.Polyline(renderTo, config);
}
}
this.getBox = function(renderTo, config){
if(vectorType == 'vml'){
return new YAHOO.ext.Vector.Box(renderTo, config);
}
}
this.getGroup = function(renderTo, config){
if(vectorType == 'vml'){
return new YAHOO.ext.Vector.Group(renderTo, config);
}
}
}
YAHOO.ext.EventManager.onDocumentReady(YAHOO.ext.Vector.VectorManager.setupVector, YAHOO.ext.Vector.VectorManager, true);
The line of code to create a graph:
function createNewLineGraph(){
var g = new YAHOO.ext.Graph.LineGraph('vmltest', {stroke: 'true',
graphData: [
[{x:0,y:0},
{x:1,y:75},
{x:2,y:100},
{x:3,y:75}],
[{x:0,y:10},
{x:1,y:65},
{x:2,y:120},
{x:3,y:100}]
]
});
}
I welcome feedback.
The current implementation of the base objects targets vml but svg support could be added relatively easily. (ie always seems to be a corporate standard...)
Here are the base classes:
/**
* @class YAHOO.ext.Line
* @extends YAHOO.ext.util.Observable
* Simple Vector Line class
* @cfg {Function} handler A function called when the Line is hovered
* @cfg {Object} scope The scope of the handler
* @cfg {String} Id optional to identify the line
* @cfg {Coord} from beginning point of line
* @cfg (Coord} to end point of line
* @cfg {Number} strokeweight width of line
* @cfg {String} strokecolor color of line
* @constructor
* Create a new line
* @param {String/HTMLElement/Element} renderTo The element to append the button to
* @param {Object} config The config object
*/
YAHOO.ext.Vector.Line = function(renderTo,config){
this.id = YAHOO.util.Dom.generateId();
YAHOO.ext.util.Config.apply(this,config);
this.events = {
};
if(renderTo){
this.render(renderTo);
}
}
YAHOO.extendX(YAHOO.ext.Vector.Line, YAHOO.ext.util.Observable, {
render : function(renderTo){
this.lineTemplate = new YAHOO.ext.DomHelper.Template('<v:line id="' + this.id + '" ' +
'stroke=true strokecolor="' + this.strokecolor + '" strokeweight="' + this.strokeweight + '"' +
' style="position:relative;left:0px;top0px" ' + 'coordorigin="0,0"' +
' to="' + this.to.x + ' ' + this.to.y + '" from="' + this.from.x + ' ' + this.from.y + '"></v:line>');
this.el = this.lineTemplate.append(getEl(renderTo).dom, [''], true);
},
/**
* Returns the line element
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
}
});
/**
* @class YAHOO.ext.Polyline
* @extends YAHOO.ext.util.Observable
* Simple Vector Line class
* @cfg {Function} handler A function called when the Line is hovered
* @cfg {Object} scope The scope of the handler
* @cfg {Number} strokeweight width of line
* @cfg {Array} pts x and y pairs
* @cfg {String} strokecolor color of line
* @constructor
* Create a new line
* @param {String/HTMLElement/Element} renderTo The element to append the button to
* @param {Object} config The config object
*/
YAHOO.ext.Vector.Polyline = function(renderTo,config){
YAHOO.ext.util.Config.apply(this,config);
this.events = {
/**
* @event hover
* Fires when line is hovered over
* @param {Line} this
* @param {EventObject} e The hover event
*/
'hover' : true
};
if(renderTo){
this.render(renderTo);
}
}
YAHOO.extendX(YAHOO.ext.Vector.Polyline, YAHOO.ext.util.Observable, {
render : function(renderTo){
var s = "";
for(var i=0; i<this.pts.length; i++) {
s += this.pts[i].x + ' ' + this.pts[i].y + ' ';
}
this.polyTemplate = new YAHOO.ext.DomHelper.Template('<v:polyline id="' + YAHOO.util.Dom.generateId() + '" ' +
'filled=false stroke=true strokecolor="' + this.strokecolor + '" strokeweight="' + this.strokeweight +
'" Points="' + s + '"></v:polyline>');
this.el = this.polyTemplate.append(getEl(renderTo).dom, [''], true);
},
/**
* Returns the polyline element
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
}
});
/**
* @class YAHOO.ext.Box
* @extends YAHOO.ext.util.Observable
* Simple Vector Rectangle class
* @cfg {Number} strokeweight width of line
* @cfg {String} strokecolor color of line
* @constructor
* Create a new line
* @param {String/HTMLElement/Element} renderTo The element to append the button to
* @param {Object} config The config object
*/
YAHOO.ext.Vector.Box = function(renderTo,config){
this.shadow = 'true';
this.strokecolor = 'black';
this.strokweight = '1';
this.cls ='graph-box';
YAHOO.ext.util.Config.apply(this,config);
this.events = {
};
if(renderTo){
this.render(renderTo);
}
}
YAHOO.extendX(YAHOO.ext.Vector.Box, YAHOO.ext.util.Observable, {
render : function(renderTo){
this.boxTemplate = new YAHOO.ext.DomHelper.Template('<v:rect id="' +
YAHOO.util.Dom.generateId() + '" ' +
' class=' + this.cls + ' style="position:relative;width:' + this.width + ';height:' + this.height + ';' +
'left:0px;top:0px;"' +
' strokecolor=' + this.strokecolor + ' strokeweight=' + this.strokeweight +
'><v:shadow on=' + this.shadow + ' />' +
'</v:rect>');
this.el = this.boxTemplate.append(getEl(renderTo).dom, [''], true);
},
/**
* Returns the line element
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
}
});
YAHOO.ext.Vector.Group = function(renderTo, config){
YAHOO.ext.util.Config.apply(this,config);
this.groupTemplate = new YAHOO.ext.DomHelper.Template('<v:group ' +
'style="position:relative;left:0px;top:0px;width:' + this.width +
'; height:' + this.height + ';" ' +
'coordsize="' + this.width + ',' + this.height + '" coordorigin="0,0">');
this.el = this.groupTemplate.append(getEl(renderTo).dom, [''], true);
this.getEl = function(){
return this.el;
}
}
The line graph class:
YAHOO.namespace('ext.Graph');
/**
* @class YAHOO.ext.Graph.LineGraph
* @extends YAHOO.ext.util.Observable
* Simple Vector Line Graph class
* @cfg {Object} graphData array of array object
* Example: [[{x:0,y:5},{x:1,y:10}],[{x:0,y:8},{x:1,y:13}]]
* @constructor
* Create a new line
* @param {Object} config The config object
*/
YAHOO.ext.Graph.LineGraph = function(renderTo,config){
YAHOO.ext.util.Config.apply(this,config);
if(renderTo){
this.render(renderTo);
}
}
YAHOO.extendX(YAHOO.ext.Graph.LineGraph, YAHOO.ext.util.Observable, {
render : function(renderTo){
this.graphTemplate = new YAHOO.ext.DomHelper.Template('<div></div>');
this.container = getEl(renderTo);
this.width = this.container.getWidth();
this.height = this.container.getHeight();
this.el = this.graphTemplate.append(this.container.dom, [''], true);
this.el.addClass('graph-main');
this.el.setHeight(this.height);
this.el.setWidth(this.width);
this.mainX = 25;
this.mainY = this.height -25;
this.lengthY = this.height - this.mainY;
this.lengthX = this.width - this.mainX;
var x = this.getMaxX(this.graphData);
var y = this.getMaxY(this.graphData);
this.scaleX = parseFloat(x/(this.lengthX-this.mainX));
this.scaleY = parseFloat(y/(this.mainY-this.lengthY));
Log.log('max x: ' + x + ' max y: ' + y);
this.rescaleData();
this.adjustData();
this.group = YAHOO.ext.Vector.VectorManager.getGroup(this.el,
{
height: this.height,
width: this.width
});
this.graphBox = YAHOO.ext.Vector.VectorManager.getBox(this.group.getEl(),
{
strokecolor: 'gray',
height: this.height,
width: this.width
});
this.xAxis = YAHOO.ext.Vector.VectorManager.getLine(this.group.getEl(),
{
id: 'xLine',
strokecolor: 'steelblue',
strokeweight: '1px',
from:{x:this.mainX,y:this.mainY},
to:{x:this.lengthX,y:this.mainY}
});
this.yAxis = YAHOO.ext.Vector.VectorManager.getLine(this.group.getEl(),
{
id: 'yLine',
strokecolor: 'steelblue',
strokeweight: '1px',
from:{x:this.mainX,y:this.mainY},
to:{x:this.mainX,y:this.lengthY}
});
for(var i=0; i<this.graphData.length; i++) {
Log.log('graph line: ' + i);
YAHOO.ext.Vector.VectorManager.getPoly(this.group.getEl(),
{
strokecolor: 'blue',
strokeweight: '1px',
pts: this.graphData[i]
});
}
// Log.log(getEl('yLine').dom.from + ' and to: ' + getEl('yLine').dom.to);
},
rescaleData : function(){
for(var i=0; i<this.graphData.length; i++) {
for(var j=0; j<this.graphData[i].length; j++) {
this.graphData[i][j].x = this.graphData[i][j].x / this.scaleX;
this.graphData[i][j].y = this.graphData[i][j].y / this.scaleY;
}
}
},
adjustData : function(){
for(var i=0; i<this.graphData.length; i++) {
for(var j=0; j<this.graphData.length; j++) {
this.graphData[i][j].x = this.graphData[i][j].x + this.mainX;
this.graphData[i][j].y = this.mainY - this.graphData[i][j].y;
}
}
},
getMaxX : function(obj){
var m = 0;
for(var i=0; i<obj.length; i++) {
for(var j=0; j<obj[i].length; j++) {
(m<obj[i][j].x)?m=obj[i][j].x:'';
}
}
this.maxX = m;
return m;
},
getMaxY : function(obj){
var m = 0;
for(var i=0; i<obj.length; i++) {
for(var j=0; j<obj[i].length; j++) {
(m<obj[i][j].y)?m=obj[i][j].y:'';
}
}
this.maxY = m;
return m;
},
/**
* Returns the line element
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
}
});
I almost forgot, there is also a vector manager class. My thought is that this class would handle vml/svg decision. Kind of like a factory pattern.
YAHOO.namespace('ext.Vector');
/**
* @class YAHOO.ext.Vector.VectorManager
* This class is a singleton that manages vector objects
*/
YAHOO.ext.Vector.VectorManager = new function(){
var brows = YAHOO.ext.util.Browser;
var vectorType = 'vml'; //vml or svg
/**
* Sets up required vector graphics options per browser
*/
this.setupVector = function(){
if(brows.isIE||brows.isIE7){
var baseHtml = document.getElementsByTagName('html')[0];
baseHtml.setAttribute("xmlns:v","urn:schemas-microsoft-com:vml");
var h = YAHOO.ext.Element.get(baseHtml, true);
vectorType = 'vml';
}else{
vectorType = 'svg';
}
}
this.getLine = function(renderTo, config){
if(vectorType == 'vml'){
return new YAHOO.ext.Vector.Line(renderTo, config);
}
}
this.getPoly = function(renderTo, config){
if(vectorType == 'vml'){
return new YAHOO.ext.Vector.Polyline(renderTo, config);
}
}
this.getBox = function(renderTo, config){
if(vectorType == 'vml'){
return new YAHOO.ext.Vector.Box(renderTo, config);
}
}
this.getGroup = function(renderTo, config){
if(vectorType == 'vml'){
return new YAHOO.ext.Vector.Group(renderTo, config);
}
}
}
YAHOO.ext.EventManager.onDocumentReady(YAHOO.ext.Vector.VectorManager.setupVector, YAHOO.ext.Vector.VectorManager, true);
The line of code to create a graph:
function createNewLineGraph(){
var g = new YAHOO.ext.Graph.LineGraph('vmltest', {stroke: 'true',
graphData: [
[{x:0,y:0},
{x:1,y:75},
{x:2,y:100},
{x:3,y:75}],
[{x:0,y:10},
{x:1,y:65},
{x:2,y:120},
{x:3,y:100}]
]
});
}
I welcome feedback.