4. contents
1. 왜 웹 기술로 만들었나?
2. 어떤 Angular.js 구조로 만들어졌을까?
3. 성능과 관련 있는 Angular.js Things
4. 그밖에 알아두면 좋은 Angular.js Things
5. PSD 파싱은 어떻게 했을까?
6. 테스트 자동화는?
7. 마치며
7. 1.1 왜 웹 기술로 만들어졌을까?
• 기획의 최종 목표는 웹 서비스로 제공.
• 그렇지만 웹툰 작가님들이 Offline 으로 작업 가능 해야함.
• 작가님들 PC는 대부분 Windows 이지만 Mac도 있음.
• 두가지 방법이 있음.
OS별
Native Application
Platform-Neutral
WebApp
Why Platform-Neutral
11. 2.1 복잡한 Angular.js 구조
Flexible
1. Angular.js는 DOM에 Controller를 자유롭게 연결 할 수 있고,
2. ng-include를 이용하여 View를 짜집기 할 수 있으며,
3. Directive를 이용해 UI 컴포넌트를 만들수도 있고,
4. Helper로 만들 수도 있다.
14. 2.2 쉽고 간결한 Angular.js 구조
머리 - Controller
다리 - Directive
팔, 몸통 - Directives
Body Structure Pattern
15. 2.2 쉽고 간결한 Angular.js 구조
Define Directives
effects
pages content layers
applied-effects
16. 2.2 쉽고 간결한 Angular.js 구조
Attention
여기서 주의할 점은,
1. 한 페이지의 Main Controller는 하나이고,
2. ng-include는 Directive 내에서만 꼭 필요할 때만 사용하며,
3. Directive와 View는 1:1 매칭한다.
4. Directive의 역할이 커질수록 Service와 Factory를 이용하고,
5. 필요에 따라 사람의 소뇌 성격의 Controller가 추가 될 수 있다.
17. 2.3 외부 패키지 관리 방법
Package Managing Rule
• Bower뿐만 아니라 NPM을 이용해서 모듈을 설치 가능
• 예를 들어 underscore.js 를 설치하려고 했을 때,
Bower를 이용할지, NPM을 이용할지 고민해야 한다.
1. 순위 : Bower 이용
2. 순위 : NPM 이용
• 이유 : 최대한 Front-end모듈로 작성을 해야 추후 웹서비스로 만들때, NPM을
이용한 모듈만 Back-end로 작성하여 AJAX 통신하면 기존 코드에서 큰 수정
없이 작동 가능하기 때문이다.
27. $scope 의 변수가 반영되는 조건은,
1. DOM 이벤트(ng-click, ng-mousedown, …)가 발생
2. $http와 $resource에서 응답이 돌아왔을 경우
3. $location에서 URL을 변경한 후
4. $timeout이벤트가 발생한 후
5. $scope.$apply()나 $scope.$digest() 호출
4.1 외부 모듈 사용하여 개발할 때,
jQuery나 Node.js 또는 Custom Event 를 이용할 시,
Angular.js의 $scope 내의 값이 변하지 않는다.
in Controller : $scope.$safeApply();
in Directive : scope.$root.$safeApply();
28. Directive 로 컴포넌트를 만들때 initialize()를 DOM과 같이 할 때가 있다.
하지만, Directive 에는 DOM Ready Event가 없다.
4.2 Directive DOM Ready
DOM 렌더링 완료 Event는 $timeout() 메소드로 대체 할 수 있다.
그렇지만 $timeout() 보단 setTimeout() 을 이용하자.
$timeout() 을 이용하면, 불필요한 Dirty Checking을 수행하여 성능 저하를 초
래 할 수 있다.
29. 4.3 Undo/Redo
Editor 작업을 총괄하는 하나의 Object(workspace) 이용,
History 추가시 Object Snapshot 을 저장
memento-promise : http://goo.gl/ZQwBY3
35. 6.2 End to End Test
http://angular.github.io/protractor
36. 6.2 End to End Test
https://github.com/nwjs/nw.js/wiki/chromedriver
1. 셀레니움 다운로드
2. http://dl.nwjs.io/ chromedriver 다운로드
3. nw or nw.exe(win),
or node-webkit.app(osx) 다운로드
4. 모두 같은 디렉토리에 넣음
5. java -jar selenium-server-standalone-VE
R.jar
-Dwebdriver.chrome.driver=./chromedri
ver
6. npm install wd (프로젝트 폴더)
48. 1.1 스크롤 이벤트 연속성: iOS
Safari UIWebView WKWebView
iOS7 X X N / A
iOS8 O X O
49. 1.1 스크롤 이벤트 연속성: iOS
<div style=“
overflow: auto;
”></div>
<div style=“
overflow: auto;
-webkit-overflow-scrolling: touch
”></div>
스크롤 이벤트 연속성 O
스크롤 가속도 X
스크롤 이벤트 연속성 X
스크롤 가속도 O
50. 1.1 스크롤 이벤트 연속성: iOS
document.body.addEventListener(“touchmove”, function () {
console.log(document.body.scrollTop);
});
touchmove 이벤트는 연속적으로 발생하기는 하지만
이 상태에서 갱신된 실제 스크롤 위치를 얻을 수는 없다.
51. 1.1 스크롤 이벤트 연속성: iOS
setInterval(function () {
console.log(document.body.scrollTop);
});
사용자가 스크롤 하는 동안 타이머를 포함한 자바스크립트
동작이 멈추므로 setInterval 이나
requestAnimationFrame 같은 타이머 함수로도 연속적인
스크롤 위치 정보를 얻을 수는 없다.
52. 1.1 스크롤 이벤트 연속성: iOS
User Agent String
네이버앱
Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like
Gecko) Mobile/12B440 NAVER(inapp; search; 390; 6.0.2)
라인
Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like
Gecko) Mobile/12B440 Safari Line/5.1.1
카카오톡
Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like
Gecko) Mobile/12B440 KAKAOTALK
페이스북
Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like
Gecko) Mobile/12B440
[FBAN/FBIOS;FBAV/28.0.0.10.10;FBBV/8930087;FBDV/iPhone7,2;FBMD/iPhone;FBSN/iPhone
OS;FBSV/8.1.2;FBSS/2; FBCR/SKTelecom;FBID/phone;FBLC/ko_KR;FBOP/5]
UA string 은 UIWebView 와 WKWebView 가 완전히 같다.
Tip. iOS8 WKWebView 구분하는 방법:
53. 1.1 스크롤 이벤트 연속성: iOS
iOS8
WKWebView
iOS8
UIWebView
iOS7
UIWebView
WebGL3D O O X
CSS Shapes O O X
Indexed DB O X X
HTML5
Coverage Score
440/555 427/555 410/555
UA string 으로 WebView 가려낸 뒤 indexedDB 지원 여부 확인
Tip. iOS8 WKWebView 구분하는 방법:
54. 1.2 스크롤 이벤트 연속성: Android
단말기
OS
버전
실행환경
스크롤 이벤트
연속성
브라우저 엔진
갤럭시
S3
4.1.2
S Browser Good AppleWebKit/534.30
Chrome Good AppleWebKit/537.36
NAVER App. Good AppleWebKit/534.30
갤럭시
S4 mini
4.2
S Browser Bad Chrome/18.0.1025.308
Chrome Good Chrome/42.0.2311.111
NAVER App. Good AppleWebKit/534.30
갤럭시
S4
4.3
S Browser Good Chrome/28.0.1500.94
Chrome Good Chrome/28.0.1500.94
NAVER App. Good AppleWebKit/534.30
갤럭시
S5
4.4.2
S Browser Bad Chrome/28.0.1500.94
Chrome Good Chrome/42.0.2311.111
NAVER App. Good Chrome/30.0.0.0
갤럭시
S4
4.4.2
S Browser Bad Chrome/28.0.1500.94
Chrome Good Chrome/42.0.2311.111
NAVER App. Good Chrome/30.0.0.0
단말기
OS
버전
실행환경
스크롤 이벤트
연속성
브라우저 엔진
갤럭시
S4 mini
4.4.4
S Browser Bad Chrome/28.0.1500.94
Chrome Good Chrome/42.0.2311.111
NAVER App. Good Chrome/33.0.0.0
갤럭시
노트4
4.4.4
S Browser Good Chrome/34.0.1847.76
Chrome Good Chrome/42.0.2311.111
NAVER App. Good Chrome/33.0.0.0
갤럭시
노트4
5.0.1
S Browser Bad
Chrome/34.0.1847.76
SamsungBrowser/2.1
Chrome Good Chrome/39.0.2171.93
NAVER App. Good Chrome/37.0.0.0
갤럭시
S6
5.0.2
S Browser Good Chrome/38.0.2125.102
Chrome Good Chrome/39.0.2171.93
NAVER App. Good Chrome/37.0.0.0
Android 4.1+ : 일부 삼성 브라우저를 제외하고 연속적인 스크롤 이벤트 제공
55. 1.2 스크롤 이벤트 연속성: Android
예외 #1.
1. 스크롤 이벤트는 연속적이지만 화면 갱신이 느린 경우
2. 스크롤 이벤트에서 스타일 변화를 주면
브라우저 크래시 되는 경우
(Android 4.1.2 Chrome/42.0.2311.111)
Android 4.1.2 WebView (NAVER App), Chrome, S-Browser
Android 4.2.0 WebView (NAVER App)
56. 1.2 스크롤 이벤트 연속성: Android
예외 #2.
스크립트 스크롤 (iscroll.js) 영역의 높이가 긴 경우
브라우저 앱 충돌 발생 (Fatal signal 11 SIGSEGV)
Android 4.4.2 WebView (NAVER App. Chrome/30.0.0.0)
57. 1.3 스크롤 이벤트 특성
Event Type Sync/Async
Trusted event target
types
DOM interface
scroll Async Document, Element UIEvent
wheel Async Element WheelEvent
mousemove Sync Element MouseEvent
click Sync Element MouseEvent
load Async
Window,
Document,Element
Event
http://www.w3.org/TR/DOM-Level-3-Events/
scroll 이벤트 자체가 비동기적 이벤트
58. 1.4 스크립트 스크롤의 활용
scroll 이벤트가 없으면 만들면 되지:
touchmove 이벤트를 이용해 마치 스크롤 하는 것 같은 느낌을 준다
<div style=“overflow: hidden;”>
<div style=“transform: translate3d(0, -100px, 0);”>
…
</div>
</div>
JMC, iscroll.js, ScrollMagic, Skrollr …
59. 1.4 스크립트 스크롤의 활용
그런데, 효과툰 한 편의 콘텐트를 스크립트 스크롤 영역에 넣으면 …
Size: 638 x 72049px
Memory: 175Mb
60. 1.4 스크립트 스크롤의 활용
개선 #1.
하나의 거대한 <div> 대신 해당 구간의 작은 <div> 를 움직이자
Size: 360x40201
Memory: 55.2Mb
Size: 360x640
Memory: 900Kb
61. 1.4 스크립트 스크롤의 활용
개선 #2.
활성 상태로 만들 페이지 구간을 현재 페이지 기준 전후 일정 개수에서
현재 스크롤 위치 기준 화면 크기만큼 전후 구간에 포함되는 페이지로
62. 1.4 스크립트 스크롤의 활용
Q. 화면 안에 들고 날 때마다 display 속성을 변경 한다는 말인가요?
A. 네
Q. Display 속성을 변경하면 Layout (Reflow) 발생할 텐데요?
A. 알아요
Q. 그걸 아는 사람이 그래?
A.
63. 1.4 스크립트 스크롤의 활용
그대로 두면 그래픽 레이어 과다로
메모리 문제 발생
à display 속성 제어가
성능 저해 요소지만 유일한 해법
구간 안에 존재하는 레이어 수가 한정되어 있어서
Reflow 비용이 비교적 적은 편이라 가능한 것이기도
display: none 으로 레이어 제거 비용보다는
display: block 으로 레이어 생성 비용이 더 큼.
64. 1.4 스크립트 스크롤의 활용
레이어의 생성 비용은 크기에 비례:
적당한 크기로 나누어 줄 필요가 있다
iOS Safari 기준 최대 이미지 크기
가로 x 세로 <= 1024 x 1024 x 3
https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/
CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html
65. 1.4 스크립트 스크롤의 활용
- 네이버 효과툰 저작툴에서 [페이지 나누기] 기능을 제공
- 일정 크기 이상의 이미지는
자동으로 분할:
정해진 크기 단위가 아니라
컷 사이 여백을 고려한
자연스러운 이미지로 분할
X O
66. 1.4 스크립트 스크롤의 활용
개선 #3.
scroll 이벤트:
스크롤에 따라 활성 구간에 들어가는 페이지만 이미지 로딩
= <img> src 지정하는 순간 Paint (Image Decode) 발생
scrollEnd 이벤트 CustomEvent:
스크롤이 잠시 멈췄을 때 = 사용자가 현재 로딩 된 구간을 보는 동안
다음 구간의 이미지를 불러오기 (pre-load)
+ 미리 Image Decode 해두기 (pre-paint)
67. 1.4 스크립트 스크롤의 활용
개선 #3.
Pre-paint 사용 전
Pre-paint 사용 후
스크롤 멈춘 시점들
스크롤 시작한 시점들
68. 1.4 스크립트 스크롤의 활용
개선 #4.
CSS3 Transform 사용시 GPU 가속을 받는 속성을 사용한다
scale, opacity 사용시에도 주의!
transform: scale(x,y) à
transform: scale3d(x,y,0)
opacity: n à
opacity: n;
transform: translateZ(0)
CSS3 Transform 속성이 변화할 때
Layout 이 계속 발생한다면 GPU 가속 여부 확인!
69. 1.4 스크립트 스크롤의 활용
스크롤 스크립트 영역 바깥에 이미 HTML 요소가 들어있으면?
iscroll
footer
- 스크립트 스크롤 영역 끝까지 도달하면 비활성화
Iscroll.on(“scroll”, function () {
if (Iscroll.y === Iscroll.maxScrollY) {
Iscroll.disable();
}
});
window.addEventListener(“scroll”, function () {
if (window.scrollY === 0) {
Iscroll.enable();
}
});
- 네이티브 스크롤 위치가 문서 처음이면 활성화
72. 2.2 HTML5 Audio의 한계
HTML5 Audio (Element)
다양한 환경에서 쉽게 사용할 수 있지만
동시에 여러 리소스 재생은 불가능
https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/
Device-SpecificConsiderations/Device-SpecificConsiderations.html
mediaGroup (controller) 속성을 이용해 동시 재생하는 방법이 있지만
같은 그룹 내의 사운드를 개별적으로 재생할 수는 없음.
https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/
ControllingMediaWithJavaScript/ControllingMediaWithJavaScript.html
73. 2.2 HTML5 WebAudio API의 활용
WebAudio API
웹 어플리케이션에서 오디오 데이터를
Processing/Synthesizing 할 수 있는 고수준 API
= 동시에 여러 사운드 리소스 재생 가능
http://www.slideshare.net/deview/2-hello-world-web-aaudioapi
Source GainNode Destination
AudioContext
var context = new AudioContext();
var gainNode = context.createGain();
var source = context.createBufferSource();
source.buffer = ArrayBuffer;
gainNode.gain.value = 1.0; // volume
source.connect(gainNode);
gainNode.connect(context.destination);
source.noteOn(0); // play
74. 2.2 HTML5 WebAudio API의 활용
WebAudio API available on:
https://gist.github.com/NielsLeenheer/4daa6a9ce7f4a0f4733d
http://caniuse.com/#feat=audio-api
MSIE Edge, FireFox 25+, Chrome 10+
iOS 6+, Android 5.x+ (Chromium 40+)
갤럭시 S4
삼성 브라우저 1.5 (Chromium 28)
Android 4.3 / 4.4.2 / 4.4.4 / 5.0.1
+
75. 2.2 HTML5 WebAudio API의 활용
WebAudio API 가 제공되기는 하는데…
https://code.google.com/p/chromium/issues/detail?id=393436
https://code.google.com/p/chromium/issues/detail?id=176902
갤럭시 S4
삼성 브라우저 1.5 (Chromium 28)
Android 4.3 / 4.4.2 / 4.4.4 / 5.0.1
- Web Audio API crashes tab when decodeAudioData is called with a large
( > 15MB) arraybuffer In Chrome Version: 24.0.1312.57 m
- decodeAudioData crashes confirmed on Android 4.2.2 chrome v31~43
may be some buggy ArrayBuffer data ? but it should crash the app anyhow.
76. 2.3 자동 재생 문제
iOS
명시적인 사용자 액션에 의해서만 사운드 재생이 가능함.
On iOS, the Web AudioAPI requires sounds to be triggered from an explicit user action.
https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/
PlayingandSynthesizingSounds/PlayingandSynthesizingSounds.html
http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
단, 한 번 사용자 액션에 의해 재생을 하고나면
그 이후로는 프로그램적으로 재생 가능
As soon as the Web Audio context is “unmuted”, it will stay that way for the entire session,
and every other action won’t require a user event.
77. 2.3 자동 재생 문제
iOS
http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
window.addEventListener('touchstart', function() {
// create empty buffer
var buffer = myContext.createBuffer(1, 1, 22050);
var source = myContext.createBufferSource();
source.buffer = buffer;
// connect to output (your speakers)
source.connect(myContext.destination);
// play the file
source.noteOn(0);
}, false);
한 번 사용자 액션이 있을 때
임의의 빈 사운드를 재생해두면
그 이후로는 자유롭게
사운드를 재생할 수 있다.
78. 2.3 자동 재생 문제
http://trac.webkit.org/changeset/108831
Android
일단 사운드가 로드되면 프로그램적으로 자동 재생이 가능함
(Webkit 528+) All restrictions are removed in the first successful load() or play() call.
단,
갤럭시 S4 Android 4.3
갤럭시 노트4 Android 4.4.4
삼성 브라우저에서는 자동 재생 불가
79. 2.4 다른 음악앱 재생이 멈추는 경우
http://lab.laziel.com/when-webaudio-stops-music/
WebAudio API
var context = new AudioContext();
var gainNode = context.createGain();
var source = context.createBufferSource();
source.buffer = ArrayBuffer;
gainNode.gain.value = 1.0; // volume
source.connect(gainNode);
gainNode.connect(context.destination);
source.noteOn(0); // play
이 시점에 재생중이던
다른 음악앱 재생이 중단된다.
그러므로 .createGain() 은
실제로 사운드 재생하기
직전에 하는 것이 좋다
82. 3.2 CSS3 Transform in IE
-ms-transform 속성으로 translateX, translate 를 포함해서
rotate, scale … 등 2D transform 사용 가능.
àtranslate3d(), scale3d() 등 3D 속성은
translateX, translateY 등 2D 속성으로 변환해서 사용
IE9
DXImageTransform.Microsoft.Matrix 필터를 사용해야 한다
설마하니 2015년에도 이걸 쓰게 될 줄이야
IE8
83. 3.2 CSS3 Transform in IE
https://msdn.microsoft.com/en-us/library/ms533014(v=vs.85).aspx
- translateX, translateY 는 top, left 속성 제어
- scale, rotate 는 Matrix 필터
IE8
var scale = 3, degrees = 50;
var radian = (degrees - 360) * Math.PI / 180; // degree to radian
var cos = Math.cos(radian), sin = Math.sin(radian);
matrix.scale = parseFloat(scale);
matrix.rotate = {M11: cos, M12: -sin, M21: sin, M22: cos};
var matrixStr = ['M11=' + matrix.rotate.M11 * matrix.scale,
'M12=' + matrix.rotate.M12 * matrix.scale,
'M21=' + matrix.rotate.M21 * matrix.scale,
'M22=' + matrix.rotate.M22 * matrix.scale].join(',');
element.style.filter = 'progid:DXImageTransform.Microsoft.Matrix(' + matrixStr + ')’;
84. 3.2 CSS3 Transform in IE
http://blogs.msdn.com/b/ie/archive/2008/09/08/microsoft-css-vendor-extensions.aspx
- Opacity 는 Alpha 필터
IE8
element.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)’;
- 투명 PNG 이미지는 AlphaImageLoader 필터
element.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=”img.png")';
이 모든 필터들은 띄어쓰기로 중첩 지정 가능
85. 3.2 CSS3 Transform in IE
AlphaImageLoader 필터 사용시 주의사항
- AlphaImageLoader 필터는 모든 필터에 앞서
가장 먼저 지정되어야 한다
- AlphaImageLoader 필터와Alpha 필터를
동시 지정시 렌더링 오류 발생 할 수 있으므로
HTML 마크업을 분리하여 지정해야 한다
IE8
<div style=“filter:Alpha”>
<div style=“filter:AlphaImageLoader”></div>
</div>
86. 3.2 CSS3 Transform in IE
In Internet Explorer 7, 8, 9, non-static child elements
do not inherit the opacity of the parent.
IE8
http://www.jacklmoore.com/notes/ie-opacity-inheritance/
<div style=“filter:Alpha”>
<div style=“position: static”></div>
</div>
87. 3.2 CSS3 Transform in IE
CSS3 transform 을 적용한 엘리먼트가
부모 엘리먼트 overflow: hidden 무시하는 현상
transform 엘리먼트에 opacity 속성 부여로 해결
@media all and (-ms-high-contrast:none) {
*::-ms-backdrop, .trasformed-element {
opacity: 0.99;
}
}
IE11 @ Windows 8.1
88. 3.2 CSS3 Animation in IE
- setInterval() 타이머 함수로 대체
- @-webkit-keyframe {} 설정을 CSS 파일에 선언한 뒤
자바스크립트 정규식으로 분석해서 유사한 동작으로 변환
è 하나의 애니메이션 설정 파일로
여러 환경 동일하게 대응 가능
IE8 ~ IE9