123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786 |
- define("dojox/gfx/VectorText", ["dojo/_base/lang","dojo/_base/declare","dojo/_base/array", "dojo/_base/loader" /* dojo._getText */,
- "dojo/_base/xhr","./_base", "dojox/xml/DomParser", "dojox/html/metrics","./matrix"],
- function (lang,declare,arr,loader,xhr,gfx,xmlDomParser,HtmlMetrics,Matrix){
- /*=====
- gfx = dojox.gfx;
- dojox.gfx.VectorText = {
- // summary:
- // An implementation of the SVG Font 1.1 spec, using dojox.gfx.
- //
- // Basic interface:
- // var f = new dojox.gfx.Font(url|string);
- // surface||group.createVectorText(text)
- // .setFill(fill)
- // .setStroke(stroke)
- // .setFont(fontStyleObject);
- //
- // The arguments passed to createVectorText are the same as you would
- // pass to surface||group.createText; the difference is that this
- // is entirely renderer-agnostic, and the return value is a subclass
- // of dojox.gfx.Group.
- //
- // Note also that the "defaultText" object is slightly different:
- // { type:"vectortext", x:0, y:0, width:null, height: null,
- // text: "", align: "start", decoration: "none" }
- //
- // ...as well as the "defaultVectorFont" object:
- // { type:"vectorfont", size:"10pt" }
- //
- // The reason for this should be obvious: most of the style for the font is defined
- // by the font object itself.
- //
- // Note that this will only render IF and WHEN you set the font.
- };
- =====*/
- var _getText = function(url){
- var result;
- xhr.get({url:url, sync:true, load:function(text){ // Note synchronous!
- result = text;
- }});
- return result;
- };
-
- lang.getObject("dojox.gfx.VectorText", true);
- lang.mixin(gfx, {
- vectorFontFitting: {
- NONE: 0, // render text according to passed size.
- FLOW: 1, // render text based on the passed width and size
- FIT: 2 // render text based on a passed viewbox.
- },
- defaultVectorText: {
- type:"vectortext", x:0, y:0, width: null, height: null,
- text: "", align: "start", decoration: "none", fitting: 0, // vectorFontFitting.NONE
- leading: 1.5 // in ems.
- },
- defaultVectorFont: {
- type:"vectorfont", size: "10pt", family: null
- },
- _vectorFontCache: {},
- _svgFontCache: {},
- getVectorFont: function(/* String */url){
- if(gfx._vectorFontCache[url]){
- return gfx._vectorFontCache[url];
- }
- return new gfx.VectorFont(url);
- }
- });
- return declare("dojox.gfx.VectorFont", null, { // EARLY RETURN
- _entityRe: /&(quot|apos|lt|gt|amp|#x[^;]+|#\d+);/g,
- _decodeEntitySequence: function(str){
- // unescape the unicode sequences
- // nothing to decode
- if(!str.match(this._entityRe)){ return; } // undefined
- var xmlEntityMap = {
- amp:"&", apos:"'", quot:'"', lt:"<", gt:">"
- };
- // we have at least one encoded entity.
- var r, tmp="";
- while((r=this._entityRe.exec(str))!==null){
- if(r[1].charAt(1)=="x"){
- tmp += String.fromCharCode(parseInt(r[1].slice(2), 16));
- }
- else if(!isNaN(parseInt(r[1].slice(1),10))){
- tmp += String.fromCharCode(parseInt(r[1].slice(1), 10));
- }
- else {
- tmp += xmlEntityMap[r[1]] || "";
- }
- }
- return tmp; // String
- },
- _parse: function(/* String */svg, /* String */url){
- // summary:
- // Take the loaded SVG Font definition file and convert the info
- // into things we can use. The SVG Font definition must follow
- // the SVG 1.1 Font specification.
- var doc = gfx._svgFontCache[url]||xmlDomParser.parse(svg);
- // font information
- var f = doc.documentElement.byName("font")[0], face = doc.documentElement.byName("font-face")[0];
- var unitsPerEm = parseFloat(face.getAttribute("units-per-em")||1000, 10);
- var advance = {
- x: parseFloat(f.getAttribute("horiz-adv-x"), 10),
- y: parseFloat(f.getAttribute("vert-adv-y")||0, 10)
- };
- if(!advance.y){
- advance.y = unitsPerEm;
- }
- var origin = {
- horiz: {
- x: parseFloat(f.getAttribute("horiz-origin-x")||0, 10),
- y: parseFloat(f.getAttribute("horiz-origin-y")||0, 10)
- },
- vert: {
- x: parseFloat(f.getAttribute("vert-origin-x")||0, 10),
- y: parseFloat(f.getAttribute("vert-origin-y")||0, 10)
- }
- };
- // face information
- var family = face.getAttribute("font-family"),
- style = face.getAttribute("font-style")||"all",
- variant = face.getAttribute("font-variant")||"normal",
- weight = face.getAttribute("font-weight")||"all",
- stretch = face.getAttribute("font-stretch")||"normal",
- // additional info, may not be needed
- range = face.getAttribute("unicode-range")||"U+0-10FFFF",
- panose = face.getAttribute("panose-1") || "0 0 0 0 0 0 0 0 0 0",
- capHeight = face.getAttribute("cap-height"),
- ascent = parseFloat(face.getAttribute("ascent")||(unitsPerEm-origin.vert.y), 10),
- descent = parseFloat(face.getAttribute("descent")||origin.vert.y, 10),
- baseline = {};
- // check for font-face-src/font-face-name
- var name = family;
- if(face.byName("font-face-name")[0]){
- name = face.byName("font-face-name")[0].getAttribute("name");
- }
- // see if this is cached already, and if so, forget the rest of the parsing.
- if(gfx._vectorFontCache[name]){ return; }
- // get any provided baseline alignment offsets.
- arr.forEach(["alphabetic", "ideographic", "mathematical", "hanging" ], function(attr){
- var a = face.getAttribute(attr);
- if(a !== null /* be explicit, might be 0 */){
- baseline[attr] = parseFloat(a, 10);
- }
- });
- /*
- // TODO: decoration hinting.
- var decoration = { };
- arr.forEach(["underline", "strikethrough", "overline"], function(type){
- if(face.getAttribute(type+"-position")!=null){
- decoration[type]={ };
- }
- });
- */
- // missing glyph info
- var missing = parseFloat(doc.documentElement.byName("missing-glyph")[0].getAttribute("horiz-adv-x")||advance.x, 10);
- // glyph information
- var glyphs = {}, glyphsByName={}, g=doc.documentElement.byName("glyph");
- arr.forEach(g, function(node){
- // we are going to assume the following:
- // 1) we have the unicode attribute
- // 2) we have the name attribute
- // 3) we have the horiz-adv-x and d attributes.
- var code = node.getAttribute("unicode"),
- name = node.getAttribute("glyph-name"),
- xAdv = parseFloat(node.getAttribute("horiz-adv-x")||advance.x, 10),
- path = node.getAttribute("d");
- // unescape the unicode sequences
- if(code.match(this._entityRe)){
- code = this._decodeEntitySequence(code);
- }
- // build our glyph objects
- var o = { code: code, name: name, xAdvance: xAdv, path: path };
- glyphs[code]=o;
- glyphsByName[name]=o;
- }, this);
- // now the fun part: look for kerning pairs.
- var hkern=doc.documentElement.byName("hkern");
- arr.forEach(hkern, function(node, i){
- var k = -parseInt(node.getAttribute("k"),10);
- // look for either a code or a name
- var u1=node.getAttribute("u1"),
- g1=node.getAttribute("g1"),
- u2=node.getAttribute("u2"),
- g2=node.getAttribute("g2"),
- gl;
- if(u1){
- // the first of the pair is a sequence of unicode characters.
- // TODO: deal with unicode ranges and mulitple characters.
- u1 = this._decodeEntitySequence(u1);
- if(glyphs[u1]){
- gl = glyphs[u1];
- }
- } else {
- // we are referring to a name.
- // TODO: deal with multiple names
- if(glyphsByName[g1]){
- gl = glyphsByName[g1];
- }
- }
- if(gl){
- if(!gl.kern){ gl.kern = {}; }
- if(u2){
- // see the notes above.
- u2 = this._decodeEntitySequence(u2);
- gl.kern[u2] = { x: k };
- } else {
- if(glyphsByName[g2]){
- gl.kern[glyphsByName[g2].code] = { x: k };
- }
- }
- }
- }, this);
- // pop the final definition in the font cache.
- lang.mixin(this, {
- family: family,
- name: name,
- style: style,
- variant: variant,
- weight: weight,
- stretch: stretch,
- range: range,
- viewbox: { width: unitsPerEm, height: unitsPerEm },
- origin: origin,
- advance: lang.mixin(advance, {
- missing:{ x: missing, y: missing }
- }),
- ascent: ascent,
- descent: descent,
- baseline: baseline,
- glyphs: glyphs
- });
- // cache the parsed font
- gfx._vectorFontCache[name] = this;
- gfx._vectorFontCache[url] = this;
- if(name!=family && !gfx._vectorFontCache[family]){
- gfx._vectorFontCache[family] = this;
- }
- // cache the doc
- if(!gfx._svgFontCache[url]){
- gfx._svgFontCache[url]=doc;
- }
- },
- _clean: function(){
- // summary:
- // Clean off all of the given mixin parameters.
- var name = this.name, family = this.family;
- arr.forEach(["family","name","style","variant",
- "weight","stretch","range","viewbox",
- "origin","advance","ascent","descent",
- "baseline","glyphs"], function(prop){
- try{ delete this[prop]; } catch(e) { }
- }, this);
- // try to pull out of the font cache.
- if(gfx._vectorFontCache[name]){
- delete gfx._vectorFontCache[name];
- }
- if(gfx._vectorFontCache[family]){
- delete gfx._vectorFontCache[family];
- }
- return this;
- },
- constructor: function(/* String|dojo._Url */url){
- // summary::
- // Create this font object based on the SVG Font definition at url.
- this._defaultLeading = 1.5;
- if(url!==undefined){
- this.load(url);
- }
- },
- load: function(/* String|dojo._Url */url){
- // summary::
- // Load the passed SVG and send it to the parser for parsing.
- this.onLoadBegin(url.toString());
- this._parse(
- gfx._svgFontCache[url.toString()]||_getText(url.toString()),
- url.toString()
- );
- this.onLoad(this);
- return this; // dojox.gfx.VectorFont
- },
- initialized: function(){
- // summary::
- // Return if we've loaded a font def, and the parsing was successful.
- return (this.glyphs!==null); // Boolean
- },
- // preset round to 3 places.
- _round: function(n){ return Math.round(1000*n)/1000; },
- _leading: function(unit){ return this.viewbox.height * (unit||this._defaultLeading); },
- _normalize: function(str){
- return str.replace(/\s+/g, String.fromCharCode(0x20));
- },
- _getWidth: function(glyphs){
- var w=0, last=0, lastGlyph=null;
- arr.forEach(glyphs, function(glyph, i){
- last=glyph.xAdvance;
- if(glyphs[i] && glyph.kern && glyph.kern[glyphs[i].code]){
- last += glyph.kern[glyphs[i].code].x;
- }
- w += last;
- lastGlyph = glyph;
- });
- // if the last glyph was a space, pull it off.
- if(lastGlyph && lastGlyph.code == " "){
- w -= lastGlyph.xAdvance;
- }
- return this._round(w/*-last*/);
- },
- _getLongestLine: function(lines){
- var maxw=0, idx=0;
- arr.forEach(lines, function(line, i){
- var max = Math.max(maxw, this._getWidth(line));
- if(max > maxw){
- maxw = max;
- idx=i;
- }
- }, this);
- return { width: maxw, index: idx, line: lines[idx] };
- },
- _trim: function(lines){
- var fn = function(arr){
- // check if the first or last character is a space and if so, remove it.
- if(!arr.length){ return; }
- if(arr[arr.length-1].code == " "){ arr.splice(arr.length-1, 1); }
- if(!arr.length){ return; }
- if(arr[0].code == " "){ arr.splice(0, 1); }
- };
- if(lang.isArray(lines[0])){
- // more than one line.
- arr.forEach(lines, fn);
- } else {
- fn(lines);
- }
- return lines;
- },
- _split: function(chars, nLines){
- // summary:
- // split passed chars into nLines by finding the closest whitespace.
- var w = this._getWidth(chars),
- limit = Math.floor(w/nLines),
- lines = [],
- cw = 0,
- c = [],
- found = false;
- for(var i=0, l=chars.length; i<l; i++){
- if(chars[i].code == " "){ found = true; }
- cw += chars[i].xAdvance;
- if(i+1<l && chars[i].kern && chars[i].kern[chars[i+1].code]){
- cw += chars[i].kern[chars[i+1].code].x;
- }
- if(cw>=limit){
- var chr=chars[i];
- while(found && chr.code != " " && i>=0){
- chr = c.pop(); i--;
- }
- lines.push(c);
- c=[];
- cw=0;
- found=false;
- }
- c.push(chars[i]);
- }
- if(c.length){ lines.push(c); }
- // "trim" it
- return this._trim(lines);
- },
- _getSizeFactor: function(size){
- // given the size, return a scaling factor based on the height of the
- // font as defined in the font definition file.
- size += ""; // force the string cast.
- var metrics = HtmlMetrics.getCachedFontMeasurements(),
- height=this.viewbox.height,
- f=metrics["1em"],
- unit=parseFloat(size, 10); // the default.
- if(size.indexOf("em")>-1){
- return this._round((metrics["1em"]*unit)/height);
- }
- else if(size.indexOf("ex")>-1){
- return this._round((metrics["1ex"]*unit)/height);
- }
- else if(size.indexOf("pt")>-1){
- return this._round(((metrics["12pt"] / 12)*unit) / height);
- }
- else if(size.indexOf("px")>-1){
- return this._round(((metrics["16px"] / 16)*unit) / height);
- }
- else if(size.indexOf("%")>-1){
- return this._round((metrics["1em"]*(unit / 100)) / height);
- }
- else {
- f=metrics[size]||metrics.medium;
- return this._round(f/height);
- }
- },
- _getFitFactor: function(lines, w, h, l){
- // summary:
- // Find the scaling factor for the given phrase set.
- if(!h){
- // if no height was passed, we assume an array of glyphs instead of lines.
- return this._round(w/this._getWidth(lines));
- } else {
- var maxw = this._getLongestLine(lines).width,
- maxh = (lines.length*(this.viewbox.height*l))-((this.viewbox.height*l)-this.viewbox.height);
- return this._round(Math.min(w/maxw, h/maxh));
- }
- },
- _getBestFit: function(chars, w, h, ldng){
- // summary:
- // Get the best number of lines to return given w and h.
- var limit=32,
- factor=0,
- lines=limit;
- while(limit>0){
- var f=this._getFitFactor(this._split(chars, limit), w, h, ldng);
- if(f>factor){
- factor = f;
- lines=limit;
- }
- limit--;
- }
- return { scale: factor, lines: this._split(chars, lines) };
- },
- _getBestFlow: function(chars, w, scale){
- // summary:
- // Based on the given scale, do the best line splitting possible.
- var lines = [],
- cw = 0,
- c = [],
- found = false;
- for(var i=0, l=chars.length; i<l; i++){
- if(chars[i].code == " "){ found = true; }
- var tw = chars[i].xAdvance;
- if(i+1<l && chars[i].kern && chars[i].kern[chars[i+1].code]){
- tw += chars[i].kern[chars[i+1].code].x;
- }
- cw += scale*tw;
- if(cw>=w){
- var chr=chars[i];
- while(found && chr.code != " " && i>=0){
- chr = c.pop(); i--;
- }
- lines.push(c);
- c=[];
- cw=0;
- found=false;
- }
- c.push(chars[i]);
- }
- if(c.length){ lines.push(c); }
- return this._trim(lines);
- },
- // public functions
- getWidth: function(/* String */text, /* Float? */scale){
- // summary:
- // Get the width of the rendered text without actually rendering it.
- return this._getWidth(arr.map(this._normalize(text).split(""), function(chr){
- return this.glyphs[chr] || { xAdvance: this.advance.missing.x };
- }, this)) * (scale || 1); // Float
- },
- getLineHeight: function(/* Float? */scale){
- // summary:
- // return the height of a single line, sans leading, based on scale.
- return this.viewbox.height * (scale || 1); // Float
- },
- // A note:
- // Many SVG exports do not include information such as x-height, caps-height
- // and other coords that may help alignment. We can calc the baseline and
- // we can get a mean line (i.e. center alignment) but that's about all, reliably.
- getCenterline: function(/* Float? */scale){
- // summary:
- // return the y coordinate that is the center of the viewbox.
- return (scale||1) * (this.viewbox.height/2);
- },
- getBaseline: function(/* Float? */scale){
- // summary:
- // Find the baseline coord for alignment; adjust for scale if passed.
- return (scale||1) * (this.viewbox.height+this.descent); // Float
- },
- draw: function(/* dojox.gfx.Container */group, /* dojox.gfx.__TextArgs */textArgs, /* dojox.gfx.__FontArgs */fontArgs, /* dojox.gfx.__FillArgs */fillArgs, /* dojox.gfx.__StrokeArgs? */strokeArgs){
- // summary:
- // based on the passed parameters, draw the given text using paths
- // defined by this font.
- //
- // description:
- // The main method of a VectorFont, draw() will take a text fragment
- // and render it in a set of groups and paths based on the parameters
- // passed.
- //
- // The basics of drawing text are simple enough: pass it your text as
- // part of the textArgs object, pass size and family info as part of
- // the fontArgs object, pass at least a color as the fillArgs object,
- // and if you are looking to create an outline, pass the strokeArgs
- // object as well. fillArgs and strokeArgs are the same as any other
- // gfx fill and stroke arguments; they are simply applied to any path
- // object generated by this method.
- //
- // Resulting GFX structure
- // -----------------------
- //
- // The result of this function is a set of gfx objects in the following
- // structure:
- //
- // | dojox.gfx.Group // the parent group generated by this function
- // | + dojox.gfx.Group[] // a group generated for each line of text
- // | + dojox.gfx.Path[] // each glyph/character in the text
- //
- // Scaling transformations (i.e. making the generated text the correct size)
- // are always applied to the parent Group that is generated (i.e. the top
- // node in the above example). In theory, if you are looking to do any kind
- // of other transformations (such as a translation), you should apply it to
- // the group reference you pass to this method. If you find that you need
- // to apply transformations to the group that is returned by this method,
- // you will need to reapply the scaling transformation as the *last* transform,
- // like so:
- //
- // | textGroup.setTransform(new dojox.gfx.Matrix2D([
- // | dojox.gfx.matrix.translate({ dx: dx, dy: dy }),
- // | textGroup.getTransform()
- // | ]));
- //
- // In general, this should never be necessary unless you are doing advanced
- // placement of your text.
- //
- // Advanced Layout Functionality
- // -----------------------------
- //
- // In addition to straight text fragments, draw() supports a few advanced
- // operations not normally available with vector graphics:
- //
- // * Flow operations (i.e. wrap to a given width)
- // * Fitting operations (i.e. find a best fit to a given rectangle)
- //
- // To enable either, pass a `fitting` property along with the textArgs object.
- // The possible values are contained in the dojox.gfx.vectorFontFitting enum
- // (NONE, FLOW, FIT).
- //
- // `Flow fitting`
- // Flow fitting requires both a passed size (in the fontArgs object) and a
- // width (passed with the textArgs object). draw() will attempt to split the
- // passed text up into lines, at the closest whitespace according to the
- // passed width. If a width is missing, it will revert to NONE.
- //
- // `Best fit fitting`
- // Doing a "best fit" means taking the passed text, and finding the largest
- // size and line breaks so that it is the closest fit possible. With best
- // fit, any size arguments are ignored; if a height is missing, it will revert
- // to NONE.
- //
- // Other notes
- // -----------
- //
- // `a11y`
- // Since the results of this method are rendering using pure paths (think
- // "convert to outlines" in Adobe Illustrator), any text rendered by this
- // code is NOT considered a11y-friendly. If a11y is a requirement, we
- // suggest using other, more a11y-friendly methods.
- //
- // `Font sources`
- // Always make sure that you are legally allowed to use any fonts that you
- // convert to SVG format; we claim no responsibility for any licensing
- // infractions that may be caused by the use of this code.
- if(!this.initialized()){
- throw new Error("dojox.gfx.VectorFont.draw(): we have not been initialized yet.");
- }
- // TODO: BIDI handling. Deal with layout/alignments based on font parameters.
- // start by creating the overall group. This is the INNER group (the caller
- // should be the outer).
- var g = group.createGroup();
- // do the x/y translation on the parent group
- // FIXME: this is probably not the best way of doing this.
- if(textArgs.x || textArgs.y){
- group.applyTransform({ dx: textArgs.x||0, dy: textArgs.y||0 });
- }
- // go get the glyph array.
- var text = arr.map(this._normalize(textArgs.text).split(""), function(chr){
- return this.glyphs[chr] || { path:null, xAdvance: this.advance.missing.x };
- }, this);
- // determine the font style info, ignore decoration.
- var size = fontArgs.size,
- fitting = textArgs.fitting,
- width = textArgs.width,
- height = textArgs.height,
- align = textArgs.align,
- leading = textArgs.leading||this._defaultLeading;
- // figure out if we have to do fitting at all.
- if(fitting){
- // more than zero.
- if((fitting==gfx.vectorFontFitting.FLOW && !width) || (fitting==gfx.vectorFontFitting.FIT && (!width || !height))){
- // reset the fitting if we don't have everything we need.
- fitting = gfx.vectorFontFitting.NONE;
- }
- }
- // set up the lines array and the scaling factor.
- var lines, scale;
- switch(fitting){
- case gfx.vectorFontFitting.FIT:
- var o=this._getBestFit(text, width, height, leading);
- scale = o.scale;
- lines = o.lines;
- break;
- case gfx.vectorFontFitting.FLOW:
- scale = this._getSizeFactor(size);
- lines = this._getBestFlow(text, width, scale);
- break;
- default:
- scale = this._getSizeFactor(size);
- lines = [ text ];
- }
- // make sure lines doesn't have any empty lines.
- lines = arr.filter(lines, function(item){
- return item.length>0;
- });
- // let's start drawing.
- var cy = 0,
- maxw = this._getLongestLine(lines).width;
- for(var i=0, l=lines.length; i<l; i++){
- var cx = 0,
- line=lines[i],
- linew = this._getWidth(line),
- lg=g.createGroup();
- // loop through the glyphs and add them to the line group (lg)
- for (var j=0; j<line.length; j++){
- var glyph=line[j];
- if(glyph.path!==null){
- var p = lg.createPath(glyph.path).setFill(fillArgs);
- if(strokeArgs){ p.setStroke(strokeArgs); }
- p.setTransform([
- Matrix.flipY,
- Matrix.translate(cx, -this.viewbox.height-this.descent)
- ]);
- }
- cx += glyph.xAdvance;
- if(j+1<line.length && glyph.kern && glyph.kern[line[j+1].code]){
- cx += glyph.kern[line[j+1].code].x;
- }
- }
- // transform the line group.
- var dx = 0;
- if(align=="middle"){ dx = maxw/2 - linew/2; }
- else if(align=="end"){ dx = maxw - linew; }
- lg.setTransform({ dx: dx, dy: cy });
- cy += this.viewbox.height * leading;
- }
- // scale the group
- g.setTransform(Matrix.scale(scale));
- // return the overall group
- return g; // dojox.gfx.Group
- },
- // events
- onLoadBegin: function(/* String */url){ },
- onLoad: function(/* dojox.gfx.VectorFont */font){ }
- });
- // TODO: dojox.gfx integration
- /*
- // Inherit from Group but attach Text properties to it.
- dojo.declare("dojox.gfx.VectorText", dojox.gfx.Group, {
- constructor: function(rawNode){
- dojox.gfx.Group._init.call(this);
- this.fontStyle = null;
- },
- // private methods.
- _setFont: function(){
- // render this using the font code.
- var f = this.fontStyle;
- var font = dojox.gfx._vectorFontCache[f.family];
- if(!font){
- throw new Error("dojox.gfx.VectorText._setFont: the passed font family '" + f.family + "' was not found.");
- }
- // the actual rendering belongs to the font itself.
- font.draw(this, this.shape, this.fontStyle, this.fillStyle, this.strokeStyle);
- },
- getFont: function(){ return this.fontStyle; },
- // overridden public methods.
- setShape: function(newShape){
- dojox.gfx.Group.setShape.call(this);
- this.shape = dojox.gfx.makeParameters(this.shape, newShape);
- this.bbox = null;
- this._setFont();
- return this;
- },
- // if we've been drawing, we should have exactly one child, and that
- // child will contain the real children.
- setFill: function(fill){
- this.fillStyle = fill;
- if(this.children[0]){
- dojo.forEach(this.children[0].children, function(group){
- dojo.forEach(group.children, function(path){
- path.setFill(fill);
- });
- }, this);
- }
- return this;
- },
- setStroke: function(stroke){
- this.strokeStyle = stroke;
- if(this.children[0]){
- dojo.forEach(this.children[0].children, function(group){
- dojo.forEach(group.children, function(path){
- path.setStroke(stroke);
- });
- }, this);
- }
- return this;
- },
- setFont: function(newFont){
- // this will do the real rendering.
- this.fontStyle = typeof newFont == "string" ? dojox.gfx.splitFontString(newFont)
- : dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont);
- this._setFont();
- return this;
- },
- getBoundingBox: function(){
- return this.bbox;
- }
- });
- // TODO: figure out how to add this to container objects!
- dojox.gfx.shape.Creator.createVectorText = function(text){
- return this.createObject(dojox.gfx.VectorText, text);
- }
- */
- });
|