기본 콘텐츠로 건너뛰기

UI깎는 노인-Making a knob for Mobile

Knob, 흔히들 Dial 이라고 말하는 전통적인 인터페이스가 있다.
돌리고~돌리~고~ (출처)

webAudio를 하다보니 ( http://jsbin.com/hacotahttp://output.jsbin.com/tidoqi 등등) 직관적인 UI 컨트롤러가 필요해서 잠깐 찾다가 이럴게 아니라 최소한의 요소만 뽑아내서 만들어보기로 함.

목표는 PC/Android/iOS 모두 잘 작동하도록 하는 것.
구현할 기능을 생각해보면

  1. 현재 값을 시각화하는 요소가 있을 것 - 위 사진에서처럼 음각으로 만든 홈.
  2. 경계값이 있을 것 - 12시 방향 기준으로 -140도~140도까지
  3. 클릭 후 드래그 시만 움직이고 즉각적으로 반응
정도로 잡고 일단 SVG로 원을 두개 그려본다.

      <circle cx="6em" cy="6em" r="5em"/>
      <circle class="handle" cx="6em" cy="3em" r="0.6em"/>

단위는 서로 다른 디바이스에서도 잘 보이도록 em을 써서 만든다. 1em은 글자 한글자 높이정도의 단위인데 해상도에 대한 걱정을 덜어줘서 참 편하다.
em은 이정도, 즉 1em=1글자 높이

이걸 돌려주기만 하면 된다.
돌리는 건 뭘로? css transform / rotate 를 사용한다.
두 개의 원을 그룹으로 묶어서 돌리자.

    <g class="jog" style="-webkit-transform: rotate3d(0,0,1,{{knob}}deg); transform: rotate3d(0,0,1,{{knob}}deg)">
      <circle cx="6em" cy="6em" r="5em"/>
      <circle class="handle" cx="6em" cy="3em" r="0.6em"/>
    </g>

g를 이용해 두 개의 원을 한번에 transform(-webkit-transform)으로 회전한다. 어짜피 Blaze(http://meteor.github.io/blaze/)를 사용할꺼니까 은근 슬적 {{konb}}을 끼워넣었다 ㅋㅋㅋㅋ
가로 세로 정중앙을 중심으로 회전할 것이므로 CSS에서 .jog {transform-origin: 50% 50%;} 필수체크!
여기서 주목할 것은 rotate3d를 사용한 것인데, 이는 css3 가속이 3d에서만 이루어지기 때문.
애플이 어서 Safari 를 업뎃하든 포기하든 해서 저 -webkit prefix를 그만 썼으면 하는 바램이다.

외견은 어쨌든 되었고 이제 저걸 돌려봐야하는데 마우스나 터치를 하고 있는 좌표가 큰 원의 중심으로부터 수평선을 그엇을 때 몇 도나 나오는지 알아내는 것이 관건.
Math.atan2를 사용하여 구해보자.

x,y만 알면 간단하게 구할 수 있다.
저 값은 Radian 값인데 이 Radian이 무엇인고 하니

이런 거.
너무 움짤 설명이 훌륭해서 더 이상 자세한 설명은 생략한다.
파이 3.14 라디안이 180도이므로 rad * 180 / Math.PI 를 하면 계산이 딱 나온다.
12시 방향 기준이니 90도 보정을 해주고 Blaze로 {{knob}}에 꽂아주기만 하면 끝.

터치인터페이스에서 해보니 손가락이 핸들을 가릴 수 있어서 좀 더 UI를 강화해야할 필요를 느꼈다.
큰 원엔 바깥쪽 그림자, 작은 원엔 안쪽 그림자를 적용해보고 이 전체를 회전하자.

defs 로 필터를 일단 정의하자.

  <defs>
      <filter id="f3" x="-10%" y="-5%" width="210%" height="205%">
        <feoffset result="offOut" in="SourceAlpha" dx="0" dy="2" />
        <fegaussianblur result="blurOut" in="offOut" stddeviation="1" />
        <feblend in="SourceGraphic" in2="blurOut" mode="normal" />
      </filter>
  </defs>

fegaussianblur 를 사용하여 gaussain blur(https://en.wikipedia.org/wiki/Gaussian_blur)로 만든다음에 feoffset으로 아래쪽으로 2만큼 번지게 하였다.

이걸 큰쪽 바닥이 되는 원에 적용하자.
      <circle class="floor" cx="6em" cy="6em" r="5em" filter="url(#f3)"/>

마찬가지로 f4 를 만들어서 위쪽으로 2만큼 번지게 변화를 줘보자.

      <filter id="f4" x="-10%" y="-30%" width="210%" height="205%">
        <feoffset result="offOut" in="SourceAlpha" dx="0" dy="-4" />
        <fegaussianblur result="blurOut" in="offOut" stddeviation="1" />
        <feblend in="SourceGraphic" in2="blurOut" mode="normal" />
      </filter>

반대쪽으로 -4만큼 깊게.

이게 전부다. 무한 회전 노브라던가 기준점이 바뀐다던가 여러가지 변화가 있으니 역시 궁리해보자.

최종 결과물은 이쪽.

이 블로그의 인기 게시물

Mac 주의 - 약간 빡치는 git 대소문자 변환 파일명 변환(renaming)하는 법

Mac에서 종종 화나는 일 중 하나가 파일 시스템이 대소문자를 구분하지 않는 점이다.
가령, A.png를 a.png로 바꿔야할 경우 HFS 기준으론 전혀 바뀐 점이 없는 걸로 인식하는데 다소 화가난다.
하지만, 방법이 없는 것은 아닌데

A.png를 임의의 다른 파일로 바꾼다. (ex. A_.png)1에서 바꾼 상태에서 staging 한다. (git add A_.png)1의 파일을 다시 원래 바꾸려고 했던 파일로 바꾼다. (mv A_.png a.png)3을 다시 staging 한다. (git add a.png)commit 한다.https://stackoverflow.com/a/40307511/880991 에서 답변해준 Chris Barr 님에게 감사를.
* 추가

실제로 해보니 git mv --force A.png a.png 가 더 간단하다. 이는 바로 staging 영역에 add까지 해준다.

즐거운 Online Prototyping Tool 들

jsbin, codepen, jsfiddle 이런 것들은 일단 생략. 너무 유명한 것들이라.

https://launchpad.graphql.com - node.js 기반 graphQL 연습장. 이것만으로도 충분히 훌륭한 백엔드
https://codesandbox.io/ npm 사용이 가능한 클라이언트 사이드 연습장. webpackbin이 너무 문제가 많아서 찾아본 것.

https://scrimba.com 이건 codesandbox+ asciinema(https://asciinema.org/) 같은 느낌인데 키 녹화와 음성 녹화 기능이 추가되었다. 다 좋은데 화살표 키로 빨리감기 뒤로감기 기능이 안되고 익스포트(youtube등)으로 지원이 없는게 아쉽다.

이 둘이 만나면? https://codesandbox.io/s/jvlrl98xw3?from-embed
뭐야 이거 무서워 하지마 ㄷㄷ;  graphql+react-native-web(부왘ㅋㅋ)

https://repl.it/languages 전통을 자랑하는 REPL 도구. 지원 언어 종류가 -_-;;;;;

https://tio.run/# repl.it? 장난함? 얘는 지원 언어가 무려 386종류. J랑 아희도 있다.

https://play.golang.org/ 즐거운 go playground. 소스 포멧팅 넘 좋아.

http://decaffeinate-project.org/repl/ 최고의 coffeescript REPL. 원래 용도는 coffee를 ecma6코드로 바꾸는 것이지만...

https://scaphold.io
https://www.graph.cool/ graphql backend service. scaphold.io는 설치도 필요없는 클라우드. graphcool은 호스팅+클라우드 다있음. 둘 다 막상막하. 푸쉬서버도 되고 뭐 미친득.

https://glitch.com/ gomix에서 결국 glitch로 안착.  node.js

https://www.shadertoy.com 잘하고 싶다! 쉐이다! 오디오도 된다!

http:/…

graphql 연습 /w launchpad

https://launchpad.graphql.com/mw9wkzv99
단순 전체쿼리+조건쿼리+추가

http://graphql.org/graphql-js/passing-arguments/
참고. random ID는 crypto 1.0.1 사용
  type Query {
    Members: [member]
    getMember(id: ID!): member
  }
  type member {
    id: ID!
    text: String
  }
  input memberInput {
    text: String
  }
  type Mutation {
    addMember(member: memberInput): member
  } SQL 정의. facebook 쪽은 스트링에 지지는 거 진짜 좋아하네. *.gql 파일이 있다고 하니 이해해주자.
resolver는 var buffer = [];
const resolvers = {
  Query: {
    Members: (root, args, context) => {
      return buffer;
    },
    getMember: (id)=> {
      return buffer.find(o=>o.id)
    }
  },
  Mutation: {
    addMember(_, {member}) {
      const mm = { ...member, id:randomBytes(10).toString('hex') };
      buffer.push(mm);
      return mm;
    }
  }
}; 평범 평범.
https://dev-blog.apollodata.com/tutorial-graphql-subscriptions-server-side-e51c32dc2951 다음으로 pub/sub 연습.
https://launchpad.graphql.com/xvn94n3ql   type Subscription {
    memberAdded: member
  } member가 added되는 순간을 감시. imp…