OSDN Git Service

Client is version 0.5.52, New balloon is working at Editor & Reader.
[pettanr/pettanr.git] / app / assets / javascripts / peta-common.js
index 96133ed..0458082 100644 (file)
@@ -1,6 +1,6 @@
 /*\r
  * pettanR peta.common.js\r
- *   version 0.5.39\r
+ *   version 0.5.52\r
  * \r
  *   author:\r
  *     itozyun\r
@@ -40,7 +40,7 @@ var pettanr = ( function(){
                })(),\r
                IS_DEBUG = Type.isBoolean( URL_PARAMS.debug ) ? URL_PARAMS.debug : IS_LOCAL === true;\r
        return {\r
-               version: '0.5.31',\r
+               version: '0.5.40',\r
                URL_PARAMS: URL_PARAMS,\r
                LOCAL: IS_LOCAL,\r
                DEBUG: IS_DEBUG,\r
@@ -84,52 +84,33 @@ pettanr.CONST = ( function(){
                })();\r
                \r
        return {\r
-               PETTANR_ROOT_PATH:                      PETTANR_ROOT_PATH,\r
-               URL_ORIGINAL_PICTURES_JSON: ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'original_pictures.json',\r
-               URL_RESOURCE_PICTURES_JSON: ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'resource_pictures.json',\r
-               URL_MY_RESOURCE_PICTURES_JSON: ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/resource_picture.json',\r
-               URL_COMICS_JSON:                        ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'comics.json',\r
-               URL_MY_COMICS_JSON:                     ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/comic.json',\r
-               URL_PANELS_JSON:                        ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'panels.json',\r
-               URL_MY_PANELS_JSON:                     ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/panel.json',\r
-               NS_PETTANR_COMIC:                       'pettanr-comic',\r
-               THUMBNAIL_PATH:             SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/thumbnail\/' : PETTANR_ROOT_PATH + 'resource_pictures\/',\r
-               RESOURCE_PICTURE_PATH:          SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/' : PETTANR_ROOT_PATH + 'resource_pictures\/full\/',\r
-               PANEL_PICTURE_PATH:                 SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/' : PETTANR_ROOT_PATH + 'pictures\/',\r
-               SYSTEM_PICTURE_PATH:            ( SERVER_SUPPORT === false ? RELATIVE : PETTANR_ROOT_PATH ) + 'system_pictures\/',\r
-               CREATE_COMIC_JS:                        SERVER_SUPPORT === false ? 'js\/create_new_comic.js' : PETTANR_ROOT_PATH + 'comics\/new.js',\r
-               CREATE_PANEL_JS:                        SERVER_SUPPORT === false ? 'js\/create_new_panel.js' : PETTANR_ROOT_PATH + 'panels\/new.js',\r
-               UPLOAD_PICTURE_JS:                      SERVER_SUPPORT === false ? 'js\/upload_picture.js' : PETTANR_ROOT_PATH + 'original_pictures\/new.js',\r
-               REGISTER_ARTIST_JS:                     SERVER_SUPPORT === false ? 'js\/register_artist.js' : PETTANR_ROOT_PATH + 'artists\/new.js',\r
-               SERVER_SUPPORT:                         SERVER_SUPPORT,\r
-               URL_PETA_APPS_CSS:                      ( SERVER_SUPPORT === false ? 'stylesheets' : '\/assets' ) + '\/peta.apps.css'\r
+               PETTANR_ROOT_PATH             : PETTANR_ROOT_PATH,\r
+               URL_MY_ORIGINAL_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'original_pictures.json',\r
+               URL_MY_RESOURCE_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/resource_pictures.json',\r
+               URL_RESOURCE_PICTURES_JSON    : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'resource_pictures.json',\r
+               URL_MY_RESOURCE_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/resource_picture.json',\r
+               URL_COMICS_JSON               : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'comics.json',\r
+               URL_MY_COMICS_JSON            : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/comic.json',\r
+               URL_PANELS_JSON               : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'panels.json',\r
+               URL_MY_PANELS_JSON            : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/panel.json',\r
+               SPEECH_BALOON_TEMPLETE        : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'speech_balloon_templates.json\/',\r
+               NS_PETTANR_COMIC              : 'pettanr-comic',\r
+               THUMBNAIL_PATH                : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/thumbnail\/' : PETTANR_ROOT_PATH + 'resource_pictures\/',\r
+               RESOURCE_PICTURE_PATH         : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/' : PETTANR_ROOT_PATH + 'resource_pictures\/full\/',\r
+               ORIGINAL_PICTURE_PATH         : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/' : PETTANR_ROOT_PATH + 'original_pictures\/',\r
+               PICTURE_PATH                  : SERVER_SUPPORT === false ? RELATIVE + 'pictures\/' : PETTANR_ROOT_PATH + 'pictures\/',\r
+               SYSTEM_PICTURE_PATH           : ( SERVER_SUPPORT === false ? RELATIVE : PETTANR_ROOT_PATH ) + 'system_pictures\/',\r
+               CREATE_COMIC_JS               : SERVER_SUPPORT === false ? 'js\/create_new_comic.js' : PETTANR_ROOT_PATH + 'comics\/new.js',\r
+               CREATE_PANEL_JS               : SERVER_SUPPORT === false ? 'js\/create_new_panel.js' : PETTANR_ROOT_PATH + 'panels\/new.js',\r
+               UPLOAD_PICTURE_JS             : SERVER_SUPPORT === false ? 'js\/upload_picture.js' : PETTANR_ROOT_PATH + 'original_pictures\/new.js',\r
+               REGISTER_ARTIST_JS            : SERVER_SUPPORT === false ? 'js\/register_artist.js' : PETTANR_ROOT_PATH + 'artists\/new.js',\r
+               SERVER_SUPPORT                : SERVER_SUPPORT,\r
+               URL_PETA_APPS_CSS             : ( SERVER_SUPPORT === false ? 'stylesheets' : '\/assets' ) + '\/peta.apps.css'\r
        }\r
 })();\r
 \r
 /* ----------------------------------------\r
- * Vector Support\r
- * \r
- *              __________\r
- *             /          \\r
- *            /            \\r
- *            |,startX,Y    |\r
- * tailX,Y - <              |\r
- *            |'endX,Y      |\r
- *            \            /\r
- *                \__________/\r
- * \r
- * SVG\r
- * -----------------------\r
- * ie9, other modern browser\r
- * \r
- * XML\r
- * -----------------------\r
- * ie5.5-8\r
- * \r
- * 内部の角度計算は radian で統一したい。\r
- * 当初 vectorEnabled = true で一度書いてみる。\r
- * 駄目なら、代替のイメージのsrcの用意もここで担当。\r
- * 閲覧と編集両方で使う。\r
+ * old balloon.\r
  * \r
  */\r
 pettanr.balloon = ( function() {\r
@@ -145,7 +126,7 @@ pettanr.balloon = ( function() {
                ELM_BALLOON_ORIGIN = ( function(){\r
                        var ret;\r
                        try {\r
-                               if( IS_VML === true){\r
+                               if( IS_VML === true ){\r
                                        ret = document.createElement( 'DIV');\r
                                        var shape = document.createElement( 'v:shape');\r
                                        shape.coordorigin = "0,0";\r
@@ -185,22 +166,57 @@ pettanr.balloon = ( function() {
                TARGET     = TAIL_WIDTH * TAIL_WIDTH,\r
                isFinit    = Type.isFinite,\r
                ACCURACY   = 1, // 有効少数桁      \r
-               cround     = function ( v, r ){\r
+               cround     = function( v, r ){\r
                                                r = r || ACCURACY;\r
                                                return round( v * pow( 10.0, r )) / pow( 10.0, r );\r
                                        },\r
                DEG_TO_RAD = Math.PI / 180;\r
 \r
        var XBROWSER_BALLOON_CLASS = function( w, h, a ){\r
-               var balloonElm = vectorEnabled === true ? ELM_BALLOON_ORIGIN.cloneNode( true ) : document.createElement( 'img' ), // pettanr.imageに変更\r
-                       path = balloonElm.getElementsByTagName( 'path' )[ 0 ],\r
-                       shape = balloonElm.getElementsByTagName( 'shape' )[ 0 ],\r
-                       instance = this,\r
-                       l = ',';\r
-               \r
-               function draw( _a ){\r
-                       var rx      = w / 2,\r
-                               ry      = h / 2,\r
+               this.elm   = vectorEnabled === true ? ELM_BALLOON_ORIGIN.cloneNode( true ) : document.createElement( 'img' ); // pettanr.imageに変更\r
+               this.path  = this.elm.getElementsByTagName( IS_VML === true ? 'shape' : 'path' )[ 0 ];\r
+               this.resize( a, w, h );\r
+       };\r
+       XBROWSER_BALLOON_CLASS.prototype = {\r
+               elm   : null,\r
+               path  : null,\r
+               w     : 0,\r
+               h     : 0,\r
+               a     : 0,\r
+               resize : function ( _a, _w, _h ){\r
+                       this.w  = isFinit( _w ) === true ? _w - PADDING_TOP  * 2 : this.w;\r
+                       this.h  = isFinit( _h ) === true ? _h - PADDING_LEFT * 2 : this.h;\r
+                       // ie6 でリサイズが反応しない対策\r
+                       if( vectorEnabled === false && UA.isIE === true && UA.ieVersion < 7 ){\r
+                               var parent = this.elm.parentNode;\r
+                               parent.removeChild( this.elm );\r
+                               parent.insertBefore( this.elm, parent.firstChild );\r
+                       };\r
+                       this.angle( _a );\r
+               },\r
+               angle : function( _a ){\r
+                       if( isFinit( _a ) === true ){\r
+                               this.a = _a;\r
+                               if( vectorEnabled === false ){\r
+                                       this.elm.src = pettanr.balloon.getBalloonUrl( this.w, this.h, _a );\r
+                               } else {\r
+                                       this.draw( _a );\r
+                               };\r
+                       };\r
+                       return this.a;\r
+               },\r
+               type : function( _type ){\r
+                       //draw( _a);\r
+               },\r
+               destroy : function(){\r
+                       this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );\r
+                       delete this.elm;\r
+                       delete this.path;\r
+               },\r
+               draw : function( _a ){\r
+                       var rx      = this.w / 2,\r
+                               ry      = this.h / 2,\r
+                               l       = ',',\r
                                tailRad = _a * DEG_TO_RAD,\r
                                tailX   = rx + ( rx + TAIL_HEIGHT ) * sin( tailRad ),\r
                                tailY   = ry - ( ry + TAIL_HEIGHT ) * cos( tailRad ),\r
@@ -213,7 +229,7 @@ pettanr.balloon = ( function() {
                                tailDeg = 0, d;\r
                        \r
                        for( var i = 45; i > 0.01; i /= 2){\r
-                               d = ( tailDeg + i ) /2;\r
+                               d = ( tailDeg + i ) / 2;\r
                                startRad = ( _a + d ) * DEG_TO_RAD;\r
                                endRad   = ( _a - d ) * DEG_TO_RAD;\r
                                \r
@@ -237,27 +253,27 @@ pettanr.balloon = ( function() {
                        if( IS_VML === true ){\r
                                var _tailX = tailX *10,\r
                                        _tailY = tailY *10,\r
-                                       __w = w *10,\r
-                                       __h = h *10;\r
+                                       __w = this.w *10,\r
+                                       __h = this.h *10;\r
                                \r
-                               shape.style.width = w + 'px';\r
-                               shape.style.height = h + 'px';\r
-                               shape.coordsize = [ __w, __h ].join( l );\r
-                               shape.path = [\r
+                               this.path.style.width  = this.w + 'px';\r
+                               this.path.style.height = this.h + 'px';\r
+                               this.path.coordsize = [ __w, __h ].join( l );\r
+                               this.path.path = [\r
                                        ' ar ', 0, l, 0, l, __w, l, __h, l,\r
                                        round( endX * 10 ), l, round( endY * 10 ), l,\r
                                        round( startX * 10 ), l, round( startY * 10 ),\r
                                        ' l ', round( _tailX ), l, round( _tailY ),\r
                                        ' x e'\r
-                               ].join( '');\r
+                               ].join( '' );\r
 \r
-                               balloonElm.style.marginTop =  _tailY < 0 ? floor( ( 60 + _tailY) / 10 ) : 10;\r
-                               balloonElm.style.marginLeft = _tailX < 0 ? floor( ( 60 + _tailX) / 10 ) : 10;\r
+                               this.elm.style.marginTop =  _tailY < 0 ? floor( ( 60 + _tailY) / 10 ) : 10;\r
+                               this.elm.style.marginLeft = _tailX < 0 ? floor( ( 60 + _tailX) / 10 ) : 10;\r
                        } else {\r
-                               balloonElm.setAttribute( 'width', w + PADDING_LEFT *2 );\r
-                               balloonElm.setAttribute( 'height', h + PADDING_TOP *2 );\r
-                               path.setAttribute( 'd', [\r
-                                       'M', cround( tailX + PADDING_LEFT ), l, cround( tailY + PADDING_TOP ),\r
+                               this.elm.setAttribute( 'width',  this.w + PADDING_LEFT *2 );\r
+                               this.elm.setAttribute( 'height', this.h + PADDING_TOP *2 );\r
+                               this.path.setAttribute( 'd', [\r
+                                       'M', cround( tailX + PADDING_LEFT ),  l, cround( tailY  + PADDING_TOP ),\r
                                        'L', cround( startX + PADDING_LEFT ), l, cround( startY + PADDING_TOP ),\r
                                        'A', rx, l, ry,\r
                                        '0 1 1',                        // flag\r
@@ -266,40 +282,6 @@ pettanr.balloon = ( function() {
                                ].join( ' '));\r
                        }\r
                }\r
-               \r
-               this.elm = balloonElm;\r
-               this.resize = function ( _a, _w, _h ){\r
-                       w  = isFinit( _w ) === true ? _w - PADDING_TOP * 2 : w;\r
-                       h  = isFinit( _h ) === true ? _h - PADDING_LEFT * 2 : h;\r
-                       // ie6 でリサイズが反応しない対策\r
-                       if( vectorEnabled === false && UA.isIE === true && UA.ieVersion < 7 ){\r
-                               var parent = balloonElm.parentNode;\r
-                               parent.removeChild( balloonElm );\r
-                               parent.insertBefore( balloonElm, parent.firstChild );\r
-                       }\r
-                       instance.angle( _a );\r
-               };\r
-               this.angle = function( _a ){\r
-                       if( isFinit( _a ) === true ){\r
-                               a = _a;\r
-                               if( vectorEnabled === false ){\r
-                                       balloonElm.src = pettanr.balloon.getBalloonUrl( w, h, _a );\r
-                               } else {\r
-                                       draw( _a );\r
-                               }\r
-                       }\r
-                       return a;\r
-               }\r
-               this.type = function( _type ){\r
-                       //draw( _a);\r
-               }\r
-               this.destroy = function(){\r
-                       delete instance.destroy;\r
-                       balloonElm.parentNode && balloonElm.parentNode.removeChild( balloonElm );\r
-                       balloonElm = path = shape = instance = null;\r
-               }\r
-               \r
-               instance.resize( a, w, h );\r
        };\r
        \r
        return {\r
@@ -328,6 +310,228 @@ pettanr.balloon = ( function() {
 })();\r
 \r
 /* ----------------------------------------\r
+ * New Balloon\r
+ * \r
+ * Vector : SVG, Canvas, VML, Flash, None\r
+ * \r
+ */\r
+pettanr.newBalloon = ( function(){\r
+       var TEMPLETES = [];\r
+       \r
+       var PICTURE_PATH       = pettanr.CONST.SYSTEM_PICTURE_PATH,\r
+               STROKE_WIDTH       = 1.2,\r
+               IS_VML             = UA.isIE === true && UA.ieVersion < 9,\r
+               ELM_BALLOON_ORIGIN = ( function(){\r
+                       var ret;\r
+                       try {\r
+                               if( IS_VML === true ){\r
+                                       ret = document.createElement( 'DIV' );\r
+                                       var shape = document.createElement( 'v:shape' );\r
+                                       shape.coordorigin  = "0,0";\r
+                                       shape.strokecolor  = "black";\r
+                                       shape.strokeweight = STROKE_WIDTH;\r
+                                       shape.fillcolor    = "white";\r
+                                       ret.appendChild( shape);\r
+                               } else {\r
+                                       var kSVGNS = 'http://www.w3.org/2000/svg';\r
+                                       // http://modernizr.com/downloads/modernizr.js\r
+                                       // Thanks to Erik Dahlstrom\r
+                                       if( !document.createElementNS || !document.createElementNS(kSVGNS, 'svg' ).createSVGRect ){\r
+                                               return null;\r
+                                       };\r
+                                       ret = document.createElementNS( kSVGNS, 'svg' );\r
+                                       var path = document.createElementNS( kSVGNS, 'path' );\r
+                                       path.setAttribute( 'fill', "white" );\r
+                                       path.setAttribute( 'stroke', "black" );\r
+                                       path.setAttribute( 'strokeWidth', STROKE_WIDTH );\r
+                                       ret.appendChild( path );\r
+                               };\r
+                               return ret;     \r
+                       } catch( e ){\r
+                               return null;\r
+                       };\r
+               })(),\r
+               vectorEnabled = ELM_BALLOON_ORIGIN !== null &&\r
+                                               pettanr.URL_PARAMS.vector !== false &&\r
+                                               !( IS_VML === true && UA.VML === false ),\r
+               BalloonClass;\r
+       \r
+       if( vectorEnabled === true ){\r
+               BalloonClass = function( klass ){\r
+                       this.elm     = ELM_BALLOON_ORIGIN.cloneNode( true );\r
+                       this.path    = this.elm.getElementsByTagName( IS_VML === true ? 'shape' : 'path' )[ 0 ];\r
+                       this.klass   = klass;\r
+                       this.getPath = klass.getPath;\r
+               };\r
+               BalloonClass.prototype = {\r
+                       elm     : null,\r
+                       path    : null,\r
+                       klass   : null,\r
+                       getPath : null,\r
+                       args    : null,\r
+                       update  : IS_VML === true ?\r
+                               function( /* w, h [, angle, ,,, ] */ ){\r
+                                       var w = arguments[ 0 ],\r
+                                               h = arguments[ 1 ];\r
+                                       var path = this.getPath.call( this.klass, arguments );\r
+                                       if( !path ) return false;\r
+                                       path = /* SVG2VML */ path;\r
+                                       this.path.style.width  = w + 'px';\r
+                                       this.path.style.height = h + 'px';\r
+                                       this.path.coordsize    = ( w * 10 ) + ',' + ( h * 10 );\r
+                                       this.path.path         = path;\r
+                                       // this.elm.style.marginTop =  _tailY < 0 ? floor( ( 60 + _tailY) / 10 ) : 10;\r
+                                       // this.elm.style.marginLeft = _tailX < 0 ? floor( ( 60 + _tailX) / 10 ) : 10;\r
+                               } :\r
+                               function( /* w, h [, angle, ,,, ] */ ){\r
+                                       var w = arguments[ 0 ],\r
+                                               h = arguments[ 1 ],\r
+                                               d = this.getPath.call( this.klass, arguments );\r
+                                       if( !d ) return false;\r
+                                       this.elm.width  = w + PADDING_LEFT * 2;\r
+                                       this.elm.height = h + PADDING_TOP  * 2;\r
+                                       this.path.setAttribute( 'd', d );\r
+                               },\r
+                       destroy : function(){\r
+                               this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );\r
+                               delete this.elm;\r
+                               delete this.path;\r
+                       }\r
+               };\r
+       } else {\r
+               BalloonClass = function( klass ){\r
+                       // templete の vector の有無\r
+                       this.elm          = document.createElement( 'img' ); // pettanr.imageに変更\r
+                       this.klass        = klass;\r
+                       this.getPictureID = klass.getPictureID;\r
+               };\r
+               BalloonClass.prototype = {\r
+                       elm          : null,\r
+                       klass        : null,\r
+                       getPictureID : null,\r
+                       args         : null,\r
+                       update : function( /* w, h [, angle, ,,, ] */ ){\r
+                               var id = this.getPictureID.call( this.klass, arguments );\r
+                               if( id !== 0 && !id ) return false;\r
+                               this.elm.src = PICTURE_PATH + id + '.gif';\r
+                       },\r
+                       destroy : function(){\r
+                               this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );\r
+                       }\r
+               };\r
+       };\r
+       \r
+       /* js を持たず ハッシュに格納したデータと 1枚以上の system picture から描画を行う\r
+        * http://sourceforge.jp/projects/pettanr/wiki/HowToMakeSpeechBalloon\r
+        */\r
+       var NonVectorBalloonClass = function( templete ){\r
+               this.elm       = document.createElement( 'img' ); // pettanr.imageに変更\r
+               this.size      = this.elm.style;\r
+               //this.templete  = templete;\r
+               //this.speech    = templete.speech_template_attributes;\r
+               //this.defaultW  = templete.default_width;\r
+               //this.defaultH  = templete.default_height;\r
+               //this.sizeCount = templete.size_count;\r
+               this.wOffset   = templete.speech_balloon.width_offset;\r
+               this.hOffset   = templete.speech_balloon.height_offset;\r
+               this.wStep     = templete.speech_balloon.width_step;\r
+               this.hStep     = templete.speech_balloon.height_step;\r
+               // r_offset\r
+               // r_steps\r
+               \r
+               var obj = templete, v, p;\r
+               // 2013.3.31 itozyun's memo\r
+               // 以下の使いやすく加工する処理は pettanr.balloon.register() 内に移動してもよさそう\r
+               // new TempleteClass( templeteJson );\r
+               // NonVectorBalloon.templete.defaultW みたいにアクセス\r
+               if( templete.speech_balloon.size_count && 1 < templete.speech_balloon.size_count ){\r
+                       this.picIDs = []; // system picture id list\r
+                       for( p in templete ){\r
+                               if( p === 'speech_balloon' ) continue;\r
+                               v = obj[ p ];\r
+                               this.picIDs[ this.picIDs.length ] = v.balloon.system_picture_id;\r
+                       };                      \r
+               } else {\r
+                       for( p in obj ){\r
+                               if( p === 'speech_balloon' ) continue;\r
+                               v = obj[ p ];\r
+                               this.picID = v.balloon.system_picture_id;\r
+                               break;\r
+                       };\r
+               };\r
+       };\r
+       NonVectorBalloonClass.prototype = {\r
+               elm      : null,\r
+               size     : null,\r
+               templete : null,\r
+               args     : null,\r
+               picIDs   : null,\r
+               picID    : 0,\r
+               src      : 0,\r
+               w        : 0,\r
+               h        : 0,\r
+               update : function( w, h /* [, angle, ,,, ] */ ){\r
+                       var l, id, _w, _h;\r
+                       if( this.picIDs ){\r
+                               _w = ( w - this.wOffset ) / this.wStep;\r
+                               _h = ( h - this.hOffset ) / this.hStep;\r
+                               l  = this.picIDs.length - 1;\r
+                               _w = _w < 0 ? 0 : ( _w > l ? l : _w );\r
+                               _h = _h < 0 ? 0 : ( _h > l ? l : _h );\r
+                               id = this.picIDs[ Math.floor( _w > _h ? _w : _h ) ];\r
+                       } else {\r
+                               id = this.picID;\r
+                       };\r
+                       if( this.src !== id ){\r
+                               this.elm.src = PICTURE_PATH + id + '.gif';\r
+                               this.src = id;\r
+                       };\r
+                       if( this.w !== w ){\r
+                               this.size.width = w + 'px';\r
+                               this.w = w;\r
+                       };\r
+                       if( this.h !== h ){\r
+                               this.size.height = h + 'px';\r
+                               this.h = h;\r
+                       };\r
+               },\r
+               destroy : function(){\r
+                       this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );\r
+               }\r
+       };\r
+       \r
+       return {\r
+               /**\r
+                * balloon_templetes.json 取得時に呼ばれる\r
+                * className は存在しない場合もある \r
+                */\r
+               register : function( id, name, templete ){\r
+                       templete = $.parseJSON( templete );\r
+                       if( !TEMPLETES[ name ] ){\r
+                               TEMPLETES[ name ] = templete;\r
+                               TEMPLETES[ id ]   = templete;\r
+                       };\r
+               },\r
+               create : function( idOrName, w, h /* [, angle, ,,, ] */ ){\r
+                       var ret;\r
+                       if( Type.isString( idOrName ) === true && idOrName in window ){\r
+                               ret = new BalloonClass( window[ idOrName ] );\r
+                       } else {\r
+                               ret = new NonVectorBalloonClass( TEMPLETES[ idOrName ] );\r
+                       };\r
+                       ret.update( w, h /* [, angle, ,,, ] */ );\r
+                       return ret;\r
+               },\r
+               isTemplete : function( templete ){\r
+                       \r
+               },\r
+               isInstance : function( balloon ){\r
+                       return balloon instanceof BalloonClass || balloon instanceof NonVectorBalloonClass;\r
+               }\r
+       }\r
+})();\r
+\r
+/* ----------------------------------------\r
  *  pettanr.image\r
  *  \r
  *   xBackendな画像反転、画像描画機能。\r
@@ -346,7 +550,8 @@ pettanr.balloon = ( function() {
  *     - VML\r
  *     - flash(lite)\r
  *     - silverlight\r
- *     \r
+ *     - pettan server\r
+ * \r
  *     -moz-transform:scale( -1, -1);\r
  */\r
 pettanr.image = ( function(){\r
@@ -628,9 +833,9 @@ pettanr.image = ( function(){
 pettanr.bind = ( function(){\r
        var BIND_WORKER_ARRAY   = [],\r
                NAMESPACE_CLASSNAME = pettanr.CONST.NS_PETTANR_COMIC + '-',\r
-               PICTURE_PATH        = pettanr.CONST.PANEL_PICTURE_PATH,\r
+               PICTURE_PATH        = pettanr.CONST.PICTURE_PATH,\r
                ELM_DETECT_WIDTH    = ( function(){\r
-                       var ret = document.createElement( 'div');\r
+                       var ret = document.createElement( 'div' );\r
                        ret.style.cssText = 'width: auto;height: 0;padding: 0;margin: 0;display: block;visibility: hidden;float: none;position: static;';\r
                        return ret;\r
                })(),\r
@@ -644,10 +849,10 @@ pettanr.bind = ( function(){
         */\r
        var ResizeAgentClass = function( onResizeFunction, opt_elmCheck){\r
                var     _globalLock = 0,\r
-                       _size = { w: 0, h: 0 };\r
+                       _size = { w: 0, h: 0 },\r
                        _ie = !!document.all,\r
                        _quirks = (document.compatMode || "") !== "CSS1Compat",\r
-                       _ieroot = _quirks ? "body" : "documentElement";\r
+                       _ieroot = _quirks ? "body" : "documentElement",\r
                        _root = opt_elmCheck ? opt_elmCheck : ( _ie ? document[_ieroot] : window);\r
 \r
                function getInnerSize(){\r
@@ -675,173 +880,216 @@ pettanr.bind = ( function(){
        };\r
        \r
        \r
-       var ElementBuilderClass = function( elmTarget, noClassnameMode ){\r
-               var RIMG_ARRAY     = [],\r
-                       BALLOON_ARRAY  = [];\r
-               \r
-               function buildComicElement(){\r
+       var ElementBuilder = function( elmTarget, noClassname ){\r
+               this.imageList    = [];\r
+               this.balloonList  = [];\r
+               this.elmTarget    = elmTarget;\r
+               this.noClassname  = noClassname;\r
+       };\r
+       ElementBuilder.prototype = {\r
+               build : function( json, zoom ){\r
+                       this.clean();\r
                        \r
-               };\r
-               \r
-               function buildPanelElement( json, zoom ){\r
-                       var _elmPanel = document.createElement( 'div' ),\r
-                               _style = {\r
+                       // json is Comic ? Panel ?\r
+                       var stories = json.children || json.stories,\r
+                               i, l;\r
+                       if( Type.isArray( stories ) === true ){\r
+                               // comic\r
+                               for( i = 0, l = stories.length; i<l; ++i ){\r
+                                       this.buildPanelElement( stories[ i ], zoom );\r
+                               };\r
+                       } else\r
+                       if( json.elements ){\r
+                               // panel\r
+                               this.buildPanelElement( json, zoom );\r
+                       } else {\r
+                               // invalid json\r
+                       };\r
+               },\r
+               buildFromFile : function( file, zoom ){\r
+                       this.clean();\r
+                       \r
+                       var l    = file.getChildFileLength(),\r
+                               data = file.read(),\r
+                               i, story;\r
+                       if( data.title ){\r
+                               // comic\r
+                               for( i = 0; i<l; ++i ){\r
+                                       story = file.getChildFileAt( i ).read();\r
+                                       this.buildPanelElement( story.panel, zoom );\r
+                               };\r
+                       } else\r
+                       if( data.panel ){\r
+                               // story\r
+                               this.buildPanelElement( data.panel, zoom );\r
+                       } else\r
+                       if( data.border ){\r
+                               // panel\r
+                               this.buildPanelElement( data, zoom );\r
+                       } else {\r
+                               // invalid json\r
+                       };\r
+               },\r
+               buildComicElement : function(){\r
+                       \r
+               },\r
+               buildPanelElement : function( json, zoom ){\r
+                       var elmPanel = document.createElement( 'div' ),\r
+                               style = {\r
                                                'border-width':         typeof json.border === 'number' ? json.border + 'px' : 0,\r
-                                               width:                          json.width + 'px',\r
+                                               width:                          json.width  + 'px',\r
                                                height:                         json.height + 'px'\r
                                },\r
-                               _cssText = [],\r
-                               _comicElements = json.elements || ( json.panel ? json.panel.elements : [] ),\r
-                               _comicElement, _elmImg, _rImg, _rPic,\r
-                               _balloon, _elmBalloonWrap, _elmText, _text, _speechesAttributes, _key,\r
-                               i, l;\r
-                       elmTarget.appendChild( _elmPanel );\r
+                               cssText  = [],\r
+                               elements = json.elements,\r
+                               realPic,\r
+                               p, i, l, data;\r
+                       this.elmTarget.appendChild( elmPanel );\r
                        \r
-                       if( noClassnameMode === true ){\r
+                       if( this.noClassname === true ){\r
                                \r
                        } else {\r
-                               _elmPanel.className = NAMESPACE_CLASSNAME + 'panel';\r
+                               elmPanel.className = NAMESPACE_CLASSNAME + 'panel';\r
                        };\r
-                       for( _key in _style ){\r
-                               _cssText.push( _key + ':' + _style[ _key ] );\r
+                       for( p in style ){\r
+                               cssText.push( p + ':' + style[ p ] );\r
                        };\r
-                       _elmPanel.style.cssText = _cssText.join( ';' );\r
+                       elmPanel.style.cssText = cssText.join( ';' );\r
                        \r
-                       for( i = 0, l = _comicElements.length; i<l; ++i ){\r
-                               _comicElement = _comicElements[ i ];\r
-                               _rPic = _comicElement.picture;\r
-                               if( _rPic ){\r
-                                       _rImg = pettanr.image.createReversibleImage(\r
-                                                       [ PICTURE_PATH, _rPic.id, '.', _rPic.ext ].join( ''),\r
-                                                       _comicElement.width, _comicElement.height\r
-                                               );\r
-                                       _elmImg = _rImg.elm;\r
-                                       _elmPanel.appendChild( _elmImg );\r
-                                       _elmImg.className = NAMESPACE_CLASSNAME + 'image';\r
-                                       _elmImg.style.cssText = [\r
-                                               'left:',   _comicElement.x, 'px;',\r
-                                               'top:',    _comicElement.y, 'px;',\r
-                                               'z-index:',_comicElement.z, ';'\r
-                                       ].join( '');                                    \r
-                                       if( _elmImg.tagName === 'img' ){\r
-                                               _elmImg.width        = Math.abs( _comicElement.width );\r
-                                               _elmImg.height       = Math.abs( _comicElement.height );\r
-                                       } else {\r
-                                               _elmImg.style.width  = Math.abs( _comicElement.width ) + 'px';\r
-                                               _elmImg.style.height = Math.abs( _comicElement.height ) + 'px';\r
-                                       };\r
-                                       \r
-                                       RIMG_ARRAY.push( _rImg );\r
+                       if( !elements ) return;\r
+                       for( i = 0, l = elements.length; i < l; ++i ){\r
+                               data    = elements[ i ];\r
+                               if( !data.balloons ){\r
+                                       this.buildImage( elmPanel, data, data.picture );\r
                                } else {\r
-                                       _elmBalloonWrap = document.createElement( 'div' );\r
-                                       _elmPanel.appendChild( _elmBalloonWrap );\r
-                                       _elmBalloonWrap.className = NAMESPACE_CLASSNAME + 'balloon';\r
-                                       _elmBalloonWrap.style.cssText = [\r
-                                               'width:',   _comicElement.width, 'px;',\r
-                                               'height:',  _comicElement.height, 'px;',\r
-                                               'left:',    _comicElement.x, 'px;',\r
-                                               'top:',     _comicElement.y, 'px;',\r
-                                               'z-index:', _comicElement.z, ';'\r
-                                       ].join( '');\r
-\r
-                                       _balloon = pettanr.balloon.createBalloon( _comicElement.width, _comicElement.height, _comicElement.tail );\r
-                                       _elmBalloonWrap.appendChild( _balloon.elm );\r
-                                       \r
-                                       _elmText = document.createElement( 'p' );\r
-                                       _elmBalloonWrap.appendChild( _elmText );\r
-                                       \r
-                                       _elmText.appendChild( document.createElement( 'span' ) );\r
-                                       \r
-                                       _text = '';\r
-                                       _speechesAttributes = _comicElement.speeches_attributes;\r
-                                       if( _speechesAttributes ){\r
-                                               for( _key in _speechesAttributes ){\r
-                                                       _text += _speechesAttributes[ _key ] && _speechesAttributes[ _key ].content ? _speechesAttributes[ _key ].content : '';\r
-                                               };\r
-                                       };\r
-                                       _elmText.firstChild.appendChild( document.createTextNode( _text ));\r
-                                       BALLOON_ARRAY.push( _balloon );\r
+                                       this.buildBalloon( elmPanel, data );\r
                                };\r
                        };\r
-               };\r
-               \r
-               function clean(){\r
-                       // clean elmTarget\r
-                       while( RIMG_ARRAY.length > 0 ){\r
-                               RIMG_ARRAY.shift().destroy();\r
-                       };\r
-                       while( BALLOON_ARRAY.length > 0 ){\r
-                               BALLOON_ARRAY.shift().destroy();\r
+               },\r
+               buildImage : function( elmPanel, data, realPic ){\r
+                       var rImg = pettanr.image.createReversibleImage(\r
+                                       [ PICTURE_PATH, realPic.id, '.', realPic.ext ].join( '' ),\r
+                                       data.width, data.height\r
+                               ),\r
+                               elmImg = rImg.elm;\r
+                       elmPanel.appendChild( elmImg );\r
+                       elmImg.className = NAMESPACE_CLASSNAME + 'image';\r
+                       elmImg.style.cssText = [\r
+                               'left:',    data.x, 'px;',\r
+                               'top:',     data.y, 'px;',\r
+                               'z-index:', data.z, ';'\r
+                       ].join( '');                                    \r
+                       if( elmImg.tagName === 'img' ){\r
+                               elmImg.width        = Math.abs( data.width );\r
+                               elmImg.height       = Math.abs( data.height );\r
+                       } else {\r
+                               elmImg.style.width  = Math.abs( data.width ) + 'px';\r
+                               elmImg.style.height = Math.abs( data.height ) + 'px';\r
                        };\r
-                       Util.removeAllChildren( elmTarget );            \r
-               };\r
-               \r
-               this.build = function( json, zoom ){\r
-                       clean();\r
                        \r
-                       // json is Comic ? Panel ?\r
-                       var stories = json.children || json.stories,\r
-                               i, l;\r
-                       if( Type.isArray( stories ) === true ){\r
-                               // comic\r
-                               for( i = 0, l = stories.length; i<l; ++i ){\r
-                                       buildPanelElement( stories[ i ], zoom );\r
+                       this.imageList.push( rImg );                    \r
+               },\r
+               buildBalloon : function( elmPanel, data ){\r
+                       var elmBalloonWrap = document.createElement( 'div' ),\r
+                               elmText        = document.createElement( 'p' ),\r
+                               content        = '',\r
+                               balloons       = data.balloons,\r
+                               speeches       = data.speeches,\r
+                               balloonData,\r
+                               balloon, p;\r
+                       elmPanel.appendChild( elmBalloonWrap );\r
+                       elmBalloonWrap.className = NAMESPACE_CLASSNAME + 'balloon';\r
+                       \r
+                       if( balloons ){\r
+                               for( p in balloons ){\r
+                                       balloonData = balloons[ p ];\r
+                                       break;\r
                                };\r
-                       } else\r
-                       if( json.elements ){\r
-                               // panel\r
-                               buildPanelElement( json, zoom );\r
-                       } else {\r
-                               // invalid json\r
+                               if( balloonData ){\r
+                                       elmBalloonWrap.style.cssText = [\r
+                                               'width:',   balloonData.width, 'px;',\r
+                                               'height:',  balloonData.height, 'px;',\r
+                                               'left:',    balloonData.x, 'px;',\r
+                                               'top:',     balloonData.y, 'px;',\r
+                                               'z-index:', data.z, ';'\r
+                                       ].join( '' );                                   \r
+                               };\r
+                               \r
+                               balloon = pettanr.newBalloon.create( data.balloon_template.id, balloonData.width, balloonData.height, data.settings );\r
+                               elmBalloonWrap.appendChild( balloon.elm );\r
+       \r
+                               elmBalloonWrap.appendChild( elmText );\r
+                               \r
+                               elmText.appendChild( document.createElement( 'span' ) );\r
+                               \r
+                               if( speeches ){\r
+                                       for( p in speeches ){\r
+                                               content += speeches[ p ] && speeches[ p ].content ? speeches[ p ].content : '';\r
+                                       };\r
+                               };\r
+                               elmText.firstChild.appendChild( document.createTextNode( content ));\r
+                               this.balloonList.push( balloon );                               \r
                        };\r
-               };\r
-               this.zoom = function(){\r
-                       \r
-               };\r
-               this.destroy = function(){\r
-                       clean();\r
-               };\r
+               },\r
+               clean : function(){\r
+                       // clean elmTarget\r
+                       while( this.imageList.length > 0 ){\r
+                               this.imageList.shift().destroy();\r
+                       };\r
+                       while( this.balloonList.length > 0 ){\r
+                               this.balloonList.shift().destroy();\r
+                       };\r
+                       Util.removeAllChildren( this.elmTarget );\r
+               },\r
+               zoom : function(){},\r
+               destroy : function(){\r
+                       this.clean();\r
+               }                       \r
        };\r
        \r
-       var BindWorkerClass = function( elmTarget, json, zoomSelfEnabled, noClassnameMode ){\r
-               var builder    = new ElementBuilderClass( elmTarget, noClassnameMode );\r
-               var elmDetectW = ELM_DETECT_WIDTH.cloneNode( false );\r
-               var resizer    = null;\r
-               \r
+       var BindWorker = function( elmTarget, json, zoomSelfEnabled, noClassname ){\r
+               this.builder     = new ElementBuilder( elmTarget, noClassname );\r
+               this.elmDetectW  = ELM_DETECT_WIDTH.cloneNode( false );\r
+               this._json        = json;\r
+               this.noClassname = noClassname;\r
                if( zoomSelfEnabled === true ){\r
-                       elmTarget.parentNode.insertBefore( elmDetectW, elmTarget );\r
-                       resizer = new ResizeAgentClass( onResize, elmDetectW );\r
+                       elmTarget.parentNode.insertBefore( this.elmDetectW, elmTarget );\r
+                       this.resizer = new ResizeAgentClass( onResize, this.elmDetectW );\r
                };\r
                function onResize(){\r
                        \r
                };\r
-               json && typeof json === 'object' && builder.build( json );\r
-               \r
-               this.init = function(){\r
+               json && typeof json === 'object' && this.builder.build( json );\r
+       };\r
+       BindWorker.prototype = {\r
+               init : function(){\r
                                \r
-               };\r
-               this.zoom = function(){\r
-                       builder.zoom();\r
-               };\r
-               this.json = function( _json ){\r
-                       json = _json;\r
-                       builder.build( _json );\r
-               };\r
-               this.targetElement = function(){\r
+               },\r
+               zoom : function(){\r
+                       this.builder.zoom();\r
+               },\r
+               json : function( json ){\r
+                       this._json = json;\r
+                       this.builder.build( json, this.noClassname );\r
+               },\r
+               file : function( file ){\r
+                       this.builder.buildFromFile( file, this.noClassname );\r
+               },\r
+               targetElement : function(){\r
                                \r
-               };\r
-               this.layout = function(){\r
+               },\r
+               layout : function(){\r
                                \r
-               };\r
-               this.destroy = function(){\r
-                       builder.destroy();\r
-                       elmTarget = json = builder = null;\r
-               };\r
+               },\r
+               destroy : function(){\r
+                       this.builder.destroy();\r
+                       delete this.json;\r
+                       delete this.builder;\r
+               }               \r
        };\r
-       \r
        return {\r
                createBindWorker: function( elmTarget, opt_COMICJSONorPANELJSON, opt_zoomSelfEnabled, opt_noClassnameMode ){\r
-                       var ret = new BindWorkerClass( elmTarget, opt_COMICJSONorPANELJSON, !!opt_zoomSelfEnabled, !!opt_noClassnameMode);\r
+                       var ret = new BindWorker( elmTarget, opt_COMICJSONorPANELJSON, !!opt_zoomSelfEnabled, !!opt_noClassnameMode );\r
                        BIND_WORKER_ARRAY.push( ret );\r
                        return ret;\r
                },\r