スパイラルカレンダー
操作方法:
* ドラッグ上下:拡大・縮小
* ドラッグ左右:回転
* Spaceキー:初期化/表示変更
* Shift or Ctrl+ドラッグ:?
/**
* Copyright talte ( http://wonderfl.net/user/talte )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/m6PQ
*/
/*
* 操作方法:
* ドラッグ上下:拡大・縮小
* ドラッグ左右:回転
* Spaceキー:初期化/表示変更
* Shift or Ctrl+ドラッグ:?
*/
package
{
import flash.display.Sprite
import flash.events.Event
import flash.events.MouseEvent
import flash.events.KeyboardEvent
import org.papervision3d.objects.DisplayObject3D
import org.papervision3d.scenes.Scene3D
import org.papervision3d.typography.Font3D
import org.papervision3d.view.Viewport3D
import org.papervision3d.cameras.Camera3D
import org.papervision3d.render.BasicRenderEngine
import org.papervision3d.core.geom.Lines3D
import org.papervision3d.materials.special.LineMaterial
import org.papervision3d.core.math.Number3D
import org.papervision3d.typography.Text3D
import org.papervision3d.materials.special.Letter3DMaterial
import org.papervision3d.core.proto.MaterialObject3D
import org.papervision3d.typography.fonts.HelveticaBold
import org.papervision3d.core.math.Matrix3D
public class Calender extends Sprite
{
// 3D関連
private var object:DisplayObject3D
private var scene:Scene3D
private var camera:Camera3D
private var viewport:Viewport3D
private var render:BasicRenderEngine
// 操作関連
private var mouse_down:Boolean = false
private var mouse_x:int
private var mouse_y:int
private var key_shift:Boolean = false
private var key_ctrl:Boolean = false
private var key_space:Boolean = false
// 日付関連
private var now:Date = new Date
private var today:Date = new Date
private var firstweek:int
private var lastday:int
public function Calender()
{
this.addEventListener(Event.ADDED_TO_STAGE, this.onInit) // 初期化
}
// 初期設定
public function onInit(event:Event):void
{
// 3D関連初期化
this.viewport = new Viewport3D(0, 0, true)
this.viewport.opaqueBackground = 0x000000
this.addChild(this.viewport)
this.render = new BasicRenderEngine
this.camera = new Camera3D
this.scene = new Scene3D
// 初期化
this.initObject() // 描画
this.initDisplay() // 表示
// 動作登録
stage.addEventListener(Event.ENTER_FRAME, this.onEnterFrame)
stage.addEventListener(MouseEvent.MOUSE_DOWN, this.onMouseDown)
stage.addEventListener(MouseEvent.MOUSE_UP, this.onMouseUp)
stage.addEventListener(MouseEvent.MOUSE_MOVE, this.onMouseMove)
stage.addEventListener(MouseEvent.MOUSE_WHEEL, this.onMouseWheel)
stage.addEventListener(KeyboardEvent.KEY_DOWN, this.onKeyDown)
stage.addEventListener(KeyboardEvent.KEY_UP, this.onKeyUp)
}
// 描画初期化
private function initObject():void
{
// 初期化
var obj:DisplayObject3D = new DisplayObject3D
if(this.object != null) {
this.scene.removeChild(this.object) // クリア
obj.copyTransform(this.object.transform) // 表示情報を引き継ぐ
}
this.scene.addChild(obj)
this.object = obj
// 日付関連計算
var date:Date = new Date(now)
date.date -= date.date - 1
this.firstweek = date.day // 月初めの曜日
date.month += 1
date.date -= 1
this.lastday = date.date // 月終わりの日
// 日付描画
var letter_day:Letter3DMaterial = new Letter3DMaterial(0xaaaaaa)
var letter_sun:Letter3DMaterial = new Letter3DMaterial(0xff4444)
var letter_sat:Letter3DMaterial = new Letter3DMaterial(0x4444ff)
var font:Font3D = new HelveticaBold
for(var i:int = 1; i <= lastday; i++) {
// 文字色
var mat:MaterialObject3D
if((i + firstweek) % 7 == 1) { // 日曜
mat = letter_sun
}
else if ((i + firstweek) % 7 == 0) { // 土曜
mat = letter_sat
}
else {
mat = letter_day
}
var text:Text3D = new Text3D(i.toString(), font, mat)
var ang:Number = ((i - 1) / 7 + 0.25) * Math.PI * 2
text.x = 500 * -Math.cos(ang)
text.y = 500 * Math.sin(ang)
text.z = -1520 + i * 100
text.rotationX = -90
text.rotationZ = -360 * ((i - 1) / 7)
this.object.addChild(text)
}
// 枠線
var line_today:LineMaterial = new LineMaterial(0xffff00)
var line_other:LineMaterial = new LineMaterial(0xff0000)
// 横線描画
var lines:Lines3D = new Lines3D
var pos_from:Number3D = null
for(i = 0; i <= (lastday + 7) * 10; i++) { // 曲線にするため細かく
// 文字色
if (this.now.fullYear == this.today.fullYear && this.now.month == this.today.month && ((i > (this.today.date - 1) * 10 && i <= this.today.date * 10) || (i > (this.today.date + 6) * 10 && i <= (this.today.date + 7) * 10))) { // 今日
lines.material = line_today
}
else {
lines.material = line_other
}
var pos_to:Number3D = new Number3D
ang = ((i / 10 - 0.5) / 7 + 0.25) * Math.PI * 2
pos_to.x = 500 * -Math.cos(ang)
pos_to.y = 500 * Math.sin(ang)
pos_to.z = -1600 + i * 10
if (pos_from != null) {
lines.addNewLine(1, pos_from.x, pos_from.y, pos_from.z, pos_to.x, pos_to.y, pos_to.z)
}
pos_from = pos_to // 前回の位置を保存して次回に使う
}
this.object.addChild(lines)
// 縦線描画
for(i = 0; i <= lastday; i++) { // 線の片側が画面外だと消えるので分けて描画
lines = new Lines3D
// 文字色
if(this.now.fullYear == this.today.fullYear && this.now.month == this.today.month && (i == this.today.date - 1 || i == this.today.date)) { // 今日
lines.material = line_today
}
else {
lines.material = line_other
}
ang = (((i - 0.5) / 7 + 0.25) * Math.PI * 2)
pos_from = new Number3D(500 * -Math.cos(ang), 500 * Math.sin(ang), -1600 + (i / 7 * 7) * 100)
pos_to = new Number3D(500 * -Math.cos(ang), 500 * Math.sin(ang), -1600 + ((i / 7 + 1) * 7) * 100)
lines.addNewLine(1, pos_from.x, pos_from.y, pos_from.z, pos_to.x, pos_to.y, pos_to.z)
this.object.addChild(lines)
}
}
// 表示初期化
private function initDisplay():void
{
this.object.transform = new Matrix3D
if(this.key_space) {
this.object.moveUp(this.now.date * 100 - 1300)
this.object.pitch(90)
this.camera.z = -600
this.key_space = false
}
else {
this.camera.z = -2200
this.key_space = true
}
this.object.roll((this.now.day - this.firstweek) / 7 * 360)
}
// 更新
private function onEnterFrame(event:Event):void
{
// 再描画
this.render.renderScene(this.scene, this.camera, this.viewport)
}
// マウス移動
private function onMouseMove(event:MouseEvent):void
{
// クリック時
if(this.mouse_down) {
if(this.key_shift && !this.key_ctrl) { // shiftのみ
this.object.transform = Matrix3D.multiply(Matrix3D.translationMatrix((event.stageX - this.mouse_x) * 3, 0, 0), this.object.transform) // 横:X軸移動
this.object.transform = Matrix3D.multiply(Matrix3D.translationMatrix(0, -(event.stageY - this.mouse_y) * 3, 0), this.object.transform) // 縦:Y軸移動
}
else if(!this.key_shift && this.key_ctrl) { // ctrlのみ
this.object.transform = Matrix3D.multiply(Matrix3D.rotationY((event.stageX - this.mouse_x) / 60), this.object.transform) // 横:Y軸回転
this.object.transform = Matrix3D.multiply(Matrix3D.rotationX( -(event.stageY - this.mouse_y) / 60), this.object.transform) // 縦:X軸回転
}
else if(this.key_shift && this.key_ctrl) { // shiftとctrl
this.object.transform = Matrix3D.multiply(Matrix3D.rotationZ(-(event.stageX - this.mouse_x) / 60), this.object.transform) // 横:Z軸回転
this.camera.z -= (event.stageY - this.mouse_y) * 10 // 縦:ズーム
}
else { // キーなし
this.object.roll(-(event.stageX - this.mouse_x)) // 横:カレンダー回転
this.object.moveForward((event.stageY - this.mouse_y) * 3) // 縦:カレンダー上下
}
// マウス位置更新
this.mouse_x = event.stageX
this.mouse_y = event.stageY
}
}
// マウス押す
private function onMouseDown(event:MouseEvent):void
{
this.mouse_down = true // クリック
// マウス位置更新
this.mouse_x = event.stageX
this.mouse_y = event.stageY
}
// マウス離す
private function onMouseUp(event:MouseEvent):void
{
this.mouse_down = false // クリック解除
}
// マウスホイール
private function onMouseWheel(event:MouseEvent):void
{
this.now.month += event.delta > 0 ? 1 : -1
this.now.date = 1
this.initObject()
}
// キー押す
private function onKeyDown(event:KeyboardEvent):void
{
switch(event.keyCode) {
case 16: // shift
this.key_shift = true
break
case 17: // ctrl
this.key_ctrl = true
break
}
}
// キー離す
private function onKeyUp(event:KeyboardEvent):void
{
switch(event.keyCode) {
case 16: // shift
this.key_shift = false
break
case 17: // ctrl
this.key_ctrl = false
break
case 32: // space
this.initDisplay()
break
}
}
}
}