공부놀이 2007. 12. 24. 10:41

[펌] 개인발행의 진화

또또 영어로군요~~ 해석 ㄱㄱ싱~



The Evolution of Personal Publishing

Written by Alex Iskold / December 11, 2007 12:00 AM / 13 Comments

Fred Wilson recently wrote a post on his blog in which he argues that the rapid adoption of Twitter and Tumblr were not accidents. Fred sees these microblogging platforms as a direct evolution of blogging and social networks. Recently, I've been mulling over similar thoughts. Clearly, the success of these sites was not accidental; because they took off in a crowded market, these were things that people obviously needed.


The image above is by Fred Wilson.

In this post, we will argue that each category - blogs, social networks and microblogs - forms a separate vertical. Each vertical is focused on a different type of user and serves to fill a different purpose in the bigger landscape of social publishing.

Prehistory - Web Sites

Remember the days in which the more technically inclined of us had web sites? I went through 3 or 4 different versions of my site with about the same content - books I liked, software I'd written, my resume, and my photos. Making a web site was not very difficult if you knew HTML, but was nearly impossible if you did not. The WYSIWYG web site tools never quite worked as expected and in the end people found them unappealing.

Yet, quite a few people did have personal web sites back in the earlier days of world wide web. The biggest problem with those sites, however, was that they were static. The content of a site rarely changed, and even when it did, there was no way for other people to find out. As a result, personal web sites really never caught on with mainstream web users. That all changed when blogs burst on the scene.

Blogs as Online Diaries

Blogs worked because they were like diaries. Content is presented in reverse chronological order (with the latest content on top). This single fact alone made a big difference, because it quickly showed readers how content was changing and being updated. The other thing blogs got right was templates. One of the difficulties in making web sites is that there is an enormous number of ways in which content can be presented, and for people who are not technically savvy this presents a barrier. Templates solve this problem because pre-structured content leaves less room to screw things up.

So, blogging platforms made it easier for people to publish online without having to deal with HTML. Liberated from the need to deal with technical quirks, people finally had the chance to focus on the content. And they did. Blogging took off in a major way around 2003-2004. At the time, it was really the only only way to do personal publishing online.

Social Networks Take Personal Publishing Mainstream

Social networks arrived next and reached a much wider audience than blogs. The reason for this is that social networks are publishing systems where the content is produced automatically as the consequence of social interactions. For example, writing on a Facebook Wall is a form of personal publishing, but we just don't generally look at it in that way. We think of it as a message sent to a friend, but an aggregate of all the messages that we leave amounts to a chunk of our online personal publishing. Posting a photo or a video is no different, as it is an act of creating personal content.

The trick is that social networks do not emphasize the publishing angle. They focus on the social bits. The publishing occurs in the context of socializing and therefore is transparent. More important, it is perceived as easy. Writing a long blog post is much harder than posting a photo. It is this ease of content creation that immediately made social networks appealing to the mainstream as a method of online content publishing.

Microblogging Jumps in the Middle

Despite the fact that content creation in social networks is very easy, it has a very different purpose and very different feel from blogging. In social networks the informational bits are scattered, but in blogs, they are focused and organized sequentially. Social network publishing is very terse, blog publishing is verbose. Is there a form of publishing which is on one hand as easy as social networking, but as sequential as regular blogs? Twitter and Tumblr have recently emerged to define this new category of microblogging.

Characterized by ease of use and compactness, these new forms of communication are racing to fill a niche between blogs and social networks. In addition to the standard publishing, which both borrowed from blogs, both services have taken ideas from social networking sites, as well, allowing people to remix and see each other's content.

Twitter has mashed up communication and personal publishing to create a compelling new form of real-time publishing. The idea of expressing of what you are doing right now in less than 140 characters is clever, but remixing other users' posts and allowing people to subscribe to each other's messages was the stroke of genius that made Twitter a hit. But while Twitter is probably a descendant of a chat and social networking, Tumblr is a direct remix of blogging and social networking.

Tumblr dramatically simplifies blogging in the same way that blogs simplified web sites. Unlike traditional blogging software - Blogger, Typepad, Wordpress, MoveableType - Tumblr posts are much more focused and shorter. The simplicity is achieved by focusing each post on a single object - a photo, a video, a link, a quote, or a piece of text. Tumblr supports rich text editing, but it has been downplayed in favor of quick posting. It is also possible to have widgets and other stuff present in your Tumblr's sidebar, but most Tumblr blogs do not use them, favoring instead a clean, bare look. The point is to simplify blogging by focusing on the personal lifestream, the essence of personal content.

Verticalization of Everything

Coming back to Fred Wilson's observation - the emergence of microblogging is not an accident. It represents a well known trend of verticalization. When new markets form they continue to be partitioned into niches. Since the gap between blogging and social networking was very wide, and the audience was quite different, microblogging emerged. Tumblr in particular defines a new class of users. These are people who may be daunted by the complexity of blogging platforms, but want more than the primitive publishing offered by social networks. In addition, Tumblr is appealing to users like myself, who use blogging platforms professionally, but are happy with a lighter solution for a personal blog.

In terms of ease of use and elegance of delivery, Tumblr certainly fills its niche. The bigger question is, would people find the social aspects of Tumblr interesting? On one hand, as Fred Wilson points out, the fact that your personal stream is mixed with other people's streams is cool. Beyond cool, however, is there a value in seeing small, random bits from other people's lives? This is different from reading people's blogs, where posts seemed to be lengthier and more topical. Yet, the answer is likely still to be yes.

Conclusion

The personal publishing market evolved from cumbersome web sites to online diaries called blogs to social networks and more recently to microblogs. Each form of personal publishing is different and each has its niche and audience. While social networks have been the most wide spread, the content creation there feels different from publishing. Because traditional blogging platforms are powerful and still require technical know-how, microblogging has evolved as an intermediate form of self-publishing. Microblogging has a shot of spreading blogging further into the mainstream as well as swaying some professional bloggers to start personal blogs.

It will be interesting to see what will to happen to microbogging in 2008. Do you think it is going to take off? Do you have a Tumblr blog today? Are you likely to get one soon? Do you use Twitter?

Disclosure: Fred Wilson is a managing partner of Union Square Ventures, a fund which invested in Alex's company AdaptiveBlue, as well as Twitter and Tumblr.

'공부놀이' 카테고리의 다른 글

구글API - GData [1]  (0) 2007.12.12
,
공부놀이 2007. 12. 12. 15:11

구글API - GData [1]

Google Data APIs Protocol Basics
이 문서는 query 가 어떻게 생겨먹었는지, 결과는 어떻게 생겼는지, 기타 등등을 포함한 oogle data API(GData) 에 의해 사용되는 프로토콜의 기본을 설명하고 있습니다.

Google data API 에 대해서 더 많은 정보가 필요하다면, Google Data APIs Overview 문서와 Protocol Reference 문서를 들여다 보시지요.


알림말

이 문서는 누구든지 보편적인 관념의 XML 형식과 Google data API 가 사용하는 프로토콜을 이해하기 원하는 아무나를 대상으로 계획되었습니다.

Gdata 클라이언트 API 를 사용하는 코드를 쓰고 싶다면, 특정 언어의 client libraries 를 사용할 수도 있습니다.
어쨋든 client libray 추상 레이어의 이득이 뭔지 이해하기 위해서라면 이 문서를 읽고 싶을지도 모르겠군요.
(뭔소리람 -ㅍ-.. 해석을 잘 못한걸지도;)

이 문서는 XML의 기본을 이해하고 있다는 것을 전제로 합니다. 네임스페이스, 조직적인 피드와 http 요청중 GET, POST, PUT, DELETE 등과, HTTP의 리소스 로서의 컨셉등등을 말이죠. 이런 것들에 대한 더 많은 정보를 원한다면, 이 문서의 Additional resources(추가 리소스) 를 들여다 보기 바랍니다.

이 문서는 다른 어떤 특정한 프로그래밍 언어에도 의지하지 않습니다. HTTP 요청을 송신하고 XML 기반의 응답을 파싱 할 수 있는 아무 프로그래밍 언어를 사용해서 GData 메시지를 주고받을수 있습니다.

예제

다음의 예제들은 일반적인 서비스에 보낼 그대로의 GData 프로토콜 요청과 받을 GData 형식의 결과를 보여줍니다. 예를들어 여러가지 프로그래밍 언어를 사용해서 어떻게 요청을 보내는가는, 특정언어 samples 과 client libraries 를 보시기 바랍니다. GData 를 이용하는 특정한 구글 서비스에 대한 더 많은 정보를 원한다면, 특정서비스 문서를 보세요.

feed 혹은 다른 리소스 요청

/myFeed 라는 feed 가 있다고 치고, 지금은 아무런 엔트리가 없다고 칩시다. 그것을 보기 위해서는 다음과 같은 요청을 서버로 보내면 됩니다.

GET /myFeed

서버 응답:

200 OK

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Foo</title>
  <updated>2006-01-23T16:25:00-08:00</updated>
  <id>http://www.example.com/myFeed</id>
  <author>
    <name>Jo March</name>
  </author>
  <link href="/myFeed" rel="self"/>
</feed>

feed 에 어떠한 엔트리도 없고, 제목이나 저작자 이름 같은 메타데이터는 있는것을 유념하십시오.

새로운 엔트리 삽입

새 엔트리를 만들기 위해서는, 새로운 엔트리를 GData 형식에 맞춰서 POST 요청을 보내면 됩니다.

POST /myFeed

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Elizabeth Bennet</name> 
    <email>liz@gmail.com</email> 
  </author>
  <title type="text">Entry 1</title>
  <content type="text">This is my entry</content>
</entry>

일반적인 Atom 의 <id>, <link>, 또는 <updated> 엘레먼트가 포함되지 않는다는것을 유념하세요; 그런건 서버가 당신의 POST 요청에 응답하면서 만듭니다. 또한 feed 의 저작자가 엔트리의 저작자와 같을 필요가 없다는것도 주의하세요.

서버응답:

201 CREATED

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>1</id>
  <link rel="edit" href="http://example.com/myFeed/1/1/"/>
  <updated>2006-01-23T16:26:03-08:00</updated>
  <author>
    <name>Elizabeth Bennet</name> 
    <email>liz@gmail.com</email> 
  </author>
  <title type="text">Entry 1</title>
  <content type="text">This is my entry</content>
</entry>

문자열로 찾기

full-text 찾기를 지원하는 서비스를 사용할때, 특정한 문자열로 full-text 찾기를 하기 위해서는
q 파라메터를 GET 요청과 함께 보냅니다. 쿼리 파라메터에 관한 더 많은 정보를 원하시면 프로토콜
레퍼런스 문서에서 Query requests 를 보시기 바랍니다

GET /myFeed?q=This



서버는 This 라는 문자열에 맞는 모든 엔트리들로 응답할 것입니다.
(지금의 경우에는 하나 뿐입니다만.)


200 OK <?xml version="1.0"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>Foo</title> <updated>2006-01-23T16:26:03-08:00</updated> <id>http://www.example.com/myFeed</id> <author> <name>Jo March</name> </author> <link href="/myFeed" rel="self"/> <entry> <id>1</id> <link rel="edit" href="http://example.com/myFeed/1/1/"/> <updated>2006-01-23T16:26:03-08:00</updated> <author> <name>Elizabeth Bennet</name> <email>liz@gmail.com</email> </author> <title type="text">Entry 1</title> <content type="text">This is my entry</content> </entry> </feed>



엔트리 업데이트 하기
To update an existing entry, use PUT, with the entry's edit URI
(as provided by the server in the previous example,
in the <link rel="edit"> element).

이미 존재하는 엔트리를 업데이트 하기 위해서는 엔트리의 edit URI 와 함께 PUT 을 사용하세요.
만일 방화벽이 PUT 을 허용하지 않는다면, HTTP POST 와 header 메소드를 다음과 같이 오버라이드
하십시오:

X-HTTP-Method-Override: PUT

다음의 예제에서는 엔트리의 텍스트를 ("This is my entry") 에서 ("This is my first entry.")
로 바꾸려고 합니다:

PUT /myFeed/1/1/

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>1</id>
  <link rel="edit" href="http://example.com/myFeed/1/1/"/>
  <updated>2006-01-23T16:28:05-08:00</updated>
  <author>
    <name>Elizabeth Bennet</name> 
    <email>liz@gmail.com</email> 
  </author>
  <title type="text">Entry 1</title>
  <content type="text">This is my first entry.</content>
</entry>

The server responds:

200 OK

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>1</id>
  <link rel="edit" href="http://example.com/myFeed/1/2/"/>
  <updated>2006-01-23T16:28:05-08:00</updated>
  <author>
    <name>Elizabeth Bennet</name> 
    <email>liz@gmail.com</email> 
  </author>
  <title type="text">Entry 1</title>
  <content type="text">This is my first entry.</content>
</entry>


edit URI 가 바뀐것에 주의하십시오; 그건 이제 "/1/" 로 끝나지 않고 "/2/" 로 끝납니다.
edit URI 에서 마지막 숫자는 버전 숫자를 의미합니다. 버전에 대해 더 많은 정보를 원한다면,
프로토콜 레퍼런스 문서의 Optimistic concurrency 섹션을 보십시오.



컨텍스트에서 새로운 엔트리를 보기 위해서는, 모든 리소스를 다시 요청하세요:

GET /myFeed

서버응답:

200 OK

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Foo</title>
  <updated>2006-01-23T16:28:05-08:00</updated>
  <id>http://www.example.com/myFeed</id>
  <author>
    <name>Jo March</name>
  </author>
  <link href="/myFeed" rel="self"/>
  <entry>
    <id>1</id>
    <link rel="edit" href="http://example.com/myFeed/1/2/"/>
    <updated>2006-01-23T16:28:05-08:00</updated>
    <author>
      <name>Elizabeth Bennet</name> 
      <email>liz@gmail.com</email> 
    </author>
    <title type="text">Entry 1</title>
    <content type="text">This is my first entry.</content>
  </entry>
</feed>

엔트리 삭제하기

이미 존재하는 엔트리를 삭제하려면, 엔트리의 edit URI 를 사용해서 DELETE 요청을 보내면 됩니다.

만일 방화벽이 DELETE 를 허용하지 않으면, HTTP POST 와 header 메소드를 다음과 같이 오버라이드
하십시오:

 X-HTTP-Method-Override: DELETE

다음의 예제는 엔트리를 삭제합니다:

DELETE /myFeed/1/2/

서버응답:

200 OK

이제 feed 가 아무런 엔트리를 가지지 않은것을 보려면또다를 GET 을 보내세요:

GET /myFeed

서버응답:

200 OK

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Foo</title>
  <updated>2006-01-23T16:30:11-08:00</updated>
  <id>http://www.example.com/myFeed</id>
  <author>
    <name>Jo March</name>
  </author>
  <link href="/myFeed" rel="self"/>
</feed>



'공부놀이' 카테고리의 다른 글

[펌] 개인발행의 진화  (0) 2007.12.24
,
공부놀이/ActionScripT 2007. 10. 24. 17:13

[3.0] 커스텀 버튼 클래스

package CustomButton {
 import flash.display.Sprite;
 import flash.events.MouseEvent;
 import flash.geom.ColorTransform;
 import flash.text.TextField;
 import flash.text.TextFormat;
 import flash.text.TextFormatAlign;

 public class CustomButton extends Sprite
 {
  private var btnTarget:Sprite;

  private var lbButton:TextField;
  private var lbFormat:TextFormat;
  private var btnName:String;
 
  private var btnColor:uint;
  private var isToggle:Boolean;
  private var isTargeted:Boolean;
 
  private var _toggled:Boolean;
 
  public function CustomButton(mcTarget:Sprite = null, color:uint = 0xffcc33)
  {
   if(mcTarget == null) {
    btnTarget = new Sprite();
    isTargeted = false;
    btnColor = color;
   } else {
    btnTarget = mcTarget;
    isTargeted = true;
    color = 0x000000;
   }
   btnName = "Button";
  }
 
  public function get toggled():Boolean { return _toggled; }
 
 
  public function activate():void
  {
   this.buttonMode = true;
   this.useHandCursor = true;
   draw_button();
  }
 
  public function destroy():void
  {
   isAlive(false);
   this.buttonMode = false;
   
   var dsFormat:TextFormat = new TextFormat();
   dsFormat.bold = false;
   dsFormat.color = 0x777777;
   
   lbButton.setTextFormat(dsFormat);
   
   btnTarget.removeEventListener(MouseEvent.MOUSE_OVER, over_listener);
   btnTarget.removeEventListener(MouseEvent.MOUSE_OUT, out_listener);
   btnTarget.removeEventListener(MouseEvent.MOUSE_UP, up_listener);
   btnTarget.removeEventListener(MouseEvent.MOUSE_DOWN, down_listener);
  }
 
  public function setToggle(val:Boolean):void
  {
   if(val) {
    isToggle = true;
    make_toggle();
   } else {
    isToggle = false;
   }
  }
 
  public function set label(button_name:String):void
  {
   btnName = button_name;
   addLabel();
  }
 
  public function get label():String
  {
   return btnName;
  }
 
  private function addLabel():void
  {
   if(lbButton == null){
    lbButton = new TextField();
    lbButton.width = btnTarget.width;
    lbButton.height = 20;
    lbButton.x = (this.width - lbButton.width)/2;
    lbButton.y = (this.height - lbButton.height)/2;
    lbButton.mouseEnabled = false;
   }
   
   lbFormat = new TextFormat();
   if(!isToggle)
    lbFormat.color = 0xFFFFFF;
   lbFormat.bold = false;
   lbFormat.size = 10;
   lbFormat.align = TextFormatAlign.CENTER;
   
   lbButton.text = btnName;
   
   lbButton.setTextFormat(lbFormat);
   
   this.addChild(lbButton);
  }
 
  private function addListeners():void
  {
   btnTarget.addEventListener(MouseEvent.MOUSE_OVER, over_listener);
   btnTarget.addEventListener(MouseEvent.MOUSE_OUT, out_listener);
   btnTarget.addEventListener(MouseEvent.MOUSE_DOWN, down_listener);
   btnTarget.addEventListener(MouseEvent.MOUSE_UP, up_listener);
  }
 
  private function over_listener(evt:MouseEvent):void
  {
   //trace("over");
   var ovFormat:TextFormat = new TextFormat();
   ovFormat.bold = false;
   ovFormat.color = 0xFFFF00;
   
   lbButton.setTextFormat(ovFormat);
  }
 
  private function down_listener(evt:MouseEvent):void
  {
   //trace("down");
   var dnFormat:TextFormat = new TextFormat();
   dnFormat.bold = false;
   dnFormat.color = 0xCCCCCC;
   
   lbButton.setTextFormat(dnFormat);
  }
 
  private function up_listener(evt:MouseEvent):void
  {
   //trace("up");
   lbButton.setTextFormat(lbFormat);
   //dispatchEvent(new MouseEvent("customCLICK", evt.bubbles, evt.cancelable, evt.localX, evt.localY, evt.relatedObject, evt.ctrlKey, evt.altKey, evt.shiftKey, evt.buttonDown, evt.delta));
   //dispatchEvent(evt);
  }
 
  private function out_listener(evt:MouseEvent):void
  {
   //trace("out");
   lbButton.setTextFormat(lbFormat);
  }
 
  private function draw_button():void
  {
   if(!isTargeted){
    //trace("drawing button elements");
    btnTarget.graphics.beginFill(btnColor);
    btnTarget.graphics.drawRoundRect(0, 0, 80, 20, 5);
    btnTarget.graphics.endFill();
   }
   this.addChild(btnTarget);
   addListeners();
   isAlive(true);
   addLabel();
  }
 
  private function isAlive(val:Boolean):void
  {
   //trace("Button status change");
   var rOffset:Number;
   var gOffset:Number;
            var bOffset:Number;
   if(val) {
             rOffset = 0;
             gOffset = 0;
             bOffset = 0;
   } else {
    rOffset = -125;
             gOffset = -125;
             bOffset = -125;
   }  
   btnTarget.transform.colorTransform = new ColorTransform(1, 1, 1, 1, rOffset, gOffset, bOffset);
  }
 
  private function make_toggle():void
  {
   btnTarget.removeEventListener(MouseEvent.MOUSE_OVER, over_listener);
   btnTarget.removeEventListener(MouseEvent.MOUSE_OUT, out_listener);
   btnTarget.removeEventListener(MouseEvent.MOUSE_UP, up_listener);
   btnTarget.removeEventListener(MouseEvent.MOUSE_DOWN, down_listener);
   
   btnTarget.addEventListener(MouseEvent.CLICK, toggle_listener);
   _toggled = false;
   
   var tgFormat = new TextFormat();
   tgFormat.bold = false;
   tgFormat.color = 0x777777;
   
   lbButton.setTextFormat(tgFormat);
  }
 
  private function toggle_listener(evt:MouseEvent):void
  {
   var tgFormat = new TextFormat();
   if(_toggled) {
    _toggled = false;
    tgFormat.bold = false;
    tgFormat.color = 0x777777;
    dispatchEvent(new MouseEvent("customOFF", evt.bubbles, evt.cancelable, evt.localX, evt.localY, evt.relatedObject, evt.ctrlKey, evt.altKey, evt.shiftKey, evt.buttonDown, evt.delta));
   } else {
    _toggled = true;
    tgFormat.bold = true;
    tgFormat.color = 0xFFFF00;
    dispatchEvent(new MouseEvent("customON", evt.bubbles, evt.cancelable, evt.localX, evt.localY, evt.relatedObject, evt.ctrlKey, evt.altKey, evt.shiftKey, evt.buttonDown, evt.delta));
   }
   lbButton.setTextFormat(tgFormat);
   //trace(_toggled);
  }
 }
}

한번 만들어봤습니다만.

3.0 에서는 굳이 이런식으로 만들 필요 없이 걍 SimpleButton 클래스를 사용하면 될 것 같습니다 -_-

그래도... 요녀석의 장점이라면... 그냥 쓰면 임의대로 Sprite 에서 버튼 모양을 그려준다는 겁니다.
그 버튼의 색도 지정할 수 있구요..
토글식으로 만들어 줄 수도 있습니다.
이경우에는 이벤트 리스너를 걸어줄 때 "customON", "customOFF" 라는 식으로 문자로 걸어주는거죠
뭐 저런건 걍 스태틱 클래스로 모아서 만들어줘도 됩니다만, 아직 제 라이브러리가 없어서 그냥 씁니다 ㅎ

사용법은 간단합니다.
import CustomButton.CustomButton;
// 우선은 Import 를 해줘야겠지요
// package 는 customUI.CustomButton 이지만.. 마음껏 수정하셔도 됩니당
var buttonInstance:CustomButton = new CustomButton(null, 0x000000);
// 앞에는 버튼이 될 무비클립, 요기서 아무것도 지정을 안해주면(null) 임의로 그려줍니다.
// 뒤에는 임의로 그려줄때 버튼의 색으로 쓸 uint 값 그냥 웹컬러 코드에 0x 붙는 시츄 -_-
buttonInstance.activate()
// 버튼 활성화를 해줘야 합니다.
buttonInstance.destroy()
// 버튼 비활성화 메서드
buttonInstance.setToggle(true)
// true, false 로 토글 버튼으로 쓸건지 말건지 정해줍니다


일단 동작은 잘 합니다.
충분한 테스트를 거치치 않은 미완성이긴 하지만... 공부겸 해서 올려둡니다.
,
공부놀이/ActionScripT 2007. 10. 16. 11:47

[3.0] Depth 처리

액션스크립트 3.0 에서는 기존의 액션스크립트 2.0 및 1.0 에서 사용하던
Stage 및 MovieClip 의 구조와 체계가 달라졌습니다.
그래서 Depth 관리 방식도 기존과는 많이 달라졌지요.
 
3.0 에서는 모든 MovieClip 뿐 아니라 Shape, 혹은 새로 생긴 Sprite 등등이 모두 DisplayObject 를 상속하며, 트리구조로 Stage 에(정확히는 DisplayObjectContainer에) 들어가게 됩니다.

뭐 E4X 의 Event 방식을 따르기 위해서 그리 되었는지는 모르겠지만, 관리면에 있어서는 한결 편해진듯 싶군요.

그러한 연유로 3.0 에서는 swapDepths와 getNextHighestDepth() 가 사라져 버렸습니다.
그 MovieClip 혹은 Shape, Sprite 가 언제 생성되었던 간에
addChild 메서드를 사용해서 Stage 에 발라주는 순서에 따라서 위아래가 바뀌게 됩니다.
먼저 addChild 한 녀석이 아래쪽에 붙게 되지요.

하지만 우리가 DisplayObject(MovieClip, Shape, Sprite) 를 사용하다 보면 아래에 있던 녀석을 위로 올린다던가 하는 처리가 필요할 경우가 생기기 마련입니다.

그래서 3.0 에서는 Depth를 처리하기 위해서 몇가지의 메서드를 제공합니다.
그중에서 setChildIndex 만 사용해도 쉽사리 Depth 를 바꿀 수 있습니다.
그러나 2.0 에서 쓰듯이 아무렇게나 Depth 를 지정해서 사용할 수는 없지요

예를 들자면 Stage 에는 TargetName 이라는 녀석을 포함한 DisplayObject 들이 세개정도가 있다고 하면,
setChildIndex(TargetName, 1000000)
이런식으로는 안된다는 겁니다.

그래서 간절해지는 녀석은 2.0 시절의 getNextHighestDepth 인데... 사라지고 없는 녀석입니다.

하지만 역시 또 제공되는 녀석이 있지요.
3.0 에서 새로 생긴 녀석인 Sprite에서 numChildren을 읽어올 수 있습니다.

이녀석은 자신의 자식 객체수를 담고 있습니다. (트리구조를 이루고 있으니까요)
물론 읽기 전용 변수로서 임의대로 갱신할 수는 없습니다.

getNextHighestDepth 처럼 최상위 Depth를 구하기 위해서는 저 변수에 -1 을 해주면 해당 객체의 자식들 중 최상위의 Depth 를 구할 수 있는 것이지요.

그렇게 최상위 위치를 구해서 SetChildIndex 를 해주면, 이전의 위치가 비어버리는것도 아니고,
기존 위치에 있던 녀석이 사라지는것도 아닙니다. 자동으로 Depth 들이 재조정 됩니다.
일일이 신경써줄 필요가 없어지는 거지요.

MovieClip 이나 Sprite 등 DisplayObject 에 대해서는 나중에 따로 다루도록 하지요~~
,
공부놀이/ActionScripT 2007. 2. 28. 04:33

[2.0] 플래시 타임라인, 다이나믹, 리버스 뎁스 관련

Zones of Depth

In specifying depths for your objects, you need to be aware of the three "zones" in the ranges of valid depth values in Flash. Depths themselves, for visual objects, cannot be less than -16,384 or greater than 2,130,690,045 (there is an exception for createEmptyMovieClip). Indeed, unusual numbers, but those are the acceptable values for an object's depth. No depth will be outside of this range and, as you can see, Flash starts with the lowest part of that range when adding objects to the screen when reading the timeline. Now, within that range there are more or less 3 other ranges. One is the range that Flash uses to handle the timeline, that being from depths -16,384 to -1. Following that is the range, 0 to 1,048,575, the range that specifies the depths at which a movieclip or textfield can be removed with removeMovieClip() or removeTextField(), something not possible within the depths of the previous range. After that range, and going to the end, 1,048,576 to 2,130,690,04, is a kind of reserve range where movieclips can be placed by you, but can't be removed. Respectively I call these ranges, or zones, timeline, dynamic and reserve:

Zone Range Note
 Timeline  -16,384 to -1 handled by timeline with Flash, dynamic removal disabled
 Dynamic  0 to 1,048,575 most dynamically accessible, allows dynamic removal
 Reserve  1,048,576 to 2,130,690,045 overflow - ignored by timeline, dynamic removal disabled

The timeline zone of depths is where Flash handles timeline placed instances, working from around -16384 up giving plenty of depths before reaching the dynamic zone at depth 0. These are all based on arrangement specified in the Flash authoring environment. The very low starting depth mentioned before, where the lowest clips in the Flash authoring environment are first placed, starts at around this lowest depth of -16,384 (usually -16,383). From there it places objects in sequentially higher depths until all of the objects on the timeline are accounted for. Since there are only 16,000 instances allowed on the screen at one time in Flash, that gives plenty of depths for Flash to handle those timeline instances. Now, there's a little more involved here, but we'll touch upon that a bit later.

Next is the dynamic zone. This represents the range in which most dynamic instances would be, ideally, created. After all, intuitively, if Flash asks you to give a depth for an attached movieclip, you would consider some reasonable positive number value and nothing negative or anything too terribly high such as anything above 1,048,575. This doesn't mean that any object created dynamically on the screen has to be within this range. It's just the supposed range for these clips to exists since it is only within this range, and this is the important part, that you are allowed to remove instances with actionscript. Dynamically created instances, however, can be initially attached within any valid depth within any of the 3 zones. Should you want to remove them, however, you would want to place them here. And if not, then you would have to use swapDepths to place them within this zone to remove them. Note, this is valid for instances placed on the timeline as well. Though you may not initially be able to remove any movieclip you place on the timeline in the Flash authoring environment, should you use swapDepths to place that clip in the Dynamic zone, you are then able to remove it with removeMovieClip.

The reserve zone kind of makes up what's left. Its basically just an extension of the dynamic zone with removal disabled. Objects can be created there or swapped to a depth within that zone using swapDepths, but it deems itself unorthodox in that there is no ability for removal and that the simple value of the depth seems ridiculously high. Nevertheless, this allows 2,129,641,470 more values of depths to work with when arranging your objects on the screen through actionscript giving you a lot of room for playing around.

// swap to an arbitrary depth within removable range
my_mc.swapDepths(10000);
// no ok to remove, no matter how it was created or where
my_mc.removeMovieClip();

The exception to this set of ranges is for the createEmptyMovieClip method. There is no real limit for the depth when creating an empty movieclip. You can very well define it with a depth below -99999999999 or above 999999999999 and Flash will still create the empty clip despite the fact its out of the 3 valid zone's ranges. The depth of such an empty clip, however, when set beyond 2147483647 on the positive side and -2147483648 on the negative, it will start to fluctuate from what you truly set it, sometimes even being negative if set at positive and vise versa. You never can tell. It seems as though this is the absolute range for timeline instances, -2147483647 to -2147483648, though really only fully attainable through empty movieclips. Other clips, such as those within the timeline or created with something like attachMovie are restricted to the depths of -16,384 to 2,130,690,045 as laid out in the 3 zones.

The Timeline Refresh

Lets go back to the timeline zone for a moment. There is something that happens within that range that can cause a lot of confusion when toying with the depths of clips there, both dynamic and those placed in the timeline. What happens is, whenever the timeline is "refreshed" and all of the instances are redrawn, Flash actually goes through the depths in the timeline zone and removes all of the clips which exist within those depths, whether they were created there through their existence on the timeline or dynamically with actionscript. Flash then redraws the screen for those depths based on the information within the timeline disregarding any movieclips that might have been placed in those depths through dynamic means. An example of this kind of refreshing is caused by using gotoAndPlay to go to a frame which has already passed; going to frame 5 from frame 10 for example. When this happens, Flash does this refresh allowing it to correctly display the screen at this new frame as the progression of the timeline has diverted from normal playback and therefore must be completely re-conceived by Flash.

Obviously, this can cause several problems. One being the obvious of you losing any dynamically place instances within that range during a refresh of this sort, placed there either during their creation or as a result of swapDepths. What can you do? Well, you can not put dynamic instances in that range for one. Alternatively, if you know that you wont run into a situation where something like that will occur, say a controlled movieclip consisting of only one stopped frame, then it can be pretty safe to have clips within the range of the timeline zone with minimal worry.

Another problem, which may not be so obvious, is that concerning depth-swapped timeline instances. If you use swapDepths to bring a movieclip which was placed on the timeline in Flash out of the timeline zone and into a depth above 0, then in a timeline refresh, that clip will not be removed in Flash's clearing of the timeline instances and a new instance of that clip will be placed on the screen at its original depth, effectively duplicating it. Similarly, to avoid this, don't do it. Again, its safe in controlled timelines, but otherwise, its risky. Something to be aware of nonetheless.

Kind of along those same lines is the progression of the Flash timeline from one scene to another. This does not constitute a timeline refresh, nor, really, any other particularly special event. Scenes themselves are only slices of the main timeline which, when the Flash movie is published, get added on to one another as one big, single main timeline. Because of this, any dynamic instance you create (or any instance swapped above 0 depth) in one scene will be present in any other scene as the timeline plays through them. If you would not like this to happen, then you would need to use removeMovieClip/removeTextField to get rid of them at the end of the scene which they were placed.

Execution Order

Another somewhat overlooked role in depths is their influence in determining execution order of ActionScript. Actually, the depths themselves don't necessarily affect execution order but rather the order in which instances are created does. However, since movieclips are created in the order relating to their arrangement (depth) on the screen, there is that connection, at least in terms of the timeline. In regards to actionscript, its more a matter of the order in which you create any of those instances that you decide to make. Those you create first (these in the same timeline) will have their script run before those you create afterwards. Otherwise, the Flash authoring environment decides the order of execution based on arrangement or order created. Oddly enough, for instances on the timeline, those created last are those who's enterFrame event scripts get run first.

By default, instances are created from the timeline starting with the lowest layer upward. This is at the Bottom Up load order setting in you Publish Settings options. You have two options for load order, Bottom Up and Top Down, both which control the order in which layers are created within Flash. Frame scripts in these layers are run in the order they are created, so in a Bottom Up situation, any scripts on lower layers would be technically run first. However, as mentioned, enterFrame events are opposite that -and this includes both onEnterFrame and onClipEvent(enterFrame). In a Top Down situation, the opposite is true. So, with the default Bottom Up setting, assuming you have two movieclips on your timeline, one in a high layer 1 and the other in a lower layer 2, if both contain an onEnterFrame event as well as some script in the first frame of their timeline, then the movieclip in the lower layer will first have its timeline script run followed by the timeline script of the movieclip on the higher layer. Then the enterFrame event of the clip in the higher layer will run followed by that corresponding to the lower layer. Note, however, that script order within

'공부놀이 > ActionScripT' 카테고리의 다른 글

[3.0] 커스텀 버튼 클래스  (0) 2007.10.24
[3.0] Depth 처리  (0) 2007.10.16
[2.0] 플래시 웹페이지 포커스  (0) 2007.02.28
,
TOTAL TODAY