달력

11

« 2024/11 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
반응형

2019/07/24 - [개발/ionic2, Angular] - ionic에서 모바일 접근성 적용하기 (1) : toast

 

ionic에서 모바일 접근성 적용하기 (1) : toast

최근 ionic앱에 모바일 접근성(Mobile Accessibility)을 적용할 일이 생겼다. ionic에는 크게 ionic-angular, ionic-native로 나뉘어 지는데 플러그인들이 많은데 toast도 그중 하나다. 나는 평소 ionic을 테스트..

risha-lee.tistory.com

↑위 글과 연결된 글입니다.

 

이전에 설명했던 ionic-angular http의 문제를 수정하는 법을 작성하겠다.

 

원인은 인증서 문제라면서 앱에 인증서를 고정하라는 답변을 발견하였다.

하지만 native 소스를 직접 건드리는 것은 좋은 방법이 아닌 것 같아 더 찾아본 결과, 

가장 효율적으로 보이는 https release error 수정하는 법은 다음과 같다.

(ionic-angular http를 이미 사용하고 있다고 가정하고 코드를 작성하였다)

 

2019/01/15 - [개발/ionic2, Angular] - Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response. error 해결법

그리고 위 포스팅에서 쓴 것과 달리 간혹 핸드폰에서도 CORS 오류가 나는 현상을 발견하였다.

이 문제도 아래 코드로 해결되는 것을 확인하였다. (디바이스에서 약간 디버깅이 어렵다는 것 말고는 여러모로 이득이다)

=> https://로 시작하는 URI를 제대로 동작시키지 못하는 이유는 서버에서 SSL을 제대로 적용 못해서였고 서버에서 제대로 적용해주면 ionic-angular http를 사용해도 apk를 release 했을 때 제대로 동작함을 확인했음

비슷한 이유로 CORS 오류도 서버 문제일 가능성이 높음

디버깅이 어려우므로 정말 서버를 수정할 수 없는 경우 이외엔 아래의 소스를 사용하지 않을 것 같음

그래도 필요한 경우가 생길 수도 있으니 소스는 삭제하지 아니함 (2020. 09. 03)

참고 : forum.ionicframework.com/t/ionic-native-http-ngx-v-s-angular-common-http-which-should-be-used-in-an-ionic4-app/169629/8

 

1. ionic-native http를 설치한다.

$ ionic cordova plugin add cordova-plugin-advanced-http
$ npm install --save @ionic-native/http

 

2. app.module.ts에서 ionic-native http providers에 넣는다.

import { HTTP } from '@ionic-native/http';

@NgModule({
   .....
providers: [
     .....
     HTTP
  ]
})

 

3. ts 파일을 수정한다.

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { Http } from '@angular/http';
import { HTTP } from '@ionic-native/http';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
    url:string = "your_server_url";
    page_index: number = 1;
   
    constructor(public platform: Platform,
                public http: Http,
                public n_http: HTTP) {
      this.goGetNoti();
    }
    
    goGetNoti() {
        var param = "?page_index=" + this.page_index;
        this.getNoti(param).then(data => {
          console.log("getNoti", data);
          var _data:any = data;
                
          if (_data.isOk == 'Y') {
            // success
          } else {
            // server error
          }
        }).catch(error => {
            console.log("Error", error);
        });
    }
    
    public getNoti(param: string) {
       if (this.platform.is('cordova') == false){ 
            return new Promise((resolve, reject) => {
                this.http.get(url+'/v1/noti' + param).timeout(5000).subscribe(res => {
                    resolve(res.json());
                }, (err) => {
                    reject(err);
                });  
            });  
        } else {
            return new Promise((resolve, reject) => {
                this.n_http.setSSLCertMode('nocheck');
                this.n_http.setRequestTimeout(5);
                this.n_http.get(url+'/v1/noti' + param, {}, {}).then(res =>{
                    resolve(JSON.parse(res.data));
                }).catch(err =>{
                    reject(err);
                });
            });
        }
    }
}

(보통 getNoti와 같이 동작하는 함수는 다른 ts에 넣고 사용하기 때문에 getNoti와 goGetNoti로 분리하였다)

 

this.n_http.setSSLCertMode('nocheck'); 이 부분이 SSL 확인하지 않게 해주는 부분인듯하다.

찾아보았으나 아쉽게도 ionic-angular http에서는 ionic-native http처럼 SSL 확인을 하지 않아도 되는 기능이 없다.

그래서 앞으로 http onic-angular, ionic-native 분기 코딩은 계속될 거 같다.

 

보안 문제를 살짝 생각해봤는데 보통 서버도 같이 개발해서

이미 인증된 서버이므로 위와 같은 방법을 써도 문제는 없을 것 같다.

=> 위와 같은 이유로 취소선 추가

 

참고 : https://stackoverflow.com/questions/44833534/http-requests-fails-only-while-releasing-android-apk

https://forum.ionicframework.com/t/https-post-requests-not-working-in-release-build/154099/3

 

반응형
:
Posted by 리샤씨
반응형

2019/07/25 - [개발/ionic2, Angular] - ionic에서 모바일 접근성 적용하기 (3) : ion-select ②

 

ionic에서 모바일 접근성 적용하기 (3) : ion-select ②

2019/07/25 - [개발/ionic2, Angular] - ionic에서 모바일 접근성 적용하기 (2) : ion-select ① ionic에서 모바일 접근성 적용하기 (2) : ion-select ① 2019/07/24 - [개발/ionic2, Angular] - ionic에서 모바일..

risha-lee.tistory.com

↑위 글과 연결된 글입니다.

Voice Assistant를 이용하여 들었을 때, 

기본 radio는 정상적으로 label과 선택되었는지 안 되었는지를 잘 읽어주지만

ion-radio는 label을 전혀 읽어주지 않았다.. 그냥 선택되었는지 안 되었는지만 읽어주는데

그것으로는 절대 접근성을 적용했다고 할 수 없을 거 같았다.

 

그렇다고 이것 역시 기본 radio로 바꾸기엔 ion-radio로 바꾼 이유가 명확해서

(기본 radio는 뭔가 안 눌리는 느낌이 있다)

ion-radio로 꼭 써야 하는 상황이었다.

 

사실 ion-radio는 앞의 글들과는 다른 유형의 문제였다.

그냥 내가 잘못 사용하고 있던 것일 뿐..

 

ion-radio를 잘못 사용한

<ion-content>
  <ion-list radio-group>
    <span class="ion_radio_items">
      <span style="float: left;">
    	<ion-radio mode="md" id="no1" name="no1" value="N" ></ion-radio>
      </span>
      <ion-label text-wrap>아니오</ion-label>
    </span>
    <span>
      <span style="float: left;">
    	  <ion-radio mode="md" id="yes1" name="yes1" value="Y" ></ion-radio>
      </span>
      <ion-label text-wrap>예</ion-label>
    </span>
  </ion-list>
</ion-content>

대강 이런 식으로 사용하고 있었는데 공식 홈페이지를 보니

ion-list 안에 ion-item안에 하나의 ion-radio와 ion-label이 들어가 있었다..

 

아마 처음에 이런 식으로 코딩했던 이유는 ion-item을 사용하면 css가 굉장히 깨져서였던 거 같다.

하지만 ion-item을 입혀주니 Voice Assistant를 이용하여 들었을 때,

ion-radio에 ion-label을 잘 연결해서 읽어주는 것을 확인하여

별 수 없이 ion-item을 입히고 css를 수정하게 되었다.

 

ion-radio를 제대로 사용한

<ion-content>
  <ion-list radio-group>
    <ion-item>
      <span style="float: left;">
        <ion-radio mode="md" id="no1" name="no1" value="N" ></ion-radio>
      </span>
      <ion-label text-wrap>아니오</ion-label>
    </ion-item>
    <ion-item>
      <span style="float: left;">
        <ion-radio mode="md" id="yes1" name="yes1" value="Y" ></ion-radio>
      </span>
      <ion-label text-wrap>예</ion-label>
    </ion-item>
  </ion-list>
</ion-content>

위처럼 코드를 수정하니 Voice Assistant를 이용했을 때 제대로 들려주는 것을 확인하였다!


참고: https://ionicframework.com/docs/api/radio

반응형
:
Posted by 리샤씨
반응형

2019/07/25 - [개발/ionic2, Angular] - ionic에서 모바일 접근성 적용하기 (2) : ion-select ①

 

ionic에서 모바일 접근성 적용하기 (2) : ion-select ①

2019/07/24 - [개발/ionic2, Angular] - ionic에서 모바일 접근성 적용하기 (1) : toast ionic에서 모바일 접근성 적용하기 (1) : toast 최근 ionic앱에 모바일 접근성(Mobile Accessibility)을 적용할 일이 생겼..

risha-lee.tistory.com

↑위 글과 연결된 글입니다.

이전에 위 글이 서버에서 가져오는 정보를 이용하여 n개의 정해져 있지 않은

ion-select를 사용할 때엔 해결법이 올바르지 않다고 했었다.

 

왜냐면 ViewChild를 이용하여 정의하기가 어렵기 때문..

그래서 해결법으로 모든 Select를 ViewChildren으로 이용하여 리스트로 저장하고

그것을 이용하여 모바일 접근성을 적용하도록 하겠다.

 

코드는 다음과 같다.

 

1. html을 다음과 같은 형식으로 작성한다.

<ion-content>
    <ul>
        <li *ngFor="let ques of quesList; let i = index;">
            <span>{{ques.ques_sno}}. {{ques.question}} </span>
            <ion-item (click)="openSelect(i)">
                <ion-label style="display: none">{{ques.ques_sno}}. {{ques.question}}</ion-label>
                <ion-select okText="확인" cancelText="취소" [id]="'select'+i"
                            [selectOptions]="{title:ques.question}" placeholder="선택안함">
                    <ion-option *ngFor="let ans of ques.ansList" [value]="ans.ans_sno">{{ans.answer}}</ion-option>
                </ion-select>
            </ion-item>
        </li>
    </ul>
</ion-content> 

 

2. ts를 작성한다.

(quesList는 server에서 가져왔다고 가정하고 list의 개수는 유동적이어도 코드는 제대로 작동함을 확인하였다)

import { Component, ViewChildren, QueryList } from '@angular/core';
import { Select } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  @ViewChildren(Select) selectGroup: QueryList<Select>;
  
  quesList: any;
  
  constructor() {
        this.quesList = [{
          ques_sno: 1,
          question: "ionic앱 모바일 접근성을 적용하기 글에 어떻게 방문하게 되셨습니까?",
          ansList:[{
            ans_sno: 1,
            answer: "직접 검색"
          }, {
            ans_sno: 2,
            answer: "지인 추천"
          }, {
            ans_sno: 3,
            answer: "기타"
          }]
        }, {
          ques_sno: 2,
          question: "ionic앱 모바일 접근성 적용하기 글이 만족스러우십니까?",
          ansList:[{
            ans_sno: 1,
            answer: "매우 만족"
          }, {
            ans_sno: 2,
            answer: "만족"
          }, {
            ans_sno: 3,
            answer: "불만족"
          }, {
            ans_sno: 4,
            answer: "매우 불만족"
          }]
        }, {
          ques_sno: 3,
          question: "ionic앱 모바일 접근성 적용하기에 얼마나 관심이 있으십니까?",
          ansList:[{
            ans_sno: 1,
            answer: "매우 관심"
          }, {
            ans_sno: 2,
            answer: "관심"
          }, {
            ans_sno: 3,
            answer: "무관심"
          }, {
            ans_sno: 4,
            answer: "매우 무관심"
          }]
        }];
    }

    openSelect(index: number) {
        this.selectGroup.toArray()[index].open();
    }
}

 

 

Voice Assistant를 이용하여 유동적인 ion-select 팝업 연 화면

반응형
:
Posted by 리샤씨
반응형

 

2019/07/24 - [개발/ionic2, Angular] - ionic에서 모바일 접근성 적용하기 (1) : toast

 

ionic에서 모바일 접근성 적용하기 (1) : toast

최근 ionic앱에 모바일 접근성(Mobile Accessibility)을 적용할 일이 생겼다. ionic에는 크게 ionic-angular, ionic-native로 나뉘어 지는데 플러그인들이 많은데 toast도 그중 하나다. 나는 평소 ionic을 테스트..

risha-lee.tistory.com

↑위 글과 연결된 글입니다.

 

삼성 안드로이드 폰의 Voice Assistant를 이용하여 모바일 접근성을 테스트할 때

(테스트 폰은 Samsung Galaxy S7, Samsung Galaxy S10e였다)

앞의 글과 또 다른 문제점을 발견했다.

그것은 ion-select가 클릭되지 않는다는 것이었다.

(사실 아예 클릭이 되지 않는 것은 아니고.. 가끔 운이 좋으면 클릭되어 팝업이 열린다;)

 

기본 select를 사용하지 않고 ion-select를 사용한 이유는..

기본 select가 Android에서는 잘 나오지만

IOS에서는 웹뷰 select에서 보이는 Done 버튼도 안 나오고 딱히 UI도 예쁘지 않고 불편하기만 해서이다.

 

그래서 모바일 접근성을 위해서 다시 기본 select로 바꾸기는 좀 그런 상황인 데다

어떠한 이유에서 클릭 되지 않는 것인지 (Voice Assistant를 이용하지 않으면 잘 되기 때문)

알 수 없어서 꽤 난감한 상황이 되었다.

 

그래도 여차여차 ion-focus, ion-click 이벤트로 여러 테스트를 거친 결과,

Voice Assistant를 이용할 때 ion-click 이벤트를 타기는 한다는 점을 알게 되었다.

여전히 정확한 원인은 모르겠지만 click 이벤트를 추가로 코딩하면 잘 작동하는 것으로 보아

아마도 click 이벤트로 ion-select의 open 이벤트를 발생시키지 않아서 생기게 된 오류 같아 보였다.

 

그래서 해결법은 다음과 같은 코딩을 추가로 해주면 된다.

 

1. html에 ion-select에 다음과 같은 방식으로 id(#bloodType)를 부여하고 ion-item이나 ion-select에 click 이벤트(

(click)="openSelect('bloodType')")를 추가한다.

<ion-content>
   <ion-item (click)="openSelect('bloodType')">
        <ion-label>혈액형</ion-label>
        <ion-select okText="확인" cancelText="취소" placeholder="혈액형 선택" 
        			[selectOptions]="{title:'혈액형 선택'}" #bloodType>
            <ion-option value="a">A</ion-option>
            <ion-option value="b">B</ion-option>
            <ion-option value="o">O</ion-option>
            <ion-option value="ab">AB</ion-option>
        </ion-select>
    </ion-item>
</ion-content> 

 

2. ts에 ViewChild를 이용하여 Select 변수를 만들고 click 이벤트를 생성한다.

import { Component, ViewChild } from '@angular/core';
import { Select } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  @ViewChild('bloodType') bloodType: Select;
    
  openSelect(selector) {
    this[selector].open();
  }
}

 

Voice Assistant를 이용하여 ion-select 팝업 연 화면

그런데 이것은 이미 정해져 있는 ion-select에 접근성을 입힐 때는 적절한 방법이라고 생각되지만

서버에서 가져오는 정보를 이용하여 n개의 정해져 있지 않은 ion-select를 사용할 때엔 해결법이 올바르지 않다.

이런 상황에 해결하는 코딩은 다음 글에서 작성하도록 하겠다.

반응형
:
Posted by 리샤씨
반응형

최근 ionic앱에 모바일 접근성(Mobile Accessibility)을 적용할 일이 생겼다.

 

ionic에는 크게 ionic-angular, ionic-native로 나누어지는데 플러그인들이 많은데 toast도 그중 하나다.

나는 평소 ionic을 테스트할 때 초반엔 ionic serve 명령어를 이용하여 웹으로 보기 때문에

toast를 포함하여 대부분의 기능을 ionic-angular에서 제공하는 것으로 사용하고 있었다.

 

그러나 ionic-angular에서 제공하는 것은 웹에서도 사용 가능하다는 장점이 있지만

cordova를 이용하여 디바이스(Android, IOS)에 올렸을 때,

native가 기본적으로 제공해주는 기능을 못 사용하는 경우가 있다는 걸 최근에 절실히 깨닫고 있다.

(코드를 꽤 많이 고쳐야 하는 경우도 생긴다)

 

아무튼 ionic-angular toast도 모바일 접근성을 테스트할 때 알게 된 사실인데,

삼성 안드로이드 폰에서 Voice Assistant를 이용하여 들으면

ionic 앱에서 ionic-angular toast를 읽어주지 않는다는 치명적인 단점이 있었다.

 

그래서 좀 찾아보고 직접 적용하여 테스트해 본 결과,

ionic-angular, ionic-native를 모두 적용하여 platform.is('cordova')로 분기를 태워 코드를 작성하면

웹과 앱 모두 적절한 toast를 사용할 수 있다.

(ionic-native toast를 사용하면 삼성 안드로이드 폰에서 Voice Assistant를 이용하여 들었을 때,

안드로이드 native로 작성된 앱의 toast처럼 정말 잘 읽어준다..!)

 

또한, ionic-angular http를 사용하면 apk를 release 했을 때 https://로 시작하는 URI를 제대로 동작시키지 못하지만,

이것도 위와 같은 방법으로 하면 해결된다. (ionic-angular, ionic-native 분기 적용)

=> https://로 시작하는 URI를 제대로 동작시키지 못하는 이유는 서버에서 SSL을 제대로 적용 못해서였고 서버에서 제대로 적용해주면 ionic-angular http를 사용해도 apk를 release 했을 때 제대로 동작함을 확인했음 (2020. 09. 03)

 

본론으로 들어가 코드를 작성해본다면 다음과 같다.

 

1. ionic-native toast를 설치한다.

$ ionic cordova plugin add cordova-plugin-x-toast 
$ npm install @ionic-native/toast --save

 

2. app.module.ts에서 ionic-native toast를 providers에 넣는다.

import { Toast } from '@ionic-native/toast';

@NgModule({
   .....
providers: [
     .....
     Toast
  ]
})

 

3. ts 파일을 작성한다.

import { Component } from '@angular/core';
import { Platform, ToastController } from 'ionic-angular';
import { Toast } from '@ionic-native/toast';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  constructor(public platform: Platform,
              public toastCtrl: ToastController,
              public toast: Toast) {
      if (this.platform.is('cordova') == false) {
        let toast = toastCtrl.create({
            message: "test~",
            duration: 3000,
            position: "middle",
            cssClass: "toast-default"
        });
        toast.present();
      } else {
        this.toast.show("test~", "3000", "center").subscribe(
          toast => {
            console.log(toast);
          }
        );
      }
    }
  }

 

웹에서 보는 ionic-angular toast / 앱에서 보는 ionic-native toast

그러나 후에 ios에서 테스트해보았는데 ios의 voice over 기능으로는 toast message를 읽어주지 않았다.

나중에 작성하겠지만 간단히 설명하자면 ios에서는 phonegap-plugin-mobile-accessibility plugin을 설치하고

(<any>window).MobileAccessibility.speak(msg);

위 코드를 이용하여 원하는 메시지를 읽어주면 된다.

 

↓자세한 내용은 아래 링크에 작성해놓았다.

2019/09/18 - [개발/ionic2, Angular] - ionic에서 Voice Over/Voice Assistant/Talk Back이 켜져 있을 때 원하는 문장을 읽어주는 법 (모바일 접근성)

반응형
:
Posted by 리샤씨
반응형

ionic2 프로젝트에 http로 데이터를 주고받을 때 header에 값을 넣어 준 뒤

ionic serve로 구동 시

Access to XMLHttpRequest at '***api url***' from origin 'http://localhost:8100' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

오류가 났었다.



찾아보니 ionic serve로 구동 시에만 그런거고 모바일에선 문제없다고 한다.

웹에서 문제 있는 소스를 모바일로 구동해보니 잘 돌아가는 것을 확인했다.

그리고 그 답변에서 웹에서도 되려면 아래 링크에서 크롬 확장 프로그램을 설치하면 된다고 한다.


https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en



출처 : https://forum.ionicframework.com/t/http-post-request-error-no-access-control-origin-in-ionic/106029/4



2019/07/25 - [개발/ionic2, Angular] - ionic에서 https release error, CORS(Access-Control-Allow-Headers) error 해결법

위 답변과 달리 핸드폰에도 문제 있을 때는 위 포스팅을 참고하시길 바랍니다!

반응형
:
Posted by 리샤씨
반응형

※ 해당 글은 아래 글과 연결되어 있습니다.

혹시 잘 안되거나 이해 안 되는 부분이 있으시면 아래 글을 참조하여 주세요.

http://risha-lee.tistory.com/18?category=764955

 

 

 

앞서 말했다시피 사용자 범례를 이전 글처럼 만들기만 해서는 

위 그림처럼 범례 클릭 시 해당 데이터셋의 숨김/보이기 토글 기능을 사용할 수 없다.

 

해당 기능을 만들려면 이전 글의 코드에 다음과 같이 추가로 코드를 작성해주어야 한다.

 

<script>
	 window.onload = function() {
		$("#chartLegend li").click(function(){
			updateDataset(event, $(this).attr("datasetIndex"), "theChart");
			if($(this).css("text-decoration").indexOf("line-through")<0){
				$(this).css("text-decoration", "line-through");
			} else{
				$(this).css("text-decoration", "none");
			}
		});
	 }

	 //범례 클릭시 해당 데이터셋이 숨김/보이기 토글 기능 함수
	 function updateDataset(e, datasetIndex, chartId) {
		var index = datasetIndex;
		var ci = e.view[chartId];
		var meta = ci.getDatasetMeta(index);
		var scaleList = ci.options.scales["yAxes"];
        
		meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
		ci.update();
	 }
</script>

 

참고 : https://github.com/chartjs/Chart.js/issues/2565

 

반응형
:
Posted by 리샤씨
반응형

Chart.js가 기본적으로 제공하는 범례는 그냥 위치를 위나 아래로 정하면 무조건 가운데 정렬만 할 뿐,

왼쪽 위. 오른쪽 위, 오른쪽 아래, 왼쪽 아래 등 위치를 자유자재로 변경할 수 없어서 

오른쪽 위에 범례를 두기 위해 사용자 범례를 사용했었다.

물론 디자인도 자유자재로 변경할 수 있다는 점이 마음에 들어서 위치를 바꿀 겸 범례의 디자인도 조정하였다.

 

추가로 덧붙이자면 Chart.js에서 제공하는 기본 범례를 사용하면 그래프가 길어져 스크롤이 생겼을 때,

스크롤 위치에 따라 어떤 부분에서는 범례가 보이지만 어떤 부분에서는 범례가 보이지 않을 수 있다.

사용자 범례를 사용하면 위의 문제점도 해결해준다. (차트를 좌우로 스크롤해도 범례의 위치는 고정된다)

 

1. 막대 차트&막대 라인 차트 - 막대 형식 데이터셋 원형, 라인 형식 데이터셋 선형 범례

2. 라인 차트 - 라인 형식 데이터셋 사각형 범례

 

별다른 설정 없이 막대 차트냐, 라인 차트냐, 해당 데이터셋의 형식이 라인이냐 바이냐에 따라 자동으로 class를 입히도록 작성하였다.

아래의 코드를 사용하면 위와 같은 범례를 만들 수 있다. 예제는 막대 라인 차트이다. 

 

<style type="text/css">
.chartjs-legend ol,
.chartjs-legend ul {
  list-style: none;
  margin:0;
  padding:0;
  text-align:right;
}

.chartjs-legend li {
  cursor:pointer;
  display: inline-table;
  margin: 10px 4px;
}

.chartjs-legend li span.bar{
  position:relative;
  padding: 0px 10px;
  margin: 5px;
  border-radius:100px;
  color:white;
}

.chartjs-legend li span.line{
  position:relative;
  padding: 1px 10px;
  margin: 5px;
  color:white;
}

.chartjs-legend li div.line{
	float:left;
	height:2px;
	background:#000;
	font-size:0;
	line-height:0;
	width:25px;
	padding:1px 0px;
	border-radius:100px;
	margin: 9px 5px;
}
</style>

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.bundle.min.js"></script>
<script>       
	var barChartData = {        
	        labels: ["January", "February", "March", "April", "May", "June", "July"],
	        datasets: [{
	            type: 'line',
	            label: 'line',
	            borderColor: "#1E90FF",
	            fill: false,
	            data: [
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000
	           ]
	        }, 
	        {
	            type: 'bar',
	            label: 'bar',
	            backgroundColor: "#F7464A",
	            data: [
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000
	            ]
	        }]
	    };
	
	 window.onload = function() {
	    var ctx = $('#chart').get(0).getContext("2d"); 
	    window.theChart = new Chart(ctx, {
	         type: 'bar',
	         data: barChartData,
	         options: {
	             legend: false,
	             legendCallback: function(chart){
	                return drawCustomLegend(chart);
	             }// 사용자 범례를 만들 때 쓰는 함수를 지정하거나 작성한다.
	         }
	    });
	    $('#chartLegend').html(window.theChart.generateLegend());//사용자 범례 자리에 해당 차트에 대한 사용자 범례 코드를 넣는다.
	 }
	 
	 function drawCustomLegend(chart){
    	var text = [];
    	text.push('<ul class="' + chart.id + '-legend">');
    	if(chart.config.type == 'bar'){//막대차트, 막대라인차트일 경우
    		var barIndex = chart.data.datasets.length;
        	for (var i = 0; i <chart.data.datasets.length; i++) {
        		if(chart.data.datasets[i].type == 'line' == false){
        			barIndex = i;
        			break;
        		}
        	}//라인 형식 데이터셋이 어디까지인지 확인
        	// -> 막대 형식의 데이터셋을 라인 형식의 데이터셋보다 앞에 둘 경우 라인이 막대에 묻히기 때문에 라인 형식이 먼저 올 수 밖에 없다.
        	//그러나 막대 형식의 데이터셋의 범례를 먼저 그리고 싶었기 때문에 해당 작업을 했다.
        	
        	for (i = barIndex; i <chart.data.datasets.length; i++) {
        		if(!(chart.data.datasets[i].hideLegend) && chart.data.datasets[i].label){
        			text.push('<li  datasetIndex="'+i+'"><span class="bar" style="background-color:' + chart.data.datasets[i].backgroundColor + '" ></span>');
        			text.push('<span>'+chart.data.datasets[i].label+'</span>');
        			text.push('</li>');
        		} 
        	}//막대 형식 데이터셋의 범례를 먼저 그림
        	
        	for (i = 0; i <barIndex; i++) {
        		if(!(chart.data.datasets[i].hideLegend) && chart.data.datasets[i].label){
        			text.push('<li datasetIndex="'+i+'"><div class="line" style="background:' + chart.data.datasets[i].borderColor + '"></div>');
        			text.push('<span>'+chart.data.datasets[i].label+'</span>');
        			text.push('</li>');
        		} 
        	}//막대 형식 데이터셋의 범례를 그린 후 라인 형식 데이터셋의 범례를 그림.
    	} else if(chart.config.type == 'line'){//라인 차트일 경우
    		for (i = 0; i <chart.data.datasets.length; i++) {
        		if(!(chart.data.datasets[i].hideLegend) && chart.data.datasets[i].label){
        			text.push('<li datasetIndex="'+i+'"><span class="line" style="background-color:' + chart.data.datasets[i].borderColor + '"></span>');
        			text.push('<span>'+chart.data.datasets[i].label+'</span>');
        			text.push('</li>');
        		} 
    		}
    	}
      	text.push('</ul>');
      	return text.join("");
    }
</script>

<div id="chartArea" style="width:700px;">  
	<div id="chartLegend" class="chartjs-legend"></div>
	<canvas id="chart"></canvas>
</div>

 

그러나 이것만 해서는.. 기본 범례에서 제공하는 범례를 클릭하면 

해당 데이터셋의 숨김/보이기 토글이 작동하지 않아 다소 불편했다.

그래서 나는 사용자 범례에 해당 기능도 추가했었다.

 

다음 글에서 설명하도록 하겠다.

반응형
:
Posted by 리샤씨


반응형
반응형