매출이 떨어진다면「UI를 바꿔라!」

User Interface/Etc 2007. 2. 21. 11:14

인터넷 기업이 매출을 올리는 방법은 많은 사람들을 끌어들이는 것이다. 그리고 이들에게 유용한 정보를 쉽게 전달함으로써 상품을 판매하거나 광고 매출을 올리게 된다. 정보를 쉽게 전달한다는 것은 콘텐츠에 대한 접근성을 높이는 것으로 유저 인터페이스(UI)의 중요성은 재차 언급할 필요가 없다.

보다폰이 중, 장년층을 겨냥해 내놓은 심플리의 성공요인은 다양한 부가서비스를 생략하고 통화기능을 내세운 것, 그리고 디스플레이 가독성을 강화한 것이다. 특히 이 제품의 액정에는 어떠한 아이콘도 없고 텍스트만이 보일 뿐이다. 보다폰은 심플리의 성공적인 UI로 45세 전후 고객들의 마음을 사로잡았으며 유럽에서 선풍적인 인기를 끌며 실버폰 열풍을 확산시킨 바 있다.

또 하나 해외의 사례를 들면, 오래된 건물을 인수해 백화점으로 개조한 한 회사는 엘리베이터가 한 개 밖에 없어 고객들로부터 끊임없는 불만을 들어왔다. 건물구조상 추가로 엘리베이터 설치는 불가능했지만, 고심 끝에 적은 비용을 들여 고객들의 불만을 일순간 잠재울 수 있었다. 주변에 수많은 거울을 설치함으로써 고객들의 주위를 분산시킨 것이 해답이었다. 물리적으로 불가능한 것을 심리적으로 해결한 것이다.

위 사례와 같이, 인터넷 기업의 웹사이트 역시 가독성 강화와 심리적인 부분을 십분 활용한 UI를 개발하는 것이 매출을 증대시키는 기본 요인이 될 것이다.

우수한 UI는 인간 심리와 4관에 충실해야

지난 20일 랭키닷컴이 개최한 ‘유저 스페이스 컨퍼런스 2006’에서 경희대학교 커뮤니케이션연구소 소장인 김태용 교수는 웹사이트에서 UI의 중요성에 대해 설명했다.

UI개발 프로세스에서 중요한 것은 시스템(웹사이트)에 대한 개발자의 인식과 이를 사용하는 사용자의 일치하는 정도인 ‘객관적 일치도’를 비롯해 ‘주관적 일치도’와 ‘정확도’ 등 사용자와 개발자의 상호지향성이다. 즉, 편지봉투 모양의 메일 아이콘에 대해 누구나가 ‘저건 메일이구나’라고 생각이 일치하는 데에서 UI설계가 시작된다는 것이다.

김태용 교수는 “우수한 UI를 만들기 위해서는 직관, 객관, 일관, 미관 등 ‘4관법’만 잘하면 된다. 어떤 서비스나 제품에 대한 사용설명서는 직관, 객관, 일관적이지 못하다는 잘못에 대해 사용자에게 용서를 구하는 사과문이다”라고 말했다.

여기서 말하는 4관은 ▲ 직관 : 학습 없이 짐작으로 통하는 UI가 가장 우수한 것이다. ▲ 객관 : 널리 통용돼 설명이 필요 없는 UI ▲ 일관 : 시스템 내부적으로 일관성이 확보된 UI, 잦은 변화로 매번 학습이 필요한 UI는 좋지 않음 ▲ 미관 : 같은 구조라면 아름다운 UI 등 네 가지이다.

또한 우수한 UI는 인간의 심리를 이용해서 만들어 졌을 때 큰 효과를 발휘할 수 있다. 웹사이트를 새로 만들거나 개편할 경우, 콘텐츠 구성과 사이트 맵 설계에 앞서 심리적/생물학적인 인간의 본성을 이해하는 것이 중요하다.

시각적 원리를 이용해 콘텐츠 배치

인간의 본성을 이용한 UI 설계는 인터넷 사이트의 특성 상, 시각의 원리를 이용하는 것이 기본이 된다. 포털 사이트들이 강조하고자 하는 콘텐츠를 좌측 상단이나 가운데 상단에 배치하는 것도 이러한 본성을 활용한 것이다.

실제 포털 사이트들의 검색 광고는 상단이냐 아니냐에 따라 광고비에 큰 차이가 있으며, 쇼핑몰의 경우도 주요 이벤트를 상단 가운데 자리에 위치시키고 판매자에게 더 많은 수수료를 챙기기도 한다.

인터넷 브라우저 상에서 상하, 좌우의 특정 지점에 대한 시각 반응을 분석해 보면, ▲ 좌우 양 지점에 대한 첫 응시율(사용자가 바라보는 비중)은 왼쪽 73%, 오른쪽 27%이다. ▲ 상하의 첫 응시율은 위쪽 69%, 아래쪽 23%로 조사됐다. ▲ 그리고 좌우에 상관없이 대각선으로 양쪽 지점을 잡더라도 아래쪽보다는 위쪽이 월등하게 높은 응시율을 나타냈다.

이러한 패턴을 종합한 결과 인간이 브라우저를 바라보는 본능적인 시선의 움직임에 가장 적합한 사이트 구성은 첫 번째 좌측 상단에서 시작해 우측으로 진행해 내려오는 ‘시계방향” 구성이 가장 뛰어나며, 가운데 상단에서 시작해 다시 왼쪽으로 갔다가 시계방향으로 보는 구성이 두 번째라는 것이 김교수의 설명이다.

‘감’ 보다 ‘과학’

콘텐츠 위치, 구성이 곧 매출과 직결되는 인터넷 사이트에서는 사용자(고객)과의 접점인 초기화면 UI가 무엇보다 중요하다. 장기적으로, 우수한 UI가 반영된 웹사이트로의 개편 여부에 따라 기업의 매출이 큰 폭으로 변할 수도 있는 것이다.

때문에 대형 사이트들은 이미 UI에 대한 중요성을 인식하고 내부조직을 갖추고 있다. 일례로 네이버는 100명이 넘는 UX(User Experience)센터를 운영하고 있으며, 다음은 주요 서비스 별로 UI조직을 운영하는 동시에 신규서비스 론칭에 따라 TFT를 운영하고 있다.

네이버의 한 관계자는 “사이트 개편 등 변화가 생길 때면 수십 명의 이용자를 대상으로 수차례 테스트를 진행한다. UI가 조금만 바뀌어도 클릭 수에 엄청난 변화를 보이기 때문에 감이 아닌 과학적이고 체계적인 운영이 반드시 필요하다”고 말했다.

동서리서치 UI LAB에서 조사한 결과, 인터넷 중앙일보(조인스닷컴)과 조선일보의 헤드라인 가독성 면에서 좌측상단에 위치한 중앙일보보다 가운데 상단에 위치한 조선일보가 더 뛰어나다는 내용도 있듯이, 반드시 위에 설명한 이론이 정확한 것은 아니다.

그렇지만 UI는 인터넷 기업 매출 활동의 최전방 접점이라는 점에서 체계적(Systematic)으로 만들어 놓아야 할 것이다. 이제는 단순히 디자이너에 의존하기 보다, 모든 구성요소를 포괄하는 하나의 총체적 시스템으로 기획해야 하고, UI 관련 직무분석에 따른 프로세스 정립도 필요하다.

또한 기존 오프라인 광고나 PR 분야에서 이루어 지던 ROI 평가처럼, UI 개편에 따른 ROI 평가/분석 체계의 수립도 요구돼야 할 때이다. @


출처 : 김효정 기자 ( ZDNet Korea )

    

설정

트랙백

댓글

SKT 유저인터페이스(UI), 'T스타일'로 간다

User Interface/Mobile 2007. 2. 21. 11:13

SK텔레콤이 향후 선보일 표준 UI에 올해 새롭게 런칭한 브랜드인 ‘T’를 적극 반영할 예정이다. SK텔레콤은 28일 T타워 수팩스홀에서 ‘표준 UI 3.0 2차 설명회’를 갖고 “향후 출시될 표준 UI 3.0은 T스타일 인턴페이스가 될 것”이라고 밝혔다.

사용자 삽입 이미지

▲ 표준 UI 3.0에 대해 설명하고 있는 SKT 조영삼 매니저ⓒK모바일

사용자 삽입 이미지

▲ SKT 표준 UI 3.0 설명회 모습 ⓒK모바일

‘T’는 SK텔레콤의 새로운 이동통신 통합브랜드로 올해 8월부터 선보이기 시작했다. 브랜드 런칭 당시 SK텔레콤은 향후 모든 이동통신 서비스와 기존 브랜드을 단계적으로 ‘T’로 통합한다고 밝힌바 있다. SK텔레콤이 현재 준비하고 있는 표준 UI도 ‘T’브랜드의 전략을 따르고 있는 것.

SK텔레콤이 말하고 있는 T스타일 인터페이스를 간단히 정의하면, GUI와 AUI를 통해 단말기에서 제공되는 서비스의 경험을 T브랜드로 느끼게 한다는 것이다. T스타일 인터페이스 기반의 GUI와 AUI는 SK텔레콤의 단말, 서비스 임베디드 메뉴, 임베디드 어플리케이션에 적용되어 사용자가 단말을 On해서 Off하는 순간까지 T브랜드가 추구하는 가치(세련된/전문가적인, 고품질/자부심, 기술혁신/이동통신리더)를 경험하게 된다.

사용자 삽입 이미지

▲ T스타일 UI화면 ⓒK모바일

이를 위해 SK텔레콤 전 단말의 전원On/Off 애니메이션, 송/수신 콜 애니메이션 등도 T스타일 인터페이스로 적용될 예상이다. 또한 이 인터페이스에 기반한 T스타일폰이 내년 상반기 중 출시될 예정으로 현재 단말제조사와 개발에 들어간 상태이다.

T스타일 인터페이스 하에서 기존 UI와 가장 큰 차별점이라고 하면 바로 'OK키'의 사용이다. 향후 SK텔레콤의 전 단말 및 어플리케이션, 서비스는 해당 항목을 선택 및 주요 순방향 기능키로 ‘OK키’를 사용하게 된다. 현재 ‘네이트 키’가 ‘네이트/OK 키’로 사용될 예정이며 ;‘확인 키’와의 혼동을 줄이기 위해 소프트키 레이블 또한 ‘OK'로 바뀌게 된다.

문자입력 시 특수문자를 사용하기 위해 입력모드를 전환하는 방식도 변경된다. 입력모드 전환을 F2키로 통일 기존의 팟업방식이 아닌 토글방식으로 한글, 기호, 숫자, 영소, 영대, 순으로 변경되게 된다. 이외에 숫자키를 길게 누르면 숫자가 입력되는 방식등도 고려되고 있다. UI 바탕화면 색상은 단말기에 따라 달라질 가능성이 있다. 즉 단말기 색상이 블랙이면 UI의 배경 팔렛트 색상역시 블랙 톤을 뛰며, 단말기가 흰색이면 배경역시 흰색으로 제공될 예정이다.

SK텔레콤은 현재 T스타일 인터페이스를 적용한 표준 UI 3.0을 통해 Accessibility, Consistency, User Support, Identity 등의 UI개선 핵심 속성을 도출할 예정이며 내년 중/하반기 경에 단말기에 적용할 계획이다.


출처 : K모바일  조정형 기자  focus@kmobile.co.kr
    

설정

트랙백

댓글

휴대폰의 진화

Design/Mobile 2007. 2. 21. 11:12
휴대전화는 끊임없이 진화해왔다. 치열한 휴대전화 업계의 특성상 성능 면에서. 디자인 면에서 유행을 선도하지 않으면 존재의 위협을 받기 때문에 변화 속도는 빠르다.

기능적으로는 단순 통화기능에서 MP3도 추가되고 카메라도 들어가고 이제는 TV까지 소화해낸다. 간혹 EVDO 방식으로 연결하여 무선 인터넷기능까지…. 세세하게 추가된 기능을 설명하자면 끝도 없다. 몇 년 전부터 외쳐왔던 유비쿼터스 시대가 조만간 도래할 듯 하다.

디자인 면에서 살펴보면 무전기같던 플립에서 심플한 플립으로 그리고 폴더로. 스윙폰. 가로 LCD. LCD를 뒤집고 돌리고 꺾고. 이제는 지갑 안에 들어갈 카드형까지 나왔다. 기능에 맞춰서 크기가 커졌다 줄었다 하더니만 확실히 가벼워졌다.

그럼 다음은 무엇일까?
사진은 컨셉트폰으로 얼마전에 발표된 디자인이다.
전면 LCD폰인 Nokia의 ‘aeon’. 두개의 LCD로 이뤄어졌으며 유일한 키 버튼은 가운데 가로 바.

또 하나는 BenQ-Siemens의 ‘black-box’. BenQ-Siemens는 얼마 전 부도로 인해 신제품이 실제로 발표되기는 힘들겠다. 터치스크린 방식이기 때문에 키에 익숙한 사용자들에게는 좀 불편하겠지만 뭐 나름대로 적응하고 살지 않을까?
아~ 아시는가? 휴대전화 가격을 결정짓는 것 중에 LCD가격이 가장 비중이 크다. 전면 LCD에 터치스크린이라면 가격이 만만치 않겠군. 물론 컨셉트폰의 특성상 생산이 안될 수도 있다는거~.

출처 : 송동욱 [nalso.egloos.com/]

사용자 삽입 이미지


    

설정

트랙백

댓글

버튼 없는 엘리베이터, "편리하네"

User Interface/Etc 2007. 2. 21. 11:12

사용자 삽입 이미지





















엘리베이터 탑승 시간을 획기적으로 줄인 엘리베이터가 뉴욕 맨해튼의 고층 오피스 건물들을 중심으로 확산되고 있다고 월스트리트저널이 14일 보도했다.

뉴욕 매리어트 마르퀴스 호텔과 뉴스코 본사, 허스트 본사 건물 등에 있는 이 엘리베이터의 특징은 엘리베이터 안에 버튼이 없다는 점이다.

대신 각 층 마다 있는 키패드에 자신이 원하는 층수를 입력한 후 키패드가 지정하는 엘리베이터를 타도록 돼 있다.

이럴 경우 같은 층에 가는 이용자들을 분류할 수 있기 때문에 매 층마다 서는 불편이 줄고 자동적으로 운행시간도 줄게 된다.

도입 초기에는 작동법을 몰라 당황하는 사람들이 적지 않았지만 적응하고 나면 오히려 짧아진 대기, 운영 시간에 흡족해 한다는 것이 제조사인 쉰들러엘리베이터사의 설명이다.

타임스퀘어 있는 매리어트 마르퀴스 호텔은 객실이 2000실에 달해 엘리베이터가 항상 혼잡을 빚었지만 도입 후 고객들이 만족하고 있다.

루퍼트 머독 뉴스코 회장도 이 새로운 엘리베이터에 대해 "처음에는 어떻게 해야 하는 지 몰라 혼란스러웠지만 지금은 아파트에 있는 엘리베이터의 버튼을 누르지 않아 당황할 정도로 익숙해졌고 시스템에 만족한다"고 말했다.


<저작권자 © ‘돈이 보이는 리얼타임 뉴스’ 머니투데이>

    

설정

트랙백

댓글

HCI(Human Computer Interaction)의 미래...

User Interface/Etc 2007. 2. 21. 11:11

미래를 엿볼수 있는 영화

영화 마이너리티 리포트의 주무대인 워싱턴 D.C.의 2054년 모습을 그리기 위해 스티븐 스필버그 감독을 비롯한 제작진은 1999년 4월, Think Tank를 구성했다고 한다. 이 Think Tank 내에서 제작진과 저명한‘미래학자’들이 도시 경관에서부터 미래 무기에 이르는 다양한 주제에 대해 머리를 맞대고 연구하여 철저한 과학적 지식에 근거한 영화 제작을 시도한 것이다.

영화 속의 시간적 배경은 2054년으로 설정되어 있지만, 영화 속 미래 사회의 모습은 현재 개발이 진행 중인 과학기술상의 지식을 토대로 하여 그려지고 있다. 예를 들면 영화의 주요한 기술적 배경이 되고 있는 e-Paper(Electronic Paper), 3D 디스플레이 등 차세대 디스플레이 기술, 생체인식 기술, 지능형 교통시스템(ITS : Intelligent Transport System) 기술 등은 현재에도 활발한 연구활동이 이루어지고 있다.

영화에 등장하는 다음 기술들에 유의하며 영화를 감상하도록 하자.

1. 미래 기술 관점

1) 미래의 컴퓨터

수사관인 존 앤더튼(톰 크루즈 분)은 유리(Glass) 컴퓨터, 유리 디스켓에 촉각 디스플레이 장갑(Haptic Glove)을 끼고 제스처로 파일들을 처리한다. 이때 장갑에서는 빛이 발광하는데, 아마도 발광다이오드의 촉각 장갑처럼 보인다. 이때의 빛은 바로 네트워킹으로 광자(Photon) 베이스의 빛을 이용한 네트워킹으로 발전할 가능성이 높다. 미래의 컴퓨터는 이처럼 현존의 LCD/PDP가 더욱 혁신을 거듭하여 (1) Liquid Metal 베이스의 유리 컴퓨터나 (2) 아니면 플라스틱 베이스의 FOELD, LEPD로 진화할 것으로 보인다.

2) e-Paper 기술

영화에서 주인공인 존이 당국의 추적을 피해 지하철 속으로 숨어 드는 장면이 나온다. 지하철 승객들 중 일부가 신문을 보고 있는데, 이 신문이 바로 e-Paper 기술이 상용화된 제품이다. 영화 장면을 유심히 살펴보면 신문의 내용이 실시간으로 전송되는 정보로 업데이트 되며 심지어는 동영상까지 나타난다. 이미 지명수배자가 된 주인공은 결국 신문을 통해 정체가 드러나 다시 도주할 수 밖에 없게 된다.

3) 멀티모달(Multimodal) HI(Human Interface)의 기술

이 영화에 등장하는 홍채인식(Iris Recognition, or Eye Scanning) 기술은 음성인식, 지문인식, 얼굴인식, 서명인식, 유전자인식 등의 기술과 비교해볼 때, 그리고 오감 중 인간의 시각이 의사결정에 87% 영향을 미친다는 사실을 고려해볼 때 과연 영화에서처럼 상용화되어 일반화 될 것인가? 유비쿼터스 환경의 중요한 부분을 차지하는 생체인식 기술의 혁신과 확산에 대해 생각해보자.

4) 생체 인식 시스템

영화 속의 주요 건물이나 거리, 지하철 역 등에는 홍채나 망막 등 인간의 안구로부터 정보를 추출해내는 생체 인식 시스템이 설치되어 개인정보를 분석해낸다. 또한 생체 인식 로봇은 돌아다니면서 시민들의 신원을 파악하기도 한다. 이러한 생체 인식 시스템은 범죄 용의자 색출은 물론 일대일 마케팅 등 상업적으로도 응용될 수 있다. 영화에서 주인공이 백화점을 지나갈 때 백화점 내에 설치되어 있는 생체 인식기가 주인공을 개별적으로 식별한 후 직접 이름을 호명하면서 일대일 광고를 내 보내는 장면이 나타나는데, 이것이 상업적 응용의 한 예가 될 수 있다. 생체 인식 시스템의 비즈니스 모델에의 응용에 대해 생각해 보자.

5). Wrist Watch

John 수사관의 Personal Solution의 핵심제품은 Wrist Watch 이다. 2003년 9월에 등장하는 Microsoft 사의 Wristwatch, 그리고 일본의 NTT DoCoMo와 Seiko가 2003년 5월 7일 출시한 Wristtomo가 대표적인데, Wristtomo는 2003년 7월 1일 현재 없어서 못 파는 제품이 되고 있다. 원래 1,000대 목표였으나 지금까지 3,850대가 팔렸고 따라서 올해 판매대수를 10,000대로 늘려 잡았다. 미래의 PDA가 이러한 마이크로 손목시계로 컨버징 된다면 우리는 이에 대해 어떻게 대비해야 하는가?

6) 유비쿼터스 혁명(Ubiquitous Revolution)

Minority Report에 등장하는 미래 전략 사업은 유비쿼터스 혁명(Ubiquitous Revolution)으로 요약할 수 있다. 미래의 u-교통, u-Telematics, u-도로, u-식물원, u-경찰, u-Wearable Computer 등이 등장하는데, 본과정의 학습과 연구를 통해 유비쿼터스 환경하의 미래 사업에는 어떠한 것들이 있는지, 그 요소 기술과 비즈니스 모델에 대해 생각해보자.

7) 최첨단의 지능형 교통시스템(ITS)

영화 속에서는 자기역학을 응용한 자동차가 마치 스파이더맨처럼 빌딩 벽을 오르내리고, 도로 상에는 자동차들이 매우 근접한 상태에서 빠른 속도로 달린다. 물론 자기역학을 응용한 미래형 자동차는 아직 먼 얘기가 될 수 있다. 그러나 차간 거리를 최소화한 상태에서 고속 주행이 가능하게끔 하는 시스템인 ITS는 상용화가 근접한 기술 중 하나이다. ITS에 관련된 기술과 비즈니스에 어떻게 접근할 것인가?

8) 미래의 무기-충격 음파총

주인공이 추격하는 경찰들에게 제압용 총을 쏘는 장면이 나온다. 이 총은 충격음파를 이용하는 것이다.주인공 존 앤더튼(톰 크루즈 분)은 인지자들이 자신을 미래 살인자로 지목하면서 동료들로부터 쫓기는 신세가 된다. 이 과정에서 미래의 경찰이 사용하는 총은 살상용이 아닌 제압용 충격 음파총이다. 자동차 조립공장에서 앤더튼은 이 총을 뺏어 추적하는 경찰들에게 쏜다. 그러자 이 충격음파에 맞은 경찰들은 두 팔을 벌린 채 뒤로 나가떨어진 후 정신을 못 차린다. 충격 음파총은 고강도 음탄(sonic bullet)을 발사해 비행기 납치범을 무력화할 목적으로 미국 캘리포니아에 위치한 아메리칸 테크놀로지스사에서 2001년부터 개발되고 있다. 이 무기는 비행기 기체와 창문을 파괴하지 않고 비행기 납치범에게 일시적으로 극심한 통증을 유발하며 방향감각을 잃게 한다. 국방이나 군사 관련 솔루션은 큰 시장이므로 어떠한 것이 있는지 생각해보자.

기타 홀로그램, 홀로그래픽, 인공지능 베이스의 로봇, 과학/군사용 생물체 로봇 등 기능적 감성, 감각적 감성, 사회적 감성, 문화적 감성을 창출해내는 미래의 기술들을 Minority Report에서 파악해보자.

그 밖에 잘 드러나지는 않지만 마이너리티 리포트가 그려내는 미래 사회는 차세대 초고속, 광대역 통신 인프라의 구축을 기반으로 하고 있다. 또 무선 네트워킹 기술이 활용되는 장면도 부분적으로 나타나는 등 차세대 정보통신기술의 상용화도 예견해내고 있다.

그 대표적인 인프라 기반이 그리드이다.
2. 브로드밴드 네트워크 인프라 관점

다음의 네트워크 인프라 관점의 질문에 대한 해답을 생각하며 영화를 보도록 하자.

1) 영화 마이너리티 리포트에서는 곳곳에서 그리드의 존재를 볼 수 있다. 이 때문에 주인공은 개별 맞춤형 광고의 홍수 속에서 살고 경찰이 워싱턴 D.C. 근처의 그물처럼 얽힌 자동화 고속도로에서도 주인공의 차를 찾아낸다. 가상의 세일즈 맨이 주인공 톰 크루즈를 스캔해 그가 최근 구매했던 옷과 어울릴만한 아이템을 추천해 주는 장면도 등장한다. 마이너리티 리포트에 등장하는 이러한 그리드와 매트릭스의 AI(인공지능)의 공통점은 무엇인가? 2054년의 마이너리티 리포트의 그리드가 2199년의 매트릭스로 진화할 수 있을 것인가?

2) 사물과 사람에 이식된 스마트 칩과 무선기술이 통합되면 모든 것이 변하게 될 것이다. 체내에 이식되는 바이오칩은 무선기술과 통합되면 모든 것이 변하게 될 것이다. 체내에 이식되는 바이오 칩은 그리드를 통해 심장박동 상태를 실시간으로 의사에게 보낼 수 있게 된다. 자동차 메이커는 고객의 차량에 장착된 스마트칩을 이용해 차와 고객의 운전습관까지도 추적할 수 있을 것이다. 고객의 자동차에 대한 디지털화된 정보가 그리드에도 저장돼 이를 통해 정비소는 엔진고장을 발견하고 경찰은 사용자의 과속여부를 확인할 수 있게 될 것이다.

영화 마이너리티 리포트에 등장하는 이러한 시대가 도래하면 빅 브러더에 대한 우려가 현실화 된다. 이것을 해결할 수 잇는 방법은 무엇인가?

3) 그리드는 시큐리티 관련 기술이 상당히 중요하다. 그러나 현재 개발되고 있는 생체인식 기술들은 영화 속에서 큰 허점을 보이기도 한다. 이 영화에서는 홍채인식 기술이 등장하는데 주인공 (톰 크루즈 분)은 그리드를 피하기 위해 암시장에서 안구 이식수술을 받는다, 또한 영화 가타카(GATTACA)에서는 타인의 혈액을 빌려 DNA칩에 의한 보안 검색을 교묘히 피하기도 한다. 현재 개발되고 있는 생체인식 기술의 장단점을 생각해보고 어떤 기술이 가장 효율적인지 생각해보자

4) 그리드가 도입되면 우리가 작동원리도 알지 못하고 전기를 사용하듯 컴퓨터의 기능은 전력 망처럼 눈에 보이지 않게 우리 삶의 일부로 자리잡을 것이다. 또한 컴퓨터의 기능은 그 어느 때보다 복잡해지고 끊임없이 쏟아지는 데이터는 엔지니어들이 감당할 수 없을 정도로 방대해질 것이다. 그러므로 그리드는 스스로 관리하고, 문제점을 진단하고, 보수하는 능력을 갖춰, 이상이 생길 때 우리에게 알려주고 고치는 방법까지 가르쳐 주어야 할 것이다.

이러한 관점에서 IBM이 추진하는 그리드 컴퓨팅과 ANS베이스의 Autonomic Computing에 대해 생각해보자.

5) 매트릭스가 VR(Virtual Reality)의 세계라면 마이너리티리포트는 R(Augmented Reality)의 세계이다. AR과 VR의 차이점은 무엇이며 우리가 추구하는 미래사업은 AR인가, 그렇지 않으면VR인가? AR라면 어떠한 세상을 그려볼 수 있으며 사업의 기회는 무엇인가?

기타 다음의 근본적인 의문에 대해서도 생각해보자.

3. 근본적인 의문

1) Minority Report 는 결국 시스템 에러이다. 시스템이지만 전적으로 인간의 능력에 의존한 시스템이다. 따라서 이 시스템 에러는 결국 Human Error를 의미하는가?

* 미국계 한국인인 제퍼슨 한의 미래형 GUI를 보면 이런 날이 멀지 않았다는 생각이 든다. 물론 지금의 마우스와 키보드의 입력장치에 비해 노동을 많이 해야하는(양 손과 손가락을 이용) 문제점을 어떻게 해결할 것인가를 생각해야 할 듯 싶다.

* 이런 것을 감안해 보면 미래의 두뇌 스포츠로 발전할 수도 있지 않을까 하는 생각이 든다. 질문에 대한 답을 빠른 손동작과 검색 판단 그리고 art 적인 화면 구성 배합 등으로 정보의 정확성, 빠른 판단, 그리고 체력, 미적 감각을 필요로하는 스포츠로 발전 시키면 어떨까 하는 생각도 해본다...

사용자 삽입 이미지

마이너리티 리포트 (Minority Report)

    

설정

트랙백

댓글

UI디자인 가이드라인 - Elements 만들기

User Interface/Web 2007. 2. 21. 11:11

명확한 단계를 요구하는 입력폼
입력폼은 사용자의 정보를 요구하는 화면이므로 사용자들이 가장 민감하게 반응할 수 있고 특히 결재에 관한 입력폼은 금전적인 위험요소도 고려되어 사용자는 과정이나 결과에 대한 확인을 매우 필요해 한다.
해외의 사례를 보면 성질이 같은 덩어리로 단계를 나누고 그 단계마다 화면이 전환되어 사용자가 지금 어느 위치에서 어떤 작업을 하고 있는지를 각 화면마다 정확하게 인지시키는 것을 선호한다는 결론을 도출한 바 있다.
그러나 우리나라의 경우 여러 테스트와 전문가의 분석 결과 조금 다른 사용자의 행태를 발견할 수 있었는데 단계가 시각적으로 명확하게 구분되어 보이되 화면의 길이가 조금 길더라도 한 화면에 보여지는 입력폼의 디자인을 선호하였다.
물론 너무 긴 화면은 지루할 수도 있고 사용자가 포기하거나 힘들어 하는 원인이지만 외국의 사례처럼 서너 줄의 입력폼마다 성격이 다르다는 이유로 화면전환을 하는 것은 우리나라 실정이나 국민성(?)에는 맞지 않는다는 것이 UI 전문가들의 결론이었다.
이러한 결과는 UI 전문가가 여러 번의 테스트를 객관적으로 진행한 산출물이지만 모든 사이트에 적용되는 정답일 수는 없고 사이트와 입력사항의 성격에 따라 달라질 것이다.

결론적으로 화면의 전환 여부는 사용자의 성향에 따라 달라질 수 있으나 입력폼은 가장 명확성이 요구되는 화면이므로 정확히 단계를 나누고 지금 사용자가 어디에서 무엇을 하고 있는지와 얼마나 걸릴 것인지를 여러가지 방법을 이용하여 꼭 명시해야 한다.


마우스오버 만들기
마우스오버를 하지 않을 수 없는 곳은 아무래도 메인 메뉴에 해당하는 네비게이션 바이다. 그러므로 이 곳에 마우스오버를 사용하여 만들 경우가 많을 것이다. 이때 마우스오버 했을 때 서브메뉴링크가 뜨도록 해주면 좋다.

보통 마우스오버를 하면 숨겨있던 이미지나 텍스트가 나온다. 그러나, 숨겨져 있는 정보를 사용자들이 찾아내지 못했을 경우는 어떻게 하겠는가?

사용자가 사용할 마우스의 위치를 생각해 볼 때 대부분 상하로 생기는 스크롤을 움직이기 위해서 마우스의 포인터는 오른쪽 스크롤 바에 가 있다. 마우스가 마우스오버를 하지 않았을 경우에는 숨겨져 있는 정보를 볼 수가 없지 않을까? 그러므로 마우스오버하기 전에 이미 떠 있어야 하는 정보를 굳이 마우스오버 후에 나타나도록 숨겨진 정보로 만들 필요는 없다.


풀다운 메뉴 만들기
풀다운 메뉴는 오래된 사이트에서 단골손님을 위한 메뉴 '바로가기'로써의 역할로 만든다.

풀다운 메뉴의 장점이라고 하면 일반적인 사용자 인터페이스(User Interface)사용하는 요소들 - Back, Forward, Up, Down의 구조 - 를 뛰어넘는 Jump라는 기능을 가지고 있다는 것이다. 하지만, 모든 선택 메뉴들이 숨어 있다는 단점을 가지고 있다.

이 메뉴들이 사용자들의 호기심을 자극하지 않는 한 열어보지 않을 수도 있기 때문에 주의해야 할 UI요소이다. 그러므로, 새로운 사용자들을 위하기 보다는 기존의 사용자들이 빨리 자신이 원하는 메뉴로 점프(Jump)하게 끔 하는 역할로 사용하는 것이 좋다. 또한, 사용자 자신이 자기만의 풀다운 메뉴를 등록 하게끔 하는 것도 괜찮은 방법이다.


검색엔진의 사용성. (1)
사이트 상의 검색 엔진들은 사이트내의 컨텐츠를 찾는 것을 도와주는 목적으로 있다.
그러나 사용성 테스트의 타스크를 통한 성공률을 보면 검색엔진을 사용해서는 30%, 사용하지 않고서는 53% 성공하는 것을 볼 때 검색엔진 자체가 사용성에 충분히 도움을 주지는 못하는 것 같다. 그러나 사용자들은 검색엔진의 사용을 빨리 가기로 인식하는 것 같다.

검색엔진이 일으키는 문제들은 다음과 같다.
- 사용자에게 컨텐츠가 어떻게 쓰여지고 구성되어 있는지에 대해 이해 할 것을 요구한다.
- 검색엔진 스스로가 정보의 향기를 제공하지 않고 있으며 오히려 사용자들 스스로가 향기를 제공해야 한다는 것이다.

검색은 사용자들에게 즉각적인 만족을 주기도 한다. 그러나 사용자가 목적을 달성하는데 얼만큼의 시간을 단축시켜 주는지, 또는 정확하게 목적을 달성하는데 도움을 주는지, 도움을 주기 위해서는 어떤 방법들이 있는지에 대해 디자이너는 고민해야 할 것이다.


검색엔진의 사용성. (2)
Netscape의 DevEdge 검색 엔진으로부터 추출된 1주일치 데이터를 분석해 본 결과에 의하면 일반적으로 1단어 검색이 가장 많은 44%에 달했다고 한다.

또한 복수 단어 검색 중 반 이상이 연속 단어를 사용했으며 나머지 반은 정확한 모양의 쿼리를 사용했다는 것이다. 더욱 중요한 것은 쿼리의 3%가 잘못된 스펠링을 포함하고 있었다는 것이다. 이러한 결과는 사용자는 키워드를 치는 방법에 있어서 자신들의 단어로 원하는 것을 정의하며 이는 1단어 이상이기가 어렵다는 것이며 사용자는 검색 후에 틀린 답에도 뭐가 잘못 되었는지 결코 모른다는 것을 뜻한다. 또한 많은 사용자들이 부울 논리를 사용하지 않는 것으로 나타났다.

검색은 세가지 형태의 문제점을 안고 있다.
- 올바른 검색 영역에 도달하는 것
- 검색을 정의하는 것
- 결과를 해석하는 것

이러한 문제점들은 사용자들이 어떤 키워드를 입력해야 할지 잘 모른다는 것을 의미하며 종종 사용자들을 사이트의 다른 부분으로 갖다 놓는다는 것이다.

그러나 검색은 사용자들에게 즉각적인 만족을 준다. 그러므로 검색엔진의 사용성에 있어 사용자를 고려한 많은 노력(검색의 범위를 좁히는 도구나 프로세스)이 있다면 사용성이 높아지겠지만 그렇지 않다면 오히려 사용성을 감소시키는 주된 요인으로 작용된다는 것을 명심하자.


프레임의 실수
프린트를 어렵게 한다.
프린트를 방해한다. 여러 프레임 중 엉뚱한 부분이 프린트되어져 나올 수 있다.

북마크를 어렵게 한다.
프레임 페이지를 북마크 했을 경우, 다시 찾아갔을 때 엉뚱한 곳으로 왔다는 것을 발견할 수 있다.

검색엔진에 잘못 등록될 수 있다.
검색엔진에서 결과로 나온 URL을 찾아갔을 때 프레임의 일부분만 링크되어 있는 것을 본적이 있을 것이다.

수평 스크롤이 생길 수 있다.
스크롤에는 수직 스크롤과 수평 스크롤이 있는데 수직 스크롤은 요즘 많이들 사용하고 있는 휠마우스를 사용하여 어느 정도 사용하기 편하지만, 수평스크롤은 오른쪽과 왼쪽으로 왔다갔다하는 움직임을 해야 하기 때문에 몹시 불편을 준다.

출처 : UIdesign

    

설정

트랙백

댓글

UI디자인 가이드라인 - 사이트 구성하기

User Interface/Web 2007. 2. 21. 11:10

링크의 품질을 높이는 방법
사용자에게 자신감을 부추기고 자신이 찾고자 하는 정보의 향기를 전달하는 방법의 반은 링크에 의해 만들어진다.
또한 자신감은 링크 타입, 커뮤니케이트된 정보의 양, 링크가 생긴 모양에 의해 부추겨지는 수가 많다.

링크의 분류는 다음과 같이 나눌 수 있다.

- 컨텐츠 링크 : 컨텐츠를 포함하는 페이지로 간다.
- 카테고리 링크 : 다른 링크의 우선적으로 포함하는 페이지로 간다.
- 키워드 링크 : 검색의 부분으로 사용자가 입력하는 것이다.
- 백 혹은 홈 링크 : 홈이나 먼저 방문한 페이지로 간다.

위의 분류 중에서 컨텐츠 링크가 가장 좋은 방법이다. 사용자들은 카테고리 링크가 아니라 컨텐츠 링크를 사용할 때 더 성공할 가능성이 높다. (현재 국내의 사이트는 카테고리 링크가 더 많다.) 백, 홈 링크는 문제의 징조이기도 하다. 사용자가 향기를 놓쳤을 경우 많이 사용하기 때문이다.
링크들은 사용자들을 끌기 위해 올바른 단어들을 가지고 있어야 한다.(링크를 신호로 만드는 방법)


링크를 신호로 만드는 방법
문법적으로 정확한 문장은 정보를 찾기 어렵게 할 경우가 있다는 조사 결과(제이콥 닐슨 Alert Box 1997. 10.1 'How users Read on the Web)가 있다.
컨텐츠의 문장을 읽어가는(Scanning) 사용자는 그것을 신호와 잡음으로 구분하는데, 자신이 원하는 정보와 관련된 단어의 링크를 신호로, 그 밖의 내용은 그저 잉크인 잡음으로 보는 것이다. 보통 20개의 단어 중 4-5단어들(20%)은 신호, 나머지는 잡음이라고 간주 한다.
따라서 링크 안의 큰 잡음들은 관련 텍스트를 숨긴다.

링크는 커뮤니케이트 하기 위해 충분한 단어들을 가지는 것이 필요하다.
같은 목적을 가진 사용자들 이라도 사용자가 다르면 다른 단어를 찾을 수 있다.
예를 들어 취업을 원하는 사용자가 찾는 단어들을 살펴보면 어떤 이는 '이력서 올리기', 또 다른 사람은 'Job찾기', '구직', '일자리' 등… 사용자들은 동의어를 핸들 할 수 있지만 그것은 문맥 안에서 만 가능한 것이다.
그러므로 링크는 밑줄 쳐진 단어들과 그와 관련된 텍스트 둘 다 라고 할 수 있다.

그러므로 카테고리 링크가 더 어려운 일이다.
그 이유는 복수 링크들을 설명(묘사)해야만 하고, 보통 컨텐츠 링크 사이즈의 3분의 1정도 밖에 되지 않기 때문이다.

그렇다고 링크의 길이가 길어야 좋은 것은 아니다. 사용자의 선택을 도울 의도로 된 텍스트(제목들도 어떤 때는 포함)를 올바르게 디자이너가 결정해야 한다.


스캐닝(훑어 보기)를 도울 수 있는 방법
이 때 우리는 게슈탈트 심리이론이나 기억에 관한 인지 심리학 이론의 단기 기억 (의미덩이 만들기: chunking)을 이용한다.

1. 링크의 그룹핑 : 사용자들은 비슷한 아이템들을 서로 관련된 것으로 인식한다. 링크 그룹이 많은 웹 페이지가 능률적이다.(컨텐츠 링크 그룹이 잘 되어 있는 사이트는 CNN.com이다.)
2. 구조화된 목록 : 사용자에 따라 공통의 분류나 친숙한 영역들을 구조화 한다. (달력이 좋은 예이다.)
3. 링크의 차별화 : 다른 컨텐츠로 이끄는 링크는 그 차이점을 명확하게 차별화하는 것이 필요하다.(좋은 예 HP사이트)
4. 여분 링크를 이용한다. : 여분 링크란 사용자에게 복수의 향기를 제공하는 것, 즉 다른 문맥과 다른 목표로 다른 아이디어를 가지고 있는 다른 사용자들을 지원한다.
5. 괄호와 뷸렛을 이용한다. : 사용자들이 링크 그룹들을 다발 짖는 것을 도와 준다. 특히 복수 라인에 걸쳐 링크들이 묶여 있을 때 뷸렛은 사용자가 링크들을 서로 구분하는데 도움이 된다. 


배너처럼 보여서 간과되는 중요한 정보들
사용자들은 화면을 훑고 지나간 다음 중요한 내용이나 시선을 끄는 이미지에 관심을 보이지만 배너 같은 정보는 무시한다.
사용성 테스트 결과, 사용자들은 배너처럼 생긴 그래픽이 중요한 정보이더라도 무시해 버린다는 것을 발견할 수 있었다.
그러므로 사이트의 중요한 정보나 네비게이션을 광고처럼 이미지로 만들거나 배너 영역에 두어서 배너와 혼돈을 일으켜, 사용자들이 이를 간과해 버리도록 만들어서는 안된다.

여러 개의 이미지들이 오른쪽 밑 부분의 배너 광고 영역에 있으며, 그 형태 또한 배너 광고 형식을 띠고 있어 사용자들은 배너로 생각하고 무시하지만 사실은 내부의 주요한 정보들로 연결되는 중요한 링크이다. 그 중 ‘봄나들이’를 클릭하면 ‘봄 나들이 특집 주요 기사 모음’으로 화면이 전환된다.


링크 가능한 영역의 크기와 거리
웹페이지에서 버튼이 너무 작아서 클릭하기 원하는 것을 제대로 클릭하지 못하거나, text 주위의 background를 클릭했으나 클릭되지 않는 경우가 종종있다.
이러한 현상을 Fitts' Law (피츠의 법칙)로 설명할 수 있다. 피츠의 법칙은 속도와 정확성간 접합점의 기본적인 원리이다.

스크린 상에서 버튼의 크기와 커서를 이동시키려는 거리가 주어지면, 버튼까지 커서를 움직이려는데 걸리는 평균시간을 피츠의 법칙을 이용하여 구할 수 있다.

Time(in msec)=a+blog2(D/S+1) 
S : 버튼의 크기 
D : 버튼까지의 거리

위와 같이 커서가 버튼까지 움직이는 시간은 거리에 비례하고 버튼의 크기에 반비례한다.

Button을 클릭하기 위하여, Mouse를 이동시키는 거리가 멀면 멀수록 실수 없이 정확히 Button에 Mouse를 접근시키는 것이 더 어려워진다. 그리고 버튼의 크기(또는 클릭할 수 있는 영역)가 작을 수록 커서를 가져갈 target에 접근시켰을 때 성공할 확률이 낮아진다.

메뉴나 버튼은 쉽게 클릭하기에 ‘충분한 크기와 거리’를 고려해서 디자인 되어야 한다.


사용자들은 긴 화면을 스크롤한다
사용자들이 스크롤하기 싫어한다는 전통적인 견해는 흔히 옳은 것으로 간주되어 왔다.
이러한 가정 하에 한정된 분량을 한 화면에 담으려고 할 때, 디자이너는 대부분 다음의 두 가지 경우 중 한 가지를 택할 것이다.

한정된 화면 공간에 맞추기 위해 정보를 임의로 줄인다.
이 경우, 사용자는 내용 파악에 어려움을 느낀다.

하나의 화면을 몇 개의 페이지로 나눈다.
이 경우, 사용자는 다음 페이지가 로딩될 때까지 기다리는 것보다 다소 길어진 페이지를 스크롤하며 훑어보는 것을 더 선호한다.

사용성 테스트의 결과, 사용자들은 스크롤 자체를 기피하지는 않는다는 것이다. 하지만, 스크롤 바가 있는 긴 페이지에는 반드시 사용자들이 원하는 정보를 찾을 수 있도록 이끌어주는 요소로서의 ‘향기(scent)’가 있어야 한다.

출처 : UIdesign

    

설정

트랙백

댓글

UI디자인 가이드라인 - 신뢰도 높이기

User Interface/Web 2007. 2. 21. 11:10

단기간에 효과적으로 사용성을 높이는 방법
사용성테스트를 할 여건이 안 될 경우 좀더 적은 노력으로 혁신적인 사용성 개선을 원한다면 다음과 같은 방법을 사용해 보라.

우선 로그데이타나 기타조사를 통해 가장 빈번하게 사용하는 기능 또는 작업의 목록을 작성하라. 이 목록 중 최상위의 한두개를 골라 최대한 클릭 수를 줄이고 단순화하기 위해 다음과 같은 방법을 이용해 본다.

하나의 태스크를 대상으로 사용자가 그 태스크를 수행하는데 걸리는 예상 시간을 계산하는 것이다. 손을 마우스에 가져가고, 마우스를 움직이고, 누르고, 메뉴바의 이름을 기억해 내고, 각각에 드는 시간을 기준으로 태스크를 수행하는데 걸리는 총시간을 계산한다. 이때에는 육체적인 액션과 정신적인 액션에 드는 시간을 모두 계산한다. 이러한 방법 GOMS는 매우 세분화되고 한 태스크당 작업 시간도 꽤 걸리지만 놀라운 정도로 정확한 결과를 보여준다.

또 다른 방법은 태스크를 수행하는 각각의 방법을 경로화하여 가장 이상적인 경로를 찾는 Cognitive Walkthrough이다. 사용자별로 태스크를 수행하는 경로를 관찰함으로써 시스템이나 서비스가 사용자의 기대에 부합하는가, 이해가 쉬운가를 볼 수 있다.

이러한 방법들은 사용성테스트보다 간단하게 수행할 수 있으면서 사용자가 기대하는 효과를 성취할 수 있는가를 평가해 볼 수 있는 아주 효과적인 방법이다.
 
사용자에게 자신감을 주는 법
사용자가 자신이 원하는 정보로 접근하고 있다는 자신감을 주는 것이 좋은 디자인이다.
클릭 전에는 그들이 올바른 트랙에 있다는 것을 알려 주어야 하며 클릭 후에는 그들이 정말로 자신이 원하는 정보에 접근해 있다는 자신감을 느끼도록 해야 한다.
사용자들은 보통 자기들이 올바른 트랙에 있는지 아닌지를 안다.
사용자는 먼저 페이지를 대충 훑어 본다(Scanning)는 것을 명심하자.
그 때 그들이 찾는 정보의 키워드나 문장이 링크로 발견 된다면 클릭 전 사용자에게 자신감을 줄 수 있다.
그를 위한 디자인 요소로는 링크의 품질, 내비게이션 그래픽, 정보 구조의 디자인이 있다.

클릭 후에는 키워드나 문장 등에서 요구된 정보를 보여 주는 것, 혹은 더욱 강력하고 구체적인 정보를 발견 할 수 있도록 설계되어야 하며 그 때부터는 사용자가 정보를 꼼꼼히 읽기 시작할 것이다.

- 사용자가 자신감을 잃어버리도록 하는 것 들은
- 거짓말하는 링크
- 키워드가 없는 것(링크에 있던 단어가 컨텐츠에 없으면 속은 기분이 들것이다.)
- 보다 일반적인 컨텐츠
- 예쁘기만 하거나 희미한 링크

등 이며 자신감의 상실은 사용자의 포기를 야기한다.
조사에 따르면 백 버튼을 한번 누르면 42%, 두번 누르면 18%, 세번은 2%의 집계로 나타나는데 결론적으로 사용자가 백 버튼을 2번 누르면 정보 찾기를 완전히 그만둔다는 것을 알 수 있다.

확실한 UI를 짧은 시간에 만들기
확실한 UI를 만들고자 한다면 단연 '사용성 테스트(Usability Test)'를 하는 것이다.
이것은 개발 과정에서 짧은 시간만을 들여서 사용자로부터 훌륭한 피드백을 얻을 수 있는 기회를 마련하는 것이다.
디자인 결정에 있어서 망설여지는 부분이 있다면 테스트해라. 거창하게 할 필요도 없다. 그저 실제 사용자를 데리고 실제 사이트를 테스트하기만 하면 되는 것이다.


잘못된 UI를 아는 방법
사용성 테스트(Usability Test)를 했을 때-간략하게 하건, 본격적으로 하건- UI가 잘못되었다는 것을 어떻게 알 수 있을까. UI가 가장 잘못된 경우는 바로 사용자가 길을 잃고 헤매는 것이다. 사용자가 길을 잃었다는 신호는 다음과 같다.

- 사용자가 길을 잃었다는 신호
- Back button을 사용한다.
- 검색엔진을 사용하여 키워드 검색을 한다.
- 홈으로 돌아오는 버튼을 누른다.
- 사이트 맵으로 찾아간다.


훌륭한 웹 디자인을 위한 10가지 Tips
1. 한 페이지에는 하나의 주제에 대한 내용만 있어야 한다.
2. 액션 버튼들과 링크들은 눈에 잘 띄도록 만들어야 한다.
3. 결정적으로 중요한 페이지는 깔끔하고 심플한 구성을 항상 유지해야 한다.
4. 사용자가 쉽게 읽을 수 있도록 영어의 산세리프체 같은 심플하고 명료한 글씨체, 그룹 박스와 여유 공간을 사용하라.
5. 다운로드 시간을 줄이기 위해 그래픽을 최소화한다.
6. 로고를 클릭하면 home으로 갈 수 있도록 만든다.
7. 페이지의 타이틀은 명시된 버튼이나 링크와 같아야 한다.
8. 모든 입력 페이지에는 취소버튼을 제공하고 모든 메시지 페이지에는 뒤로 가기 버튼이 있어야 한다.
9. 기술적 용어(자바, 자바 스크립트, 애플렛 등) 을 피해야 한다.
10. 개발 전에 Prototype에 의한 Mock-up 테스트와 사용성(Usability) 테스트 등으로 사용자와 충분히 교류해야 한다.


사용성(Usability)을 높이기 위한 Tips
 -가시성과 독이성(읽기 쉬움) 
중요한 링크와 액션은 가시적이고 명백하게 만들어야 한다. 사용자들의 “훑어 읽기”를 감안하여 하이라이트 글자를 사용, 뷰렛화 된 리스트, 짧은 문장 등으로 디자인한다. 
 
 -간결성
빈번하거나 결정적인 업무들은 짧고 간단하게 유지한다. 용어는 사용자의 언어를 기초로 하는 것이 좋다. 기억하라. 짧게 적을수록 효과는 크다. 
 
 -실행
아직 인터넷 접근환경을 33.6kb 이하로 선호하는 반 이상의 사용자들을 위해 다운로드가 빠르도록 디자인한다.
 
 -네비게이션과 조직성
모든 페이지마다 [계속하기], [취소하기] 또는 [뒤로 가기] 그리고 [home]으로 갈 수 있는 명확한 방법을 공급한다. 사용자가 위치를 계속적으로 정보 받을 수 있는 효과적인 페이지 타이틀을 제공해야 한다. 페이지간을 조직적으로 배열하여 정보가 서로 그룹화 되고 접근하기 용이하도록 연계되어야 한다. 
 
 -일관성
비슷한 과업은 같은 맥락으로 수행되는 것이 좋다.  
 
 -피드백(feedback)
문제가 생겼을 때, 메시지는 사용자에게 정확히 무엇이 오류인지, 그리고 어떻게 고쳐야 하는지를 사용자가 이해할 수 있는 언어로 전달해야 한다.
 
 -관용
사용자가 실수한 것에 대한 최소한의 비용을 허용하는 시스템을 제공하고 또한 사용자들의 실행취소(undo)를 허락해야 한다.


사용자를 잡아두는 방법
웹에서의 사용자 시각 추적 연구 결과 사용자가 스크린을 보는 장소에 대해 일정한 패턴을 보여준다고 한다. 제일 먼저 가운데 그리고 왼쪽, 오른쪽의 순으로 나타난 것이다. 그러므로 정보의 중요도나 사이트 전략에 따라 이를 활용하는 것이 바람직 하다. 
 
사용자들은 대부분 배너광고를 무시하는 것을 재빨리 배운다. 여러 사이트의 사용성 테스트 결과, 배너를 마치 하나의 경계선처럼 여기고 배너처럼 생긴 그래픽은 그것이 중요한 정보임에도 발견하지 못하는 것을 발견할 수 있다. 그러므로 사이트의 중요한 정보나 네비게이션은 배너 광고처럼 이미지를 만들어서도 안되며 배너 영역에 두어서도 안 된다. 웹에서의 광고에 대해서는 사이트마다 심각하게 고려해야 할 대상이다.
 
만약 페이지 레이아웃의 그리드가 항상 똑같은 상태면 사용자들은 그 페이지의 부분을 무시하는 것을 배운다. 그러나 레이아웃이 현저하게 바뀌면 전 페이지를 다시 스캔 한다고 한다.(eBay.com은 각 페이지가 다른 레이아웃으로 되어 있음)
 
출처 : UIdesign

    

설정

트랙백

댓글

구글, HDD 10만개를 테스트하다.

Miscellaneous/Etc 2007. 2. 21. 11:10
“과도한 사용이나 고온의 작업 환경이 하드디스크 고장을 증가시킨다는 것은 다소 과장된 것 같습니다. 그리고 고장 점검 기술인 ‘SMART(Self Monitoring, Analysis, Reporting, Technology)’ 기능은 개인 사용자들의 하드디스크 고장을 탐지해내는데 그다지 효과적이지 못합니다.”

수십만 대 서버를 중심으로 2001년부터 80GB~400GB까지 10만 여개 하드디스크를 테스트 한 구글 서버 관리자들의 결론이다.

지난 13일부터 16일까지 캘리포니아 산호세에서 열린 저장장치 콘퍼런스 ‘USENIX FAST 2007(File And Storage Technologies 2007, http://www.usenix.org/events/fast07)’에서 공개된 구글 논문이 인터넷에 공개됐다.

에듀아도 핀헤이로(Eduardo Pinheiro), 울프 디트리히 웨버(Wolf-Dietrich Weber), 루이스 안드레 바로소(Luiz Andre Barroso) 세 명의 구글 엔지니어가 공동 작성한 이 논문은 하드디스크 고장의 원인을 사용량, 온도, SMART 기능 등을 중심으로 분석한 자료를 담았다.

구글는 일단 고장이 발생한 하드디스크들은 ‘failed’로 분류된 뒤, 웹페이지 캐시 저장용으로 사용하고 있는 것으로 알려져 있다.

사용자 삽입 이미지


[클릭 : PDF 논문 원본 - Failure Trends in a Large Disk Drive Population]

◆고온 환경과 하드디스크 고장은 무관 = 우선 구글 엔지니어들은 제조사들이 제시하는 ‘평균 고장 간격(Mean Time Between Failure)’에 대해 의문을 제기했다. MTBF란 수리 가능한 장치의 어떤 고장과 다음 고장 사이, 즉 수리 완료로부터 다음 고장까지 무고장으로 작동하는 시간의 평균값이다.

이들은 논문에서 “기존 사용자들이 주장한 것 보다 사용률(utilisation levels)과 고장 사이에는 상관관계가 약하다”고 주장했다. 일반적으로 하드디스크는 많이 사용하면, 온도가 높을수록 고장이 날 가능성이 높다고 알려져 있다.

조사 자료에 따르면 사용한 지 3년 이하인 하드디스크의 경우 많은 작업을 수행한 하드디스크가 부정기적으로 사용한 하드디스크에 비해 고장 발생비율이 적었다. 이러한 사용 행태는 ‘최적화 이론’으로 풀이할 수 있다. 초기에 일찌감치 고장이 발생한 하드디스크들은 제거되기 때문에 전체 하드디스크 샘플이 점점 더 수명이 길어지게 되는 것이다.

또한 저자들은 “테스트 결과 높은 온도는 하드디스크 고장과 큰 상관관계가 없으며, 오히려 낮은 온도가 고장 발생 비율을 높였다”고 설명했다. 일정 수준에 이르면 온도가 더 상승한다고 하더라도 오류 발생 비율은 늘어나지 않는다는 주장이다. 다만 논문은 “3년 이상 지난 하드디스크의 경우 더 높은 온도 환경에서 계속 사용할 경우 고장 발생 비율이 높아졌다”고 덧붙였다.

저자들은 “이것은 매우 놀라운 결과”라며 “데이터센터나 서버 설계자들은 과거의 온도 설계 방식에서 좀 더 자유로워 질 수 있을 것”이라고 말했다.

사용자 삽입 이미지
 

◆고장 점검 기능 ‘SMART’ 기대이하 = 이 논문은 SMART 기능을 중심으로 ‘검사 오류(scan errors)’에 대해서도 집중적으로 다뤘다.

저자들은 “검사 오류가 발생한 하드디스크 그룹은 검사 오류가 발생하지 않은 그룹에 비해 10애 이상 고장이 많이 발생했다”며 “첫 번째 검사 오류가 발생한 후 해당 하드디스크는 검사오류가 없는 하드디스크에 비해 60일 이내 고장날 확률이 39배나 높았다”고 설명했다.

엔지니어들은 이에 따라 “SMART 기능이 개인 사용자들의 하드디스크 오류를 추출해 낼 때에는 유용할 것 같지 않다”며 “다만 대량으로 하드디스크를 관리할 때 고장 패턴을 분석하는 데 더 유용할 것”이라고 지적했다.

이 밖에도 구글은 어느 회사의 하드디스크가 더 수명이 긴 것인지 별도의 통계 자료를 가지고 있지만, “하드디스크 수명과 고장 상관관계를 이해하는데 도움이 되지 않는다”는 자체 판단에 따라 논문에 싣지 않았다.

인터넷뉴스부 서명덕기자
    

설정

트랙백

댓글

Nokia Concept Phone UI 동영상

Design/Mobile 2007. 2. 21. 11:09
 
    

설정

트랙백

댓글

Iterator

Programming/Design Patterns 2007. 2. 21. 11:09









1 class DinerMenu{
2         public static var MAX_ITEMS = 6;
3         private var numberOfItems = 0;
4         private var menuItems:Array;
5
6         public function DinerMenu(){
7                 menuItems = new Array();
8
9                 addItem("채식주의자용 BLT", "통밀 위에(식물성) 베이컨, 상추, 토마토를 얹은 메뉴", true, 2.99);
10                 addItem("BLT", "통밀 위에 베이컨, 상추, 토마토를 얹은 메뉴", false, 2.99);
11                 addItem("오늘의 스프", "감자 샐러드를 곁들인 오늘의 스프", false, 3.29);
12                 addItem("핫도그", "사워크라우트, 갖은 양념, 양파, 치즈가 곁들여진 핫도그", false, 3.05);
13
14         }
15
16         public function addItem(name:String, description:String, vegetarian:Boolean, price:Number):Void{
17                 var menuItem:MenuItem = new MenuItem(name, description, vegetarian, price);
18                 if(numberOfItems >= MAX_ITEMS){
19                         trace("죄송합니다. 메뉴가 꽉 찼습니다. 더이상 추가할 수 없습니다.");
20                 }else{
21                         menuItems[numberOfItems] = menuItem;
22                         numberOfItems+=1;
23                 }
24         }
25         /* public function getMenuItems():Array{
26         return menuItems;
27 }*/

28         public function createIterator():Iterator{
29                 return new DinerMenuIterator(menuItems);
30         }
31
32 }

////////////////////////////////////////

 1 class DinerMenuIterator implements Iterator{
2         private var items:Array;
3         private var position:Number;
4
5         public function DinerMenuIterator(items:Array){
6                 this.items = items;
7                 this.position = 0;
8         }
9         public function next():Object{
10                 var menuItem:MenuItem = items[position];
11                 position += 1;
12                 return menuItem;
13         }
14         public function hasNext():Boolean{
15                 if(position>= items.length || items[position] == null){
16                         return false;
17                 }else{
18                         return true;
19                 }
20         }
21 }

///////////////////////////////////////////

 1 interface Iterator{
2         public function hasNext():Boolean;
3         public function next():Object;
4 }

///////////////////////////////////////////

 1 class MenuItem{
2         private var name;
3         private var description:String;
4         private var vegetarian:Boolean;
5         private var price:Number;
6
7         public function MenuItem(name:String, description:String, vegetarian:Boolean, price:Number){
8                 this.name = name;
9                 this.description = description;
10                 this.vegetarian = vegetarian;
11                 this.price = price;
12         }
13         public function getName():String{
14                 return name;
15         }
16         public function getDescription():String{
17                 return description;
18         }
19         public function getPrice():Number{
20                 return price;
21         }
22         public function isVegetarian():Boolean{
23                 return vegetarian;
24         }
25         public function toString():String{
26                 return name+" of MenuItem Object\n";
27         }
28 }

//////////////////////////////////////////

 1 class PancakeHouseMenu{
2         private var menuItems:Array;
3
4         public function PancakeHouseMenu(){
5                 menuItems = new Array();
6                 addItem("K&B 팬케이크 세트", "스크램블드 에그와 포스트가 곁들여진 팬케이크", true, 2.99);
7                 addItem("레귤러 팬케이크 세트", "달걀 후라이와 소시지가 곁들여진 팬케이크", false, 2.99);
8                 addItem("블루베리 팬케이크", "신선한 블루베리와 블루베리 시럽으로 만든 팬케이크", true, 3.49);
9                 addItem("와플", "와플, 취향에 따라 블루베리나 딸기를 얹을 수 있습니다.", true, 3,59);
10         }
11         public function addItem(name:String, description:String, vegetarian:Boolean, price:Number):Void{
12                 var menuItem:MenuItem = new MenuItem(name, description, vegetarian, price);
13                 menuItems.push(menuItem);
14         }
15         /* public function getMenuItems():Array{
16         return menuItems;
17 }*/

18         public function createIterator():Iterator{
19                 return new PancakeIterator(menuItems);
20         }
21 }

/////////////////////////////////////////////

1 class PancakeIterator implements Iterator{
2         private var items:Array;
3         private var position:Number;
4
5         public function PancakeIterator(items:Array){
6                 this.items = items;
7                 this.position = 0;
8         }
9         public function next():Object{
10                 var menuItem:MenuItem = items[position];
11                 position += 1;
12                 return menuItem;
13         }
14         public function hasNext():Boolean{
15                 if(position>= items.length || items[position] == null){
16                         return false;
17                 }else{
18                         return true;
19                 }
20         }
21 }

////////////////////////////////////////////////

 1 class Waitress{
2         private var pancakeHouseMenu:PancakeHouseMenu;
3         private var dinerMenu:DinerMenu;
4
5         public function Waitress(pancakeHouseMenu:PancakeHouseMenu, dinerMenu:DinerMenu){
6                 this.pancakeHouseMenu = pancakeHouseMenu;
7                 this.dinerMenu = dinerMenu;
8         }
9         public function printMenu():Void{
10                 var pancakeIterator:Iterator = pancakeHouseMenu.createIterator();
11                 var dinerIterator:Iterator = dinerMenu.createIterator();
12                 trace("메뉴 ----- \n 아침 메뉴");
13                 printMenuList(pancakeIterator);
14                 trace("\n점심 메뉴");
15                 printMenuList(dinerIterator);
16         }
17         private function printMenuList(iterator:Iterator):Void{
18                 while(iterator.hasNext()){
19                         var menuItem:MenuItem = MenuItem(iterator.next());
20                         trace(menuItem.getName()+", ");
21                         trace(menuItem.getPrice()+"--");
22                         trace(menuItem.getDescription());
23                 }
24
25         }
26 }

////////////////////////////////////////////

 1 class MenuTestDrive{
2         public function MenuTestDrive(){
3                 initialize();
4         }
5         private function initialize():Void{
6                 var pancakeHouseMenu:PancakeHouseMenu = new PancakeHouseMenu();
7                 var dinerMenu:DinerMenu = new DinerMenu();
8                 var waitress:Waitress = new Waitress(pancakeHouseMenu, dinerMenu);
9                 waitress.printMenu();
10         }
11 }
    

설정

트랙백

댓글

TemplateMethod

Programming/Design Patterns 2007. 2. 21. 11:09
 1 class CaffeineBeverage{
2         public function prepareRecipe():Void{
3                 boilWater();
4                 brew();
5                 pourInCup();
6                 if(hook()){
7                         addCondiments();
8                 }
9         }
10         public function brew():Void{
11
12         }
13         public function addCondiments():Void{
14
15         }
16         public function boilWater():Void{
17                 trace("물 끓이는 중");
18         }
19         public function pourInCup():Void{
20                 trace("컵에 따르는 중");
21         }
22         public function hook():Boolean{
23                 return true;
24         }
25 }

/////////////////////////////////////////////

 1 class Coffee extends CaffeineBeverage{
2         public function brew():Void{
3                 trace("필터로 커피를 우려내는 중");
4         }
5         public function addCondiments():Void{
6                 trace("설탕과 커피를 추가하는 중");
7         }
8         public function hook():Boolean{
9                 return false;
10         }
11 }

//////////////////////////////////////////////

 1 class Tea extends CaffeineBeverage{
2         public function brew():Void{
3                 trace("차를 우려내는 중");
4         }
5         public function addCondiments():Void{
6                 trace("레몬을 추가하는 중");
7         }
8 }

//////////////////////////////////////////////

 1 class TemplateTest{
2         public function TemplateTest(){
3                 init();
4         }
5         private function init():Void{
6                 var tea:CaffeineBeverage = new Tea();
7                 var coffee:CaffeineBeverage = new Coffee();
8
9                 trace("Tea Test..............");
10                 tea.prepareRecipe();
11
12                 trace("Coffee Test...........");
13                 coffee.prepareRecipe();
14         }
15 }
    

설정

트랙백

댓글

Adapter

Programming/Design Patterns 2007. 2. 21. 11:08
 1 interface Duck{
2         public function quack():Void;
3         public function fly():Void;
4 }

////////////////////////////////////

 1 class MallardDuck implements Duck{
2         public function quack():Void{
3                 trace("Quack");
4         }
5         public function fly():Void{
6                 trace("I'm flying");
7         }
8 }

/////////////////////////////////////

 1 interface Turkey{
2         public function gobble():Void;
3         public function fly():Void;
4 }

/////////////////////////////////////

class TurkeyAdapter implements Duck{
        private var turkey:Turkey;
        public function TurkeyAdapter(turkey:Turkey){
                this.turkey = turkey;
        }
        public function quack():Void{
                turkey.gobble();
        }
        public function fly():Void{
                for(var i=0;i<5;i++){
                        turkey.fly();
                }
        }
}


//////////////////////////////////////

 1 class WildTurkey implements Turkey{
2         public function gobble():Void{ 3 trace("Gobble gobble");
4         }
5         public function fly():Void{
6                 trace("I'm flying a short distance");
7         }
8 }

//////////////////////////////////////

 1 class DuckTestDrive{
2         public function DuckTestDrive(){
3                 initialize();
4         }
5         public function initialize():Void{
6                 var duck:MallardDuck = new MallardDuck();
7
8                 var turkey:WildTurkey = new WildTurkey();
9                 var turkeyAdapter:Duck = new TurkeyAdapter(turkey);
10
11                 trace("The Turkey says...");
12                 turkey.gobble();
13                 turkey.fly();
14
15                 trace("The Duck says...");
16                 testDuck(duck);
17
18                 trace("The TurkeyAdapter says...");
19                 testDuck(turkeyAdapter);
20         }
21         private function testDuck(duck:Duck):Void{
22                 duck.quack();
23                 duck.fly();
24         }
25
26 }
    

설정

트랙백

댓글

Command

Programming/Design Patterns 2007. 2. 21. 11:08
 1 interface Command{
2         public function execute();
3 }

///////////////////////////////

 1 class Light{
2         private var name:String;
3         public function Light(name:String){
4                 this.name = name;
5         }
6         public function lightOn():Void{
7                 trace(name+" : 불을 켜다");
8         }
9         public function lightOff():Void{
10                 trace(name+" : 불을 끄다");
11         }
12 }

/////////////////////////////////

 1 class LightOffCommand implements Command{
2         private var light:Light;
3
4         public function LightOffCommand(light:Light){
5                 this.light = light;
6         }
7         public function execute(){
8                 light.lightOff();
9         }
10 }

////////////////////////////////////

 1 class LightOnCommand implements Command{
2         private var light:Light;
3
4         public function LightOnCommand(light:Light){
5                 this.light = light;
6         }
7         public function execute(){
8                 light.lightOn();
9         }
10 }

/////////////////////////////////////

 1 class RemoteControl{
2         private var onCommands:Array;
3         private var offCommands:Array;
4
5         public function RemoteControl(){
6                 onCommands = new Array();
7                 offCommands = new Array();
8         }
9         public function setCommand(slot:Number, onCommand:LightOnCommand, offCommand:LightOffCommand):Void{
10                 onCommands[slot] = onCommand;
11                 offCommands[slot] = offCommand;
12         }
13         public function onButtonWasPressed(slot:Number):Void{
14                 onCommands[slot].execute();
15         }
16         public function offButtonWasPressed(slot:Number):Void{
17                 offCommands[slot].execute();
18         }
19 }

//////////////////////////////////////

 1 class RemoteControlTest
2 {
3         public function RemoteControlTest ()
4         {
5                 init ();
6         }
7         public function init () : Void
8         {
9                 var remote : RemoteControl = new RemoteControl ();
10                 var light : Light = new Light ("스텐드");
11                 var lightOn : LightOnCommand = new LightOnCommand (light);
12                 var lightOff : LightOffCommand = new LightOffCommand (light);
13                 remote.setCommand (0, lightOn, lightOff);
14                 remote.onButtonWasPressed (0);
15                 remote.offButtonWasPressed (0);
16         }
17 }

    

설정

트랙백

댓글

Singleton

Programming/Design Patterns 2007. 2. 21. 11:08
 1 class Singleton{
2         private static var uniqueInstance;
3
4         private function Singleton(){
5
6         }
7         public static function getInstance():Singleton{
8                 if(uniqueInstance == null){
9                         uniqueInstance = new Singleton();
10                 }
11                 return uniqueInstance;
12         }
13         public function getName(){
14                 trace("Singleton pattern");
15         }
16 }
    

설정

트랙백

댓글

Factory

Programming/Design Patterns 2007. 2. 21. 11:07
 1 class SimplePizzaFactory{
2         public function createPizza(type:String):Pizza{
3                 var pizza:Pizza = null;
4                 if(type == "cheese"){
5                         pizza = new CheesePizza();
6                 }else if(type == "pepperoni"){
7                         pizza = new PepperoniPizza();
8                 }else if(type == "clam"){
9                         pizza = new ClamPizza();
10                 }else if(type == "veggie"){
11                         pizza = new VeggiePizza();
12                 }
13                 return pizza;
14         }
15 }

////////////////////////////////////////

 1 class CheesePizza extends Pizza{
2         public function CheesePizza(){
3                 pizza_name = "CheesePizza";
4                 dough = "얇게";
5                 sauce = "짜게";
6         }
7
8         private function bake(){
9                 trace("Bake for 25 minutes at 350");
10         }
11         private function cut(){
12                 trace("Cutting the pizza into diagonal slices");
13         }
14         private function box(){
15                 trace("Place pizza in official PizzaStore box");
16         }
17         public function getName():String{
18                 return pizza_name;
19         }
20 }

/////////////////////////////////

 1 class VeggiePizza extends Pizza{
2         public function VeggiePizza(){
3                 pizza_name = "VeggiePizza";
4                 dough = "굵게";
5                 sauce = "달게";
6         }
7
8         private function bake(){
9                 trace("Bake for 25 minutes at 350");
10         }
11         private function cut(){
12                 trace("Cutting the pizza into diagonal slices");
13         }
14         private function box(){
15                 trace("Place pizza in official PizzaStore box");
16         }
17         public function getName():String{
18                 return pizza_name;
19         }
20 }

/////////////////////////////////////////////

 1 class ClamPizza extends Pizza{
2         public function ClamPizza(){
3                 pizza_name = "ClamPizza";
4                 dough = "굵게";
5                 sauce = "달게";
6         }
7
8         private function bake(){
9                 trace("Bake for 25 minutes at 350");
10         }
11         private function cut(){
12                 trace("Cutting the pizza into diagonal slices");
13         }
14         private function box(){
15                 trace("Place pizza in official PizzaStore box");
16         }
17         public function getName():String{
18                 return pizza_name;
19         }
20 }

//////////////////////////////////////

 1 class PepperoniPizza extends Pizza{
2         public function PepperoniPizza(){
3                 pizza_name = "PepperoniPizza";
4                 dough = "굵게";
5                 sauce = "달게";
6         }
7
8         private function bake(){
9                 trace("Bake for 25 minutes at 350");
10         }
11         private function cut(){
12                 trace("Cutting the pizza into diagonal slices");
13         }
14         private function box(){
15                 trace("Place pizza in official PizzaStore box");
16         }
17         public function getName():String{
18                 return pizza_name;
19         }
20 }

/////////////////////////////////////////

 1 class Pizza{
2         private var pizza_name:String;
3         private var dough:String;
4         private var sauce:String;
5         private var ary:Array = new Array();
6
7         public function prepare(){
8                 trace("피자이름 : "+pizza_name);
9
10         }
11         public function bake(){
12                 trace("Bake for 25 minutes at 350");
13         }
14         public function cut(){
15                 trace("Cutting the pizza into diagonal slices");
16         }
17         public function box(){
18                 trace("Place pizza in official PizzaStore box");
19         }
20         public function getName():String{
21                 return pizza_name;
22         }
23
24 }

///////////////////////////////////////

 1 class PizzaStore{
2         private var factory:SimplePizzaFactory;
3         public function PizzaStore(factory:SimplePizzaFactory){
4                 this.factory = factory;
5         }
6         public function orderPizza(type:String):Pizza{
7                 var pizza:Pizza; 8 pizza = factory.createPizza(type);
9                 pizza.prepare();
10                 // pizza.bake();
11                 // pizza.cut();
12                 // pizza.box();
13                 return pizza;
14         }
15 }

////////////////////////////////////////
var myPizzaStore:PizzaStore = new PizzaStore(new SimplePizzaFactory());
myPizzaStore.orderPizza("cheese");
myPizzaStore.orderPizza("pepperoni");
myPizzaStore.orderPizza("clam");
myPizzaStore.orderPizza("veggie");


    

설정

트랙백

댓글

Decorator

Programming/Design Patterns 2007. 2. 21. 11:07
 1 class Beverage{
2         private var descriptions:String = "제목없음";
3         public function getDescription():String{
4                 return descriptions;
5         }
6         public function cost():Number{
7                 return 0;
8         }
9 }

////////////////////////////////////

 1 class CondimentDecorator extends Beverage{
2         public function getDepscription(){
3
4         }
5 }

////////////////////////////////////

 1 class DarkRoast extends Beverage{
2         public function DarkRoast(){
3                 descriptions = "다트로스트 커피";
4         }
5         public function cost():Number{
6                 return 2.89;
7         }
8 }

/////////////////////////////////////

 1 class Espresso extends Beverage{
2         public function Espresso(){
3                 descriptions = "에스프레소";
4         }
5         public function cost():Number{
6                 return 1.99;
7         }
8 }

//////////////////////////////////////

 1 class HouseBlend extends Beverage{
2         public function HouseBlend(){
3                 descriptions = "하우스 브렌드 커피";
4         }
5         public function cost():Number{
6                 return .89;
7         }
8 }

//////////////////////////////////////

 1 class Mocha extends CondimentDecorator{
2         private var beverage:Beverage;
3         public function Mocha(beverage:Beverage){
4                 this.beverage = beverage;
5         }
6         public function getDescription():String{
7                 return beverage.getDescription()+", 모카";
8         }
9         public function cost():Number{
10                 return .20+beverage.cost();
11         }
12 }

///////////////////////////////////////

 1 class Whip extends Beverage{
2         private var beverage:Beverage;
3         public function Whip(beverage:Beverage){
4                 this.beverage = beverage; 5 } 6 public function getDescription():String{
7                 return beverage.getDescription()+", 휘핑";
8         }
9         public function cost():Number{
10                 return .20+beverage.cost();
11         }
12 }

///////////////////////////////////////

 1 class Main{
2         public function Main(){
3                 init();
4         }
5         private function init(){
6                 var beverage:Beverage = new Espresso();
7                 trace(beverage.getDescription()+" $"+beverage.cost());
8
9                 var beverage2:Beverage = new DarkRoast();
10                 beverage2 = new Mocha(beverage2);
11                 beverage2 = new Mocha(beverage2);
12                 beverage2 = new Whip(beverage2);
13                 trace(beverage2.getDescription()+" $"+beverage2.cost());
14
15                 var beverage3:Beverage = new HouseBlend();
16                 beverage3 = new Mocha(beverage3);
17                 beverage3 = new Whip(beverage3);
18                 trace(beverage3.getDescription()+" $"+beverage3.cost());
19
20         }
21 }
    

설정

트랙백

댓글

Observer

Programming/Design Patterns 2007. 2. 21. 11:06
 1 class CurrentConditionsDisplay implements Observer, DisplayElement{
2         private var temperature:Number;
3         private var humidity:Number;
4         private var pressure:Number;
5         private var weatherData:Subject;
6
7         public function CurrentConditionsDisplay(weatherData:Subject){
8                 this.weatherData = weatherData;
9                 weatherData.registerObserver(this);
10         }
11         public function update(temperature:Number, humidity:Number, pressure:Number):Void{
12                 this.temperature = temperature;
13                 this.humidity = humidity;
14                 this.pressure = pressure;
15                 display();
16         }
17         public function display():Void{
18                 trace("Temperature: "+temperature);
19                 trace("Humidity: "+humidity);
20                 trace("Pressure: "+pressure);
21                 trace("----------------------");
22         }
23 }

////////////////////////////////////////////////////////////////

 1 interface DisplayElement{
2         public function display():Void;
3 }

////////////////////////////////////////////////////////////////

 1 interface Observer{
2         public function update(temp:Number, humidity:Number, pressure:Number):Void;
3 }

///////////////////////////////////////////////////////////////
 1 interface Subject{
2         public function registerObserver(o:Observer):Void;
3         public function removeObserver(o:Observer):Void;
4         public function notifyObserver():Void;
5 }

///////////////////////////////////////////////////////////////

 1 class WeatherData implements Subject{
2         private var observers:Array;
3         private var temperature:Number;
4         private var humidity:Number;
5         private var pressure:Number;
6
7         public function WeatherData(){
8                 observers = new Array();
9         }
10         public function registerObserver(o:Observer):Void{
11                 observers.push(o);
12         }
13         public function removeObserver(o:Observer):Void{
14                 var lastIndex:Number = observers.length;
15                 for(var i=0;i<lastIndex;i++){
16                         if(observers[i] == o){
17                                 observers.splice(i,1);
18                         }
19                 }
20         }
21         public function notifyObserver():Void{
22                 var lastIndex:Number = observers.length;
23                 for(var i=0;i< lastIndex;i++){
24                         var observer:Observer = Observer(observers[i]);
25                         observer.update(temperature, humidity, pressure);
26                 }
27         }
28         public function measurementsChanged():Void{
29                 notifyObserver();
30         }
31         public function setMeasurements(temperature:Number, humidity:Number, pressure:Number):Void{
32                 this.temperature = temperature;
33                 this.humidity = humidity;
34                 this.pressure = pressure;
35                 measurementsChanged();
36         }
37 }

//////////////////////////////////////////////////////////////

 1 class WeatherStation{
2         public function WeatherStation(){
3                 var weatherData:WeatherData = new WeatherData();
4                 var weatherData2:WeatherData = new WeatherData();
5                 var currentDisplay:CurrentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
6                 var currentDisplay:CurrentConditionsDisplay = new CurrentConditionsDisplay(weatherData2);
7                 weatherData.setMeasurements(80,30,23);
8                 weatherData2.setMeasurements(11,22,33);
9                 weatherData.setMeasurements(22,30,23);
10
11         }
12 }

///////////////////////////////////////////////////////////////////


    

설정

트랙백

댓글

StrategyPattern

Programming/Design Patterns 2007. 2. 21. 11:06
class Duck{
        public var flyBehavior:FlyBehavior;
        public var quackBehavior:QuackBehavior;

        public function Duck(){

        }
        public function swim():Void{

        }
        public function display():Void{

        }
        public function performQuack():Void{
                quackBehavior.quack();
        }
        public function performFly():Void{
                flyBehavior.fly();
        }
        public function setFlyBehavior(fb:FlyBehavior):Void{
                flyBehavior = fb;
        }
        public function setQuackBehavior(qb:QuackBehavior):Void{
                quackBehavior = qb;
        }
}

////////////////////////////////////////////////

interface FlyBehavior{
        public function fly():Void;
}
////////////////////////////////////////////////
class FlyNoWay implements FlyBehavior{
        public function fly():Void{
                trace("저 안 날아요");
        }
}
////////////////////////////////////////////////
class FlyWithWings implements FlyBehavior{
        public function fly():Void{
                trace("저 날아요");
        }
}
////////////////////////////////////////////////
class ModelDuck extends Duck{
        public function ModelDuck(){
                flyBehavior = new FlyNoWay();
                quackBehavior = new MuteQuack();
        }
        private function display():Void{
                trace("가짜 오리입니다");
        }
}
////////////////////////////////////////////////
class MuteQuack implements QuackBehavior{
        public function quack():Void{
                trace("나 벙어리");
        }
}
///////////////////////////////////////////////
class Quack implements QuackBehavior{
        public function quack():Void{
                trace("꽥꽥");
        }
}
/////////////////////////////////////////////////
interface QuackBehavior{
        public function quack():Void;
}
/////////////////////////////////////////////////
class Squack implements QuackBehavior{
        public function quack():Void{
                trace("삑삑");
        }
}
/////////////////////////////////////////////////
class Main{
        private var myDuck:Duck;
        public function Main(){
                myDuck = new ModelDuck();
                init();
        }
        private function init():Void{
                myDuck.display();
                myDuck.performFly();
                myDuck.performQuack();
                myDuck.setFlyBehavior(new FlyWithWings());
                myDuck.performFly();

        }
}
/////////////////////////////////////////////////
    

설정

트랙백

댓글

스킨 편집 팁 : 파이어폭스와의 CSS 호환성

Programming/Etc 2007. 2. 21. 11:05
스킨 편집 팁 : 파이어폭스와의 CSS 호환성

이번에 소개해 볼것은 스킨 편집 및 웹페이지 제작 등에 쓰일수 있는 파이어폭스와의 호환성에 관한 간단한 팁입니다.

'파이어폭스와의 호환성' 이라고 예기해 봤습니다만.
사실상 파이어폭스와의 호환성이라 함은 바로 '웹표준' 을 말하는 것입니다.
인터넷 익스플로러(이하 IE)가 대다수인 실정상. 한국에서는 대부분의 웹페이지가 IE에 맞추어져 제작되어 있습니다만.
IE에만 맞추어져 있는 홈페이지는 다른 브라우져에서 그 구조가 깨어지거나 사용이 불가능할 정도까지도 될수 있습니다.
이 문제는 IE가 웹표준을 따르지 않는데서 기인하는 문제인데요.

표준에 맞추었을 경우 IE및 모든 브라우져에서 완벽하게 잘 보이는 것에 반해,
IE에만 맞추었을 경우 다른 모든 브라우져에서는 올바르게 보이지 않는 것에 비추어 보아 이것은 전적으로 IE의 문제라고 볼수 있습니다.

그러나. 웹디자이너가 아닌 이상에야 일반 사용자가,
HTML코드를 짜는데에 있어 표준이고 아니고를 맞추기가 사실 실로 힘든 부분이라 할수 있습니다.
뭐니해도 사실상, 자신이 사용하고 또한 가장 많이 사용하는 IE에서만 잘 보이면 그만이니까요.

하지만. 웹페이지라는 것의 특성상 절대적 대다수만이 아닌 소수들에게도 동일한 서비스를 제공해야 하는 암묵적인 책임이 있을 뿐더러.
IE가 아닌 다른 브라우져 사용자들은 점점 늘어나는 추세라. 비록 일반 사용자임에도 불구하고 이것은 무시하지 못할 정도의 문제라고 생각할수 있습니다.
특히, 스킨 편집을 하고자 하시는 분들은 커스터마이징이나 디자인적 관점에서의 접근을 하게 됩니다만.
다른 브라우져에서 보았을때 그것이 무참하게 깨져 버림으로써 자신의 노력이 물거품이 되는 정신적 충격을 받을수도 있습니다.

이번 기회엔 초보자도 간단히 사용할수 있는 호환성에 관한 간단한 팁을 소개해 보겠습니다.




CSS에서 가장 문제가 되는 것은 다름아닌 '박스모델' 입니다.
특히 이글루스 스킨은 레이아웃을 잡는데에 있어 박스모델이 주로 사용됩니다만.
그 코드를 작성함에 있어 IE위주로 작성한다면 필연적으로 다른 브라우져에서는 깨지게 됩니다.
결론적으로, 이 '박스모델' 만 신경써 준다면 웬만한 브라우져에서는 다 잘 보인다는 것이죠.

IE에서 박스모델이 표준이 아닌 이유는 바로 padding, margin, border 사이즈에 있습니다.
예를들어 가로와 세로가 각각 100px인 박스에 padding 10px, margin 10px, border 1px를 준다고 생각해 봅시다.
간단히 생각해 보자면 다음과 같은 코드를 사용하면 되겠지요.

예제1-IE전용

DIV.TEST{
WIDTH: 100PX;
HEIGHT: 100PX;
PADDING: 10PX;
MARGIN: 10PX;
BORDER: 1PX SOLID #000000;
}


사실, 솔직히 말해 직관적입니다. 그냥 생각한 대로 가로세로 100픽셀에 그냥 padding, margin, border 만 주면 됩니다.
그런데. 이런 식으로 코드를 작성하면 반드시 이것은 다른 브라우져에서 문제가 생깁니다.
왜냐하면, IE의 경우 가로세로 수치가 눈으로 보이는 박스 사이즈에 기준한것에 반해,
다른 브라우져가 사용하는 가로세로 수치는 눈으로 보이는 사이즈가 아닌 내용이 표시되는 부분을 기준으로 하고 있기 때문이죠.

그러니까. 눈으로 보이는 박스 사이즈가 100px라고 하면, IE에서는 그냥 100px을 적어주면 끝납니다만.
표준 브라우져에서는 그 사이즈에서 padding과 border 사이즈를 뺀 사이즈, 위의 경우에서는 78px를 적어줘야 하는 것입니다.


자. 그렇다면 코드를 작성할때 일일히 이것을 계산해서 조심스레 적어야 할까요.
...솔직히 매우 머리아프고 귀찮은 짓임에 분명합니다.
또한 이렇게 적으면 되려 IE에서 잘 보이지 않는 결과가 생길수도 있습니다. (첨부 이미지 참조)

결국 생각해볼수 있는 방법은. 바로 표준과 IE를 따로 적어주는 방법인 것이죠.
위에서 초보자라도 쉽게 할수 있다고 언급했습니다만. 이 방법이야말로 가장 간단한 방법이라고 생각합니다.
왜. 이미 모든 코드를 작성한 상태에서도 각 박스모델에 몇줄씩 추가/수정만 해주는 것으로도 호환성 상승을 노릴수 있기 때문이죠.
자. 가로와 세로가 각각 100px인 박스에 padding 10px, margin 10px, border 1px를 준다면,
표준으로는 이렇게 적어야 다른 브라우져에서 IE와 같은 모델이 보입니다.

예제2-표준

DIV.TEST {
WIDTH: 78PX;
HEIGHT: 78PX;
PADDING: 10PX;
MARGIN: 10px;
BORDER: 1PX SOLID #000000;
}


그러나. 이 박스모델 코드를 해석하는 방식이. IE가 표준이 아니기 때문에 오히려 IE에서 깨지는 현상이 생겨버리는 것입니다.
IE 쪽을 쓰기 위해서는 그냥 가로세로 사이즈를 100px를 적으면 됩니다만 그러자니 다른 브라우져에서 깨지고....
해서, 위의 코드를 적은 뒤 아래에 IE에서만 인식하는 다음의 코드를 추가해 주는 방법으로 해결할수 있습니다.

* html DIV.TEST{
WIDTH: 100PX;
HEIGHT: 100PX;
}



* html ~~ 은 IE에서만 인식되는 특수한 selector라고 합니다. 저도 이유는 잘 모르겠습니다-_-
중요한 사실은 오로지, "* html ~~ 를 적어줌으로써 표준인 코드를 비표준인 IE에도 맞출수 있다" 는 것일 뿐이겠죠.

결론적으로, 가로와 세로가 각각 100px인 박스에 padding 10px, margin 10px, border 1px를 주고 싶을때.
표준과 IE에서 전부 잘 작동하는 코드를 만들고 싶다면 다음과 같이 작성하면 간단하게 해결할수 있습니다.

예제3-절충안

DIV.TEST{
WIDTH: 78PX;
HEIGHT: 78PX;
PADDING: 10PX;
MARGIN: 10px;
BORDER: 1PX SOLID #000000;
}

* html DIV.TEST{
WIDTH: 100PX;
HEIGHT: 100PX;
}



●중요!
이미 써져있는 코드를 수정할 경우, * html ~~ 을 각 박스 아래쪽 라인에 추가한 뒤,
원래의 수치는 * html ~~ 쪽으로 옮기고, 이미 써져 있던 수치는 margin은 제외하고 padding, border 사이즈를 빼서 적어주면 됩니다.
ex) 가로, 세로 100px에 padding 10px, border 1px라면. 100px - (20+2)= 78px 입니다.



<참고 이미지>
사용자 삽입 이미지

왼쪽은 파이어폭스, 오른쪽은 인터넷 익스플로러입니다.
IE전용이 파이어폭스에서는 크게 나오는 반면, 표준은 IE에서 작게 나옵니다.
절충안을 사용하면 두개의 브라우져에서 완전히 같은 박스모델이 구현 가능합니다.




이쪽에 대해서는 사실 크게 깊은 지식이 없기에 다소의 오류를 포함하고 있을수도 있습니다.
하지만. 위에 언급한 방법은 실제 사용해 본 결과, IE및 다른 브라우져에서도 완전히 같이 동작한다는 것을 확인하였기에 이렇게 소개해 봅니다.

이글루스에서 스킨을 직접 만드시는 분들.
특히 기존 스킨의 수정이 아닌 완전히 새로 만들 경우에 한해 호환성이 문제가 될 경우가 가끔 있습니다.
(물론, 이글루스 자체는 다른 브라우져에서 잘 보이는 편이고, 공개 스킨 또한 잘 보입니다만 가끔씩 과격한 모딩이 되어있는 스킨은 깨질때가 있습니다)

실로 간단한 방법입니다만.
이 팁으로 인해 리퍼러에 약 몇%만을 차지하는 소수의 타 브라우져 사용자들에게도 떳떳하게 블로그를 보일수 있었으면 하는 바램입니다.

참고 링크: 한국 모질라 포럼

덧붙임:
이 글은 한국 모질라 포럼의 웹 표준화 프로젝트 계시판에서 CSS 박스 모델 문서를 참조하였습니다.

출처 : 안티에고이스트
    

설정

트랙백

댓글

blog를 접하면서....

Miscellaneous/Story 2007. 2. 21. 11:05

블로그를 시작하면서 그동안 내가 너무 모르는 것들이 많았구나 하는 생각을 하게 된다. css, html.. 사실 html은 대학교를 다니면서 홈페이지를 만들기 위해서는 몇백개 되는 코드를 이용해서 만들 수 있다는 것에서 처음 접하게 되었는데 실무에서 직접 html을 다루지 않다보니 아는게 별로 없는 듯 싶다...

css도 예전보다 많이 변한 듯 싶다. class 개념으로 지금은 예전보다 사용하기 편하고 관리하기 편한 구조화가 가능해 진 듯 싶다. 쿠쿠 이게 언제때 이야기인데 그러나 하시는 분들도 있지 않을까 싶은데 나는 모든게 새롭게 다가오니, 내 분야가 아니더라도 평소에 조금의 관심은 갖고 있어야 무식하다는 소리를 듣지 않을 듯 싶다...

트랙백, 개념적으로는 다른 사람이 쓴 글을 다른 곳에서 댓글을 달 수 있고 상호 커뮤니케이션이 이루어 질 수 있도록 하는 개념이라고 들은 것 같은데...쿠쿠 실제로 블로그를 하다보니 당췌 어찌 써야 하는 것인지 모르겠다. 트랙백 주소를 클릭하면 복사가 되긴 하는데 그걸 어디다가 써먹는지 모르겠다는... 며칠 낑낑대며 찾아다니다보면 알게 되겠지만 이 또한 생소한 용어다.

IT는 내가 잠시 다른 것에 한눈을 팔때 사과가 수박이 되기도 하는 것 같다. 차례 때문에 수박 1/4쪽을 1만5천원에 샀다고 했는데... 냉장고에 있는 수박을 급습해야 겠다... 갑자기 먹고 싶네~ 쿠쿠


    

설정

트랙백

댓글

RGB Color Cop(컬러피커)

Design/Etc 2007. 2. 21. 11:04
  1. 사용자 삽입 이미지
    Eyedropper
    Just click and drag the eyedropper anywhere on the screen to select a new color. Single pixel or 3x3/5x5 average sampling options are available.
  2. Magnifier This control works exactly like the eyedropper. It can be used to zoom in on an area of the screen. After zooming, you can click in the magnifier view to select a color. The plus and minus buttons can be used to change the magnification level before or after magnifiying an area.
  3. Auto-copy to clipboard With this option enabled, the output value will automatically be copied to the clipboard.
  4. Multiple output options
    HTML hex, Delphi hex, Powerbuilder, Visual Basic, Visual C++, RGB float, RGB int
  5. Color options
    Snap to WebSafe, Detect WebSafe, Reverse, Random, Convert to Grayscale
  6. Relative position measuring Press the Control key while eyedropping and the coordinates will be set to zero (0,0). When you drag the mouse to a new location, the coordinate values will be relative to the point.
  7. Color History The last 7 colors selected will appear in the color history. To select a previous color, simply click on it. Colors can be pushed into the color history by right clicking while eyedropping.
  8. Complementary color palette 42 colors that complement the current color will be generated on the fly.
  9. System tray support The application can be minimized to the system tray.
  10. Mouse wheel support Spin the mouse wheel while magnifying to change the magnification level. Spinning the mouse wheel while focus is on either of the Red, Green, or Blue edit controls will increment or decrement by 1(hold shift for +/- 2, hold control for +/- 5).
  11. Other minor features RGB Float mode will output the color as 0.50,0.25,0.00 Alt+[ will decrease floating point precision and Alt+] will increase floating point precision.
    The standard windows cross hair cursor can be used in lieu of the eyedropper cursor.
    Omit the # or $ symbols from the hex codes
    Upper or Lowercase hex output


사용자 삽입 이미지
Color Cop은 3.0 부터 사용해 왔다. 지금은 5.4.2버전까지 나와 있다. 웹 작업을 하다보면 자주 컴퓨터 화면의 특정 부분의 컬러를 축출하여 사용하는 경우가 많은데 이럴때 유용한 유틸이다.

컴퓨터 화면에서 보여지는 특정 픽셀의 컬러를 바로 축출할 수 있고 프로그램 자체도 가볍기 때문에 웹과 관련된 작업하는 분들에게는 작지만 아주 유용한 프로그램이 아닐까 생각된다.

프로그램은 http://prall.net/ 에서 다운로드 가능하며 필요한 분들은 아래 파일을 첨부하니 다운로드 하시면 된다.
사용법은 첨부한 압축파일을 풀고 exe파일을 실행.

invalid-file

버전 4.0

invalid-file

버전 5.4.3



 

    

설정

트랙백

댓글

[UI&C] Crop BitmapData

Project/UI&C Lab 2007. 2. 21. 11:03
이번에는 BitmapData를 이용하여 특정 무비클립을 bitmap으로 전환하고 다시 무비클립으로 되돌리는 클래스를 제작한 이후에 재미난 기능을 추가했다.

플래시 8의 bitmapData 클래스가 아니라면 예전에는 상상도 못할 구현이 가능해졌다. 플래시로 만든 마술이라고 해야할까...;;

사용자 삽입 이미지

위에 보이는 이미지는 중앙에 있는 crop 버튼을 누르게 되면 현재 화면에 보여지고 있는 오른쪽 네비게이션을 포함한 화면에 보여지는 모든 무비클립을 하나의 BitmapData로 전환하고 기존에 있던 무비클립을 visible = false를 적용한다. 이렇게 하면 화면에서 event가 발생하는 모든 것들은 bitmapData로 전환되기 때문에 작동하지 않는다.

여기서 화면에서 특정 좌표에 마우스로 클릭하고 사각 박스를 드레그하여 영역을 잡게 되면 그 영역을 새로운 bitmapData로 전환하여 무비클립을 생성하게 되는데 그 무비클립을 마우스로 press and drag하면 그 부분만 따로 분리하게 만들어 졌다. 화면에 보여지는 것처럼 rectangle로 선택한 영역을 따로 분리되는 것을 볼수가 있다.

ctrl 키를 누르게되면 순차적으로 다시 제자리로 되돌아간 이후 기존에 있던 무비크립으로 대체된다.

사용자 삽입 이미지

이것은 위의 것을 조금 응용한 모션이다. 중앙에 있는 crop 버튼을 누르게되면 화면에서 random 좌표의 사각 박스가 화면에서 분리되어 위로 올라가게 된다. _y값 모션에서 blur 필터를 적용하였다. 모두 올라간 이후에는 ctrl 키를 누르면 다시 각각의 영역이 자신의 자리로 되돌아 오게 된다.

이번 아이디어의 구상은 처음 원하는 무비클립을 bitmapData로 전환하고 되돌리는 클래스를 제작한 이후에 파생된 모션 형태이다. 이것은 많은 부분에서 활용도가 높을 것으로 예상된다. 예를 들면 처음 모션이 이루어진 이후에 더이상 움직임이 없는 배경의 경우는 이렇게 bitmapData로 전환하게 되면 모션을 주기 위해서 생성했던 많은 무비클립들을 하나의 무비클립으로 대체할 수있어 리소스 낭비를 줄일 수 있는 점이 있을 것이고, 화면전환효과에서 이를 활용하면 다양한 형태의 전환효과를 만들어 낼 수 있을 것으로 예상된다.

    

설정

트랙백

댓글

[UI&C Lab] Clip Navigation

Project/UI&C Lab 2007. 2. 21. 11:02

사용자 삽입 이미지
 
무비클립 생성 화면
 
클립 형태의 네비게이션을 만들어볼 생각으로 만든 기본적인 무비클립 생성이다. 생성된 무비클립들의 _rotation을 통해서 모션을 적용하였다.
 
사용자 삽입 이미지
스케일 조정 화면

사용자 삽입 이미지
네비게이션 무비클립 생성
 
앞에서 만든 기본적인 무비클립 생성을 통해서 각각의 무비클립에 event를 적용하였다.
각 무비클립을 클릭했을 때의 모션으로 선택된 무비클립의 rotation을 0으로 하며 나머지는 특정 rotation값을 적용하고 무비클립이 포함된 무비클립의 좌표를 왼쪽 상단으로 위치시켰다.
Back 버튼을 통해서 다시 펼쳐진 형태로 되돌아 가는데 클릭할 때 적용했던 scale을 그대로 적용함으로서 클릭하기 전의 형태를 유지하도록 하였다.

사용자 삽입 이미지
특정 무비클립 클릭시 모션 적용

사용자 삽입 이미지
컨텐츠 view 화면 back 버튼을 누르면 초기화면으로 모션 적용

사용자 삽입 이미지
네이게이션 무비클립 생성
 

사용자 삽입 이미지
특정 무비클립 클릭시 모션 적용

사용자 삽입 이미지
컨텐츠 view 화면 scale을 통해서 줌인 형태로 화면을 채움

사용자 삽입 이미지
 
BACK 버튼을 눌렀을때 화면으로 되돌아 가는 모션
 
 
clip_navi_2번과 같은 로직으로 구성하였으나 무비크립을 클릭했을 때 무비클립 전체가 scale이 커지면서 보여지는 화면을 채우는 형태로 제작하였다.
이것 또한 2번과 같이 back 버튼을 누르면 기존의 형태로 되돌아 간다.
 
이로써 간단한 _rotation의 Tween을 통한 재미있는 네비게이션이 만들어진듯 하다.
    

설정

트랙백

댓글

무비클립 60만개로 만든 바탕화면

Design/Etc 2007. 2. 21. 11:02
사용자 삽입 이미지
    

설정

트랙백

댓글

[UI&C Lab] Create Random MovieClip

Project/UI&C Lab 2007. 2. 21. 11:01
사용자 삽입 이미지

Create Random MovieClip_1

stage의 특정 random 영역에 무비클립을 생성한다. 생성할 때는 중심점이 되는 new Point(x,y)좌표점을 rnadom으로 설정하므로써 그룹단위로 무비클립을 생성하게 된다. 여기서의 문제점은 무비클립이 많아지면 많아질수록 CPU의 과부화 문제가 발생한다. 노트북에서는 무비클립 300개 이상이되면 그때부터 현저하게 속도 저하가 발생한다.

사용자 삽입 이미지

Create Random MovieClip_2

앞의 버전에서 발생한 CPU 문제점을 BitmapData를 통해서 해결한 버전이다. 생성 방법은 앞과 동일하며 그룹단위(무비클립이 30개 단위로 그룹으로 묶는다 if count%30 == 0)

한 그룹이 완료되었을 때 BitmapData를 통해서 화면에 보여지는 무비클립들을 빈 무비클립으로 생성한 무비클립에 draw하고 생성했던 30개의 무비클립을 remove 시킨다. 그리고 다시 30개의 그룹이 완료되면 또다시 밑에 있는 BitmapData로 그린 무비클립과 새로 생성한 무비클립을 다시 BitmapData로 draw시킨다.

이렇게 진행하면 쌓이는 무비클립이 30개 이상을 넘지 않기 때문에 생성하는 무비클립의 갯수가 무한정 늘어난다고 하여도 CPU의 문제는 없다.

진행을 하면서 오류를 범했던 부분은 BitmapData를 draw시키는 무비클립을 draw 시킬때 마다 새로 생성하지 않고 같은 무비클립에 draw시킬 경우에 기존의 draw시킨 무비클립이 메모리에 쌓이는 문제로 인하여 CPU문제가 그대로 존재한다는 것이었다. 이는 30개 그룹단위로 draw시킨때 같은 depth에 새로 무비클립을 생성하여 기존의 무비클립을 삭제하는 형태로 해결하였다.

BitmapData로 draw시킬때 alpha 값을 50%으로 설정하여 draw시키는 시점과 30개의 무비클립이 삭제되는 시점을 화면에 보여주고 있다

사용자 삽입 이미지
Create Random MovieClip_3
 
앞의 구조와 같다. 앞의 경우는 draw시키는 시점을 alpha = 50으로 보여주었으나 여기서는 Bitmap에 blur 필터를 적용한 것이다.
var filter = new BlurFilter (2, 2, 1);
bitmap.applyFilter (bitmap,bitmap.rectangle, new Point (0, 0) , filter);
 

사용자 삽입 이미지
 
Create Random MovieClip_4
 
앞에서 연구한 결과를 가지고 비주얼적으로 표현할 수 있는 방법으로 이와 같은 형태로 작업을 진행하였다.
 
이것은 앞의 것들과 무비클립의 생성과정은 동일하다. 여기서 해당 무비클립이 그룹단위로 생성할때 자신의 고유색을 가지고 생성을 하는데 그 색은 Shift버튼을 누르면 나타나는 background 이미지의 pixel단위 RGB를 축출하여 적용하였다.이미지의 사이즈가 작기 때문에 앞의 것들보다 무비클립을 작게 하였다.
 
사용자 삽입 이미지
 
Shift 버튼을 눌렀을때 배경을 볼 수 있다.
 
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지

Create Random MovieClip의 가장 중요한 부분은 화면에 나타난 무비클립이 변형되지 않는다는 전제조건이 있을 경우에는 해당 무비클립을 stage에 남겨두는 것이 아니라 remove 시키되 기존의 이미지가 그대로 남도록 BitmapData를 사용하여 특정 무비클립에 draw시키므로써 수많은 무비클립의 생성으로 발생하는 플래시의 전체적인 cpu 문제점을 해소하는 것에 중점을 두었다.
    

설정

트랙백

댓글

[UI&C Lab] graph

Project/UI&C Lab 2007. 2. 21. 11:01
예전 모 클라이언트가 그래프를 플래시로 제작하고자하여 만들었던 그래프다. 기본적인 형태는 xml을 로그하여 데이터를 보여주게 되는데 그래프가 나타날때 다이나믹한 모션 효과를 주었다. 시간이없어서 재사용성을 고려하지 않고 만들었던 아쉬움이 있는데 나중에 다용도로 사용할 수 있는 그래프 컴포넌트를 만들어볼 생각이다.
사용자 삽입 이미지


    

설정

트랙백

댓글

[UI&C Lab] trapezoid navigation

Project/UI&C Lab 2007. 2. 21. 11:00
사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

trapezoid navigation 은 좌우로 슬라이드되는 형태의 네비게이션을 만들기 위해 만들었는데 여러장을 적용했을 경우 CPU문제가 있어서 잠시 보류중이다. 이것은 무비클립을 좌우로 사다리꼴모양으로 외곡시켜기 중앙에 위치했을 때는 무비클립을 사용할 수 있도록 만들어 졌다.
 
    

설정

트랙백

댓글

[UI&C Lab] BitmpData Characters...

Project/UI&C Lab 2007. 2. 21. 10:59
이번은 BitmapData를 이용하여 배경 이미지의 색을 축출하여 문자가 포함된 무비클립의 색을 변경하는 작업을 해봤다. 이미지의 윤곽을 잘 보이도록 하기 위해서 무비클립의 갯수를 늘려 6000개가 넘어가니 무비클립을 생성할 때와 색을 입힐때 다소 처리 시간이 지연되는 경향이 있다...
사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지


    

설정

트랙백

댓글

[UI&C Lab] distort bitmapData...

Project/UI&C Lab 2007. 2. 21. 10:59

사용자 삽입 이미지
 
bitmapData를 이용하여 rectangle의 상하좌우의 좌표를 이용하여 이미지를 외곡하는 클래스를 통해서 3D 육면체와 유사한 네비게이션을 만들어 보면 어떨까하는 생각에서 시작했다. 요즘들어 bitmapData를 이용하여 그러한 화면전환 효과를 보여주는 사이트들이
심심치않게 보인다. 4개의 좌표를 이용하여 이미지 또는 무비클립을 외곡시킬수 있어서 다양한 형태로 적용이 가능할 것으로 생각된다.

사용자 삽입 이미지
 
이것은 위의 기본적인 4개의 좌표를 이용하여 왼쪽과 오른쪽 화면전환을 할 수있도록 제작하였다. 여기서 문제가 되었던 부분은
현재 화면이 왼쪽으로 out하는 것과 오른쪽으로 in하는 것, 그리고 왼쪽의 이미지가 오른쪽에서 in하는 것과 오른쪽으로 out하는
메소드를 따로 만들어야 했다. 기본적인 구조는 같으나 여러가지 유기적으로 연결되어야 하는 좌표가 있어서 찜찜하지만
서로 다른 메소드로 구현을 했다.
 
또하나의 문제점, bitmapData를 이용하여 픽셀들의 값을 얻어 뿌려주는 과정에서 기존의 이미지 정보를 지우고 새로운 이미지를 쓰게 되는데 이때 이미지가 깜박거리는 문제점이 있다 심한 깜박임은 기존의 이미지를 최상위 뎁스로 이동시키고 그 아래에서 뿌려주는 것으로 해결했지만 바람직한 방법은 아닌듯 싶다.

사용자 삽입 이미지
 
이것은 기존의 구조를 그대로 사용하되 이미지를 대신하여 input textField를 넣어 사용자가 입력할 수 있도록 하였다.
bitmapData를 통해서 무비클립의 모양을 데이터를 취득한 이후에는 해당 무비클립에 입력텍스트필드가 있다고 하여도 그것은 하나의 이미지 정보를 가지고 있는 이미지일 뿐이기 때문에 입력하지 못한다.
 
구조는 이러하다. 이런 형태의 화면전환을 하고자하는 무비클립과 그 무비클립이 포함될 경로(무비클립)을 플래스 생성시에 전달받으면 어떠한 무비클립이도 이러한 형태로 화면전환이 가능하다. 이는 적용하고자 하는 무비클립 안에서 프레임으로 화면의 페이지를 넣어두었고 클래스 내에서 해당 무비클립의 프레임을 이동한 무비클립을 복제하였다. 그리고 bitmapData를 통해서 모션이 이루어지고 마지막 정지 시점에서 bitmapData를 통해서 모션을 주었던 무비클립을 제거하고 그 자리에 해당 무비클립을 바꿔치기 하는 방법으로 진행하였다. 그리고 다시 모션이 이루어지기 전에 현재 보고있는 화면의 bitmapData를 다시 draw하여 기존에 있는 bitmapData를 통해서 만들어진 무비클립을 대체하는 것으로 마치 bitmapData를 사용하지 않고 무비크립을 distrot 시키는 것 같은 효과가 가능하게 되었다. 위에 보이는 텍스트는 사용자가 작성하는 것으로 모션을 줄 수가 있다.
 
클래스 생성에서 넘겨주는 파라미터 값은 현재 무비클립과 적용한 무비클립으로 단 두개의 파라미터만을 넘겨주며 그 무비클립의 이미지 사이즈에 따라서 계산처리하기 때문에 화면전환 효과에 적용하기가 단순하여 사용하기 쉽다는 것이 강점일 듯 싶다.
 
 
모델 : 밍밍이...
    

설정

트랙백

댓글