2008-08-28

在 UIComponent 中加入 Bitmap

Flex UIComponent 的 addChild() 只能加入 UIComponent 物件,
若要從 BitmapData 弄個 Bitmap 便無法加入。

Flex3 的 SWFLoader 可以解決這個問題,例如:
var bmp:BitmapData = new BitmapData(sw, sh);
bmp.draw(global.application.t_canvas, matrix);
var swf:SWFLoader = new SWFLoader();
swf.source = new Bitmap(bmp);
this.addChildAt(swf, 0);

2008-08-04

Flex in a Week

Flex in a Week
Adobe 官方影音教學, 應該要有 5 天的教學課程, 目前只有 3 天...
真的一個星期就可以學會 Flex 嗎? 這要看「會」的定義是什麼...

2008-06-24

動態改變 Flash Movie 的大小

原始網頁: BrowserCanvas. The World’s Easiest Way to Dynamically Resize Flash

2008-06-22

JavaScript Components

blueshoes.org 提供不少 JavaScript Components

另外, Swazz Calendar 是個滿讚的日期輸入月曆

2008-06-21

FileReference 上傳後得知檔案大小

上傳圖檔時, 同時上傳資料, 可以參考之前舊文: FileReference 上傳圖檔

利用偵聽 uploadCompleteData (DataEvent.UPLOAD_COMPLETE_DATA) 事件即可解決

Frame Actions
var uploadURL:String = "upload_test.php";
var req:URLRequest = new URLRequest(uploadURL);
var file:FileReference = new FileReference();

// 設定偵聽器
file.addEventListener(Event.SELECT, myFileSelect);
file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA , myUploadCompleteData);

// 瀏覽上傳的檔案
file.browse([new FileFilter("Images", "*.jpg;*.gif;*.png")]);

// 選擇所欲上傳的圖檔後
function myFileSelect(e:Event):void{
file.upload(req);
}
// 上傳完成後
function myUploadCompleteData(e:DataEvent):void{
var data:String = e.data as String;
trace(data);
var filename = data.split('::')[0];
// 載入圖片
var picReq:URLRequest = new URLRequest(filename);
var pic:Loader = new Loader();
pic.load(picReq);
pic.y = 20;
this.addChild(pic);
// 秀出回傳的字串
var tf:TextField = new TextField();
tf.autoSize = 'left';
tf.text = data;
this.addChild(tf);
}

PHP
<?php
// 圖檔上傳後所欲存放的目錄
$up_dir = "./imgs/";
// 若目錄不存在, 則建立之
if(!is_dir($up_dir))
mkdir($up_dir, 0755);
// 取得上傳檔案的副檔名
$pos = strrpos($_FILES["Filedata"]["name"], ".");
if ($pos === false) {
$ext = "";
}else{
$ext = substr($_FILES["Filedata"]["name"], $pos);
}
// 檔案大小 bytes
$size = $_FILES['Filedata']['size'];
// 以隨機的字串為檔名
$uniq = md5(uniqid(rand(), true));
$up_file = $up_dir . $uniq . $ext;
// 將檔案放到設定的目錄內
move_uploaded_file($_FILES["Filedata"]["tmp_name"], $up_file);
chmod($up_file, 0777);

echo $up_file . '::' . $size;
?>

2008-06-18

透過 ActionScript 產生 PDF

Flash 8 / ActionScript 2 Version: blazePDF v2 component (要付費)

ActionScript 3 Open-Source PDF Library: AlivePDF

Neo's blog 整理的 [PHP] 免費好用的 PDF Library 大搜集

2008-06-10

台灣 Adobe/macromedia 使用者俱樂部論壇搬家中

這兩天無法上 mmug.com.tw
問了一下 Willy,才知道原來在搬家中,可能還會暫停服務數天。

2008-06-09

2008-06-06

flashandmath.com - ActionScript 3 Tutorials

flashandmath.com 滿讚的 AS3 教學網站。

以動態文字作為遮罩

mmug上討論的問題
在此我用之前的 Substitute 類別來解決

Frame Actions:
// 底
var bmd:BitmapData = new BitmapData(200, 200, true, 0xFFCCCCCC);
var seed:int = int(Math.random() * int.MAX_VALUE);
var channels:uint = BitmapDataChannel.RED | BitmapDataChannel.BLUE;
bmd.perlinNoise(100, 80, 12, seed, false, true, channels, false, null);
var bm:Bitmap = new Bitmap(bmd);
this.addChild(bm);

// 動態文字
var _txt:TextField = new TextField;
_txt.autoSize = "left";
var myTextFormat:TextFormat = new TextFormat(null, 30, 0, true);
_txt.text = "動態文字";
_txt.x = 50;
_txt.setTextFormat(myTextFormat);
this.addChild(_txt);

// 建立替身
import lin.shinder.display.Substitute;
var s:Substitute = new Substitute(_txt).displace();
s.rotation = 30;

// 設定遮罩
bm.cacheAsBitmap = true;
s.cacheAsBitmap = true;
bm.mask = s;

原始檔下載

2008-06-05

取得 Domain Name (AS3 版)

/**
* author: shinder lin
* email: shinder.lin@gmail.com
*/
package lin.shinder.net
{
import flash.display.DisplayObject;
public class HttpDomain
{
static public var defaultDomain:String = "http://localhost";
static public function getDomain(displayObj:DisplayObject)
{
var url_str:String = displayObj['stage'].loaderInfo.loaderURL;
if (url_str.indexOf("http://") == 0 || url_str.indexOf("https://") == 0) {
var s_index:int = url_str.indexOf("/", 10);
return url_str.substring(0, s_index);
} else {
return defaultDomain;
}
}
}
}

由 URL 取得 Domain Name (AS2 版)

2008-06-04

PHP 使用 JSON 和 AS3 溝通

JSON 常用在 AJAX 的資料交換上,其實也可以用在 SWF<->PHP 上。
PHP5有內建 JSON 的函式;PHP4沒有,但可以用 PEAR 的 JSON 類別
AS3 則可以用 as3corelib 裡的 JSON 類別。
以下是將DB資料轉換成JSON的例子。
mysql2json4.php
/*** shinder.lin@gmail.com
for PHP4
*/
require_once("JSON.php");
function mysql2json4($sql) {
if(is_string($sql)) {
$query = mysql_query($query) or die(mysql_error());
} else {
$query = $sql;
}

$ar = array();
if($total = mysql_num_rows($query)) {
while($row = mysql_fetch_assoc($query)) {
$obj = array();
foreach($row as $key => $value) {
$obj[ $key ] = $value;
}
array_push($ar, $obj);
}
mysql_data_seek($query, 0);
}

$json = new Services_JSON();
return $json->encode($ar);
}
?>

test_mysql2json4.php
require("mysql2json4.php");

mysql_connect("localhost", "root", "");
mysql_select_db("test");
mysql_query("SET NAMES 'utf8'");
$q = mysql_query("select * from ctest");
echo mysql2json4($q);
?>

test_json.fla frame actions:
import  com.adobe.serialization.json.*;

var ur:URLRequest = new URLRequest("http://localhost/json_test/test_mysql2json4.php");
var ul:URLLoader = new URLLoader();
ul.addEventListener(Event.COMPLETE, onComplete);
ul.load(ur);

function onComplete(evt:Event) {
trace(ul.data);
var o:Object = JSON.decode(ul.data);
QopDump.echo(o);
}



資料傳給 PHP
test_json_insert4.php
require_once("JSON.php");

$raw = $GLOBALS["HTTP_RAW_POST_DATA"];

$json = new Services_JSON();
$ar = (array) $json->decode($raw);

mysql_connect("localhost", "root", "");

mysql_select_db("test");
mysql_query("SET NAMES 'utf8'");
// watch out for sql injection
$sql = sprintf("INSERT INTO `ctest` (`sno`, `name`, `phone`) VALUES (NULL, '%s', '%s')", $ar['name'], $ar['phone']);
echo (bool) mysql_query($sql);
?>

test_json_submit.fla frame actions:
import  com.adobe.serialization.json.*;

var ur:URLRequest = new URLRequest("http://localhost/json_test/test_json_insert4.php");
ur.method = URLRequestMethod.POST;
var ul:URLLoader = new URLLoader;

submit_btn.addEventListener(MouseEvent.CLICK, onSubmit);

function onSubmit(evt:MouseEvent):void {
var obj:Object = {name:name_ti.text, phone:phone_ti.text};
var str:String = JSON.encode(obj);
ur.data = str;
ur.contentType = "text/plain";
ul.load(ur);
// trace(str);
}

ul.addEventListener(Event.COMPLETE, onComplete);

function onComplete(evt:Event) {
info_ta.text = ul.data;
}

相關檔案下載

2008-05-20

建立 DisplayObject 物件 的 Bitmap 替身

包含動態文字的視覺物件常會因為旋轉而消失
在此弄個類別用以建立替身, 由於是點陣資料, 故縮放的時候會比較醜
測試的 Frame Actions :
import lin.shinder.display.Substitute;

var _txt:TextField = new TextField;
_txt.text = "ABCDEF";
this.addChild(_txt);

var s:Substitute = new Substitute(_txt).displace();
s.rotation = 30;

var s_mc:Substitute = new Substitute(t_mc);
s_mc.x = 200;
s_mc.y = 200;
this.addChild(s_mc);

類別檔 Substitute.as :
package lin.shinder.display
{
import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.PixelSnapping;
// 替身
dynamic public class Substitute extends Sprite
{
private var bitmap:Bitmap;
public var bitmapData:BitmapData;
public var original:DisplayObject;

public function Substitute(disp:DisplayObject)
{
original = disp;
bitmapData = new BitmapData(disp.width, disp.height, true, 0);
var rect:Rectangle = disp.getBounds(disp);
var matrix:Matrix = new Matrix;
matrix.translate(-rect.x, -rect.y);
bitmapData.draw(disp, matrix);
bitmap = new Bitmap(bitmapData, PixelSnapping.AUTO, true);
bitmap.x = rect.x;
bitmap.y = rect.y;
this.addChild(bitmap);
this.visible = original.visible;
this.x = original.x;
this.y = original.y;
this.scaleX = original.scaleX;
this.scaleY = original.scaleY;
this.rotation = original.rotation;
}

public function displace():Substitute
{
if(! original.parent) {
trace('The original DisplayObject is not in display chains !');
return null;
}
var _parent:DisplayObjectContainer = original.parent as DisplayObjectContainer;
var depth:int = _parent.getChildIndex(original);
_parent.addChildAt(this, depth);

_parent.removeChild(original);
return this;
}
}
}

測試範例原始檔

2008-05-16

Flash Player 10 beta, code-named "Astro"

新的 Flash Player 10 進入 beta 階段
Developer 另一階段的苦難又要開始了 :P

2008-04-25

Firefox 2 的 IE Tab 外掛跑 Flash 會有怪問題

Flash CS3/AS3, stage.stageWidth 和 stage.stageHeight 在 FireFox 2 的 IE Tab 外掛會有 Bug, 一開始值為 0.

2008-04-18

AS3 亂數排序的效能

利用三種方式來實作亂數排序的功能, 並比較效能
A. 製作 Array.sort() 的排序函式
B. 大風吹, 兩兩隨機交換位置
C. 使用 splice() 隨機一個個切出來
結果 B 效能最佳:
A: 2116
B: 66
C: 3828

Flash Frame Actions:
/*
*******
A. 配合 Array.sort() 使用
*******
*/
function shuffle_1(...args):int
{
return Math.floor(3 * Math.random()) - 1;
}
/*
*******
B. 大風吹, 隨機交換位置
*******
*/
function shuffle_2(ar:Array):void
{
var rnd:int;
var tmp:Object;
for (var i:int=0; i < ar.length; i++) {
rnd = Math.floor(Math.random()*ar.length);
tmp = ar[i];
ar[i] = ar[rnd];
ar[rnd] = tmp;
}
}
/*
*******
C. 隨機一個一個取出, 推入新陣列
*******
*/
function shuffle_3(ar:Array):Array
{
var br:Array = [];
var rnd:int;
var cr:Array;
while (ar.length)
{
rnd = Math.floor(Math.random()*ar.length);
//cr = ar.splice(rnd, 1);
br.push( ar.splice(rnd, 1)[0] );

}
return br;
}
/*****************************************/
var ar:Array = [];
for (var i:int=0; i < 100000; i++) {
ar.push(i);
}

var t:int = getTimer();
ar.sort(shuffle_1);
trace("A: "+ (getTimer()-t) );

t = getTimer();
shuffle_2(ar);
trace("B: "+ (getTimer()-t) );

t = getTimer();
ar = shuffle_3(ar);
trace("C: "+ (getTimer()-t) );

AS3 兩點求距離

AS3 求兩點間的距離不用記公式了
var p1:Point = new Point(10, 8);
var p2:Point = new Point(2, 17);
trace( Point.distance(p1, p2));
trace(p1.subtract(p2).length);

2008-04-17

Popup Modal MovieClip for Flash/AS3

Flex 有 PopUpManager 可以 pop-up window 或 custom component
Flash CS3/AS3 則沒有 :(
若只是用個 PopUpManager, 以 Flex 發佈後實在有點肥大...

我在網路上找了老半天, 只找到 Yahoo ASTRA Flash Components 裡提供的 AlertManager. 不過功能實在太陽春, 想說做點客制化, 改著改著幾乎跟重寫差不多了. 版權 follow BSD.

Demo:


ModalDisplayManager.as
/*
Copyright (c) 2008 Yahoo! Inc. All rights reserved.
The copyrights embodied in the content of this file are licensed under the BSD (revised) open source license

shinder modified
refer com.yahoo.astra.fl.managers.AlertManager

shinder.lin@gmail.com
http://qops.blogspot.com/
*/

package lin.shinder.fl.managers
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.Graphics;
import flash.display.Stage;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BitmapFilterQuality;
import flash.filters.BlurFilter;
import flash.filters.BitmapFilter;

public class ModalDisplayManager extends MovieClip
{
private static var _alertQueue:Array = [];
private static var _alert:MovieClip;
private static var _displayManager:ModalDisplayManager;
private static var _stage:Stage;
public static var overlayAlpha:Number = .16;
public static var modalBackgroundBlur:int = 3;
private static var _overlay:MovieClip;
protected var container:DisplayObject;
protected var parentFilters:Array;

public function ModalDisplayManager(container:DisplayObject)
{
if (! _displayManager) {
if (container != null) {
_stage = container.stage;
} else {
trace("ModalDisplayManager: the 1st parameter cannot be null !");
}
if ( _stage.scaleMode != StageScaleMode.NO_SCALE ) {
// trace("ModalDisplayManager prefers: stage.scaleMode = StageScaleMode.NO_SCALE !");
}
if ( _stage.align != StageAlign.TOP_LEFT ) {
trace("ModalDisplayManager prefers: stage.align = StageAlign.TOP_LEFT !");
}
_stage.addChild(this);
_stage.addEventListener(Event.RESIZE, stageResizeHandler);
_stage.addEventListener(Event.FULLSCREEN, stageResizeHandler);
}
}

public static function createModalDisplay(container:DisplayObject,
content:Class = null,
promp:Object = null):ModalDisplayManager
{
if (! _displayManager) {
_displayManager = new ModalDisplayManager(container);
}
_overlay = new MovieClip();
var g:Graphics = _overlay.graphics as Graphics;
g.beginFill(0xeeeeee, overlayAlpha);
g.moveTo(0,0);
g.lineTo(100, 0);
g.lineTo(100, 100);
g.lineTo(0, 100);
g.lineTo(0, 0);
g.endFill();
_displayManager.addChild(_overlay);

_overlay.stageResizeHandler = function() {
this.width = _stage.stageWidth;
this.height = _stage.stageHeight;
if (this._alert != null ) {
this._alert.x = (_stage.stageWidth-this._alert.width)/2;
this._alert.y = (_stage.stageHeight-this._alert.height)/2;
}
};

_alert = new content() as MovieClip;
_overlay._alert = _alert;
_overlay.stageResizeHandler();
if (_alert.init) {
_alert.init(promp);
} else {
// trace("ModalDisplayManager: the 2nd parameter should define a function named init(promp:Object) !");
}
_displayManager.addChild(_alert);
_displayManager.container = container;
var newFilters:Array = _displayManager.container.filters.concat();
var oldFilters:Array = _displayManager.container.filters.concat();

if(_alertQueue.length == 0) {
newFilters.push(_displayManager.getBlurFilter());
_displayManager.container.filters = newFilters;
}
for(var i:int=0; i < _alertQueue.length; i++) {
_alertQueue[i]['_alert'].filters = [_displayManager.getBlurFilter()];
}

var alertParams:Object = {
container:container,
content:content,
promp:promp,
_overlay:_overlay,
_alert:_alert,
_filters:oldFilters
};
_alertQueue.push(alertParams);
return _displayManager;
}

public function manageQueue():void
{
if(_alertQueue.length == 0){
return;
}
var obj:Object = _alertQueue.pop();
obj.container.filters = obj._filters;
_displayManager.removeChild(obj._alert);
_displayManager.removeChild(obj._overlay);
if(_alertQueue.length>0) {
_alertQueue[_alertQueue.length-1]['_alert'].filters = [];
}
}

public function getBlurFilter():BitmapFilter
{
var blurFilter:BlurFilter = new BlurFilter();
blurFilter.blurX = modalBackgroundBlur;
blurFilter.blurY = modalBackgroundBlur;
blurFilter.quality = BitmapFilterQuality.HIGH;
return blurFilter;
}

private function stageResizeHandler(evt:Event):void
{
for each(var o:Object in _alertQueue) {
o._overlay.stageResizeHandler();
}
}
}
}

Frame Actions:
import lin.shinder.fl.managers.ModalDisplayManager;
stage.align = StageAlign.TOP_LEFT;
b_btn.addEventListener(MouseEvent.CLICK, onClick);
y_btn.addEventListener(MouseEvent.CLICK, onClick);
function onClick(evt:MouseEvent):void
{
if (evt.currentTarget==b_btn) {
ModalDisplayManager.createModalDisplay(this, mc_gear);
} else {
ModalDisplayManager.createModalDisplay(this, mc_gear2, {a:"abc"});
ModalDisplayManager.createModalDisplay(this, mc_gear3);
}
}
測試範例原始檔

2008-04-14

關掉 USB 碟的自動播放吧

朋友給資料時的 USB 碟幾乎每支都有木馬, 而且共用的電腦也常中木馬
在此建議關掉 autorun 功能, 資料來源 資安論壇

執行 regedit,至
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explor
er]
加入(修改) dword
名稱=NoDriveTypeAutoRun
值=000000ff

2008-03-22

使用 Flash CS3 製作 Flex 的組件


  1. http://www.adobe.com/go/flex3_cs3_swfkit 下載 Flex Component Kit for Flash CS3 (也可以一併下載 Flex Skin Design Extensions)

  2. 使用 Extension Manager 安裝如這篇說明 Installing the Flex Component Kit for Flash CS3

  3. nick velloff 的製作範例在 Flex Component Kit Examples, MAX 2007 Chicago Presentation

2008-03-10

在 CodeIgniter 裡建立 SabreAMF 的 gateway

承上一篇 結合 CodeIgniter 和 SabreAMF
接著是建立 gateway, 請參考 Using Flex 2 RemoteObject and SabreAMFGetting started with SabreAMF 的作法。
我們會將 gateway 放在 Controllers 裡。Server side remoting 程式則是放在 Models 裡。
在 ci_project/system/application/controllers/ 新增檔案 gateway.php
<?php
class Gateway extends Controller {
function Gateway()
{
parent::Controller();
}

function index()
{
require_once('SabreAMF/CallbackServer.php');
try {
$callbackServer = new SabreAMF_CallbackServer();
$callbackServer->onInvokeService = array($this, 'invokeService');
$callbackServer->exec();
}catch(Exception $e){
echo $e->getMessage();
}
}

function invokeService($service, $method, $data) {
$modelPath = str_replace( '.', '/', $service);
$this->load->model($modelPath, 'amf_model');
return call_user_func_array( array( $this->amf_model, $method ), $data );
}
}
?>

測試的 Models 放在 ci_project/system/application/models/test/test_model.php
<?php
class Test_model extends Model
{
function Test_model()
{
parent::Model();
}

function myMethod($d1, $d2)
{
$ret = array(
array( 'ID' => $d1, 'name' => 'okok', 'phone' => $d2 ),
array( 'ID' => '35712', 'name' => 'Esbd V. Mb', 'phone' => '235-4263' ),
array( 'ID' => '46823', 'name' => 'Ftce W. Nc', 'phone' => '346-5374' ),
);
return $ret;
}
}
?>

Flash CS3 AS3 的 client 測試
import fl.data.DataProvider;
var nc:NetConnection = new NetConnection();
//nc.objectEncoding = ObjectEncoding.AMF3;

var onResult:Function = function(result:Object) {
QopDump.echo(result);
dg.dataProvider = new DataProvider(result);
};
var onStatus:Function = function(info:Object) {
QopDump.echo(info);
};
var responder:Responder = new Responder(onResult, onStatus);
nc.connect("http://localhost/ci/?/gateway");

nc.call("test.Test_model.myMethod", responder, ["888", "666"]);

Flex 的 client 測試
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:RemoteObject id="ro"
destination=" "
endpoint="http://localhost/ci/?/gateway"
source="test.Test_model"
result="resultHandler( event )"
fault="faultHandler( event )">
</mx:RemoteObject>
<mx:Script>
<![CDATA[
import mx.rpc.events.*;
import mx.controls.Alert;
import mx.rpc.*;

private function load():void {
ro.myMethod('first','123-456789');
}
private function resultHandler( event:ResultEvent ):void {
Alert.show( QopDump.go(event.result) );
dg.dataProvider = event.result;
}
private function faultHandler( event:FaultEvent ):void {
Alert.show( event.toString() );
}
]]>
</mx:Script>
<mx:Button click="load()" label="Load" />
<mx:DataGrid id="dg" />
</mx:Application>

結合 CodeIgniter 和 SabreAMF

參考這篇 將 Zend Framework 放進 CodeIgniter
將符合 PEAR 規定的 library 掛上 CodeIgniter
1. 設定 config
修改 ci_project/system/application/config/config.php
$config['enable_hooks'] = TRUE;


2. 增加 hooks 設定
於 ci_project/system/application/config/hooks.php 增加
$hook['pre_controller'][] = array(
'class' => 'Pearroot',
'function' => 'index',
'filename' => 'pearroot.php',
'filepath' => 'hooks',
);


3. 增加 hooks 程式
於 ci_project/system/application/hooks/ 裡增加 pearroot.php
<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');
class Pearroot
{
function index()
{
set_include_path(get_include_path() . PATH_SEPARATOR . BASEPATH . 'pearroot/');
}
}
?>


4. 放置 SabreAMF 目錄
建立 ci_project/system/pearroot/ 目錄並將 SabreAMF/ 放置其底下, 就完成初步的設定。
下一篇 在 CodeIgniter 裡建立 SabreAMF 的 gateway

2008-02-24

設定 eclipse - PDT 檔案預設編碼

Preferences
→ 點左側 Content Types
→ 點右側 PHP Content Type
→ 在右下的 Default encoding 欄填入編碼例如「utf-8」
→ 點 Update
→ 點 OK

2008-01-27

如何選擇 MySQL 的儲存引擎

MySQL Storage Engines 值得細細品味!
簡單的講, 要快要方便用 MyISAM, 要 Transaction-safe 用 innoDB。

JavaScript 動態產生 radio 選項

例子
如果沒有表單成員, 不可以直接使用 document.form1.radiog.value 去判斷, 否則會發生語法錯誤, 而應先以 document.form1.radiog 判斷。
多個 radio button 會變成陣列, 判斷方式和單一個不同。
另外, 上面的例子在 Firefox 2.0.0.11 會發生錯誤, 如果先在「單一選項」或「多個選項」選第一個項目再回到「沒有選項」並按「檢查」, 就可以看到問題 =.=

2008-01-24

AS3 翻頁效果 (使用現成類別)

PageFlip class
作者首頁
測試範例

import com.foxaweb.pageflip.PageFlip;

const PAGE_WIDTH = 240;
const PAGE_HEIGHT = 180;

var render:Shape=new Shape();
var page0:BitmapData=new p0(PAGE_WIDTH, PAGE_HEIGHT);
var page1:BitmapData=new p1(PAGE_WIDTH, PAGE_HEIGHT);

render.x=250;
render.y=35;
addChild(render);
this.addEventListener(Event.ENTER_FRAME, onEF);

function onEF(e:Event){
render.graphics.clear();
// 計算翻頁的物件
var o0:Object = PageFlip.computeFlip(
new Point(render.mouseX, render.mouseY), // 翻折位置
new Point(1,1), // 右下角
PAGE_WIDTH, PAGE_HEIGHT, // 尺寸
true, // 水平翻頁
1);
PageFlip.drawBitmapSheet(o0, render, page0, page1);
}

測試範例原始檔

2008-01-16

JavaScript 傳中文給 PHP

用 GET 送中文字時, 不同瀏覽器的行為不同
所以先以 JS 轉換成 Unicode
傳給 PHP 後, 再轉成 utf8
資料來源: Neo's Blog 使用 PHP 解譯 javascript escape() 編碼過的字串
<?php
$search_value = uniDecode($search_value, 'utf8');

function uniDecode($str,$charcode){
$text = preg_replace_callback("/%u[0-9A-Za-z]{4}/",toUtf8,$str);
return mb_convert_encoding($text, $charcode, 'utf-8');
}

function toUtf8($ar){
foreach($ar as $val){
$val = intval(substr($val,2),16);
if($val < 0x7F){ // 0000-007F
$c .= chr($val);
}elseif($val < 0x800) { // 0080-0800
$c .= chr(0xC0 | ($val / 64));
$c .= chr(0x80 | ($val % 64));
}else{ // 0800-FFFF
$c .= chr(0xE0 | (($val / 64) / 64));
$c .= chr(0x80 | (($val / 64) % 64));
$c .= chr(0x80 | ($val % 64));
}
}
return $c;
}
?>

2008-01-14

無權設定 php.ini 時

可以使用 ini_set() 函式
若只是設定 include path 可以使用 set_include_path()
以下是官網的範例:
<?php
$path = '/usr/lib/pear';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
?>

2008-01-11

INNER JOIN 的效能 (SQL)

個人經驗是 JOIN 三張表以上, 效能明顯變慢。可以使用 sub select 來達到相同的目的。
用一個資料表開得不好的例子來說明。
第一種:
SELECT a. * , ch.listname AS chl, cn.listname AS cnl, en.listname AS enl, jp.listname AS jpl, kr.listname AS krl
FROM aa_mainmenu a
INNER JOIN ch_mainmenu ch ON a.sno = ch.a_id
INNER JOIN cn_mainmenu cn ON a.sno = cn.a_id
INNER JOIN en_mainmenu en ON a.sno = en.a_id
INNER JOIN jp_mainmenu jp ON a.sno = jp.a_id
INNER JOIN kr_mainmenu kr ON a.sno = kr.a_id
ORDER BY a.priority DESC

第二種:
SELECT *
FROM (

SELECT a. * , b.listname AS kr
FROM aa_mainmenu a
INNER JOIN kr_mainmenu b ON a.sno = b.a_id
)a
INNER JOIN (

SELECT a. * , b.en, b.jp
FROM (

SELECT a.a_id, a.listname AS ch, b.listname AS cn
FROM ch_mainmenu a
INNER JOIN cn_mainmenu b ON a.a_id = b.a_id
)a
INNER JOIN (

SELECT a.a_id, a.listname AS en, b.listname AS jp
FROM en_mainmenu a
INNER JOIN jp_mainmenu b ON a.a_id = b.a_id
)b ON a.a_id = b.a_id
)b ON a.sno = b.a_id
ORDER BY a.priority DESC

第二種看起來較複雜, 但執行效能通常比第一種好。

FB 留言