From 49a07c4ea06159f8850bd02976b364f2b2892787 Mon Sep 17 00:00:00 2001 From: chicpro Date: Tue, 28 Jul 2015 16:01:03 +0900 Subject: [PATCH 01/21] =?UTF-8?q?=ED=85=8C=EB=A7=88=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adm/admin.lib.php | 188 +++++++- adm/admin.menu100.php | 1 + adm/board_form.php | 38 +- adm/config_form.php | 140 ++---- adm/css/admin.css | 34 ++ adm/css/theme.css | 8 + adm/img/close.gif | Bin 0 -> 200 bytes adm/img/link_icon.gif | Bin 0 -> 53 bytes adm/img/theme_img.jpg | Bin 0 -> 7992 bytes adm/menu_form.php | 4 +- adm/menu_list.php | 4 +- adm/theme.js | 80 ++++ adm/theme.php | 77 +++ adm/theme_config_load.php | 78 ++++ adm/theme_detail.php | 64 +++ adm/theme_preview.php | 118 +++++ adm/theme_update.php | 52 +++ bbs/board.php | 8 +- bbs/board_head.php | 2 +- bbs/board_tail.php | 2 +- bbs/content.php | 4 +- bbs/group.php | 13 +- bbs/qahead.php | 4 +- common.php | 193 +++++--- config.php | 1 + extend/user.config.php | 5 - g4_import.php | 4 +- g4_import_run.php | 4 +- head.php | 25 +- head.sub.php | 13 +- index.php | 18 +- install/gnuboard5.sql | 1 + install/install_db.php | 1 + js/autosave.js | 4 +- js/common.js | 2 +- lib/common.lib.php | 35 ++ lib/connect.lib.php | 23 +- lib/json.lib.php | 79 ++++ lib/latest.lib.php | 32 +- lib/outlogin.lib.php | 23 +- lib/poll.lib.php | 28 +- lib/popular.lib.php | 26 +- lib/visit.lib.php | 26 +- mobile/content.php | 4 +- mobile/head.php | 5 + mobile/index.php | 9 +- mobile/skin/board/basic/view.skin.php | 2 +- mobile/skin/board/gallery/view.skin.php | 2 +- mobile/tail.php | 5 + plugin/editor/smarteditor2/editor.lib.php | 2 +- plugin/kcaptcha/kcaptcha.js | 8 +- plugin/sns/view_comment_write.sns.skin.php | 4 +- skin/board/basic/view.skin.php | 2 +- skin/board/basic/view_comment.skin.php | 2 +- skin/board/gallery/view.skin.php | 2 +- skin/board/gallery/view_comment.skin.php | 2 +- tail.php | 12 +- tail.sub.php | 5 +- theme/basic/_common.php | 3 + theme/basic/css/default.css | 282 +++++++++++ theme/basic/css/mobile.css | 250 ++++++++++ theme/basic/group.php | 49 ++ theme/basic/head.php | 159 +++++++ theme/basic/head.sub.php | 91 ++++ theme/basic/img/gnb_bg00.gif | Bin 0 -> 54 bytes theme/basic/img/wrest.gif | Bin 0 -> 51 bytes theme/basic/index.php | 43 ++ theme/basic/mobile/_common.php | 3 + theme/basic/mobile/group.php | 35 ++ theme/basic/mobile/head.php | 177 +++++++ theme/basic/mobile/index.php | 30 ++ .../mobile/skin/board/basic/img/icon_file.gif | Bin 0 -> 107 bytes .../mobile/skin/board/basic/img/icon_hot.gif | Bin 0 -> 97 bytes .../mobile/skin/board/basic/img/icon_img.gif | Bin 0 -> 145 bytes .../mobile/skin/board/basic/img/icon_link.gif | Bin 0 -> 104 bytes .../skin/board/basic/img/icon_mobile.gif | Bin 0 -> 62 bytes .../skin/board/basic/img/icon_movie.gif | Bin 0 -> 110 bytes .../mobile/skin/board/basic/img/icon_new.gif | Bin 0 -> 71 bytes .../skin/board/basic/img/icon_reply.gif | Bin 0 -> 77 bytes .../skin/board/basic/img/icon_secret.gif | Bin 0 -> 97 bytes .../skin/board/basic/img/icon_sound.gif | Bin 0 -> 113 bytes .../mobile/skin/board/basic/list.skin.php | 224 +++++++++ theme/basic/mobile/skin/board/basic/style.css | 238 ++++++++++ .../mobile/skin/board/basic/view.skin.php | 270 +++++++++++ .../skin/board/basic/view_comment.skin.php | 321 +++++++++++++ .../mobile/skin/board/basic/write.skin.php | 252 ++++++++++ .../skin/board/gallery/img/icon_file.gif | Bin 0 -> 107 bytes .../skin/board/gallery/img/icon_hot.gif | Bin 0 -> 97 bytes .../skin/board/gallery/img/icon_img.gif | Bin 0 -> 145 bytes .../skin/board/gallery/img/icon_link.gif | Bin 0 -> 104 bytes .../skin/board/gallery/img/icon_mobile.gif | Bin 0 -> 62 bytes .../skin/board/gallery/img/icon_movie.gif | Bin 0 -> 110 bytes .../skin/board/gallery/img/icon_new.gif | Bin 0 -> 71 bytes .../skin/board/gallery/img/icon_reply.gif | Bin 0 -> 77 bytes .../skin/board/gallery/img/icon_secret.gif | Bin 0 -> 97 bytes .../skin/board/gallery/img/icon_sound.gif | Bin 0 -> 113 bytes .../mobile/skin/board/gallery/list.skin.php | 251 ++++++++++ .../basic/mobile/skin/board/gallery/style.css | 225 +++++++++ .../mobile/skin/board/gallery/view.skin.php | 270 +++++++++++ .../skin/board/gallery/view_comment.skin.php | 321 +++++++++++++ .../mobile/skin/board/gallery/write.skin.php | 251 ++++++++++ .../skin/connect/basic/connect.skin.php | 8 + .../connect/basic/current_connect.skin.php | 38 ++ .../basic/mobile/skin/connect/basic/style.css | 9 + .../skin/content/basic/content.skin.php | 18 + .../basic/mobile/skin/content/basic/style.css | 8 + .../basic/mobile/skin/faq/basic/list.skin.php | 120 +++++ theme/basic/mobile/skin/faq/basic/style.css | 25 + .../skin/latest/basic/img/icon_file.gif | Bin 0 -> 107 bytes .../mobile/skin/latest/basic/img/icon_hot.gif | Bin 0 -> 97 bytes .../mobile/skin/latest/basic/img/icon_img.gif | Bin 0 -> 145 bytes .../skin/latest/basic/img/icon_link.gif | Bin 0 -> 104 bytes .../skin/latest/basic/img/icon_mobile.gif | Bin 0 -> 62 bytes .../skin/latest/basic/img/icon_more.gif | Bin 0 -> 169 bytes .../skin/latest/basic/img/icon_movie.gif | Bin 0 -> 110 bytes .../mobile/skin/latest/basic/img/icon_new.gif | Bin 0 -> 71 bytes .../skin/latest/basic/img/icon_reply.gif | Bin 0 -> 77 bytes .../skin/latest/basic/img/icon_secret.gif | Bin 0 -> 97 bytes .../skin/latest/basic/img/icon_sound.gif | Bin 0 -> 113 bytes .../mobile/skin/latest/basic/latest.skin.php | 43 ++ .../basic/mobile/skin/latest/basic/style.css | 10 + .../skin/member/basic/formmail.skin.php | 96 ++++ .../skin/member/basic/img/zip_ico_up.gif | Bin 0 -> 54 bytes .../mobile/skin/member/basic/login.skin.php | 59 +++ .../skin/member/basic/login_check.skin.php | 5 + .../skin/member/basic/member_confirm.skin.php | 46 ++ .../mobile/skin/member/basic/memo.skin.php | 40 ++ .../skin/member/basic/memo_form.skin.php | 57 +++ .../skin/member/basic/memo_view.skin.php | 56 +++ .../skin/member/basic/password.skin.php | 47 ++ .../skin/member/basic/password_lost.skin.php | 46 ++ .../mobile/skin/member/basic/point.skin.php | 81 ++++ .../mobile/skin/member/basic/profile.skin.php | 48 ++ .../skin/member/basic/register.skin.php | 57 +++ .../skin/member/basic/register_form.skin.php | 441 ++++++++++++++++++ .../member/basic/register_result.skin.php | 44 ++ .../mobile/skin/member/basic/scrap.skin.php | 27 ++ .../skin/member/basic/scrap_popin.skin.php | 39 ++ .../basic/mobile/skin/member/basic/style.css | 190 ++++++++ .../basic/mobile/skin/new/basic/new.skin.php | 66 +++ theme/basic/mobile/skin/new/basic/style.css | 9 + .../skin/outlogin/basic/outlogin.skin.1.php | 63 +++ .../skin/outlogin/basic/outlogin.skin.2.php | 46 ++ .../mobile/skin/outlogin/basic/style.css | 29 ++ .../mobile/skin/poll/basic/poll.skin.php | 65 +++ .../skin/poll/basic/poll_result.skin.php | 120 +++++ theme/basic/mobile/skin/poll/basic/style.css | 86 ++++ .../skin/popular/basic/popular.skin.php | 17 + .../basic/mobile/skin/popular/basic/style.css | 11 + .../mobile/skin/qa/basic/img/btn_close.gif | Bin 0 -> 211 bytes .../mobile/skin/qa/basic/img/icon_answer.gif | Bin 0 -> 77 bytes .../mobile/skin/qa/basic/img/icon_file.gif | Bin 0 -> 107 bytes .../mobile/skin/qa/basic/img/icon_hot.gif | Bin 0 -> 97 bytes .../mobile/skin/qa/basic/img/icon_img.gif | Bin 0 -> 145 bytes .../mobile/skin/qa/basic/img/icon_link.gif | Bin 0 -> 104 bytes .../mobile/skin/qa/basic/img/icon_mobile.gif | Bin 0 -> 62 bytes .../mobile/skin/qa/basic/img/icon_movie.gif | Bin 0 -> 110 bytes .../mobile/skin/qa/basic/img/icon_new.gif | Bin 0 -> 71 bytes .../mobile/skin/qa/basic/img/icon_secret.gif | Bin 0 -> 97 bytes .../mobile/skin/qa/basic/img/icon_sound.gif | Bin 0 -> 113 bytes .../basic/mobile/skin/qa/basic/list.skin.php | 152 ++++++ theme/basic/mobile/skin/qa/basic/style.css | 247 ++++++++++ .../mobile/skin/qa/basic/view.answer.skin.php | 24 + .../skin/qa/basic/view.answerform.skin.php | 125 +++++ .../basic/mobile/skin/qa/basic/view.skin.php | 187 ++++++++ .../basic/mobile/skin/qa/basic/write.skin.php | 184 ++++++++ .../mobile/skin/search/basic/search.skin.php | 142 ++++++ .../basic/mobile/skin/search/basic/style.css | 33 ++ theme/basic/mobile/skin/visit/basic/style.css | 11 + .../mobile/skin/visit/basic/visit.skin.php | 25 + theme/basic/mobile/tail.php | 47 ++ theme/basic/readme.txt | 8 + theme/basic/screenshot.png | Bin 0 -> 11304 bytes .../basic/skin/board/basic/img/btn_close.gif | Bin 0 -> 211 bytes .../basic/skin/board/basic/img/icon_file.gif | Bin 0 -> 107 bytes theme/basic/skin/board/basic/img/icon_hot.gif | Bin 0 -> 97 bytes theme/basic/skin/board/basic/img/icon_img.gif | Bin 0 -> 145 bytes .../basic/skin/board/basic/img/icon_link.gif | Bin 0 -> 104 bytes .../skin/board/basic/img/icon_mobile.gif | Bin 0 -> 62 bytes .../basic/skin/board/basic/img/icon_movie.gif | Bin 0 -> 110 bytes theme/basic/skin/board/basic/img/icon_new.gif | Bin 0 -> 71 bytes .../basic/skin/board/basic/img/icon_reply.gif | Bin 0 -> 77 bytes .../skin/board/basic/img/icon_secret.gif | Bin 0 -> 97 bytes .../basic/skin/board/basic/img/icon_sound.gif | Bin 0 -> 113 bytes theme/basic/skin/board/basic/list.skin.php | 255 ++++++++++ theme/basic/skin/board/basic/style.css | 256 ++++++++++ theme/basic/skin/board/basic/view.skin.php | 283 +++++++++++ .../skin/board/basic/view_comment.skin.php | 330 +++++++++++++ theme/basic/skin/board/basic/write.skin.php | 268 +++++++++++ .../skin/board/gallery/img/btn_close.gif | Bin 0 -> 211 bytes .../skin/board/gallery/img/icon_file.gif | Bin 0 -> 107 bytes .../basic/skin/board/gallery/img/icon_hot.gif | Bin 0 -> 97 bytes .../basic/skin/board/gallery/img/icon_img.gif | Bin 0 -> 145 bytes .../skin/board/gallery/img/icon_link.gif | Bin 0 -> 104 bytes .../skin/board/gallery/img/icon_mobile.gif | Bin 0 -> 62 bytes .../skin/board/gallery/img/icon_movie.gif | Bin 0 -> 110 bytes .../basic/skin/board/gallery/img/icon_new.gif | Bin 0 -> 71 bytes .../skin/board/gallery/img/icon_reply.gif | Bin 0 -> 77 bytes .../skin/board/gallery/img/icon_secret.gif | Bin 0 -> 97 bytes .../skin/board/gallery/img/icon_sound.gif | Bin 0 -> 113 bytes theme/basic/skin/board/gallery/list.skin.php | 249 ++++++++++ theme/basic/skin/board/gallery/style.css | 249 ++++++++++ theme/basic/skin/board/gallery/view.skin.php | 283 +++++++++++ .../skin/board/gallery/view_comment.skin.php | 330 +++++++++++++ theme/basic/skin/board/gallery/write.skin.php | 268 +++++++++++ .../basic/skin/connect/basic/connect.skin.php | 9 + .../connect/basic/current_connect.skin.php | 41 ++ theme/basic/skin/connect/basic/style.css | 1 + .../basic/skin/content/basic/content.skin.php | 17 + theme/basic/skin/content/basic/style.css | 8 + theme/basic/skin/faq/basic/list.skin.php | 136 ++++++ theme/basic/skin/faq/basic/style.css | 23 + .../basic/skin/latest/basic/img/icon_file.gif | Bin 0 -> 107 bytes .../basic/skin/latest/basic/img/icon_hot.gif | Bin 0 -> 97 bytes .../basic/skin/latest/basic/img/icon_img.gif | Bin 0 -> 145 bytes .../basic/skin/latest/basic/img/icon_link.gif | Bin 0 -> 104 bytes .../skin/latest/basic/img/icon_mobile.gif | Bin 0 -> 62 bytes .../basic/skin/latest/basic/img/icon_more.gif | Bin 0 -> 169 bytes .../skin/latest/basic/img/icon_movie.gif | Bin 0 -> 110 bytes .../basic/skin/latest/basic/img/icon_new.gif | Bin 0 -> 71 bytes .../skin/latest/basic/img/icon_reply.gif | Bin 0 -> 77 bytes .../skin/latest/basic/img/icon_secret.gif | Bin 0 -> 97 bytes .../skin/latest/basic/img/icon_sound.gif | Bin 0 -> 113 bytes theme/basic/skin/latest/basic/latest.skin.php | 44 ++ theme/basic/skin/latest/basic/style.css | 11 + .../basic/skin/member/basic/formmail.skin.php | 101 ++++ .../skin/member/basic/img/zip_ico_up.gif | Bin 0 -> 54 bytes theme/basic/skin/member/basic/login.skin.php | 60 +++ .../skin/member/basic/login_check.skin.php | 5 + .../skin/member/basic/member_confirm.skin.php | 50 ++ theme/basic/skin/member/basic/memo.skin.php | 53 +++ .../skin/member/basic/memo_form.skin.php | 59 +++ .../skin/member/basic/memo_view.skin.php | 60 +++ .../basic/skin/member/basic/password.skin.php | 50 ++ .../skin/member/basic/password_lost.skin.php | 47 ++ theme/basic/skin/member/basic/point.skin.php | 88 ++++ .../basic/skin/member/basic/profile.skin.php | 50 ++ .../basic/skin/member/basic/register.skin.php | 57 +++ .../skin/member/basic/register_form.skin.php | 441 ++++++++++++++++++ .../member/basic/register_result.skin.php | 46 ++ theme/basic/skin/member/basic/scrap.skin.php | 46 ++ .../skin/member/basic/scrap_popin.skin.php | 41 ++ theme/basic/skin/member/basic/style.css | 173 +++++++ theme/basic/skin/new/basic/new.skin.php | 144 ++++++ theme/basic/skin/new/basic/style.css | 7 + .../skin/outlogin/basic/outlogin.skin.1.php | 69 +++ .../skin/outlogin/basic/outlogin.skin.2.php | 46 ++ theme/basic/skin/outlogin/basic/style.css | 45 ++ theme/basic/skin/poll/basic/poll.skin.php | 67 +++ .../skin/poll/basic/poll_result.skin.php | 131 ++++++ theme/basic/skin/poll/basic/style.css | 90 ++++ .../basic/skin/popular/basic/popular.skin.php | 19 + theme/basic/skin/popular/basic/style.css | 12 + theme/basic/skin/qa/basic/img/btn_close.gif | Bin 0 -> 211 bytes theme/basic/skin/qa/basic/img/icon_answer.gif | Bin 0 -> 77 bytes theme/basic/skin/qa/basic/img/icon_file.gif | Bin 0 -> 107 bytes theme/basic/skin/qa/basic/img/icon_hot.gif | Bin 0 -> 97 bytes theme/basic/skin/qa/basic/img/icon_img.gif | Bin 0 -> 145 bytes theme/basic/skin/qa/basic/img/icon_link.gif | Bin 0 -> 104 bytes theme/basic/skin/qa/basic/img/icon_mobile.gif | Bin 0 -> 62 bytes theme/basic/skin/qa/basic/img/icon_movie.gif | Bin 0 -> 110 bytes theme/basic/skin/qa/basic/img/icon_new.gif | Bin 0 -> 71 bytes theme/basic/skin/qa/basic/img/icon_secret.gif | Bin 0 -> 97 bytes theme/basic/skin/qa/basic/img/icon_sound.gif | Bin 0 -> 113 bytes theme/basic/skin/qa/basic/list.skin.php | 167 +++++++ theme/basic/skin/qa/basic/style.css | 281 +++++++++++ .../basic/skin/qa/basic/view.answer.skin.php | 25 + .../skin/qa/basic/view.answerform.skin.php | 125 +++++ theme/basic/skin/qa/basic/view.skin.php | 187 ++++++++ theme/basic/skin/qa/basic/write.skin.php | 184 ++++++++ theme/basic/skin/search/basic/search.skin.php | 140 ++++++ theme/basic/skin/search/basic/style.css | 29 ++ theme/basic/skin/visit/basic/style.css | 13 + theme/basic/skin/visit/basic/visit.skin.php | 27 ++ theme/basic/tail.php | 57 +++ theme/basic/tail.sub.php | 25 + theme/basic/theme.config.php | 34 ++ 277 files changed, 14730 insertions(+), 310 deletions(-) create mode 100644 adm/css/theme.css create mode 100644 adm/img/close.gif create mode 100644 adm/img/link_icon.gif create mode 100644 adm/img/theme_img.jpg create mode 100644 adm/theme.js create mode 100644 adm/theme.php create mode 100644 adm/theme_config_load.php create mode 100644 adm/theme_detail.php create mode 100644 adm/theme_preview.php create mode 100644 adm/theme_update.php create mode 100644 lib/json.lib.php create mode 100644 theme/basic/_common.php create mode 100644 theme/basic/css/default.css create mode 100644 theme/basic/css/mobile.css create mode 100644 theme/basic/group.php create mode 100644 theme/basic/head.php create mode 100644 theme/basic/head.sub.php create mode 100644 theme/basic/img/gnb_bg00.gif create mode 100644 theme/basic/img/wrest.gif create mode 100644 theme/basic/index.php create mode 100644 theme/basic/mobile/_common.php create mode 100644 theme/basic/mobile/group.php create mode 100644 theme/basic/mobile/head.php create mode 100644 theme/basic/mobile/index.php create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_file.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_hot.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_img.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_link.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_mobile.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_movie.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_new.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_reply.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_secret.gif create mode 100644 theme/basic/mobile/skin/board/basic/img/icon_sound.gif create mode 100644 theme/basic/mobile/skin/board/basic/list.skin.php create mode 100644 theme/basic/mobile/skin/board/basic/style.css create mode 100644 theme/basic/mobile/skin/board/basic/view.skin.php create mode 100644 theme/basic/mobile/skin/board/basic/view_comment.skin.php create mode 100644 theme/basic/mobile/skin/board/basic/write.skin.php create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_file.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_hot.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_img.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_link.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_mobile.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_movie.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_new.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_reply.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_secret.gif create mode 100644 theme/basic/mobile/skin/board/gallery/img/icon_sound.gif create mode 100644 theme/basic/mobile/skin/board/gallery/list.skin.php create mode 100644 theme/basic/mobile/skin/board/gallery/style.css create mode 100644 theme/basic/mobile/skin/board/gallery/view.skin.php create mode 100644 theme/basic/mobile/skin/board/gallery/view_comment.skin.php create mode 100644 theme/basic/mobile/skin/board/gallery/write.skin.php create mode 100644 theme/basic/mobile/skin/connect/basic/connect.skin.php create mode 100644 theme/basic/mobile/skin/connect/basic/current_connect.skin.php create mode 100644 theme/basic/mobile/skin/connect/basic/style.css create mode 100644 theme/basic/mobile/skin/content/basic/content.skin.php create mode 100644 theme/basic/mobile/skin/content/basic/style.css create mode 100644 theme/basic/mobile/skin/faq/basic/list.skin.php create mode 100644 theme/basic/mobile/skin/faq/basic/style.css create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_file.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_hot.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_img.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_link.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_mobile.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_more.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_movie.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_new.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_reply.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_secret.gif create mode 100644 theme/basic/mobile/skin/latest/basic/img/icon_sound.gif create mode 100644 theme/basic/mobile/skin/latest/basic/latest.skin.php create mode 100644 theme/basic/mobile/skin/latest/basic/style.css create mode 100644 theme/basic/mobile/skin/member/basic/formmail.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/img/zip_ico_up.gif create mode 100644 theme/basic/mobile/skin/member/basic/login.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/login_check.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/member_confirm.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/memo.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/memo_form.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/memo_view.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/password.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/password_lost.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/point.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/profile.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/register.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/register_form.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/register_result.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/scrap.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/scrap_popin.skin.php create mode 100644 theme/basic/mobile/skin/member/basic/style.css create mode 100644 theme/basic/mobile/skin/new/basic/new.skin.php create mode 100644 theme/basic/mobile/skin/new/basic/style.css create mode 100644 theme/basic/mobile/skin/outlogin/basic/outlogin.skin.1.php create mode 100644 theme/basic/mobile/skin/outlogin/basic/outlogin.skin.2.php create mode 100644 theme/basic/mobile/skin/outlogin/basic/style.css create mode 100644 theme/basic/mobile/skin/poll/basic/poll.skin.php create mode 100644 theme/basic/mobile/skin/poll/basic/poll_result.skin.php create mode 100644 theme/basic/mobile/skin/poll/basic/style.css create mode 100644 theme/basic/mobile/skin/popular/basic/popular.skin.php create mode 100644 theme/basic/mobile/skin/popular/basic/style.css create mode 100644 theme/basic/mobile/skin/qa/basic/img/btn_close.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_answer.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_file.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_hot.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_img.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_link.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_mobile.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_movie.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_new.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_secret.gif create mode 100644 theme/basic/mobile/skin/qa/basic/img/icon_sound.gif create mode 100644 theme/basic/mobile/skin/qa/basic/list.skin.php create mode 100644 theme/basic/mobile/skin/qa/basic/style.css create mode 100644 theme/basic/mobile/skin/qa/basic/view.answer.skin.php create mode 100644 theme/basic/mobile/skin/qa/basic/view.answerform.skin.php create mode 100644 theme/basic/mobile/skin/qa/basic/view.skin.php create mode 100644 theme/basic/mobile/skin/qa/basic/write.skin.php create mode 100644 theme/basic/mobile/skin/search/basic/search.skin.php create mode 100644 theme/basic/mobile/skin/search/basic/style.css create mode 100644 theme/basic/mobile/skin/visit/basic/style.css create mode 100644 theme/basic/mobile/skin/visit/basic/visit.skin.php create mode 100644 theme/basic/mobile/tail.php create mode 100644 theme/basic/readme.txt create mode 100644 theme/basic/screenshot.png create mode 100644 theme/basic/skin/board/basic/img/btn_close.gif create mode 100644 theme/basic/skin/board/basic/img/icon_file.gif create mode 100644 theme/basic/skin/board/basic/img/icon_hot.gif create mode 100644 theme/basic/skin/board/basic/img/icon_img.gif create mode 100644 theme/basic/skin/board/basic/img/icon_link.gif create mode 100644 theme/basic/skin/board/basic/img/icon_mobile.gif create mode 100644 theme/basic/skin/board/basic/img/icon_movie.gif create mode 100644 theme/basic/skin/board/basic/img/icon_new.gif create mode 100644 theme/basic/skin/board/basic/img/icon_reply.gif create mode 100644 theme/basic/skin/board/basic/img/icon_secret.gif create mode 100644 theme/basic/skin/board/basic/img/icon_sound.gif create mode 100644 theme/basic/skin/board/basic/list.skin.php create mode 100644 theme/basic/skin/board/basic/style.css create mode 100644 theme/basic/skin/board/basic/view.skin.php create mode 100644 theme/basic/skin/board/basic/view_comment.skin.php create mode 100644 theme/basic/skin/board/basic/write.skin.php create mode 100644 theme/basic/skin/board/gallery/img/btn_close.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_file.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_hot.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_img.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_link.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_mobile.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_movie.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_new.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_reply.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_secret.gif create mode 100644 theme/basic/skin/board/gallery/img/icon_sound.gif create mode 100644 theme/basic/skin/board/gallery/list.skin.php create mode 100644 theme/basic/skin/board/gallery/style.css create mode 100644 theme/basic/skin/board/gallery/view.skin.php create mode 100644 theme/basic/skin/board/gallery/view_comment.skin.php create mode 100644 theme/basic/skin/board/gallery/write.skin.php create mode 100644 theme/basic/skin/connect/basic/connect.skin.php create mode 100644 theme/basic/skin/connect/basic/current_connect.skin.php create mode 100644 theme/basic/skin/connect/basic/style.css create mode 100644 theme/basic/skin/content/basic/content.skin.php create mode 100644 theme/basic/skin/content/basic/style.css create mode 100644 theme/basic/skin/faq/basic/list.skin.php create mode 100644 theme/basic/skin/faq/basic/style.css create mode 100644 theme/basic/skin/latest/basic/img/icon_file.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_hot.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_img.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_link.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_mobile.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_more.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_movie.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_new.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_reply.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_secret.gif create mode 100644 theme/basic/skin/latest/basic/img/icon_sound.gif create mode 100644 theme/basic/skin/latest/basic/latest.skin.php create mode 100644 theme/basic/skin/latest/basic/style.css create mode 100644 theme/basic/skin/member/basic/formmail.skin.php create mode 100644 theme/basic/skin/member/basic/img/zip_ico_up.gif create mode 100644 theme/basic/skin/member/basic/login.skin.php create mode 100644 theme/basic/skin/member/basic/login_check.skin.php create mode 100644 theme/basic/skin/member/basic/member_confirm.skin.php create mode 100644 theme/basic/skin/member/basic/memo.skin.php create mode 100644 theme/basic/skin/member/basic/memo_form.skin.php create mode 100644 theme/basic/skin/member/basic/memo_view.skin.php create mode 100644 theme/basic/skin/member/basic/password.skin.php create mode 100644 theme/basic/skin/member/basic/password_lost.skin.php create mode 100644 theme/basic/skin/member/basic/point.skin.php create mode 100644 theme/basic/skin/member/basic/profile.skin.php create mode 100644 theme/basic/skin/member/basic/register.skin.php create mode 100644 theme/basic/skin/member/basic/register_form.skin.php create mode 100644 theme/basic/skin/member/basic/register_result.skin.php create mode 100644 theme/basic/skin/member/basic/scrap.skin.php create mode 100644 theme/basic/skin/member/basic/scrap_popin.skin.php create mode 100644 theme/basic/skin/member/basic/style.css create mode 100644 theme/basic/skin/new/basic/new.skin.php create mode 100644 theme/basic/skin/new/basic/style.css create mode 100644 theme/basic/skin/outlogin/basic/outlogin.skin.1.php create mode 100644 theme/basic/skin/outlogin/basic/outlogin.skin.2.php create mode 100644 theme/basic/skin/outlogin/basic/style.css create mode 100644 theme/basic/skin/poll/basic/poll.skin.php create mode 100644 theme/basic/skin/poll/basic/poll_result.skin.php create mode 100644 theme/basic/skin/poll/basic/style.css create mode 100644 theme/basic/skin/popular/basic/popular.skin.php create mode 100644 theme/basic/skin/popular/basic/style.css create mode 100644 theme/basic/skin/qa/basic/img/btn_close.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_answer.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_file.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_hot.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_img.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_link.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_mobile.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_movie.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_new.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_secret.gif create mode 100644 theme/basic/skin/qa/basic/img/icon_sound.gif create mode 100644 theme/basic/skin/qa/basic/list.skin.php create mode 100644 theme/basic/skin/qa/basic/style.css create mode 100644 theme/basic/skin/qa/basic/view.answer.skin.php create mode 100644 theme/basic/skin/qa/basic/view.answerform.skin.php create mode 100644 theme/basic/skin/qa/basic/view.skin.php create mode 100644 theme/basic/skin/qa/basic/write.skin.php create mode 100644 theme/basic/skin/search/basic/search.skin.php create mode 100644 theme/basic/skin/search/basic/style.css create mode 100644 theme/basic/skin/visit/basic/style.css create mode 100644 theme/basic/skin/visit/basic/visit.skin.php create mode 100644 theme/basic/tail.php create mode 100644 theme/basic/tail.sub.php create mode 100644 theme/basic/theme.config.php diff --git a/adm/admin.lib.php b/adm/admin.lib.php index 38a1183f4..bc1ab9fcd 100644 --- a/adm/admin.lib.php +++ b/adm/admin.lib.php @@ -12,11 +12,30 @@ if (!get_session('ss_admin')) { // 스킨디렉토리를 SELECT 형식으로 얻음 function get_skin_select($skin_gubun, $id, $name, $selected='', $event='') { - $skins = get_skin_dir($skin_gubun); + global $config; + + $skins = array(); + + if(defined('G5_THEME_PATH') && $config['cf_theme']) { + $dirs = get_skin_dir($skin_gubun, G5_THEME_PATH.'/'.G5_SKIN_DIR); + if(!empty($dirs)) { + foreach($dirs as $dir) { + $skins[] = 'theme/'.$dir; + } + } + } + + $skins = array_merge($skins, get_skin_dir($skin_gubun)); + $str = ""; return $str; @@ -25,11 +44,30 @@ function get_skin_select($skin_gubun, $id, $name, $selected='', $event='') // 모바일 스킨디렉토리를 SELECT 형식으로 얻음 function get_mobile_skin_select($skin_gubun, $id, $name, $selected='', $event='') { - $skins = get_skin_dir($skin_gubun, G5_MOBILE_PATH.'/'.G5_SKIN_DIR); + global $config; + + $skins = array(); + + if(defined('G5_THEME_PATH') && $config['cf_theme']) { + $dirs = get_skin_dir($skin_gubun, G5_THEME_MOBILE_PATH.'/'.G5_SKIN_DIR); + if(!empty($dirs)) { + foreach($dirs as $dir) { + $skins[] = 'theme/'.$dir; + } + } + } + + $skins = array_merge($skins, get_skin_dir($skin_gubun, G5_MOBILE_PATH.'/'.G5_SKIN_DIR)); + $str = ""; return $str; @@ -44,6 +82,9 @@ function get_skin_dir($skin, $skin_path=G5_SKIN_PATH) $result_array = array(); $dirname = $skin_path.'/'.$skin.'/'; + if(!is_dir($dirname)) + return; + $handle = opendir($dirname); while ($file = readdir($handle)) { if($file == '.'||$file == '..') continue; @@ -57,6 +98,101 @@ function get_skin_dir($skin, $skin_path=G5_SKIN_PATH) } +// 테마 +function get_theme_dir() +{ + $result_array = array(); + + $dirname = G5_PATH.'/'.G5_THEME_DIR.'/'; + $handle = opendir($dirname); + while ($file = readdir($handle)) { + if($file == '.'||$file == '..') continue; + + if (is_dir($dirname.$file)) { + $theme_path = $dirname.$file; + if(is_file($theme_path.'/index.php') && is_file($theme_path.'/head.php') && is_file($theme_path.'/tail.php')) + $result_array[] = $file; + } + } + closedir($handle); + natsort($result_array); + + return $result_array; +} + + +// 테마정보 +function get_theme_info($dir) +{ + $info = array(); + $path = G5_PATH.'/'.G5_THEME_DIR.'/'.$dir; + + if(is_dir($path)) { + $screenshot = $path.'/screenshot.png'; + if(is_file($screenshot)) { + $size = @getimagesize($screenshot); + + if($size[2] == 3) + $screenshot_url = str_replace(G5_PATH, G5_URL, $screenshot); + } + + $info['screenshot'] = $screenshot_url; + + $text = $path.'/readme.txt'; + if(is_file($text)) { + $content = file($text, false); + $content = array_map('trim', $content); + + preg_match('#^Theme Name:(.+)$#i', $content[0], $m0); + preg_match('#^Theme URI:(.+)$#i', $content[1], $m1); + preg_match('#^Maker:(.+)$#i', $content[2], $m2); + preg_match('#^Maker URI:(.+)$#i', $content[3], $m3); + preg_match('#^Version:(.+)$#i', $content[4], $m4); + preg_match('#^Detail:(.+)$#i', $content[5], $m5); + preg_match('#^License:(.+)$#i', $content[6], $m6); + preg_match('#^License URI:(.+)$#i', $content[7], $m7); + + $info['theme_name'] = trim($m0[1]); + $info['theme_uri'] = trim($m1[1]); + $info['maker'] = trim($m2[1]); + $info['maker_uri'] = trim($m3[1]); + $info['version'] = trim($m4[1]); + $info['detail'] = trim($m5[1]); + $info['license'] = trim($m6[1]); + $info['license_uri'] = trim($m7[1]); + } + + if(!$info['theme_name']) + $info['theme_name'] = $dir; + } + + return $info; +} + + +// 테마설정 정보 +function get_theme_config_value($dir, $key='*') +{ + $tconfig = array(); + + $theme_config_file = G5_PATH.'/'.G5_THEME_DIR.'/'.$dir.'/theme.config.php'; + if(is_file) { + include($theme_config_file); + + if($key == '*') { + $tconfig = $theme_config; + } else { + $keys = array_map('trim', explode(',', $key)); + foreach($keys as $v) { + $tconfig[$v] = trim($theme_config[$v]); + } + } + } + + return $tconfig; +} + + // 회원권한을 SELECT 형식으로 얻음 function get_member_level_select($name, $start_id=0, $end_id=10, $selected="", $event="") { @@ -95,26 +231,48 @@ function get_member_id_select($name, $level, $selected="", $event="") } // 권한 검사 -function auth_check($auth, $attr) +function auth_check($auth, $attr, $return=false) { global $is_admin; if ($is_admin == 'super') return; - if (!trim($auth)) - alert('이 메뉴에는 접근 권한이 없습니다.\\n\\n접근 권한은 최고관리자만 부여할 수 있습니다.'); + if (!trim($auth)) { + $msg = '이 메뉴에는 접근 권한이 없습니다.\\n\\n접근 권한은 최고관리자만 부여할 수 있습니다.'; + if($return) + return $msg; + else + alert($msg); + } $attr = strtolower($attr); if (!strstr($auth, $attr)) { - if ($attr == 'r') - alert('읽을 권한이 없습니다.'); - else if ($attr == 'w') - alert('입력, 추가, 생성, 수정 권한이 없습니다.'); - else if ($attr == 'd') - alert('삭제 권한이 없습니다.'); - else - alert('속성이 잘못 되었습니다.'); + if ($attr == 'r') { + $msg = '읽을 권한이 없습니다.'; + if($return) + return $msg; + else + alert($msg); + } else if ($attr == 'w') { + $msg = '입력, 추가, 생성, 수정 권한이 없습니다.'; + if($return) + return $msg; + else + alert($msg); + } else if ($attr == 'd') { + $msg = '삭제 권한이 없습니다.'; + if($return) + return $msg; + else + alert($msg); + } else { + $msg = '속성이 잘못 되었습니다.'; + if($return) + return $msg; + else + alert($msg); + } } } diff --git a/adm/admin.menu100.php b/adm/admin.menu100.php index 26bdda490..44f93712a 100644 --- a/adm/admin.menu100.php +++ b/adm/admin.menu100.php @@ -3,6 +3,7 @@ $menu['menu100'] = array ( array('100000', '환경설정', G5_ADMIN_URL.'/config_form.php', 'config'), array('', '기본환경설정', G5_ADMIN_URL.'/config_form.php', 'cf_basic'), array('', '관리권한설정', G5_ADMIN_URL.'/auth_list.php', 'cf_auth'), + array('', '테마설정', G5_ADMIN_URL.'/theme.php', 'cf_theme', 1), array('', '메뉴설정', G5_ADMIN_URL.'/menu_list.php', 'cf_menu', 1), array('100300', '메일 테스트', G5_ADMIN_URL.'/sendmail_test.php', 'cf_mailtest'), array('100310', '팝업레이어관리', G5_ADMIN_URL.'/newwinlist.php', 'scf_poplayer'), diff --git a/adm/board_form.php b/adm/board_form.php index d40bd5756..c91fbb273 100644 --- a/adm/board_form.php +++ b/adm/board_form.php @@ -153,10 +153,9 @@ $pg_anchor = ' @@ -158,8 +157,8 @@ if (G5_IS_MOBILE) {
- - + +
-
+
\ No newline at end of file diff --git a/head.sub.php b/head.sub.php index 96a8d8d27..208c20c38 100644 --- a/head.sub.php +++ b/head.sub.php @@ -2,14 +2,14 @@ // 이 파일은 새로운 파일 생성시 반드시 포함되어야 함 if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가 -$begin_time = get_microtime(); - -// 사용자가 지정한 head.sub.php 파일이 있다면 include -if(defined('G5_HEAD_SUB_FILE') && is_file(G5_PATH.'/'.G5_HEAD_SUB_FILE)) { - include_once(G5_PATH.'/'.G5_HEAD_SUB_FILE); +// 테마 head.sub.php 파일 +if(!defined('G5_IS_ADMIN') && defined('G5_THEME_PATH') && is_file(G5_THEME_PATH.'/head.sub.php')) { + require_once(G5_THEME_PATH.'/head.sub.php'); return; } +$begin_time = get_microtime(); + if (!isset($g5['title'])) { $g5['title'] = $config['cf_title']; $g5_head_title = $g5['title']; @@ -54,7 +54,8 @@ if($config['cf_add_meta']) <?php echo $g5_head_title; ?> '.PHP_EOL; + if(!defined('_THEME_PREVIEW_')) + echo ''.PHP_EOL; } else { echo ''.PHP_EOL; } diff --git a/index.php b/index.php index 7dd4be537..becc86997 100644 --- a/index.php +++ b/index.php @@ -1,11 +1,12 @@

최신글

@@ -35,6 +36,7 @@ for ($i=0; $row=sql_fetch_array($result); $i++) {
@@ -44,5 +46,5 @@ for ($i=0; $row=sql_fetch_array($result); $i++) { +include_once(G5_PATH.'/tail.php'); +?> \ No newline at end of file diff --git a/install/gnuboard5.sql b/install/gnuboard5.sql index 731e6f53b..ce6977937 100644 --- a/install/gnuboard5.sql +++ b/install/gnuboard5.sql @@ -185,6 +185,7 @@ CREATE TABLE IF NOT EXISTS `g5_board_new` ( DROP TABLE IF EXISTS `g5_config`; CREATE TABLE IF NOT EXISTS `g5_config` ( `cf_title` varchar(255) NOT NULL DEFAULT '', + `cf_theme` varchar(255) NOT NULL DEFAULT '', `cf_admin` varchar(255) NOT NULL DEFAULT '', `cf_admin_email` varchar(255) NOT NULL DEFAULT '', `cf_admin_email_name` varchar(255) NOT NULL DEFAULT '', diff --git a/install/install_db.php b/install/install_db.php index 52d64d8d9..f7fbf935f 100644 --- a/install/install_db.php +++ b/install/install_db.php @@ -90,6 +90,7 @@ $download_point = 0; // config 테이블 설정 $sql = " insert into `{$table_prefix}config` set cf_title = '".G5_VERSION."', + cf_theme = 'basic', cf_admin = '$admin_id', cf_admin_email = '$admin_email', cf_admin_email_name = '".G5_VERSION."', diff --git a/js/autosave.js b/js/autosave.js index c03fe0188..b65891ff8 100644 --- a/js/autosave.js +++ b/js/autosave.js @@ -69,7 +69,7 @@ $(function(){ }); // 임시저장된 글 제목과 내용을 가져와서 제목과 내용 입력박스에 노출해 줌 - $(".autosave_load").live("click", function(){ + $(document).on( "click", ".autosave_load", function(){ var $li = $(this).parents("li"); var as_id = $li.data("as_id"); var as_uid = $li.data("uid"); @@ -93,7 +93,7 @@ $(function(){ $("#autosave_pop").hide(); }); - $(".autosave_del").live("click", function(){ + $(document).on( "click", ".autosave_del", function(){ var $li = $(this).parents("li"); var as_id = $li.data("as_id"); $.get(g5_bbs_url+"/ajax.autosavedel.php", {"as_id":as_id}, function(data){ diff --git a/js/common.js b/js/common.js index b964cd782..5344868bd 100644 --- a/js/common.js +++ b/js/common.js @@ -674,7 +674,7 @@ $(function(){ } }); - $("textarea#wr_content[maxlength]").live("keyup change", function() { + $(document).on( "keyup change", "textarea#wr_content[maxlength]", function(){ var str = $(this).val(); var mx = parseInt($(this).attr("maxlength")); if (str.length > mx) { diff --git a/lib/common.lib.php b/lib/common.lib.php index 9ffc825b1..c5baf7d4e 100644 --- a/lib/common.lib.php +++ b/lib/common.lib.php @@ -2993,4 +2993,39 @@ function get_device_change_url() return $href; } + +// 스킨 path +function get_skin_path($dir, $skin) +{ + global $config; + + if(preg_match('#^theme/(.+)$#', $skin, $match)) { // 테마에 포함된 스킨이라면 + $theme_path = ''; + $cf_theme = trim($config['cf_theme']); + + $theme_path = G5_PATH.'/'.G5_THEME_DIR.'/'.$cf_theme; + if(G5_IS_MOBILE) { + $skin_path = $theme_path.'/'.G5_MOBILE_DIR.'/'.G5_SKIN_DIR.'/'.$dir.'/'.$match[1]; + if(!is_dir($skin_path)) + $skin_path = $theme_path.'/'.G5_SKIN_DIR.'/'.$dir.'/'.$match[1]; + } else { + $skin_path = $theme_path.'/'.G5_SKIN_DIR.'/'.$dir.'/'.$match[1]; + } + } else { + if(G5_IS_MOBILE) + $skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/'.$dir.'/'.$skin; + else + $skin_path = G5_SKIN_PATH.'/'.$dir.'/'.$skin; + } + + return $skin_path; +} + +// 스킨 url +function get_skin_url($dir, $skin) +{ + $skin_path = get_skin_path($dir, $skin); + + return str_replace(G5_PATH, G5_URL, $skin_path); +} ?> \ No newline at end of file diff --git a/lib/connect.lib.php b/lib/connect.lib.php index e1ad4a841..3be01c4de 100644 --- a/lib/connect.lib.php +++ b/lib/connect.lib.php @@ -10,12 +10,25 @@ function connect($skin_dir='basic') $sql = " select sum(IF(mb_id<>'',1,0)) as mb_cnt, count(*) as total_cnt from {$g5['login_table']} where mb_id <> '{$config['cf_admin']}' "; $row = sql_fetch($sql); - if(G5_IS_MOBILE) { - $connect_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/connect/'.$skin_dir; - $connect_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/connect/'.$skin_dir; + if(preg_match('#^theme/(.+)$#', $skin_dir, $match)) { + if (G5_IS_MOBILE) { + $connect_skin_path = G5_THEME_MOBILE_PATH.'/'.G5_SKIN_DIR.'/connect/'.$match[1]; + if(!is_dir($connect_skin_path)) + $connect_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/connect/'.$match[1]; + $connect_skin_url = str_replace(G5_PATH, G5_URL, $connect_skin_path); + } else { + $connect_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/connect/'.$match[1]; + $connect_skin_url = str_replace(G5_PATH, G5_URL, $connect_skin_path); + } + $skin_dir = $match[1]; } else { - $connect_skin_path = G5_SKIN_PATH.'/connect/'.$skin_dir; - $connect_skin_url = G5_SKIN_URL.'/connect/'.$skin_dir; + if(G5_IS_MOBILE) { + $connect_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/connect/'.$skin_dir; + $connect_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/connect/'.$skin_dir; + } else { + $connect_skin_path = G5_SKIN_PATH.'/connect/'.$skin_dir; + $connect_skin_url = G5_SKIN_URL.'/connect/'.$skin_dir; + } } ob_start(); diff --git a/lib/json.lib.php b/lib/json.lib.php new file mode 100644 index 000000000..37fa82b10 --- /dev/null +++ b/lib/json.lib.php @@ -0,0 +1,79 @@ + $v) $result[] = json_encode($k).':'.json_encode($v); + return '{' . join(',', $result) . '}'; + } + } +} + +if(!function_exists('json_decode')) +{ + function json_decode($json) + { + $comment = false; + $out = '$x='; + for ($i=0; $i \ No newline at end of file diff --git a/lib/latest.lib.php b/lib/latest.lib.php index 150438b8e..9e9372774 100644 --- a/lib/latest.lib.php +++ b/lib/latest.lib.php @@ -6,16 +6,28 @@ if (!defined('_GNUBOARD_')) exit; function latest($skin_dir='', $bo_table, $rows=10, $subject_len=40, $cache_time=1, $options='') { global $g5; - //static $css = array(); if (!$skin_dir) $skin_dir = 'basic'; - if(G5_IS_MOBILE) { - $latest_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/latest/'.$skin_dir; - $latest_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/latest/'.$skin_dir; + if(preg_match('#^theme/(.+)$#', $skin_dir, $match)) { + if (G5_IS_MOBILE) { + $latest_skin_path = G5_THEME_MOBILE_PATH.'/'.G5_SKIN_DIR.'/latest/'.$match[1]; + if(!is_dir($latest_skin_path)) + $latest_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/latest/'.$match[1]; + $latest_skin_url = str_replace(G5_PATH, G5_URL, $latest_skin_path); + } else { + $latest_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/latest/'.$match[1]; + $latest_skin_url = str_replace(G5_PATH, G5_URL, $latest_skin_path); + } + $skin_dir = $match[1]; } else { - $latest_skin_path = G5_SKIN_PATH.'/latest/'.$skin_dir; - $latest_skin_url = G5_SKIN_URL.'/latest/'.$skin_dir; + if(G5_IS_MOBILE) { + $latest_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/latest/'.$skin_dir; + $latest_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/latest/'.$skin_dir; + } else { + $latest_skin_path = G5_SKIN_PATH.'/latest/'.$skin_dir; + $latest_skin_url = G5_SKIN_URL.'/latest/'.$skin_dir; + } } $cache_fwrite = false; @@ -60,14 +72,6 @@ function latest($skin_dir='', $bo_table, $rows=10, $subject_len=40, $cache_time= } } - /* - // 같은 스킨은 .css 를 한번만 호출한다. - if (!in_array($skin_dir, $css) && is_file($latest_skin_path.'/style.css')) { - echo ''; - $css[] = $skin_dir; - } - */ - ob_start(); include $latest_skin_path.'/latest.skin.php'; $content = ob_get_contents(); diff --git a/lib/outlogin.lib.php b/lib/outlogin.lib.php index fe94feacb..7f2916ec9 100644 --- a/lib/outlogin.lib.php +++ b/lib/outlogin.lib.php @@ -13,12 +13,25 @@ function outlogin($skin_dir='basic') $point = number_format($member['mb_point']); } - if (G5_IS_MOBILE) { - $outlogin_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/outlogin/'.$skin_dir; - $outlogin_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/outlogin/'.$skin_dir; + if(preg_match('#^theme/(.+)$#', $skin_dir, $match)) { + if (G5_IS_MOBILE) { + $outlogin_skin_path = G5_THEME_MOBILE_PATH.'/'.G5_SKIN_DIR.'/outlogin/'.$match[1]; + if(!is_dir($outlogin_skin_path)) + $outlogin_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/outlogin/'.$match[1]; + $outlogin_skin_url = str_replace(G5_PATH, G5_URL, $outlogin_skin_path); + } else { + $outlogin_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/outlogin/'.$match[1]; + $outlogin_skin_url = str_replace(G5_PATH, G5_URL, $outlogin_skin_path); + } + $skin_dir = $match[1]; } else { - $outlogin_skin_path = G5_SKIN_PATH.'/outlogin/'.$skin_dir; - $outlogin_skin_url = G5_SKIN_URL.'/outlogin/'.$skin_dir; + if (G5_IS_MOBILE) { + $outlogin_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/outlogin/'.$skin_dir; + $outlogin_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/outlogin/'.$skin_dir; + } else { + $outlogin_skin_path = G5_SKIN_PATH.'/outlogin/'.$skin_dir; + $outlogin_skin_url = G5_SKIN_URL.'/outlogin/'.$skin_dir; + } } // 읽지 않은 쪽지가 있다면 diff --git a/lib/poll.lib.php b/lib/poll.lib.php index eb8527dea..f45693c8d 100644 --- a/lib/poll.lib.php +++ b/lib/poll.lib.php @@ -15,16 +15,30 @@ function poll($skin_dir='basic', $po_id=false) if(!$po_id) return; + if(preg_match('#^theme/(.+)$#', $skin_dir, $match)) { + if (G5_IS_MOBILE) { + $poll_skin_path = G5_THEME_MOBILE_PATH.'/'.G5_SKIN_DIR.'/poll/'.$match[1]; + if(!is_dir($poll_skin_path)) + $poll_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/poll/'.$match[1]; + $poll_skin_url = str_replace(G5_PATH, G5_URL, $poll_skin_path); + } else { + $poll_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/poll/'.$match[1]; + $poll_skin_url = str_replace(G5_PATH, G5_URL, $poll_skin_path); + } + $skin_dir = $match[1]; + } else { + if (G5_IS_MOBILE) { + $poll_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; + $poll_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; + } else { + $poll_skin_path = G5_SKIN_PATH.'/poll/'.$skin_dir; + $poll_skin_url = G5_SKIN_URL.'/poll/'.$skin_dir; + } + } + $po = sql_fetch(" select * from {$g5['poll_table']} where po_id = '$po_id' "); ob_start(); - if (G5_IS_MOBILE) { - $poll_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; - $poll_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; - } else { - $poll_skin_path = G5_SKIN_PATH.'/poll/'.$skin_dir; - $poll_skin_url = G5_SKIN_URL.'/poll/'.$skin_dir; - } include_once ($poll_skin_path.'/poll.skin.php'); $content = ob_get_contents(); ob_end_clean(); diff --git a/lib/popular.lib.php b/lib/popular.lib.php index c7e5ab1de..fcb9c0801 100644 --- a/lib/popular.lib.php +++ b/lib/popular.lib.php @@ -20,14 +20,28 @@ function popular($skin_dir='basic', $pop_cnt=7, $date_cnt=3) $list[$i]['pp_word'] = get_text($list[$i]['pp_word']); } - ob_start(); - if(G5_IS_MOBILE) { - $popular_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/popular/'.$skin_dir; - $popular_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/popular/'.$skin_dir; + if(preg_match('#^theme/(.+)$#', $skin_dir, $match)) { + if (G5_IS_MOBILE) { + $popular_skin_path = G5_THEME_MOBILE_PATH.'/'.G5_SKIN_DIR.'/popular/'.$match[1]; + if(!is_dir($popular_skin_path)) + $popular_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/popular/'.$match[1]; + $popular_skin_url = str_replace(G5_PATH, G5_URL, $popular_skin_path); + } else { + $popular_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/popular/'.$match[1]; + $popular_skin_url = str_replace(G5_PATH, G5_URL,$popular_skin_path); + } + $skin_dir = $match[1]; } else { - $popular_skin_path = G5_SKIN_PATH.'/popular/'.$skin_dir; - $popular_skin_url = G5_SKIN_URL.'/popular/'.$skin_dir; + if(G5_IS_MOBILE) { + $popular_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/popular/'.$skin_dir; + $popular_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/popular/'.$skin_dir; + } else { + $popular_skin_path = G5_SKIN_PATH.'/popular/'.$skin_dir; + $popular_skin_url = G5_SKIN_URL.'/popular/'.$skin_dir; + } } + + ob_start(); include_once ($popular_skin_path.'/popular.skin.php'); $content = ob_get_contents(); ob_end_clean(); diff --git a/lib/visit.lib.php b/lib/visit.lib.php index ed0677857..1808fd5f7 100644 --- a/lib/visit.lib.php +++ b/lib/visit.lib.php @@ -18,14 +18,28 @@ function visit($skin_dir='basic') settype($visit[3], "integer"); settype($visit[4], "integer"); - ob_start(); - if(G5_IS_MOBILE) { - $visit_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/visit/'.$skin_dir; - $visit_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/visit/'.$skin_dir; + if(preg_match('#^theme/(.+)$#', $skin_dir, $match)) { + if (G5_IS_MOBILE) { + $visit_skin_path = G5_THEME_MOBILE_PATH.'/'.G5_SKIN_DIR.'/visit/'.$match[1]; + if(!is_dir($visit_skin_path)) + $visit_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/visit/'.$match[1]; + $visit_skin_url = str_replace(G5_PATH, G5_URL, $visit_skin_path); + } else { + $visit_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/visit/'.$match[1]; + $visit_skin_url = str_replace(G5_PATH, G5_URL, $visit_skin_path); + } + $skin_dir = $match[1]; } else { - $visit_skin_path = G5_SKIN_PATH.'/visit/'.$skin_dir; - $visit_skin_url = G5_SKIN_URL.'/visit/'.$skin_dir; + if(G5_IS_MOBILE) { + $visit_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/visit/'.$skin_dir; + $visit_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/visit/'.$skin_dir; + } else { + $visit_skin_path = G5_SKIN_PATH.'/visit/'.$skin_dir; + $visit_skin_url = G5_SKIN_URL.'/visit/'.$skin_dir; + } } + + ob_start(); include_once ($visit_skin_path.'/visit.skin.php'); $content = ob_get_contents(); ob_end_clean(); diff --git a/mobile/content.php b/mobile/content.php index c789834b8..cb683b2e1 100644 --- a/mobile/content.php +++ b/mobile/content.php @@ -49,8 +49,8 @@ $str = preg_replace($src, $dst, $str); if(trim($co['co_mobile_skin']) == '') $co['co_mobile_skin'] = 'basic'; -$content_skin_path = G5_MOBILE_PATH .'/'.G5_SKIN_DIR.'/content/'.$co['co_mobile_skin']; -$content_skin_url = G5_MOBILE_URL .'/'.G5_SKIN_DIR.'/content/'.$co['co_mobile_skin']; +$content_skin_path = get_skin_path('content', $co['co_mobile_skin']); +$content_skin_url = get_skin_url('content', $co['co_mobile_skin']); $skin_file = $content_skin_path.'/content.skin.php'; if(is_file($skin_file)) { diff --git a/mobile/head.php b/mobile/head.php index 3a580e3d6..c7727e996 100644 --- a/mobile/head.php +++ b/mobile/head.php @@ -1,6 +1,11 @@ @@ -26,5 +31,5 @@ for ($i=0; $row=sql_fetch_array($result); $i++) { \ No newline at end of file diff --git a/mobile/skin/board/basic/view.skin.php b/mobile/skin/board/basic/view.skin.php index 1b8ba0c93..d3c88271d 100644 --- a/mobile/skin/board/basic/view.skin.php +++ b/mobile/skin/board/basic/view.skin.php @@ -179,7 +179,7 @@ add_stylesheet('', 0
diff --git a/mobile/skin/board/gallery/view.skin.php b/mobile/skin/board/gallery/view.skin.php index 7b7e369ab..8dcba3f09 100644 --- a/mobile/skin/board/gallery/view.skin.php +++ b/mobile/skin/board/gallery/view.skin.php @@ -179,7 +179,7 @@ add_stylesheet('', 0
diff --git a/mobile/tail.php b/mobile/tail.php index 44d88ff22..723b51cd8 100644 --- a/mobile/tail.php +++ b/mobile/tail.php @@ -1,5 +1,10 @@
diff --git a/plugin/editor/smarteditor2/editor.lib.php b/plugin/editor/smarteditor2/editor.lib.php index 8ef0c9ccf..2fd2473a3 100644 --- a/plugin/editor/smarteditor2/editor.lib.php +++ b/plugin/editor/smarteditor2/editor.lib.php @@ -29,7 +29,7 @@ function editor_html($id, $content, $is_dhtml_editor=true) $(this).text("단축키 일람 닫기"); } }); - $(".btn_cke_sc_close").live("click",function(){ + $(document).on("click", ".btn_cke_sc_close", function(){ $(this).parent("div.cke_sc_def").remove(); }); });'; diff --git a/plugin/kcaptcha/kcaptcha.js b/plugin/kcaptcha/kcaptcha.js index a70f09066..8d1c2b218 100644 --- a/plugin/kcaptcha/kcaptcha.js +++ b/plugin/kcaptcha/kcaptcha.js @@ -1,7 +1,7 @@ $(function(){ var mp3_url = ""; - $("#captcha_reload").live("click", function(){ + $(document).on( "click", "#captcha_reload", function(){ $.ajax({ type: 'POST', url: g5_captcha_url+'/kcaptcha_session.php', @@ -24,9 +24,9 @@ $(function(){ } } }); - }).trigger("click"); + }); - $("#captcha_mp3").live("click", function(){ + $(document).on( "click", "#captcha_mp3", function(){ $("body").css("cursor", "wait"); $.ajax({ @@ -74,6 +74,8 @@ $(function(){ return false; }).css('cursor', 'pointer'); + + $("#captcha_reload").trigger("click"); }); // 출력된 캡챠이미지의 키값과 입력한 키값이 같은지 비교한다. diff --git a/plugin/sns/view_comment_write.sns.skin.php b/plugin/sns/view_comment_write.sns.skin.php index c47fc9f32..75584ba35 100644 --- a/plugin/sns/view_comment_write.sns.skin.php +++ b/plugin/sns/view_comment_write.sns.skin.php @@ -41,7 +41,7 @@ if ($config['cf_facebook_appid']) { echo ''; echo ''; echo ''; - echo ''; + echo ''; } echo ''; } @@ -99,7 +99,7 @@ if ($config['cf_twitter_key']) { echo ''; echo ''; echo ''; - echo ''; + echo ''; } echo ''; } diff --git a/skin/board/basic/view.skin.php b/skin/board/basic/view.skin.php index 22efc3c16..7670a331c 100644 --- a/skin/board/basic/view.skin.php +++ b/skin/board/basic/view.skin.php @@ -191,7 +191,7 @@ add_stylesheet('', 0 diff --git a/skin/board/basic/view_comment.skin.php b/skin/board/basic/view_comment.skin.php index cea2d1c63..20d997b44 100644 --- a/skin/board/basic/view_comment.skin.php +++ b/skin/board/basic/view_comment.skin.php @@ -142,7 +142,7 @@ var char_max = parseInt(); // 최대 onkeyup="check_byte('wr_content', 'char_count');"> + + +
+ + + + +
+ + +
+ +
+ + + + + +
+ + +
+
+ + +
+
+
\ No newline at end of file diff --git a/theme/basic/head.sub.php b/theme/basic/head.sub.php new file mode 100644 index 000000000..78a36adff --- /dev/null +++ b/theme/basic/head.sub.php @@ -0,0 +1,91 @@ + + + + + +'.PHP_EOL; + echo ''.PHP_EOL; + echo ''.PHP_EOL; +} else { + echo ''.PHP_EOL; + echo ''.PHP_EOL; +} + +if($config['cf_add_meta']) + echo $config['cf_add_meta'].PHP_EOL; +?> +<?php echo $g5_head_title; ?> + + + + + + + +'.PHP_EOL; // overflow scroll 감지 +} +?> + + +'.$sr_admin_msg.$member['mb_nick'].'님 로그인 중 '; + echo '로그아웃
'; +} +?> \ No newline at end of file diff --git a/theme/basic/img/gnb_bg00.gif b/theme/basic/img/gnb_bg00.gif new file mode 100644 index 0000000000000000000000000000000000000000..fd24f34da9bdf9a056c6bd3c311849133bf97407 GIT binary patch literal 54 zcmZ?wbhEHb6k%XtXkcWhtgQV1|G(l-7DfgJMg|=QAOOiQF!8qVFFf6IbCK~Ty^Lr^ G25SI*`VKV! literal 0 HcmV?d00001 diff --git a/theme/basic/img/wrest.gif b/theme/basic/img/wrest.gif new file mode 100644 index 0000000000000000000000000000000000000000..a5ecfb334be107c3830c02709fb06c8ef837ebef GIT binary patch literal 51 zcmZ?wbhEHbWMg1sXkcWBjrIHg|G(l-7DfgJMg|=QAOOiQFmbiWr%ycbk74!#1_o;Y DKOqcu literal 0 HcmV?d00001 diff --git a/theme/basic/index.php b/theme/basic/index.php new file mode 100644 index 000000000..bb7a67441 --- /dev/null +++ b/theme/basic/index.php @@ -0,0 +1,43 @@ + + +

최신글

+ + 'mobile' "; +if(!$is_admin) + $sql .= " and a.bo_use_cert = '' "; +$sql .= " order by b.gr_order, a.bo_order "; +$result = sql_query($sql); +for ($i=0; $row=sql_fetch_array($result); $i++) { + if ($i%2==1) $lt_style = "margin-left:20px"; + else $lt_style = ""; +?> +
+ +
+ + + + \ No newline at end of file diff --git a/theme/basic/mobile/_common.php b/theme/basic/mobile/_common.php new file mode 100644 index 000000000..2ce42a3fc --- /dev/null +++ b/theme/basic/mobile/_common.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/theme/basic/mobile/group.php b/theme/basic/mobile/group.php new file mode 100644 index 000000000..06eb09b4a --- /dev/null +++ b/theme/basic/mobile/group.php @@ -0,0 +1,35 @@ + + + + 'pc' "; +if(!$is_admin) + $sql .= " and bo_use_cert = '' "; +$sql .= " order by bo_table "; +$result = sql_query($sql); +for ($i=0; $row=sql_fetch_array($result); $i++) { + // 이 함수가 바로 최신글을 추출하는 역할을 합니다. + // 스킨은 입력하지 않을 경우 관리자 > 환경설정의 최신글 스킨경로를 기본 스킨으로 합니다. + + // 사용방법 + // latest(스킨, 게시판아이디, 출력라인, 글자수); + echo latest('theme/basic', $row['bo_table'], 5, 70); +} +?> + + + diff --git a/theme/basic/mobile/head.php b/theme/basic/mobile/head.php new file mode 100644 index 000000000..d45c8969d --- /dev/null +++ b/theme/basic/mobile/head.php @@ -0,0 +1,177 @@ + + +
+

+ + + + + +
+ + + + + +
+
    + +
  • + + '.PHP_EOL; + ?> +
  • + 0) + echo '
'.PHP_EOL; + ?> + + +
  • 메뉴 준비 중입니다.
    관리자모드 > 환경설정 > 메뉴설정에서 설정하세요.
  • + + + +
    + + + +
    +

    사이트 내 전체검색

    +
    + + + + +
    + + + +
    + + + + + +
    +
    + +
    + +
    +
    + +
    +
    +
    +
    + + + + +
    \ No newline at end of file diff --git a/theme/basic/mobile/index.php b/theme/basic/mobile/index.php new file mode 100644 index 000000000..3df4ba11b --- /dev/null +++ b/theme/basic/mobile/index.php @@ -0,0 +1,30 @@ + + + + 'pc' "; +if(!$is_admin) + $sql .= " and a.bo_use_cert = '' "; +$sql .= " order by b.gr_order, a.bo_order "; +$result = sql_query($sql); +for ($i=0; $row=sql_fetch_array($result); $i++) { + // 이 함수가 바로 최신글을 추출하는 역할을 합니다. + // 스킨은 입력하지 않을 경우 관리자 > 환경설정의 최신글 스킨경로를 기본 스킨으로 합니다. + + // 사용방법 + // latest(스킨, 게시판아이디, 출력라인, 글자수); + echo latest('theme/basic', $row['bo_table'], 5, 25); +} +?> + + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/board/basic/img/icon_file.gif b/theme/basic/mobile/skin/board/basic/img/icon_file.gif new file mode 100644 index 0000000000000000000000000000000000000000..cca47f566ac0db655fb2ab0f56628b64958e48b2 GIT binary patch literal 107 zcmZ?wbhEHb-Wqsc#^P~2x#@rVooH@5wHB9i@BozKb;P9uI^*c|UyXO5@>VyLmgEat< Cr6(f* literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/basic/img/icon_hot.gif b/theme/basic/mobile/skin/board/basic/img/icon_hot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c95b839aeef0c1e26a4bab4ea50cd6d3f1969d7f GIT binary patch literal 97 zcmZ?wbhEHbzHen|7VvwFnzUPlarEA ZqW~YXyUO~T+#YkUoJ%V_>ib05Q5F AasU7T literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/basic/img/icon_mobile.gif b/theme/basic/mobile/skin/board/basic/img/icon_mobile.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad934d23c440c83db0c4589596465cb087353e01 GIT binary patch literal 62 zcmZ?wbhEHbZ% literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/basic/img/icon_reply.gif b/theme/basic/mobile/skin/board/basic/img/icon_reply.gif new file mode 100644 index 0000000000000000000000000000000000000000..91c135977b4f445a90c849310dc80efde1983830 GIT binary patch literal 77 zcmZ?wbhEHb&!1E4^4&ClEzh)PmWxV3{9A~!gB2-%RL5bHcgg3Zp^!+W)H2^A_AxQuL literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/basic/img/icon_sound.gif b/theme/basic/mobile/skin/board/basic/img/icon_sound.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5188318a5cdc394b984125c0ddd376c5f57bbe4 GIT binary patch literal 113 zcmZ?wbhEHbE1CJY$zMikVi`-#gIi|DbmsXBWf6U5szE@->A`0*`&<;b@XASRrB8=E6~=S>Pbm I%fes{0AXt-SpWb4 literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/basic/list.skin.php b/theme/basic/mobile/skin/board/basic/list.skin.php new file mode 100644 index 000000000..b9946b974 --- /dev/null +++ b/theme/basic/mobile/skin/board/basic/list.skin.php @@ -0,0 +1,224 @@ +', 0); +?> + +

    목록

    + + +
    "> + + + + + +
    +
    + Total + 페이지 +
    + + + + +
    + +
    + + + + + + + + + + + + +
    + + + +
    + +
    +
    + + + + + + + + +
    + 게시물 검색 + +
    + + + + + + + +
    +
    + + + + + diff --git a/theme/basic/mobile/skin/board/basic/style.css b/theme/basic/mobile/skin/board/basic/style.css new file mode 100644 index 000000000..b1d433d3a --- /dev/null +++ b/theme/basic/mobile/skin/board/basic/style.css @@ -0,0 +1,238 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +/* 게시판 버튼 */ +/* 목록 버튼 */ +#bo_list a.btn_b01 {} +#bo_list a.btn_b01:focus, #bo_list .btn_b01:hover {} +#bo_list a.btn_b02 {} +#bo_list a.btn_b02:focus, #bo_list .btn_b02:hover {} +#bo_list a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_list a.btn_admin:focus, #bo_list a.btn_admin:hover {} + +/* 읽기 버튼 */ +#bo_v a.btn_b01 {} +#bo_v a.btn_b01:focus, #bo_v .btn_b01:hover {} +#bo_v a.btn_b02 {} +#bo_v a.btn_b02:focus, #bo_v .btn_b02:hover {} +#bo_v a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_v a.btn_admin:focus, #bo_v a.btn_admin:hover {} + +/* 쓰기 버튼 */ +#bo_w .btn_confirm {} /* 서식단계 진행 */ +#bo_w .btn_submit {} +#bo_w .btn_cancel {} +#bo_w .btn_frmline {} /* 우편번호검색버튼 등 */ + +/* 기본테이블 */ +/* 목록 테이블 */ +#bo_list .tbl_head01 {} +#bo_list .tbl_head01 caption {} +#bo_list .tbl_head01 thead th {} +#bo_list .tbl_head01 thead a {} +#bo_list .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_list .tbl_head01 tfoot th {} +#bo_list .tbl_head01 tfoot td {} +#bo_list .tbl_head01 tbody th {} +#bo_list .tbl_head01 td {} +#bo_list .tbl_head01 a {} +#bo_list td.empty_table {} + +/* 읽기 내 테이블 */ +#bo_v .tbl_head01 {} +#bo_v .tbl_head01 caption {} +#bo_v .tbl_head01 thead th {} +#bo_v .tbl_head01 thead a {} +#bo_v .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_v .tbl_head01 tfoot th {} +#bo_v .tbl_head01 tfoot td {} +#bo_v .tbl_head01 tbody th {} +#bo_v .tbl_head01 td {} +#bo_v .tbl_head01 a {} +#bo_v td.empty_table {} + +/* 쓰기 테이블 */ +#bo_w table {} +#bo_w caption {} +#bo_w .frm_address {} +#bo_w .frm_file {} +#bo_w .frm_info {} + +#bo_w .tbl_frm01 {} +#bo_w .tbl_frm01 caption {} +#bo_w .tbl_frm01 th {} +#bo_w .tbl_frm01 td {} +#bo_w .tbl_frm01 textarea, #bo_w .frm_input {} +#bo_w .tbl_frm01 textarea {} +/* +#bo_w .tbl_frm01 #captcha {} +#bo_w .tbl_frm01 #captcha input {} +*/ +#bo_w .tbl_frm01 a {} + +#bo_w .required, #bo_w textarea.required {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 게시판 목록 */ +#bo_list .td_chk {width:30px;text-align:center} +#bo_list .td_group {width:100px;text-align:center} +#bo_list .td_board {width:120px;text-align:center} +#bo_list .td_num {width:50px;text-align:center} +#bo_list .td_numbig {width:80px;text-align:center} +#bo_list .td_mb_id {width:100px;text-align:center} +#bo_list .td_nick {width:100px;text-align:center} +#bo_list .td_name {width:100px;text-align:left} +#bo_list .td_date {width:60px;text-align:center} +#bo_list .td_datetime {width:150px;text-align:center} +#bo_list .td_mng {width:80px;text-align:center} + +#bo_cate h2 {width:0;height:0;font-size:0;line-height:0;overflow:hidden} +#bo_cate ul {margin:5px 10px;padding-left:1px;zoom:1} +#bo_cate ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_cate li {float:left;margin-bottom:-1px;width:25%} +#bo_cate a {display:block;position:relative;margin-left:-1px;padding:5px 0;border:1px solid #ddd;background:#f7f7f7;color:#888;text-align:center;text-decoration:none;letter-spacing:-0.1em} +#bo_cate a:focus, #bo_cate a:hover, #bo_cate a:active {text-decoration:none} +#bo_cate #bo_cate_on {z-index:2;border:1px solid #565e60;background:#fff;color:#565e60;font-weight:bold} + +/* 관리자일 때 */ +#bo_list_admin th label {position:absolute;font-size:0;line-height:0;overflow:hidden} + +#bo_list_admin th:nth-of-type(1) {width:40px} +#bo_list_admin th:nth-of-type(3) {width:100px} + +#bo_list_admin td:nth-of-type(1) {text-align:center} +#bo_list_admin td:nth-of-type(3) {text-align:center} + +/* 관리자가 아닐 때 */ +#bo_list th:nth-of-type(2) {width:100px} + +#bo_list td:nth-of-type(2) {text-align:center} + +/* 게시판 목록 공통 */ +.bo_fx {margin-bottom:5px;padding:5px 10px} +.bo_fx:after {display:block;visibility:hidden;clear:both;content:""} +.bo_fx ul {margin:0;padding:0;list-style:none} +#bo_list_total {float:left;padding:0;height:2.5em;line-height:2.5em} +.btn_bo_user {float:right;margin:0;padding:0;list-style:none} +.btn_bo_user li {float:left;margin-left:5px} +.btn_bo_adm {float:left} +.btn_bo_adm li {float:left;margin-right:5px} +.btn_bo_adm input {padding:8px;border:0;background:#e8180c;color:#fff;text-decoration:none;vertical-align:middle} +.bo_notice td {background:#f7f7f7} +.bo_notice td a {font-weight:bold} +.td_num strong {color:#000} +.bo_cate_link {display:inline-block;margin:0 3px 0 0;padding:0 6px 0 0;border-right:1px solid #e7f1ed;color:#999 !important;font-weight:bold;text-decoration:none} /* 글제목줄 분류스타일 */ +.bo_current {color:#e8180c} +.td_subject a {display:block} +.td_subject img {margin-left:3px} +#bo_list .cnt_cmt {display:inline-block;margin:0 0 0 3px;font-weight:bold} + +#bo_sch {margin-bottom:10px;padding-top:5px;text-align:center} + +/* 게시판 쓰기 */ +#bo_w #wr_email, #bo_w #wr_homepage, #bo_w #wr_subject {width:100%} + +#char_count_desc {display:block;margin:0 0 5px;padding:0} +#char_count_wrap {margin:5px 0 0;text-align:right} +#char_count {font-weight:bold} + +#wr_email, #wr_homepage, #wr_subject, .wr_link {width:100%} + +/* 게시판 읽기 */ +#bo_v {margin-bottom:15px;padding-bottom:15px} + +#bo_v_table {padding:0 10px;color:#999;font-size:0.9em;font-weight:bold} + +#bo_v_title {padding:0 10px 5px;font-size:1.2em} + +#bo_v_info {padding:0 10px 10px;border-bottom:1px solid #ddd} +#bo_v_info h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_info {} +#bo_v_info strong {display:inline-block;margin:0 0 0 5px;font-weight:normal} + +#bo_v_file {} +#bo_v_file h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_file ul {margin:0;padding:0;list-style:none} +#bo_v_file li {padding:0 10px;border-bottom:1px solid #eee;background:#f7f7f7} +#bo_v_file a {display:inline-block;padding:5px 0;color:#000;text-decoration:none} +#bo_v_file a:focus, #bo_v_file a:hover, #bo_v_file a:active {text-decoration:none} +.bo_v_file_cnt {display:inline-block;margin:0 10px} + +#bo_v_link {} +#bo_v_link h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_link ul {margin:0;padding:0;list-style:none} +#bo_v_link li {padding:0 10px;border-bottom:1px solid #eee;background:#f7f7f7} +#bo_v_link a {display:inline-block;padding:5px 0;color:#000;text-decoration:none} +#bo_v_link a:focus, #bo_v_link a:hover, #bo_v_link a:active {text-decoration:none} +.bo_v_link_cnt {display:inline-block;margin:0 10px} + +#bo_v_top {margin:0 0 10px;padding:10px} +#bo_v_top:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_top h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_top ul {margin:0;padding:0;list-style:none} + +#bo_v_bot {padding:0 10px} +#bo_v_bot:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_bot h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_bot ul {margin:0;padding:0;list-style:none} + +.bo_v_nb {float:left} +.bo_v_nb li {float:left;margin-right:5px} +.bo_v_com {float:right} +.bo_v_com li {float:left;margin-left:5px} + +#bo_v_atc {padding:0 10px;min-height:200px} +#bo_v_atc_title {margin:0;padding:0;height:0;overflow:hidden} + +#bo_v_img {margin:0 0 10px;width:100%;overflow:hidden;zoom:1} +#bo_v_img:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_img img {margin-bottom:15px;max-width:100%;height:auto} + +#bo_v_con {margin-bottom:20px;width:100%;font-size:1.250em;line-height:1.7em;word-break:break-all;overflow:hidden} +#bo_v_con a {color:#000;text-decoration:underline} +#bo_v_con img {max-width:100%;height:auto} + +#bo_v_act {position:relative;margin-bottom:20px;text-align:center} +#bo_v_act a {margin-right:5px;vertical-align:middle} +#bo_v_act strong {color:#ff3061} +#bo_v_act_good, #bo_v_act_nogood {display:none;position:absolute;top:30px;right:10%;padding:10px 0;width:165px;background:#ff3061;color:#fff;text-align:center} + +#bo_v_sns {margin:0 0 20px;padding:0;list-style:none;zoom:1} +#bo_v_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_sns li {float:left;margin:0 5px 0 0} + +/* 게시판 댓글 */ +#bo_vc {margin:0 0 20px;padding:20px 10px 10px;border:1px solid #e5e8ec;background:#f5f8f9} +#bo_vc h2 {margin-bottom:5px} +#bo_vc article {padding:0 0 5px;border-top:1px dotted #ccc} +#bo_vc header {position:relative;padding:13px 0 5px} +#bo_vc header .icon_reply {position:absolute;top:13px;left:-20px} +#bo_vc .sv_member, #bo_vc .sv_guest {font-weight:bold} +.bo_vc_hdinfo {display:inline-block;margin:0 10px 0 5px} +#bo_vc h1 {width:0;height:0;font-size:0;line-height:0;overflow:hidden} +#bo_vc a {color:#000;text-decoration:none} +#bo_vc p {padding:0 0 5px;line-height:1.8em} +#bo_vc p a {text-decoration:underline} +#bo_vc p a.s_cmt {text-decoration:none} +#bo_vc_empty {margin:0;padding:15px !important;text-align:center} +#bo_vc #bo_vc_winfo {float:left} +#bo_vc footer {zoom:1} +#bo_vc footer:after {display:block;visibility:hidden;clear:both;content:""} + +.bo_vc_act {float:right;margin:0;list-style:none} +.bo_vc_act:after {display:block;visibility:hidden;clear:both;content:""} +.bo_vc_act li {float:left;margin-left:5px} + +#bo_vc_w {position:relative;margin-bottom:10px;padding:0 10px 15px;border-bottom:1px solid #dde4e9} +#bo_vc_w h2 {padding:10px 0 5px} +#bo_vc_w .tbl_wrap {margin:0 0 15px} +#bo_vc_w #char_cnt {display:block;margin-bottom:5px} +#bo_vc_w textarea {width:99%} + +#bo_vc_sns {margin:0;padding:0;list-style:none;zoom:1} +#bo_vc_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_vc_sns li {float:left;margin:0 10px 0 0} +#bo_vc_sns input {margin:0 0 0 5px} \ No newline at end of file diff --git a/theme/basic/mobile/skin/board/basic/view.skin.php b/theme/basic/mobile/skin/board/basic/view.skin.php new file mode 100644 index 000000000..7311cf9ef --- /dev/null +++ b/theme/basic/mobile/skin/board/basic/view.skin.php @@ -0,0 +1,270 @@ +', 0); +?> + + + +
    + +
    +
    +

    + +

    +
    + +
    +

    페이지 정보

    + 작성자 + 작성일 + 조회 + 댓글 +
    + + + + +
    +

    첨부파일

    + +
    + + + + + + +
    + + + + + + + +
    + +
    +

    본문

    + + \n"; + + for ($i=0; $i<=count($view['file']); $i++) { + if ($view['file'][$i]['view']) { + //echo $view['file'][$i]['view']; + echo get_view_thumbnail($view['file'][$i]['view']); + } + } + + echo "
    \n"; + } + ?> + +
    + + +

    + + +
    + 스크랩 + + + 추천 + 이 글을 추천하셨습니다 + + + + + 비추천 + + + +
    + +
    + 추천 + 비추천 +
    + + + + + + +
    + + +
    + + + + + + + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/board/basic/view_comment.skin.php b/theme/basic/mobile/skin/board/basic/view_comment.skin.php new file mode 100644 index 000000000..c6984f652 --- /dev/null +++ b/theme/basic/mobile/skin/board/basic/view_comment.skin.php @@ -0,0 +1,321 @@ + + + + + +
    +

    댓글목록

    + \]/i", "", $str); + ?> +
    style="margin-left:px;border-top-color:#e0e0e0"> +
    +

    님의 댓글

    + + 댓글의 댓글 + + 아이피 + + + 작성일 + + +
    + + +

    + "; ?> + +

    + + + + + "> + + + + + +
    + +

    등록된 댓글이 없습니다.

    + +
    + + + + + + diff --git a/theme/basic/mobile/skin/board/basic/write.skin.php b/theme/basic/mobile/skin/board/basic/write.skin.php new file mode 100644 index 000000000..b28d9abb7 --- /dev/null +++ b/theme/basic/mobile/skin/board/basic/write.skin.php @@ -0,0 +1,252 @@ +', 0); +?> + +
    +

    + +
    + + + + + + + + + + + '.PHP_EOL.''; + } + + if ($is_html) { + if ($is_dhtml_editor) { + $option_hidden .= ''; + } else { + $option .= PHP_EOL.''.PHP_EOL.''; + } + } + + if ($is_secret) { + if ($is_admin || $is_secret==1) { + $option .= PHP_EOL.''.PHP_EOL.''; + } else { + $option_hidden .= ''; + } + } + + if ($is_mail) { + $option .= PHP_EOL.''.PHP_EOL.''; + } + } + + echo $option_hidden; + ?> +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    class="frm_input " maxlength="20">
    옵션
    + +
    + + +

    이 게시판은 최소 글자 이상, 최대 글자 이하까지 글을 쓰실 수 있습니다.

    + + + + +
    글자
    + +
    " id="wr_link" class="frm_input wr_link">
    파일 # + + + + + + + +
    자동등록방지 + +
    +
    + +
    + + 취소 +
    +
    +
    + + diff --git a/theme/basic/mobile/skin/board/gallery/img/icon_file.gif b/theme/basic/mobile/skin/board/gallery/img/icon_file.gif new file mode 100644 index 0000000000000000000000000000000000000000..cca47f566ac0db655fb2ab0f56628b64958e48b2 GIT binary patch literal 107 zcmZ?wbhEHb-Wqsc#^P~2x#@rVooH@5wHB9i@BozKb;P9uI^*c|UyXO5@>VyLmgEat< Cr6(f* literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/gallery/img/icon_hot.gif b/theme/basic/mobile/skin/board/gallery/img/icon_hot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c95b839aeef0c1e26a4bab4ea50cd6d3f1969d7f GIT binary patch literal 97 zcmZ?wbhEHbzHen|7VvwFnzUPlarEA ZqW~YXyUO~T+#YkUoJ%V_>ib05Q5F AasU7T literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/gallery/img/icon_mobile.gif b/theme/basic/mobile/skin/board/gallery/img/icon_mobile.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad934d23c440c83db0c4589596465cb087353e01 GIT binary patch literal 62 zcmZ?wbhEHbZ% literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/gallery/img/icon_reply.gif b/theme/basic/mobile/skin/board/gallery/img/icon_reply.gif new file mode 100644 index 0000000000000000000000000000000000000000..91c135977b4f445a90c849310dc80efde1983830 GIT binary patch literal 77 zcmZ?wbhEHb&!1E4^4&ClEzh)PmWxV3{9A~!gB2-%RL5bHcgg3Zp^!+W)H2^A_AxQuL literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/gallery/img/icon_sound.gif b/theme/basic/mobile/skin/board/gallery/img/icon_sound.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5188318a5cdc394b984125c0ddd376c5f57bbe4 GIT binary patch literal 113 zcmZ?wbhEHbE1CJY$zMikVi`-#gIi|DbmsXBWf6U5szE@->A`0*`&<;b@XASRrB8=E6~=S>Pbm I%fes{0AXt-SpWb4 literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/board/gallery/list.skin.php b/theme/basic/mobile/skin/board/gallery/list.skin.php new file mode 100644 index 000000000..20f50eada --- /dev/null +++ b/theme/basic/mobile/skin/board/gallery/list.skin.php @@ -0,0 +1,251 @@ +', 0); +?> + + + +

    목록

    + + +
    + + + + + +
    +
    + Total + 페이지 +
    + + + + +
    + +
    + + + + + + + + + +

    이미지 목록

    + + +
    + + +
    + + +
      + +
    • + + + + + + 열람중"; + else + echo $list[$i]['num']; + ?> + + +
    • + + 게시물이 없습니다."; } ?> +
    + + +
    + + + +
    + + +
    +
    + + + + + + + + + + +
    + 게시물 검색 + +
    + + + + + + + +
    +
    + + + + + diff --git a/theme/basic/mobile/skin/board/gallery/style.css b/theme/basic/mobile/skin/board/gallery/style.css new file mode 100644 index 000000000..4f69e8f65 --- /dev/null +++ b/theme/basic/mobile/skin/board/gallery/style.css @@ -0,0 +1,225 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +/* 게시판 버튼 */ +/* 목록 버튼 */ +#bo_gall a.btn_b01 {} +#bo_gall a.btn_b01:focus, #bo_gall .btn_b01:hover {} +#bo_gall a.btn_b02 {} +#bo_gall a.btn_b02:focus, #bo_gall .btn_b02:hover {} +#bo_gall a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_gall a.btn_admin:focus, #bo_gall a.btn_admin:hover {} + +/* 읽기 버튼 */ +#bo_v a.btn_b01 {} +#bo_v a.btn_b01:focus, #bo_v .btn_b01:hover {} +#bo_v a.btn_b02 {} +#bo_v a.btn_b02:focus, #bo_v .btn_b02:hover {} +#bo_v a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_v a.btn_admin:focus, #bo_v a.btn_admin:hover {} + +/* 쓰기 버튼 */ +#bo_w .btn_confirm {} /* 서식단계 진행 */ +#bo_w .btn_submit {} +#bo_w .btn_cancel {} +#bo_w .btn_frmline {} /* 우편번호검색버튼 등 */ + +/* 기본테이블 */ +/* 읽기 내 테이블 */ +#bo_v .tbl_head01 {} +#bo_v .tbl_head01 caption {} +#bo_v .tbl_head01 thead th {} +#bo_v .tbl_head01 thead a {} +#bo_v .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_v .tbl_head01 tfoot th {} +#bo_v .tbl_head01 tfoot td {} +#bo_v .tbl_head01 tbody th {} +#bo_v .tbl_head01 td {} +#bo_v .tbl_head01 a {} +#bo_v td.empty_table {} + +/* 쓰기 테이블 */ +#bo_w table {} +#bo_w caption {} +#bo_w .frm_address {} +#bo_w .frm_file {} +#bo_w .frm_info {} + +#bo_w .tbl_frm01 {} +#bo_w .tbl_frm01 caption {} +#bo_w .tbl_frm01 th {} +#bo_w .tbl_frm01 td {} +#bo_w .tbl_frm01 textarea, #bo_w .frm_input {} +#bo_w .tbl_frm01 textarea {} +/* +#bo_w .tbl_frm01 #captcha {} +#bo_w .tbl_frm01 #captcha input {} +*/ +#bo_w .tbl_frm01 a {} + +#bo_w .required, #bo_w textarea.required {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 갤러리 목록 */ +#bo_gall h2 {margin:0;padding:0;width:0;height:0;font-size:0;line-height:0;overflow:hidden} + +#bo_gall #gall_allchk {margin:0 10px} + +#bo_gall #gall_ul {margin:10px 0 0;padding:0 10px;list-style:none} +#bo_gall #gall_ul:after {display:block;visibility:hidden;clear:both;content:""} + +#bo_cate h2 {width:0;height:0;font-size:0;line-height:0;overflow:hidden} +#bo_cate ul {margin:10px;padding-left:1px;zoom:1} +#bo_cate ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_cate li {float:left;margin-bottom:-1px;width:25%} +#bo_cate a {display:block;position:relative;margin-left:-1px;padding:5px 0;border:1px solid #ddd;background:#f7f7f7;color:#888;text-align:center;text-decoration:none;letter-spacing:-0.1em} +#bo_cate a:focus, #bo_cate a:hover, #bo_cate a:active {text-decoration:none} +#bo_cate #bo_cate_on {z-index:2;border:1px solid #565e60;background:#fff;color:#565e60;font-weight:bold} + +#bo_gall .gall_li {float:left;padding:0 10px 20px 0} +#bo_gall .gall_clear {clear:both} + +#bo_gall .gall_con {margin:0;padding:0;list-style:none} +#bo_gall .gall_con li {margin:0 0 5px} +#bo_gall .gall_con .gall_subject {display:inline-block;width:50px} + +#bo_gall .gall_now .gall_text_href a {color:#ff3061} + +#bo_gall .gall_href a:link, #bo_gall .gall_href a:focus, #bo_gall .gall_href a:hover {text-decoration:none} +#bo_gall .gall_href strong, #bo_gall .gall_href span {display:block;width:174px;height:124px;background:#f7f7f7;text-align:center;line-height:8em} + +#bo_gall .gall_text_href {margin:10px 0 !important} +#bo_gall .gall_text_href a {color:#000;font-weight:bold;text-decoration:none} +#bo_gall .gall_text_href img {margin:0 0 0 5px} + +/* 게시판 목록 공통 */ +.bo_fx {margin-bottom:5px;padding:5px 10px} +.bo_fx:after {display:block;visibility:hidden;clear:both;content:""} +.bo_fx ul {margin:0;padding:0;list-style:none} +#bo_list_total {float:left;padding:0;height:2.5em;line-height:2.5em} +.btn_bo_user {float:right;margin:0;padding:0;list-style:none} +.btn_bo_user li {float:left;margin-left:5px} +.btn_bo_adm {float:left} +.btn_bo_adm li {float:left;margin-right:5px} +.btn_bo_adm input {padding:8px;border:0;background:#e8180c;color:#fff;text-decoration:none;vertical-align:middle} +.bo_notice td {background:#f7f7f7} +.bo_notice td a {font-weight:bold} +.td_num strong {color:#000} +.bo_cate_link {display:inline-block;margin:0 3px 0 0;padding:0 6px 0 0;border-right:1px solid #e7f1ed;color:#999 !important;font-weight:bold;text-decoration:none} /* 글제목줄 분류스타일 */ +.bo_current {color:#e8180c} +.td_subject img {margin-left:3px} +.cnt_cmt {font-weight:bold} + +#bo_sch {margin-bottom:10px;padding-top:5px;text-align:center} + +#bo_gall li.empty_list {padding:30px 0;text-align:center} + +/* 게시판 쓰기 */ +#char_count_desc {display:block;margin:0 0 5px;padding:0} +#char_count_wrap {margin:5px 0 0;text-align:right} +#char_count {font-weight:bold} + +#wr_email, #wr_homepage, #wr_subject, .wr_link {width:100%} + +/* 게시판 읽기 */ +#bo_v {margin-bottom:15px;padding-bottom:15px} + +#bo_v_table {padding:0 10px;color:#999;font-size:0.9em;font-weight:bold} + +#bo_v_title {padding:0 10px 5px;font-size:1.2em} + +#bo_v_info {padding:0 10px 10px;border-bottom:1px solid #ddd} +#bo_v_info h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_info {} +#bo_v_info strong {display:inline-block;margin:0 0 0 5px;font-weight:normal} + +#bo_v_file {} +#bo_v_file h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_file ul {margin:0;padding:0;list-style:none} +#bo_v_file li {padding:0 10px;border-bottom:1px solid #eee;background:#f7f7f7} +#bo_v_file a {display:inline-block;padding:5px 0;color:#000} +#bo_v_file a:focus, +#bo_v_file a:hover, +#bo_v_file a:active {text-decoration:none} +.bo_v_file_cnt {display:inline-block;margin:0 10px} + +#bo_v_link {} +#bo_v_link h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_link ul {margin:0;padding:0;list-style:none} +#bo_v_link li {padding:0 10px;border-bottom:1px solid #eee;background:#f7f7f7} +#bo_v_link a {display:inline-block;padding:5px 0;color:#000} +#bo_v_link a:focus, +#bo_v_link a:hover, +#bo_v_link a:active {text-decoration:none} +.bo_v_link_cnt {display:inline-block;margin:0 10px} + +#bo_v_top {margin:0 0 10px;padding:10px} +#bo_v_top:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_top h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_top ul {margin:0;padding:0;list-style:none} + +#bo_v_bot {padding:0 10px} +#bo_v_bot:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_bot h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_bot ul {margin:0;padding:0;list-style:none} + +.bo_v_nb {float:left} +.bo_v_nb li {float:left;margin-right:5px} +.bo_v_com {float:right} +.bo_v_com li {float:left;margin-left:5px} + +#bo_v_atc {padding:0 10px;min-height:200px} +#bo_v_atc_title {margin:0;padding:0;height:0;overflow:hidden} + +#bo_v_img {margin:0 0 10px;width:100%;overflow:hidden;zoom:1} +#bo_v_img:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_img img {margin-bottom:15px;max-width:100%;height:auto} + +#bo_v_con {margin-bottom:20px;width:100%;line-height:1.7em;word-break:break-all;overflow:hidden} +#bo_v_con a {color:#000;text-decoration:underline} +#bo_v_con img {max-width:100%;height:auto} + +#bo_v_act {position:relative;margin-bottom:20px;text-align:center} +#bo_v_act a {margin-right:5px;vertical-align:middle} +#bo_v_act strong {color:#ff3061} +#bo_v_act_good, #bo_v_act_nogood {display:none;position:absolute;top:30px;right:10%;padding:10px 0;width:165px;background:#ff3061;color:#fff;text-align:center} + +#bo_v_sns {margin:0 0 20px;padding:0;list-style:none;zoom:1} +#bo_v_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_sns li {float:left;margin:0 5px 0 0} + +/* 게시판 댓글 */ +#bo_vc {margin:0 0 20px;padding:20px 10px 10px;border:1px solid #e5e8ec;background:#f5f8f9} +#bo_vc h2 {margin-bottom:5px} +#bo_vc article {padding:0 0 5px;border-top:1px dotted #ccc} +#bo_vc header {position:relative;padding:13px 0 5px} +#bo_vc header .icon_reply {position:absolute;top:13px;left:-20px} +#bo_vc .sv_member, #bo_vc .sv_guest {font-weight:bold} +.bo_vc_hdinfo {display:inline-block;margin:0 10px 0 5px} +#bo_vc h1 {width:0;height:0;font-size:0;line-height:0;overflow:hidden} +#bo_vc a {color:#000;text-decoration:none} +#bo_vc p {padding:0 0 5px;line-height:1.8em} +#bo_vc p a {text-decoration:underline} +#bo_vc p a.s_cmt {text-decoration:none} +#bo_vc_empty {margin:0;padding:15px !important;text-align:center} +#bo_vc #bo_vc_winfo {float:left} +#bo_vc footer {zoom:1} +#bo_vc footer:after {display:block;visibility:hidden;clear:both;content:""} + +.bo_vc_act {float:right;margin:0;list-style:none} +.bo_vc_act:after {display:block;visibility:hidden;clear:both;content:""} +.bo_vc_act li {float:left;margin-left:5px} + +#bo_vc_w {position:relative;margin-bottom:10px;padding:0 10px 15px;border-bottom:1px solid #dde4e9} +#bo_vc_w h2 {padding:10px 0 5px} +#bo_vc_w .tbl_wrap {margin:0 0 15px} +#bo_vc_w #char_cnt {display:block;margin-bottom:5px} +#bo_vc_w textarea {width:99%} + +#bo_vc_sns {margin:0;padding:0;list-style:none;zoom:1} +#bo_vc_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_vc_sns li {float:left;margin:0 10px 0 0} +#bo_vc_sns input {margin:0 0 0 5px} \ No newline at end of file diff --git a/theme/basic/mobile/skin/board/gallery/view.skin.php b/theme/basic/mobile/skin/board/gallery/view.skin.php new file mode 100644 index 000000000..9b151b50c --- /dev/null +++ b/theme/basic/mobile/skin/board/gallery/view.skin.php @@ -0,0 +1,270 @@ +', 0); +?> + + + +
    + +
    +
    +

    + +

    +
    + +
    +

    페이지 정보

    + 작성자 + 작성일 + 조회 + 댓글 +
    + + + + +
    +

    첨부파일

    + +
    + + + + + + +
    + + + + + + + +
    + +
    +

    본문

    + + \n"; + + for ($i=0; $i<=count($view['file']); $i++) { + if ($view['file'][$i]['view']) { + //echo $view['file'][$i]['view']; + echo get_view_thumbnail($view['file'][$i]['view']); + } + } + + echo "
    \n"; + } + ?> + +
    + + +

    + + +
    + 스크랩 + + + 추천 + + + + + + 비추천 + + + +
    + +
    + 추천 + 비추천 +
    + + + + + + +
    + + +
    + + + + + + + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/board/gallery/view_comment.skin.php b/theme/basic/mobile/skin/board/gallery/view_comment.skin.php new file mode 100644 index 000000000..c6984f652 --- /dev/null +++ b/theme/basic/mobile/skin/board/gallery/view_comment.skin.php @@ -0,0 +1,321 @@ + + + + + +
    +

    댓글목록

    + \]/i", "", $str); + ?> +
    style="margin-left:px;border-top-color:#e0e0e0"> +
    +

    님의 댓글

    + + 댓글의 댓글 + + 아이피 + + + 작성일 + + +
    + + +

    + "; ?> + +

    + + + + + "> + + + + + +
    + +

    등록된 댓글이 없습니다.

    + +
    + + + + + + diff --git a/theme/basic/mobile/skin/board/gallery/write.skin.php b/theme/basic/mobile/skin/board/gallery/write.skin.php new file mode 100644 index 000000000..f40d8db61 --- /dev/null +++ b/theme/basic/mobile/skin/board/gallery/write.skin.php @@ -0,0 +1,251 @@ +', 0); +?> + +
    +

    + +
    + + + + + + + + + + + '.PHP_EOL.''; + } + + if ($is_html) { + if ($is_dhtml_editor) { + $option_hidden .= ''; + } else { + $option .= PHP_EOL.''.PHP_EOL.''; + } + } + + if ($is_secret) { + if ($is_admin || $is_secret==1) { + $option .= PHP_EOL.''.PHP_EOL.''; + } else { + $option_hidden .= ''; + } + } + + if ($is_mail) { + $option .= PHP_EOL.''.PHP_EOL.''; + } + } + + echo $option_hidden; + ?> +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    class="frm_input " size="15" maxlength="20">
    옵션
    + +
    + + +

    이 게시판은 최소 글자 이상, 최대 글자 이하까지 글을 쓰실 수 있습니다.

    + + + + +
    글자
    + +
    " id="wr_link" class="frm_input wr_link">
    파일 # + + + + + + + +
    자동등록방지 + +
    +
    + +
    + + 취소 +
    +
    +
    + + diff --git a/theme/basic/mobile/skin/connect/basic/connect.skin.php b/theme/basic/mobile/skin/connect/basic/connect.skin.php new file mode 100644 index 000000000..96d2da394 --- /dev/null +++ b/theme/basic/mobile/skin/connect/basic/connect.skin.php @@ -0,0 +1,8 @@ +', 0); +?> + diff --git a/theme/basic/mobile/skin/connect/basic/current_connect.skin.php b/theme/basic/mobile/skin/connect/basic/current_connect.skin.php new file mode 100644 index 000000000..5d47774b7 --- /dev/null +++ b/theme/basic/mobile/skin/connect/basic/current_connect.skin.php @@ -0,0 +1,38 @@ +', 0); +?> + +
    + + + + + + + + + + ".$location.""; + else $display_location = $location; + ?> + + + + + + "; + ?> + +
    번호이름위치
    현재 접속자가 없습니다.
    +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/connect/basic/style.css b/theme/basic/mobile/skin/connect/basic/style.css new file mode 100644 index 000000000..09c88df61 --- /dev/null +++ b/theme/basic/mobile/skin/connect/basic/style.css @@ -0,0 +1,9 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 현재접속자 */ +#current_connect_tbl {} +#current_connect_tbl th:nth-of-type(1) {width:50px} +#current_connect_tbl th:nth-of-type(2) {width:120px} + +#current_connect_tbl td:nth-of-type(1) {padding:10px 0;text-align:center} \ No newline at end of file diff --git a/theme/basic/mobile/skin/content/basic/content.skin.php b/theme/basic/mobile/skin/content/basic/content.skin.php new file mode 100644 index 000000000..79d47d932 --- /dev/null +++ b/theme/basic/mobile/skin/content/basic/content.skin.php @@ -0,0 +1,18 @@ +', 0); + +?> + +
    +
    +

    +
    + +
    + +
    + +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/content/basic/style.css b/theme/basic/mobile/skin/content/basic/style.css new file mode 100644 index 000000000..638229597 --- /dev/null +++ b/theme/basic/mobile/skin/content/basic/style.css @@ -0,0 +1,8 @@ +@charset "utf-8"; + +/* 내용관리 */ +#ctt {margin:10px 0;padding:10px;border-top:1px solid #e9e9e9;border-bottom:1px solid #e9e9e9} +.ctt_admin {margin:0 5px;text-align:right} +#ctt header h1 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#ctt_con {padding:10px 0} +.ctt_img {text-align:center} \ No newline at end of file diff --git a/theme/basic/mobile/skin/faq/basic/list.skin.php b/theme/basic/mobile/skin/faq/basic/list.skin.php new file mode 100644 index 000000000..f625ff36a --- /dev/null +++ b/theme/basic/mobile/skin/faq/basic/list.skin.php @@ -0,0 +1,120 @@ +', 0); +?> + + +'.conv_content($fm['fm_mobile_head_html'], 1).'
    '; +?> + + + + + +
    + +
    +

    목록

    +
      + $v){ + if(empty($v)) + continue; + ?> +
    1. +

      +
      + +
      +
      +
    2. + +
    +
    + 검색된 게시물이 없습니다.

    '; + } else { + echo '
    등록된 FAQ가 없습니다.'; + if($is_admin) + echo '
    FAQ를 새로 등록하시려면 FAQ관리 메뉴를 이용하십시오.'; + echo '
    '; + } + } + ?> +
    + + + +'.conv_content($fm['fm_tail_html'], 1).''; +?> + +
    +
    + + + + +
    +
    + + + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/faq/basic/style.css b/theme/basic/mobile/skin/faq/basic/style.css new file mode 100644 index 000000000..d573cdfb7 --- /dev/null +++ b/theme/basic/mobile/skin/faq/basic/style.css @@ -0,0 +1,25 @@ +@charset "utf-8"; + +#bo_cate {margin:0 10px} +#bo_cate h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_cate ul {margin-bottom:10px;padding-left:1px;zoom:1} +#bo_cate ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_cate li {float:left;margin-bottom:-1px} +#bo_cate a {display:block;position:relative;margin-left:-1px;padding:6px 0 5px;width:90px;border:1px solid #ddd;background:#f7f7f7;color:#888;text-align:center;letter-spacing:-0.1em;line-height:1.2em;cursor:pointer} +#bo_cate a:focus, #bo_cate a:hover, #bo_cate a:active {text-decoration:none} +#bo_cate #bo_cate_on {z-index:2;border:1px solid #565e60;background:#fff;color:#565e60;font-weight:bold} + +#faq_wrap {margin:10px} +#faq_wrap h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +.faq_admin {margin:0 5px;text-align:right} +#faq_wrap p {line-height:1.8em} +#faq_wrap ol {margin:0;padding:0;list-style:none} +#faq_con {border:1px solid #e9e9e9;border-top:0} +#faq_con h3 a {display:block;padding:10px;background:#f2f5f9;border-top:1px solid #e9e9e9} +#faq_con .con_inner {display:none;padding:10px;line-height:1.8em} +#faq_con .con_closer {margin:10px 0 0;text-align:right} +#faq_con .closer_btn {margin:0;padding:10px;border:0;background:#666;color:#fff} +.faq_tolist {padding:0 10px;text-align:right} +.faq_img {text-align:center} + +#faq_sch {text-align:center} \ No newline at end of file diff --git a/theme/basic/mobile/skin/latest/basic/img/icon_file.gif b/theme/basic/mobile/skin/latest/basic/img/icon_file.gif new file mode 100644 index 0000000000000000000000000000000000000000..cca47f566ac0db655fb2ab0f56628b64958e48b2 GIT binary patch literal 107 zcmZ?wbhEHb-Wqsc#^P~2x#@rVooH@5wHB9i@BozKb;P9uI^*c|UyXO5@>VyLmgEat< Cr6(f* literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/latest/basic/img/icon_hot.gif b/theme/basic/mobile/skin/latest/basic/img/icon_hot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c95b839aeef0c1e26a4bab4ea50cd6d3f1969d7f GIT binary patch literal 97 zcmZ?wbhEHbzHen|7VvwFnzUPlarEA ZqW~YXyUO~T+#YkUoJ%V_>ib05Q5F AasU7T literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/latest/basic/img/icon_mobile.gif b/theme/basic/mobile/skin/latest/basic/img/icon_mobile.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad934d23c440c83db0c4589596465cb087353e01 GIT binary patch literal 62 zcmZ?wbhEHbI6zOJt}3$`6RT1g06226*Z@+ongb7@ XU=fBkjtXNz0xpR_!)cQgkRbp&KI&WI literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/latest/basic/img/icon_movie.gif b/theme/basic/mobile/skin/latest/basic/img/icon_movie.gif new file mode 100644 index 0000000000000000000000000000000000000000..cb958f83f9c606f290a260714cd9a3cff043f3a2 GIT binary patch literal 110 zcmZ?wbhEHbZ% literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/latest/basic/img/icon_reply.gif b/theme/basic/mobile/skin/latest/basic/img/icon_reply.gif new file mode 100644 index 0000000000000000000000000000000000000000..91c135977b4f445a90c849310dc80efde1983830 GIT binary patch literal 77 zcmZ?wbhEHb&!1E4^4&ClEzh)PmWxV3{9A~!gB2-%RL5bHcgg3Zp^!+W)H2^A_AxQuL literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/latest/basic/img/icon_sound.gif b/theme/basic/mobile/skin/latest/basic/img/icon_sound.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5188318a5cdc394b984125c0ddd376c5f57bbe4 GIT binary patch literal 113 zcmZ?wbhEHbE1CJY$zMikVi`-#gIi|DbmsXBWf6U5szE@->A`0*`&<;b@XASRrB8=E6~=S>Pbm I%fes{0AXt-SpWb4 literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/latest/basic/latest.skin.php b/theme/basic/mobile/skin/latest/basic/latest.skin.php new file mode 100644 index 000000000..6a2e4e9c2 --- /dev/null +++ b/theme/basic/mobile/skin/latest/basic/latest.skin.php @@ -0,0 +1,43 @@ +', 0); +?> + +
    + +
      + +
    • + "; + if ($list[$i]['is_notice']) + echo "".$list[$i]['subject'].""; + else + echo $list[$i]['subject']; + + if ($list[$i]['comment_cnt']) + echo " ".$list[$i]['comment_cnt'].""; + + // if ($list[$i]['link']['count']) { echo "[{$list[$i]['link']['count']}]"; } + // if ($list[$i]['file']['count']) { echo "<{$list[$i]['file']['count']}>"; } + + if (isset($list[$i]['icon_new'])) echo " " . $list[$i]['icon_new']; + if (isset($list[$i]['icon_hot'])) echo " " . $list[$i]['icon_hot']; + if (isset($list[$i]['icon_file'])) echo " " . $list[$i]['icon_file']; + if (isset($list[$i]['icon_link'])) echo " " . $list[$i]['icon_link']; + if (isset($list[$i]['icon_secret'])) echo " " . $list[$i]['icon_secret']; + + echo ""; + + ?> +
    • + + +
    • 게시물이 없습니다.
    • + +
    + +
    diff --git a/theme/basic/mobile/skin/latest/basic/style.css b/theme/basic/mobile/skin/latest/basic/style.css new file mode 100644 index 000000000..8434bf210 --- /dev/null +++ b/theme/basic/mobile/skin/latest/basic/style.css @@ -0,0 +1,10 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 최근게시물 스킨 (latest) */ +.lt {position:relative;margin:0 0 10px;padding:0 10px 15px;border-bottom:1px solid #ddd} +.lt ul {margin:0 0 10px;padding:0;list-style:none} +.lt a {display:block;padding:5px 0;color:#000;text-decoration:none} +.lt .lt_title {display:inline-block;padding:10px 0} +.lt .lt_more {position:absolute;top:5px;right:10px} +.lt .cnt_cmt {display:inline-block;margin:0 0 0 3px;font-weight:bold} \ No newline at end of file diff --git a/theme/basic/mobile/skin/member/basic/formmail.skin.php b/theme/basic/mobile/skin/member/basic/formmail.skin.php new file mode 100644 index 000000000..3add8546b --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/formmail.skin.php @@ -0,0 +1,96 @@ +', 0); +?> + +
    +

    님께 메일보내기

    + +
    + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    메일쓰기
    형식 + + + +
    자동등록방지
    +
    + +
    + + +
    + +
    +
    + + diff --git a/theme/basic/mobile/skin/member/basic/img/zip_ico_up.gif b/theme/basic/mobile/skin/member/basic/img/zip_ico_up.gif new file mode 100644 index 0000000000000000000000000000000000000000..a1eff70fa850bea122f6924d8c3cd63f1d573c53 GIT binary patch literal 54 zcmZ?wbhEHb', 0); +?> + +
    +

    + +
    + + +
    + + + + + +
    + + +
    +
    + +
    +

    회원로그인 안내

    +

    + 회원아이디 및 비밀번호가 기억 안나실 때는 아이디/비밀번호 찾기를 이용하십시오.
    + 아직 회원이 아니시라면 회원으로 가입 후 이용해 주십시오. +

    + +
    + + + +
    + +
    + + diff --git a/theme/basic/mobile/skin/member/basic/login_check.skin.php b/theme/basic/mobile/skin/member/basic/login_check.skin.php new file mode 100644 index 000000000..1b182915e --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/login_check.skin.php @@ -0,0 +1,5 @@ + diff --git a/theme/basic/mobile/skin/member/basic/member_confirm.skin.php b/theme/basic/mobile/skin/member/basic/member_confirm.skin.php new file mode 100644 index 000000000..76978b193 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/member_confirm.skin.php @@ -0,0 +1,46 @@ +', 0); +?> + +
    +

    + +

    + 비밀번호를 한번 더 입력해주세요. + + 비밀번호를 입력하시면 회원탈퇴가 완료됩니다. + + 회원님의 정보를 안전하게 보호하기 위해 비밀번호를 한번 더 확인합니다. + +

    + +
    + + + +
    + 회원아이디 + + + +
    + +
    + + + +
    + + diff --git a/theme/basic/mobile/skin/member/basic/memo.skin.php b/theme/basic/mobile/skin/member/basic/memo.skin.php new file mode 100644 index 000000000..2d2174b1c --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/memo.skin.php @@ -0,0 +1,40 @@ +', 0); +?> + +
    +

    + + + +
    + 전체 쪽지
    +
    + + + +

    + 쪽지 보관일수는 최장 일 입니다. +

    + +
    + +
    +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/member/basic/memo_form.skin.php b/theme/basic/mobile/skin/member/basic/memo_form.skin.php new file mode 100644 index 000000000..47d0355f0 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/memo_form.skin.php @@ -0,0 +1,57 @@ +', 0); +?> + +
    +

    쪽지보내기

    + + + +
    +
    + + + + + + + + + + + + + + + + +
    쪽지쓰기
    + + 여러 회원에게 보낼때는 컴마(,)로 구분하세요. +
    자동등록방지 + +
    +
    + +
    + + +
    +
    +
    + + diff --git a/theme/basic/mobile/skin/member/basic/memo_view.skin.php b/theme/basic/mobile/skin/member/basic/memo_view.skin.php new file mode 100644 index 000000000..ae87bfacf --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/memo_view.skin.php @@ -0,0 +1,56 @@ +', 0); +?> + +
    +

    + + + +
    +
    +

    쪽지 내용

    +
    +
      +
    • + 사람 + +
    • +
    • + 시간 + +
    • +
    +

    + +

    +
    + +
    + + 이전쪽지 + + + 다음쪽지 + + 답장 + 목록보기 + +
    +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/member/basic/password.skin.php b/theme/basic/mobile/skin/member/basic/password.skin.php new file mode 100644 index 000000000..7a73f21e9 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/password.skin.php @@ -0,0 +1,47 @@ +', 0); +?> + +
    +

    +

    + + 작성자만 글을 수정할 수 있습니다. + 작성자 본인이라면, 글 작성시 입력한 비밀번호를 입력하여 글을 수정할 수 있습니다. + + 작성자만 글을 삭제할 수 있습니다. + 작성자 본인이라면, 글 작성시 입력한 비밀번호를 입력하여 글을 삭제할 수 있습니다. + + 비밀글 기능으로 보호된 글입니다. + 작성자와 관리자만 열람하실 수 있습니다. 본인이라면 비밀번호를 입력하세요. + +

    + +
    + + + + + + + + +
    + + +
    +
    + + + +
    diff --git a/theme/basic/mobile/skin/member/basic/password_lost.skin.php b/theme/basic/mobile/skin/member/basic/password_lost.skin.php new file mode 100644 index 000000000..a4e1d11ef --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/password_lost.skin.php @@ -0,0 +1,46 @@ +', 0); +?> + +
    +

    아이디/비밀번호 찾기

    + +
    +
    +

    + 회원가입 시 등록하신 이메일 주소를 입력해 주세요.
    + 해당 이메일로 아이디와 비밀번호 정보를 보내드립니다. +

    + +
    + + + +
    + + +
    +
    +
    + + diff --git a/theme/basic/mobile/skin/member/basic/point.skin.php b/theme/basic/mobile/skin/member/basic/point.skin.php new file mode 100644 index 000000000..bc0ff54b7 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/point.skin.php @@ -0,0 +1,81 @@ +', 0); +?> + +
    +

    + +
      + 0) { + $point1 = '+' .number_format($row['po_point']); + $sum_point1 += $row['po_point']; + } else { + $point2 = number_format($row['po_point']); + $sum_point2 += $row['po_point']; + } + + $po_content = $row['po_content']; + + $expr = ''; +// if($row['po_expired'] == 1) + $expr = ' txt_expired'; + ?> +
    • +
      + + +
      +
      + + + 만료 + + + +
      +
    • + 자료가 없습니다.'; + else { + if ($sum_point1 > 0) + $sum_point1 = "+" . number_format($sum_point1); + $sum_point2 = number_format($sum_point2); + } + ?> +
    + +
    +
    + 지급 + +
    +
    + 사용 + +
    +
    + 보유 + +
    +
    + + + +
    +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/member/basic/profile.skin.php b/theme/basic/mobile/skin/member/basic/profile.skin.php new file mode 100644 index 000000000..0cc8d8d02 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/profile.skin.php @@ -0,0 +1,48 @@ +', 0); +?> + +
    +

    님의 프로필

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    회원권한
    포인트
    홈페이지
    회원가입일= $mb['mb_level']) ? substr($mb['mb_datetime'],0,10) ." (".number_format($mb_reg_after)." 일)" : "알 수 없음"; ?>
    최종접속일= $mb['mb_level']) ? $mb['mb_today_login'] : "알 수 없음"; ?>
    +
    + +
    +

    인사말

    +

    +
    + +
    + +
    +
    diff --git a/theme/basic/mobile/skin/member/basic/register.skin.php b/theme/basic/mobile/skin/member/basic/register.skin.php new file mode 100644 index 000000000..76069e2df --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/register.skin.php @@ -0,0 +1,57 @@ +', 0); +?> + +
    + +
    + +

    회원가입약관 및 개인정보처리방침안내의 내용에 동의하셔야 회원가입 하실 수 있습니다.

    + +
    +

    회원가입약관

    + +
    + + +
    +
    + +
    +

    개인정보처리방침안내

    + +
    + + +
    +
    + +
    + +
    + +
    + + + +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/member/basic/register_form.skin.php b/theme/basic/mobile/skin/member/basic/register_form.skin.php new file mode 100644 index 000000000..9b783960b --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/register_form.skin.php @@ -0,0 +1,441 @@ +', 0); +?> + +
    + + + + + +
    + + + + + + + + date("Y-m-d", G5_SERVER_TIME - ($config['cf_nick_modify'] * 86400))) { // 닉네임수정일이 지나지 않았다면 ?> + + + + +
    + + + + + + + + + + + + + + +
    사이트 이용정보 입력
    + 영문자, 숫자, _ 만 입력 가능. 최소 3자이상 입력하세요. + > + +
    >
    >
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    개인정보 입력
    + + 아이핀 본인확인 후에는 이름이 자동 입력되고 휴대폰 본인확인 후에는 이름과 휴대폰번호가 자동 입력되어 수동으로 입력할수 없게 됩니다. + + class="frm_input "> + 아이핀 본인확인'.PHP_EOL; + if($config['cf_cert_hp'] && $config['cf_cert_hp'] != 'lg') + echo ''.PHP_EOL; + + echo ''.PHP_EOL; + } + ?> + +
    + 본인확인성인인증 완료 +
    + +
    + + 공백없이 한글,영문,숫자만 입력 가능 (한글2자, 영문4자 이상)
    + 닉네임을 바꾸시면 앞으로 일 이내에는 변경 할 수 없습니다. +
    + + + +
    + + + + + + + + +
    " maxlength="255" >
    " maxlength="20" >
    + class="frm_input " maxlength="20"> + + + +
    + 주소 + 필수 + + + class="frm_input " size="5" maxlength="6"> +
    + + class="frm_input frm_address " size="50">
    + + +
    + + + +
    +
    + +
    + + + + + + + + + + + + + + + + + = $config['cf_icon_level']) { ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    기타 개인설정
    + + 이미지 크기는 가로 픽셀, 세로 픽셀 이하로 해주세요.
    + gif만 가능하며 용량 바이트 이하만 등록됩니다. +
    + + + 회원아이콘 + + + +
    + > + 정보 메일을 받겠습니다. +
    + > + 휴대폰 문자메세지를 받겠습니다. +
    + + 정보공개를 바꾸시면 앞으로 일 이내에는 변경이 안됩니다. + + + > + 다른분들이 나의 정보를 볼 수 있도록 합니다. +
    정보공개 + + 정보공개는 수정후 일 이내, 까지는 변경이 안됩니다.
    + 이렇게 하는 이유는 잦은 정보공개 수정으로 인하여 쪽지를 보낸 후 받지 않는 경우를 막기 위해서 입니다. +
    + +
    자동등록방지
    +
    + +
    + + 취소 +
    +
    + + +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/member/basic/register_result.skin.php b/theme/basic/mobile/skin/member/basic/register_result.skin.php new file mode 100644 index 000000000..44ebe9dd4 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/register_result.skin.php @@ -0,0 +1,44 @@ +', 0); +?> + +
    + +

    + 님의 회원가입을 진심으로 축하합니다.
    +

    + + +

    + 회원 가입 시 입력하신 이메일 주소로 인증메일이 발송되었습니다.
    + 발송된 인증메일을 확인하신 후 인증처리를 하시면 사이트를 원활하게 이용하실 수 있습니다. +

    +
    + 아이디 +
    + 이메일 주소 + +
    +

    + 이메일 주소를 잘못 입력하셨다면, 사이트 관리자에게 문의해주시기 바랍니다. +

    + + +

    + 회원님의 비밀번호는 아무도 알 수 없는 암호화 코드로 저장되므로 안심하셔도 좋습니다.
    + 아이디, 비밀번호 분실시에는 회원가입시 입력하신 이메일 주소를 이용하여 찾을 수 있습니다. +

    + +

    + 회원 탈퇴는 언제든지 가능하며 일정기간이 지난 후, 회원님의 정보는 삭제하고 있습니다.
    + 감사합니다. +

    + + + +
    diff --git a/theme/basic/mobile/skin/member/basic/scrap.skin.php b/theme/basic/mobile/skin/member/basic/scrap.skin.php new file mode 100644 index 000000000..ccb43bac5 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/scrap.skin.php @@ -0,0 +1,27 @@ +', 0); +?> + +
    +

    + +
      + +
    • + + + 삭제 +
    • + + 자료가 없습니다."; ?> +
    + + + +
    + +
    +
    diff --git a/theme/basic/mobile/skin/member/basic/scrap_popin.skin.php b/theme/basic/mobile/skin/member/basic/scrap_popin.skin.php new file mode 100644 index 000000000..04dfd5fd3 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/scrap_popin.skin.php @@ -0,0 +1,39 @@ +', 0); +?> + +
    +

    스크랩하기

    + +
    + + + +
    + + + + + + + + + + + + +
    제목 확인 및 댓글 쓰기
    제목
    +
    + +

    + 스크랩을 하시면서 감사 혹은 격려의 댓글을 남기실 수 있습니다. +

    + +
    + +
    +
    +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/member/basic/style.css b/theme/basic/mobile/skin/member/basic/style.css new file mode 100644 index 000000000..ae88a4653 --- /dev/null +++ b/theme/basic/mobile/skin/member/basic/style.css @@ -0,0 +1,190 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +/* 버튼 */ +.mbskin a.btn01 {} +.mbskin a.btn01:focus, .mbskin a.btn01:hover {} +.mbskin a.btn02 {} +.mbskin a.btn02:focus, .mbskin .btn02:hover {} +.mbskin .btn_confirm {} /* 서식단계 진행 */ +.mbskin .btn_submit {} +.mbskin .btn_cancel {} +.mbskin .btn_frmline {} /* 우편번호검색버튼 등 */ +.mbskin .win_btn {} /* 새창용 */ +.mbskin .win_btn a {} +.mbskin .win_btn button {} +.mbskin .win_btn input {} +/* 게시판용 버튼 */ +.mbskin a.btn_b01 {} +.mbskin a.btn_b01:focus, .mbskin .btn_b01:hover {} +.mbskin a.btn_b02 {} +.mbskin a.btn_b02:focus, .mbskin .btn_b02:hover {} +.mbskin a.btn_admin {} /* 관리자 전용 버튼 */ +.mbskin a.btn_admin:focus, .mbskin a.btn_admin:hover {} + +/* 기본테이블 */ +.mbskin .tbl_head01 {} +.mbskin .tbl_head01 caption {} +.mbskin .tbl_head01 thead th {} +.mbskin .tbl_head01 thead a {} +.mbskin .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +.mbskin .tbl_head01 tfoot th {} +.mbskin .tbl_head01 tfoot td {} +.mbskin .tbl_head01 tbody th {} +.mbskin .tbl_head01 td {} +.mbskin .tbl_head01 a {} +.mbskin td.empty_table {} + +/* 폼 테이블 */ +.mb_skin table {} +.mb_skin caption {} +.mb_skin .frm_info {} +.mb_skin .frm_file {} + +.mbskin .tbl_frm01 {} +.mbskin .tbl_frm01 caption {} +.mbskin .tbl_frm01 th {} +.mbskin .tbl_frm01 td {} +.mbskin .tbl_frm01 textarea, .mbskin .frm_input {} +.mbskin .tbl_frm01 textarea {} +/* +.mbskin .tbl_frm01 #captcha {} +.mbskin .tbl_frm01 #captcha input {} +*/ +.mbskin .tbl_frm01 a {} + +.mbskin .required, .mbskin textarea.required {} /* 필수입력 */ + +/* 테이블 항목별 정의 */ +.mbskin .td_board {} +.mbskin .td_chk {} +.mbskin .td_date {} +.mbskin .td_datetime {} +.mbskin .td_group {} +.mbskin .td_mb_id {} +.mbskin .td_mng {} +.mbskin .td_name {} +.mbskin .td_nick {} +.mbskin .td_num {} +.mbskin .td_numbig {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 회원가입 약관 */ +#fregister section {padding:15px;border-bottom:1px solid #eee;background:#fafafa} +#fregister h2 {margin:0 0 15px;text-align:center} +#fregister textarea {display:block;margin-bottom:10px;padding:5px;width:99%;height:150px;border:1px solid #cfded8;background:#f7f7f7} +.fregister_agree {padding:10px 0 0;text-align:right} +.fregister_agree label {display:inline-block;margin-right:5px} +#fregister p {color:#e8180c;text-align:center} +#fregister .btn_confirm {margin:15px 0} + +/* 회원가입 입력 */ +#fregisterform #reg_mb_email, #fregisterform .frm_address {width:100%} + +#fregisterform textarea {width:100%;height:50px} + +#fregisterform #msg_certify {margin:5px 0 0;padding:5px;border:1px solid #dbecff;background:#eaf4ff;text-align:center} + +#fregisterform .frm_address {margin:5px 0 0} +#fregisterform #mb_addr3 {display:block;margin:5px 0 0} +#fregisterform #mb_addr_jibeon {display:block;margin:5px 0 0} + +/* 회원가입 완료 */ +#reg_result {padding:40px 10px 0} +#reg_result #result_email {margin:20px 0;padding:10px 50px;border-top:1px solid #eee;border-bottom:1px solid #eee;background:#fff;line-height:2em} +#reg_result #result_email span {display:inline-block;width:150px} +#reg_result #result_email strong {color:#e8180c;font-size:1.2em} +#reg_result p {line-height:1.8em} +#reg_result .btn_confirm {margin:50px 0} + +/* 아이디/비밀번호 찾기 */ +#find_info #info_fs {margin:0 20px 10px} +#find_info #info_fs p {margin:0 0 10px;line-height:1.8em} +#find_info #info_fs #mb_email {width:100%} +#find_info #captcha {margin:0 20px;padding:0 0 10px} +#find_info #captcha input {margin-left:5px} + +/* 로그인 */ +#mb_login {margin:20px 0} +#mb_login h1 {margin:0 0 15px;padding:0 10px;font-size:1.3em} +#mb_login h2 {margin:0} +#mb_login p {padding:10px 0;line-height:1.5em} +#mb_login #login_frm {position:relative;padding:0 5px;font-size:1em} +#mb_login #login_frm div {padding:10px 0 0;text-align:right} +#mb_login .frm_input {display:block;margin-bottom:5px;padding:0;width:81%;height:1.8em;line-height:1.8em} +#mb_login .btn_submit {position:absolute;top:0;right:5px;padding:0 !important;width:18%;height:4.3em !important;text-align:center} +#mb_login section {margin:30px 0;padding:15px 10px;border:1px solid #cfded8;background:#f7f7f7} +#mb_login section div {text-align:right} + +/* 쪽지 */ +#memo_view_contents {margin:0 auto 20px;width:90%} +#memo_view_contents h1 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#memo_view_ul {margin:0;padding:0 0 10px;border-bottom:1px solid #eee;list-style:none} +.memo_view_li {position:relative;padding:5px 0} +.memo_view_subj {display:inline-block;width:65px} +#memo_view_ul a {} +#memo_view p {padding:10px 0;min-height:150px;height:auto !important;height:150px;line-height:1.8em} + +#memo_list_ul {margin:0 20px;padding:0;border-top:1px solid #e9e9e9;list-style:none} +#memo_list_ul li {position:relative;padding:10px 0;border-bottom:1px solid #e9e9e9} +#memo_list_ul .memo_link {} +#memo_list_ul .memo_send {position:absolute;top:10px;right:30px} +#memo_list_ul .memo_read {font-size:0.95em;color:#666} +#memo_list_ul .memo_del {position:absolute;top:10px;right:0} + +#memo_write #me_recv_mb_id {width:98%} +#memo_write textarea {width:99%;height:100px} + +/* 스크랩 */ +#scrap_ul {margin:0 20px;padding:0;border-top:1px solid #e9e9e9;list-style:none} +#scrap_ul li {position:relative;padding:10px 35px 10px 0;border-bottom:1px solid #e9e9e9} +#scrap_ul .scrap_board {display:inline-block;margin:0 10px 0 0;font-weight:bold} +#scrap_ul .scrap_del {position:absolute;top:10px;right:0} + +#scrap_do table {margin:0 0 10px;width:100%} +#scrap_do textarea {width:99%;height:100px} + +/* 포인트 */ +#point_ul {margin:0 20px;padding:0;border-top:1px solid #e9e9e9;list-style:none} +#point_ul li {position:relative;padding:10px 0;border-bottom:1px solid #e9e9e9} +#point_ul .point_wrap01 {position:relative;padding:0 0 0 90px} +#point_ul .point_wrap02 {margin:7px 0 0;text-align:right} +#point_ul .point_date {position:absolute;top:0;left:0} + +#point_sum {margin:0 20px} +#point_sum .sum_row {margin:0 0 1px;background:#f2f5f9} +#point_sum .sum_row:after {display:block;visibility:hidden;clear:both;content:''} +#point_sum .sum_tit, #point_sum .sum_val {display:block;margin:0 0 1px;padding:10px} +#point_sum .sum_tit {clear:both;float:left;width:100px} +#point_sum .sum_val {float:right} + +/* 회원 비밀번호 확인 */ +#mb_confirm {margin:30px 0} +#mb_confirm h1 {margin:0 0 15px;padding:0 10px;font-size:1.3em} +#mb_confirm p {padding:15px 10px;border-bottom:1px solid #cfded8;border-bottom:0;background:#fff} +#mb_confirm p strong {display:block} +#mb_confirm fieldset {position:relative;margin:0 0 5px;padding:20px 10px;border-bottom:1px solid #cfded8;background:#f7f7f7} +#mb_confirm_pw {display:block;margin-top:10px;padding:0;width:88%;line-height:1.8em !important} +#mb_confirm .btn_submit {position:absolute;bottom:20px;right:10px;width:10%;height:1.9em !important;line-height:1.9em} + +/* 비밀글 비밀번호 확인 */ +#pw_confirm {margin:30px 0} +#pw_confirm h1 {margin:0 0 15px;padding:0 10px;font-size:1.3em} +#pw_confirm p {padding:15px 10px;border-bottom:1px solid #cfded8;border-bottom:0;background:#fff} +#pw_confirm p strong {display:block} +#pw_confirm fieldset {position:relative;margin:0 0 5px;padding:5px 5px 10px;border-bottom:1px solid #cfded8;background:#f7f7f7} +#pw_wr_password {display:block;margin-top:10px;padding:0;width:88%;line-height:1.8em !important} +#pw_confirm .btn_submit {position:absolute;bottom:10px;right:5px;width:10%;height:1.9em !important;line-height:1.9em} + +/* 폼메일 */ +#formmail #subject {width:98%} +#formmail textarea {width:99%;height:100px} + +/* 자기소개 */ +#profile table {margin-bottom:0} +#profile section {padding:10px 20px} +#profile h2 {margin:0} +#profile .sv_wrap a {margin:0 0 5px;padding:0;font-weight:bold;line-height:10px} \ No newline at end of file diff --git a/theme/basic/mobile/skin/new/basic/new.skin.php b/theme/basic/mobile/skin/new/basic/new.skin.php new file mode 100644 index 000000000..9055d2b52 --- /dev/null +++ b/theme/basic/mobile/skin/new/basic/new.skin.php @@ -0,0 +1,66 @@ +', 0); +?> + + +
    + 상세검색 +
    + + + + + +
    + +
    + + + +
    + + + + + + + + + + + + + + + + + + '; + ?> + +
    게시판제목일시
    게시물이 없습니다.
    +
    + + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/new/basic/style.css b/theme/basic/mobile/skin/new/basic/style.css new file mode 100644 index 000000000..6fe648fcf --- /dev/null +++ b/theme/basic/mobile/skin/new/basic/style.css @@ -0,0 +1,9 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 새글 */ +#new_sch {margin:0 0 5px;padding:5px 10px} +#new_tbl {} +#new_tbl th:nth-of-type(3) {width:50px} + +#new_tbl td:nth-of-type(3) {text-align:center} \ No newline at end of file diff --git a/theme/basic/mobile/skin/outlogin/basic/outlogin.skin.1.php b/theme/basic/mobile/skin/outlogin/basic/outlogin.skin.1.php new file mode 100644 index 000000000..a9dcf1b8f --- /dev/null +++ b/theme/basic/mobile/skin/outlogin/basic/outlogin.skin.1.php @@ -0,0 +1,63 @@ +', 0); +?> + + + + + diff --git a/theme/basic/mobile/skin/outlogin/basic/outlogin.skin.2.php b/theme/basic/mobile/skin/outlogin/basic/outlogin.skin.2.php new file mode 100644 index 000000000..a7c703339 --- /dev/null +++ b/theme/basic/mobile/skin/outlogin/basic/outlogin.skin.2.php @@ -0,0 +1,46 @@ +', 0); +?> + + + + + + diff --git a/theme/basic/mobile/skin/outlogin/basic/style.css b/theme/basic/mobile/skin/outlogin/basic/style.css new file mode 100644 index 000000000..e98b3ab56 --- /dev/null +++ b/theme/basic/mobile/skin/outlogin/basic/style.css @@ -0,0 +1,29 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 아웃로그인 */ +.ol {position:relative;margin:0 0 10px;padding:0 5px 5px;border-bottom:1px solid #e7f1ed} +.ol h2 {width:0;height:0;overflow:hidden} + +.ol a.btn_admin {display:inline-block;margin:0 0 5px;padding:0 10px;border:1px solid #e8180c;background:#e8180c;color:#fff;text-decoration:none;line-height:2em;vertical-align:middle} /* 관리자 전용 버튼 */ +.ol a.btn_admin:focus, .ol a.btn_admin:hover {text-decoration:none} + +#ol_before input[type=text], #ol_before input[type=password] {display:block;margin-bottom:5px;padding:0;width:80%;height:1.8em;border:1px solid #e4eaec;background:#f7f7f7;vertical-align:middle;line-height:1.8em} +#ol_before input[type=submit] {position:absolute;top:0;right:5px;padding:0 !important;width:18%;height:4.3em;border:0;background:#333;color:#fff;letter-spacing:-0.1em;vertical-align:top;cursor:pointer} +#ol_svc {margin:15px 0 5px;text-align:right} +#ol_svc a {display:inline-block;margin:0 0 0 5px;color:#000;text-decoration:none;vertical-align:middle} + +#ol_after_hd strong {display:inline-block;padding:0 0 5px} +#ol_after_hd .btn_admin {display:block;padding:0 !important;text-align:center} +#ol_after_private {margin:0;padding:0;list-style:none} +#ol_after_private:after {display:block;visibility:hidden;clear:both;content:""} +#ol_after_private li {float:left} +#ol_after_memo {width:30%} +#ol_after_pt {width:40%} +#ol_after_scrap {width:30%} +#ol_after_private a {display:block;height:3em;background:#f7f7f7;color:#000;text-decoration:none;text-align:center;line-height:3em} +#ol_after_private a strong {color:#000;font-weight:normal} +#ol_after_private a:nth-of-type(1) {border-right:1px solid #fff} +#ol_after_private a:nth-of-type(2) {border-right:1px solid #fff} +#ol_after_ft {margin-top:5px;text-align:right} +#ol_after_ft a {display:inline-block;padding:0 20px;height:2em;background:#333;color:#fff;text-decoration:none;text-align:center;line-height:2em} \ No newline at end of file diff --git a/theme/basic/mobile/skin/poll/basic/poll.skin.php b/theme/basic/mobile/skin/poll/basic/poll.skin.php new file mode 100644 index 000000000..3585bbf6a --- /dev/null +++ b/theme/basic/mobile/skin/poll/basic/poll.skin.php @@ -0,0 +1,65 @@ +', 0); +?> + +
    + + + +
    + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/poll/basic/poll_result.skin.php b/theme/basic/mobile/skin/poll/basic/poll_result.skin.php new file mode 100644 index 000000000..451d92217 --- /dev/null +++ b/theme/basic/mobile/skin/poll/basic/poll_result.skin.php @@ -0,0 +1,120 @@ +', 0); +?> + +
    +

    + +
    +

    결과

    + +
    +
    전체
    +
    +
      + +
    1. +

      + + + % +

      +
      + +
      +
    2. + +
    +
    +
    +
    + + +
    +

    이 설문에 대한 기타의견

    + + +
    +
    +

    님의 의견

    + + +
    +

    + +

    +
    + "; } ?> +
    +
    + + + = $po['po_level']) { ?> +
    + + + + +

    + +
    + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + + +
    + +
    +
    + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/poll/basic/style.css b/theme/basic/mobile/skin/poll/basic/style.css new file mode 100644 index 000000000..f0d852baa --- /dev/null +++ b/theme/basic/mobile/skin/poll/basic/style.css @@ -0,0 +1,86 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +#poll a.btn_admin {} /* 관리자 전용 버튼 */ +#poll a.btn_admin:focus, #poll a.btn_admin:hover {} + +/* 폼 테이블 */ +#poll .tbl_frm table {} +#poll .tbl_frm .frm_address {} +#poll .tbl_frm .frm_file {} +#poll .tbl_frm .frm_info {} + +#poll .tbl_frm01 {} +#poll .tbl_frm01 caption {} +#poll .tbl_frm01 th {} +#poll .tbl_frm01 td {} +#poll .tbl_frm01 textarea, #poll .frm_input {} +#poll .tbl_frm01 textarea {} +/* +#poll .tbl_frm01 #captcha {} +#poll .tbl_frm01 #captcha input {} +*/ +#poll .tbl_frm01 a {} + +#poll .required, #poll textarea.required {} + +#poll .btn_confirm {} /* 서식단계 진행 */ +#poll .btn_submit {} +#poll .btn_cancel {} +#poll .btn_frmline {} /* 우편번호검색버튼 등 */ +#poll .win_btn {} /* 새창용 */ +#poll .win_btn a {} +#poll .win_btn button {} +#poll .win_btn input {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 설문조사 스킨 */ +#poll {margin:10px 0 0;padding:0 0 10px} +#poll header {position:relative;padding:0 5px} +#poll h2 {padding:0 0 5px} +#poll header .btn_admin {display:block;margin:0 0 5px;padding:0 10px;border:1px solid #e8180c;background:#e8180c;color:#fff;text-align:center;text-decoration:none;line-height:2em;vertical-align:middle} +#poll header p {padding:0} +#poll ul {margin:0 0 10px;padding:5px 10px;list-style:none} +#poll li {padding:3px 0} +#poll footer {padding:0 5px} +#poll footer:after {display:block;visibility:hidden;clear:both;content:""} +#poll footer input {float:left;width:49%;height:2.5em;border:0;background:#333;color:#fff;letter-spacing:-0.1em;vertical-align:top;cursor:pointer;-webkit-appearance:none} +#poll footer a {display:inline-block;float:right;width:49%;height:2.4em;border:1px solid #ccc;background:#fafafa;color:#000;text-decoration:none;text-align:center;line-height:2.4em} +#poll footer a:focus, #poll footer a:hover {text-decoration:none !important} + +/* 설문조사 결과 (새창) */ +#poll_result section {padding:10px;border-bottom:1px solid #eee} +#poll_result h2 {margin:0;padding:0} +#poll_result .member, #poll_result .guest, #poll_result .sv_member, #poll_result .sv_guest {font-weight:bold;margin-right:5px} +#poll_result_list {margin:0 auto} +#poll_result_list h2 {text-align:center} +#poll_result_list dl, #poll_result_list dt, #poll_result_list dd {margin:0;padding:0} +#poll_result_list dl {padding-bottom:20px} +#poll_result_list dt {margin-right:5%;color:#e8180d;text-align:right} +#poll_result_list ol {margin:0;padding-left:25px} +#poll_result_list li {margin-top:10px} +#poll_result_list p {position:relative;margin:0;padding:5px 0} +#poll_result_list p strong {position:absolute;top:5px;right:5%;margin-right:60px;width:100px;text-align:right} +#poll_result_list p span {position:absolute;top:5px;right:5%;width:60px;color:#68999c;text-align:right} +.poll_result_graph {position:relative;margin-right:5%;height:5px;background:#eee} +.poll_result_graph span {position:absolute;top:0;left:0;height:5px;background:#565e60;font-size:0.1em} +#poll_result_cmt {margin:0 auto;padding:15px !important;background:#f7f7f7} +#poll_result_cmt h2 {margin:0 0 20px;text-align:center} +#poll_result_cmt h3 {margin:0 auto 10px} +#poll_result_cmt article {margin:0 0 10px;border-bottom:1px solid #eee} +#poll_result_cmt h1 {margin:0;padding:0;width:0;height:0;font-size:0;line-height:0;overflow:hidden} +#poll_result_cmt p {padding:5px 0} +#poll_result_cmt footer {text-align:right} +#poll_result_cmt .tbl_wrap {margin:0} +#poll_result_wcmt {margin:0 0 10px !important} +#poll_result_wcmt td {padding:0 0 5px;border:0} +#poll_result_wcmt input[type=text] {background:#fff !important} +#pc_idea {width:98%} +.poll_cmt_del a {display:inline-block;padding-bottom:10px} +#poll_result_oth {margin:0 auto 15px} +#poll_result_oth h2 {padding:10px} +#poll_result_oth ul {margin:0;padding:0 10px;list-style:none} +#poll_result_oth a {display:block;padding:10px 0;border-bottom:1px solid #eee;color:#000;text-decoration:none} \ No newline at end of file diff --git a/theme/basic/mobile/skin/popular/basic/popular.skin.php b/theme/basic/mobile/skin/popular/basic/popular.skin.php new file mode 100644 index 000000000..463b3b01c --- /dev/null +++ b/theme/basic/mobile/skin/popular/basic/popular.skin.php @@ -0,0 +1,17 @@ +', 0); +?> + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/popular/basic/style.css b/theme/basic/mobile/skin/popular/basic/style.css new file mode 100644 index 000000000..545cd3086 --- /dev/null +++ b/theme/basic/mobile/skin/popular/basic/style.css @@ -0,0 +1,11 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 인기검색어 */ +#popular {border-bottom:1px dotted #dde4e9} +#popular div {zoom:1} +#popular div:after {display:block;visibility:hidden;clear:both;content:""} +#popular h2 {float:left;padding:10px 5px 10px 10px} +#popular ul {float:left;margin:0 0 0 10px;padding:0;list-style:none} +#popular li {float:left} +#popular a {display:inline-block;padding:10px 5px;text-decoration:none} \ No newline at end of file diff --git a/theme/basic/mobile/skin/qa/basic/img/btn_close.gif b/theme/basic/mobile/skin/qa/basic/img/btn_close.gif new file mode 100644 index 0000000000000000000000000000000000000000..040b180ac6584ae612ef2886487110f0ad079963 GIT binary patch literal 211 zcmZ?wbhEHbC>lw|Nj2|^XJd+Ki|K7yLIc<@85r}UAy+@_wT|Ns9P2m!^PEMO%%AQEIJ18abSL2rs@7wgh> zI-xzeYYr882T$7a>~-(!J@=MOy}Z$ltNl`73Cq0Bi3wIGB-b=ECVhGFY*&ANIg94( d^Unm859R4|2rw-)wA%9i`(c-qSMQw}tN}eeW+eas literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/qa/basic/img/icon_answer.gif b/theme/basic/mobile/skin/qa/basic/img/icon_answer.gif new file mode 100644 index 0000000000000000000000000000000000000000..91c135977b4f445a90c849310dc80efde1983830 GIT binary patch literal 77 zcmZ?wbhEHb-Wqsc#^P~2x#@rVooH@5wHB9i@BozKb;P9uI^*c|UyXO5@>VyLmgEat< Cr6(f* literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/qa/basic/img/icon_hot.gif b/theme/basic/mobile/skin/qa/basic/img/icon_hot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c95b839aeef0c1e26a4bab4ea50cd6d3f1969d7f GIT binary patch literal 97 zcmZ?wbhEHbzHen|7VvwFnzUPlarEA ZqW~YXyUO~T+#YkUoJ%V_>ib05Q5F AasU7T literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/qa/basic/img/icon_mobile.gif b/theme/basic/mobile/skin/qa/basic/img/icon_mobile.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad934d23c440c83db0c4589596465cb087353e01 GIT binary patch literal 62 zcmZ?wbhEHbZ% literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/qa/basic/img/icon_secret.gif b/theme/basic/mobile/skin/qa/basic/img/icon_secret.gif new file mode 100644 index 0000000000000000000000000000000000000000..c04899f14fa727b64223f6c5457877c6c939639d GIT binary patch literal 97 zcmZ?wbhEHb&!1E4^4&ClEzh)PmWxV3{9A~!gB2-%RL5bHcgg3Zp^!+W)H2^A_AxQuL literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/qa/basic/img/icon_sound.gif b/theme/basic/mobile/skin/qa/basic/img/icon_sound.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5188318a5cdc394b984125c0ddd376c5f57bbe4 GIT binary patch literal 113 zcmZ?wbhEHbE1CJY$zMikVi`-#gIi|DbmsXBWf6U5szE@->A`0*`&<;b@XASRrB8=E6~=S>Pbm I%fes{0AXt-SpWb4 literal 0 HcmV?d00001 diff --git a/theme/basic/mobile/skin/qa/basic/list.skin.php b/theme/basic/mobile/skin/qa/basic/list.skin.php new file mode 100644 index 000000000..2efc6fb57 --- /dev/null +++ b/theme/basic/mobile/skin/qa/basic/list.skin.php @@ -0,0 +1,152 @@ +', 0); +?> + +
    + + + + + + + +
    +
    + Total + 페이지 +
    + + + + +
    + + +
    + + + + + +
    + + +
    + + +
    +
      + +
    • + +
      + + +
      + + +
      + + + + +
      +
      +
    • + + + 게시물이 없습니다.'; } ?> +
    +
    + +
    + +
      +
    • +
    + + + +
    +
    +
    + + + + + + + + + +
    + 게시물 검색 + +
    + + + + +
    +
    + + + + + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/qa/basic/style.css b/theme/basic/mobile/skin/qa/basic/style.css new file mode 100644 index 000000000..28bdeaac5 --- /dev/null +++ b/theme/basic/mobile/skin/qa/basic/style.css @@ -0,0 +1,247 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +/* 게시판 버튼 */ +/* 목록 버튼 */ +#bo_list a.btn_b01 {} +#bo_list a.btn_b01:focus, #bo_list .btn_b01:hover {} +#bo_list a.btn_b02 {} +#bo_list a.btn_b02:focus, #bo_list .btn_b02:hover {} +#bo_list a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_list a.btn_admin:focus, #bo_list a.btn_admin:hover {} + +/* 읽기 버튼 */ +#bo_v a.btn_b01 {} +#bo_v a.btn_b01:focus, #bo_v .btn_b01:hover {} +#bo_v a.btn_b02 {} +#bo_v a.btn_b02:focus, #bo_v .btn_b02:hover {} +#bo_v a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_v a.btn_admin:focus, #bo_v a.btn_admin:hover {} + +/* 쓰기 버튼 */ +#bo_w .btn_confirm {} /* 서식단계 진행 */ +#bo_w .btn_submit {} +#bo_w .btn_cancel {} +#bo_w .btn_frmline {} /* 우편번호검색버튼 등 */ + +/* 읽기 내 테이블 */ +#bo_v .tbl_head01 {} +#bo_v .tbl_head01 caption {} +#bo_v .tbl_head01 thead th {} +#bo_v .tbl_head01 thead a {} +#bo_v .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_v .tbl_head01 tfoot th {} +#bo_v .tbl_head01 tfoot td {} +#bo_v .tbl_head01 tbody th {} +#bo_v .tbl_head01 td {} +#bo_v .tbl_head01 a {} +#bo_v td.empty_table {} + +/* 쓰기 테이블 */ +#bo_w table {} +#bo_w caption {} +#bo_w .frm_address {} +#bo_w .frm_file {} +#bo_w .frm_info {} + +#bo_w .tbl_frm01 {} +#bo_w .tbl_frm01 caption {} +#bo_w .tbl_frm01 th {} +#bo_w .tbl_frm01 td {} +#bo_w .tbl_frm01 textarea, #bo_w .frm_input {} +#bo_w .tbl_frm01 textarea {} +/* +#bo_w .tbl_frm01 #captcha {} +#bo_w .tbl_frm01 #captcha input {} +*/ +#bo_w .tbl_frm01 a {} + +#bo_w .required, #bo_w textarea.required {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 게시판 목록 */ +#bo_list #list_chk {padding:0 10px 10px} +#bo_list .ul_wrap ul {margin:0;padding:0;border-top:1px solid #e9e9e9;list-style:none} +#bo_list .ul_wrap li {position:relative;padding:8px 10px;border-bottom:1px solid #e9e9e9} +#bo_list .ul_wrap li.bo_adm {padding:8px 10px 8px 30px} +#bo_list .ul_wrap a {display:block;padding:0 0 10px} +#bo_list .ul_wrap .li_chk {position:absolute;top:8px;left:10px} +#bo_list .ul_wrap .li_info span {display:inline-block;margin:0 5px 0 0;vertical-align:middle} +#bo_list .ul_wrap .li_stat {position:absolute;bottom:8px;right:10px} + +#bo_cate h2 {width:0;height:0;font-size:0;line-height:0;overflow:hidden} +#bo_cate ul {margin:5px 10px;padding-left:1px;zoom:1} +#bo_cate ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_cate li {float:left;margin-bottom:-1px;width:25%} +#bo_cate a {display:block;position:relative;margin-left:-1px;padding:5px 0;border:1px solid #ddd;background:#f7f7f7;color:#888;text-align:center;text-decoration:none;letter-spacing:-0.1em} +#bo_cate a:focus, +#bo_cate a:hover, +#bo_cate a:active {text-decoration:none} +#bo_cate #bo_cate_on {z-index:2;border:1px solid #565e60;background:#fff;color:#565e60;font-weight:bold} + +/* 관리자일 때 */ +#bo_list_admin th label {position:absolute;font-size:0;line-height:0;overflow:hidden} + +#bo_list_admin th:nth-of-type(1) {width:40px} +#bo_list_admin th:nth-of-type(3) {width:100px} + +#bo_list_admin td:nth-of-type(1) {text-align:center} +#bo_list_admin td:nth-of-type(3) {text-align:center} + +/* 관리자가 아닐 때 */ +#bo_list th:nth-of-type(2) {width:100px} + +#bo_list td:nth-of-type(2) {text-align:center} + +/* 게시판 목록 공통 */ +.bo_fx {margin-bottom:5px;padding:5px 10px} +.bo_fx:after {display:block;visibility:hidden;clear:both;content:""} +.bo_fx ul {margin:0;padding:0;list-style:none} +#bo_list_total {float:left;padding:0;height:2.5em;line-height:2.5em} +.btn_bo_user {float:right;margin:0;padding:0;list-style:none} +.btn_bo_user li {float:left;margin-left:5px} +.btn_bo_adm {float:left} +.btn_bo_adm li {float:left;margin-right:5px} +.btn_bo_adm input {padding:0 10px;height:2em;border:1px solid #e8180c !important;background:#e8180c;color:#fff;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-appearance:none} +.bo_notice td {background:#f7f7f7} +.bo_notice td a {font-weight:bold} +.td_num strong {color:#000} +.bo_cate_link {display:inline-block;margin:0 3px 0 0;padding:0 6px 0 0;border-right:1px solid #e7f1ed;color:#999 !important;font-weight:bold;text-decoration:none} /* 글제목줄 분류스타일 */ +.bo_current {color:#e8180c} +.td_subject img {margin-left:3px} +#bo_list .cnt_cmt {display:inline-block;margin:0 0 0 3px;font-weight:bold} + +#bo_sch {margin-bottom:10px;padding-top:5px;text-align:center} + +/* 게시판 쓰기 */ +#bo_w #wr_email, #bo_w #wr_homepage, #bo_w #wr_subject {width:100%} + +#char_count_desc {display:block;margin:0 0 5px;padding:0} +#char_count_wrp {margin:5px 0 0;text-align:right} +#char_count {font-weight:bold} + +#qa_email {width:50%} +#qa_subject {width:100%} + +/* 게시판 읽기 */ +#bo_v {margin-bottom:15px;padding-bottom:15px} + +#bo_v_table {margin:0 0 5px;padding:0 10px;color:#999;font-size:0.9em;font-weight:bold} + +#bo_v_title {padding:0 10px 10px;font-size:1.2em} + +#bo_v_info {padding:0 10px 10px;border-bottom:1px solid #ddd} +#bo_v_info h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_info {} +#bo_v_info strong {display:inline-block;margin:0 0 0 5px;font-weight:normal} + +#bo_v_file {} +#bo_v_file h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_file ul {margin:0;padding:0;list-style:none} +#bo_v_file li {padding:0 10px;border-bottom:1px solid #eee;background:#f7f7f7} +#bo_v_file a {display:inline-block;padding:5px 0;color:#000;text-decoration:none} +#bo_v_file a:focus, #bo_v_file a:hover, #bo_v_file a:active {text-decoration:none} +.bo_v_file_cnt {display:inline-block;margin:0 10px} + +#bo_v_link {} +#bo_v_link h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_link ul {margin:0;padding:0;list-style:none} +#bo_v_link li {padding:0 10px;border-bottom:1px solid #eee;background:#f7f7f7} +#bo_v_link a {display:inline-block;padding:5px 0;color:#000;text-decoration:none} +#bo_v_link a:focus, #bo_v_link a:hover, #bo_v_link a:active {text-decoration:none} +.bo_v_link_cnt {display:inline-block;margin:0 10px} + +#bo_v_contact {border-bottom:1px solid #ddd} +#bo_v_contact h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_contact dl {margin:0;padding:0;list-style:none} +#bo_v_contact dl:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_contact dt, #bo_v_contact dd {float:left;margin:0;border-bottom:1px solid #eee;background:#f5f6fa} +#bo_v_contact dt {clear:both;padding:8px 0 8px 10%;width:20%;font-weight:bold} +#bo_v_contact dd {padding:8px 0;width:70%} + +#bo_v_top {margin:0 0 10px;padding:10px} +#bo_v_top:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_top h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_top ul {margin:0;padding:0;list-style:none} + +#bo_v_bot {padding:0 10px} +#bo_v_bot:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_bot h2 {position:absolute;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +#bo_v_bot ul {margin:0;padding:0;list-style:none} + +.bo_v_nb {float:left} +.bo_v_nb li {float:left;margin-right:5px} +.bo_v_com {float:right} +.bo_v_com li {float:left;margin-left:5px} + +#bo_v_atc {padding:0 10px;min-height:100px} +#bo_v_atc_title {margin:0;padding:0;height:0;overflow:hidden} + +#bo_v_img {margin:0 0 10px;width:100%;overflow:hidden;zoom:1} +#bo_v_img:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_img img {margin-bottom:15px;max-width:100%;height:auto} + +#bo_v_con {margin-bottom:20px;width:100%;line-height:1.7em;word-break:break-all;overflow:hidden} +#bo_v_con a {color:#000;text-decoration:underline} +#bo_v_con img {max-width:100%;height:auto} + +#bo_v_act {margin-bottom:20px;text-align:center} +#bo_v_act a {margin-right:5px;vertical-align:top} +#bo_v_act span {display:inline-block;margin-right:5px;padding:0 10px;border:1px solid #eee !important;background:#fafafa !important;color:#000 !important;text-decoration:none !important;line-height:2em;vertical-align:top} +#bo_v_act strong {color:#ff3061} +#bo_v_act_good, #bo_v_act_nogood {display:inline-block;width:1px;height:1px;font-size:0;line-height:0;overflow:hidden} + +#bo_v_sns {margin:0 0 20px;padding:0;list-style:none;zoom:1} +#bo_v_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_sns li {float:left;margin:0 5px 0 0} + +#bo_v_addq {margin:0 0 30px;text-align:right} + +#bo_v_ans {margin:0 10px 30px;padding:30px 0 0;border-top:1px solid #e9e9e9} +#bo_v_ans h2 {display:inline-block;vertical-align:middle;font-size:1.2em} +#bo_v_ans #ans_datetime {margin:10px 0;color:#999} +#bo_v_ans #ans_con {margin:0 0 10px;line-height:1.8em} +#bo_v_ans #ans_add {text-align:right} +#bo_v_ans #ans_msg {padding:40px 0;background:#f2f5f9;text-align:center} + +#bo_v_rel {margin:0 0 30px;padding:30px 0 0;border-top:1px solid #e9e9e9} +#bo_v_rel h2 {margin:0 10px 10px;font-size:1.2em} + +#bo_v form {padding-top:15px} + +/* 게시판 댓글 */ +#bo_vc {margin:0 0 5px;padding:15px 15px 5px;border-top:1px solid #cfded8;border-bottom:1px solid #cfded8;background:#f7f7f7} +#bo_vc h2 {margin-bottom:5px} +#bo_vc article {padding:0 0 5px;border-top:1px dotted #ccc} +#bo_vc header {position:relative;padding:13px 0 5px} +#bo_vc header .icon_reply {position:absolute;top:13px;left:-20px} +#bo_vc .sv_member, #bo_vc .sv_guest {font-weight:bold} +.bo_vc_hdinfo {display:inline-block;margin:0 10px 0 5px} +#bo_vc h1 {width:0;height:0;font-size:0;line-height:0;overflow:hidden} +#bo_vc a {color:#000;text-decoration:none} +#bo_vc p {padding:0 0 5px;line-height:1.8em} +#bo_vc p a {text-decoration:underline} +#bo_vc_empty {margin:0;padding:15px !important;border-bottom:1px dotted #ccc;text-align:center} +#bo_vc fieldset {margin:0 0 10px;padding:0} +#bo_vc #bo_vc_winfo {float:left} +#bo_vc footer {zoom:1} +#bo_vc footer:after {display:block;visibility:hidden;clear:both;content:""} + +.bo_vc_act {float:right;margin:0;list-style:none} +.bo_vc_act:after {display:block;visibility:hidden;clear:both;content:""} +.bo_vc_act li {float:left;margin-left:5px} + +#bo_vc_w {position:relative;margin-bottom:10px;padding:0 15px 15px;border-bottom:1px solid #cfded8} +#bo_vc_w h2 {padding:10px 0 5px} +#bo_vc_w #char_cnt {display:block;margin-bottom:5px} +#bo_vc_w textarea {width:99%} + +#bo_vc_sns {margin:0;padding:0;list-style:none;zoom:1} +#bo_vc_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_vc_sns li {float:left;margin:0 10px 0 0} +#bo_vc_sns input {margin:0 0 0 5px} + +#bo_vc form {padding:0} \ No newline at end of file diff --git a/theme/basic/mobile/skin/qa/basic/view.answer.skin.php b/theme/basic/mobile/skin/qa/basic/view.answer.skin.php new file mode 100644 index 000000000..d8d8beb1f --- /dev/null +++ b/theme/basic/mobile/skin/qa/basic/view.answer.skin.php @@ -0,0 +1,24 @@ + + +
    +

    답변:

    + 추가질문 + +
    + +
    +
    + +
    + +
    + + 답변수정 + + + 답변삭제 + +
    +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/qa/basic/view.answerform.skin.php b/theme/basic/mobile/skin/qa/basic/view.answerform.skin.php new file mode 100644 index 000000000..7fbf8d81f --- /dev/null +++ b/theme/basic/mobile/skin/qa/basic/view.answerform.skin.php @@ -0,0 +1,125 @@ + + +
    + +

    답변등록

    + +
    + + + + + + '; + } else { + $option .= "\n".''."\n".''; + } + + echo $option_hidden; + ?> + +
    + + + + + + + + + + + + + + + + + +
    옵션
    + +
    +
    + +
    + +
    +
    + + + +

    고객님의 문의에 대한 답변을 준비 중입니다.

    + +
    \ No newline at end of file diff --git a/theme/basic/mobile/skin/qa/basic/view.skin.php b/theme/basic/mobile/skin/qa/basic/view.skin.php new file mode 100644 index 000000000..cf9be9ccd --- /dev/null +++ b/theme/basic/mobile/skin/qa/basic/view.skin.php @@ -0,0 +1,187 @@ +', 0); +?> + + + + +
    + +
    +
    +

    + +

    +
    + +
    +

    페이지 정보

    + 작성자 + 작성일 +
    + + + +
    +

    첨부파일

    + +
    + + + + +
    +

    연락처정보

    +
    + +
    이메일
    +
    + + +
    휴대폰
    +
    + +
    +
    + + + +
    + + + + + + + +
    + + +
    +

    본문

    + + \n"; + + for ($i=0; $i<$view['img_count']; $i++) { + //echo $view['img_file'][$i]; + echo get_view_thumbnail($view['img_file'][$i], $qaconfig['qa_image_width']); + } + + echo "\n"; + } + ?> + + +
    + + + + + + +
    + + + + +
    +

    연관질문

    + +
    + + + + + + + + + + + + + + + + + + + +
    분류제목상태등록일
    + + + +
    +
    +
    + + + +
    + +
    + + +
    + + + \ No newline at end of file diff --git a/theme/basic/mobile/skin/qa/basic/write.skin.php b/theme/basic/mobile/skin/qa/basic/write.skin.php new file mode 100644 index 000000000..39118b80b --- /dev/null +++ b/theme/basic/mobile/skin/qa/basic/write.skin.php @@ -0,0 +1,184 @@ +', 0); +?> + +
    + +
    + + + + + + '; + } else { + $option .= "\n".''."\n".''; + } + + echo $option_hidden; + ?> + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    옵션
    + class="frm_input email" maxlength="100"> + > + +
    + class="frm_input" size="30"> + + > 답변등록 SMS알림 수신 + +
    + +
    + +
    파일 #1 + + + + +
    파일 #2 + + + + +
    +
    + +
    + + 목록 +
    +
    + + +
    + \ No newline at end of file diff --git a/theme/basic/mobile/skin/search/basic/search.skin.php b/theme/basic/mobile/skin/search/basic/search.skin.php new file mode 100644 index 000000000..c1ae64ec8 --- /dev/null +++ b/theme/basic/mobile/skin/search/basic/search.skin.php @@ -0,0 +1,142 @@ +', 0); +?> + +
    + +
    + 상세검색 +
    + + + + + +
    +
    + + + + + +
    +
    + id="sop_or" name="sop"> + + id="sop_and" name="sop"> + +
    +
    +
    + +
    + + +
    +

    전체검색 결과

    +
    +
    게시판
    +
    +
    게시물
    +
    +
    +

    / 페이지 열람 중

    +
    + + + + + +
    검색된 자료가 하나도 없습니다.
    + + +
    + +
    + +

    게시판 내 결과

    +
      + 댓글'; + $comment_href = '#c_'.$list[$idx][$i]['wr_id']; + } + else + { + $comment_def = ''; + $comment_href = ''; + } + ?> +
    • + + 새창 +

      + + +
    • + +
    + + +
    + +
    + + + +
    diff --git a/theme/basic/mobile/skin/search/basic/style.css b/theme/basic/mobile/skin/search/basic/style.css new file mode 100644 index 000000000..56295b0f4 --- /dev/null +++ b/theme/basic/mobile/skin/search/basic/style.css @@ -0,0 +1,33 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 전체검색결과 스킨 */ +#sch_res_detail {padding:0 0 10px;border-bottom:1px solid #e9e9e9;text-align:center} +#sch_res_detail legend {position:absolute;font-size:0;line-height:0;overflow:hidden} +#sch_res_detail div {margin:0 0 5px} +#sch_res_detail .frm_input {height:2.5em;line-height:2.5em} + +#sch_res_ov {padding:10px;border-bottom:1px solid #e9e9e9;background:#f5f6fa;zoom:1} +#sch_res_ov:after {display:block;visibility:hidden;clear:both;content:""} +#sch_res_ov h2 {margin:0 0 5px} +#sch_res_ov dl {margin:0 0 5px;zoom:1} +#sch_res_ov dl:after {display:block;visibility:hidden;clear:both;content:""} +#sch_res_ov dt {float:left} +#sch_res_ov dd {float:left;margin:0 10px 0 5px} +#sch_res_ov p {margin:0;padding:0} + +#sch_res_board {margin:0 0 10px;padding:0;list-style:none;zoom:1} +#sch_res_board:after {display:block;visibility:hidden;clear:both;content:""} +#sch_res_board a {display:block;position:relative;margin-left:-1px;padding:5px 10px;border-bottom:1px solid #e9e9e9;text-decoration:none;letter-spacing:-0.1em;line-height:1.2em;cursor:pointer} +#sch_res_board a:focus, #sch_res_board a:hover, #sch_res_board a:active {text-decoration:none} +#sch_res_board .cnt_cmt {font-weight:normal !important} + +.sch_res_list {margin:0 0 10px;padding:10px 0} +.sch_res_list h2 {margin:0 0 10px;padding:0 10px;font-size:1.2em} +.sch_res_list ul {margin:0;padding:0;list-style:none} +.sch_res_list li {margin:0 0 10px;padding:0 10px 10px;border-bottom:1px solid #e9e9e9} +.sch_res_list a {text-decoration:none} +.sch_res_title {display:inline-block;margin:0 0 5px} +.sch_res_list p {margin:0 0 10px;line-height:1.8em} +.sch_more {padding:0 10px;text-align:right} +.sch_on {color:#ff3061} \ No newline at end of file diff --git a/theme/basic/mobile/skin/visit/basic/style.css b/theme/basic/mobile/skin/visit/basic/style.css new file mode 100644 index 000000000..5a9c00719 --- /dev/null +++ b/theme/basic/mobile/skin/visit/basic/style.css @@ -0,0 +1,11 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +#visit {border-bottom:1px dotted #dde4e9} +#visit div {zoom:1} +#visit div:after {display:block;visibility:hidden;clear:both;content:""} +#visit h2 {float:left;padding:10px} +#visit dl {float:left;margin:0 0 0 5px;padding:0} +#visit dt {float:left;margin:0;padding:10px 5px;letter-spacing:-0.1em} +#visit dd {float:left;margin:0 3px 0 0;padding:10px 5px} +#visit a {display:inline-block;padding:10px 3px;text-decoration:none} \ No newline at end of file diff --git a/theme/basic/mobile/skin/visit/basic/visit.skin.php b/theme/basic/mobile/skin/visit/basic/visit.skin.php new file mode 100644 index 000000000..04027bdec --- /dev/null +++ b/theme/basic/mobile/skin/visit/basic/visit.skin.php @@ -0,0 +1,25 @@ +', 0); +?> + + diff --git a/theme/basic/mobile/tail.php b/theme/basic/mobile/tail.php new file mode 100644 index 000000000..70cac5cc0 --- /dev/null +++ b/theme/basic/mobile/tail.php @@ -0,0 +1,47 @@ + + + + +
    + + + +
    + +
    + + +
    + + Copyright © 소유하신 도메인. All rights reserved.
    + 상단으로 +
    +
    + + +PC 버전으로 보기 + + + + + \ No newline at end of file diff --git a/theme/basic/readme.txt b/theme/basic/readme.txt new file mode 100644 index 000000000..7e1102ba6 --- /dev/null +++ b/theme/basic/readme.txt @@ -0,0 +1,8 @@ +Theme Name: 베이직 +Theme URI: http://demo.sir.co.kr/gnuboard5 +Maker: SIR +Maker URI: http://sir.co.kr +Version: 1.0.0 +Detail: 베이직 테마는 SIR에서 제공하는 그누보드5 테마입니다. 베이직 테마는 웹표준 및 접근성을 준수합니다. +License: GNU LESSER GENERAL PUBLIC LICENSE Version 2.1 +License URI: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html \ No newline at end of file diff --git a/theme/basic/screenshot.png b/theme/basic/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..423a3993e322ca8e9d300249e51c3336deb8ac68 GIT binary patch literal 11304 zcmb7qby(X?yCzz+xO*v1DDL)_BE_vhaCdiyVx_pdy|@Jk?q1vq6t_~`HAt{c`^ous z_guTz$sd#Cmzl?Ao_p?jCJ`!1GOy9e(Ba_VUdw)zRD**<0K&n+_n{)fo*-4pXu{q| z-K2nS>W&s}p2jZbaPQ3=P0VRz?TszX)y$2}yq!nPMPMVMRTMr+9UUE~rKR88++1AW zZf$LU3ID3Bta5M)SzcK^y}TJ68~5<^n*H&Eo16Ri{OacZ(ZbT|;`;9S`T6kdvcLb^ z`PKEs#brlFM@402eSHJ;0s8RxR9INV%*?#Ew|{bRcYSjQdu{C;prWEaK0aREK<^$N z*Ee@p*EZ&t)-EA8$7i?DrBaMwsZJj-* zr>8aG+Ox~6%bUmB`}?Tqn7cdZ&cSJSPj6LKb#`{n^Yc?nOY8a7ZQkGciAl+&WtBm} z!M=X}XID@=J9}#z{f{3%I=i@PYipmKU)>f zWmO6E5ekLgpPXMGpIz)9pG!zcaBy${0DzN=o7>yl$H#|@8|c&1Gt9I2_=NS1jo!Y# ztLtl+golR*T3Xuq`Gv*BMHhE#GBUD_UmG{K_a-K$Rp1I?Vd2`^%BSa-&@cX7UER$s z^*?`ZmX(zqpWj|W?q6PB)J#i!xl^Z(~0XWk_Z)4#IrRVZ!2q zYgya#7AdJ|Nlq?8cIor?I`R5ji$n8$4!v!c#s1A}4wa3-M>-?jsv9AJ$>FOjgjTo& zKmW^J#R8JxzpCGmbRgq=MurE%njkm;YELk%K{9#|M+9qV;4l!tzngpAUYBuJLkO)Q z4?5DLzcI4T@dpnvYkl;wOdEC0xhHJH?Tan>Lcgx?H0hwKZdOog7%)qDkUVX6&5o4) zm#(89$CZy4+vDaIxnz1f$Cr9gBYf`$0ntiXfMK>wS71v3v+YsV@u#yEjaC8AN*R%k zyS5YmG3eM1Mj^uDvguz=G2qA&_N=u}_pgAqS2~MxIgL5k^-Y{%5X1}P9qlG3>P$}F zd9g=9?P^ri>ered=y<*9e&DT#PIpvYz9YzuE>&kB`etdiL{9?6tCKFVB=EhcUT-S* z>ToGx{`)gY8n=U79>LcG)9oMk62o{wf^5gw&_Ub1pMUK&dNA0Xuz`p+AB-&Wb`lFT zLt0)O{^qmSLxVeNGZI|RHGa7(+gLD|el`YD4-tMrz4eV5Y3Ytde@;mW$o&9VKhTYP z+Q}8`%7LW0i`Z>!96Z#g%XXh!3nQXuj6bI+?Qu9Of<5NTPSzkful+GvnrgdnpAmqB zL68ja4Jn}T{VvX+Dad@&fkLyAkp>htI39pus>|?co8mzg>%L`q$J>@c)ZU*_Y9pll z@F>P4a3rw6HokU+Ofkcyx`|#4Rv`O zu{Pn@o7*tW2|V)x(b@aRoeSzQB=W)&v6(aWqo|OS@Q*h`F(ahn&)-%(U68vA-qx4+ zQ=IT0#T{ThQ5pnVLN&Xz&nQ$c}D7I|p!j*vm; zoiZ1_jP2vMw>~*~qFKs(W7YEY8v5nQ^`fWq3X07;=y`KU>Z{a@i_yCiWe&4UxisGv zljQ4p8J0xY`4PXy&&1Y}C>M*$`jdLpSS4a8R35kpBFYZ1mX8Yp(;KqzrznlwXhcb7rBCC3^fP}(xkHN;(J zgJ5~xYeb~8>;28mame)u3YbE*d1%D&Gd)N5!aad!wTb9v8#Dc8i33UMTj|6iCT=25 zLf7J%Zd(&&3U7Zr(}e2JVb&Fr*v^v0B2>N^)L-k?)IS<#vVkl_Y74S)J=Pp*c3ia3 zrAJ?v$`G#N%X=mMqHoUj7^+4f@w6PRrY<*Q_y7@EQqUoQC@#@BdrwkPQ7Qg9hYMY3ejM_-uiSeka@G0M_!ot?6<b=q^0n)tCU*&*My0%&XdWBuj>Bh^}JmH~f2xrrc>rG*y2z|K@^fMZh6&h#Ww zl3~4VQ}NA~qEBHt)0f%yb_aZy0aW^&*eC#lCi|2fsYO{yyKv_jl^d^GzrI#a-S9+i zSMaPg>4%ZKt1+V){OYW)_$ImY4GpYwS1ppyT!6{`;f^%Nc-e$xz{k@!*vvFd>zy4& z#_XFvc=i^_mF3L(E~ruuJyCE{GwJZBtOEs>#c37JST$GU3hQ3(79I2Wnxj>6>Zazj zAeYEce`ygLz_gy;BA z^r~N&VOyYddKLLDOxB){e(I{(6x9hV8D*W}QqV1U0@1^34BiQ9smS&5QL00`Z@1ua zH;43!qY1!UzoBQjD{RRLNB;Y3qIU7hnn~?}nU(v_(|1Xe6J%BkssG<6uE-KHKq|}1 z?6H1+?#CTI&4I00hHWb0a$oZl7hP#<s&qlbRMlEQ z&ZZmkrB6_M3E%u%WrKBwg9((ZAJU)j(1D#vI?y^U+)XE!h{XtOJU0|_m09QP&0 zb0nUlTXSvE*(B}yvi>1FnhNE0a?6cl_5ed}W($-;Ri1aspX&R(F%Aq0e7(h@o(nl? zH{732d!2V(m|4`Qf@|p_lEdY0Zph2c)RJp#Osx^sMvL>DHl07n#i~{bPLrRNwCuPP zRz*3N11p%Vc&g`z_KaeLbF6I_Z04FHp}BaR*VMb;hYdLdwx6u?yrn#Wr(au@#*IvF z7!#j@1TMY@v@UWU-CWvJreAy@wD2eJaTN>HCp>x=Hs(N2weEdBY_YQIS-tPj(}EG> zxrJd`v3HBE?T;U1?%-2{qoLSHOTOjf?)^)VL_Cb6f~zH4H8Cx%+k?;X7Huag+!lqHAXra<^5jY=uk;PN^VDBjjoj^#v z+OpQz_^a({-fLF<#`eJik>=NRs_({VpLyTG`JwcIx_NiBs{Vv1v&!f&86&-5Av-(c0hVv`?f}IoV{ERqh zC)BzR7Oyn6x1OC#^VZHNQ%bv8?z^mbF_?VpsB|Bmlq|ny#j|fvQ&D@@IMz7rorWaw zdzOOdpH-$FwDIA6)@v@}V+SfLE<)e-cp+`^5ASiJW0l6a9d*x5;X7;JD6BAHR?D{A z^C-EO4wIic)RosLuTK;+W+*H(!8hiD>vU*+iw2?6L^p~ z{5-@WutTIqaT98;b(A$r`-3cS@m76}Cg2W7)9VQj#QPcI88%l3I&pGEtF5gy_P*tO zB3e(+iGw)4{uPq3&}aMlxG$Zu;JqIQddOAna~IeEZLx#asPDmu9pZ?xI985{;%mLG zX}j0&Ts2=@YS&9z6sYz8W_*7LA*>mu4su69X#Ha3`6k{L^+p+Wn=H692*w-#MGe6; zIG^1oT79)%g!qg0wvW3mPPXkr#a2evT(=-u_+D3V^K*jJRd)8GLJ=aFZv?%$Pb8WS zER;^gB1HteuV~DozfwE~H!0;x_eot@<3q9ZAG!o=ELot#v-sAFs zuKosdUGlTLl!};v0NB!W*g*3T9kRc@RA`_1>74gV)4(mC^}Fj`(&BP=W{P5duFI0; zYYQcNz6n`##$?2_GqK=X93y>X)^=5*amvIt8s8xl}U6BJ`-_m}!nq-3I+|DGyy>cY51 zTUW-0%4!xFG1OeW7(=kVp*}%mQD=|;{BG-`WX!;i3!=!Z3t#r1im>rLb(Z5th(ekb zS={9xrt~|Xk5}Wyiif7_%3Ar|fQ;;XBf;7_fhUt!)6ql|-zUf)6& zIh(b76O=r~NBH>pRAK}+18)4GscCukW(7?X|#?&!@)|7xY}4@cFDItr?X_T zD%ReGsRC*$8X63212j!@1S5I~hS^CRLLi&UcR51{Mamihp1c@gq<)#{#hy`3&ZX+n7k<;OMhM_LF$ zalD@5ub-a@vGkcFQ#u&aL%cMm94jlS+wV{8_TzS&4QpStx2U>a0WlDcHpjvP zl>*G4H@atQwcu>u8?EsZMh)CtQAZ6>N7+9e$ruihoIeSWYgvo4PtuEv8NXbKKX1MC zlsFk1HCAZk6{<-|QA-5LRRJZ-G~bu-Nt}523gK8~RRoGKgg!fNcK>a{h64zX_=Qtz zNXp;JGF`!`q;9)vQC^0&rK3+gWehA9!q!#}c=X>!1Y#hLh4UVa0MT6CMRLIw#F=)pW|~#rB5}~b!IYZi=>15tQ1_#E+Q2fLf-JLXA=Wv{XaJf zfR}+RgpNN&-xPjtkZjS{%SjOMY^&^-8>Ybf)eeVo`Pv>-%U|j-Vn9znq~3y)#CTdA zECPv;SMV%u8KW15C)z$*0Z!pxY=@>r?2*oGSvN%4L80r5bAaV|{L<0Xwk39X0hs`zz<+!8B>cPd+b`)DL%?DDn*}w)q7G z<$3Z{LvZs2$An^bji<`uIzB5;$FUcR)OP-|n$-L+o#)*zC>dA}Iog^f)Q*l8o|gEJ z78pG`=>Y)4+LKCxm4O08btn=2fu@DOFsv*`P zR_H{+^U1yyU%8MpaG>*_Z2MHv&h_YZwqZ?>58>+rRT_3m(}SceBe?ik^BB>&J0z7ya?~)i*Kb=Ftgo^R#_xvves38IrO$EsGJ6 zmYsBX-_YV*mAlUEZswnE!3}#XRjF|?MDw3HvhGz%Bfp5S0%?C_mc++)Ib>juVA&T1e5ho}aLNGYN; zr)*DP_B7K}L!_a8EhsD~w~xb;8uPe~iR;UjJ2z|q6{wW()eOoP>adm!4$CFD6DYTNsmVDiqQWA`}+?YINKm2K>)6+BhaNwW1zIE*#{zj&i0 z(Uo2349)0H{RjG(COBAJ?Jec0m4hlTzHCRaUNIUlQuUT)6*s` zyyEsQ%`=h2c{s+Ft;fsQPG0%hyGI$R2cm#uQ4k!vtVv6J>O_d0&fm#GlxK=3iUqu* zq#w(`%z7k16PB&~Clh1(6Ez;WU0dL0`lT*!y}0-a>!&%~>R&Bf;3Nk?>J+w9GZT$w zOxC(4po??9u-_%x{L92Q4bZw`5u@IZ57=v*QM3J(Vbx)1G$?Oi2(?7;3Zcg4b>q<_ ztGgagBjxb+Aey2EojZ^1n#@HTmyKl3blI$gf(S*L^I>DfjM@5g6>I(oPalyycQgfH z&k5|8JC;aCxyJ=*t7ysMDlc=Z*KVrxCN*MH5>K7pQvuECkbF5&ZqHmM40oi)*Rgz3 z;!W+3w0v;`4--K;|4Qn8b6%~>^4&c~`YrK`$1IRSn5^!_6 z0Gl~c*aO>^C{~@}K)UH^8w(CRHGwUNgc!@f?}NV!wJ<^fhw+bMZEpn}?DHidn1X>? zq6FQh9;vtSo!+ZBmMXrUU_WwD)3Nkxt{|qy>W_3GV23G_S}vH_3dSvy}X>vG}0c1v_es2j=iwVBeJ{ZsX8lq+q`Cg@>1x zr5YkI-Z5xrBuZ7N`U0Lmw|RDSm@^ffv#zHg@^I=r=a|IkeV4WRFtd%QVQiDA$)Mpm z529!@_t82faZruN8&dFn?F zs1eVbO4|BsttK9VHa%LVmYXU26AVjLj!_zYdfvkP&-LxW2b+6zeCtnUj z5!z?udp;mP!G8cy+XPqvvnN;&5dey}gZaK{j250~0uPLD)dB$+Tj7b!*1=!xq%IHu z!yU%X_e8k}zo|4W`1LO86T$qCy z_yDs$@casd91dn_Z(GKHEUWpGFZ7}PtN5^9+<@3xV0x`Hj?XwQOb;Uvfp?dKR!-zS zq1c;pB3K6u00XB3&sWKYNQDes!5(keBNRX+T6n+d7n?UpbfX6mFrTkJn{UQMN^!!Q zRrs2*=%c_i_Ee~J&?^YuCaBgrmCC@P)p|_Wg!h&>OfbGsmH4ZFHH_7`28AK8HQ9qU zJdh7MDE_#~4>Rf?wD?&FOo0W{CJbT(){H5>tQFTLQo^Ia!UdmdI?gi~U0iiW$N*-< zlFx>DDA?1-gs}D1sy|4f$c%Gt0wxR_7$IrugR>l}VDlbNwjK_q?=vB{67%o?)a5%0Hg)&G+I95MVE&FK9ua^<|y zplQk8Y}f@eOd>I0QUG;AmB^o$_!wp>J8&9iX>SFZvmi38Gs;+tQOc&`FyjzxVhzBk zrRE}7Lq5D_YDuuZ&4a@IjCdk*5@nJ6uvO`>_IiM7iW~Gk+VuA~aD4xd;E?a}_x=Ah z;g`fVrWrqJc+8%C!z63?`QQP=e#UbEg~DF9(mFpP;@=C9s287PP_+}z1@*Lp5@rHo zlnL1;NAEe?C$}UUs^1S-$#SSdOBBA&c}XAx$yVoe43I zW|YzXh)wYR?eg5(_pj1yB^jK#Ff0)4l^EV@51PXOJBWkG(f*Yyfuz7jB3)Rjc=uoO zwnZ01Jcx1sDEoedCmEM9TEXc6ixxJBQ_6_~_oOi)@3Ap*NB-GiiO-q#e z-dhc48_^eRNqhOwyUDxX{B~6d47QjOK&6EBD%ArshmNCZPRwlIGpO@qp4v2F!Ir|I zgO#g-$uak-AelZUOeYdXegSrM=odZ2|F91RqW{Qc7zo2w<)2Hip5Rp_pfTeM#Mvd5 zjMeYM`U|Q4XZJDV@|=_!W${@)?UtIU7Gnh1c`Zs$5DInc2qMw~`MWFVVHmMt0*VB&8xJoTvzVK>{@s z#}Gn@K2^mmr+gMGUvnV;fc43n@d&L)M+GR;4=69cc48T8b15T)hKJ=ttfXE7uAPCg z2Kp0VB6JN!v2T2pLM3u50#lV=DN@S{UlH0)8&_?A^s|-q9Tlt$i|=GSXV05zT*BA3Z=^MU7>2s zSBY~h<`~8+RUM7F_fHW+cAo9~9+kbe_x|sDE)J1_Dz!w-?Z(B0yTU_mENms6 zVaDsL>|0B#qn1XEs!Q2ZHW4;Hzb1>U`BE2-5$6<(kUxdM6j@lI@4h`c|1Ly9g%$U} zD%090H{|npaQda`Et{p8qbD>}L#uJX`2p|-Nu`Q%U-hh=92Nx*z|m-=YD+9cftj*q zoQcxEZqNTlZ}#+-4}CnAM|gRlU^)lV6+*x=PumZ@{2&x`(>@-%uW+Urc@}$4@*(Bd zLn}-Q0mxARbuEuF6wA;2C(SiNFLZF$0%5~t8B@B)ni~VLGL5RWOK7CFkip2165bT? zPo?0~e~^jatNPE4?q~OvOBcvR% zKli@BQ{n$4CchKoU)RC^ydC~`p8Vc%{#h^lcUAD86_4M5`Hwqg7!>?rIR8IE|4}RX zr?CGfHUEqD{CBqg$>x9f{X3ig+-Cm^iT?cdPjmmB>Hl+a|8u|o8K6L%dB;+?qtuDWG~2h>Cj6IC50bKtA6VRuT6SiDorz6X<%4bPjKn`;git= zLt}WbI;;c>+lm*EE6wV2UfGwH&XQSR` z{O0|ZY&3JPQ8|+11455Z-P7%uhVH?IwUhUKBio(8-Sv)J3jshBODQPSW~_IPJ-Cr4 z#NF{_^6BCBokFc>d6-=BOitRZJiRV6>e<6dIHYBJy2uH*);e@G{S+!k@iFmGn~`6_ zw@xZzEDLqZ7ps(@+W&dPF1MC#?W+olY~rVVJ!2MUg1~d9mAWlW(}+*U#jn@zbg?lm z{N2kO9{4?ZPH>2y{FqY&55GUV6+3NTdulduF6${V`4js`8?n6@_;>hv-T{FwlyBMCbq-jJ%0E1*|+ie?TZVJ zOp(-yaBbEXZD7-otXi+t!){PXf{m9q|5v10J9pZ z)CM1AjflFFvkf#}a^yjW9=;@>q+#Zkm0oP$ChIUHZEgGw33xC@p3a@IscJo|e(j>l zb0O2s7&p-3KM;ZE;^*ijiMy1YaasLM48_)(RJ};Fx$VNgBs+E%qOw0A3`|g{2539s zwiYF4DKtu`)H;X)$P2U%TRLvnL@iMK^9~sUW`%wkv~o)npV^|G6-_H=*`kU={RSeP z)I?9`+W0!+WA{de_O6k-j~v$D6w%>n)M%|C0;5!F?Z}yH7TP^kB0~)pzn&njd?ATD z6Eyr1OrK@n*@|B)C6VCdx>v7{B(E#X?C57&X*QiV)#;qSH`YWL@o4vkHqJC-{PgKN zx7U`VC}_5L_<9>;U6T~h-O#{G*(92CLqn4_J$ui?MgHuT8+JWp&z7TC-?;awTpSQJ|#|` zS6{QVcYO48=bE&x-069$swMLLR@n=(@4I)Z@7I@C1N<91?Vx|4(}y#l%Y-xFId!1r zwv>Iav&Jymm)fx0u#H6A(BP0A810F;IO}^GJ+-uO?0N$Ucx;tDD-{#HEn}s6Nnq^o zxt?{seJ8fr$x5`}Zw_^Gt}%%A)dCE5I%-Fk20~3lo}dF>(2Epkag_7frCMOGNeB67 z#WzUHzfn@#3pguJJ^9WlJvT<|gn}Kpbj!Z@!05ZC&jtMy-;ox!fe5R`f%+A>tFqzd zQ^a}RVP>GQ-W@KF1zN6eO0lx2m4~$qhk*ZntCrv`a_cLgeD8N#0<8IqqIs4n*(sY#pvgwetcUpEo6gvE((Z+;pzj-#XJJCA!Qh%OD*+&|3J zfllr$JD7-{HQa^Tm$rNOXl6Cr(LcTC({(1q(Zc`@`>X~e4}}|N#Uz37lkBVBC3ppV z6iu$zqz@$NWUs7iGEw?_DiuH;vXHViRLYEoQS)NUFm~he&<7DB-VJOi4aKFhl}n^g z7_iJLH(W6H?(l;k$~`D)6m-z0C30oxFL4Rq3vRnrfpfT!&uSm{eDfI_DsX|7IW#sYhOxze*?n zODwvuZ5c{I1V%YS6wnYLcS@%*;4U}26x)@oF^ucEaZPMJ9z{pcR`G4oo$FKKH%n#3 z0Q-?B%oKNYwRwlB#MK7D`sf6&lf%kRxvvU0qYc`UiDhOeqg$k)M#=2QgF_ifvN~yt zqLYMgC$kpz9lZAbZ?(}ayYcB~Q^0cAv%YW7z7hyZ(bw;EQqvAj8T*2KJejbDl6LIL zd)lyIP<+!6vpRX|58VwX%+81-S^HHvvLn?vdMfM0lQrB4=GFX^)2TTWbunoHmZ& zn-#t)xqFH9Vr*yE-ow_AS&>3Bw$;Cl5*}sp!rj}Jf7Qtyq3DiRPa_vwWcA?@boldv ze%g9=R{uCu#GTS@!hmQGpgTyaXM){#M#jdBIkP-1MW;m!7DVK3G3RrC4C{8d&&qs8 zH4UXY70Tght+kJxV$sBrU7s&{=2FDE68=8iMg;tNL%jdt#bUo*5#v3y@ODJ8!GF=S z2_?W^em~9`FQnrc>*f9komrM@`{GBc-CP~wZQTjTWZ(mJt4E)Qc(ol3TdSg-8fQD~ zpFzLqM>>7X_XcNNfDH7-G#IBsijj07Fxz?FeJvvM^@A|5NtmrE5qD2I+DUt2)bpjr z>L{I=)n6zoL~S4f7vL)!DA<$St2#96@)v6EF9+v|(DU_uY3b7FBPO}6Fse?6@7MRL z4Y0oO-KxndkCI+4I+q7Du>*DV8H1^TE z!&cS}q;%!=Xr;z2>Q8tASR*)BhHgX`J}RnRxHk~i8jqNr+c~;-xH9hEfb5+&dQ;DJ zj1G8B@Y0`!HR?C@`oD=^)BMq?HtLYi|{6NVXm z2IPf^wvY`a4Z2T$0{knuo6P9$bM8^yX${X9+By@V5Fx=BU?4v5e4+Bq0`4(0lFRGf)AuwBICp7`@wOu`#71z* YuY;XbV-|^EfBl7%l~R(dmM{wbUw`rJHUIzs literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/basic/img/btn_close.gif b/theme/basic/skin/board/basic/img/btn_close.gif new file mode 100644 index 0000000000000000000000000000000000000000..040b180ac6584ae612ef2886487110f0ad079963 GIT binary patch literal 211 zcmZ?wbhEHbC>lw|Nj2|^XJd+Ki|K7yLIc<@85r}UAy+@_wT|Ns9P2m!^PEMO%%AQEIJ18abSL2rs@7wgh> zI-xzeYYr882T$7a>~-(!J@=MOy}Z$ltNl`73Cq0Bi3wIGB-b=ECVhGFY*&ANIg94( d^Unm859R4|2rw-)wA%9i`(c-qSMQw}tN}eeW+eas literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/basic/img/icon_file.gif b/theme/basic/skin/board/basic/img/icon_file.gif new file mode 100644 index 0000000000000000000000000000000000000000..cca47f566ac0db655fb2ab0f56628b64958e48b2 GIT binary patch literal 107 zcmZ?wbhEHb-Wqsc#^P~2x#@rVooH@5wHB9i@BozKb;P9uI^*c|UyXO5@>VyLmgEat< Cr6(f* literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/basic/img/icon_hot.gif b/theme/basic/skin/board/basic/img/icon_hot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c95b839aeef0c1e26a4bab4ea50cd6d3f1969d7f GIT binary patch literal 97 zcmZ?wbhEHbzHen|7VvwFnzUPlarEA ZqW~YXyUO~T+#YkUoJ%V_>ib05Q5F AasU7T literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/basic/img/icon_mobile.gif b/theme/basic/skin/board/basic/img/icon_mobile.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad934d23c440c83db0c4589596465cb087353e01 GIT binary patch literal 62 zcmZ?wbhEHbZ% literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/basic/img/icon_reply.gif b/theme/basic/skin/board/basic/img/icon_reply.gif new file mode 100644 index 0000000000000000000000000000000000000000..91c135977b4f445a90c849310dc80efde1983830 GIT binary patch literal 77 zcmZ?wbhEHb&!1E4^4&ClEzh)PmWxV3{9A~!gB2-%RL5bHcgg3Zp^!+W)H2^A_AxQuL literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/basic/img/icon_sound.gif b/theme/basic/skin/board/basic/img/icon_sound.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5188318a5cdc394b984125c0ddd376c5f57bbe4 GIT binary patch literal 113 zcmZ?wbhEHbE1CJY$zMikVi`-#gIi|DbmsXBWf6U5szE@->A`0*`&<;b@XASRrB8=E6~=S>Pbm I%fes{0AXt-SpWb4 literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/basic/list.skin.php b/theme/basic/skin/board/basic/list.skin.php new file mode 100644 index 000000000..d995a8555 --- /dev/null +++ b/theme/basic/skin/board/basic/list.skin.php @@ -0,0 +1,255 @@ +', 0); +?> + +

    목록

    + + +
    + + + + + + + + +
    +
    + Total + 페이지 +
    + + + + +
    + + +
    + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + "> + + + + + + + + + + + + + '; } ?> + +
    목록
    번호 + + + 제목글쓴이날짜조회추천비추천
    + 공지'; + else if ($wr_id == $list[$i]['wr_id']) + echo "열람중"; + else + echo $list[$i]['num']; + ?> + + + + + + + + + + + 댓글 + + + '; } + + if (isset($list[$i]['icon_new'])) echo $list[$i]['icon_new']; + if (isset($list[$i]['icon_hot'])) echo $list[$i]['icon_hot']; + if (isset($list[$i]['icon_file'])) echo $list[$i]['icon_file']; + if (isset($list[$i]['icon_link'])) echo $list[$i]['icon_link']; + if (isset($list[$i]['icon_secret'])) echo $list[$i]['icon_secret']; + + ?> +
    게시물이 없습니다.
    +
    + + +
    + +
      +
    • +
    • +
    • +
    + + + + + +
    + +
    +
    + + + + + + + + + +
    + 게시물 검색 + +
    + + + + + + + + +
    +
    + + + + + + diff --git a/theme/basic/skin/board/basic/style.css b/theme/basic/skin/board/basic/style.css new file mode 100644 index 000000000..8d63d833f --- /dev/null +++ b/theme/basic/skin/board/basic/style.css @@ -0,0 +1,256 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +/* 게시판 버튼 */ +/* 목록 버튼 */ +#bo_list a.btn_b01 {} +#bo_list a.btn_b01:focus, #bo_list a.btn_b01:hover {} +#bo_list a.btn_b02 {} +#bo_list a.btn_b02:focus, #bo_list a.btn_b02:hover {} +#bo_list a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_list a.btn_admin:focus, #bo_list .btn_admin:hover {} + +/* 읽기 버튼 */ +#bo_v a.btn_b01 {} +#bo_v a.btn_b01:focus, #bo_v a.btn_b01:hover {} +#bo_v a.btn_b02 {} +#bo_v a.btn_b02:focus, #bo_v a.btn_b02:hover {} +#bo_v a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_v a.btn_admin:focus, #bo_v a.btn_admin:hover {} + +/* 쓰기 버튼 */ +#bo_w .btn_confirm {} /* 서식단계 진행 */ +#bo_w .btn_submit {} +#bo_w button.btn_submit {} +#bo_w fieldset .btn_submit {} +#bo_w .btn_cancel {} +#bo_w button.btn_cancel {} +#bo_w .btn_cancel:focus, #bo_w .btn_cancel:hover {} +#bo_w a.btn_frmline, #bo_w button.btn_frmline {} /* 우편번호검색버튼 등 */ +#bo_w button.btn_frmline {} + +/* 기본 테이블 */ +/* 목록 테이블 */ +#bo_list .tbl_head01 {} +#bo_list .tbl_head01 caption {} +#bo_list .tbl_head01 thead th {} +#bo_list .tbl_head01 thead a {} +#bo_list .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_list .tbl_head01 tfoot th {} +#bo_list .tbl_head01 tfoot td {} +#bo_list .tbl_head01 tbody th {} +#bo_list .tbl_head01 td {} +#bo_list .tbl_head01 a {} +#bo_list td.empty_table {} + +/* 읽기 내 테이블 */ +#bo_v .tbl_head01 {} +#bo_v .tbl_head01 caption {} +#bo_v .tbl_head01 thead th {} +#bo_v .tbl_head01 thead a {} +#bo_v .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_v .tbl_head01 tfoot th {} +#bo_v .tbl_head01 tfoot td {} +#bo_v .tbl_head01 tbody th {} +#bo_v .tbl_head01 td {} +#bo_v .tbl_head01 a {} +#bo_v td.empty_table {} + +/* 쓰기 테이블 */ +#bo_w table {} +#bo_w caption {} +#bo_w .frm_info {} +#bo_w .frm_address {} +#bo_w .frm_file {} + +#bo_w .tbl_frm01 {} +#bo_w .tbl_frm01 th {} +#bo_w .tbl_frm01 td {} +#bo_w .tbl_frm01 textarea, #bo_w tbl_frm01 .frm_input {} +#bo_w .tbl_frm01 textarea {} +/* +#bo_w .tbl_frm01 #captcha {} +#bo_w .tbl_frm01 #captcha input {} +*/ +#bo_w .tbl_frm01 a {} + +/* 필수입력 */ +#bo_w .required, #bo_w textarea.required {} + +#bo_w .cke_sc {} +#bo_w button.btn_cke_sc{} +#bo_w .cke_sc_def {} +#bo_w .cke_sc_def dl {} +#bo_w .cke_sc_def dl:after {} +#bo_w .cke_sc_def dt, #bo_w .cke_sc_def dd {} +#bo_w .cke_sc_def dt {} +#bo_w .cke_sc_def dd {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 게시판 목록 */ +#bo_list .td_board {width:120px;text-align:center} +#bo_list .td_chk {width:30px;text-align:center} +#bo_list .td_date {width:60px;text-align:center} +#bo_list .td_datetime {width:110px;text-align:center} +#bo_list .td_group {width:100px;text-align:center} +#bo_list .td_mb_id {width:100px;text-align:center} +#bo_list .td_mng {width:80px;text-align:center} +#bo_list .td_name {width:100px;text-align:left} +#bo_list .td_nick {width:100px;text-align:center} +#bo_list .td_num {width:50px;text-align:center} +#bo_list .td_numbig {width:80px;text-align:center} + +#bo_list .txt_active {color:#5d910b} +#bo_list .txt_expired {color:#ccc} + +#bo_cate h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_cate ul {margin-bottom:10px;padding-left:1px;zoom:1} +#bo_cate ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_cate li {float:left;margin-bottom:-1px} +#bo_cate a {display:block;position:relative;margin-left:-1px;padding:6px 0 5px;width:90px;border:1px solid #ddd;background:#f7f7f7;color:#888;text-align:center;letter-spacing:-0.1em;line-height:1.2em;cursor:pointer} +#bo_cate a:focus, #bo_cate a:hover, #bo_cate a:active {text-decoration:none} +#bo_cate #bo_cate_on {z-index:2;border:1px solid #565e60;background:#fff;color:#565e60;font-weight:bold} + +.td_subject img {margin-left:3px} + +/* 게시판 목록 공통 */ +.bo_fx {margin-bottom:5px;zoom:1} +.bo_fx:after {display:block;visibility:hidden;clear:both;content:""} +.bo_fx ul {margin:0;padding:0;list-style:none} +#bo_list_total {float:left;padding-top:5px} +.btn_bo_user {float:right;margin:0;padding:0;list-style:none} +.btn_bo_user li {float:left;margin-left:5px} +.btn_bo_adm {float:left} +.btn_bo_adm li {float:left;margin-right:5px} +.btn_bo_adm input {padding:8px;border:0;background:#e8180c;color:#fff;text-decoration:none;vertical-align:middle} +.bo_notice td {background:#f5f6fa} +.bo_notice td a {font-weight:bold} +.td_num strong {color:#000} +.bo_cate_link {display:inline-block;margin:0 3px 0 0;padding:0 6px 0 0;border-right:1px solid #e7f1ed;color:#999 !important;font-weight:bold;text-decoration:none} /* 글제목줄 분류스타일 */ +.bo_current {color:#e8180c} +#bo_list .cnt_cmt {display:inline-block;margin:0 0 0 3px;font-weight:bold} + +#bo_sch {margin-bottom:10px;padding-top:5px;text-align:center} +#bo_sch legend {position:absolute;margin:0;padding:0;font-size:0;line-height:0;text-indent:-9999em;overflow:hidden} + +/* 게시판 쓰기 */ +#char_count_desc {display:block;margin:0 0 5px;padding:0} +#char_count_wrap {margin:5px 0 0;text-align:right} +#char_count {font-weight:bold} + +#autosave_wrapper {position:relative} +#autosave_pop {display:none;z-index:10;position:absolute;top:24px;right:117px;padding:8px;width:350px;height:auto !important;height:180px;max-height:180px;border:1px solid #565656;background:#fff;overflow-y:scroll} +html.no-overflowscrolling #autosave_pop {height:auto;max-height:10000px !important} /* overflow 미지원 기기 대응 */ +#autosave_pop strong {position:absolute;font-size:0;line-height:0;overflow:hidden} +#autosave_pop div {text-align:right} +#autosave_pop button {margin:0;padding:0;border:0;background:transparent} +#autosave_pop ul {margin:10px 0;padding:0;border-top:1px solid #e9e9e9;list-style:none} +#autosave_pop li {padding:8px 5px;border-bottom:1px solid #e9e9e9;zoom:1} +#autosave_pop li:after {display:block;visibility:hidden;clear:both;content:""} +#autosave_pop a {display:block;float:left} +#autosave_pop span {display:block;float:right} +.autosave_close {cursor:pointer} +.autosave_content {display:none} + +/* 게시판 읽기 */ +#bo_v {margin-bottom:20px;padding-bottom:20px} + +#bo_v_table {position:absolute;top:0;right:16px;margin:0;padding:0 5px;height:25px;background:#ff3061;color:#fff;font-weight:bold;line-height:2.2em} + +#bo_v_title {padding:10px 0;font-size:1.2em} + +#bo_v_info {padding:0 0 10px;border-bottom:1px solid #ddd} +#bo_v_info h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_info strong {display:inline-block;margin:0 15px 0 5px;font-weight:normal} +#bo_v_info .sv_member, +#bo_v_info .sv_guest, +#bo_v_info .member, +#bo_v_info .guest {font-weight:bold} + +#bo_v_file {} +#bo_v_file h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_file ul {margin:0;padding:0;list-style:none} +#bo_v_file li {padding:0 10px;border-bottom:1px solid #eee;background:#f5f6fa} +#bo_v_file a {display:inline-block;padding:8px 0 7px;width:100%;color:#000;word-wrap:break-word} +#bo_v_file a:focus, #bo_v_file a:hover, #bo_v_file a:active {text-decoration:none} +#bo_v_file img {float:left;margin:0 10px 0 0} +.bo_v_file_cnt {display:inline-block;margin:0 0 3px 16px} + +#bo_v_link {} +#bo_v_link h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_link ul {margin:0;padding:0;list-style:none} +#bo_v_link li {padding:0 10px;border-bottom:1px solid #eee;background:#f5f6fa} +#bo_v_link a {display:inline-block;padding:8px 0 7px;width:100%;color:#000;word-wrap:break-word} +#bo_v_link a:focus, #bo_v_link a:hover, #bo_v_link a:active {text-decoration:none} +.bo_v_link_cnt {display:inline-block;margin:0 0 3px 16px} + +#bo_v_top {margin:0 0 10px;padding:10px 0;zoom:1} +#bo_v_top:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_top h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_top ul {margin:0;padding:0;list-style:none} + +#bo_v_bot {zoom:1} +#bo_v_bot:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_bot h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_bot ul {margin:0;padding:0;list-style:none} + +.bo_v_nb {float:left} +.bo_v_nb li {float:left;margin-right:5px} +.bo_v_com {float:right} +.bo_v_com li {float:left;margin-left:5px} + +#bo_v_atc {min-height:200px;height:auto !important;height:200px} +#bo_v_atc_title {position:absolute;font-size:0;line-height:0;overflow:hidden} + +#bo_v_img {margin:0 0 10px;width:100%;overflow:hidden;zoom:1} +#bo_v_img:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_img img {margin-bottom:20px;max-width:100%;height:auto} + +#bo_v_con {margin-bottom:30px;width:100%;line-height:1.7em;word-break:break-all;overflow:hidden} +#bo_v_con a {color:#000;text-decoration:underline} +#bo_v_con img {max-width:100%;height:auto} + +#bo_v_act {margin-bottom:30px;text-align:center} +#bo_v_act .bo_v_act_gng {position:relative} +#bo_v_act a {margin-right:5px;vertical-align:middle} +#bo_v_act strong {color:#ff3061} +#bo_v_act_good, #bo_v_act_nogood {display:none;position:absolute;top:30px;left:0;padding:10px 0;width:165px;background:#ff3061;color:#fff;text-align:center} + +#bo_v_sns {margin:0 0 20px;padding:0;list-style:none;zoom:1} +#bo_v_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_sns li {float:left;margin:0 5px 0 0} + +/* 게시판 댓글 */ +#bo_vc {margin:0 0 20px;padding:20px 20px 10px;border:1px solid #e5e8ec;background:#f5f8f9} +#bo_vc h2 {margin-bottom:10px} +#bo_vc article {padding:0 0 10px;border-top:1px dotted #ccc} +#bo_vc header {position:relative;padding:15px 0 5px} +#bo_vc header .icon_reply {position:absolute;top:15px;left:-20px} +#bo_vc .sv_wrap {margin-right:15px} +#bo_vc .member, #bo_vc .guest, #bo_vc .sv_member, #bo_vc .sv_guest {font-weight:bold} +.bo_vc_hdinfo {display:inline-block;margin:0 15px 0 5px} +#bo_vc h1 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_vc a {color:#000;text-decoration:none} +#bo_vc p {padding:0 0 5px;line-height:1.8em} +#bo_vc p a {text-decoration:underline} +#bo_vc p a.s_cmt {text-decoration:none} +#bo_vc_empty {margin:0;padding:20px !important;text-align:center} +#bo_vc #bo_vc_winfo {float:left} +#bo_vc footer {zoom:1} +#bo_vc footer:after {display:block;visibility:hidden;clear:both;content:""} + +.bo_vc_act {float:right;margin:0;list-style:none;zoom:1} +.bo_vc_act:after {display:block;visibility:hidden;clear:both;content:""} +.bo_vc_act li {float:left;margin-left:5px} + +#bo_vc_w {position:relative;margin:0 0 10px;padding:0 0 20px;border-bottom:1px solid #cfded8} +#bo_vc_w h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_vc_w #char_cnt {display:block;margin:0 0 5px} + +#bo_vc_sns {margin:0;padding:0;list-style:none;zoom:1} +#bo_vc_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_vc_sns li {float:left;margin:0 20px 0 0} +#bo_vc_sns input {margin:0 0 0 5px} \ No newline at end of file diff --git a/theme/basic/skin/board/basic/view.skin.php b/theme/basic/skin/board/basic/view.skin.php new file mode 100644 index 000000000..7f53d70d7 --- /dev/null +++ b/theme/basic/skin/board/basic/view.skin.php @@ -0,0 +1,283 @@ +', 0); +?> + + + + +
    + +
    +
    +

    + +

    +
    + +
    +

    페이지 정보

    + 작성자 + 작성일 + 조회 + 댓글 +
    + + + + + +
    +

    첨부파일

    + +
    + + + + + + + + + + +
    + + + + + + + +
    + + +
    +

    본문

    + + \n"; + + for ($i=0; $i<=count($view['file']); $i++) { + if ($view['file'][$i]['view']) { + //echo $view['file'][$i]['view']; + echo get_view_thumbnail($view['file'][$i]['view']); + } + } + + echo "\n"; + } + ?> + + +
    + + + +

    + + + +
    + 스크랩 + + + 추천 + + + + + + 비추천 + + + +
    + +
    + 추천 + 비추천 +
    + + +
    + + + + + + +
    + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/theme/basic/skin/board/basic/view_comment.skin.php b/theme/basic/skin/board/basic/view_comment.skin.php new file mode 100644 index 000000000..8c6deacbc --- /dev/null +++ b/theme/basic/skin/board/basic/view_comment.skin.php @@ -0,0 +1,330 @@ + + + + + +
    +

    댓글목록

    + \]/i", "", $comment); + $cmt_sv = $cmt_amt - $i + 1; // 댓글 헤더 z-index 재설정 ie8 이하 사이드뷰 겹침 문제 해결 + ?> + +
    style="margin-left:px;border-top-color:#e0e0e0"> +
    +

    님의 댓글

    + + 댓글의 댓글 + + 아이피 + + + 작성일 + + +
    + + +

    + 비밀글 + +

    + + + + + " id="secret_comment_"> + + + + + +
    + +

    등록된 댓글이 없습니다.

    + +
    + + + + + + + + + \ No newline at end of file diff --git a/theme/basic/skin/board/basic/write.skin.php b/theme/basic/skin/board/basic/write.skin.php new file mode 100644 index 000000000..f0e7e91e8 --- /dev/null +++ b/theme/basic/skin/board/basic/write.skin.php @@ -0,0 +1,268 @@ +', 0); +?> + +
    +

    + + +
    + + + + + + + + + + + + '."\n".''; + } + + if ($is_html) { + if ($is_dhtml_editor) { + $option_hidden .= ''; + } else { + $option .= "\n".''."\n".''; + } + } + + if ($is_secret) { + if ($is_admin || $is_secret==1) { + $option .= "\n".''."\n".''; + } else { + $option_hidden .= ''; + } + } + + if ($is_mail) { + $option .= "\n".''."\n".''; + } + } + + echo $option_hidden; + ?> + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    class="frm_input " maxlength="20">
    옵션
    + +
    +
    + + + + +
    + 임시 저장된 글 목록 +
    +
      +
      +
      + +
      +
      + + +

      이 게시판은 최소 글자 이상, 최대 글자 이하까지 글을 쓰실 수 있습니다.

      + + + + +
      글자
      + +
      " id="wr_link" class="frm_input" size="50">
      파일 # + + + + + + + +
      자동등록방지 + +
      +
      + +
      + + 취소 +
      +
      + + +
      + \ No newline at end of file diff --git a/theme/basic/skin/board/gallery/img/btn_close.gif b/theme/basic/skin/board/gallery/img/btn_close.gif new file mode 100644 index 0000000000000000000000000000000000000000..040b180ac6584ae612ef2886487110f0ad079963 GIT binary patch literal 211 zcmZ?wbhEHbC>lw|Nj2|^XJd+Ki|K7yLIc<@85r}UAy+@_wT|Ns9P2m!^PEMO%%AQEIJ18abSL2rs@7wgh> zI-xzeYYr882T$7a>~-(!J@=MOy}Z$ltNl`73Cq0Bi3wIGB-b=ECVhGFY*&ANIg94( d^Unm859R4|2rw-)wA%9i`(c-qSMQw}tN}eeW+eas literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/gallery/img/icon_file.gif b/theme/basic/skin/board/gallery/img/icon_file.gif new file mode 100644 index 0000000000000000000000000000000000000000..cca47f566ac0db655fb2ab0f56628b64958e48b2 GIT binary patch literal 107 zcmZ?wbhEHb-Wqsc#^P~2x#@rVooH@5wHB9i@BozKb;P9uI^*c|UyXO5@>VyLmgEat< Cr6(f* literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/gallery/img/icon_hot.gif b/theme/basic/skin/board/gallery/img/icon_hot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c95b839aeef0c1e26a4bab4ea50cd6d3f1969d7f GIT binary patch literal 97 zcmZ?wbhEHbzHen|7VvwFnzUPlarEA ZqW~YXyUO~T+#YkUoJ%V_>ib05Q5F AasU7T literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/gallery/img/icon_mobile.gif b/theme/basic/skin/board/gallery/img/icon_mobile.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad934d23c440c83db0c4589596465cb087353e01 GIT binary patch literal 62 zcmZ?wbhEHbZ% literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/gallery/img/icon_reply.gif b/theme/basic/skin/board/gallery/img/icon_reply.gif new file mode 100644 index 0000000000000000000000000000000000000000..91c135977b4f445a90c849310dc80efde1983830 GIT binary patch literal 77 zcmZ?wbhEHb&!1E4^4&ClEzh)PmWxV3{9A~!gB2-%RL5bHcgg3Zp^!+W)H2^A_AxQuL literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/gallery/img/icon_sound.gif b/theme/basic/skin/board/gallery/img/icon_sound.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5188318a5cdc394b984125c0ddd376c5f57bbe4 GIT binary patch literal 113 zcmZ?wbhEHbE1CJY$zMikVi`-#gIi|DbmsXBWf6U5szE@->A`0*`&<;b@XASRrB8=E6~=S>Pbm I%fes{0AXt-SpWb4 literal 0 HcmV?d00001 diff --git a/theme/basic/skin/board/gallery/list.skin.php b/theme/basic/skin/board/gallery/list.skin.php new file mode 100644 index 000000000..507fe6000 --- /dev/null +++ b/theme/basic/skin/board/gallery/list.skin.php @@ -0,0 +1,249 @@ +', 0); +?> + +

      목록

      + + +
      + + + + + +
      +
      + Total + 페이지 +
      + + + + +
      + +
      + + + + + + + + + + +
      + + +
      + + +
        + 0 && ($i % $bo_gallery_cols == 0)) + $style = 'clear:both;'; + else + $style = ''; + if ($i == 0) $k = 0; + $k += 1; + if ($k % $bo_gallery_cols == 0) $style .= "margin:0 !important;"; + ?> +
      • + + + + + + 열람중"; + else + echo $list[$i]['num']; + ?> + + +
      • + + 게시물이 없습니다."; } ?> +
      + + +
      + +
        +
      • +
      • +
      • +
      + + + + + +
      + +
      +
      + + + + + + + + + +
      + 게시물 검색 + +
      + + + + + + + + +
      +
      + + + + + + diff --git a/theme/basic/skin/board/gallery/style.css b/theme/basic/skin/board/gallery/style.css new file mode 100644 index 000000000..5701375da --- /dev/null +++ b/theme/basic/skin/board/gallery/style.css @@ -0,0 +1,249 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +/* 게시판 버튼 */ +/* 목록 버튼 */ +#bo_gall a.btn_b01 {} +#bo_gall a.btn_b01:focus, #bo_gall a.btn_b01:hover {} +#bo_gall a.btn_b02 {} +#bo_gall a.btn_b02:focus, #bo_gall a.btn_b02:hover {} +#bo_gall a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_gall a.btn_admin:focus, #bo_gall .btn_admin:hover {} + +/* 읽기 버튼 */ +#bo_v a.btn_b01 {} +#bo_v a.btn_b01:focus, #bo_v a.btn_b01:hover {} +#bo_v a.btn_b02 {} +#bo_v a.btn_b02:focus, #bo_v a.btn_b02:hover {} +#bo_v a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_v a.btn_admin:focus, #bo_v a.btn_admin:hover {} + +/* 쓰기 버튼 */ +#bo_w .btn_confirm {} /* 서식단계 진행 */ +#bo_w .btn_submit {} +#bo_w button.btn_submit {} +#bo_w fieldset .btn_submit {} +#bo_w .btn_cancel {} +#bo_w button.btn_cancel {} +#bo_w .btn_cancel:focus, #bo_w .btn_cancel:hover {} +#bo_w a.btn_frmline, #bo_w button.btn_frmline {} /* 우편번호검색버튼 등 */ +#bo_w button.btn_frmline {} + +/* 기본 테이블 */ +/* 읽기 내 테이블 */ +#bo_v .tbl_head01 {} +#bo_v .tbl_head01 caption {} +#bo_v .tbl_head01 thead th {} +#bo_v .tbl_head01 thead a {} +#bo_v .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_v .tbl_head01 tfoot th {} +#bo_v .tbl_head01 tfoot td {} +#bo_v .tbl_head01 tbody th {} +#bo_v .tbl_head01 td {} +#bo_v .tbl_head01 a {} +#bo_v td.empty_table {} + +/* 쓰기 테이블 */ +#bo_w table {} +#bo_w caption {} +#bo_w .frm_info {} +#bo_w .frm_address {} +#bo_w .frm_file {} + +#bo_w .tbl_frm01 {} +#bo_w .tbl_frm01 th {} +#bo_w .tbl_frm01 td {} +#bo_w .tbl_frm01 textarea, #bo_w tbl_frm01 .frm_input {} +#bo_w .tbl_frm01 textarea {} +/* +#bo_w .tbl_frm01 #captcha {} +#bo_w .tbl_frm01 #captcha input {} +*/ +#bo_w .tbl_frm01 a {} + +/* 필수입력 */ +#bo_w .required, #bo_w textarea.required {} + +#bo_w .cke_sc {} +#bo_w button.btn_cke_sc{} +#bo_w .cke_sc_def {} +#bo_w .cke_sc_def dl {} +#bo_w .cke_sc_def dl:after {} +#bo_w .cke_sc_def dt, #bo_w .cke_sc_def dd {} +#bo_w .cke_sc_def dt {} +#bo_w .cke_sc_def dd {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 게시판 목록 */ +#bo_cate h2 {width:1px;height:1px;font-size:0;line-height:0;overflow:hidden} +#bo_cate ul {margin-bottom:10px;padding-left:1px;zoom:1} +#bo_cate ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_cate li {float:left;margin-bottom:-1px} +#bo_cate a {display:block;position:relative;margin-left:-1px;padding:6px 0 5px;width:90px;border:1px solid #ddd;background:#f7f7f7;color:#888;text-align:center;letter-spacing:-0.1em;line-height:1.2em;cursor:pointer} +#bo_cate a:focus, #bo_cate a:hover, #bo_cate a:active {text-decoration:none} +#bo_cate #bo_cate_on {z-index:2;border:1px solid #565e60;background:#fff;color:#565e60;font-weight:bold} + +.td_subject img {margin-left:3px} + +/* 갤러리 목록 */ +#bo_gall h2 {margin:0;padding:0;width:1px;height:1px;font-size:0;line-height:0;overflow:hidden} +#bo_gall #gall_ul {margin:10px 0 0;padding:0;list-style:none;zoom:1} +#bo_gall #gall_ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_gall .gall_li {float:left;margin:0 10px 30px 0} + +#bo_gall .gall_con {margin:0;padding:0;list-style:none} +#bo_gall .gall_con li {margin:0 0 4px} +#bo_gall .gall_con .gall_subject {display:inline-block;width:50px} + +#bo_gall .gall_now .gall_text_href a {color:#ff3061} + +#bo_gall .gall_href a:link, #bo_gall .gall_href a:focus, #bo_gall .gall_href a:hover {text-decoration:none} +#bo_gall .gall_href strong, #bo_gall .gall_href span {display:inline-block;background:#f7f7f7;text-align:center;line-height:10em} + +#bo_gall .gall_text_href {margin:10px 0 !important} +#bo_gall .gall_text_href a {font-weight:bold} +#bo_gall .gall_text_href span {display:inline !important} +#bo_gall .gall_text_href img {margin:0 0 0 4px} + +/* 게시판 목록 공통 */ +.bo_fx {margin-bottom:5px;zoom:1} +.bo_fx:after {display:block;visibility:hidden;clear:both;content:""} +.bo_fx ul {margin:0;padding:0;list-style:none} +#bo_list_total {float:left;padding-top:5px} +.btn_bo_user {float:right;margin:0;padding:0;list-style:none} +.btn_bo_user li {float:left;margin-left:5px} +.btn_bo_adm {float:left} +.btn_bo_adm li {float:left;margin-right:5px} +.btn_bo_adm input {padding:7px;border:0;background:#e8180c;color:#fff;text-decoration:none;vertical-align:middle} +.bo_notice td {background:#f7f7f2} +.bo_notice td a {font-weight:bold} +.td_num strong {color:#000} +.bo_cate_link {display:inline-block;margin:0 3px 0 0;padding:0 6px 0 0;border-right:1px solid #e7f1ed;color:#999 !important;font-weight:bold;text-decoration:none} /* 글제목줄 분류스타일 */ +.bo_current {color:#e8180c} + +#bo_sch {margin-bottom:10px;padding-top:5px;text-align:center} +#bo_sch legend {position:absolute;margin:0;padding:0;font-size:0;line-height:0;text-indent:-9999em;overflow:hidden} + +#bo_gall li.empty_list {padding:85px 0;text-align:center} + +/* 게시판 쓰기 */ +#char_count_desc {display:block;margin:0 0 5px;padding:0} +#char_count_wrap {margin:5px 0 0;text-align:right} +#char_count {font-weight:bold} + +#autosave_wrapper {position:relative} +#autosave_pop {display:none;z-index:10;position:absolute;top:24px;right:117px;padding:8px;width:350px;height:auto !important;height:180px;max-height:180px;border:1px solid #565656;background:#fff;overflow-y:scroll} +html.no-overflowscrolling #autosave_pop {height:auto;max-height:10000px !important} /* overflow 미지원 기기 대응 */ +#autosave_pop strong {position:absolute;font-size:0;line-height:0;overflow:hidden} +#autosave_pop div {text-align:right} +#autosave_pop button {margin:0;padding:0;border:0;background:transparent} +#autosave_pop ul {margin:10px 0;padding:0;border-top:1px solid #e9e9e9;list-style:none} +#autosave_pop li {padding:8px 5px;border-bottom:1px solid #e9e9e9;zoom:1} +#autosave_pop li:after {display:block;visibility:hidden;clear:both;content:""} +#autosave_pop a {display:block;float:left} +#autosave_pop span {display:block;float:right} +.autosave_close {cursor:pointer} +.autosave_content {display:none} + +/* 게시판 읽기 */ +#bo_v {margin-bottom:20px;padding-bottom:20px} + +#bo_v_table {position:absolute;top:0;right:16px;margin:0;padding:0 5px;height:25px;background:#565e60;color:#fff;font-weight:bold;line-height:2.2em} + +#bo_v_title {padding:10px 0;font-size:1.2em} + +#bo_v_info {padding:0 0 10px;border-bottom:1px solid #ddd} +#bo_v_info h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_info strong {display:inline-block;margin:0 15px 0 5px;font-weight:normal} +#bo_v_info .sv_member, +#bo_v_info .sv_guest, +#bo_v_info .member, +#bo_v_info .guest {font-weight:bold} + +#bo_v_file {} +#bo_v_file h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_file ul {margin:0;padding:0;list-style:none} +#bo_v_file li {padding:0 10px;border-bottom:1px solid #eee;background:#f5f6fa} +#bo_v_file a {display:inline-block;padding:8px 0 7px;width:100%;color:#000;word-wrap:break-word} +#bo_v_file a:focus, #bo_v_file a:hover, #bo_v_file a:active {text-decoration:none} +#bo_v_file img {float:left;margin:0 10px 0 0} +.bo_v_file_cnt {display:inline-block;margin:0 0 3px 16px} + +#bo_v_link {} +#bo_v_link h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_link ul {margin:0;padding:0;list-style:none} +#bo_v_link li {padding:0 10px;border-bottom:1px solid #eee;background:#f5f6fa} +#bo_v_link a {display:inline-block;padding:8px 0 7px;width:100%;color:#000;word-wrap:break-word} +#bo_v_link a:focus, #bo_v_link a:hover, #bo_v_link a:active {text-decoration:none} +.bo_v_link_cnt {display:inline-block;margin:0 0 3px 16px} + +#bo_v_top {margin:0 0 10px;padding:10px 0;zoom:1} +#bo_v_top:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_top h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_top ul {margin:0;padding:0;list-style:none} + +#bo_v_bot {zoom:1} +#bo_v_bot:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_bot h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_bot ul {margin:0;padding:0;list-style:none} + +.bo_v_nb {float:left} +.bo_v_nb li {float:left;margin-right:5px} +.bo_v_com {float:right} +.bo_v_com li {float:left;margin-left:5px} + +#bo_v_atc {min-height:200px;height:auto !important;height:200px} +#bo_v_atc_title {position:absolute;font-size:0;line-height:0;overflow:hidden} + +#bo_v_img {margin:0 0 10px;width:100%;overflow:hidden;zoom:1} +#bo_v_img:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_img img {margin-bottom:20px;max-width:100%;height:auto} + +#bo_v_con {margin-bottom:30px;width:100%;line-height:1.7em;word-break:break-all;overflow:hidden} +#bo_v_con a {color:#000;text-decoration:underline} +#bo_v_con img {max-width:100%;height:auto} + +#bo_v_act {margin-bottom:30px;text-align:center} +#bo_v_act .bo_v_act_gng {position:relative} +#bo_v_act a {margin-right:5px;vertical-align:middle} +#bo_v_act strong {color:#ff3061} +#bo_v_act_good, #bo_v_act_nogood {display:none;position:absolute;top:30px;left:0;padding:10px 0;width:165px;background:#ff3061;color:#fff;text-align:center} + +#bo_v_sns {margin:0 0 20px;padding:0;list-style:none;zoom:1} +#bo_v_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_sns li {float:left;margin:0 5px 0 0} + +/* 게시판 댓글 */ +#bo_vc {margin:0 0 20px;padding:20px 20px 10px;border:1px solid #e5e8ec;background:#f5f8f9} +#bo_vc h2 {margin-bottom:10px} +#bo_vc article {padding:0 0 10px;border-top:1px dotted #ccc} +#bo_vc header {position:relative;padding:15px 0 5px} +#bo_vc header .icon_reply {position:absolute;top:15px;left:-20px} +#bo_vc .sv_wrap {margin-right:15px} +#bo_vc .member, #bo_vc .guest, #bo_vc .sv_member, #bo_vc .sv_guest {font-weight:bold} +.bo_vc_hdinfo {display:inline-block;margin:0 15px 0 5px} +#bo_vc h1 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_vc a {color:#000;text-decoration:none} +#bo_vc p {padding:0 0 5px;line-height:1.8em} +#bo_vc p a {text-decoration:underline} +#bo_vc p a.s_cmt {text-decoration:none} +#bo_vc_empty {margin:0;padding:20px !important;text-align:center} +#bo_vc #bo_vc_winfo {float:left} +#bo_vc footer {zoom:1} +#bo_vc footer:after {display:block;visibility:hidden;clear:both;content:""} + +.bo_vc_act {float:right;margin:0;list-style:none;zoom:1} +.bo_vc_act:after {display:block;visibility:hidden;clear:both;content:""} +.bo_vc_act li {float:left;margin-left:5px} + +#bo_vc_w {position:relative;margin:0 0 10px;padding:0 0 20px;border-bottom:1px solid #cfded8} +#bo_vc_w h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_vc_w #char_cnt {display:block;margin:0 0 5px} + +#bo_vc_sns {margin:0;padding:0;list-style:none;zoom:1} +#bo_vc_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_vc_sns li {float:left;margin:0 20px 0 0} +#bo_vc_sns input {margin:0 0 0 5px} \ No newline at end of file diff --git a/theme/basic/skin/board/gallery/view.skin.php b/theme/basic/skin/board/gallery/view.skin.php new file mode 100644 index 000000000..7f53d70d7 --- /dev/null +++ b/theme/basic/skin/board/gallery/view.skin.php @@ -0,0 +1,283 @@ +', 0); +?> + + + + +
      + +
      +
      +

      + +

      +
      + +
      +

      페이지 정보

      + 작성자 + 작성일 + 조회 + 댓글 +
      + + + + + +
      +

      첨부파일

      + +
      + + + + + + + + + + +
      + + + + + + + +
      + + +
      +

      본문

      + + \n"; + + for ($i=0; $i<=count($view['file']); $i++) { + if ($view['file'][$i]['view']) { + //echo $view['file'][$i]['view']; + echo get_view_thumbnail($view['file'][$i]['view']); + } + } + + echo "\n"; + } + ?> + + +
      + + + +

      + + + +
      + 스크랩 + + + 추천 + + + + + + 비추천 + + + +
      + +
      + 추천 + 비추천 +
      + + +
      + + + + + + +
      + +
      + + +
      + + + + + + \ No newline at end of file diff --git a/theme/basic/skin/board/gallery/view_comment.skin.php b/theme/basic/skin/board/gallery/view_comment.skin.php new file mode 100644 index 000000000..ea87902ed --- /dev/null +++ b/theme/basic/skin/board/gallery/view_comment.skin.php @@ -0,0 +1,330 @@ + + + + + +
      +

      댓글목록

      + \]/i", "", $comment); + $cmt_sv = $cmt_amt - $i + 1; // 댓글 헤더 z-index 재설정 ie8 이하 사이드뷰 겹침 문제 해결 + ?> + +
      style="margin-left:px;border-top-color:#e0e0e0"> +
      +

      님의 댓글

      + + 댓글의 댓글 + + 아이피 + + + 작성일 + + +
      + + +

      + 비밀글 + +

      + + + + + " id="secret_comment_"> + + + + + +
      + +

      등록된 댓글이 없습니다.

      + +
      + + + + + + + + + \ No newline at end of file diff --git a/theme/basic/skin/board/gallery/write.skin.php b/theme/basic/skin/board/gallery/write.skin.php new file mode 100644 index 000000000..898489957 --- /dev/null +++ b/theme/basic/skin/board/gallery/write.skin.php @@ -0,0 +1,268 @@ +', 0); +?> + +
      +

      + + +
      + + + + + + + + + + + + '."\n".''; + } + + if ($is_html) { + if ($is_dhtml_editor) { + $option_hidden .= ''; + } else { + $option .= "\n".''."\n".''; + } + } + + if ($is_secret) { + if ($is_admin || $is_secret==1) { + $option .= "\n".''."\n".''; + } else { + $option_hidden .= ''; + } + } + + if ($is_mail) { + $option .= "\n".''."\n".''; + } + } + + echo $option_hidden; + ?> + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      class="frm_input " maxlength="20">
      옵션
      + +
      +
      + + + + +
      + 임시 저장된 글 목록 +
      +
        +
        +
        + +
        +
        + + +

        이 게시판은 최소 글자 이상, 최대 글자 이하까지 글을 쓰실 수 있습니다.

        + + + + +
        글자
        + +
        " id="wr_link" class="frm_input" size="50">
        파일 # + + + + + + + +
        자동등록방지 + +
        +
        + +
        + + 취소 +
        +
        + + +
        + \ No newline at end of file diff --git a/theme/basic/skin/connect/basic/connect.skin.php b/theme/basic/skin/connect/basic/connect.skin.php new file mode 100644 index 000000000..55849443c --- /dev/null +++ b/theme/basic/skin/connect/basic/connect.skin.php @@ -0,0 +1,9 @@ +', 0); +?> + + diff --git a/theme/basic/skin/connect/basic/current_connect.skin.php b/theme/basic/skin/connect/basic/current_connect.skin.php new file mode 100644 index 000000000..27397f5ac --- /dev/null +++ b/theme/basic/skin/connect/basic/current_connect.skin.php @@ -0,0 +1,41 @@ +', 0); +?> + + +
        + + + + + + + + + + ".$location.""; + else $display_location = $location; + ?> + + + + + + "; + ?> + +
        번호이름위치
        현재 접속자가 없습니다.
        +
        + \ No newline at end of file diff --git a/theme/basic/skin/connect/basic/style.css b/theme/basic/skin/connect/basic/style.css new file mode 100644 index 000000000..55cfd4ea2 --- /dev/null +++ b/theme/basic/skin/connect/basic/style.css @@ -0,0 +1 @@ +@charset "utf-8"; \ No newline at end of file diff --git a/theme/basic/skin/content/basic/content.skin.php b/theme/basic/skin/content/basic/content.skin.php new file mode 100644 index 000000000..5fd7fcecd --- /dev/null +++ b/theme/basic/skin/content/basic/content.skin.php @@ -0,0 +1,17 @@ +', 0); +?> + +
        +
        +

        +
        + +
        + +
        + +
        \ No newline at end of file diff --git a/theme/basic/skin/content/basic/style.css b/theme/basic/skin/content/basic/style.css new file mode 100644 index 000000000..8c69c58c6 --- /dev/null +++ b/theme/basic/skin/content/basic/style.css @@ -0,0 +1,8 @@ +@charset "utf-8"; + +/* 내용관리 */ +#ctt {margin:10px 0;padding:10px;border:1px solid #e9e9e9} +.ctt_admin {text-align:right} +#ctt header h1 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#ctt_con {padding:10px 0} +.ctt_img {text-align:center} \ No newline at end of file diff --git a/theme/basic/skin/faq/basic/list.skin.php b/theme/basic/skin/faq/basic/list.skin.php new file mode 100644 index 000000000..86def35fd --- /dev/null +++ b/theme/basic/skin/faq/basic/list.skin.php @@ -0,0 +1,136 @@ +', 0); + +if ($admin_href) + echo ''; +?> + + +'; + +// 상단 HTML +echo '
        '.conv_content($fm['fm_head_html'], 1).'
        '; +?> + + + + + +
        + +
        +

        목록

        +
          + $v){ + if(empty($v)) + continue; + ?> +
        1. +

          +
          + +
          +
          +
        2. + +
        +
        + 검색된 게시물이 없습니다.

        '; + } else { + echo '
        등록된 FAQ가 없습니다.'; + if($is_admin) + echo '
        FAQ를 새로 등록하시려면 FAQ관리 메뉴를 이용하십시오.'; + echo '
        '; + } + } + ?> +
        + + + +'.conv_content($fm['fm_tail_html'], 1).''; + +if ($timg_src) + echo '
        '; +?> + +
        + FAQ 검색 + +
        + + + + +
        +
        + + +FAQ 수정'; +?> + + + \ No newline at end of file diff --git a/theme/basic/skin/faq/basic/style.css b/theme/basic/skin/faq/basic/style.css new file mode 100644 index 000000000..35168de92 --- /dev/null +++ b/theme/basic/skin/faq/basic/style.css @@ -0,0 +1,23 @@ +@charset "utf-8"; + +#bo_cate h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_cate ul {margin-bottom:10px;padding-left:1px;zoom:1} +#bo_cate ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_cate li {float:left;margin-bottom:-1px} +#bo_cate a {display:block;position:relative;margin-left:-1px;padding:6px 0 5px;width:90px;border:1px solid #ddd;background:#f7f7f7;color:#888;text-align:center;letter-spacing:-0.1em;line-height:1.2em;cursor:pointer} +#bo_cate a:focus, #bo_cate a:hover, #bo_cate a:active {text-decoration:none} +#bo_cate #bo_cate_on {z-index:2;border:1px solid #565e60;background:#fff;color:#565e60;font-weight:bold} + +#faq_wrap {margin:10px 0 30px} +#faq_wrap h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +.faq_admin {text-align:right} +#faq_wrap ol {margin:0;padding:0;list-style:none} +#faq_con {border:1px solid #e9e9e9;border-top:0} +#faq_con h3 a {display:block;padding:10px;border-top:1px solid #e9e9e9;background:#f2f5f9;text-decoration:none} +#faq_con .con_inner {display:none;padding:10px;line-height:1.8em} +#faq_con .con_closer {margin:10px 0 0;text-align:right} +#faq_con .closer_btn {margin:0;padding:0;border:0;background:transparent} +.faq_tolist {padding:0 10px;text-align:right} +.faq_img {text-align:center} + +#faq_sch {text-align:center} \ No newline at end of file diff --git a/theme/basic/skin/latest/basic/img/icon_file.gif b/theme/basic/skin/latest/basic/img/icon_file.gif new file mode 100644 index 0000000000000000000000000000000000000000..cca47f566ac0db655fb2ab0f56628b64958e48b2 GIT binary patch literal 107 zcmZ?wbhEHb-Wqsc#^P~2x#@rVooH@5wHB9i@BozKb;P9uI^*c|UyXO5@>VyLmgEat< Cr6(f* literal 0 HcmV?d00001 diff --git a/theme/basic/skin/latest/basic/img/icon_hot.gif b/theme/basic/skin/latest/basic/img/icon_hot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c95b839aeef0c1e26a4bab4ea50cd6d3f1969d7f GIT binary patch literal 97 zcmZ?wbhEHbzHen|7VvwFnzUPlarEA ZqW~YXyUO~T+#YkUoJ%V_>ib05Q5F AasU7T literal 0 HcmV?d00001 diff --git a/theme/basic/skin/latest/basic/img/icon_mobile.gif b/theme/basic/skin/latest/basic/img/icon_mobile.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad934d23c440c83db0c4589596465cb087353e01 GIT binary patch literal 62 zcmZ?wbhEHbI6zOJt}3$`6RT1g06226*Z@+ongb7@ XU=fBkjtXNz0xpR_!)cQgkRbp&KI&WI literal 0 HcmV?d00001 diff --git a/theme/basic/skin/latest/basic/img/icon_movie.gif b/theme/basic/skin/latest/basic/img/icon_movie.gif new file mode 100644 index 0000000000000000000000000000000000000000..cb958f83f9c606f290a260714cd9a3cff043f3a2 GIT binary patch literal 110 zcmZ?wbhEHbZ% literal 0 HcmV?d00001 diff --git a/theme/basic/skin/latest/basic/img/icon_reply.gif b/theme/basic/skin/latest/basic/img/icon_reply.gif new file mode 100644 index 0000000000000000000000000000000000000000..91c135977b4f445a90c849310dc80efde1983830 GIT binary patch literal 77 zcmZ?wbhEHb&!1E4^4&ClEzh)PmWxV3{9A~!gB2-%RL5bHcgg3Zp^!+W)H2^A_AxQuL literal 0 HcmV?d00001 diff --git a/theme/basic/skin/latest/basic/img/icon_sound.gif b/theme/basic/skin/latest/basic/img/icon_sound.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5188318a5cdc394b984125c0ddd376c5f57bbe4 GIT binary patch literal 113 zcmZ?wbhEHbE1CJY$zMikVi`-#gIi|DbmsXBWf6U5szE@->A`0*`&<;b@XASRrB8=E6~=S>Pbm I%fes{0AXt-SpWb4 literal 0 HcmV?d00001 diff --git a/theme/basic/skin/latest/basic/latest.skin.php b/theme/basic/skin/latest/basic/latest.skin.php new file mode 100644 index 000000000..989a3ee40 --- /dev/null +++ b/theme/basic/skin/latest/basic/latest.skin.php @@ -0,0 +1,44 @@ +', 0); +?> + + +
        + +
          + +
        • + "; + if ($list[$i]['is_notice']) + echo "".$list[$i]['subject'].""; + else + echo $list[$i]['subject']; + + if ($list[$i]['comment_cnt']) + echo $list[$i]['comment_cnt']; + + echo ""; + + // if ($list[$i]['link']['count']) { echo "[{$list[$i]['link']['count']}]"; } + // if ($list[$i]['file']['count']) { echo "<{$list[$i]['file']['count']}>"; } + + if (isset($list[$i]['icon_new'])) echo " " . $list[$i]['icon_new']; + if (isset($list[$i]['icon_hot'])) echo " " . $list[$i]['icon_hot']; + if (isset($list[$i]['icon_file'])) echo " " . $list[$i]['icon_file']; + if (isset($list[$i]['icon_link'])) echo " " . $list[$i]['icon_link']; + if (isset($list[$i]['icon_secret'])) echo " " . $list[$i]['icon_secret']; + ?> +
        • + + +
        • 게시물이 없습니다.
        • + +
        + +
        + \ No newline at end of file diff --git a/theme/basic/skin/latest/basic/style.css b/theme/basic/skin/latest/basic/style.css new file mode 100644 index 000000000..ab55517b1 --- /dev/null +++ b/theme/basic/skin/latest/basic/style.css @@ -0,0 +1,11 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 새글 스킨 (latest) */ +.lt_pc {float:left;margin-left:20px} +.lt {position:relative;float:left;margin-bottom:20px;padding-bottom:10px;width:354px;height:150px;border-bottom:1px solid #e9e9e9} +.lt ul {margin:0 0 10px;padding:0;list-style:none} +.lt li {padding:3px 0} +.lt .lt_title {display:block;padding:10px 0 8px} +.lt .lt_more {position:absolute;top:10px;right:0} +.lt .cnt_cmt {display:inline-block;margin:0 0 0 3px;font-weight:bold} \ No newline at end of file diff --git a/theme/basic/skin/member/basic/formmail.skin.php b/theme/basic/skin/member/basic/formmail.skin.php new file mode 100644 index 000000000..76e7bc910 --- /dev/null +++ b/theme/basic/skin/member/basic/formmail.skin.php @@ -0,0 +1,101 @@ +', 0); +?> + + +
        +

        님께 메일보내기

        + +
        + + + + + + + + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        메일쓰기
        형식 + + + +
        + + 첨부 파일은 누락될 수 있으므로 메일을 보낸 후 파일이 첨부 되었는지 반드시 확인해 주시기 바랍니다. +
        자동등록방지
        +
        + +
        + + +
        + +
        +
        + + + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/img/zip_ico_up.gif b/theme/basic/skin/member/basic/img/zip_ico_up.gif new file mode 100644 index 0000000000000000000000000000000000000000..a1eff70fa850bea122f6924d8c3cd63f1d573c53 GIT binary patch literal 54 zcmZ?wbhEHb', 0); +?> + + +
        +

        + +
        + + +
        + 회원로그인 + + + + + + + +
        + + + + + +
        + +
        + + + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/login_check.skin.php b/theme/basic/skin/member/basic/login_check.skin.php new file mode 100644 index 000000000..1b182915e --- /dev/null +++ b/theme/basic/skin/member/basic/login_check.skin.php @@ -0,0 +1,5 @@ + diff --git a/theme/basic/skin/member/basic/member_confirm.skin.php b/theme/basic/skin/member/basic/member_confirm.skin.php new file mode 100644 index 000000000..3ea749ba7 --- /dev/null +++ b/theme/basic/skin/member/basic/member_confirm.skin.php @@ -0,0 +1,50 @@ +', 0); +?> + + +
        +

        + +

        + 비밀번호를 한번 더 입력해주세요. + + 비밀번호를 입력하시면 회원탈퇴가 완료됩니다. + + 회원님의 정보를 안전하게 보호하기 위해 비밀번호를 한번 더 확인합니다. + +

        + +
        + + + +
        + 회원아이디 + + + + + +
        + +
        + + + +
        + + + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/memo.skin.php b/theme/basic/skin/member/basic/memo.skin.php new file mode 100644 index 000000000..f7477b5bf --- /dev/null +++ b/theme/basic/skin/member/basic/memo.skin.php @@ -0,0 +1,53 @@ +', 0); +?> + + +
        +

        + + + +
        + + + + + + + + + + + + + + + + + + + + '; } ?> + +
        + 전체 쪽지
        +
        보낸시간읽은시간관리
        삭제
        자료가 없습니다.
        +
        + +

        + 쪽지 보관일수는 최장 일 입니다. +

        + +
        + +
        +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/memo_form.skin.php b/theme/basic/skin/member/basic/memo_form.skin.php new file mode 100644 index 000000000..66d3d9c57 --- /dev/null +++ b/theme/basic/skin/member/basic/memo_form.skin.php @@ -0,0 +1,59 @@ +', 0); +?> + + +
        +

        쪽지 보내기

        + + + +
        +
        + + + + + + + + + + + + + + + + +
        쪽지쓰기
        + + 여러 회원에게 보낼때는 컴마(,)로 구분하세요. +
        자동등록방지 + +
        +
        + +
        + + +
        +
        +
        + + + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/memo_view.skin.php b/theme/basic/skin/member/basic/memo_view.skin.php new file mode 100644 index 000000000..87f15ce42 --- /dev/null +++ b/theme/basic/skin/member/basic/memo_view.skin.php @@ -0,0 +1,60 @@ +', 0); +?> + + +
        +

        + + + + + +
        +
        +

        쪽지 내용

        +
        +
          +
        • + 사람 + +
        • +
        • + 시간 + +
        • +
        +

        + +

        +
        + +
        + + 이전쪽지 + + + 다음쪽지 + + 답장 + 목록보기 + +
        +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/password.skin.php b/theme/basic/skin/member/basic/password.skin.php new file mode 100644 index 000000000..4564a05fa --- /dev/null +++ b/theme/basic/skin/member/basic/password.skin.php @@ -0,0 +1,50 @@ +', 0); +?> + + +
        +

        +

        + + 작성자만 글을 수정할 수 있습니다. + 작성자 본인이라면, 글 작성시 입력한 비밀번호를 입력하여 글을 수정할 수 있습니다. + + 작성자만 글을 삭제할 수 있습니다. + 작성자 본인이라면, 글 작성시 입력한 비밀번호를 입력하여 글을 삭제할 수 있습니다. + + 비밀글 기능으로 보호된 글입니다. + 작성자와 관리자만 열람하실 수 있습니다. 본인이라면 비밀번호를 입력하세요. + +

        + +
        + + + + + + + + +
        + + + +
        +
        + + + +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/password_lost.skin.php b/theme/basic/skin/member/basic/password_lost.skin.php new file mode 100644 index 000000000..c56ca88d2 --- /dev/null +++ b/theme/basic/skin/member/basic/password_lost.skin.php @@ -0,0 +1,47 @@ +', 0); +?> + + +
        +

        회원정보 찾기

        + +
        +
        +

        + 회원가입 시 등록하신 이메일 주소를 입력해 주세요.
        + 해당 이메일로 아이디와 비밀번호 정보를 보내드립니다. +

        + + +
        + +
        + + +
        +
        +
        + + + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/point.skin.php b/theme/basic/skin/member/basic/point.skin.php new file mode 100644 index 000000000..d0e754fba --- /dev/null +++ b/theme/basic/skin/member/basic/point.skin.php @@ -0,0 +1,88 @@ +', 0); +?> + +
        +

        + +
        + + + + + + + + + + + + + 0) { + $point1 = '+' .number_format($row['po_point']); + $sum_point1 += $row['po_point']; + } else { + $point2 = number_format($row['po_point']); + $sum_point2 += $row['po_point']; + } + + $po_content = $row['po_content']; + + $expr = ''; + if($row['po_expired'] == 1) + $expr = ' txt_expired'; + ?> + + + + + + + + '; + else { + if ($sum_point1 > 0) + $sum_point1 = "+" . number_format($sum_point1); + $sum_point2 = number_format($sum_point2); + } + ?> + + + + + + + + + + + + +
        포인트 사용내역 목록
        일시내용만료일지급포인트사용포인트
        + + 만료 + +
        자료가 없습니다.
        소계
        보유포인트
        +
        + + + +
        +
        \ No newline at end of file diff --git a/theme/basic/skin/member/basic/profile.skin.php b/theme/basic/skin/member/basic/profile.skin.php new file mode 100644 index 000000000..0b0535fab --- /dev/null +++ b/theme/basic/skin/member/basic/profile.skin.php @@ -0,0 +1,50 @@ +', 0); +?> + + +
        +

        님의 프로필

        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + +
        회원권한
        포인트
        홈페이지
        회원가입일= $mb['mb_level']) ? substr($mb['mb_datetime'],0,10) ." (".number_format($mb_reg_after)." 일)" : "알 수 없음"; ?>
        최종접속일= $mb['mb_level']) ? $mb['mb_today_login'] : "알 수 없음"; ?>
        +
        + +
        +

        인사말

        +

        +
        + +
        + +
        +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/register.skin.php b/theme/basic/skin/member/basic/register.skin.php new file mode 100644 index 000000000..455150d9d --- /dev/null +++ b/theme/basic/skin/member/basic/register.skin.php @@ -0,0 +1,57 @@ +', 0); +?> + + +
        +
        + +

        회원가입약관 및 개인정보처리방침안내의 내용에 동의하셔야 회원가입 하실 수 있습니다.

        + +
        +

        회원가입약관

        + +
        + + +
        +
        + +
        +

        개인정보처리방침안내

        + +
        + + +
        +
        + +
        + +
        + +
        + + +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/register_form.skin.php b/theme/basic/skin/member/basic/register_form.skin.php new file mode 100644 index 000000000..16d6181e8 --- /dev/null +++ b/theme/basic/skin/member/basic/register_form.skin.php @@ -0,0 +1,441 @@ +', 0); +?> + + +
        + + + + + + +
        + + + + + + + + date("Y-m-d", G5_SERVER_TIME - ($config['cf_nick_modify'] * 86400))) { // 닉네임수정일이 지나지 않았다면 ?> + + + + +
        + + + + + + + + + + + + + + + + +
        사이트 이용정보 입력
        + 영문자, 숫자, _ 만 입력 가능. 최소 3자이상 입력하세요. + class="frm_input " minlength="3" maxlength="20"> + +
        class="frm_input " minlength="3" maxlength="20">
        class="frm_input " minlength="3" maxlength="20">
        +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        개인정보 입력
        + + 아이핀 본인확인 후에는 이름이 자동 입력되고 휴대폰 본인확인 후에는 이름과 휴대폰번호가 자동 입력되어 수동으로 입력할수 없게 됩니다. + + class="frm_input " size="10"> + 아이핀 본인확인'.PHP_EOL; + if($config['cf_cert_hp']) + echo ''.PHP_EOL; + + echo ''.PHP_EOL; + } + ?> + +
        + 본인확인성인인증 완료 +
        + +
        + + 공백없이 한글,영문,숫자만 입력 가능 (한글2자, 영문4자 이상)
        + 닉네임을 바꾸시면 앞으로 일 이내에는 변경 할 수 없습니다. +
        + + + +
        + + + + + + + + +
        class="frm_input " size="70" maxlength="255">
        class="frm_input " maxlength="20">
        + class="frm_input " maxlength="20"> + + + +
        + 주소 + 필수 + + + class="frm_input " size="5" maxlength="6"> +
        + class="frm_input frm_address " size="50"> +
        + + +
        + + + +
        +
        + +
        + + + + + + + + + + + + + + + + + + = $config['cf_icon_level']) { ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        기타 개인설정
        + + 이미지 크기는 가로 픽셀, 세로 픽셀 이하로 해주세요.
        + gif만 가능하며 용량 바이트 이하만 등록됩니다. +
        + + + 회원아이콘 + + + +
        + > + 정보 메일을 받겠습니다. +
        + > + 휴대폰 문자메세지를 받겠습니다. +
        + + 정보공개를 바꾸시면 앞으로 일 이내에는 변경이 안됩니다. + + + id="reg_mb_open"> + 다른분들이 나의 정보를 볼 수 있도록 합니다. +
        정보공개 + + 정보공개는 수정후 일 이내, 까지는 변경이 안됩니다.
        + 이렇게 하는 이유는 잦은 정보공개 수정으로 인하여 쪽지를 보낸 후 받지 않는 경우를 막기 위해서 입니다. +
        + +
        자동등록방지
        +
        + +
        + + 취소 +
        +
        + + + +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/register_result.skin.php b/theme/basic/skin/member/basic/register_result.skin.php new file mode 100644 index 000000000..1267d20ee --- /dev/null +++ b/theme/basic/skin/member/basic/register_result.skin.php @@ -0,0 +1,46 @@ +', 0); +?> + + +
        + +

        + 님의 회원가입을 진심으로 축하합니다.
        +

        + + +

        + 회원 가입 시 입력하신 이메일 주소로 인증메일이 발송되었습니다.
        + 발송된 인증메일을 확인하신 후 인증처리를 하시면 사이트를 원활하게 이용하실 수 있습니다. +

        +
        + 아이디 +
        + 이메일 주소 + +
        +

        + 이메일 주소를 잘못 입력하셨다면, 사이트 관리자에게 문의해주시기 바랍니다. +

        + + +

        + 회원님의 비밀번호는 아무도 알 수 없는 암호화 코드로 저장되므로 안심하셔도 좋습니다.
        + 아이디, 비밀번호 분실시에는 회원가입시 입력하신 이메일 주소를 이용하여 찾을 수 있습니다. +

        + +

        + 회원 탈퇴는 언제든지 가능하며 일정기간이 지난 후, 회원님의 정보는 삭제하고 있습니다.
        + 감사합니다. +

        + + + +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/scrap.skin.php b/theme/basic/skin/member/basic/scrap.skin.php new file mode 100644 index 000000000..e89053522 --- /dev/null +++ b/theme/basic/skin/member/basic/scrap.skin.php @@ -0,0 +1,46 @@ +', 0); +?> + + +
        +

        + +
        + + + + + + + + + + + + + + + + + + + + + + + "; ?> + +
        스크랩 목록
        번호게시판제목보관일시삭제
        삭제
        자료가 없습니다.
        +
        + + + +
        + +
        +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/scrap_popin.skin.php b/theme/basic/skin/member/basic/scrap_popin.skin.php new file mode 100644 index 000000000..81f82a5a9 --- /dev/null +++ b/theme/basic/skin/member/basic/scrap_popin.skin.php @@ -0,0 +1,41 @@ +', 0); +?> + + +
        +

        스크랩하기

        + +
        + + + +
        + + + + + + + + + + + + +
        제목 확인 및 댓글 쓰기
        제목
        +
        + +

        + 스크랩을 하시면서 감사 혹은 격려의 댓글을 남기실 수 있습니다. +

        + +
        + +
        +
        +
        + \ No newline at end of file diff --git a/theme/basic/skin/member/basic/style.css b/theme/basic/skin/member/basic/style.css new file mode 100644 index 000000000..481d30037 --- /dev/null +++ b/theme/basic/skin/member/basic/style.css @@ -0,0 +1,173 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +/* 버튼 */ +.mbskin a.btn01 {} +.mbskin a.btn01:focus, .mbskin .btn01:hover {} +.mbskin a.btn02 {} +.mbskin a.btn02:focus, .mbskin .btn02:hover {} +.mbskin .btn_confirm {} /* 서식단계 진행 */ +.mbskin .btn_submit {} +.mbskin button.btn_submit {} +.mbskin fieldset .btn_submit {} +.mbskin .btn_cancel {} +.mbskin button.btn_cancel {} +.mbskin .btn_cancel:focus, .mbskin .btn_cancel:hover {} +.mbskin a.btn_frmline, .mbskin button.btn_frmline {} /* 우편번호검색버튼 등 */ +.mbskin button.btn_frmline {} +.mbskin .win_btn {} /* 새창용 */ +.mbskin .win_btn button {} +.mbskin .win_btn input {} +.mbskin .win_btn a {} +.mbskin .win_btn a:focus, .mbskin .win_btn a:hover {} +/* 게시판용 버튼 */ +.mbskin a.btn_b01 {} +.mbskin a.btn_b01:focus, .mbskin .btn_b01:hover {} +.mbskin a.btn_b02 {} +.mbskin a.btn_b02:focus, .mbskin .btn_b02:hover {} +.mbskin a.btn_admin {} /* 관리자 전용 버튼 */ +.mbskin a.btn_admin:focus, .mbskin a.btn_admin:hover {} + +/* 기본테이블 */ +.mbskin .tbl_head01 {} +.mbskin .tbl_head01 caption {} +.mbskin .tbl_head01 thead th {} +.mbskin .tbl_head01 thead a {} +.mbskin .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +.mbskin .tbl_head01 tfoot th {} +.mbskin .tbl_head01 tfoot td {} +.mbskin .tbl_head01 tbody th {} +.mbskin .tbl_head01 td {} +.mbskin .tbl_head01 a {} +.mbskin td.empty_table {} + +/* 폼 테이블 */ +.mbskin table {} +.mbskin caption {} +.mbskin .frm_info {} +.mbskin .frm_file {} + +.mbskin .tbl_frm01 {} +.mbskin .tbl_frm01 th {width:85px;} +.mbskin .tbl_frm01 td {} +.mbskin .tbl_frm01 textarea, .mb_skin tbl_frm01 .frm_input {} +.mbskin .tbl_frm01 textarea {} +/* +.mbskin .tbl_frm01 #captcha {} +.mbskin .tbl_frm01 #captcha input {} +*/ +.mbskin .tbl_frm01 a {} + +/* 필수입력 */ +.mbskin .required, .mbskin textarea.required {} + +/* 테이블 항목별 정의 */ +.mbskin .td_board {} +.mbskin .td_chk {} +.mbskin .td_date {} +.mbskin .td_datetime {} +.mbskin .td_group {} +.mbskin .td_mb_id {} +.mbskin .td_mng {} +.mbskin .td_name {} +.mbskin .td_nick {} +.mbskin .td_num {} +.mbskin .td_numbig {} + +.mbskin .txt_active {} +.mbskin .txt_expired {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 회원가입 약관 */ +#fregister section {margin:0 0 20px;padding:20px 0} +#fregister h2 {margin:0 0 20px;text-align:center} +#fregister textarea {display:block;margin-bottom:10px;padding:5px;width:98%;height:150px;border:1px solid #e9e9e9;background:#f7f7f7} +#fregister .fregister_agree {padding:10px 0 0;text-align:right} +#fregister .fregister_agree label {display:inline-block;margin-right:5px} +#fregister p {color:#e8180c;text-align:center} +#fregister .btn_confirm {margin-bottom:20px} + +/* 회원가입 입력 */ +#fregisterform textarea {height:50px} + +#fregisterform #msg_certify {margin:5px 0 0;padding:5px;border:1px solid #dbecff;background:#eaf4ff;text-align:center} + +#fregisterform .frm_address {margin:5px 0 0} +#fregisterform #mb_addr3 {display:inline-block;margin:5px 0 0;vertical-align:middle} +#fregisterform #mb_addr_jibeon {display:block;margin:5px 0 0} + +/* 회원가입 완료 */ +#reg_result {padding:50px 0 0} +#reg_result #result_email {margin:20px 0;padding:10px 50px;border-top:1px solid #e9e9e9;border-bottom:1px solid #dde4e9;background:#fff;line-height:2em} +#reg_result #result_email span {display:inline-block;width:150px} +#reg_result #result_email strong {color:#e8180c;font-size:1.2em} +#reg_result p {line-height:1.8em} +#reg_result .btn_confirm {margin:50px 0} + +/* 아이디/비밀번호 찾기 */ +#find_info #mb_hp_label {display:inline-block;margin-left:10px} +#find_info #info_fs {margin:0 20px 20px;padding:0;background:#fff} +#find_info #info_fs .frm_input {width:70%} +#find_info p {margin:0 0 10px;line-height:1.8em} +#find_info #captcha {margin:0 20px} + +/* 로그인 */ +#mb_login {margin:0 auto;padding:100px 0;width:500px} +#mb_login h1 {margin:0 0 20px;font-size:1.3em} +#mb_login h2 {margin:0} +#mb_login p {padding:10px 0;line-height:1.5em} +#mb_login #login_fs {position:relative;margin:0;padding:20px 20px 20px 95px;border:1px solid #cfded8;border-bottom:0;background:#fff} +#mb_login #login_fs legend {position:absolute;margin:0;padding:0;font-size:0;line-height:0;text-indent:-9999em;overflow:hidden} +#mb_login #login_fs label {letter-spacing:-0.1em} +#mb_login #login_fs .login_id {position:absolute;top:26px;left:95px} +#mb_login #login_fs .login_pw {position:absolute;top:52px;left:95px} +#mb_login #login_fs .frm_input {display:block;margin:0 0 5px 80px;width:162px} +#mb_login #login_fs .btn_submit {position:absolute;top:20px;right:95px;width:60px;height:53px} +#mb_login #login_info {margin:0 0 30px;padding:20px;border:1px solid #cfded8;background:#f5f6fa} +#mb_login #login_info div {text-align:right} + +/* 쪽지 */ +#memo_view_contents {margin:0 auto 20px;width:90%} +#memo_view_contents h1 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#memo_view_ul {margin:0;padding:0 0 10px;border-bottom:1px solid #eee;list-style:none} +.memo_view_li {position:relative;padding:5px 0} +.memo_view_subj {display:inline-block;width:65px} +#memo_view p {padding:10px 0;min-height:150px;height:auto !important;height:150px;background:#fff;line-height:1.8em} + +#memo_write textarea {height:100px} + +/* 스크랩 */ +#scrap_do table {margin:0 0 10px;width:100%} +#scrap_do textarea {height:100px} + +/* 회원 비밀번호 확인 */ +#mb_confirm {margin:0 auto;padding:100px 0;width:500px} +#mb_confirm h1 {margin:0 0 20px;font-size:1.3em} +#mb_confirm p {padding:20px;border:1px solid #dde4e9;border-bottom:0;background:#fff} +#mb_confirm p strong {display:block} +#mb_confirm fieldset {margin:0 0 30px;padding:30px 0;border:1px solid #e9e9e9;background:#f5f6fa;text-align:center} +#mb_confirm fieldset .frm_input {background-color:#fff !important} +#mb_confirm label {letter-spacing:-0.1em} +#mb_confirm_id {display:inline-block;margin-right:20px;font-weight:bold} + +/* 비밀글 비밀번호 확인 */ +#pw_confirm {margin:0 auto;padding:100px 0;width:500px} +#pw_confirm h1 {margin:0 0 20px;font-size:1.3em} +#pw_confirm p {padding:20px;border:1px solid #dde4e9;border-bottom:0;background:#fff} +#pw_confirm p strong {display:block} +#pw_confirm fieldset {margin:0 0 30px;padding:30px 0;border:1px solid #e9e9e9;background:#f5f6fa;text-align:center} +#pw_confirm fieldset .frm_input {background-color:#fff !important} +#pw_confirm label {letter-spacing:-0.1em} +#pw_confirm_id {display:inline-block;margin-right:20px;font-weight:bold} + +/* 폼메일 */ +#formmail #subject {width:386px} +#formmail textarea {height:100px} + +/* 자기소개 */ +#profile table {margin-bottom:0} +#profile section {margin:0 auto 20px;padding:20px;width:86%} +#profile h2 {margin:0} \ No newline at end of file diff --git a/theme/basic/skin/new/basic/new.skin.php b/theme/basic/skin/new/basic/new.skin.php new file mode 100644 index 000000000..2558d8118 --- /dev/null +++ b/theme/basic/skin/new/basic/new.skin.php @@ -0,0 +1,144 @@ +', 0); +?> + + +
        + 상세검색 +
        + + + + + + +

        회원 아이디만 검색 가능

        +
        + +
        + + + +
        + + + + + + + + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + ?> + +
        + + + 그룹게시판제목이름일시
        + + + + +
        게시물이 없습니다.
        +
        + + +
        + +
        + +
        + + + + + + + \ No newline at end of file diff --git a/theme/basic/skin/new/basic/style.css b/theme/basic/skin/new/basic/style.css new file mode 100644 index 000000000..da1c877f2 --- /dev/null +++ b/theme/basic/skin/new/basic/style.css @@ -0,0 +1,7 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 최근게시물 스킨 (new) */ +#new_sch {margin-bottom:10px;text-align:right} +#new_sch legend {position:absolute;margin:0;padding:0;font-size:0;line-height:0;text-indent:-9999em;overflow:hidden} +#new_sch p {padding:5px 0 0;font-size:0.95em;text-align:right;letter-spacing:-0.1em} \ No newline at end of file diff --git a/theme/basic/skin/outlogin/basic/outlogin.skin.1.php b/theme/basic/skin/outlogin/basic/outlogin.skin.1.php new file mode 100644 index 000000000..b71bae3d9 --- /dev/null +++ b/theme/basic/skin/outlogin/basic/outlogin.skin.1.php @@ -0,0 +1,69 @@ +', 0); +?> + + +
        +

        회원로그인

        +
        +
        + + + + + + + +
        + + +
        +
        +
        +
        + + + diff --git a/theme/basic/skin/outlogin/basic/outlogin.skin.2.php b/theme/basic/skin/outlogin/basic/outlogin.skin.2.php new file mode 100644 index 000000000..ab1286c7d --- /dev/null +++ b/theme/basic/skin/outlogin/basic/outlogin.skin.2.php @@ -0,0 +1,46 @@ +', 0); +?> + + +
        +
        +

        나의 회원정보

        + + 관리자 모드 +
        + + +
        + + + diff --git a/theme/basic/skin/outlogin/basic/style.css b/theme/basic/skin/outlogin/basic/style.css new file mode 100644 index 000000000..f6a0e058e --- /dev/null +++ b/theme/basic/skin/outlogin/basic/style.css @@ -0,0 +1,45 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 아웃로그인 스킨 */ +.ol {position:relative;padding:15px 15px 14px 14px;border-bottom:1px solid #dde4e9} +.ol h2 {margin:0;padding:0;width:1px;height:1px;font-size:0;line-height:0;overflow:hidden} +.ol ul {margin:0;padding:0;list-style:none} + +.ol a.btn_admin {display:inline-block;padding:0 10px;height:23px;border:1px solid #e8180c;background:#e8180c;color:#fff;text-decoration:none;line-height:2.15em;vertical-align:middle} /* 관리자 전용 버튼 */ +.ol a.btn_admin:focus, .ol a.btn_admin:hover {text-decoration:none} + +#ol_before {} +#ol_before fieldset {position:relative} +#ol_id {display:block;margin:0 0 5px !important;margin:0 0 3px;padding:0 5px;width:168px;height:22px;border:1px solid #e4eaec;background:#f7f7f7;line-height:1.6em} +.ol_idlabel {position:absolute;top:6px;left:5px;color:#333;font-size:0.95em} +#ol_pw {display:block;margin:0 0 5px !important;margin:0 0 3px;padding:0 5px;width:168px;height:22px;border:1px solid #e4eaec;background:#f7f7f7;vertical-align:top;line-height:1.6em} +.ol_pwlabel {position:absolute;top:35px;left:5px;color:#333;font-size:0.95em} +#auto_login {} +#auto_login_label {letter-spacing:-0.1em} +#ol_submit {display:inline-block;width:60px;height:24px;border:0;background:#333;color:#fff;font-size:0.9em;font-weight:bold;vertical-align:top} +#ol_before a {letter-spacing:-0.15em} +#ol_svc {float:left;margin:5px 0 0} +#ol_password_lost {display:inline-block;margin:0 0 0 5px} +#ol_auto {position:relative;float:right;margin:5px 0 0} +#ol_auto label {letter-spacing:-0.1em} +#ol_auto input {width:13px;height:13px;vertical-align:bottom} + +#ol_after {} +#ol_after_hd {margin:0 0 3px} +#ol_after_hd .btn_admin {margin-top:5px;width:158px;text-align:center} +#ol_after_private {margin:0 0 3px;zoom:1} +#ol_after_private:after {display:block;visibility:hidden;clear:both;content:""} +#ol_after_private li {float:left} +#ol_after_private a {display:block;padding-top:8px;height:37px;background:#f7f7f7;text-align:center} +#ol_after_private a strong {display:block;padding-top:3px;color:#000;font-weight:normal} +#ol_after_private a:focus, +#ol_after_private a:hover {background:#333;color:#fff;text-decoration:none} +#ol_after_private a:focus strong, +#ol_after_private a:hover strong {color:#fff;text-decoration:none} +#ol_after_memo {width:50px;margin-right:1px} +#ol_after_pt {width:80px;margin-right:1px} +#ol_after_scrap {width:48px;line-height:2.6em !important} +#ol_after_ft {text-align:justify} +#ol_after_ft a {display:inline-block;width:88px;height:25px;background:#333;color:#fff;text-align:center;line-height:2.2em} +#ol_after_ft a:focus, #ol_after_ft a:hover {text-decoration:none !important} \ No newline at end of file diff --git a/theme/basic/skin/poll/basic/poll.skin.php b/theme/basic/skin/poll/basic/poll.skin.php new file mode 100644 index 000000000..05d3260e1 --- /dev/null +++ b/theme/basic/skin/poll/basic/poll.skin.php @@ -0,0 +1,67 @@ +', 0); +?> + + +
        + + +
        +
        +

        설문조사

        + 설문조사 관리 +

        +
        +
          + +
        • + +
        + +
        +
        + + + \ No newline at end of file diff --git a/theme/basic/skin/poll/basic/poll_result.skin.php b/theme/basic/skin/poll/basic/poll_result.skin.php new file mode 100644 index 000000000..4741f5941 --- /dev/null +++ b/theme/basic/skin/poll/basic/poll_result.skin.php @@ -0,0 +1,131 @@ +', 0); +?> + + +
        +

        + + +
        +

        결과

        + +
        +
        전체
        +
        +
          + +
        1. +

          + + + 퍼센트 +

          +
          + +
          +
        2. + +
        +
        +
        +
        + + + + +
        +

        이 설문에 대한 기타의견

        + + +
        +
        +

        님의 의견

        + + +
        +

        + +

        +
        + "; } ?> +
        +
        + + + = $po['po_level']) { ?> +
        + + + + +

        + +
        + + + + + + + + + + + + + + + + + + + +
        자동등록방지
        +
        + +
        + +
        +
        + + +
        + + + + + + + +
        + +
        +
        + + + \ No newline at end of file diff --git a/theme/basic/skin/poll/basic/style.css b/theme/basic/skin/poll/basic/style.css new file mode 100644 index 000000000..e46faafff --- /dev/null +++ b/theme/basic/skin/poll/basic/style.css @@ -0,0 +1,90 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +#poll a.btn_admin {} /* 관리자 전용 버튼 */ +#poll a.btn_admin:focus, #poll a.btn_admin:hover {} + +#poll_result .tbl_frm table {} +#poll_result .tbl_frm .frm_info {} +#poll_result .tbl_frm .frm_address {} +#poll_result .tbl_frm .frm_file {} +#poll_result .tbl_frm caption {} + +#poll_result .tbl_frm01 {} +#poll_result .tbl_frm01 th {} +#poll_result .tbl_frm01 td {} +#poll_result .tbl_frm01 textarea, #poll_result tbl_frm01 .frm_input {} +#poll_result .tbl_frm01 textarea {} +/* +#poll_result .tbl_frm01 #captcha {} +#poll_result .tbl_frm01 #captcha input {} +*/ +#poll_result .tbl_frm01 a {} + +/* 필수입력 */ +#poll_result .required, #poll_result textarea.required {} + +#poll_result .btn_confirm {} /* 서식단계 진행 */ +#poll_result .btn_submit {} +#poll_result button.btn_submit {} +#poll_result .win_btn {} /* 새창용 */ +#poll_result .win_btn button {} +#poll_result .win_btn input {} +#poll_result .win_btn a {} +#poll_result .win_btn a:focus, #poll_result .win_btn a:hover {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 설문조사 스킨 */ +#poll {border-bottom:1px solid #dde4e9} +#poll header {position:relative;padding:15px 14px 0} +#poll h2 {} +#poll header .btn_admin {margin-top:5px;width:158px;text-align:center} +#poll header p {padding:5px 0 0} +#poll ul {margin:0 0 10px;padding:5px 14px;list-style:none} +#poll li {padding:3px 0} +#poll footer {padding:0 14px 14px} +#poll footer input {width:88px;height:27px;border:0;background:#333;color:#fff;letter-spacing:-0.1em;vertical-align:top;cursor:pointer} +#poll footer a {display:inline-block;width:86px;height:25px;border:1px solid #ccc;background:#fafafa;text-align:center;line-height:2.2em} +#poll footer a:focus, #poll footer a:hover {text-decoration:none !important} + +/* 설문조사 결과 (새창) */ +#poll_result {} +#poll_result section {margin:0 20px 20px;padding:15px;border:1px solid #dde4e9;background:#fff} +#poll_result .tbl_wrap {margin:0} +#poll_result h2 {margin:0;padding:20px 0} +#poll_result a {} +#poll_result .sv_member, +#poll_result .sv_guest {font-weight:bold} +#poll_result_list {margin:0 auto 20px} +#poll_result_list h2 {text-align:center} +#poll_result_list dl, +#poll_result_list dt, +#poll_result_list dd {margin:0;padding:0} +#poll_result_list dl {padding-bottom:30px} +#poll_result_list dt {margin-right:5%;color:#e8180d;text-align:right} +#poll_result_list ol {margin:0;padding-left:30px} +#poll_result_list li {margin-top:10px} +#poll_result_list p {position:relative;margin:0;padding:5px 0} +#poll_result_list p strong {position:absolute;top:5px;right:5%;padding-right:80px;width:100px;text-align:right} +#poll_result_list p span {position:absolute;top:5px;right:5%;width:80px;color:#68999c;text-align:right} +.poll_result_graph {position:relative;margin-right:5%;height:5px;background:#eee} +.poll_result_graph span {position:absolute;top:0;left:0;height:5px;background:#565e60;font-size:0.1em} +#poll_result_cmt {} +#poll_result_cmt h2 {text-align:center} +#poll_result_cmt h3 {margin:0 0 10px} +#poll_result_cmt article {margin:0 0 15px;border-bottom:1px solid #eee} +#poll_result_cmt h1 {position:absolute;margin:0;padding:0;border:0;font-size:0;text-indent:-9999em;line-height:0;overflow:hidden} +.poll_datetime {display:inline-block;margin-left:10px} +#poll_result_cmt p {padding:3px 0} +#poll_result_cmt fieldset {margin-bottom:0;text-align:left} +#poll_result_cmt fieldset p {margin:0 0 15px;padding:3px 0 0px;text-align:left} +#poll_result_cmt footer {text-align:right} +#poll_result_wcmt {margin:0 0 10px} +.poll_cmt_del a {display:inline-block;padding-bottom:10px} +#poll_result_oth {margin:0 auto 20px;width:93%} +#poll_result_oth h2 {padding:0 0 10px} +#poll_result_oth ul {margin:0;padding:0;list-style:none} +#poll_result_oth a {display:block;padding:10px 0;border-bottom:1px solid #eee} \ No newline at end of file diff --git a/theme/basic/skin/popular/basic/popular.skin.php b/theme/basic/skin/popular/basic/popular.skin.php new file mode 100644 index 000000000..14fe12281 --- /dev/null +++ b/theme/basic/skin/popular/basic/popular.skin.php @@ -0,0 +1,19 @@ +', 0); +?> + + + + \ No newline at end of file diff --git a/theme/basic/skin/popular/basic/style.css b/theme/basic/skin/popular/basic/style.css new file mode 100644 index 000000000..d2c4219d0 --- /dev/null +++ b/theme/basic/skin/popular/basic/style.css @@ -0,0 +1,12 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 인기검색어 */ +#popular {border-bottom:1px dotted #dde4e9} +#popular div {margin:0 auto;width:970px;zoom:1} +#popular div:after {display:block;visibility:hidden;clear:both;content:""} +#popular h2 {float:left;padding:10px 45px 10px 0} +#popular ul {float:left;margin:0;padding:0;list-style:none} +#popular li {float:left} +#popular a {display:inline-block;padding:10px;text-decoration:none} +#popular a:focus, #popular a:hover {} \ No newline at end of file diff --git a/theme/basic/skin/qa/basic/img/btn_close.gif b/theme/basic/skin/qa/basic/img/btn_close.gif new file mode 100644 index 0000000000000000000000000000000000000000..040b180ac6584ae612ef2886487110f0ad079963 GIT binary patch literal 211 zcmZ?wbhEHbC>lw|Nj2|^XJd+Ki|K7yLIc<@85r}UAy+@_wT|Ns9P2m!^PEMO%%AQEIJ18abSL2rs@7wgh> zI-xzeYYr882T$7a>~-(!J@=MOy}Z$ltNl`73Cq0Bi3wIGB-b=ECVhGFY*&ANIg94( d^Unm859R4|2rw-)wA%9i`(c-qSMQw}tN}eeW+eas literal 0 HcmV?d00001 diff --git a/theme/basic/skin/qa/basic/img/icon_answer.gif b/theme/basic/skin/qa/basic/img/icon_answer.gif new file mode 100644 index 0000000000000000000000000000000000000000..91c135977b4f445a90c849310dc80efde1983830 GIT binary patch literal 77 zcmZ?wbhEHb-Wqsc#^P~2x#@rVooH@5wHB9i@BozKb;P9uI^*c|UyXO5@>VyLmgEat< Cr6(f* literal 0 HcmV?d00001 diff --git a/theme/basic/skin/qa/basic/img/icon_hot.gif b/theme/basic/skin/qa/basic/img/icon_hot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c95b839aeef0c1e26a4bab4ea50cd6d3f1969d7f GIT binary patch literal 97 zcmZ?wbhEHbzHen|7VvwFnzUPlarEA ZqW~YXyUO~T+#YkUoJ%V_>ib05Q5F AasU7T literal 0 HcmV?d00001 diff --git a/theme/basic/skin/qa/basic/img/icon_mobile.gif b/theme/basic/skin/qa/basic/img/icon_mobile.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad934d23c440c83db0c4589596465cb087353e01 GIT binary patch literal 62 zcmZ?wbhEHbZ% literal 0 HcmV?d00001 diff --git a/theme/basic/skin/qa/basic/img/icon_secret.gif b/theme/basic/skin/qa/basic/img/icon_secret.gif new file mode 100644 index 0000000000000000000000000000000000000000..c04899f14fa727b64223f6c5457877c6c939639d GIT binary patch literal 97 zcmZ?wbhEHb&!1E4^4&ClEzh)PmWxV3{9A~!gB2-%RL5bHcgg3Zp^!+W)H2^A_AxQuL literal 0 HcmV?d00001 diff --git a/theme/basic/skin/qa/basic/img/icon_sound.gif b/theme/basic/skin/qa/basic/img/icon_sound.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5188318a5cdc394b984125c0ddd376c5f57bbe4 GIT binary patch literal 113 zcmZ?wbhEHbE1CJY$zMikVi`-#gIi|DbmsXBWf6U5szE@->A`0*`&<;b@XASRrB8=E6~=S>Pbm I%fes{0AXt-SpWb4 literal 0 HcmV?d00001 diff --git a/theme/basic/skin/qa/basic/list.skin.php b/theme/basic/skin/qa/basic/list.skin.php new file mode 100644 index 000000000..a06532b6b --- /dev/null +++ b/theme/basic/skin/qa/basic/list.skin.php @@ -0,0 +1,167 @@ +', 0); +?> + +
        + + + + + + + +
        +
        + Total + 페이지 +
        + + + + +
        + + +
        + + + + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; } ?> + +
        목록
        번호 + + + 분류제목글쓴이상태등록일
        + + + + + + + +
        게시물이 없습니다.
        +
        + +
        + +
          +
        • +
        + + + +
        +
        +
        + + + + + + + + + +
        + 게시물 검색 + +
        + + + + +
        +
        + + + + + + \ No newline at end of file diff --git a/theme/basic/skin/qa/basic/style.css b/theme/basic/skin/qa/basic/style.css new file mode 100644 index 000000000..8f7022428 --- /dev/null +++ b/theme/basic/skin/qa/basic/style.css @@ -0,0 +1,281 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* ### 기본 스타일 커스터마이징 시작 ### */ + +/* 게시판 버튼 */ +/* 목록 버튼 */ +#bo_list a.btn_b01 {} +#bo_list a.btn_b01:focus, #bo_list a.btn_b01:hover {} +#bo_list a.btn_b02 {} +#bo_list a.btn_b02:focus, #bo_list a.btn_b02:hover {} +#bo_list a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_list a.btn_admin:focus, #bo_list .btn_admin:hover {} + +/* 읽기 버튼 */ +#bo_v a.btn_b01 {} +#bo_v a.btn_b01:focus, #bo_v a.btn_b01:hover {} +#bo_v a.btn_b02 {} +#bo_v a.btn_b02:focus, #bo_v a.btn_b02:hover {} +#bo_v a.btn_admin {} /* 관리자 전용 버튼 */ +#bo_v a.btn_admin:focus, #bo_v a.btn_admin:hover {} + +/* 쓰기 버튼 */ +#bo_w .btn_confirm {} /* 서식단계 진행 */ +#bo_w .btn_submit {} +#bo_w button.btn_submit {} +#bo_w fieldset .btn_submit {} +#bo_w .btn_cancel {} +#bo_w button.btn_cancel {} +#bo_w .btn_cancel:focus, #bo_w .btn_cancel:hover {} +#bo_w a.btn_frmline, #bo_w button.btn_frmline {} /* 우편번호검색버튼 등 */ +#bo_w button.btn_frmline {} + +/* 기본 테이블 */ +/* 목록 테이블 */ +#bo_list .tbl_head01 {} +#bo_list .tbl_head01 caption {} +#bo_list .tbl_head01 thead th {} +#bo_list .tbl_head01 thead a {} +#bo_list .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_list .tbl_head01 tfoot th {} +#bo_list .tbl_head01 tfoot td {} +#bo_list .tbl_head01 tbody th {} +#bo_list .tbl_head01 td {} +#bo_list .tbl_head01 a {} +#bo_list td.empty_table {} + +/* 읽기 내 테이블 */ +#bo_v .tbl_head01 {} +#bo_v .tbl_head01 caption {} +#bo_v .tbl_head01 thead th {} +#bo_v .tbl_head01 thead a {} +#bo_v .tbl_head01 thead th input {} /* middle 로 하면 게시판 읽기에서 목록 사용시 체크박스 라인 깨짐 */ +#bo_v .tbl_head01 tfoot th {} +#bo_v .tbl_head01 tfoot td {} +#bo_v .tbl_head01 tbody th {} +#bo_v .tbl_head01 td {} +#bo_v .tbl_head01 a {} +#bo_v td.empty_table {} + +/* 쓰기 테이블 */ +#bo_w table {} +#bo_w caption {} +#bo_w .frm_info {} +#bo_w .frm_address {} +#bo_w .frm_file {} + +#bo_w .tbl_frm01 {} +#bo_w .tbl_frm01 th {} +#bo_w .tbl_frm01 td {} +#bo_w .tbl_frm01 textarea, #bo_w tbl_frm01 .frm_input {} +#bo_w .tbl_frm01 textarea {} +/* +#bo_w .tbl_frm01 #captcha {} +#bo_w .tbl_frm01 #captcha input {} +*/ +#bo_w .tbl_frm01 a {} + +/* 필수입력 */ +#bo_w .required, #bo_w textarea.required {} + +#bo_w .cke_sc {} +#bo_w button.btn_cke_sc{} +#bo_w .cke_sc_def {} +#bo_w .cke_sc_def dl {} +#bo_w .cke_sc_def dl:after {} +#bo_w .cke_sc_def dt, #bo_w .cke_sc_def dd {} +#bo_w .cke_sc_def dt {} +#bo_w .cke_sc_def dd {} + +/* ### 기본 스타일 커스터마이징 끝 ### */ + +/* 게시판 목록 */ +#bo_list .td_board {width:120px;text-align:center} +#bo_list .td_chk {width:30px;text-align:center} +#bo_list .td_date {width:60px;text-align:center} +#bo_list .td_datetime {width:110px;text-align:center} +#bo_list .td_group {width:100px;text-align:center} +#bo_list .td_mb_id {width:100px;text-align:center} +#bo_list .td_mng {width:80px;text-align:center} +#bo_list .td_name {width:100px;text-align:left} +#bo_list .td_nick {width:100px;text-align:center} +#bo_list .td_num {width:50px;text-align:center} +#bo_list .td_numbig {width:80px;text-align:center} + +#bo_list .txt_active {color:#5d910b} +#bo_list .txt_expired {color:#ccc} + +#bo_cate h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_cate ul {margin-bottom:10px;padding-left:1px;zoom:1} +#bo_cate ul:after {display:block;visibility:hidden;clear:both;content:""} +#bo_cate li {float:left;margin-bottom:-1px} +#bo_cate a {display:block;position:relative;margin-left:-1px;padding:6px 0 5px;width:90px;border:1px solid #ddd;background:#f7f7f7;color:#888;text-align:center;letter-spacing:-0.1em;line-height:1.2em;cursor:pointer} +#bo_cate a:focus, #bo_cate a:hover, #bo_cate a:active {text-decoration:none} +#bo_cate #bo_cate_on {z-index:2;border:1px solid #565e60;background:#fff;color:#565e60;font-weight:bold} + +.td_subject img {margin-left:3px} + +/* 게시판 목록 공통 */ +.bo_fx {margin-bottom:5px;zoom:1} +.bo_fx:after {display:block;visibility:hidden;clear:both;content:""} +.bo_fx ul {margin:0;padding:0;list-style:none} +#bo_list_total {float:left;padding-top:5px} +.btn_bo_user {float:right;margin:0;padding:0;list-style:none} +.btn_bo_user li {float:left;margin-left:5px} +.btn_bo_adm {float:left} +.btn_bo_adm li {float:left;margin-right:5px} +.btn_bo_adm input {padding:0 10px;height:25px;border:1px solid #e8180c !important;background:#e8180c;color:#fff;text-decoration:none;vertical-align:middle;cursor:pointer} +.bo_notice td {background:#f5f6fa} +.bo_notice td a {font-weight:bold} +.td_num strong {color:#000} +.bo_cate_link {display:inline-block;margin:0 3px 0 0;padding:0 6px 0 0;border-right:1px solid #e7f1ed;color:#999 !important;font-weight:bold;text-decoration:none} /* 글제목줄 분류스타일 */ +.bo_current {color:#e8180c} +#bo_list .cnt_cmt {display:inline-block;margin:0 0 0 3px;font-weight:bold} + +#bo_sch {margin-bottom:10px;padding-top:5px;text-align:center} +#bo_sch legend {position:absolute;margin:0;padding:0;font-size:0;line-height:0;text-indent:-9999em;overflow:hidden} + +/* 게시판 쓰기 */ +#char_count_desc {display:block;margin:0 0 5px;padding:0} +#char_count_wrp {margin:5px 0 0;text-align:right} +#char_count {font-weight:bold} + +#autosave_wrapper {position:relative} +#autosave_pop {display:none;z-index:10;position:absolute;top:24px;right:117px;padding:8px;width:350px;height:auto !important;height:180px;max-height:180px;border:1px solid #565656;background:#fff;overflow-y:scroll} +html.no-overflowscrolling #autosave_pop {height:auto;max-height:10000px !important} /* overflow 미지원 기기 대응 */ +#autosave_pop strong {position:absolute;font-size:0;line-height:0;overflow:hidden} +#autosave_pop div {text-align:right} +#autosave_pop button {margin:0;padding:0;border:0;background:transparent} +#autosave_pop ul {margin:10px 0;padding:0;border-top:1px solid #e9e9e9;list-style:none} +#autosave_pop li {padding:8px 5px;border-bottom:1px solid #e9e9e9;zoom:1} +#autosave_pop li:after {display:block;visibility:hidden;clear:both;content:""} +#autosave_pop a {display:block;float:left} +#autosave_pop span {display:block;float:right} +.autosave_close {cursor:pointer} +.autosave_content {display:none} + +/* 게시판 읽기 */ +#bo_v {margin-bottom:20px;padding-bottom:20px} + +#bo_v_table {position:absolute;top:0;right:15px;margin:0;padding:0 5px;height:25px;background:#565e60;color:#fff;font-weight:bold;line-height:2.2em} + +#bo_v_title {padding:10px 0;font-size:1.2em} + +#bo_v_info {padding:0 0 10px;border-bottom:1px solid #ddd} +#bo_v_info h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_info strong {display:inline-block;margin:0 15px 0 5px;font-weight:normal} +#bo_v_info .sv_member, +#bo_v_info .sv_guest, +#bo_v_info .member, +#bo_v_info .guest {font-weight:bold} + +#bo_v_file {} +#bo_v_file h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_file ul {margin:0;padding:0;list-style:none} +#bo_v_file li {padding:0 10px;border-bottom:1px solid #eee;background:#f5f6fa} +#bo_v_file a {display:inline-block;padding:8px 0 7px;width:100%;color:#000;word-wrap:break-word} +#bo_v_file a:focus, #bo_v_file a:hover, #bo_v_file a:active {text-decoration:none} +#bo_v_file img {float:left;margin:0 10px 0 0} +.bo_v_file_cnt {display:inline-block;margin:0 0 3px 16px} + +#bo_v_link {} +#bo_v_link h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_link ul {margin:0;padding:0;list-style:none} +#bo_v_link li {padding:0 10px;border-bottom:1px solid #eee;background:#f5f6fa} +#bo_v_link a {display:inline-block;padding:8px 0 7px;width:100%;color:#000;word-wrap:break-word} +#bo_v_link a:focus, #bo_v_link a:hover, #bo_v_link a:active {text-decoration:none} +.bo_v_link_cnt {display:inline-block;margin:0 0 3px 16px} + +#bo_v_contact {border-bottom:1px solid #ddd} +#bo_v_contact h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_contact dl {margin:0;padding:0;list-style:none;zoom:1} +#bo_v_contact dl:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_contact dt, #bo_v_contact dd {float:left;margin:0;border-bottom:1px solid #eee;background:#f5f6fa} +#bo_v_contact dt {clear:both;padding:8px 0 8px 30px;width:100px;font-weight:bold} +#bo_v_contact dd {padding:8px 0;width:598px} + +#bo_v_top {margin:0 0 10px;padding:10px 0;zoom:1} +#bo_v_top:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_top h2 {margin:0;padding:0;height:0;overflow:hidden} +#bo_v_top ul {margin:0;padding:0;list-style:none} + +#bo_v_bot {zoom:1} +#bo_v_bot:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_bot h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_v_bot ul {margin:0;padding:0;list-style:none} + +.bo_v_nb {float:left} +.bo_v_nb li {float:left;margin-right:5px} +.bo_v_com {float:right} +.bo_v_com li {float:left;margin-left:5px} + +#bo_v_atc {min-height:100px;height:auto !important;height:100px} +#bo_v_atc_title {position:absolute;font-size:0;line-height:0;overflow:hidden} + +#bo_v_img {margin:0 0 10px;width:100%;overflow:hidden;zoom:1} +#bo_v_img:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_img img {margin-bottom:20px;max-width:100%;height:auto} + +#bo_v_con {margin-bottom:30px;width:100%;line-height:1.7em;word-break:break-all;overflow:hidden} +#bo_v_con a {color:#000;text-decoration:underline} +#bo_v_con img {max-width:100%;height:auto} + +#bo_v_act {margin-bottom:30px;text-align:center} +#bo_v_act a {margin-right:5px;vertical-align:top} +#bo_v_act span {display:inline-block;margin-right:5px;padding:0 10px;height:23px;border:1px solid #ccc !important;background:#fafafa !important;color:#000 !important;text-decoration:none !important;line-height:2.15em;vertical-align:top} +#bo_v_act strong {color:#ff3061} +#bo_v_act_good, +#bo_v_act_nogood {position:absolute;font-size:0;line-height:0;overflow:hidden} + +#bo_v_sns {margin:0 0 20px;padding:0;list-style:none;zoom:1} +#bo_v_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_v_sns li {float:left;margin:0 5px 0 0} + +#bo_v_addq {margin:0 0 30px;text-align:right} + +#bo_v_ans {margin:0 0 30px;padding:30px 0 0;border-top:1px solid #e9e9e9} +#bo_v_ans h2 {display:inline-block;vertical-align:middle;font-size:1.2em} +#bo_v_ans #ans_datetime {margin:10px 0;color:#999} +#bo_v_ans #ans_con {margin:0 0 10px;line-height:1.8em} +#bo_v_ans #ans_add {text-align:right} +#bo_v_ans #ans_msg {padding:40px 0;background:#f2f5f9;text-align:center} + +#bo_v_rel {margin:0 0 30px;padding:30px 0 0;border-top:1px solid #e9e9e9} +#bo_v_rel h2 {margin:0 0 10px;font-size:1.2em} + +#bo_v form {padding-top:20px} + +/* 게시판 댓글 */ +#bo_vc {padding:20px 20px 10px;border-top:1px solid #cfded8;border-bottom:1px solid #cfded8;background:#f5f6fa} +#bo_vc h2 {margin-bottom:10px} +#bo_vc article {padding:0 0 10px;border-top:1px dotted #ccc} +#bo_vc header {position:relative;padding:15px 0 5px} +#bo_vc header .icon_reply {position:absolute;top:15px;left:-20px} +#bo_vc .sv_wrap {margin-right:15px} +#bo_vc .member, #bo_vc .guest, #bo_vc .sv_member, #bo_vc .sv_guest {font-weight:bold} +.bo_vc_hdinfo {display:inline-block;margin:0 15px 0 5px} +#bo_vc h1 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_vc a {color:#000;text-decoration:none} +#bo_vc p {padding:0 0 5px;line-height:1.8em} +#bo_vc p a {text-decoration:underline} +#bo_vc_empty {margin:0;padding:20px !important;text-align:center} +#bo_vc fieldset {margin:0 0 10px;padding:0} +#bo_vc #bo_vc_winfo {float:left} +#bo_vc footer {zoom:1} +#bo_vc footer:after {display:block;visibility:hidden;clear:both;content:""} + +.bo_vc_act {float:right;margin:0;list-style:none;zoom:1} +.bo_vc_act:after {display:block;visibility:hidden;clear:both;content:""} +.bo_vc_act li {float:left;margin-left:5px} + +#bo_vc_w {position:relative;margin:0 0 10px;padding:0 0 20px;border-bottom:1px solid #cfded8} +#bo_vc_w h2 {position:absolute;font-size:0;line-height:0;overflow:hidden} +#bo_vc_w #char_cnt {display:block;margin:0 0 5px} + +#bo_vc_sns {margin:0;padding:0;list-style:none;zoom:1} +#bo_vc_sns:after {display:block;visibility:hidden;clear:both;content:""} +#bo_vc_sns li {float:left;margin:0 20px 0 0} +#bo_vc_sns input {margin:0 0 0 5px} + +#bo_vc form {padding:0} \ No newline at end of file diff --git a/theme/basic/skin/qa/basic/view.answer.skin.php b/theme/basic/skin/qa/basic/view.answer.skin.php new file mode 100644 index 000000000..357145d90 --- /dev/null +++ b/theme/basic/skin/qa/basic/view.answer.skin.php @@ -0,0 +1,25 @@ + + +
        +

        답변:

        + 추가질문 + +
        + +
        + +
        + +
        + +
        + + 답변수정 + + + 답변삭제 + +
        +
        \ No newline at end of file diff --git a/theme/basic/skin/qa/basic/view.answerform.skin.php b/theme/basic/skin/qa/basic/view.answerform.skin.php new file mode 100644 index 000000000..d77fd5422 --- /dev/null +++ b/theme/basic/skin/qa/basic/view.answerform.skin.php @@ -0,0 +1,125 @@ + + +
        + +

        답변등록

        + +
        + + + + + + '; + } else { + $option .= "\n".''."\n".''; + } + + echo $option_hidden; + ?> + +
        + + + + + + + + + + + + + + + + + +
        옵션
        + +
        +
        + +
        + +
        +
        + + + +

        고객님의 문의에 대한 답변을 준비 중입니다.

        + +
        \ No newline at end of file diff --git a/theme/basic/skin/qa/basic/view.skin.php b/theme/basic/skin/qa/basic/view.skin.php new file mode 100644 index 000000000..1caa5a63a --- /dev/null +++ b/theme/basic/skin/qa/basic/view.skin.php @@ -0,0 +1,187 @@ +', 0); +?> + + + + +
        + +
        +
        +

        + +

        +
        + +
        +

        페이지 정보

        + 작성자 + 작성일 +
        + + + +
        +

        첨부파일

        + +
        + + + + +
        +

        연락처정보

        +
        + +
        이메일
        +
        + + +
        휴대폰
        +
        + +
        +
        + + + +
        + + + + + + + +
        + + +
        +

        본문

        + + \n"; + + for ($i=0; $i<$view['img_count']; $i++) { + //echo $view['img_file'][$i]; + echo get_view_thumbnail($view['img_file'][$i], $qaconfig['qa_image_width']); + } + + echo "\n"; + } + ?> + + +
        + + + + + + +
        + + + + +
        +

        연관질문

        + +
        + + + + + + + + + + + + + + + + + + + +
        분류제목상태등록일
        + + + +
        +
        +
        + + + +
        + +
        + + +
        + + + \ No newline at end of file diff --git a/theme/basic/skin/qa/basic/write.skin.php b/theme/basic/skin/qa/basic/write.skin.php new file mode 100644 index 000000000..d81465a50 --- /dev/null +++ b/theme/basic/skin/qa/basic/write.skin.php @@ -0,0 +1,184 @@ +', 0); +?> + +
        + +
        + + + + + + '; + } else { + $option .= "\n".''."\n".''; + } + + echo $option_hidden; + ?> + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + +
        옵션
        + class="frm_input email" size="50" maxlength="100"> + > + +
        + class="frm_input" size="30"> + + > 답변등록 SMS알림 수신 + +
        + +
        + +
        파일 #1 + + + + +
        파일 #2 + + + + +
        +
        + +
        + + 목록 +
        +
        + + +
        + \ No newline at end of file diff --git a/theme/basic/skin/search/basic/search.skin.php b/theme/basic/skin/search/basic/search.skin.php new file mode 100644 index 000000000..e341efa3f --- /dev/null +++ b/theme/basic/skin/search/basic/search.skin.php @@ -0,0 +1,140 @@ +', 0); +?> + + +
        + +
        + 상세검색 + + + + + + + + + + + + id="sop_or" name="sop"> + + id="sop_and" name="sop"> + +
        +
        + +
        + + +
        +

        전체검색 결과

        +
        +
        게시판
        +
        +
        게시물
        +
        +
        +

        / 페이지 열람 중

        +
        + + + + + +
        검색된 자료가 하나도 없습니다.
        + + +
        + +
        + +

        게시판 내 결과

        +
          + 댓글 | '; + $comment_href = '#c_'.$list[$idx][$i]['wr_id']; + } + else + { + $comment_def = ''; + $comment_href = ''; + } + ?> + +
        • + + 새창 +

          + + +
        • + +
        + + +
        + +
        + + + +
        + \ No newline at end of file diff --git a/theme/basic/skin/search/basic/style.css b/theme/basic/skin/search/basic/style.css new file mode 100644 index 000000000..8adf23a45 --- /dev/null +++ b/theme/basic/skin/search/basic/style.css @@ -0,0 +1,29 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 전체검색결과 스킨 */ +#sch_res_detail {padding:0 0 10px;border-bottom:1px solid #e9e9e9;text-align:center} +#sch_res_detail legend {position:absolute;margin:0;padding:0;font-size:0;line-height:0;text-indent:-9999em;overflow:hidden} +#sch_res_ov {margin:0 0 10px;padding:10px;border-bottom:1px solid #e9e9e9;background:#f5f6fa;zoom:1} +#sch_res_ov:after {display:block;visibility:hidden;clear:both;content:""} +#sch_res_ov h2 {float:left} +#sch_res_ov dl {float:left;margin:0 0 0 10px} +#sch_res_ov dt {float:left} +#sch_res_ov dd {float:left;margin:0 10px 0 5px} +#sch_res_ov p {float:right;margin:0;padding:0;line-height:1em} + +#sch_res_board {margin:0 0 10px;padding-left:1px;list-style:none;zoom:1} +#sch_res_board:after {display:block;visibility:hidden;clear:both;content:""} +#sch_res_board li {float:left;margin-bottom:-1px} +#sch_res_board a {display:block;position:relative;margin-left:-1px;padding:6px 0 5px;width:180px;border:1px solid #ddd;text-align:center;letter-spacing:-0.1em;line-height:1.2em;cursor:pointer} +#sch_res_board a:focus, #sch_res_board a:hover, #sch_res_board a:active {text-decoration:none} +#sch_res_board .cnt_cmt {font-weight:normal !important} + +.sch_res_list {margin:0 0 10px;padding:10px 0 15px} +.sch_res_list h2 {margin:0 0 15px;font-size:1.2em} +.sch_res_list ul {margin:0;padding:0;list-style:none} +.sch_res_list li {margin:0 0 10px;padding:0 0 10px;border-bottom:1px solid #e9e9e9} +.sch_res_title {display:inline-block;margin:0 0 5px} +.sch_res_list p {margin:0 0 10px;line-height:1.8em} +.sch_more {text-align:right} +.sch_on {color:#ff3061} \ No newline at end of file diff --git a/theme/basic/skin/visit/basic/style.css b/theme/basic/skin/visit/basic/style.css new file mode 100644 index 000000000..6b061cb27 --- /dev/null +++ b/theme/basic/skin/visit/basic/style.css @@ -0,0 +1,13 @@ +@charset "utf-8"; +/* SIR 지운아빠 */ + +/* 방문자 집계 */ +#visit {border-bottom:1px dotted #dde4e9} +#visit div {margin:0 auto;width:970px;zoom:1} +#visit div:after {display:block;visibility:hidden;clear:both;content:""} +#visit h2 {float:left;padding:10px 45px 10px 0} +#visit dl {float:left;margin:0 0 0 10px;padding:0} +#visit dt {float:left;margin:0;padding:10px 0 10px} +#visit dd {float:left;margin:0 30px 0 0;padding:10px} +#visit a {display:inline-block;padding:10px;text-decoration:none} +#visit a:focus, #visit a:hover {} \ No newline at end of file diff --git a/theme/basic/skin/visit/basic/visit.skin.php b/theme/basic/skin/visit/basic/visit.skin.php new file mode 100644 index 000000000..87e481d2e --- /dev/null +++ b/theme/basic/skin/visit/basic/visit.skin.php @@ -0,0 +1,27 @@ +', 0); +?> + + +
        +
        +

        접속자집계

        +
        +
        오늘
        +
        +
        어제
        +
        +
        최대
        +
        +
        전체
        +
        +
        + 상세보기 +
        +
        + \ No newline at end of file diff --git a/theme/basic/tail.php b/theme/basic/tail.php new file mode 100644 index 000000000..f994ad894 --- /dev/null +++ b/theme/basic/tail.php @@ -0,0 +1,57 @@ + + + + + + + +
        + + +
        + + +
        <?php echo G5_VERSION ?>
        +
        +
        +
        +
        + 회사소개 + 개인정보취급방침 + 서비스이용약관 + Copyright © 소유하신 도메인. All rights reserved.
        + 상단으로 +
        +
        +
        + + +모바일 버전으로 보기 + + + + + + + \ No newline at end of file diff --git a/theme/basic/tail.sub.php b/theme/basic/tail.sub.php new file mode 100644 index 000000000..ec5920f63 --- /dev/null +++ b/theme/basic/tail.sub.php @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/theme/basic/theme.config.php b/theme/basic/theme.config.php new file mode 100644 index 000000000..ea81ad259 --- /dev/null +++ b/theme/basic/theme.config.php @@ -0,0 +1,34 @@ + false, // 기본환경설정의 최근게시물 등의 기본스킨 변경여부 true, false + 'preview_board_skin' => 'basic', // 테마 미리보기 때 적용될 기본 게시판 스킨 + 'preview_mobile_board_skin' => 'basic', // 테마 미리보기 때 적용될 기본 모바일 게시판 스킨 + 'cf_member_skin' => 'basic', // 회원 스킨 + 'cf_mobile_member_skin' => 'basic', // 모바일 회원 스킨 + 'cf_new_skin' => 'basic', // 최근게시물 스킨 + 'cf_mobile_new_skin' => 'basic', // 모바일 최근게시물 스킨 + 'cf_search_skin' => 'basic', // 검색 스킨 + 'cf_mobile_search_skin' => 'basic', // 모바일 검색 스킨 + 'cf_connect_skin' => 'basic', // 접속자 스킨 + 'cf_mobile_connect_skin' => 'basic', // 모바일 접속자 스킨 + 'cf_faq_skin' => 'basic', // FAQ 스킨 + 'cf_mobile_faq_skin' => 'basic', // 모바일 FAQ 스킨 + 'bo_gallery_cols' => 4, // 갤러리 이미지 수 + 'bo_gallery_width' => 174, // 갤러리 이미지 폭 + 'bo_gallery_height' => 124, // 갤러리 이미지 높이 + 'bo_mobile_gallery_width' => 125, // 모바일 갤러리 이미지 폭 + 'bo_mobile_gallery_height' => 100 // 모바일 갤러리 이미지 높이 +); +?> \ No newline at end of file From a757c437e2cc8a555475c40a7cb2c6f04e8a663e Mon Sep 17 00:00:00 2001 From: chicpro Date: Tue, 28 Jul 2015 18:14:36 +0900 Subject: [PATCH 02/21] =?UTF-8?q?=ED=85=8C=EB=A7=88=20=EB=AF=B8=EB=A6=AC?= =?UTF-8?q?=EB=B3=B4=EA=B8=B0=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adm/theme_preview.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adm/theme_preview.php b/adm/theme_preview.php index 170883d36..559db4e63 100644 --- a/adm/theme_preview.php +++ b/adm/theme_preview.php @@ -30,10 +30,10 @@ $write_table = $g5['write_prefix'] . $bo_table; $tconfig = get_theme_config_value($theme, 'set_default_skin, preview_board_skin, preview_mobile_board_skin'); if($mode == 'list' || $mode == 'view') { if($tconfig['preview_board_skin']) - $board['bo_skin'] = 'theme/'.$tconfig['preview_board_skin']; + $board['bo_skin'] = preg_match('#^theme/.+$#', $tconfig['preview_board_skin']) ? $tconfig['preview_board_skin'] : 'theme/'.$tconfig['preview_board_skin']; if($tconfig['preview_mobile_board_skin']) - $board['bo_mobile_skin'] = 'theme/'.$tconfig['preview_mobile_board_skin']; + $board['bo_mobile_skin'] = preg_match('#^theme/.+$#', $tconfig['preview_mobile_board_skin']) ? $tconfig['preview_mobile_board_skin'] : 'theme/'.$tconfig['preview_mobile_board_skin']; } // 스킨경로 From c103b9e6f3124ea1118e61620771073f5821565d Mon Sep 17 00:00:00 2001 From: chicpro Date: Wed, 29 Jul 2015 09:50:04 +0900 Subject: [PATCH 03/21] =?UTF-8?q?=ED=85=8C=EB=A7=88=EC=9D=98=201:1?= =?UTF-8?q?=EB=AC=B8=EC=9D=98=20=EC=8A=A4=ED=82=A8=20=EB=93=B1=EC=9D=98=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=ED=95=AD=EB=AA=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adm/board_form.php | 6 +++--- adm/theme.js | 4 ++-- adm/theme_config_load.php | 4 ++-- adm/theme_update.php | 20 +++++++++++++++++++- theme/basic/theme.config.php | 6 +++++- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/adm/board_form.php b/adm/board_form.php index c91fbb273..1d3664147 100644 --- a/adm/board_form.php +++ b/adm/board_form.php @@ -1117,7 +1117,7 @@ $frm_submit .= ''; -$#i', '', $frm_submit); ?> +$#i', '', $frm_submit); ?>

        게시판 포인트 설정

        @@ -1241,7 +1241,7 @@ $(function(){ }); $(".get_theme_galc").on("click", function() { - if(!confirm("현재 테마의 갤러리 이미지 설정을 적용하시겠습니까?")) + if(!confirm("현재 테마의 게시판 이미지 설정을 적용하시겠습니까?")) return false; $.ajax({ @@ -1257,7 +1257,7 @@ $(function(){ return false; } - var field = Array('bo_gallery_cols', 'bo_gallery_width', 'bo_gallery_height', 'bo_mobile_gallery_width', 'bo_mobile_gallery_height'); + var field = Array('bo_gallery_cols', 'bo_gallery_width', 'bo_gallery_height', 'bo_mobile_gallery_width', 'bo_mobile_gallery_height', 'bo_image_width'); var count = field.length; var key; diff --git a/adm/theme.js b/adm/theme.js index ad113c0fc..d20c53a60 100644 --- a/adm/theme.js +++ b/adm/theme.js @@ -8,7 +8,7 @@ $(function() { var set_default_skin = 0; if($(this).data("set_default_skin") == true) { - if(confirm("기본환경설정의 스킨을 테마에서 설정된 스킨으로 변경하시겠습니까?")) + if(confirm("기본환경설정, 1:1문의 스킨을 테마에서 설정된 스킨으로 변경하시겠습니까?\n\n변경을 선택하시면 테마에서 지정된 스킨으로 회원스킨 등이 변경됩니다.")) set_default_skin = 1; } @@ -36,7 +36,7 @@ $(function() { var theme = $(this).data("theme"); var name = $(this).data("name"); - if(!confirm(name+" 테마 사용설정을 해제하시겠습니까?")) + if(!confirm(name+" 테마 사용설정을 해제하시겠습니까?\n\n테마 설정을 해제하셔도 게시판 등의 스킨은 변경되지 않으므로 개별 변경작업이 필요합니다.")) return false; $.ajax({ diff --git a/adm/theme_config_load.php b/adm/theme_config_load.php index 69cc1acde..66561d960 100644 --- a/adm/theme_config_load.php +++ b/adm/theme_config_load.php @@ -29,7 +29,7 @@ if(!in_array($type, $arr_type)) { } if($type == 'board') { - $keys = array('bo_gallery_cols', 'bo_gallery_width', 'bo_gallery_height', 'bo_mobile_gallery_width', 'bo_mobile_gallery_height'); + $keys = array('bo_gallery_cols', 'bo_gallery_width', 'bo_gallery_height', 'bo_mobile_gallery_width', 'bo_mobile_gallery_height', 'bo_image_width'); $tconfig = get_theme_config_value($config['cf_theme'], implode(',', $keys)); $i = 0; @@ -41,7 +41,7 @@ if($type == 'board') { } if($i == 0) - $data['error'] = '적용할 갤러리 이미지 설정이 없습니다.'; + $data['error'] = '적용할 게시판 이미지 설정이 없습니다.'; } else if($type == 'conf_skin') { $keys = array('cf_new_skin', 'cf_mobile_new_skin', 'cf_search_skin', 'cf_mobile_search_skin', 'cf_connect_skin', 'cf_mobile_connect_skin', 'cf_faq_skin', 'cf_mobile_faq_skin'); diff --git a/adm/theme_update.php b/adm/theme_update.php index ca7f3e43f..e40f310d8 100644 --- a/adm/theme_update.php +++ b/adm/theme_update.php @@ -23,13 +23,26 @@ sql_query($sql); // 테마 설정 스킨 적용 if($_POST['set_default_skin'] == 1) { - $keys = 'set_default_skin, cf_member_skin, cf_mobile_member_skin, cf_new_skin, cf_mobile_new_skin, cf_search_skin, cf_mobile_search_skin, cf_connect_skin, cf_mobile_connect_skin, cf_faq_skin, cf_mobile_faq_skin'; + $keys = 'set_default_skin, cf_member_skin, cf_mobile_member_skin, cf_new_skin, cf_mobile_new_skin, cf_search_skin, cf_mobile_search_skin, cf_connect_skin, cf_mobile_connect_skin, cf_faq_skin, cf_mobile_faq_skin, qa_skin, qa_mobile_skin'; $tconfig = get_theme_config_value($theme, $keys); if($tconfig['set_default_skin']) { $sql_common = array(); + $qa_sql_common = array(); + foreach($tconfig as $key => $val) { + if(preg_match('#^qa_.+$#', $key)) { + if($val) { + if(!preg_match('#^theme/.+$#', $val)) + $val = 'theme/'.$val; + + $qa_sql_common[] = " $key = '$val' "; + } + + continue; + } + if(!isset($config[$key])) continue; @@ -45,6 +58,11 @@ if($_POST['set_default_skin'] == 1) { $sql = " update {$g5['config_table']} set " . implode(', ', $sql_common); sql_query($sql); } + + if(!empty($qa_sql_common)) { + $sql = " update {$g5['qa_config_table']} set " . implode(', ', $qa_sql_common); + sql_query($sql); + } } } diff --git a/theme/basic/theme.config.php b/theme/basic/theme.config.php index ea81ad259..f900e773f 100644 --- a/theme/basic/theme.config.php +++ b/theme/basic/theme.config.php @@ -10,6 +10,7 @@ $theme_config = array(); // 갤러리 이미지 수 등의 설정을 지정하시면 게시판관리에서 해당 값을 // 가져오기 기능을 통해 게시판 설정의 해당 필드에 바로 적용할 수 있습니다. +// 사용하지 않는 스킨 설정은 값을 비워두시면 됩니다. $theme_config = array( 'set_default_skin' => false, // 기본환경설정의 최근게시물 등의 기본스킨 변경여부 true, false @@ -29,6 +30,9 @@ $theme_config = array( 'bo_gallery_width' => 174, // 갤러리 이미지 폭 'bo_gallery_height' => 124, // 갤러리 이미지 높이 'bo_mobile_gallery_width' => 125, // 모바일 갤러리 이미지 폭 - 'bo_mobile_gallery_height' => 100 // 모바일 갤러리 이미지 높이 + 'bo_mobile_gallery_height' => 100, // 모바일 갤러리 이미지 높이 + 'bo_image_width' => 600, // 게시판 뷰 이미지 폭 + 'qa_skin' => 'basic', // 1:1문의 스킨 + 'qa_mobile_skin' => 'basic' // 1:1문의 모바일 스킨 ); ?> \ No newline at end of file From db83fba992ab0828459cd328df44dd09d8d7e476 Mon Sep 17 00:00:00 2001 From: chicpro Date: Wed, 29 Jul 2015 10:48:38 +0900 Subject: [PATCH 04/21] =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EC=B6=94=EA=B0=80=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=84=A4=EC=A0=95=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adm/config_form.php | 28 ++-------------------------- adm/config_form_update.php | 3 --- install/gnuboard5.sql | 3 --- 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/adm/config_form.php b/adm/config_form.php index c12b65ac9..eafa0ebb0 100644 --- a/adm/config_form.php +++ b/adm/config_form.php @@ -9,12 +9,9 @@ $token = get_token(); if ($is_admin != 'super') alert('최고관리자만 접근 가능합니다.'); -if (!isset($config['cf_include_index'])) { +if (!isset($config['cf_add_script'])) { sql_query(" ALTER TABLE `{$g5['config_table']}` - ADD `cf_include_index` VARCHAR(255) NOT NULL AFTER `cf_admin`, - ADD `cf_include_head` VARCHAR(255) NOT NULL AFTER `cf_include_index`, - ADD `cf_include_tail` VARCHAR(255) NOT NULL AFTER `cf_include_head`, - ADD `cf_add_script` TEXT NOT NULL AFTER `cf_include_tail` ", true); + ADD `cf_add_script` TEXT NOT NULL AFTER `cf_admin_email_name` ", true); } if (!isset($config['cf_mobile_new_skin'])) { @@ -1002,27 +999,6 @@ if ($config['cf_icode_id'] && $config['cf_icode_pw']) { - - - - 초기화면 파일은 index.php 파일과 동일한 위치에 존재해야 합니다.') ?> - - - - - - - 상단 파일은 head.php 파일과 동일한 위치에 존재해야 합니다.') ?> - - - - - - - 초기화면 파일은 tail.php 파일과 동일한 위치에 존재해야 합니다.') ?> - - - diff --git a/adm/config_form_update.php b/adm/config_form_update.php index c82dbd28b..7c2c7891b 100644 --- a/adm/config_form_update.php +++ b/adm/config_form_update.php @@ -29,9 +29,6 @@ $sql = " update {$g5['config_table']} cf_admin = '{$_POST['cf_admin']}', cf_admin_email = '{$_POST['cf_admin_email']}', cf_admin_email_name = '{$_POST['cf_admin_email_name']}', - cf_include_index = '{$_POST['cf_include_index']}', - cf_include_head = '{$_POST['cf_include_head']}', - cf_include_tail = '{$_POST['cf_include_tail']}', cf_add_script = '{$_POST['cf_add_script']}', cf_use_point = '{$_POST['cf_use_point']}', cf_point_term = '{$_POST['cf_point_term']}', diff --git a/install/gnuboard5.sql b/install/gnuboard5.sql index ce6977937..b960a9326 100644 --- a/install/gnuboard5.sql +++ b/install/gnuboard5.sql @@ -189,9 +189,6 @@ CREATE TABLE IF NOT EXISTS `g5_config` ( `cf_admin` varchar(255) NOT NULL DEFAULT '', `cf_admin_email` varchar(255) NOT NULL DEFAULT '', `cf_admin_email_name` varchar(255) NOT NULL DEFAULT '', - `cf_include_index` varchar(255) NOT NULL DEFAULT '', - `cf_include_head` varchar(255) NOT NULL DEFAULT '', - `cf_include_tail` varchar(255) NOT NULL DEFAULT '', `cf_add_script` text NOT NULL, `cf_use_point` tinyint(4) NOT NULL DEFAULT '0', `cf_point_term` int(11) NOT NULL DEFAULT '0', From ee8e184c10ec7379ec10c5f6053bc77e40275f32 Mon Sep 17 00:00:00 2001 From: chicpro Date: Thu, 30 Jul 2015 10:57:22 +0900 Subject: [PATCH 05/21] =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=A7=81=20=ED=85=8C?= =?UTF-8?q?=EB=A7=88=20uri=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- theme/basic/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/basic/readme.txt b/theme/basic/readme.txt index 7e1102ba6..17ed951b7 100644 --- a/theme/basic/readme.txt +++ b/theme/basic/readme.txt @@ -1,5 +1,5 @@ Theme Name: 베이직 -Theme URI: http://demo.sir.co.kr/gnuboard5 +Theme URI: http://theme.sir.co.kr/gnuboard5/demo/basic Maker: SIR Maker URI: http://sir.co.kr Version: 1.0.0 From 23f56520e271c635c0c8b661e22541c5f6e7d718 Mon Sep 17 00:00:00 2001 From: chicpro Date: Fri, 31 Jul 2015 10:08:41 +0900 Subject: [PATCH 06/21] =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adm/faqform.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adm/faqform.php b/adm/faqform.php index 19ed0894d..bce421e89 100644 --- a/adm/faqform.php +++ b/adm/faqform.php @@ -8,7 +8,7 @@ auth_check($auth[$sub_menu], "w"); $sql = " select * from {$g5['faq_master_table']} where fm_id = '$fm_id' "; $fm = sql_fetch($sql); -$html_title = 'FAQ '.$fm['fm_subject'];; +$html_title = 'FAQ '.$fm['fm_subject']; if ($w == "u") { From 7d4d645935f44e91658be1f491e76a31be4337d7 Mon Sep 17 00:00:00 2001 From: chicpro Date: Fri, 31 Jul 2015 16:55:48 +0900 Subject: [PATCH 07/21] =?UTF-8?q?kcp=20=EB=B3=B8=EC=9D=B8=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20up=5Fhash=20=EB=88=84=EB=9D=BD=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/kcpcert/kcpcert_form.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/plugin/kcpcert/kcpcert_form.php b/plugin/kcpcert/kcpcert_form.php index 64702cc3e..8a62e0c39 100644 --- a/plugin/kcpcert/kcpcert_form.php +++ b/plugin/kcpcert/kcpcert_form.php @@ -4,12 +4,41 @@ include_once('./_common.php'); // 금일 인증시도 회수 체크 certify_count_check($member['mb_id'], 'hp'); +setlocale(LC_CTYPE, 'ko_KR.euc-kr'); + // kcp 휴대폰인증파일 include_once(G5_KCPCERT_PATH.'/kcpcert_config.php'); $ordr_idxx = get_session('ss_uniqid'); if(!$ordr_idxx) $ordr_idxx = get_uniqid(); + +$ct_cert = new C_CT_CLI; +$ct_cert->mf_clear(); + +$year = "00"; +$month = "00"; +$day = "00"; +$user_name = ""; +$sex_code = ""; +$local_code = ""; + +// !!up_hash 데이터 생성시 주의 사항 +// year , month , day 가 비어 있는 경우 "00" , "00" , "00" 으로 설정이 됩니다 +// 그외의 값은 없을 경우 ""(null) 로 세팅하시면 됩니다. +// up_hash 데이터 생성시 site_cd 와 ordr_idxx 는 필수 값입니다. +$hash_data = $site_cd . + $ordr_idxx . + $user_name . + $year . + $month . + $day . + $sex_code . + $local_code; + +$up_hash = $ct_cert->make_hash_data( $home_dir, $hash_data ); + +$ct_cert->mf_clear(); ?>
        @@ -41,6 +70,8 @@ if(!$ordr_idxx) + + From 5ba1a602fe4a1a9b498064e7123c973c8a659f30 Mon Sep 17 00:00:00 2001 From: chicpro Date: Mon, 3 Aug 2015 15:36:15 +0900 Subject: [PATCH 08/21] =?UTF-8?q?=EB=B2=84=EC=A0=84=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.php b/config.php index 150d997d2..48f73aa44 100644 --- a/config.php +++ b/config.php @@ -5,7 +5,7 @@ ********************/ define('G5_VERSION', '그누보드5'); -define('G5_GNUBOARD_VER', '5.0.42'); +define('G5_GNUBOARD_VER', '5.1.0'); // 이 상수가 정의되지 않으면 각각의 개별 페이지는 별도로 실행될 수 없음 define('_GNUBOARD_', true); From 45e6bcf26f2a2f997e9841d7b4f4efb68bd4f8f4 Mon Sep 17 00:00:00 2001 From: chicpro Date: Tue, 4 Aug 2015 09:00:32 +0900 Subject: [PATCH 09/21] =?UTF-8?q?=ED=88=AC=ED=8F=AC=20=ED=85=8C=EB=A7=88?= =?UTF-8?q?=20=EC=8A=A4=ED=82=A8=20=EC=A0=81=EC=9A=A9=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bbs/poll_result.php | 23 +++++++++++++++---- lib/poll.lib.php | 2 +- .../mobile/skin/poll/basic/poll.skin.php | 4 ++-- .../skin/poll/basic/poll_result.skin.php | 4 ++-- theme/basic/skin/poll/basic/poll.skin.php | 4 ++-- .../skin/poll/basic/poll_result.skin.php | 4 ++-- 6 files changed, 27 insertions(+), 14 deletions(-) diff --git a/bbs/poll_result.php b/bbs/poll_result.php index 0866439a8..939758de6 100644 --- a/bbs/poll_result.php +++ b/bbs/poll_result.php @@ -85,12 +85,25 @@ for ($i=0; $row2=sql_fetch_array($result); $i++) { $list3[$i]['subject'] = cut_str($row2['po_subject'],60,"…"); } -if (G5_IS_MOBILE) { - $poll_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; - $poll_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; +if(preg_match('#^theme/(.+)$#', $skin_dir, $match)) { + if (G5_IS_MOBILE) { + $poll_skin_path = G5_THEME_MOBILE_PATH.'/'.G5_SKIN_DIR.'/poll/'.$match[1]; + if(!is_dir($poll_skin_path)) + $poll_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/poll/'.$match[1]; + $poll_skin_url = str_replace(G5_PATH, G5_URL, $poll_skin_path); + } else { + $poll_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/poll/'.$match[1]; + $poll_skin_url = str_replace(G5_PATH, G5_URL, $poll_skin_path); + } + //$skin_dir = $match[1]; } else { - $poll_skin_path = G5_SKIN_PATH.'/poll/'.$skin_dir; - $poll_skin_url = G5_SKIN_URL.'/poll/'.$skin_dir; + if (G5_IS_MOBILE) { + $poll_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; + $poll_skin_url = G5_MOBILE_URL.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; + } else { + $poll_skin_path = G5_SKIN_PATH.'/poll/'.$skin_dir; + $poll_skin_url = G5_SKIN_URL.'/poll/'.$skin_dir; + } } include_once(G5_PATH.'/head.sub.php'); diff --git a/lib/poll.lib.php b/lib/poll.lib.php index f45693c8d..3ffa1d770 100644 --- a/lib/poll.lib.php +++ b/lib/poll.lib.php @@ -25,7 +25,7 @@ function poll($skin_dir='basic', $po_id=false) $poll_skin_path = G5_THEME_PATH.'/'.G5_SKIN_DIR.'/poll/'.$match[1]; $poll_skin_url = str_replace(G5_PATH, G5_URL, $poll_skin_path); } - $skin_dir = $match[1]; + //$skin_dir = $match[1]; } else { if (G5_IS_MOBILE) { $poll_skin_path = G5_MOBILE_PATH.'/'.G5_SKIN_DIR.'/poll/'.$skin_dir; diff --git a/theme/basic/mobile/skin/poll/basic/poll.skin.php b/theme/basic/mobile/skin/poll/basic/poll.skin.php index 3585bbf6a..2dbdc1033 100644 --- a/theme/basic/mobile/skin/poll/basic/poll.skin.php +++ b/theme/basic/mobile/skin/poll/basic/poll.skin.php @@ -7,7 +7,7 @@ add_stylesheet('', 0) - + diff --git a/theme/basic/mobile/skin/poll/basic/poll_result.skin.php b/theme/basic/mobile/skin/poll/basic/poll_result.skin.php index 451d92217..65c0eb70f 100644 --- a/theme/basic/mobile/skin/poll/basic/poll_result.skin.php +++ b/theme/basic/mobile/skin/poll/basic/poll_result.skin.php @@ -56,7 +56,7 @@ add_stylesheet('', 0)
        - +

        @@ -93,7 +93,7 @@ add_stylesheet('', 0)

        다른 투표 결과 보기

        diff --git a/theme/basic/skin/poll/basic/poll.skin.php b/theme/basic/skin/poll/basic/poll.skin.php index 05d3260e1..e9bee3333 100644 --- a/theme/basic/skin/poll/basic/poll.skin.php +++ b/theme/basic/skin/poll/basic/poll.skin.php @@ -8,7 +8,7 @@ add_stylesheet('', 0) - +

        설문조사

        @@ -22,7 +22,7 @@ add_stylesheet('', 0)
        diff --git a/theme/basic/skin/poll/basic/poll_result.skin.php b/theme/basic/skin/poll/basic/poll_result.skin.php index 4741f5941..a19233b4c 100644 --- a/theme/basic/skin/poll/basic/poll_result.skin.php +++ b/theme/basic/skin/poll/basic/poll_result.skin.php @@ -60,7 +60,7 @@ add_stylesheet('', 0)
        - +

        @@ -102,7 +102,7 @@ add_stylesheet('', 0)

        다른 투표 결과 보기

        From adeb007cb053af11fa51403b85f31a13f4f043cd Mon Sep 17 00:00:00 2001 From: chicpro Date: Tue, 4 Aug 2015 10:41:16 +0900 Subject: [PATCH 10/21] =?UTF-8?q?parse=5Furl=20=ED=95=A8=EC=88=98=EC=97=90?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8A=94?= =?UTF-8?q?=20=EC=98=A4=EB=A5=98=20=EB=8C=80=EC=9D=91=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bbs/logout.php | 6 +++--- common.php | 2 +- lib/common.lib.php | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bbs/logout.php b/bbs/logout.php index 7aa5f34b9..3bcb99cef 100644 --- a/bbs/logout.php +++ b/bbs/logout.php @@ -2,8 +2,8 @@ include_once('./_common.php'); // 이호경님 제안 코드 -session_unset(); // 모든 세션변수를 언레지스터 시켜줌 -session_destroy(); // 세션해제함 +session_unset(); // 모든 세션변수를 언레지스터 시켜줌 +session_destroy(); // 세션해제함 // 자동로그인 해제 -------------------------------- set_cookie('ck_mb_id', '', 0); @@ -11,7 +11,7 @@ set_cookie('ck_auto', '', 0); // 자동로그인 해제 end -------------------------------- if ($url) { - $p = parse_url($url); + $p = @parse_url($url); if ($p['scheme'] || $p['host']) { alert('url에 도메인을 지정할 수 없습니다.'); } diff --git a/common.php b/common.php index 2d7afe328..89fa4f8da 100644 --- a/common.php +++ b/common.php @@ -319,7 +319,7 @@ if (isset($_REQUEST['url'])) { $url = ''; $urlencode = urlencode($_SERVER['REQUEST_URI']); if (G5_DOMAIN) { - $p = parse_url(G5_DOMAIN); + $p = @parse_url(G5_DOMAIN); $urlencode = G5_DOMAIN.urldecode(preg_replace("/^".urlencode($p['path'])."/", "", $urlencode)); } } diff --git a/lib/common.lib.php b/lib/common.lib.php index c5baf7d4e..51561d7b0 100644 --- a/lib/common.lib.php +++ b/lib/common.lib.php @@ -2066,7 +2066,7 @@ function delete_editor_thumbnail($contents) for($i=0; $i Date: Tue, 18 Aug 2015 10:02:49 +0900 Subject: [PATCH 11/21] =?UTF-8?q?SMS=20=EC=82=AC=EC=9A=A9=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=A0=81=EC=9A=A9=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adm/config_form.php | 2 +- adm/sms_admin/config.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/adm/config_form.php b/adm/config_form.php index eafa0ebb0..6535f2272 100644 --- a/adm/config_form.php +++ b/adm/config_form.php @@ -209,7 +209,7 @@ $frm_submit = '
        if (!$config['cf_icode_server_ip']) $config['cf_icode_server_ip'] = '211.172.232.124'; if (!$config['cf_icode_server_port']) $config['cf_icode_server_port'] = '7295'; -if ($config['cf_icode_id'] && $config['cf_icode_pw']) { +if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) { $userinfo = get_icode_userinfo($config['cf_icode_id'], $config['cf_icode_pw']); } ?> diff --git a/adm/sms_admin/config.php b/adm/sms_admin/config.php index 017b5a333..858cfb313 100644 --- a/adm/sms_admin/config.php +++ b/adm/sms_admin/config.php @@ -9,7 +9,7 @@ $g5['title'] = "SMS 기본설정"; if (!$config['cf_icode_server_ip']) $config['cf_icode_server_ip'] = '211.172.232.124'; if (!$config['cf_icode_server_port']) $config['cf_icode_server_port'] = '7295'; -if ($config['cf_icode_id'] && $config['cf_icode_pw']) +if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) { $userinfo = get_icode_userinfo($config['cf_icode_id'], $config['cf_icode_pw']); } From f9d415d4d795e711464c939ba6d6ffed82bba56c Mon Sep 17 00:00:00 2001 From: chicpro Date: Tue, 18 Aug 2015 15:11:21 +0900 Subject: [PATCH 12/21] =?UTF-8?q?sql=5Fmode=20=EC=B2=B4=ED=81=AC=20?= =?UTF-8?q?=ED=9B=84=20=EB=8C=80=EC=9D=91=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install/install_db.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/install/install_db.php b/install/install_db.php index f7fbf935f..d32745f86 100644 --- a/install/install_db.php +++ b/install/install_db.php @@ -53,10 +53,12 @@ if (!$select_db) { $mysql_set_mode = 'false'; @mysql_query('set names utf8'); -if(version_compare(mysql_get_server_info(), '5.6.6', '>=') == 1) { +$row = mysql_fetch_assoc(mysql_query(" SELECT @@sql_mode as mode ")); +if($row['mode']) { @mysql_query("SET SESSION sql_mode = ''"); $mysql_set_mode = 'true'; } +unset($row); ?>
        From 1d3edaf62e4e76bd3f4db81715cfbe956c2c304a Mon Sep 17 00:00:00 2001 From: chicpro Date: Tue, 4 Aug 2015 10:41:16 +0900 Subject: [PATCH 13/21] =?UTF-8?q?parse=5Furl=20=ED=95=A8=EC=88=98=EC=97=90?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8A=94?= =?UTF-8?q?=20=EC=98=A4=EB=A5=98=20=EB=8C=80=EC=9D=91=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bbs/logout.php | 6 +++--- common.php | 2 +- lib/common.lib.php | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bbs/logout.php b/bbs/logout.php index 7aa5f34b9..3bcb99cef 100644 --- a/bbs/logout.php +++ b/bbs/logout.php @@ -2,8 +2,8 @@ include_once('./_common.php'); // 이호경님 제안 코드 -session_unset(); // 모든 세션변수를 언레지스터 시켜줌 -session_destroy(); // 세션해제함 +session_unset(); // 모든 세션변수를 언레지스터 시켜줌 +session_destroy(); // 세션해제함 // 자동로그인 해제 -------------------------------- set_cookie('ck_mb_id', '', 0); @@ -11,7 +11,7 @@ set_cookie('ck_auto', '', 0); // 자동로그인 해제 end -------------------------------- if ($url) { - $p = parse_url($url); + $p = @parse_url($url); if ($p['scheme'] || $p['host']) { alert('url에 도메인을 지정할 수 없습니다.'); } diff --git a/common.php b/common.php index 2d7afe328..89fa4f8da 100644 --- a/common.php +++ b/common.php @@ -319,7 +319,7 @@ if (isset($_REQUEST['url'])) { $url = ''; $urlencode = urlencode($_SERVER['REQUEST_URI']); if (G5_DOMAIN) { - $p = parse_url(G5_DOMAIN); + $p = @parse_url(G5_DOMAIN); $urlencode = G5_DOMAIN.urldecode(preg_replace("/^".urlencode($p['path'])."/", "", $urlencode)); } } diff --git a/lib/common.lib.php b/lib/common.lib.php index c5baf7d4e..51561d7b0 100644 --- a/lib/common.lib.php +++ b/lib/common.lib.php @@ -2066,7 +2066,7 @@ function delete_editor_thumbnail($contents) for($i=0; $i Date: Tue, 18 Aug 2015 10:02:49 +0900 Subject: [PATCH 14/21] =?UTF-8?q?SMS=20=EC=82=AC=EC=9A=A9=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=A0=81=EC=9A=A9=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adm/config_form.php | 2 +- adm/sms_admin/config.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/adm/config_form.php b/adm/config_form.php index eafa0ebb0..6535f2272 100644 --- a/adm/config_form.php +++ b/adm/config_form.php @@ -209,7 +209,7 @@ $frm_submit = '
        if (!$config['cf_icode_server_ip']) $config['cf_icode_server_ip'] = '211.172.232.124'; if (!$config['cf_icode_server_port']) $config['cf_icode_server_port'] = '7295'; -if ($config['cf_icode_id'] && $config['cf_icode_pw']) { +if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) { $userinfo = get_icode_userinfo($config['cf_icode_id'], $config['cf_icode_pw']); } ?> diff --git a/adm/sms_admin/config.php b/adm/sms_admin/config.php index 017b5a333..858cfb313 100644 --- a/adm/sms_admin/config.php +++ b/adm/sms_admin/config.php @@ -9,7 +9,7 @@ $g5['title'] = "SMS 기본설정"; if (!$config['cf_icode_server_ip']) $config['cf_icode_server_ip'] = '211.172.232.124'; if (!$config['cf_icode_server_port']) $config['cf_icode_server_port'] = '7295'; -if ($config['cf_icode_id'] && $config['cf_icode_pw']) +if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) { $userinfo = get_icode_userinfo($config['cf_icode_id'], $config['cf_icode_pw']); } From e1ef69a0c48d689cebc9db70929597b81f910f3e Mon Sep 17 00:00:00 2001 From: chicpro Date: Tue, 18 Aug 2015 15:11:21 +0900 Subject: [PATCH 15/21] =?UTF-8?q?sql=5Fmode=20=EC=B2=B4=ED=81=AC=20?= =?UTF-8?q?=ED=9B=84=20=EB=8C=80=EC=9D=91=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install/install_db.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/install/install_db.php b/install/install_db.php index f7fbf935f..d32745f86 100644 --- a/install/install_db.php +++ b/install/install_db.php @@ -53,10 +53,12 @@ if (!$select_db) { $mysql_set_mode = 'false'; @mysql_query('set names utf8'); -if(version_compare(mysql_get_server_info(), '5.6.6', '>=') == 1) { +$row = mysql_fetch_assoc(mysql_query(" SELECT @@sql_mode as mode ")); +if($row['mode']) { @mysql_query("SET SESSION sql_mode = ''"); $mysql_set_mode = 'true'; } +unset($row); ?>
        From 58902f97c4eb8a9d1275b465743be99d3d8255c3 Mon Sep 17 00:00:00 2001 From: kagla Date: Thu, 20 Aug 2015 18:33:36 +0900 Subject: [PATCH 16/21] =?UTF-8?q?escapeshellarg=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9D=BC=EB=B6=80=EC=84=9C=EB=B2=84?= =?UTF-8?q?=EC=9D=98=20=EA=B2=BD=EC=9A=B0=20=EB=B9=88=EA=B0=92=EC=9D=BC?= =?UTF-8?q?=EB=95=8C=20''=20=EA=B2=B0=EA=B3=BC=EA=B0=80=20=EB=84=98?= =?UTF-8?q?=EC=96=B4=EC=98=A4=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=EA=B0=80=20=EC=9E=88=EC=8A=B5=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/kcpcert/lib/ct_cli_lib.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin/kcpcert/lib/ct_cli_lib.php b/plugin/kcpcert/lib/ct_cli_lib.php index cdd5d8177..77c629bd3 100644 --- a/plugin/kcpcert/lib/ct_cli_lib.php +++ b/plugin/kcpcert/lib/ct_cli_lib.php @@ -93,7 +93,9 @@ class C_CT_CLI while ( list(,$i) = each($arg) ) { - $exec_cmd .= " " . escapeshellarg( $i ); + // 일부서버의 경우 빈값일때 '' 결과가 넘어오지 않는 버그가 있다. kagla 150820 + //$exec_cmd .= " " . escapeshellarg( $i ); + $exec_cmd .= " " . ( escapeshellarg($i) ? escapeshellarg($i) : "''" ); } $rt = exec( $exec_cmd ); From 36e88a6a2dffea9580ef975110968f534596cc68 Mon Sep 17 00:00:00 2001 From: kagla Date: Fri, 21 Aug 2015 17:44:21 +0900 Subject: [PATCH 17/21] =?UTF-8?q?=EC=8D=B8=EB=84=A4=EC=9D=BC=EC=9D=98=20?= =?UTF-8?q?=EC=98=A4=EB=A6=AC=EC=A7=80=EB=84=90=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20ori=20=EB=A1=9C=20?= =?UTF-8?q?=EB=84=98=EA=B8=B0=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/thumbnail.lib.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/thumbnail.lib.php b/lib/thumbnail.lib.php index 15ad429fc..a40cb99e4 100644 --- a/lib/thumbnail.lib.php +++ b/lib/thumbnail.lib.php @@ -59,15 +59,19 @@ function get_list_thumbnail($bo_table, $wr_id, $thumb_width, $thumb_height, $is_ if($tname) { if($edt) { + // 오리지날 이미지 + $ori = G5_URL.$data_path; + // 썸네일 이미지 $src = G5_URL.str_replace($filename, $tname, $data_path); } else { + $ori = G5_DATA_URL.'/file/'.$bo_table.'/'.$filename; $src = G5_DATA_URL.'/file/'.$bo_table.'/'.$tname; } } else { return false; } - $thumb = array("src"=>$src, "alt"=>$alt); + $thumb = array("src"=>$src, "ori"=>$ori, "alt"=>$alt); return $thumb; } From 9337c6d7aab555996f4473df5b1ff2930020e8cd Mon Sep 17 00:00:00 2001 From: chicpro Date: Wed, 26 Aug 2015 10:47:11 +0900 Subject: [PATCH 18/21] =?UTF-8?q?=EB=AA=A8=EB=B0=94=EC=9D=BC=20=EC=AA=BD?= =?UTF-8?q?=EC=A7=80=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=82=B4=EC=9A=A9?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/skin/member/basic/memo.skin.php | 2 +- theme/basic/mobile/skin/member/basic/memo.skin.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/skin/member/basic/memo.skin.php b/mobile/skin/member/basic/memo.skin.php index 2d2174b1c..fafd275a2 100644 --- a/mobile/skin/member/basic/memo.skin.php +++ b/mobile/skin/member/basic/memo.skin.php @@ -21,7 +21,7 @@ add_stylesheet('',
        • - 에 받은 쪽지 + 쪽지 삭제 diff --git a/theme/basic/mobile/skin/member/basic/memo.skin.php b/theme/basic/mobile/skin/member/basic/memo.skin.php index 2d2174b1c..fafd275a2 100644 --- a/theme/basic/mobile/skin/member/basic/memo.skin.php +++ b/theme/basic/mobile/skin/member/basic/memo.skin.php @@ -21,7 +21,7 @@ add_stylesheet('',
          • - 에 받은 쪽지 + 쪽지 삭제 From 5321ce17d4c5abf50a92d0b7971ad7e8defb8e49 Mon Sep 17 00:00:00 2001 From: chicpro Date: Fri, 28 Aug 2015 11:31:45 +0900 Subject: [PATCH 19/21] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=EA=B8=80?= =?UTF-8?q?=ED=98=84=ED=99=A9=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adm/admin.menu300.php | 1 + adm/css/admin.css | 13 +- adm/write_count.php | 210 + plugin/jqplot/MIT-LICENSE.txt | 21 + plugin/jqplot/excanvas.js | 1438 ++ plugin/jqplot/excanvas.min.js | 3 + plugin/jqplot/jqplot.barRenderer.min.js | 3 + .../jqplot/jqplot.categoryAxisRenderer.min.js | 3 + plugin/jqplot/jqplot.pointLabels.min.js | 3 + plugin/jqplot/jquery.jqplot.css | 261 + plugin/jqplot/jquery.jqplot.js | 11411 ++++++++++++++++ plugin/jqplot/jquery.jqplot.min.css | 1 + plugin/jqplot/jquery.jqplot.min.js | 3 + .../plugins/jqplot.BezierCurveRenderer.js | 314 + .../plugins/jqplot.BezierCurveRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.barRenderer.js | 801 ++ .../jqplot/plugins/jqplot.barRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.blockRenderer.js | 235 + .../plugins/jqplot.blockRenderer.min.js | 3 + .../jqplot/plugins/jqplot.bubbleRenderer.js | 759 + .../plugins/jqplot.bubbleRenderer.min.js | 3 + .../plugins/jqplot.canvasAxisLabelRenderer.js | 203 + .../jqplot.canvasAxisLabelRenderer.min.js | 3 + .../plugins/jqplot.canvasAxisTickRenderer.js | 253 + .../jqplot.canvasAxisTickRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.canvasOverlay.js | 1021 ++ .../plugins/jqplot.canvasOverlay.min.js | 3 + .../plugins/jqplot.canvasTextRenderer.js | 449 + .../plugins/jqplot.canvasTextRenderer.min.js | 3 + .../plugins/jqplot.categoryAxisRenderer.js | 679 + .../jqplot.categoryAxisRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.ciParser.js | 116 + plugin/jqplot/plugins/jqplot.ciParser.min.js | 3 + plugin/jqplot/plugins/jqplot.cursor.js | 1108 ++ plugin/jqplot/plugins/jqplot.cursor.min.js | 3 + .../jqplot/plugins/jqplot.dateAxisRenderer.js | 741 + .../plugins/jqplot.dateAxisRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.donutRenderer.js | 805 ++ .../plugins/jqplot.donutRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.dragable.js | 225 + plugin/jqplot/plugins/jqplot.dragable.min.js | 3 + .../plugins/jqplot.enhancedLegendRenderer.js | 305 + .../jqplot.enhancedLegendRenderer.min.js | 3 + .../jqplot/plugins/jqplot.funnelRenderer.js | 943 ++ .../plugins/jqplot.funnelRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.highlighter.js | 465 + .../jqplot/plugins/jqplot.highlighter.min.js | 3 + plugin/jqplot/plugins/jqplot.json2.js | 475 + plugin/jqplot/plugins/jqplot.json2.min.js | 3 + .../jqplot/plugins/jqplot.logAxisRenderer.js | 534 + .../plugins/jqplot.logAxisRenderer.min.js | 3 + .../plugins/jqplot.mekkoAxisRenderer.js | 611 + .../plugins/jqplot.mekkoAxisRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.mekkoRenderer.js | 437 + .../plugins/jqplot.mekkoRenderer.min.js | 3 + .../plugins/jqplot.meterGaugeRenderer.js | 1029 ++ .../plugins/jqplot.meterGaugeRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.mobile.js | 45 + plugin/jqplot/plugins/jqplot.mobile.min.js | 3 + plugin/jqplot/plugins/jqplot.ohlcRenderer.js | 373 + .../jqplot/plugins/jqplot.ohlcRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.pieRenderer.js | 904 ++ .../jqplot/plugins/jqplot.pieRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.pointLabels.js | 377 + .../jqplot/plugins/jqplot.pointLabels.min.js | 3 + .../plugins/jqplot.pyramidAxisRenderer.js | 728 + .../plugins/jqplot.pyramidAxisRenderer.min.js | 3 + .../plugins/jqplot.pyramidGridRenderer.js | 429 + .../plugins/jqplot.pyramidGridRenderer.min.js | 3 + .../jqplot/plugins/jqplot.pyramidRenderer.js | 514 + .../plugins/jqplot.pyramidRenderer.min.js | 3 + plugin/jqplot/plugins/jqplot.trendline.js | 223 + plugin/jqplot/plugins/jqplot.trendline.min.js | 3 + 73 files changed, 29561 insertions(+), 1 deletion(-) create mode 100644 adm/write_count.php create mode 100644 plugin/jqplot/MIT-LICENSE.txt create mode 100644 plugin/jqplot/excanvas.js create mode 100644 plugin/jqplot/excanvas.min.js create mode 100644 plugin/jqplot/jqplot.barRenderer.min.js create mode 100644 plugin/jqplot/jqplot.categoryAxisRenderer.min.js create mode 100644 plugin/jqplot/jqplot.pointLabels.min.js create mode 100644 plugin/jqplot/jquery.jqplot.css create mode 100644 plugin/jqplot/jquery.jqplot.js create mode 100644 plugin/jqplot/jquery.jqplot.min.css create mode 100644 plugin/jqplot/jquery.jqplot.min.js create mode 100644 plugin/jqplot/plugins/jqplot.BezierCurveRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.BezierCurveRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.barRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.barRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.blockRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.blockRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.bubbleRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.bubbleRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.canvasAxisLabelRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.canvasAxisTickRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.canvasAxisTickRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.canvasOverlay.js create mode 100644 plugin/jqplot/plugins/jqplot.canvasOverlay.min.js create mode 100644 plugin/jqplot/plugins/jqplot.canvasTextRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.canvasTextRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.categoryAxisRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.categoryAxisRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.ciParser.js create mode 100644 plugin/jqplot/plugins/jqplot.ciParser.min.js create mode 100644 plugin/jqplot/plugins/jqplot.cursor.js create mode 100644 plugin/jqplot/plugins/jqplot.cursor.min.js create mode 100644 plugin/jqplot/plugins/jqplot.dateAxisRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.dateAxisRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.donutRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.donutRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.dragable.js create mode 100644 plugin/jqplot/plugins/jqplot.dragable.min.js create mode 100644 plugin/jqplot/plugins/jqplot.enhancedLegendRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.enhancedLegendRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.funnelRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.funnelRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.highlighter.js create mode 100644 plugin/jqplot/plugins/jqplot.highlighter.min.js create mode 100644 plugin/jqplot/plugins/jqplot.json2.js create mode 100644 plugin/jqplot/plugins/jqplot.json2.min.js create mode 100644 plugin/jqplot/plugins/jqplot.logAxisRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.logAxisRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.mekkoAxisRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.mekkoAxisRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.mekkoRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.mekkoRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.meterGaugeRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.meterGaugeRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.mobile.js create mode 100644 plugin/jqplot/plugins/jqplot.mobile.min.js create mode 100644 plugin/jqplot/plugins/jqplot.ohlcRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.ohlcRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.pieRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.pieRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.pointLabels.js create mode 100644 plugin/jqplot/plugins/jqplot.pointLabels.min.js create mode 100644 plugin/jqplot/plugins/jqplot.pyramidAxisRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.pyramidAxisRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.pyramidGridRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.pyramidGridRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.pyramidRenderer.js create mode 100644 plugin/jqplot/plugins/jqplot.pyramidRenderer.min.js create mode 100644 plugin/jqplot/plugins/jqplot.trendline.js create mode 100644 plugin/jqplot/plugins/jqplot.trendline.min.js diff --git a/adm/admin.menu300.php b/adm/admin.menu300.php index 1268109e0..65f848587 100644 --- a/adm/admin.menu300.php +++ b/adm/admin.menu300.php @@ -8,5 +8,6 @@ $menu['menu300'] = array ( array('300500', '1:1문의설정', ''.G5_ADMIN_URL.'/qa_config.php', 'qa'), array('300600', '내용관리', G5_ADMIN_URL.'/contentlist.php', 'scf_contents', 1), array('300700', 'FAQ관리', G5_ADMIN_URL.'/faqmasterlist.php', 'scf_faq', 1), + array('300820', '글,댓글 현황', G5_ADMIN_URL.'/write_count.php', 'scf_write_count'), ); ?> \ No newline at end of file diff --git a/adm/css/admin.css b/adm/css/admin.css index 34d7c1d43..c7066ba54 100644 --- a/adm/css/admin.css +++ b/adm/css/admin.css @@ -747,4 +747,15 @@ strong.sodr_nonpay {display:block;padding:5px 0;text-align:right} #theme_detail table{border-collapse:collapse;margin:5px 0 10px} #theme_detail table th{padding: 5px 0; border: 1px solid #d1dee2; background: #e5ecef;width:50px;padding:10px;text-align:left} #theme_detail table td{ border: 1px solid #ececec;padding:10px} -.no_theme{text-align:center;padding:100px 0;color:#555} \ No newline at end of file +.no_theme{text-align:center;padding:100px 0;color:#555} + +/*글,댓글현황*/ +#wr_cont{position:relative;margin:10px 20px} +#wr_cont input[type="submit"]{background:#ff3061;border:none;color:#fff;padding: 0 5px;height: 24px;} +#wr_cont select{height: 24px;} +#grp_color{border:2px solid #ddd;position:absolute;top:0;right:0;list-style:none;padding: 5px 5px; margin:0;} +#grp_color li{padding:5px 10px;} +#grp_color li span{width:10px;height:10px; display:inline-block;background:rgb(75, 178, 197);margin-right:5px;} +#grp_color li.color2 span{background:rgb(234, 162, 40);} +#chart_wr h5{text-align:center;border:1px solid #eee;padding:30px 0} +#chart_wr{margin:20px } \ No newline at end of file diff --git a/adm/write_count.php b/adm/write_count.php new file mode 100644 index 000000000..b16ebd172 --- /dev/null +++ b/adm/write_count.php @@ -0,0 +1,210 @@ +', 0); +add_javascript('', 0); +add_javascript('', 0); +add_javascript('', 0); +add_javascript('', 0); +add_javascript('', 0); + +if (!($graph == 'line' || $graph == 'bar')) + $graph = 'line'; + +if ($graph == 'bar') { + // 바 타입으로 사용하는 코드입니다. + add_javascript('', 0); + add_javascript('', 0); + add_javascript('', 0); +} + +$g5['title'] = '글,댓글 현황'; +include_once ('./admin.head.php'); + +$period_array = array( + '오늘'=>array('시간', 0), + '어제'=>array('시간', 0), + '7일전'=>array('일', 7), + '14일전'=>array('일', 14), + '30일전'=>array('일', 30), + '3개월전'=>array('주', 90), + '6개월전'=>array('주', 180), + '1년전'=>array('월', 365), + '2년전'=>array('월', 365*2), + '3년전'=>array('월', 365*3), + '5년전'=>array('년', 365*5), + '10년전'=>array('년', 365*10), +); + +$is_period = false; +foreach($period_array as $key=>$value) { + if ($key == $period) { + $is_period = true; + break; + } +} +if (!$is_period) + $period = '오늘'; + +$day = $period_array[$period][0]; + +$today = date('Y-m-d', G5_SERVER_TIME); +$yesterday = date('Y-m-d', G5_SERVER_TIME - 86400); + +if ($period == '오늘') { + $from = $today; + $to = $from; +} else if ($period == '어제') { + $from = $yesterday; + $to = $from; +} else if ($period == '내일') { + $from = date('Y-m-d', G5_SERVER_TIME + (86400 * 2)); + $to = $from; +} else { + $from = date('Y-m-d', G5_SERVER_TIME - (86400 * $period_array[$period][1])); + $to = $yesterday; +} + +$sql_bo_table = ''; +if ($bo_table) + $sql_bo_table = "and bo_table = '$bo_table'"; + +switch ($day) { + case '시간' : + $sql = " select substr(bn_datetime,6,8) as hours, sum(if(wr_id=wr_parent,1,0)) as wcount, sum(if(wr_id=wr_parent,0,1)) as ccount from {$g5['board_new_table']} where substr(bn_datetime,1,10) between '$from' and '$to' {$sql_bo_table} group by hours order by bn_datetime "; + $result = sql_query($sql); + for ($i=0; $row=sql_fetch_array($result); $i++) { + // 월-일 시간 + $line1[] = "['".substr($row['hours'],0,8)."',".$row['wcount'].']'; + $line2[] = "['".substr($row['hours'],0,8)."',".$row['ccount'].']'; + } + break; + case '일' : + $sql = " select substr(bn_datetime,1,10) as days, sum(if(wr_id=wr_parent,1,0)) as wcount, sum(if(wr_id=wr_parent,0,1)) as ccount from {$g5['board_new_table']} where substr(bn_datetime,1,10) between '$from' and '$to' {$sql_bo_table} group by days order by bn_datetime "; + $result = sql_query($sql); + for ($i=0; $row=sql_fetch_array($result); $i++) { + // 월-일 + $line1[] = "['".substr($row['days'],5,5)."',".$row['wcount'].']'; + $line2[] = "['".substr($row['days'],5,5)."',".$row['ccount'].']'; + } + break; + case '주' : + $sql = " select concat(substr(bn_datetime,1,4), '-', weekofyear(bn_datetime)) as weeks, sum(if(wr_id=wr_parent,1,0)) as wcount, sum(if(wr_id=wr_parent,0,1)) as ccount from {$g5['board_new_table']} where substr(bn_datetime,1,10) between '$from' and '$to' {$sql_bo_table} group by weeks order by bn_datetime "; + $result = sql_query($sql); + for ($i=0; $row=sql_fetch_array($result); $i++) { + // 올해의 몇주로 보여주면 바로 확인이 안되므로 주를 날짜로 바꾼다. + // 년-월-일 + list($lyear, $lweek) = explode('-', $row['weeks']); + $date = date('y-m-d', strtotime($lyear.'W'.str_pad($lweek, 2, '0', STR_PAD_LEFT))); + $line1[] = "['".$date."',".$row['wcount'].']'; + $line2[] = "['".$date."',".$row['ccount'].']'; + } + break; + case '월' : + $sql = " select substr(bn_datetime,1,7) as months, sum(if(wr_id=wr_parent,1,0)) as wcount, sum(if(wr_id=wr_parent,0,1)) as ccount from {$g5['board_new_table']} where substr(bn_datetime,1,10) between '$from' and '$to' {$sql_bo_table} group by months order by bn_datetime "; + $result = sql_query($sql); + for ($i=0; $row=sql_fetch_array($result); $i++) { + // 년-월 + $line1[] = "['".substr($row['months'],2,5)."',".$row['wcount'].']'; + $line2[] = "['".substr($row['months'],2,5)."',".$row['ccount'].']'; + } + break; + case '년' : + $sql = " select substr(bn_datetime,1,4) as years, sum(if(wr_id=wr_parent,1,0)) as wcount, sum(if(wr_id=wr_parent,0,1)) as ccount from {$g5['board_new_table']} where substr(bn_datetime,1,10) between '$from' and '$to' {$sql_bo_table} group by years order by bn_datetime "; + $result = sql_query($sql); + for ($i=0; $row=sql_fetch_array($result); $i++) { + // 년(4자리) + $line1[] = "['".substr($row['years'],0,4)."',".$row['wcount'].']'; + $line2[] = "['".substr($row['years'],0,4)."',".$row['ccount'].']'; + } + break; +} +?> +
            + + + + + + + + + +
              +
            • 글 수
            • +
            • 댓글 수
            • +
            +
            +
            +
            +그래프를 만들 데이터가 없습니다.\n"; +} else { +?> +
            +
            + + + + \ No newline at end of file diff --git a/plugin/jqplot/MIT-LICENSE.txt b/plugin/jqplot/MIT-LICENSE.txt new file mode 100644 index 000000000..f8111b9ce --- /dev/null +++ b/plugin/jqplot/MIT-LICENSE.txt @@ -0,0 +1,21 @@ +Title: MIT License + +Copyright (c) 2009-2013 Chris Leonello + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/plugin/jqplot/excanvas.js b/plugin/jqplot/excanvas.js new file mode 100644 index 000000000..4ca9653fc --- /dev/null +++ b/plugin/jqplot/excanvas.js @@ -0,0 +1,1438 @@ +// Memory Leaks patch from http://explorercanvas.googlecode.com/svn/trunk/ +// svn : r73 +// ------------------------------------------------------------------ +// Copyright 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// Known Issues: +// +// * Patterns only support repeat. +// * Radial gradient are not implemented. The VML version of these look very +// different from the canvas one. +// * Clipping paths are not implemented. +// * Coordsize. The width and height attribute have higher priority than the +// width and height style values which isn't correct. +// * Painting mode isn't implemented. +// * Canvas width/height should is using content-box by default. IE in +// Quirks mode will draw the canvas using border-box. Either change your +// doctype to HTML5 +// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) +// or use Box Sizing Behavior from WebFX +// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) +// * Non uniform scaling does not correctly scale strokes. +// * Optimize. There is always room for speed improvements. + +// Only add this code if we do not already have a canvas implementation +if (!document.createElement('canvas').getContext) { + +(function() { + + // alias some functions to make (compiled) code shorter + var m = Math; + var mr = m.round; + var ms = m.sin; + var mc = m.cos; + var abs = m.abs; + var sqrt = m.sqrt; + + // this is used for sub pixel precision + var Z = 10; + var Z2 = Z / 2; + + var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1]; + + /** + * This funtion is assigned to the elements as element.getContext(). + * @this {HTMLElement} + * @return {CanvasRenderingContext2D_} + */ + function getContext() { + return this.context_ || + (this.context_ = new CanvasRenderingContext2D_(this)); + } + + var slice = Array.prototype.slice; + + /** + * Binds a function to an object. The returned function will always use the + * passed in {@code obj} as {@code this}. + * + * Example: + * + * g = bind(f, obj, a, b) + * g(c, d) // will do f.call(obj, a, b, c, d) + * + * @param {Function} f The function to bind the object to + * @param {Object} obj The object that should act as this when the function + * is called + * @param {*} var_args Rest arguments that will be used as the initial + * arguments when the function is called + * @return {Function} A new function that has bound this + */ + function bind(f, obj, var_args) { + var a = slice.call(arguments, 2); + return function() { + return f.apply(obj, a.concat(slice.call(arguments))); + }; + } + + function encodeHtmlAttribute(s) { + return String(s).replace(/&/g, '&').replace(/"/g, '"'); + } + + function addNamespace(doc, prefix, urn) { + if (!doc.namespaces[prefix]) { + doc.namespaces.add(prefix, urn, '#default#VML'); + } + } + + function addNamespacesAndStylesheet(doc) { + addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml'); + addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office'); + + // Setup default CSS. Only add one style sheet per document + if (!doc.styleSheets['ex_canvas_']) { + var ss = doc.createStyleSheet(); + ss.owningElement.id = 'ex_canvas_'; + ss.cssText = 'canvas{display:inline-block;overflow:hidden;' + + // default size is 300x150 in Gecko and Opera + 'text-align:left;width:300px;height:150px}'; + } + } + + // Add namespaces and stylesheet at startup. + addNamespacesAndStylesheet(document); + + var G_vmlCanvasManager_ = { + init: function(opt_doc) { + var doc = opt_doc || document; + // Create a dummy element so that IE will allow canvas elements to be + // recognized. + doc.createElement('canvas'); + doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); + }, + + init_: function(doc) { + // find all canvas elements + var els = doc.getElementsByTagName('canvas'); + for (var i = 0; i < els.length; i++) { + this.initElement(els[i]); + } + }, + + /** + * Public initializes a canvas element so that it can be used as canvas + * element from now on. This is called automatically before the page is + * loaded but if you are creating elements using createElement you need to + * make sure this is called on the element. + * @param {HTMLElement} el The canvas element to initialize. + * @return {HTMLElement} the element that was created. + */ + initElement: function(el) { + if (!el.getContext) { + el.getContext = getContext; + + // Add namespaces and stylesheet to document of the element. + addNamespacesAndStylesheet(el.ownerDocument); + + // Remove fallback content. There is no way to hide text nodes so we + // just remove all childNodes. We could hide all elements and remove + // text nodes but who really cares about the fallback content. + el.innerHTML = ''; + + // do not use inline function because that will leak memory + el.attachEvent('onpropertychange', onPropertyChange); + el.attachEvent('onresize', onResize); + + var attrs = el.attributes; + if (attrs.width && attrs.width.specified) { + // TODO: use runtimeStyle and coordsize + // el.getContext().setWidth_(attrs.width.nodeValue); + el.style.width = attrs.width.nodeValue + 'px'; + } else { + el.width = el.clientWidth; + } + if (attrs.height && attrs.height.specified) { + // TODO: use runtimeStyle and coordsize + // el.getContext().setHeight_(attrs.height.nodeValue); + el.style.height = attrs.height.nodeValue + 'px'; + } else { + el.height = el.clientHeight; + } + //el.getContext().setCoordsize_() + } + return el; + }, + + // Memory Leaks patch : see http://code.google.com/p/explorercanvas/issues/detail?id=82 + uninitElement: function(el){ + if (el.getContext) { + var ctx = el.getContext(); + delete ctx.element_; + delete ctx.canvas; + el.innerHTML = ""; + //el.outerHTML = ""; + el.context_ = null; + el.getContext = null; + el.detachEvent("onpropertychange", onPropertyChange); + el.detachEvent("onresize", onResize); + } + } + }; + + function onPropertyChange(e) { + var el = e.srcElement; + + switch (e.propertyName) { + case 'width': + el.getContext().clearRect(); + el.style.width = el.attributes.width.nodeValue + 'px'; + // In IE8 this does not trigger onresize. + el.firstChild.style.width = el.clientWidth + 'px'; + break; + case 'height': + el.getContext().clearRect(); + el.style.height = el.attributes.height.nodeValue + 'px'; + el.firstChild.style.height = el.clientHeight + 'px'; + break; + } + } + + function onResize(e) { + var el = e.srcElement; + if (el.firstChild) { + el.firstChild.style.width = el.clientWidth + 'px'; + el.firstChild.style.height = el.clientHeight + 'px'; + } + } + + G_vmlCanvasManager_.init(); + + // precompute "00" to "FF" + var decToHex = []; + for (var i = 0; i < 16; i++) { + for (var j = 0; j < 16; j++) { + decToHex[i * 16 + j] = i.toString(16) + j.toString(16); + } + } + + function createMatrixIdentity() { + return [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1] + ]; + } + + function matrixMultiply(m1, m2) { + var result = createMatrixIdentity(); + + for (var x = 0; x < 3; x++) { + for (var y = 0; y < 3; y++) { + var sum = 0; + + for (var z = 0; z < 3; z++) { + sum += m1[x][z] * m2[z][y]; + } + + result[x][y] = sum; + } + } + return result; + } + + function copyState(o1, o2) { + o2.fillStyle = o1.fillStyle; + o2.lineCap = o1.lineCap; + o2.lineJoin = o1.lineJoin; + o2.lineWidth = o1.lineWidth; + o2.miterLimit = o1.miterLimit; + o2.shadowBlur = o1.shadowBlur; + o2.shadowColor = o1.shadowColor; + o2.shadowOffsetX = o1.shadowOffsetX; + o2.shadowOffsetY = o1.shadowOffsetY; + o2.strokeStyle = o1.strokeStyle; + o2.globalAlpha = o1.globalAlpha; + o2.font = o1.font; + o2.textAlign = o1.textAlign; + o2.textBaseline = o1.textBaseline; + o2.arcScaleX_ = o1.arcScaleX_; + o2.arcScaleY_ = o1.arcScaleY_; + o2.lineScale_ = o1.lineScale_; + } + + var colorData = { + aliceblue: '#F0F8FF', + antiquewhite: '#FAEBD7', + aquamarine: '#7FFFD4', + azure: '#F0FFFF', + beige: '#F5F5DC', + bisque: '#FFE4C4', + black: '#000000', + blanchedalmond: '#FFEBCD', + blueviolet: '#8A2BE2', + brown: '#A52A2A', + burlywood: '#DEB887', + cadetblue: '#5F9EA0', + chartreuse: '#7FFF00', + chocolate: '#D2691E', + coral: '#FF7F50', + cornflowerblue: '#6495ED', + cornsilk: '#FFF8DC', + crimson: '#DC143C', + cyan: '#00FFFF', + darkblue: '#00008B', + darkcyan: '#008B8B', + darkgoldenrod: '#B8860B', + darkgray: '#A9A9A9', + darkgreen: '#006400', + darkgrey: '#A9A9A9', + darkkhaki: '#BDB76B', + darkmagenta: '#8B008B', + darkolivegreen: '#556B2F', + darkorange: '#FF8C00', + darkorchid: '#9932CC', + darkred: '#8B0000', + darksalmon: '#E9967A', + darkseagreen: '#8FBC8F', + darkslateblue: '#483D8B', + darkslategray: '#2F4F4F', + darkslategrey: '#2F4F4F', + darkturquoise: '#00CED1', + darkviolet: '#9400D3', + deeppink: '#FF1493', + deepskyblue: '#00BFFF', + dimgray: '#696969', + dimgrey: '#696969', + dodgerblue: '#1E90FF', + firebrick: '#B22222', + floralwhite: '#FFFAF0', + forestgreen: '#228B22', + gainsboro: '#DCDCDC', + ghostwhite: '#F8F8FF', + gold: '#FFD700', + goldenrod: '#DAA520', + grey: '#808080', + greenyellow: '#ADFF2F', + honeydew: '#F0FFF0', + hotpink: '#FF69B4', + indianred: '#CD5C5C', + indigo: '#4B0082', + ivory: '#FFFFF0', + khaki: '#F0E68C', + lavender: '#E6E6FA', + lavenderblush: '#FFF0F5', + lawngreen: '#7CFC00', + lemonchiffon: '#FFFACD', + lightblue: '#ADD8E6', + lightcoral: '#F08080', + lightcyan: '#E0FFFF', + lightgoldenrodyellow: '#FAFAD2', + lightgreen: '#90EE90', + lightgrey: '#D3D3D3', + lightpink: '#FFB6C1', + lightsalmon: '#FFA07A', + lightseagreen: '#20B2AA', + lightskyblue: '#87CEFA', + lightslategray: '#778899', + lightslategrey: '#778899', + lightsteelblue: '#B0C4DE', + lightyellow: '#FFFFE0', + limegreen: '#32CD32', + linen: '#FAF0E6', + magenta: '#FF00FF', + mediumaquamarine: '#66CDAA', + mediumblue: '#0000CD', + mediumorchid: '#BA55D3', + mediumpurple: '#9370DB', + mediumseagreen: '#3CB371', + mediumslateblue: '#7B68EE', + mediumspringgreen: '#00FA9A', + mediumturquoise: '#48D1CC', + mediumvioletred: '#C71585', + midnightblue: '#191970', + mintcream: '#F5FFFA', + mistyrose: '#FFE4E1', + moccasin: '#FFE4B5', + navajowhite: '#FFDEAD', + oldlace: '#FDF5E6', + olivedrab: '#6B8E23', + orange: '#FFA500', + orangered: '#FF4500', + orchid: '#DA70D6', + palegoldenrod: '#EEE8AA', + palegreen: '#98FB98', + paleturquoise: '#AFEEEE', + palevioletred: '#DB7093', + papayawhip: '#FFEFD5', + peachpuff: '#FFDAB9', + peru: '#CD853F', + pink: '#FFC0CB', + plum: '#DDA0DD', + powderblue: '#B0E0E6', + rosybrown: '#BC8F8F', + royalblue: '#4169E1', + saddlebrown: '#8B4513', + salmon: '#FA8072', + sandybrown: '#F4A460', + seagreen: '#2E8B57', + seashell: '#FFF5EE', + sienna: '#A0522D', + skyblue: '#87CEEB', + slateblue: '#6A5ACD', + slategray: '#708090', + slategrey: '#708090', + snow: '#FFFAFA', + springgreen: '#00FF7F', + steelblue: '#4682B4', + tan: '#D2B48C', + thistle: '#D8BFD8', + tomato: '#FF6347', + turquoise: '#40E0D0', + violet: '#EE82EE', + wheat: '#F5DEB3', + whitesmoke: '#F5F5F5', + yellowgreen: '#9ACD32' + }; + + + function getRgbHslContent(styleString) { + var start = styleString.indexOf('(', 3); + var end = styleString.indexOf(')', start + 1); + var parts = styleString.substring(start + 1, end).split(','); + // add alpha if needed + if (parts.length != 4 || styleString.charAt(3) != 'a') { + parts[3] = 1; + } + return parts; + } + + function percent(s) { + return parseFloat(s) / 100; + } + + function clamp(v, min, max) { + return Math.min(max, Math.max(min, v)); + } + + function hslToRgb(parts){ + var r, g, b, h, s, l; + h = parseFloat(parts[0]) / 360 % 360; + if (h < 0) + h++; + s = clamp(percent(parts[1]), 0, 1); + l = clamp(percent(parts[2]), 0, 1); + if (s == 0) { + r = g = b = l; // achromatic + } else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hueToRgb(p, q, h + 1 / 3); + g = hueToRgb(p, q, h); + b = hueToRgb(p, q, h - 1 / 3); + } + + return '#' + decToHex[Math.floor(r * 255)] + + decToHex[Math.floor(g * 255)] + + decToHex[Math.floor(b * 255)]; + } + + function hueToRgb(m1, m2, h) { + if (h < 0) + h++; + if (h > 1) + h--; + + if (6 * h < 1) + return m1 + (m2 - m1) * 6 * h; + else if (2 * h < 1) + return m2; + else if (3 * h < 2) + return m1 + (m2 - m1) * (2 / 3 - h) * 6; + else + return m1; + } + + var processStyleCache = {}; + + function processStyle(styleString) { + if (styleString in processStyleCache) { + return processStyleCache[styleString]; + } + + var str, alpha = 1; + + styleString = String(styleString); + if (styleString.charAt(0) == '#') { + str = styleString; + } else if (/^rgb/.test(styleString)) { + var parts = getRgbHslContent(styleString); + var str = '#', n; + for (var i = 0; i < 3; i++) { + if (parts[i].indexOf('%') != -1) { + n = Math.floor(percent(parts[i]) * 255); + } else { + n = +parts[i]; + } + str += decToHex[clamp(n, 0, 255)]; + } + alpha = +parts[3]; + } else if (/^hsl/.test(styleString)) { + var parts = getRgbHslContent(styleString); + str = hslToRgb(parts); + alpha = parts[3]; + } else { + str = colorData[styleString] || styleString; + } + return processStyleCache[styleString] = {color: str, alpha: alpha}; + } + + var DEFAULT_STYLE = { + style: 'normal', + variant: 'normal', + weight: 'normal', + size: 10, + family: 'sans-serif' + }; + + // Internal text style cache + var fontStyleCache = {}; + + function processFontStyle(styleString) { + if (fontStyleCache[styleString]) { + return fontStyleCache[styleString]; + } + + var el = document.createElement('div'); + var style = el.style; + try { + style.font = styleString; + } catch (ex) { + // Ignore failures to set to invalid font. + } + + return fontStyleCache[styleString] = { + style: style.fontStyle || DEFAULT_STYLE.style, + variant: style.fontVariant || DEFAULT_STYLE.variant, + weight: style.fontWeight || DEFAULT_STYLE.weight, + size: style.fontSize || DEFAULT_STYLE.size, + family: style.fontFamily || DEFAULT_STYLE.family + }; + } + + function getComputedStyle(style, element) { + var computedStyle = {}; + + for (var p in style) { + computedStyle[p] = style[p]; + } + + // Compute the size + var canvasFontSize = parseFloat(element.currentStyle.fontSize), + fontSize = parseFloat(style.size); + + if (typeof style.size == 'number') { + computedStyle.size = style.size; + } else if (style.size.indexOf('px') != -1) { + computedStyle.size = fontSize; + } else if (style.size.indexOf('em') != -1) { + computedStyle.size = canvasFontSize * fontSize; + } else if(style.size.indexOf('%') != -1) { + computedStyle.size = (canvasFontSize / 100) * fontSize; + } else if (style.size.indexOf('pt') != -1) { + computedStyle.size = fontSize / .75; + } else { + computedStyle.size = canvasFontSize; + } + + // Different scaling between normal text and VML text. This was found using + // trial and error to get the same size as non VML text. + computedStyle.size *= 0.981; + + // Fix for VML handling of bare font family names. Add a '' around font family names. + computedStyle.family = "'" + computedStyle.family.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'"; + + return computedStyle; + } + + function buildStyle(style) { + return style.style + ' ' + style.variant + ' ' + style.weight + ' ' + + style.size + 'px ' + style.family; + } + + var lineCapMap = { + 'butt': 'flat', + 'round': 'round' + }; + + function processLineCap(lineCap) { + return lineCapMap[lineCap] || 'square'; + } + + /** + * This class implements CanvasRenderingContext2D interface as described by + * the WHATWG. + * @param {HTMLElement} canvasElement The element that the 2D context should + * be associated with + */ + function CanvasRenderingContext2D_(canvasElement) { + this.m_ = createMatrixIdentity(); + + this.mStack_ = []; + this.aStack_ = []; + this.currentPath_ = []; + + // Canvas context properties + this.strokeStyle = '#000'; + this.fillStyle = '#000'; + + this.lineWidth = 1; + this.lineJoin = 'miter'; + this.lineCap = 'butt'; + this.miterLimit = Z * 1; + this.globalAlpha = 1; + this.font = '10px sans-serif'; + this.textAlign = 'left'; + this.textBaseline = 'alphabetic'; + this.canvas = canvasElement; + + var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' + + canvasElement.clientHeight + 'px;overflow:hidden;position:absolute'; + var el = canvasElement.ownerDocument.createElement('div'); + el.style.cssText = cssText; + canvasElement.appendChild(el); + + var overlayEl = el.cloneNode(false); + // Use a non transparent background. + overlayEl.style.backgroundColor = 'red'; + overlayEl.style.filter = 'alpha(opacity=0)'; + canvasElement.appendChild(overlayEl); + + this.element_ = el; + this.arcScaleX_ = 1; + this.arcScaleY_ = 1; + this.lineScale_ = 1; + } + + var contextPrototype = CanvasRenderingContext2D_.prototype; + contextPrototype.clearRect = function() { + if (this.textMeasureEl_) { + this.textMeasureEl_.removeNode(true); + this.textMeasureEl_ = null; + } + this.element_.innerHTML = ''; + }; + + contextPrototype.beginPath = function() { + // TODO: Branch current matrix so that save/restore has no effect + // as per safari docs. + this.currentPath_ = []; + }; + + contextPrototype.moveTo = function(aX, aY) { + var p = getCoords(this, aX, aY); + this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y}); + this.currentX_ = p.x; + this.currentY_ = p.y; + }; + + contextPrototype.lineTo = function(aX, aY) { + var p = getCoords(this, aX, aY); + this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y}); + + this.currentX_ = p.x; + this.currentY_ = p.y; + }; + + contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY) { + var p = getCoords(this, aX, aY); + var cp1 = getCoords(this, aCP1x, aCP1y); + var cp2 = getCoords(this, aCP2x, aCP2y); + bezierCurveTo(this, cp1, cp2, p); + }; + + // Helper function that takes the already fixed cordinates. + function bezierCurveTo(self, cp1, cp2, p) { + self.currentPath_.push({ + type: 'bezierCurveTo', + cp1x: cp1.x, + cp1y: cp1.y, + cp2x: cp2.x, + cp2y: cp2.y, + x: p.x, + y: p.y + }); + self.currentX_ = p.x; + self.currentY_ = p.y; + } + + contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { + // the following is lifted almost directly from + // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes + + var cp = getCoords(this, aCPx, aCPy); + var p = getCoords(this, aX, aY); + + var cp1 = { + x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_), + y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_) + }; + var cp2 = { + x: cp1.x + (p.x - this.currentX_) / 3.0, + y: cp1.y + (p.y - this.currentY_) / 3.0 + }; + + bezierCurveTo(this, cp1, cp2, p); + }; + + contextPrototype.arc = function(aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise) { + aRadius *= Z; + var arcType = aClockwise ? 'at' : 'wa'; + + var xStart = aX + mc(aStartAngle) * aRadius - Z2; + var yStart = aY + ms(aStartAngle) * aRadius - Z2; + + var xEnd = aX + mc(aEndAngle) * aRadius - Z2; + var yEnd = aY + ms(aEndAngle) * aRadius - Z2; + + // IE won't render arches drawn counter clockwise if xStart == xEnd. + if (xStart == xEnd && !aClockwise) { + xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something + // that can be represented in binary + } + + var p = getCoords(this, aX, aY); + var pStart = getCoords(this, xStart, yStart); + var pEnd = getCoords(this, xEnd, yEnd); + + this.currentPath_.push({type: arcType, + x: p.x, + y: p.y, + radius: aRadius, + xStart: pStart.x, + yStart: pStart.y, + xEnd: pEnd.x, + yEnd: pEnd.y}); + + }; + + contextPrototype.rect = function(aX, aY, aWidth, aHeight) { + this.moveTo(aX, aY); + this.lineTo(aX + aWidth, aY); + this.lineTo(aX + aWidth, aY + aHeight); + this.lineTo(aX, aY + aHeight); + this.closePath(); + }; + + contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) { + var oldPath = this.currentPath_; + this.beginPath(); + + this.moveTo(aX, aY); + this.lineTo(aX + aWidth, aY); + this.lineTo(aX + aWidth, aY + aHeight); + this.lineTo(aX, aY + aHeight); + this.closePath(); + this.stroke(); + + this.currentPath_ = oldPath; + }; + + contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) { + var oldPath = this.currentPath_; + this.beginPath(); + + this.moveTo(aX, aY); + this.lineTo(aX + aWidth, aY); + this.lineTo(aX + aWidth, aY + aHeight); + this.lineTo(aX, aY + aHeight); + this.closePath(); + this.fill(); + + this.currentPath_ = oldPath; + }; + + contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) { + var gradient = new CanvasGradient_('gradient'); + gradient.x0_ = aX0; + gradient.y0_ = aY0; + gradient.x1_ = aX1; + gradient.y1_ = aY1; + return gradient; + }; + + contextPrototype.createRadialGradient = function(aX0, aY0, aR0, + aX1, aY1, aR1) { + var gradient = new CanvasGradient_('gradientradial'); + gradient.x0_ = aX0; + gradient.y0_ = aY0; + gradient.r0_ = aR0; + gradient.x1_ = aX1; + gradient.y1_ = aY1; + gradient.r1_ = aR1; + return gradient; + }; + + contextPrototype.drawImage = function(image, var_args) { + var dx, dy, dw, dh, sx, sy, sw, sh; + + // to find the original width we overide the width and height + var oldRuntimeWidth = image.runtimeStyle.width; + var oldRuntimeHeight = image.runtimeStyle.height; + image.runtimeStyle.width = 'auto'; + image.runtimeStyle.height = 'auto'; + + // get the original size + var w = image.width; + var h = image.height; + + // and remove overides + image.runtimeStyle.width = oldRuntimeWidth; + image.runtimeStyle.height = oldRuntimeHeight; + + if (arguments.length == 3) { + dx = arguments[1]; + dy = arguments[2]; + sx = sy = 0; + sw = dw = w; + sh = dh = h; + } else if (arguments.length == 5) { + dx = arguments[1]; + dy = arguments[2]; + dw = arguments[3]; + dh = arguments[4]; + sx = sy = 0; + sw = w; + sh = h; + } else if (arguments.length == 9) { + sx = arguments[1]; + sy = arguments[2]; + sw = arguments[3]; + sh = arguments[4]; + dx = arguments[5]; + dy = arguments[6]; + dw = arguments[7]; + dh = arguments[8]; + } else { + throw Error('Invalid number of arguments'); + } + + var d = getCoords(this, dx, dy); + + var w2 = sw / 2; + var h2 = sh / 2; + + var vmlStr = []; + + var W = 10; + var H = 10; + + // For some reason that I've now forgotten, using divs didn't work + vmlStr.push(' ' , + '', + ''); + + this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join('')); + }; + + contextPrototype.stroke = function(aFill) { + var lineStr = []; + var lineOpen = false; + + var W = 10; + var H = 10; + + lineStr.push(''); + + if (!aFill) { + appendStroke(this, lineStr); + } else { + appendFill(this, lineStr, min, max); + } + + lineStr.push(''); + + this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); + }; + + function appendStroke(ctx, lineStr) { + var a = processStyle(ctx.strokeStyle); + var color = a.color; + var opacity = a.alpha * ctx.globalAlpha; + var lineWidth = ctx.lineScale_ * ctx.lineWidth; + + // VML cannot correctly render a line if the width is less than 1px. + // In that case, we dilute the color to make the line look thinner. + if (lineWidth < 1) { + opacity *= lineWidth; + } + + lineStr.push( + '' + ); + } + + function appendFill(ctx, lineStr, min, max) { + var fillStyle = ctx.fillStyle; + var arcScaleX = ctx.arcScaleX_; + var arcScaleY = ctx.arcScaleY_; + var width = max.x - min.x; + var height = max.y - min.y; + if (fillStyle instanceof CanvasGradient_) { + // TODO: Gradients transformed with the transformation matrix. + var angle = 0; + var focus = {x: 0, y: 0}; + + // additional offset + var shift = 0; + // scale factor for offset + var expansion = 1; + + if (fillStyle.type_ == 'gradient') { + var x0 = fillStyle.x0_ / arcScaleX; + var y0 = fillStyle.y0_ / arcScaleY; + var x1 = fillStyle.x1_ / arcScaleX; + var y1 = fillStyle.y1_ / arcScaleY; + var p0 = getCoords(ctx, x0, y0); + var p1 = getCoords(ctx, x1, y1); + var dx = p1.x - p0.x; + var dy = p1.y - p0.y; + angle = Math.atan2(dx, dy) * 180 / Math.PI; + + // The angle should be a non-negative number. + if (angle < 0) { + angle += 360; + } + + // Very small angles produce an unexpected result because they are + // converted to a scientific notation string. + if (angle < 1e-6) { + angle = 0; + } + } else { + var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_); + focus = { + x: (p0.x - min.x) / width, + y: (p0.y - min.y) / height + }; + + width /= arcScaleX * Z; + height /= arcScaleY * Z; + var dimension = m.max(width, height); + shift = 2 * fillStyle.r0_ / dimension; + expansion = 2 * fillStyle.r1_ / dimension - shift; + } + + // We need to sort the color stops in ascending order by offset, + // otherwise IE won't interpret it correctly. + var stops = fillStyle.colors_; + stops.sort(function(cs1, cs2) { + return cs1.offset - cs2.offset; + }); + + var length = stops.length; + var color1 = stops[0].color; + var color2 = stops[length - 1].color; + var opacity1 = stops[0].alpha * ctx.globalAlpha; + var opacity2 = stops[length - 1].alpha * ctx.globalAlpha; + + var colors = []; + for (var i = 0; i < length; i++) { + var stop = stops[i]; + colors.push(stop.offset * expansion + shift + ' ' + stop.color); + } + + // When colors attribute is used, the meanings of opacity and o:opacity2 + // are reversed. + lineStr.push(''); + } else if (fillStyle instanceof CanvasPattern_) { + if (width && height) { + var deltaLeft = -min.x; + var deltaTop = -min.y; + lineStr.push(''); + } + } else { + var a = processStyle(ctx.fillStyle); + var color = a.color; + var opacity = a.alpha * ctx.globalAlpha; + lineStr.push(''); + } + } + + contextPrototype.fill = function() { + this.stroke(true); + }; + + contextPrototype.closePath = function() { + this.currentPath_.push({type: 'close'}); + }; + + function getCoords(ctx, aX, aY) { + var m = ctx.m_; + return { + x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2, + y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2 + }; + }; + + contextPrototype.save = function() { + var o = {}; + copyState(this, o); + this.aStack_.push(o); + this.mStack_.push(this.m_); + this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); + }; + + contextPrototype.restore = function() { + if (this.aStack_.length) { + copyState(this.aStack_.pop(), this); + this.m_ = this.mStack_.pop(); + } + }; + + function matrixIsFinite(m) { + return isFinite(m[0][0]) && isFinite(m[0][1]) && + isFinite(m[1][0]) && isFinite(m[1][1]) && + isFinite(m[2][0]) && isFinite(m[2][1]); + } + + function setM(ctx, m, updateLineScale) { + if (!matrixIsFinite(m)) { + return; + } + ctx.m_ = m; + + if (updateLineScale) { + // Get the line scale. + // Determinant of this.m_ means how much the area is enlarged by the + // transformation. So its square root can be used as a scale factor + // for width. + var det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; + ctx.lineScale_ = sqrt(abs(det)); + } + } + + contextPrototype.translate = function(aX, aY) { + var m1 = [ + [1, 0, 0], + [0, 1, 0], + [aX, aY, 1] + ]; + + setM(this, matrixMultiply(m1, this.m_), false); + }; + + contextPrototype.rotate = function(aRot) { + var c = mc(aRot); + var s = ms(aRot); + + var m1 = [ + [c, s, 0], + [-s, c, 0], + [0, 0, 1] + ]; + + setM(this, matrixMultiply(m1, this.m_), false); + }; + + contextPrototype.scale = function(aX, aY) { + this.arcScaleX_ *= aX; + this.arcScaleY_ *= aY; + var m1 = [ + [aX, 0, 0], + [0, aY, 0], + [0, 0, 1] + ]; + + setM(this, matrixMultiply(m1, this.m_), true); + }; + + contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) { + var m1 = [ + [m11, m12, 0], + [m21, m22, 0], + [dx, dy, 1] + ]; + + setM(this, matrixMultiply(m1, this.m_), true); + }; + + contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) { + var m = [ + [m11, m12, 0], + [m21, m22, 0], + [dx, dy, 1] + ]; + + setM(this, m, true); + }; + + /** + * The text drawing function. + * The maxWidth argument isn't taken in account, since no browser supports + * it yet. + */ + contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) { + var m = this.m_, + delta = 1000, + left = 0, + right = delta, + offset = {x: 0, y: 0}, + lineStr = []; + + var fontStyle = getComputedStyle(processFontStyle(this.font), this.element_); + + var fontStyleString = buildStyle(fontStyle); + + var elementStyle = this.element_.currentStyle; + var textAlign = this.textAlign.toLowerCase(); + switch (textAlign) { + case 'left': + case 'center': + case 'right': + break; + case 'end': + textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left'; + break; + case 'start': + textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left'; + break; + default: + textAlign = 'left'; + } + + // 1.75 is an arbitrary number, as there is no info about the text baseline + switch (this.textBaseline) { + case 'hanging': + case 'top': + offset.y = fontStyle.size / 1.75; + break; + case 'middle': + break; + default: + case null: + case 'alphabetic': + case 'ideographic': + case 'bottom': + offset.y = -fontStyle.size / 2.25; + break; + } + + switch(textAlign) { + case 'right': + left = delta; + right = 0.05; + break; + case 'center': + left = right = delta / 2; + break; + } + + var d = getCoords(this, x + offset.x, y + offset.y); + + lineStr.push(''); + + if (stroke) { + appendStroke(this, lineStr); + } else { + // TODO: Fix the min and max params. + appendFill(this, lineStr, {x: -left, y: 0}, + {x: right, y: fontStyle.size}); + } + + var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' + + m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0'; + + var skewOffset = mr(d.x / Z + 1 - m[0][0]) + ',' + mr(d.y / Z - 2 * m[1][0]); + + + lineStr.push('', + '', + ''); + + this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); + }; + + contextPrototype.fillText = function(text, x, y, maxWidth) { + this.drawText_(text, x, y, maxWidth, false); + }; + + contextPrototype.strokeText = function(text, x, y, maxWidth) { + this.drawText_(text, x, y, maxWidth, true); + }; + + contextPrototype.measureText = function(text) { + if (!this.textMeasureEl_) { + var s = ''; + this.element_.insertAdjacentHTML('beforeEnd', s); + this.textMeasureEl_ = this.element_.lastChild; + } + var doc = this.element_.ownerDocument; + this.textMeasureEl_.innerHTML = ''; + this.textMeasureEl_.style.font = this.font; + // Don't use innerHTML or innerText because they allow markup/whitespace. + this.textMeasureEl_.appendChild(doc.createTextNode(text)); + return {width: this.textMeasureEl_.offsetWidth}; + }; + + /******** STUBS ********/ + contextPrototype.clip = function() { + // TODO: Implement + }; + + contextPrototype.arcTo = function() { + // TODO: Implement + }; + + contextPrototype.createPattern = function(image, repetition) { + return new CanvasPattern_(image, repetition); + }; + + // Gradient / Pattern Stubs + function CanvasGradient_(aType) { + this.type_ = aType; + this.x0_ = 0; + this.y0_ = 0; + this.r0_ = 0; + this.x1_ = 0; + this.y1_ = 0; + this.r1_ = 0; + this.colors_ = []; + } + + CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) { + aColor = processStyle(aColor); + this.colors_.push({offset: aOffset, + color: aColor.color, + alpha: aColor.alpha}); + }; + + function CanvasPattern_(image, repetition) { + assertImageIsValid(image); + switch (repetition) { + case 'repeat': + case null: + case '': + this.repetition_ = 'repeat'; + break; + case 'repeat-x': + case 'repeat-y': + case 'no-repeat': + this.repetition_ = repetition; + break; + default: + throwException('SYNTAX_ERR'); + } + + this.src_ = image.src; + this.width_ = image.width; + this.height_ = image.height; + } + + function throwException(s) { + throw new DOMException_(s); + } + + function assertImageIsValid(img) { + if (!img || img.nodeType != 1 || img.tagName != 'IMG') { + throwException('TYPE_MISMATCH_ERR'); + } + if (img.readyState != 'complete') { + throwException('INVALID_STATE_ERR'); + } + } + + function DOMException_(s) { + this.code = this[s]; + this.message = s +': DOM Exception ' + this.code; + } + var p = DOMException_.prototype = new Error; + p.INDEX_SIZE_ERR = 1; + p.DOMSTRING_SIZE_ERR = 2; + p.HIERARCHY_REQUEST_ERR = 3; + p.WRONG_DOCUMENT_ERR = 4; + p.INVALID_CHARACTER_ERR = 5; + p.NO_DATA_ALLOWED_ERR = 6; + p.NO_MODIFICATION_ALLOWED_ERR = 7; + p.NOT_FOUND_ERR = 8; + p.NOT_SUPPORTED_ERR = 9; + p.INUSE_ATTRIBUTE_ERR = 10; + p.INVALID_STATE_ERR = 11; + p.SYNTAX_ERR = 12; + p.INVALID_MODIFICATION_ERR = 13; + p.NAMESPACE_ERR = 14; + p.INVALID_ACCESS_ERR = 15; + p.VALIDATION_ERR = 16; + p.TYPE_MISMATCH_ERR = 17; + + // set up externs + G_vmlCanvasManager = G_vmlCanvasManager_; + CanvasRenderingContext2D = CanvasRenderingContext2D_; + CanvasGradient = CanvasGradient_; + CanvasPattern = CanvasPattern_; + DOMException = DOMException_; + G_vmlCanvasManager._version = 888; +})(); + +} // if diff --git a/plugin/jqplot/excanvas.min.js b/plugin/jqplot/excanvas.min.js new file mode 100644 index 000000000..83373a537 --- /dev/null +++ b/plugin/jqplot/excanvas.min.js @@ -0,0 +1,3 @@ +/* jqPlot @VERSION | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */if(!document.createElement("canvas").getContext){(function(){var ab=Math;var n=ab.round;var l=ab.sin;var A=ab.cos;var H=ab.abs;var N=ab.sqrt;var d=10;var f=d/2;var z=+navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];function y(){return this.context_||(this.context_=new D(this))}var t=Array.prototype.slice;function g(j,m,p){var i=t.call(arguments,2);return function(){return j.apply(m,i.concat(t.call(arguments)))}}function af(i){return String(i).replace(/&/g,"&").replace(/"/g,""")}function Y(m,j,i){if(!m.namespaces[j]){m.namespaces.add(j,i,"#default#VML")}}function R(j){Y(j,"g_vml_","urn:schemas-microsoft-com:vml");Y(j,"g_o_","urn:schemas-microsoft-com:office:office");if(!j.styleSheets.ex_canvas_){var i=j.createStyleSheet();i.owningElement.id="ex_canvas_";i.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}R(document);var e={init:function(i){var j=i||document;j.createElement("canvas");j.attachEvent("onreadystatechange",g(this.init_,this,j))},init_:function(p){var m=p.getElementsByTagName("canvas");for(var j=0;j1){m--}if(6*m<1){return j+(i-j)*6*m}else{if(2*m<1){return i}else{if(3*m<2){return j+(i-j)*(2/3-m)*6}else{return j}}}}var C={};function F(j){if(j in C){return C[j]}var ag,Z=1;j=String(j);if(j.charAt(0)=="#"){ag=j}else{if(/^rgb/.test(j)){var p=M(j);var ag="#",ah;for(var m=0;m<3;m++){if(p[m].indexOf("%")!=-1){ah=Math.floor(c(p[m])*255)}else{ah=+p[m]}ag+=k[r(ah,0,255)]}Z=+p[3]}else{if(/^hsl/.test(j)){var p=M(j);ag=I(p);Z=p[3]}else{ag=b[j]||j}}}return C[j]={color:ag,alpha:Z}}var o={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"};var L={};function E(i){if(L[i]){return L[i]}var p=document.createElement("div");var m=p.style;try{m.font=i}catch(j){}return L[i]={style:m.fontStyle||o.style,variant:m.fontVariant||o.variant,weight:m.fontWeight||o.weight,size:m.fontSize||o.size,family:m.fontFamily||o.family}}function u(m,j){var i={};for(var ah in m){i[ah]=m[ah]}var ag=parseFloat(j.currentStyle.fontSize),Z=parseFloat(m.size);if(typeof m.size=="number"){i.size=m.size}else{if(m.size.indexOf("px")!=-1){i.size=Z}else{if(m.size.indexOf("em")!=-1){i.size=ag*Z}else{if(m.size.indexOf("%")!=-1){i.size=(ag/100)*Z}else{if(m.size.indexOf("pt")!=-1){i.size=Z/0.75}else{i.size=ag}}}}}i.size*=0.981;i.family="'"+i.family.replace(/(\'|\")/g,"").replace(/\s*,\s*/g,"', '")+"'";return i}function ac(i){return i.style+" "+i.variant+" "+i.weight+" "+i.size+"px "+i.family}var s={butt:"flat",round:"round"};function S(i){return s[i]||"square"}function D(i){this.m_=B();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=d*1;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=i;var m="width:"+i.clientWidth+"px;height:"+i.clientHeight+"px;overflow:hidden;position:absolute";var j=i.ownerDocument.createElement("div");j.style.cssText=m;i.appendChild(j);var p=j.cloneNode(false);p.style.backgroundColor="red";p.style.filter="alpha(opacity=0)";i.appendChild(p);this.element_=j;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var q=D.prototype;q.clearRect=function(){if(this.textMeasureEl_){this.textMeasureEl_.removeNode(true);this.textMeasureEl_=null}this.element_.innerHTML=""};q.beginPath=function(){this.currentPath_=[]};q.moveTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"moveTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.lineTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"lineTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.bezierCurveTo=function(m,j,ak,aj,ai,ag){var i=V(this,ai,ag);var ah=V(this,m,j);var Z=V(this,ak,aj);K(this,ah,Z,i)};function K(i,Z,m,j){i.currentPath_.push({type:"bezierCurveTo",cp1x:Z.x,cp1y:Z.y,cp2x:m.x,cp2y:m.y,x:j.x,y:j.y});i.currentX_=j.x;i.currentY_=j.y}q.quadraticCurveTo=function(ai,m,j,i){var ah=V(this,ai,m);var ag=V(this,j,i);var aj={x:this.currentX_+2/3*(ah.x-this.currentX_),y:this.currentY_+2/3*(ah.y-this.currentY_)};var Z={x:aj.x+(ag.x-this.currentX_)/3,y:aj.y+(ag.y-this.currentY_)/3};K(this,aj,Z,ag)};q.arc=function(al,aj,ak,ag,j,m){ak*=d;var ap=m?"at":"wa";var am=al+A(ag)*ak-f;var ao=aj+l(ag)*ak-f;var i=al+A(j)*ak-f;var an=aj+l(j)*ak-f;if(am==i&&!m){am+=0.125}var Z=V(this,al,aj);var ai=V(this,am,ao);var ah=V(this,i,an);this.currentPath_.push({type:ap,x:Z.x,y:Z.y,radius:ak,xStart:ai.x,yStart:ai.y,xEnd:ah.x,yEnd:ah.y})};q.rect=function(m,j,i,p){this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath()};q.strokeRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.stroke();this.currentPath_=Z};q.fillRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.fill();this.currentPath_=Z};q.createLinearGradient=function(j,p,i,m){var Z=new U("gradient");Z.x0_=j;Z.y0_=p;Z.x1_=i;Z.y1_=m;return Z};q.createRadialGradient=function(p,ag,m,j,Z,i){var ah=new U("gradientradial");ah.x0_=p;ah.y0_=ag;ah.r0_=m;ah.x1_=j;ah.y1_=Z;ah.r1_=i;return ah};q.drawImage=function(aq,m){var aj,ah,al,ay,ao,am,at,aA;var ak=aq.runtimeStyle.width;var ap=aq.runtimeStyle.height;aq.runtimeStyle.width="auto";aq.runtimeStyle.height="auto";var ai=aq.width;var aw=aq.height;aq.runtimeStyle.width=ak;aq.runtimeStyle.height=ap;if(arguments.length==3){aj=arguments[1];ah=arguments[2];ao=am=0;at=al=ai;aA=ay=aw}else{if(arguments.length==5){aj=arguments[1];ah=arguments[2];al=arguments[3];ay=arguments[4];ao=am=0;at=ai;aA=aw}else{if(arguments.length==9){ao=arguments[1];am=arguments[2];at=arguments[3];aA=arguments[4];aj=arguments[5];ah=arguments[6];al=arguments[7];ay=arguments[8]}else{throw Error("Invalid number of arguments")}}}var az=V(this,aj,ah);var p=at/2;var j=aA/2;var ax=[];var i=10;var ag=10;ax.push(" ','","");this.element_.insertAdjacentHTML("BeforeEnd",ax.join(""))};q.stroke=function(al){var aj=[];var Z=false;var m=10;var am=10;aj.push("ak.x){ak.x=j.x}if(ag.y==null||j.yak.y){ak.y=j.y}}}aj.push(' ">');if(!al){w(this,aj)}else{G(this,aj,ag,ak)}aj.push("");this.element_.insertAdjacentHTML("beforeEnd",aj.join(""))};function w(m,ag){var j=F(m.strokeStyle);var p=j.color;var Z=j.alpha*m.globalAlpha;var i=m.lineScale_*m.lineWidth;if(i<1){Z*=i}ag.push("')}function G(aq,ai,aK,ar){var aj=aq.fillStyle;var aB=aq.arcScaleX_;var aA=aq.arcScaleY_;var j=ar.x-aK.x;var p=ar.y-aK.y;if(aj instanceof U){var an=0;var aF={x:0,y:0};var ax=0;var am=1;if(aj.type_=="gradient"){var al=aj.x0_/aB;var m=aj.y0_/aA;var ak=aj.x1_/aB;var aM=aj.y1_/aA;var aJ=V(aq,al,m);var aI=V(aq,ak,aM);var ag=aI.x-aJ.x;var Z=aI.y-aJ.y;an=Math.atan2(ag,Z)*180/Math.PI;if(an<0){an+=360}if(an<0.000001){an=0}}else{var aJ=V(aq,aj.x0_,aj.y0_);aF={x:(aJ.x-aK.x)/j,y:(aJ.y-aK.y)/p};j/=aB*d;p/=aA*d;var aD=ab.max(j,p);ax=2*aj.r0_/aD;am=2*aj.r1_/aD-ax}var av=aj.colors_;av.sort(function(aN,i){return aN.offset-i.offset});var ap=av.length;var au=av[0].color;var at=av[ap-1].color;var az=av[0].alpha*aq.globalAlpha;var ay=av[ap-1].alpha*aq.globalAlpha;var aE=[];for(var aH=0;aH')}else{if(aj instanceof T){if(j&&p){var ah=-aK.x;var aC=-aK.y;ai.push("')}}else{var aL=F(aq.fillStyle);var aw=aL.color;var aG=aL.alpha*aq.globalAlpha;ai.push('')}}}q.fill=function(){this.stroke(true)};q.closePath=function(){this.currentPath_.push({type:"close"})};function V(j,Z,p){var i=j.m_;return{x:d*(Z*i[0][0]+p*i[1][0]+i[2][0])-f,y:d*(Z*i[0][1]+p*i[1][1]+i[2][1])-f}}q.save=function(){var i={};v(this,i);this.aStack_.push(i);this.mStack_.push(this.m_);this.m_=J(B(),this.m_)};q.restore=function(){if(this.aStack_.length){v(this.aStack_.pop(),this);this.m_=this.mStack_.pop()}};function h(i){return isFinite(i[0][0])&&isFinite(i[0][1])&&isFinite(i[1][0])&&isFinite(i[1][1])&&isFinite(i[2][0])&&isFinite(i[2][1])}function aa(j,i,p){if(!h(i)){return}j.m_=i;if(p){var Z=i[0][0]*i[1][1]-i[0][1]*i[1][0];j.lineScale_=N(H(Z))}}q.translate=function(m,j){var i=[[1,0,0],[0,1,0],[m,j,1]];aa(this,J(i,this.m_),false)};q.rotate=function(j){var p=A(j);var m=l(j);var i=[[p,m,0],[-m,p,0],[0,0,1]];aa(this,J(i,this.m_),false)};q.scale=function(m,j){this.arcScaleX_*=m;this.arcScaleY_*=j;var i=[[m,0,0],[0,j,0],[0,0,1]];aa(this,J(i,this.m_),true)};q.transform=function(Z,p,ah,ag,j,i){var m=[[Z,p,0],[ah,ag,0],[j,i,1]];aa(this,J(m,this.m_),true)};q.setTransform=function(ag,Z,ai,ah,p,j){var i=[[ag,Z,0],[ai,ah,0],[p,j,1]];aa(this,i,true)};q.drawText_=function(am,ak,aj,ap,ai){var ao=this.m_,at=1000,j=0,ar=at,ah={x:0,y:0},ag=[];var i=u(E(this.font),this.element_);var p=ac(i);var au=this.element_.currentStyle;var Z=this.textAlign.toLowerCase();switch(Z){case"left":case"center":case"right":break;case"end":Z=au.direction=="ltr"?"right":"left";break;case"start":Z=au.direction=="rtl"?"right":"left";break;default:Z="left"}switch(this.textBaseline){case"hanging":case"top":ah.y=i.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":ah.y=-i.size/2.25;break}switch(Z){case"right":j=at;ar=0.05;break;case"center":j=ar=at/2;break}var aq=V(this,ak+ah.x,aj+ah.y);ag.push('');if(ai){w(this,ag)}else{G(this,ag,{x:-j,y:0},{x:ar,y:i.size})}var an=ao[0][0].toFixed(3)+","+ao[1][0].toFixed(3)+","+ao[0][1].toFixed(3)+","+ao[1][1].toFixed(3)+",0,0";var al=n(aq.x/d+1-ao[0][0])+","+n(aq.y/d-2*ao[1][0]);ag.push('','','');this.element_.insertAdjacentHTML("beforeEnd",ag.join(""))};q.fillText=function(m,i,p,j){this.drawText_(m,i,p,j,false)};q.strokeText=function(m,i,p,j){this.drawText_(m,i,p,j,true)};q.measureText=function(m){if(!this.textMeasureEl_){var i='';this.element_.insertAdjacentHTML("beforeEnd",i);this.textMeasureEl_=this.element_.lastChild}var j=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(j.createTextNode(m));return{width:this.textMeasureEl_.offsetWidth}};q.clip=function(){};q.arcTo=function(){};q.createPattern=function(j,i){return new T(j,i)};function U(i){this.type_=i;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}U.prototype.addColorStop=function(j,i){i=F(i);this.colors_.push({offset:j,color:i.color,alpha:i.alpha})};function T(j,i){Q(j);switch(i){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=i;break;default:O("SYNTAX_ERR")}this.src_=j.src;this.width_=j.width;this.height_=j.height}function O(i){throw new P(i)}function Q(i){if(!i||i.nodeType!=1||i.tagName!="IMG"){O("TYPE_MISMATCH_ERR")}if(i.readyState!="complete"){O("INVALID_STATE_ERR")}}function P(i){this.code=this[i];this.message=i+": DOM Exception "+this.code}var X=P.prototype=new Error;X.INDEX_SIZE_ERR=1;X.DOMSTRING_SIZE_ERR=2;X.HIERARCHY_REQUEST_ERR=3;X.WRONG_DOCUMENT_ERR=4;X.INVALID_CHARACTER_ERR=5;X.NO_DATA_ALLOWED_ERR=6;X.NO_MODIFICATION_ALLOWED_ERR=7;X.NOT_FOUND_ERR=8;X.NOT_SUPPORTED_ERR=9;X.INUSE_ATTRIBUTE_ERR=10;X.INVALID_STATE_ERR=11;X.SYNTAX_ERR=12;X.INVALID_MODIFICATION_ERR=13;X.NAMESPACE_ERR=14;X.INVALID_ACCESS_ERR=15;X.VALIDATION_ERR=16;X.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=e;CanvasRenderingContext2D=D;CanvasGradient=U;CanvasPattern=T;DOMException=P;G_vmlCanvasManager._version=888})()}; \ No newline at end of file diff --git a/plugin/jqplot/jqplot.barRenderer.min.js b/plugin/jqplot/jqplot.barRenderer.min.js new file mode 100644 index 000000000..93d7a45c5 --- /dev/null +++ b/plugin/jqplot/jqplot.barRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(d){d.jqplot.BarRenderer=function(){d.jqplot.LineRenderer.call(this)};d.jqplot.BarRenderer.prototype=new d.jqplot.LineRenderer();d.jqplot.BarRenderer.prototype.constructor=d.jqplot.BarRenderer;d.jqplot.BarRenderer.prototype.init=function(o,q){this.barPadding=8;this.barMargin=10;this.barDirection="vertical";this.barWidth=null;this.shadowOffset=2;this.shadowDepth=5;this.shadowAlpha=0.08;this.waterfall=false;this.groups=1;this.varyBarColor=false;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.transposedData=true;this.renderer.animation={show:false,direction:"down",speed:3000,_supported:true};this._type="bar";if(o.highlightMouseDown&&o.highlightMouseOver==null){o.highlightMouseOver=false}d.extend(true,this,o);d.extend(true,this.renderer,o);this.fill=true;if(this.barDirection==="horizontal"&&this.rendererOptions.animation&&this.rendererOptions.animation.direction==null){this.renderer.animation.direction="left"}if(this.waterfall){this.fillToZero=false;this.disableStack=true}if(this.barDirection=="vertical"){this._primaryAxis="_xaxis";this._stackAxis="y";this.fillAxis="y"}else{this._primaryAxis="_yaxis";this._stackAxis="x";this.fillAxis="x"}this._highlightedPoint=null;this._plotSeriesInfo=null;this._dataColors=[];this._barPoints=[];var p={lineJoin:"miter",lineCap:"round",fill:true,isarc:false,strokeStyle:this.color,fillStyle:this.color,closePath:this.fill};this.renderer.shapeRenderer.init(p);var n={lineJoin:"miter",lineCap:"round",fill:true,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,closePath:this.fill};this.renderer.shadowRenderer.init(n);q.postInitHooks.addOnce(h);q.postDrawHooks.addOnce(j);q.eventListenerHooks.addOnce("jqplotMouseMove",b);q.eventListenerHooks.addOnce("jqplotMouseDown",a);q.eventListenerHooks.addOnce("jqplotMouseUp",l);q.eventListenerHooks.addOnce("jqplotClick",e);q.eventListenerHooks.addOnce("jqplotRightClick",m)};function g(t,p,o,w){if(this.rendererOptions.barDirection=="horizontal"){this._stackAxis="x";this._primaryAxis="_yaxis"}if(this.rendererOptions.waterfall==true){this._data=d.extend(true,[],this.data);var s=0;var u=(!this.rendererOptions.barDirection||this.rendererOptions.barDirection==="vertical"||this.transposedData===false)?1:0;for(var q=0;q0){this.data[q][u]+=this.data[q-1][u]}}this.data[this.data.length]=(u==1)?[this.data.length+1,s]:[s,this.data.length+1];this._data[this._data.length]=(u==1)?[this._data.length+1,s]:[s,this._data.length+1]}if(this.rendererOptions.groups>1){this.breakOnNull=true;var n=this.data.length;var v=parseInt(n/this.rendererOptions.groups,10);var r=0;for(var q=v;q570)?n[p]*0.8:n[p]+0.3*(255-n[p]);n[p]=parseInt(n[p],10)}q.push("rgb("+n[0]+","+n[1]+","+n[2]+")")}return q}function i(v,u,s,t,o){var q=v,w=v-1,n,p,r=(o==="x")?0:1;if(q>0){p=t.series[w]._plotData[u][r];if((s*p)<0){n=i(w,u,s,t,o)}else{n=t.series[w].gridData[u][r]}}else{n=(r===0)?t.series[q]._xaxis.series_u2p(0):t.series[q]._yaxis.series_u2p(0)}return n}d.jqplot.BarRenderer.prototype.draw=function(E,L,q,G){var I;var A=d.extend({},q);var w=(A.shadow!=undefined)?A.shadow:this.shadow;var O=(A.showLine!=undefined)?A.showLine:this.showLine;var F=(A.fill!=undefined)?A.fill:this.fill;var p=this.xaxis;var J=this.yaxis;var y=this._xaxis.series_u2p;var K=this._yaxis.series_u2p;var D,C;this._dataColors=[];this._barPoints=[];if(this.barWidth==null){this.renderer.setBarWidth.call(this)}var N=this._plotSeriesInfo=this.renderer.calcSeriesNumbers.call(this);var x=N[0];var v=N[1];var s=N[2];var H=[];if(this._stack){this._barNudge=0}else{this._barNudge=(-Math.abs(v/2-0.5)+s)*(this.barWidth+this.barPadding)}if(O){var u=new d.jqplot.ColorGenerator(this.negativeSeriesColors);var B=new d.jqplot.ColorGenerator(this.seriesColors);var M=u.get(this.index);if(!this.useNegativeColors){M=A.fillStyle}var t=A.fillStyle;var r;var P;var o;if(this.barDirection=="vertical"){for(var I=0;I0&&I=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._yaxis.min<=0&&this._yaxis.max>=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{o=E.canvas.height}}}}}if((this.fillToZero&&this._plotData[I][1]<0)||(this.waterfall&&this._data[I][1]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][1]>=0){H.push([r-this.barWidth/2,o]);H.push([r-this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,o])}else{H.push([r-this.barWidth/2,L[I][1]]);H.push([r-this.barWidth/2,o]);H.push([r+this.barWidth/2,o]);H.push([r+this.barWidth/2,L[I][1]])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}else{if(this.barDirection=="horizontal"){for(var I=0;I0&&I=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._xaxis.min<=0&&this._xaxis.max>=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=E.canvas.width}}}else{P=0}}}}}if((this.fillToZero&&this._plotData[I][0]<0)||(this.waterfall&&this._data[I][0]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][0]>=0){H.push([P,r+this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([L[I][0],r+this.barWidth/2])}else{H.push([L[I][0],r+this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([P,r+this.barWidth/2])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}}}if(this.highlightColors.length==0){this.highlightColors=d.jqplot.computeHighlightColors(this._dataColors)}else{if(typeof(this.highlightColors)=="string"){var N=this.highlightColors;this.highlightColors=[];for(var I=0;Ib.max||b.max==null){b.max=h[c][0]}}else{if(h[c][1]b.max||b.max==null){b.max=h[c][1]}}}}if(this.groupLabels.length){this.groups=this.groupLabels.length}};a.jqplot.CategoryAxisRenderer.prototype.createTicks=function(){var D=this._ticks;var z=this.ticks;var F=this.name;var C=this._dataBounds;var v,A;var q,w;var d,c;var b,x;if(z.length){if(this.groups>1&&!this._grouped){var r=z.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x1&&!this._grouped){var r=y.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x0&&o
            ');if(this.name=="xaxis"||this.name=="x2axis"){this._elem.width(this._plotDimensions.width)}else{this._elem.height(this._plotDimensions.height)}this.labelOptions.axis=this.name;this._label=new this.labelRenderer(this.labelOptions);if(this._label.show){var g=this._label.draw(b,j);g.appendTo(this._elem)}var f=this._ticks;for(var e=0;e
            ');g.html(this.groupLabels[e]);this._groupLabels.push(g);g.appendTo(this._elem)}}return this._elem};a.jqplot.CategoryAxisRenderer.prototype.set=function(){var e=0;var m;var k=0;var f=0;var d=(this._label==null)?false:this._label.show;if(this.show){var n=this._ticks;for(var c=0;ce){e=m}}}var j=0;for(var c=0;cj){j=m}}if(d){k=this._label._elem.outerWidth(true);f=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){e+=j+k;this._elem.css({width:e+"px",left:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}else{e+=j+k;this._elem.css({width:e+"px",right:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}}}}};a.jqplot.CategoryAxisRenderer.prototype.pack=function(e,c){var C=this._ticks;var v=this.max;var s=this.min;var n=c.max;var l=c.min;var q=(this._label==null)?false:this._label.show;var x;for(var r in e){this._elem.css(r,e[r])}this._offsets=c;var g=n-l;var k=v-s;if(!this.reverse){this.u2p=function(h){return(h-s)*g/k+l};this.p2u=function(h){return(h-l)*k/g+s};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(h-s)*g/k};this.series_p2u=function(h){return h*k/g+s}}else{this.series_u2p=function(h){return(h-v)*g/k};this.series_p2u=function(h){return h*k/g+v}}}else{this.u2p=function(h){return l+(v-h)*g/k};this.p2u=function(h){return s+(h-l)*k/g};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(v-h)*g/k};this.series_p2u=function(h){return h*k/g+v}}else{this.series_u2p=function(h){return(s-h)*g/k};this.series_p2u=function(h){return h*k/g+s}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(x=0;x=this._ticks.length-1){continue}if(this._ticks[u]._elem&&this._ticks[u].label!=" "){var o=this._ticks[u]._elem;var r=o.position();B+=r.left+o.outerWidth(true)/2;f++}}B=B/f;this._groupLabels[x].css({left:(B-this._groupLabels[x].outerWidth(true)/2)});this._groupLabels[x].css(z[0],z[1])}}else{for(x=0;x0){b=-o._textRenderer.height*Math.cos(-o._textRenderer.angle)/2}else{b=-o.getHeight()+o._textRenderer.height*Math.cos(o._textRenderer.angle)/2}break;case"middle":b=-o.getHeight()/2;break;default:b=-o.getHeight()/2;break}}else{b=-o.getHeight()/2}var D=this.u2p(o.value)+b+"px";o._elem.css("top",D);o.pack()}}var z=["left",0];if(q){var y=this._label._elem.outerHeight(true);this._label._elem.css("top",n-g/2-y/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px");z=["left",this._label._elem.outerWidth(true)]}else{this._label._elem.css("right","0px");z=["right",this._label._elem.outerWidth(true)]}this._label.pack()}var d=parseInt(this._ticks.length/this.groups,10)+1;for(x=0;x=this._ticks.length-1){continue}if(this._ticks[u]._elem&&this._ticks[u].label!=" "){var o=this._ticks[u]._elem;var r=o.position();B+=r.top+o.outerHeight()/2;f++}}B=B/f;this._groupLabels[x].css({top:B-this._groupLabels[x].outerHeight()/2});this._groupLabels[x].css(z[0],z[1])}}}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/jqplot.pointLabels.min.js b/plugin/jqplot/jqplot.pointLabels.min.js new file mode 100644 index 000000000..01a75629f --- /dev/null +++ b/plugin/jqplot/jqplot.pointLabels.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(c){c.jqplot.PointLabels=function(e){this.show=c.jqplot.config.enablePlugins;this.location="n";this.labelsFromSeries=false;this.seriesLabelIndex=null;this.labels=[];this._labels=[];this.stackedValue=false;this.ypadding=6;this.xpadding=6;this.escapeHTML=true;this.edgeTolerance=-5;this.formatter=c.jqplot.DefaultTickFormatter;this.formatString="";this.hideZeros=false;this._elems=[];c.extend(true,this,e)};var a=["nw","n","ne","e","se","s","sw","w"];var d={nw:0,n:1,ne:2,e:3,se:4,s:5,sw:6,w:7};var b=["se","s","sw","w","nw","n","ne","e"];c.jqplot.PointLabels.init=function(j,h,f,g,i){var e=c.extend(true,{},f,g);e.pointLabels=e.pointLabels||{};if(this.renderer.constructor===c.jqplot.BarRenderer&&this.barDirection==="horizontal"&&!e.pointLabels.location){e.pointLabels.location="e"}this.plugins.pointLabels=new c.jqplot.PointLabels(e.pointLabels);this.plugins.pointLabels.setLabels.call(this)};c.jqplot.PointLabels.prototype.setLabels=function(){var f=this.plugins.pointLabels;var h;if(f.seriesLabelIndex!=null){h=f.seriesLabelIndex}else{if(this.renderer.constructor===c.jqplot.BarRenderer&&this.barDirection==="horizontal"){h=(this._plotData[0].length<3)?0:this._plotData[0].length-1}else{h=(this._plotData.length===0)?0:this._plotData[0].length-1}}f._labels=[];if(f.labels.length===0||f.labelsFromSeries){if(f.stackedValue){if(this._plotData.length&&this._plotData[0].length){for(var e=0;eB||s+C>m){z.remove()}z=null;f=null}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/jquery.jqplot.css b/plugin/jqplot/jquery.jqplot.css new file mode 100644 index 000000000..db4224555 --- /dev/null +++ b/plugin/jqplot/jquery.jqplot.css @@ -0,0 +1,261 @@ +/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/ +.jqplot-target { + position: relative; + color: #666666; + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; + font-size: 1em; +/* height: 300px; + width: 400px;*/ +} + +/*rules applied to all axes*/ +.jqplot-axis { + font-size: 0.9em; +} + +.jqplot-xaxis { + margin-top: 10px; +} + +.jqplot-x2axis { + margin-bottom: 10px; +} + +.jqplot-yaxis { + margin-right: 10px; +} + +.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis { + margin-left: 10px; + margin-right: 10px; +} + +/*rules applied to all axis tick divs*/ +.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick { + position: absolute; + white-space: pre; +} + + +.jqplot-xaxis-tick { + top: 0px; + /* initial position untill tick is drawn in proper place */ + left: 15px; +/* padding-top: 10px;*/ + vertical-align: top; +} + +.jqplot-x2axis-tick { + bottom: 0px; + /* initial position untill tick is drawn in proper place */ + left: 15px; +/* padding-bottom: 10px;*/ + vertical-align: bottom; +} + +.jqplot-yaxis-tick { + right: 0px; + /* initial position untill tick is drawn in proper place */ + top: 15px; +/* padding-right: 10px;*/ + text-align: right; +} + +.jqplot-yaxis-tick.jqplot-breakTick { + right: -20px; + margin-right: 0px; + padding:1px 5px 1px 5px; + /*background-color: white;*/ + z-index: 2; + font-size: 1.5em; +} + +.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { + left: 0px; + /* initial position untill tick is drawn in proper place */ + top: 15px; +/* padding-left: 10px;*/ +/* padding-right: 15px;*/ + text-align: left; +} + +.jqplot-yMidAxis-tick { + text-align: center; + white-space: nowrap; +} + +.jqplot-xaxis-label { + margin-top: 10px; + font-size: 11pt; + position: absolute; +} + +.jqplot-x2axis-label { + margin-bottom: 10px; + font-size: 11pt; + position: absolute; +} + +.jqplot-yaxis-label { + margin-right: 10px; +/* text-align: center;*/ + font-size: 11pt; + position: absolute; +} + +.jqplot-yMidAxis-label { + font-size: 11pt; + position: absolute; +} + +.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label { +/* text-align: center;*/ + font-size: 11pt; + margin-left: 10px; + position: absolute; +} + +.jqplot-meterGauge-tick { + font-size: 0.75em; + color: #999999; +} + +.jqplot-meterGauge-label { + font-size: 1em; + color: #999999; +} + +table.jqplot-table-legend { + margin-top: 12px; + margin-bottom: 12px; + margin-left: 12px; + margin-right: 12px; +} + +table.jqplot-table-legend, table.jqplot-cursor-legend { + background-color: rgba(255,255,255,0.6); + border: 1px solid #cccccc; + position: absolute; + font-size: 0.75em; +} + +td.jqplot-table-legend { + vertical-align:middle; +} + +/* +These rules could be used instead of assigning +element styles and relying on js object properties. +*/ + +/* +td.jqplot-table-legend-swatch { + padding-top: 0.5em; + text-align: center; +} + +tr.jqplot-table-legend:first td.jqplot-table-legend-swatch { + padding-top: 0px; +} +*/ + +td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { + cursor: pointer; +} + +.jqplot-table-legend .jqplot-series-hidden { + text-decoration: line-through; +} + +div.jqplot-table-legend-swatch-outline { + border: 1px solid #cccccc; + padding:1px; +} + +div.jqplot-table-legend-swatch { + width:0px; + height:0px; + border-top-width: 5px; + border-bottom-width: 5px; + border-left-width: 6px; + border-right-width: 6px; + border-top-style: solid; + border-bottom-style: solid; + border-left-style: solid; + border-right-style: solid; +} + +.jqplot-title { + top: 0px; + left: 0px; + padding-bottom: 0.5em; + font-size: 1.2em; +} + +table.jqplot-cursor-tooltip { + border: 1px solid #cccccc; + font-size: 0.75em; +} + + +.jqplot-cursor-tooltip { + border: 1px solid #cccccc; + font-size: 0.75em; + white-space: nowrap; + background: rgba(208,208,208,0.5); + padding: 1px; +} + +.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip { + border: 1px solid #cccccc; + font-size: 0.75em; + white-space: nowrap; + background: rgba(208,208,208,0.5); + padding: 1px; +} + +.jqplot-point-label { + font-size: 1em; + z-index: 2; + font-weight:bold; + color:#ff670f; +} + +td.jqplot-cursor-legend-swatch { + vertical-align: middle; + text-align: center; +} + +div.jqplot-cursor-legend-swatch { + width: 1.2em; + height: 0.7em; +} + +.jqplot-error { +/* Styles added to the plot target container when there is an error go here.*/ + text-align: center; +} + +.jqplot-error-message { +/* Styling of the custom error message div goes here.*/ + position: relative; + top: 46%; + display: inline-block; +} + +div.jqplot-bubble-label { + font-size: 0.8em; +/* background: rgba(90%, 90%, 90%, 0.15);*/ + padding-left: 2px; + padding-right: 2px; + color: rgb(20%, 20%, 20%); +} + +div.jqplot-bubble-label.jqplot-bubble-label-highlight { + background: rgba(90%, 90%, 90%, 0.7); +} + +div.jqplot-noData-container { + text-align: center; + background-color: rgba(96%, 96%, 96%, 0.3); +} diff --git a/plugin/jqplot/jquery.jqplot.js b/plugin/jqplot/jquery.jqplot.js new file mode 100644 index 000000000..49812b77f --- /dev/null +++ b/plugin/jqplot/jquery.jqplot.js @@ -0,0 +1,11411 @@ +/** + * Title: jqPlot Charts + * + * Pure JavaScript plotting plugin for jQuery. + * + * About: Version + * + * version: 1.0.8 + * revision: 1250 + * + * About: Copyright & License + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT and GPL version 2.0 licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * See and contained within this distribution for further information. + * + * The author would appreciate an email letting him know of any substantial + * use of jqPlot. You can reach the author at: chris at jqplot dot com + * or see http://www.jqplot.com/info.php. This is, of course, not required. + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php. + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + * + * About: Introduction + * + * jqPlot requires jQuery (1.4+ required for certain features). jQuery 1.4.2 is included in the distribution. + * To use jqPlot include jQuery, the jqPlot jQuery plugin, the jqPlot css file and optionally + * the excanvas script for IE support in your web page: + * + * > + * > + * > + * > + * + * jqPlot can be customized by overriding the defaults of any of the objects which make + * up the plot. The general usage of jqplot is: + * + * > chart = $.jqplot('targetElemId', [dataArray,...], {optionsObject}); + * + * The options available to jqplot are detailed in in the jqPlotOptions.txt file. + * + * An actual call to $.jqplot() may look like the + * examples below: + * + * > chart = $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]); + * + * or + * + * > dataArray = [34,12,43,55,77]; + * > chart = $.jqplot('targetElemId', [dataArray, ...], {title:'My Plot', axes:{yaxis:{min:20, max:100}}}); + * + * For more inforrmation, see . + * + * About: Usage + * + * See + * + * About: Available Options + * + * See for a list of options available thorugh the options object (not complete yet!) + * + * About: Options Usage + * + * See + * + * About: Changes + * + * See + * + */ + +(function($) { + // make sure undefined is undefined + var undefined; + + $.fn.emptyForce = function() { + for ( var i = 0, elem; (elem = $(this)[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + $.cleanData( elem.getElementsByTagName("*") ); + } + + // Remove any remaining nodes + if ($.jqplot.use_excanvas) { + elem.outerHTML = ""; + } + else { + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + } + + elem = null; + } + + return $(this); + }; + + $.fn.removeChildForce = function(parent) { + while ( parent.firstChild ) { + this.removeChildForce( parent.firstChild ); + parent.removeChild( parent.firstChild ); + } + }; + + $.fn.jqplot = function() { + var datas = []; + var options = []; + // see how many data arrays we have + for (var i=0, l=arguments.length; i'+msg+'
        '); + $('#'+target).addClass('jqplot-error'); + document.getElementById(target).style.background = $.jqplot.config.errorBackground; + document.getElementById(target).style.border = $.jqplot.config.errorBorder; + document.getElementById(target).style.fontFamily = $.jqplot.config.errorFontFamily; + document.getElementById(target).style.fontSize = $.jqplot.config.errorFontSize; + document.getElementById(target).style.fontStyle = $.jqplot.config.errorFontStyle; + document.getElementById(target).style.fontWeight = $.jqplot.config.errorFontWeight; + } + } + else { + plot.init(target, _data, _options); + plot.draw(); + plot.themeEngine.init.call(plot); + return plot; + } + }; + + $.jqplot.version = "1.0.8"; + $.jqplot.revision = "1250"; + + $.jqplot.targetCounter = 1; + + // canvas manager to reuse canvases on the plot. + // Should help solve problem of canvases not being freed and + // problem of waiting forever for firefox to decide to free memory. + $.jqplot.CanvasManager = function() { + // canvases are managed globally so that they can be reused + // across plots after they have been freed + if (typeof $.jqplot.CanvasManager.canvases == 'undefined') { + $.jqplot.CanvasManager.canvases = []; + $.jqplot.CanvasManager.free = []; + } + + var myCanvases = []; + + this.getCanvas = function() { + var canvas; + var makeNew = true; + + if (!$.jqplot.use_excanvas) { + for (var i = 0, l = $.jqplot.CanvasManager.canvases.length; i < l; i++) { + if ($.jqplot.CanvasManager.free[i] === true) { + makeNew = false; + canvas = $.jqplot.CanvasManager.canvases[i]; + // $(canvas).removeClass('jqplot-canvasManager-free').addClass('jqplot-canvasManager-inuse'); + $.jqplot.CanvasManager.free[i] = false; + myCanvases.push(i); + break; + } + } + } + + if (makeNew) { + canvas = document.createElement('canvas'); + myCanvases.push($.jqplot.CanvasManager.canvases.length); + $.jqplot.CanvasManager.canvases.push(canvas); + $.jqplot.CanvasManager.free.push(false); + } + + return canvas; + }; + + // this method has to be used after settings the dimesions + // on the element returned by getCanvas() + this.initCanvas = function(canvas) { + if ($.jqplot.use_excanvas) { + return window.G_vmlCanvasManager.initElement(canvas); + } + return canvas; + }; + + this.freeAllCanvases = function() { + for (var i = 0, l=myCanvases.length; i < l; i++) { + this.freeCanvas(myCanvases[i]); + } + myCanvases = []; + }; + + this.freeCanvas = function(idx) { + if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) { + // excanvas can't be reused, but properly unset + window.G_vmlCanvasManager.uninitElement($.jqplot.CanvasManager.canvases[idx]); + $.jqplot.CanvasManager.canvases[idx] = null; + } + else { + var canvas = $.jqplot.CanvasManager.canvases[idx]; + canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); + $(canvas).unbind().removeAttr('class').removeAttr('style'); + // Style attributes seemed to be still hanging around. wierd. Some ticks + // still retained a left: 0px attribute after reusing a canvas. + $(canvas).css({left: '', top: '', position: ''}); + // setting size to 0 may save memory of unused canvases? + canvas.width = 0; + canvas.height = 0; + $.jqplot.CanvasManager.free[idx] = true; + } + }; + + }; + + + // Convienence function that won't hang IE or FF without FireBug. + $.jqplot.log = function() { + if (window.console) { + window.console.log.apply(window.console, arguments); + } + }; + + $.jqplot.config = { + addDomReference: false, + enablePlugins:false, + defaultHeight:300, + defaultWidth:400, + UTCAdjust:false, + timezoneOffset: new Date(new Date().getTimezoneOffset() * 60000), + errorMessage: '', + errorBackground: '', + errorBorder: '', + errorFontFamily: '', + errorFontSize: '', + errorFontStyle: '', + errorFontWeight: '', + catchErrors: false, + defaultTickFormatString: "%.1f", + defaultColors: [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"], + defaultNegativeColors: [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399", "#945381", "#959E5C", "#C7AF7B", "#478396", "#907294"], + dashLength: 4, + gapLength: 4, + dotGapLength: 2.5, + srcLocation: 'jqplot/src/', + pluginLocation: 'jqplot/src/plugins/' + }; + + + $.jqplot.arrayMax = function( array ){ + return Math.max.apply( Math, array ); + }; + + $.jqplot.arrayMin = function( array ){ + return Math.min.apply( Math, array ); + }; + + $.jqplot.enablePlugins = $.jqplot.config.enablePlugins; + + // canvas related tests taken from modernizer: + // Copyright (c) 2009 - 2010 Faruk Ates. + // http://www.modernizr.com + + $.jqplot.support_canvas = function() { + if (typeof $.jqplot.support_canvas.result == 'undefined') { + $.jqplot.support_canvas.result = !!document.createElement('canvas').getContext; + } + return $.jqplot.support_canvas.result; + }; + + $.jqplot.support_canvas_text = function() { + if (typeof $.jqplot.support_canvas_text.result == 'undefined') { + if (window.G_vmlCanvasManager !== undefined && window.G_vmlCanvasManager._version > 887) { + $.jqplot.support_canvas_text.result = true; + } + else { + $.jqplot.support_canvas_text.result = !!(document.createElement('canvas').getContext && typeof document.createElement('canvas').getContext('2d').fillText == 'function'); + } + + } + return $.jqplot.support_canvas_text.result; + }; + + $.jqplot.use_excanvas = ((!$.support.boxModel || !$.support.objectAll || !$support.leadingWhitespace) && !$.jqplot.support_canvas()) ? true : false; + + /** + * + * Hooks: jqPlot Pugin Hooks + * + * $.jqplot.preInitHooks - called before initialization. + * $.jqplot.postInitHooks - called after initialization. + * $.jqplot.preParseOptionsHooks - called before user options are parsed. + * $.jqplot.postParseOptionsHooks - called after user options are parsed. + * $.jqplot.preDrawHooks - called before plot draw. + * $.jqplot.postDrawHooks - called after plot draw. + * $.jqplot.preDrawSeriesHooks - called before each series is drawn. + * $.jqplot.postDrawSeriesHooks - called after each series is drawn. + * $.jqplot.preDrawLegendHooks - called before the legend is drawn. + * $.jqplot.addLegendRowHooks - called at the end of legend draw, so plugins + * can add rows to the legend table. + * $.jqplot.preSeriesInitHooks - called before series is initialized. + * $.jqplot.postSeriesInitHooks - called after series is initialized. + * $.jqplot.preParseSeriesOptionsHooks - called before series related options + * are parsed. + * $.jqplot.postParseSeriesOptionsHooks - called after series related options + * are parsed. + * $.jqplot.eventListenerHooks - called at the end of plot drawing, binds + * listeners to the event canvas which lays on top of the grid area. + * $.jqplot.preDrawSeriesShadowHooks - called before series shadows are drawn. + * $.jqplot.postDrawSeriesShadowHooks - called after series shadows are drawn. + * + */ + + $.jqplot.preInitHooks = []; + $.jqplot.postInitHooks = []; + $.jqplot.preParseOptionsHooks = []; + $.jqplot.postParseOptionsHooks = []; + $.jqplot.preDrawHooks = []; + $.jqplot.postDrawHooks = []; + $.jqplot.preDrawSeriesHooks = []; + $.jqplot.postDrawSeriesHooks = []; + $.jqplot.preDrawLegendHooks = []; + $.jqplot.addLegendRowHooks = []; + $.jqplot.preSeriesInitHooks = []; + $.jqplot.postSeriesInitHooks = []; + $.jqplot.preParseSeriesOptionsHooks = []; + $.jqplot.postParseSeriesOptionsHooks = []; + $.jqplot.eventListenerHooks = []; + $.jqplot.preDrawSeriesShadowHooks = []; + $.jqplot.postDrawSeriesShadowHooks = []; + + // A superclass holding some common properties and methods. + $.jqplot.ElemContainer = function() { + this._elem; + this._plotWidth; + this._plotHeight; + this._plotDimensions = {height:null, width:null}; + }; + + $.jqplot.ElemContainer.prototype.createElement = function(el, offsets, clss, cssopts, attrib) { + this._offsets = offsets; + var klass = clss || 'jqplot'; + var elem = document.createElement(el); + this._elem = $(elem); + this._elem.addClass(klass); + this._elem.css(cssopts); + this._elem.attr(attrib); + // avoid memory leak; + elem = null; + return this._elem; + }; + + $.jqplot.ElemContainer.prototype.getWidth = function() { + if (this._elem) { + return this._elem.outerWidth(true); + } + else { + return null; + } + }; + + $.jqplot.ElemContainer.prototype.getHeight = function() { + if (this._elem) { + return this._elem.outerHeight(true); + } + else { + return null; + } + }; + + $.jqplot.ElemContainer.prototype.getPosition = function() { + if (this._elem) { + return this._elem.position(); + } + else { + return {top:null, left:null, bottom:null, right:null}; + } + }; + + $.jqplot.ElemContainer.prototype.getTop = function() { + return this.getPosition().top; + }; + + $.jqplot.ElemContainer.prototype.getLeft = function() { + return this.getPosition().left; + }; + + $.jqplot.ElemContainer.prototype.getBottom = function() { + return this._elem.css('bottom'); + }; + + $.jqplot.ElemContainer.prototype.getRight = function() { + return this._elem.css('right'); + }; + + + /** + * Class: Axis + * An individual axis object. Cannot be instantiated directly, but created + * by the Plot object. Axis properties can be set or overridden by the + * options passed in from the user. + * + */ + function Axis(name) { + $.jqplot.ElemContainer.call(this); + // Group: Properties + // + // Axes options are specified within an axes object at the top level of the + // plot options like so: + // > { + // > axes: { + // > xaxis: {min: 5}, + // > yaxis: {min: 2, max: 8, numberTicks:4}, + // > x2axis: {pad: 1.5}, + // > y2axis: {ticks:[22, 44, 66, 88]} + // > } + // > } + // There are 2 x axes, 'xaxis' and 'x2axis', and + // 9 yaxes, 'yaxis', 'y2axis'. 'y3axis', ... Any or all of which may be specified. + this.name = name; + this._series = []; + // prop: show + // Wether to display the axis on the graph. + this.show = false; + // prop: tickRenderer + // A class of a rendering engine for creating the ticks labels displayed on the plot, + // See <$.jqplot.AxisTickRenderer>. + this.tickRenderer = $.jqplot.AxisTickRenderer; + // prop: tickOptions + // Options that will be passed to the tickRenderer, see <$.jqplot.AxisTickRenderer> options. + this.tickOptions = {}; + // prop: labelRenderer + // A class of a rendering engine for creating an axis label. + this.labelRenderer = $.jqplot.AxisLabelRenderer; + // prop: labelOptions + // Options passed to the label renderer. + this.labelOptions = {}; + // prop: label + // Label for the axis + this.label = null; + // prop: showLabel + // true to show the axis label. + this.showLabel = true; + // prop: min + // minimum value of the axis (in data units, not pixels). + this.min = null; + // prop: max + // maximum value of the axis (in data units, not pixels). + this.max = null; + // prop: autoscale + // DEPRECATED + // the default scaling algorithm produces superior results. + this.autoscale = false; + // prop: pad + // Padding to extend the range above and below the data bounds. + // The data range is multiplied by this factor to determine minimum and maximum axis bounds. + // A value of 0 will be interpreted to mean no padding, and pad will be set to 1.0. + this.pad = 1.2; + // prop: padMax + // Padding to extend the range above data bounds. + // The top of the data range is multiplied by this factor to determine maximum axis bounds. + // A value of 0 will be interpreted to mean no padding, and padMax will be set to 1.0. + this.padMax = null; + // prop: padMin + // Padding to extend the range below data bounds. + // The bottom of the data range is multiplied by this factor to determine minimum axis bounds. + // A value of 0 will be interpreted to mean no padding, and padMin will be set to 1.0. + this.padMin = null; + // prop: ticks + // 1D [val, val, ...] or 2D [[val, label], [val, label], ...] array of ticks for the axis. + // If no label is specified, the value is formatted into an appropriate label. + this.ticks = []; + // prop: numberTicks + // Desired number of ticks. Default is to compute automatically. + this.numberTicks; + // prop: tickInterval + // number of units between ticks. Mutually exclusive with numberTicks. + this.tickInterval; + // prop: renderer + // A class of a rendering engine that handles tick generation, + // scaling input data to pixel grid units and drawing the axis element. + this.renderer = $.jqplot.LinearAxisRenderer; + // prop: rendererOptions + // renderer specific options. See <$.jqplot.LinearAxisRenderer> for options. + this.rendererOptions = {}; + // prop: showTicks + // Wether to show the ticks (both marks and labels) or not. + // Will not override showMark and showLabel options if specified on the ticks themselves. + this.showTicks = true; + // prop: showTickMarks + // Wether to show the tick marks (line crossing grid) or not. + // Overridden by showTicks and showMark option of tick itself. + this.showTickMarks = true; + // prop: showMinorTicks + // Wether or not to show minor ticks. This is renderer dependent. + this.showMinorTicks = true; + // prop: drawMajorGridlines + // True to draw gridlines for major axis ticks. + this.drawMajorGridlines = true; + // prop: drawMinorGridlines + // True to draw gridlines for minor ticks. + this.drawMinorGridlines = false; + // prop: drawMajorTickMarks + // True to draw tick marks for major axis ticks. + this.drawMajorTickMarks = true; + // prop: drawMinorTickMarks + // True to draw tick marks for minor ticks. This is renderer dependent. + this.drawMinorTickMarks = true; + // prop: useSeriesColor + // Use the color of the first series associated with this axis for the + // tick marks and line bordering this axis. + this.useSeriesColor = false; + // prop: borderWidth + // width of line stroked at the border of the axis. Defaults + // to the width of the grid boarder. + this.borderWidth = null; + // prop: borderColor + // color of the border adjacent to the axis. Defaults to grid border color. + this.borderColor = null; + // prop: scaleToHiddenSeries + // True to include hidden series when computing axes bounds and scaling. + this.scaleToHiddenSeries = false; + // minimum and maximum values on the axis. + this._dataBounds = {min:null, max:null}; + // statistics (min, max, mean) as well as actual data intervals for each series attached to axis. + // holds collection of {intervals:[], min:, max:, mean: } objects for each series on axis. + this._intervalStats = []; + // pixel position from the top left of the min value and max value on the axis. + this._offsets = {min:null, max:null}; + this._ticks=[]; + this._label = null; + // prop: syncTicks + // true to try and synchronize tick spacing across multiple axes so that ticks and + // grid lines line up. This has an impact on autoscaling algorithm, however. + // In general, autoscaling an individual axis will work better if it does not + // have to sync ticks. + this.syncTicks = null; + // prop: tickSpacing + // Approximate pixel spacing between ticks on graph. Used during autoscaling. + // This number will be an upper bound, actual spacing will be less. + this.tickSpacing = 75; + // Properties to hold the original values for min, max, ticks, tickInterval and numberTicks + // so they can be restored if altered by plugins. + this._min = null; + this._max = null; + this._tickInterval = null; + this._numberTicks = null; + this.__ticks = null; + // hold original user options. + this._options = {}; + } + + Axis.prototype = new $.jqplot.ElemContainer(); + Axis.prototype.constructor = Axis; + + Axis.prototype.init = function() { + if ($.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + // set the axis name + this.tickOptions.axis = this.name; + // if showMark or showLabel tick options not specified, use value of axis option. + // showTicks overrides showTickMarks. + if (this.tickOptions.showMark == null) { + this.tickOptions.showMark = this.showTicks; + } + if (this.tickOptions.showMark == null) { + this.tickOptions.showMark = this.showTickMarks; + } + if (this.tickOptions.showLabel == null) { + this.tickOptions.showLabel = this.showTicks; + } + + if (this.label == null || this.label == '') { + this.showLabel = false; + } + else { + this.labelOptions.label = this.label; + } + if (this.showLabel == false) { + this.labelOptions.show = false; + } + // set the default padMax, padMin if not specified + // special check, if no padding desired, padding + // should be set to 1.0 + if (this.pad == 0) { + this.pad = 1.0; + } + if (this.padMax == 0) { + this.padMax = 1.0; + } + if (this.padMin == 0) { + this.padMin = 1.0; + } + if (this.padMax == null) { + this.padMax = (this.pad-1)/2 + 1; + } + if (this.padMin == null) { + this.padMin = (this.pad-1)/2 + 1; + } + // now that padMin and padMax are correctly set, reset pad in case user has supplied + // padMin and/or padMax + this.pad = this.padMax + this.padMin - 1; + if (this.min != null || this.max != null) { + this.autoscale = false; + } + // if not set, sync ticks for y axes but not x by default. + if (this.syncTicks == null && this.name.indexOf('y') > -1) { + this.syncTicks = true; + } + else if (this.syncTicks == null){ + this.syncTicks = false; + } + this.renderer.init.call(this, this.rendererOptions); + + }; + + Axis.prototype.draw = function(ctx, plot) { + // Memory Leaks patch + if (this.__ticks) { + this.__ticks = null; + } + + return this.renderer.draw.call(this, ctx, plot); + + }; + + Axis.prototype.set = function() { + this.renderer.set.call(this); + }; + + Axis.prototype.pack = function(pos, offsets) { + if (this.show) { + this.renderer.pack.call(this, pos, offsets); + } + // these properties should all be available now. + if (this._min == null) { + this._min = this.min; + this._max = this.max; + this._tickInterval = this.tickInterval; + this._numberTicks = this.numberTicks; + this.__ticks = this._ticks; + } + }; + + // reset the axis back to original values if it has been scaled, zoomed, etc. + Axis.prototype.reset = function() { + this.renderer.reset.call(this); + }; + + Axis.prototype.resetScale = function(opts) { + $.extend(true, this, {min: null, max: null, numberTicks: null, tickInterval: null, _ticks: [], ticks: []}, opts); + this.resetDataBounds(); + }; + + Axis.prototype.resetDataBounds = function() { + // Go through all the series attached to this axis and find + // the min/max bounds for this axis. + var db = this._dataBounds; + db.min = null; + db.max = null; + var l, s, d; + // check for when to force min 0 on bar series plots. + var doforce = (this.show) ? true : false; + for (var i=0; i db.max) || db.max == null) { + db.max = d[j][0]; + } + } + else { + if ((d[j][minyidx] != null && d[j][minyidx] < db.min) || db.min == null) { + db.min = d[j][minyidx]; + } + if ((d[j][maxyidx] != null && d[j][maxyidx] > db.max) || db.max == null) { + db.max = d[j][maxyidx]; + } + } + } + + // Hack to not pad out bottom of bar plots unless user has specified a padding. + // every series will have a chance to set doforce to false. once it is set to + // false, it cannot be reset to true. + // If any series attached to axis is not a bar, wont force 0. + if (doforce && s.renderer.constructor !== $.jqplot.BarRenderer) { + doforce = false; + } + + else if (doforce && this._options.hasOwnProperty('forceTickAt0') && this._options.forceTickAt0 == false) { + doforce = false; + } + + else if (doforce && s.renderer.constructor === $.jqplot.BarRenderer) { + if (s.barDirection == 'vertical' && this.name != 'xaxis' && this.name != 'x2axis') { + if (this._options.pad != null || this._options.padMin != null) { + doforce = false; + } + } + + else if (s.barDirection == 'horizontal' && (this.name == 'xaxis' || this.name == 'x2axis')) { + if (this._options.pad != null || this._options.padMin != null) { + doforce = false; + } + } + + } + } + } + + if (doforce && this.renderer.constructor === $.jqplot.LinearAxisRenderer && db.min >= 0) { + this.padMin = 1.0; + this.forceTickAt0 = true; + } + }; + + /** + * Class: Legend + * Legend object. Cannot be instantiated directly, but created + * by the Plot object. Legend properties can be set or overridden by the + * options passed in from the user. + */ + function Legend(options) { + $.jqplot.ElemContainer.call(this); + // Group: Properties + + // prop: show + // Wether to display the legend on the graph. + this.show = false; + // prop: location + // Placement of the legend. one of the compass directions: nw, n, ne, e, se, s, sw, w + this.location = 'ne'; + // prop: labels + // Array of labels to use. By default the renderer will look for labels on the series. + // Labels specified in this array will override labels specified on the series. + this.labels = []; + // prop: showLabels + // true to show the label text on the legend. + this.showLabels = true; + // prop: showSwatch + // true to show the color swatches on the legend. + this.showSwatches = true; + // prop: placement + // "insideGrid" places legend inside the grid area of the plot. + // "outsideGrid" places the legend outside the grid but inside the plot container, + // shrinking the grid to accomodate the legend. + // "inside" synonym for "insideGrid", + // "outside" places the legend ouside the grid area, but does not shrink the grid which + // can cause the legend to overflow the plot container. + this.placement = "insideGrid"; + // prop: xoffset + // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc. + // properties or via CSS margin styling of the .jqplot-table-legend class. + this.xoffset = 0; + // prop: yoffset + // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc. + // properties or via CSS margin styling of the .jqplot-table-legend class. + this.yoffset = 0; + // prop: border + // css spec for the border around the legend box. + this.border; + // prop: background + // css spec for the background of the legend box. + this.background; + // prop: textColor + // css color spec for the legend text. + this.textColor; + // prop: fontFamily + // css font-family spec for the legend text. + this.fontFamily; + // prop: fontSize + // css font-size spec for the legend text. + this.fontSize ; + // prop: rowSpacing + // css padding-top spec for the rows in the legend. + this.rowSpacing = '0.5em'; + // renderer + // A class that will create a DOM object for the legend, + // see <$.jqplot.TableLegendRenderer>. + this.renderer = $.jqplot.TableLegendRenderer; + // prop: rendererOptions + // renderer specific options passed to the renderer. + this.rendererOptions = {}; + // prop: predraw + // Wether to draw the legend before the series or not. + // Used with series specific legend renderers for pie, donut, mekko charts, etc. + this.preDraw = false; + // prop: marginTop + // CSS margin for the legend DOM element. This will set an element + // CSS style for the margin which will override any style sheet setting. + // The default will be taken from the stylesheet. + this.marginTop = null; + // prop: marginRight + // CSS margin for the legend DOM element. This will set an element + // CSS style for the margin which will override any style sheet setting. + // The default will be taken from the stylesheet. + this.marginRight = null; + // prop: marginBottom + // CSS margin for the legend DOM element. This will set an element + // CSS style for the margin which will override any style sheet setting. + // The default will be taken from the stylesheet. + this.marginBottom = null; + // prop: marginLeft + // CSS margin for the legend DOM element. This will set an element + // CSS style for the margin which will override any style sheet setting. + // The default will be taken from the stylesheet. + this.marginLeft = null; + // prop: escapeHtml + // True to escape special characters with their html entity equivalents + // in legend text. "<" becomes < and so on, so html tags are not rendered. + this.escapeHtml = false; + this._series = []; + + $.extend(true, this, options); + } + + Legend.prototype = new $.jqplot.ElemContainer(); + Legend.prototype.constructor = Legend; + + Legend.prototype.setOptions = function(options) { + $.extend(true, this, options); + + // Try to emulate deprecated behaviour + // if user has specified xoffset or yoffset, copy these to + // the margin properties. + + if (this.placement == 'inside') { + this.placement = 'insideGrid'; + } + + if (this.xoffset >0) { + if (this.placement == 'insideGrid') { + switch (this.location) { + case 'nw': + case 'w': + case 'sw': + if (this.marginLeft == null) { + this.marginLeft = this.xoffset + 'px'; + } + this.marginRight = '0px'; + break; + case 'ne': + case 'e': + case 'se': + default: + if (this.marginRight == null) { + this.marginRight = this.xoffset + 'px'; + } + this.marginLeft = '0px'; + break; + } + } + else if (this.placement == 'outside') { + switch (this.location) { + case 'nw': + case 'w': + case 'sw': + if (this.marginRight == null) { + this.marginRight = this.xoffset + 'px'; + } + this.marginLeft = '0px'; + break; + case 'ne': + case 'e': + case 'se': + default: + if (this.marginLeft == null) { + this.marginLeft = this.xoffset + 'px'; + } + this.marginRight = '0px'; + break; + } + } + this.xoffset = 0; + } + + if (this.yoffset >0) { + if (this.placement == 'outside') { + switch (this.location) { + case 'sw': + case 's': + case 'se': + if (this.marginTop == null) { + this.marginTop = this.yoffset + 'px'; + } + this.marginBottom = '0px'; + break; + case 'ne': + case 'n': + case 'nw': + default: + if (this.marginBottom == null) { + this.marginBottom = this.yoffset + 'px'; + } + this.marginTop = '0px'; + break; + } + } + else if (this.placement == 'insideGrid') { + switch (this.location) { + case 'sw': + case 's': + case 'se': + if (this.marginBottom == null) { + this.marginBottom = this.yoffset + 'px'; + } + this.marginTop = '0px'; + break; + case 'ne': + case 'n': + case 'nw': + default: + if (this.marginTop == null) { + this.marginTop = this.yoffset + 'px'; + } + this.marginBottom = '0px'; + break; + } + } + this.yoffset = 0; + } + + // TO-DO: + // Handle case where offsets are < 0. + // + }; + + Legend.prototype.init = function() { + if ($.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + this.renderer.init.call(this, this.rendererOptions); + }; + + Legend.prototype.draw = function(offsets, plot) { + for (var i=0; i<$.jqplot.preDrawLegendHooks.length; i++){ + $.jqplot.preDrawLegendHooks[i].call(this, offsets); + } + return this.renderer.draw.call(this, offsets, plot); + }; + + Legend.prototype.pack = function(offsets) { + this.renderer.pack.call(this, offsets); + }; + + /** + * Class: Title + * Plot Title object. Cannot be instantiated directly, but created + * by the Plot object. Title properties can be set or overridden by the + * options passed in from the user. + * + * Parameters: + * text - text of the title. + */ + function Title(text) { + $.jqplot.ElemContainer.call(this); + // Group: Properties + + // prop: text + // text of the title; + this.text = text; + // prop: show + // whether or not to show the title + this.show = true; + // prop: fontFamily + // css font-family spec for the text. + this.fontFamily; + // prop: fontSize + // css font-size spec for the text. + this.fontSize ; + // prop: textAlign + // css text-align spec for the text. + this.textAlign; + // prop: textColor + // css color spec for the text. + this.textColor; + // prop: renderer + // A class for creating a DOM element for the title, + // see <$.jqplot.DivTitleRenderer>. + this.renderer = $.jqplot.DivTitleRenderer; + // prop: rendererOptions + // renderer specific options passed to the renderer. + this.rendererOptions = {}; + // prop: escapeHtml + // True to escape special characters with their html entity equivalents + // in title text. "<" becomes < and so on, so html tags are not rendered. + this.escapeHtml = false; + } + + Title.prototype = new $.jqplot.ElemContainer(); + Title.prototype.constructor = Title; + + Title.prototype.init = function() { + if ($.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + this.renderer.init.call(this, this.rendererOptions); + }; + + Title.prototype.draw = function(width) { + return this.renderer.draw.call(this, width); + }; + + Title.prototype.pack = function() { + this.renderer.pack.call(this); + }; + + + /** + * Class: Series + * An individual data series object. Cannot be instantiated directly, but created + * by the Plot object. Series properties can be set or overridden by the + * options passed in from the user. + */ + function Series(options) { + options = options || {}; + $.jqplot.ElemContainer.call(this); + // Group: Properties + // Properties will be assigned from a series array at the top level of the + // options. If you had two series and wanted to change the color and line + // width of the first and set the second to use the secondary y axis with + // no shadow and supply custom labels for each: + // > { + // > series:[ + // > {color: '#ff4466', lineWidth: 5, label:'good line'}, + // > {yaxis: 'y2axis', shadow: false, label:'bad line'} + // > ] + // > } + + // prop: show + // whether or not to draw the series. + this.show = true; + // prop: xaxis + // which x axis to use with this series, either 'xaxis' or 'x2axis'. + this.xaxis = 'xaxis'; + this._xaxis; + // prop: yaxis + // which y axis to use with this series, either 'yaxis' or 'y2axis'. + this.yaxis = 'yaxis'; + this._yaxis; + this.gridBorderWidth = 2.0; + // prop: renderer + // A class of a renderer which will draw the series, + // see <$.jqplot.LineRenderer>. + this.renderer = $.jqplot.LineRenderer; + // prop: rendererOptions + // Options to pass on to the renderer. + this.rendererOptions = {}; + this.data = []; + this.gridData = []; + // prop: label + // Line label to use in the legend. + this.label = ''; + // prop: showLabel + // true to show label for this series in the legend. + this.showLabel = true; + // prop: color + // css color spec for the series + this.color; + // prop: negativeColor + // css color spec used for filled (area) plots that are filled to zero and + // the "useNegativeColors" option is true. + this.negativeColor; + // prop: lineWidth + // width of the line in pixels. May have different meanings depending on renderer. + this.lineWidth = 2.5; + // prop: lineJoin + // Canvas lineJoin style between segments of series. + this.lineJoin = 'round'; + // prop: lineCap + // Canvas lineCap style at ends of line. + this.lineCap = 'round'; + // prop: linePattern + // line pattern 'dashed', 'dotted', 'solid', some combination + // of '-' and '.' characters such as '.-.' or a numerical array like + // [draw, skip, draw, skip, ...] such as [1, 10] to draw a dotted line, + // [1, 10, 20, 10] to draw a dot-dash line, and so on. + this.linePattern = 'solid'; + this.shadow = true; + // prop: shadowAngle + // Shadow angle in degrees + this.shadowAngle = 45; + // prop: shadowOffset + // Shadow offset from line in pixels + this.shadowOffset = 1.25; + // prop: shadowDepth + // Number of times shadow is stroked, each stroke offset shadowOffset from the last. + this.shadowDepth = 3; + // prop: shadowAlpha + // Alpha channel transparency of shadow. 0 = transparent. + this.shadowAlpha = '0.1'; + // prop: breakOnNull + // Wether line segments should be be broken at null value. + // False will join point on either side of line. + this.breakOnNull = false; + // prop: markerRenderer + // A class of a renderer which will draw marker (e.g. circle, square, ...) at the data points, + // see <$.jqplot.MarkerRenderer>. + this.markerRenderer = $.jqplot.MarkerRenderer; + // prop: markerOptions + // renderer specific options to pass to the markerRenderer, + // see <$.jqplot.MarkerRenderer>. + this.markerOptions = {}; + // prop: showLine + // whether to actually draw the line or not. Series will still be renderered, even if no line is drawn. + this.showLine = true; + // prop: showMarker + // whether or not to show the markers at the data points. + this.showMarker = true; + // prop: index + // 0 based index of this series in the plot series array. + this.index; + // prop: fill + // true or false, whether to fill under lines or in bars. + // May not be implemented in all renderers. + this.fill = false; + // prop: fillColor + // CSS color spec to use for fill under line. Defaults to line color. + this.fillColor; + // prop: fillAlpha + // Alpha transparency to apply to the fill under the line. + // Use this to adjust alpha separate from fill color. + this.fillAlpha; + // prop: fillAndStroke + // If true will stroke the line (with color this.color) as well as fill under it. + // Applies only when fill is true. + this.fillAndStroke = false; + // prop: disableStack + // true to not stack this series with other series in the plot. + // To render properly, non-stacked series must come after any stacked series + // in the plot's data series array. So, the plot's data series array would look like: + // > [stackedSeries1, stackedSeries2, ..., nonStackedSeries1, nonStackedSeries2, ...] + // disableStack will put a gap in the stacking order of series, and subsequent + // stacked series will not fill down through the non-stacked series and will + // most likely not stack properly on top of the non-stacked series. + this.disableStack = false; + // _stack is set by the Plot if the plot is a stacked chart. + // will stack lines or bars on top of one another to build a "mountain" style chart. + // May not be implemented in all renderers. + this._stack = false; + // prop: neighborThreshold + // how close or far (in pixels) the cursor must be from a point marker to detect the point. + this.neighborThreshold = 4; + // prop: fillToZero + // true will force bar and filled series to fill toward zero on the fill Axis. + this.fillToZero = false; + // prop: fillToValue + // fill a filled series to this value on the fill axis. + // Works in conjunction with fillToZero, so that must be true. + this.fillToValue = 0; + // prop: fillAxis + // Either 'x' or 'y'. Which axis to fill the line toward if fillToZero is true. + // 'y' means fill up/down to 0 on the y axis for this series. + this.fillAxis = 'y'; + // prop: useNegativeColors + // true to color negative values differently in filled and bar charts. + this.useNegativeColors = true; + this._stackData = []; + // _plotData accounts for stacking. If plots not stacked, _plotData and data are same. If + // stacked, _plotData is accumulation of stacking data. + this._plotData = []; + // _plotValues hold the individual x and y values that will be plotted for this series. + this._plotValues = {x:[], y:[]}; + // statistics about the intervals between data points. Used for auto scaling. + this._intervals = {x:{}, y:{}}; + // data from the previous series, for stacked charts. + this._prevPlotData = []; + this._prevGridData = []; + this._stackAxis = 'y'; + this._primaryAxis = '_xaxis'; + // give each series a canvas to draw on. This should allow for redrawing speedups. + this.canvas = new $.jqplot.GenericCanvas(); + this.shadowCanvas = new $.jqplot.GenericCanvas(); + this.plugins = {}; + // sum of y values in this series. + this._sumy = 0; + this._sumx = 0; + this._type = ''; + } + + Series.prototype = new $.jqplot.ElemContainer(); + Series.prototype.constructor = Series; + + Series.prototype.init = function(index, gridbw, plot) { + // weed out any null values in the data. + this.index = index; + this.gridBorderWidth = gridbw; + var d = this.data; + var temp = [], i, l; + for (i=0, l=d.length; i. + this.renderer = $.jqplot.CanvasGridRenderer; + // prop: rendererOptions + // Options to pass on to the renderer, + // see <$.jqplot.CanvasGridRenderer>. + this.rendererOptions = {}; + this._offsets = {top:null, bottom:null, left:null, right:null}; + } + + Grid.prototype = new $.jqplot.ElemContainer(); + Grid.prototype.constructor = Grid; + + Grid.prototype.init = function() { + if ($.isFunction(this.renderer)) { + this.renderer = new this.renderer(); + } + this.renderer.init.call(this, this.rendererOptions); + }; + + Grid.prototype.createElement = function(offsets,plot) { + this._offsets = offsets; + return this.renderer.createElement.call(this, plot); + }; + + Grid.prototype.draw = function() { + this.renderer.draw.call(this); + }; + + $.jqplot.GenericCanvas = function() { + $.jqplot.ElemContainer.call(this); + this._ctx; + }; + + $.jqplot.GenericCanvas.prototype = new $.jqplot.ElemContainer(); + $.jqplot.GenericCanvas.prototype.constructor = $.jqplot.GenericCanvas; + + $.jqplot.GenericCanvas.prototype.createElement = function(offsets, clss, plotDimensions, plot) { + this._offsets = offsets; + var klass = 'jqplot'; + if (clss != undefined) { + klass = clss; + } + var elem; + + elem = plot.canvasManager.getCanvas(); + + // if new plotDimensions supplied, use them. + if (plotDimensions != null) { + this._plotDimensions = plotDimensions; + } + + elem.width = this._plotDimensions.width - this._offsets.left - this._offsets.right; + elem.height = this._plotDimensions.height - this._offsets.top - this._offsets.bottom; + this._elem = $(elem); + this._elem.css({ position: 'absolute', left: this._offsets.left, top: this._offsets.top }); + + this._elem.addClass(klass); + + elem = plot.canvasManager.initCanvas(elem); + + elem = null; + return this._elem; + }; + + $.jqplot.GenericCanvas.prototype.setContext = function() { + this._ctx = this._elem.get(0).getContext("2d"); + return this._ctx; + }; + + // Memory Leaks patch + $.jqplot.GenericCanvas.prototype.resetCanvas = function() { + if (this._elem) { + if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) { + window.G_vmlCanvasManager.uninitElement(this._elem.get(0)); + } + + //this._elem.remove(); + this._elem.emptyForce(); + } + + this._ctx = null; + }; + + $.jqplot.HooksManager = function () { + this.hooks =[]; + this.args = []; + }; + + $.jqplot.HooksManager.prototype.addOnce = function(fn, args) { + args = args || []; + var havehook = false; + for (var i=0, l=this.hooks.length; i { + // > axesDefaults:{min:0}, + // > series:[{color:'#6633dd'}], + // > title: 'A Plot' + // > } + // + + // prop: animate + // True to animate the series on initial plot draw (renderer dependent). + // Actual animation functionality must be supported in the renderer. + this.animate = false; + // prop: animateReplot + // True to animate series after a call to the replot() method. + // Use with caution! Replots can happen very frequently under + // certain circumstances (e.g. resizing, dragging points) and + // animation in these situations can cause problems. + this.animateReplot = false; + // prop: axes + // up to 4 axes are supported, each with its own options, + // See for axis specific options. + this.axes = {xaxis: new Axis('xaxis'), yaxis: new Axis('yaxis'), x2axis: new Axis('x2axis'), y2axis: new Axis('y2axis'), y3axis: new Axis('y3axis'), y4axis: new Axis('y4axis'), y5axis: new Axis('y5axis'), y6axis: new Axis('y6axis'), y7axis: new Axis('y7axis'), y8axis: new Axis('y8axis'), y9axis: new Axis('y9axis'), yMidAxis: new Axis('yMidAxis')}; + this.baseCanvas = new $.jqplot.GenericCanvas(); + // true to intercept right click events and fire a 'jqplotRightClick' event. + // this will also block the context menu. + this.captureRightClick = false; + // prop: data + // user's data. Data should *NOT* be specified in the options object, + // but be passed in as the second argument to the $.jqplot() function. + // The data property is described here soley for reference. + // The data should be in the form of an array of 2D or 1D arrays like + // > [ [[x1, y1], [x2, y2],...], [y1, y2, ...] ]. + this.data = []; + // prop: dataRenderer + // A callable which can be used to preprocess data passed into the plot. + // Will be called with 3 arguments: the plot data, a reference to the plot, + // and the value of dataRendererOptions. + this.dataRenderer; + // prop: dataRendererOptions + // Options that will be passed to the dataRenderer. + // Can be of any type. + this.dataRendererOptions; + this.defaults = { + // prop: axesDefaults + // default options that will be applied to all axes. + // see for axes options. + axesDefaults: {}, + axes: {xaxis:{}, yaxis:{}, x2axis:{}, y2axis:{}, y3axis:{}, y4axis:{}, y5axis:{}, y6axis:{}, y7axis:{}, y8axis:{}, y9axis:{}, yMidAxis:{}}, + // prop: seriesDefaults + // default options that will be applied to all series. + // see for series options. + seriesDefaults: {}, + series:[] + }; + // prop: defaultAxisStart + // 1-D data series are internally converted into 2-D [x,y] data point arrays + // by jqPlot. This is the default starting value for the missing x or y value. + // The added data will be a monotonically increasing series (e.g. [1, 2, 3, ...]) + // starting at this value. + this.defaultAxisStart = 1; + // this.doCustomEventBinding = true; + // prop: drawIfHidden + // True to execute the draw method even if the plot target is hidden. + // Generally, this should be false. Most plot elements will not be sized/ + // positioned correclty if renderered into a hidden container. To render into + // a hidden container, call the replot method when the container is shown. + this.drawIfHidden = false; + this.eventCanvas = new $.jqplot.GenericCanvas(); + // prop: fillBetween + // Fill between 2 line series in a plot. + // Options object: + // { + // series1: first index (0 based) of series in fill + // series2: second index (0 based) of series in fill + // color: color of fill [default fillColor of series1] + // baseSeries: fill will be drawn below this series (0 based index) + // fill: false to turn off fill [default true]. + // } + this.fillBetween = { + series1: null, + series2: null, + color: null, + baseSeries: 0, + fill: true + }; + // prop; fontFamily + // css spec for the font-family attribute. Default for the entire plot. + this.fontFamily; + // prop: fontSize + // css spec for the font-size attribute. Default for the entire plot. + this.fontSize; + // prop: grid + // See for grid specific options. + this.grid = new Grid(); + // prop: legend + // see <$.jqplot.TableLegendRenderer> + this.legend = new Legend(); + // prop: noDataIndicator + // Options to set up a mock plot with a data loading indicator if no data is specified. + this.noDataIndicator = { + show: false, + indicator: 'Loading Data...', + axes: { + xaxis: { + min: 0, + max: 10, + tickInterval: 2, + show: true + }, + yaxis: { + min: 0, + max: 12, + tickInterval: 3, + show: true + } + } + }; + // prop: negativeSeriesColors + // colors to use for portions of the line below zero. + this.negativeSeriesColors = $.jqplot.config.defaultNegativeColors; + // container to hold all of the merged options. Convienence for plugins. + this.options = {}; + this.previousSeriesStack = []; + // Namespace to hold plugins. Generally non-renderer plugins add themselves to here. + this.plugins = {}; + // prop: series + // Array of series object options. + // see for series specific options. + this.series = []; + // array of series indices. Keep track of order + // which series canvases are displayed, lowest + // to highest, back to front. + this.seriesStack = []; + // prop: seriesColors + // Ann array of CSS color specifications that will be applied, in order, + // to the series in the plot. Colors will wrap around so, if their + // are more series than colors, colors will be reused starting at the + // beginning. For pie charts, this specifies the colors of the slices. + this.seriesColors = $.jqplot.config.defaultColors; + // prop: sortData + // false to not sort the data passed in by the user. + // Many bar, stacked and other graphs as well as many plugins depend on + // having sorted data. + this.sortData = true; + // prop: stackSeries + // true or false, creates a stack or "mountain" plot. + // Not all series renderers may implement this option. + this.stackSeries = false; + // a shortcut for axis syncTicks options. Not implemented yet. + this.syncXTicks = true; + // a shortcut for axis syncTicks options. Not implemented yet. + this.syncYTicks = true; + // the jquery object for the dom target. + this.target = null; + // The id of the dom element to render the plot into + this.targetId = null; + // prop textColor + // css spec for the css color attribute. Default for the entire plot. + this.textColor; + // prop: title + // Title object. See for specific options. As a shortcut, you + // can specify the title option as just a string like: title: 'My Plot' + // and this will create a new title object with the specified text. + this.title = new Title(); + // Count how many times the draw method has been called while the plot is visible. + // Mostly used to test if plot has never been dran (=0), has been successfully drawn + // into a visible container once (=1) or draw more than once into a visible container. + // Can use this in tests to see if plot has been visibly drawn at least one time. + // After plot has been visibly drawn once, it generally doesn't need redrawing if its + // container is hidden and shown. + this._drawCount = 0; + // sum of y values for all series in plot. + // used in mekko chart. + this._sumy = 0; + this._sumx = 0; + // array to hold the cumulative stacked series data. + // used to ajust the individual series data, which won't have access to other + // series data. + this._stackData = []; + // array that holds the data to be plotted. This will be the series data + // merged with the the appropriate data from _stackData according to the stackAxis. + this._plotData = []; + this._width = null; + this._height = null; + this._plotDimensions = {height:null, width:null}; + this._gridPadding = {top:null, right:null, bottom:null, left:null}; + this._defaultGridPadding = {top:10, right:10, bottom:23, left:10}; + + this._addDomReference = $.jqplot.config.addDomReference; + + this.preInitHooks = new $.jqplot.HooksManager(); + this.postInitHooks = new $.jqplot.HooksManager(); + this.preParseOptionsHooks = new $.jqplot.HooksManager(); + this.postParseOptionsHooks = new $.jqplot.HooksManager(); + this.preDrawHooks = new $.jqplot.HooksManager(); + this.postDrawHooks = new $.jqplot.HooksManager(); + this.preDrawSeriesHooks = new $.jqplot.HooksManager(); + this.postDrawSeriesHooks = new $.jqplot.HooksManager(); + this.preDrawLegendHooks = new $.jqplot.HooksManager(); + this.addLegendRowHooks = new $.jqplot.HooksManager(); + this.preSeriesInitHooks = new $.jqplot.HooksManager(); + this.postSeriesInitHooks = new $.jqplot.HooksManager(); + this.preParseSeriesOptionsHooks = new $.jqplot.HooksManager(); + this.postParseSeriesOptionsHooks = new $.jqplot.HooksManager(); + this.eventListenerHooks = new $.jqplot.EventListenerManager(); + this.preDrawSeriesShadowHooks = new $.jqplot.HooksManager(); + this.postDrawSeriesShadowHooks = new $.jqplot.HooksManager(); + + this.colorGenerator = new $.jqplot.ColorGenerator(); + this.negativeColorGenerator = new $.jqplot.ColorGenerator(); + + this.canvasManager = new $.jqplot.CanvasManager(); + + this.themeEngine = new $.jqplot.ThemeEngine(); + + var seriesColorsIndex = 0; + + // Group: methods + // + // method: init + // sets the plot target, checks data and applies user + // options to plot. + this.init = function(target, data, options) { + options = options || {}; + for (var i=0; i<$.jqplot.preInitHooks.length; i++) { + $.jqplot.preInitHooks[i].call(this, target, data, options); + } + + for (var i=0; i<this.preInitHooks.hooks.length; i++) { + this.preInitHooks.hooks[i].call(this, target, data, options); + } + + this.targetId = '#'+target; + this.target = $('#'+target); + + ////// + // Add a reference to plot + ////// + if (this._addDomReference) { + this.target.data('jqplot', this); + } + // remove any error class that may be stuck on target. + this.target.removeClass('jqplot-error'); + if (!this.target.get(0)) { + throw new Error("No plot target specified"); + } + + // make sure the target is positioned by some means and set css + if (this.target.css('position') == 'static') { + this.target.css('position', 'relative'); + } + if (!this.target.hasClass('jqplot-target')) { + this.target.addClass('jqplot-target'); + } + + // if no height or width specified, use a default. + if (!this.target.height()) { + var h; + if (options && options.height) { + h = parseInt(options.height, 10); + } + else if (this.target.attr('data-height')) { + h = parseInt(this.target.attr('data-height'), 10); + } + else { + h = parseInt($.jqplot.config.defaultHeight, 10); + } + this._height = h; + this.target.css('height', h+'px'); + } + else { + this._height = h = this.target.height(); + } + if (!this.target.width()) { + var w; + if (options && options.width) { + w = parseInt(options.width, 10); + } + else if (this.target.attr('data-width')) { + w = parseInt(this.target.attr('data-width'), 10); + } + else { + w = parseInt($.jqplot.config.defaultWidth, 10); + } + this._width = w; + this.target.css('width', w+'px'); + } + else { + this._width = w = this.target.width(); + } + + for (var i=0, l=_axisNames.length; i<l; i++) { + this.axes[_axisNames[i]] = new Axis(_axisNames[i]); + } + + this._plotDimensions.height = this._height; + this._plotDimensions.width = this._width; + this.grid._plotDimensions = this._plotDimensions; + this.title._plotDimensions = this._plotDimensions; + this.baseCanvas._plotDimensions = this._plotDimensions; + this.eventCanvas._plotDimensions = this._plotDimensions; + this.legend._plotDimensions = this._plotDimensions; + if (this._height <=0 || this._width <=0 || !this._height || !this._width) { + throw new Error("Canvas dimension not set"); + } + + if (options.dataRenderer && $.isFunction(options.dataRenderer)) { + if (options.dataRendererOptions) { + this.dataRendererOptions = options.dataRendererOptions; + } + this.dataRenderer = options.dataRenderer; + data = this.dataRenderer(data, this, this.dataRendererOptions); + } + + if (options.noDataIndicator && $.isPlainObject(options.noDataIndicator)) { + $.extend(true, this.noDataIndicator, options.noDataIndicator); + } + + if (data == null || $.isArray(data) == false || data.length == 0 || $.isArray(data[0]) == false || data[0].length == 0) { + + if (this.noDataIndicator.show == false) { + throw new Error("No data specified"); + } + + else { + // have to be descructive here in order for plot to not try and render series. + // This means that $.jqplot() will have to be called again when there is data. + //delete options.series; + + for (var ax in this.noDataIndicator.axes) { + for (var prop in this.noDataIndicator.axes[ax]) { + this.axes[ax][prop] = this.noDataIndicator.axes[ax][prop]; + } + } + + this.postDrawHooks.add(function() { + var eh = this.eventCanvas.getHeight(); + var ew = this.eventCanvas.getWidth(); + var temp = $('<div class="jqplot-noData-container" style="position:absolute;"></div>'); + this.target.append(temp); + temp.height(eh); + temp.width(ew); + temp.css('top', this.eventCanvas._offsets.top); + temp.css('left', this.eventCanvas._offsets.left); + + var temp2 = $('<div class="jqplot-noData-contents" style="text-align:center; position:relative; margin-left:auto; margin-right:auto;"></div>'); + temp.append(temp2); + temp2.html(this.noDataIndicator.indicator); + var th = temp2.height(); + var tw = temp2.width(); + temp2.height(th); + temp2.width(tw); + temp2.css('top', (eh - th)/2 + 'px'); + }); + + } + } + + // make a copy of the data + this.data = $.extend(true, [], data); + + this.parseOptions(options); + + if (this.textColor) { + this.target.css('color', this.textColor); + } + if (this.fontFamily) { + this.target.css('font-family', this.fontFamily); + } + if (this.fontSize) { + this.target.css('font-size', this.fontSize); + } + + this.title.init(); + this.legend.init(); + this._sumy = 0; + this._sumx = 0; + this.computePlotData(); + for (var i=0; i<this.series.length; i++) { + // set default stacking order for series canvases + this.seriesStack.push(i); + this.previousSeriesStack.push(i); + this.series[i].shadowCanvas._plotDimensions = this._plotDimensions; + this.series[i].canvas._plotDimensions = this._plotDimensions; + for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) { + $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this); + } + for (var j=0; j<this.preSeriesInitHooks.hooks.length; j++) { + this.preSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this); + } + // this.populatePlotData(this.series[i], i); + this.series[i]._plotDimensions = this._plotDimensions; + this.series[i].init(i, this.grid.borderWidth, this); + for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) { + $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this); + } + for (var j=0; j<this.postSeriesInitHooks.hooks.length; j++) { + this.postSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this); + } + this._sumy += this.series[i]._sumy; + this._sumx += this.series[i]._sumx; + } + + var name, + axis; + for (var i=0, l=_axisNames.length; i<l; i++) { + name = _axisNames[i]; + axis = this.axes[name]; + axis._plotDimensions = this._plotDimensions; + axis.init(); + if (this.axes[name].borderColor == null) { + if (name.charAt(0) !== 'x' && axis.useSeriesColor === true && axis.show) { + axis.borderColor = axis._series[0].color; + } + else { + axis.borderColor = this.grid.borderColor; + } + } + } + + if (this.sortData) { + sortData(this.series); + } + this.grid.init(); + this.grid._axes = this.axes; + + this.legend._series = this.series; + + for (var i=0; i<$.jqplot.postInitHooks.length; i++) { + $.jqplot.postInitHooks[i].call(this, target, this.data, options); + } + + for (var i=0; i<this.postInitHooks.hooks.length; i++) { + this.postInitHooks.hooks[i].call(this, target, this.data, options); + } + }; + + // method: resetAxesScale + // Reset the specified axes min, max, numberTicks and tickInterval properties to null + // or reset these properties on all axes if no list of axes is provided. + // + // Parameters: + // axes - Boolean to reset or not reset all axes or an array or object of axis names to reset. + this.resetAxesScale = function(axes, options) { + var opts = options || {}; + var ax = axes || this.axes; + if (ax === true) { + ax = this.axes; + } + if ($.isArray(ax)) { + for (var i = 0; i < ax.length; i++) { + this.axes[ax[i]].resetScale(opts[ax[i]]); + } + } + else if (typeof(ax) === 'object') { + for (var name in ax) { + this.axes[name].resetScale(opts[name]); + } + } + }; + // method: reInitialize + // reinitialize plot for replotting. + // not called directly. + this.reInitialize = function (data, opts) { + // Plot should be visible and have a height and width. + // If plot doesn't have height and width for some + // reason, set it by other means. Plot must not have + // a display:none attribute, however. + + var options = $.extend(true, {}, this.options, opts); + + var target = this.targetId.substr(1); + var tdata = (data == null) ? this.data : data; + + for (var i=0; i<$.jqplot.preInitHooks.length; i++) { + $.jqplot.preInitHooks[i].call(this, target, tdata, options); + } + + for (var i=0; i<this.preInitHooks.hooks.length; i++) { + this.preInitHooks.hooks[i].call(this, target, tdata, options); + } + + this._height = this.target.height(); + this._width = this.target.width(); + + if (this._height <=0 || this._width <=0 || !this._height || !this._width) { + throw new Error("Target dimension not set"); + } + + this._plotDimensions.height = this._height; + this._plotDimensions.width = this._width; + this.grid._plotDimensions = this._plotDimensions; + this.title._plotDimensions = this._plotDimensions; + this.baseCanvas._plotDimensions = this._plotDimensions; + this.eventCanvas._plotDimensions = this._plotDimensions; + this.legend._plotDimensions = this._plotDimensions; + + var name, + t, + j, + axis; + + for (var i=0, l=_axisNames.length; i<l; i++) { + name = _axisNames[i]; + axis = this.axes[name]; + + // Memory Leaks patch : clear ticks elements + t = axis._ticks; + for (var j = 0, tlen = t.length; j < tlen; j++) { + var el = t[j]._elem; + if (el) { + // if canvas renderer + if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) { + window.G_vmlCanvasManager.uninitElement(el.get(0)); + } + el.emptyForce(); + el = null; + t._elem = null; + } + } + t = null; + + delete axis.ticks; + delete axis._ticks; + this.axes[name] = new Axis(name); + this.axes[name]._plotWidth = this._width; + this.axes[name]._plotHeight = this._height; + } + + if (data) { + if (options.dataRenderer && $.isFunction(options.dataRenderer)) { + if (options.dataRendererOptions) { + this.dataRendererOptions = options.dataRendererOptions; + } + this.dataRenderer = options.dataRenderer; + data = this.dataRenderer(data, this, this.dataRendererOptions); + } + + // make a copy of the data + this.data = $.extend(true, [], data); + } + + if (opts) { + this.parseOptions(options); + } + + this.title._plotWidth = this._width; + + if (this.textColor) { + this.target.css('color', this.textColor); + } + if (this.fontFamily) { + this.target.css('font-family', this.fontFamily); + } + if (this.fontSize) { + this.target.css('font-size', this.fontSize); + } + + this.title.init(); + this.legend.init(); + this._sumy = 0; + this._sumx = 0; + + this.seriesStack = []; + this.previousSeriesStack = []; + + this.computePlotData(); + for (var i=0, l=this.series.length; i<l; i++) { + // set default stacking order for series canvases + this.seriesStack.push(i); + this.previousSeriesStack.push(i); + this.series[i].shadowCanvas._plotDimensions = this._plotDimensions; + this.series[i].canvas._plotDimensions = this._plotDimensions; + for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) { + $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this); + } + for (var j=0; j<this.preSeriesInitHooks.hooks.length; j++) { + this.preSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this); + } + // this.populatePlotData(this.series[i], i); + this.series[i]._plotDimensions = this._plotDimensions; + this.series[i].init(i, this.grid.borderWidth, this); + for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) { + $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this); + } + for (var j=0; j<this.postSeriesInitHooks.hooks.length; j++) { + this.postSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this); + } + this._sumy += this.series[i]._sumy; + this._sumx += this.series[i]._sumx; + } + + for (var i=0, l=_axisNames.length; i<l; i++) { + name = _axisNames[i]; + axis = this.axes[name]; + + axis._plotDimensions = this._plotDimensions; + axis.init(); + if (axis.borderColor == null) { + if (name.charAt(0) !== 'x' && axis.useSeriesColor === true && axis.show) { + axis.borderColor = axis._series[0].color; + } + else { + axis.borderColor = this.grid.borderColor; + } + } + } + + if (this.sortData) { + sortData(this.series); + } + this.grid.init(); + this.grid._axes = this.axes; + + this.legend._series = this.series; + + for (var i=0, l=$.jqplot.postInitHooks.length; i<l; i++) { + $.jqplot.postInitHooks[i].call(this, target, this.data, options); + } + + for (var i=0, l=this.postInitHooks.hooks.length; i<l; i++) { + this.postInitHooks.hooks[i].call(this, target, this.data, options); + } + }; + + + + // method: quickInit + // + // Quick reinitialization plot for replotting. + // Does not parse options ore recreate axes and series. + // not called directly. + this.quickInit = function () { + // Plot should be visible and have a height and width. + // If plot doesn't have height and width for some + // reason, set it by other means. Plot must not have + // a display:none attribute, however. + + this._height = this.target.height(); + this._width = this.target.width(); + + if (this._height <=0 || this._width <=0 || !this._height || !this._width) { + throw new Error("Target dimension not set"); + } + + this._plotDimensions.height = this._height; + this._plotDimensions.width = this._width; + this.grid._plotDimensions = this._plotDimensions; + this.title._plotDimensions = this._plotDimensions; + this.baseCanvas._plotDimensions = this._plotDimensions; + this.eventCanvas._plotDimensions = this._plotDimensions; + this.legend._plotDimensions = this._plotDimensions; + + for (var n in this.axes) { + this.axes[n]._plotWidth = this._width; + this.axes[n]._plotHeight = this._height; + } + + this.title._plotWidth = this._width; + + if (this.textColor) { + this.target.css('color', this.textColor); + } + if (this.fontFamily) { + this.target.css('font-family', this.fontFamily); + } + if (this.fontSize) { + this.target.css('font-size', this.fontSize); + } + + this._sumy = 0; + this._sumx = 0; + this.computePlotData(); + for (var i=0; i<this.series.length; i++) { + // this.populatePlotData(this.series[i], i); + if (this.series[i]._type === 'line' && this.series[i].renderer.bands.show) { + this.series[i].renderer.initBands.call(this.series[i], this.series[i].renderer.options, this); + } + this.series[i]._plotDimensions = this._plotDimensions; + this.series[i].canvas._plotDimensions = this._plotDimensions; + //this.series[i].init(i, this.grid.borderWidth); + this._sumy += this.series[i]._sumy; + this._sumx += this.series[i]._sumx; + } + + var name; + + for (var j=0; j<12; j++) { + name = _axisNames[j]; + // Memory Leaks patch : clear ticks elements + var t = this.axes[name]._ticks; + for (var i = 0; i < t.length; i++) { + var el = t[i]._elem; + if (el) { + // if canvas renderer + if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) { + window.G_vmlCanvasManager.uninitElement(el.get(0)); + } + el.emptyForce(); + el = null; + t._elem = null; + } + } + t = null; + + this.axes[name]._plotDimensions = this._plotDimensions; + this.axes[name]._ticks = []; + // this.axes[name].renderer.init.call(this.axes[name], {}); + } + + if (this.sortData) { + sortData(this.series); + } + + this.grid._axes = this.axes; + + this.legend._series = this.series; + }; + + // sort the series data in increasing order. + function sortData(series) { + var d, sd, pd, ppd, ret; + for (var i=0; i<series.length; i++) { + var check; + var bat = [series[i].data, series[i]._stackData, series[i]._plotData, series[i]._prevPlotData]; + for (var n=0; n<4; n++) { + check = true; + d = bat[n]; + if (series[i]._stackAxis == 'x') { + for (var j = 0; j < d.length; j++) { + if (typeof(d[j][1]) != "number") { + check = false; + break; + } + } + if (check) { + d.sort(function(a,b) { return a[1] - b[1]; }); + } + } + else { + for (var j = 0; j < d.length; j++) { + if (typeof(d[j][0]) != "number") { + check = false; + break; + } + } + if (check) { + d.sort(function(a,b) { return a[0] - b[0]; }); + } + } + } + + } + } + + this.computePlotData = function() { + this._plotData = []; + this._stackData = []; + var series, + index, + l; + + + for (index=0, l=this.series.length; index<l; index++) { + series = this.series[index]; + this._plotData.push([]); + this._stackData.push([]); + var cd = series.data; + this._plotData[index] = $.extend(true, [], cd); + this._stackData[index] = $.extend(true, [], cd); + series._plotData = this._plotData[index]; + series._stackData = this._stackData[index]; + var plotValues = {x:[], y:[]}; + + if (this.stackSeries && !series.disableStack) { + series._stack = true; + /////////////////////////// + // have to check for nulls + /////////////////////////// + var sidx = (series._stackAxis === 'x') ? 0 : 1; + + for (var k=0, cdl=cd.length; k<cdl; k++) { + var temp = cd[k][sidx]; + if (temp == null) { + temp = 0; + } + this._plotData[index][k][sidx] = temp; + this._stackData[index][k][sidx] = temp; + + if (index > 0) { + for (var j=index; j--;) { + var prevval = this._plotData[j][k][sidx]; + // only need to sum up the stack axis column of data + // and only sum if it is of same sign. + // if previous series isn't same sign, keep looking + // at earlier series untill we find one of same sign. + if (temp * prevval >= 0) { + this._plotData[index][k][sidx] += prevval; + this._stackData[index][k][sidx] += prevval; + break; + } + } + } + } + + } + else { + for (var i=0; i<series.data.length; i++) { + plotValues.x.push(series.data[i][0]); + plotValues.y.push(series.data[i][1]); + } + this._stackData.push(series.data); + this.series[index]._stackData = series.data; + this._plotData.push(series.data); + series._plotData = series.data; + series._plotValues = plotValues; + } + if (index>0) { + series._prevPlotData = this.series[index-1]._plotData; + } + series._sumy = 0; + series._sumx = 0; + for (i=series.data.length-1; i>-1; i--) { + series._sumy += series.data[i][1]; + series._sumx += series.data[i][0]; + } + } + + }; + + // populate the _stackData and _plotData arrays for the plot and the series. + this.populatePlotData = function(series, index) { + // if a stacked chart, compute the stacked data + this._plotData = []; + this._stackData = []; + series._stackData = []; + series._plotData = []; + var plotValues = {x:[], y:[]}; + if (this.stackSeries && !series.disableStack) { + series._stack = true; + var sidx = (series._stackAxis === 'x') ? 0 : 1; + // var idx = sidx ? 0 : 1; + // push the current data into stackData + //this._stackData.push(this.series[i].data); + var temp = $.extend(true, [], series.data); + // create the data that will be plotted for this series + var plotdata = $.extend(true, [], series.data); + var tempx, tempy, dval, stackval, comparator; + // for first series, nothing to add to stackData. + for (var j=0; j<index; j++) { + var cd = this.series[j].data; + for (var k=0; k<cd.length; k++) { + dval = cd[k]; + tempx = (dval[0] != null) ? dval[0] : 0; + tempy = (dval[1] != null) ? dval[1] : 0; + temp[k][0] += tempx; + temp[k][1] += tempy; + stackval = (sidx) ? tempy : tempx; + // only need to sum up the stack axis column of data + // and only sum if it is of same sign. + if (series.data[k][sidx] * stackval >= 0) { + plotdata[k][sidx] += stackval; + } + } + } + for (var i=0; i<plotdata.length; i++) { + plotValues.x.push(plotdata[i][0]); + plotValues.y.push(plotdata[i][1]); + } + this._plotData.push(plotdata); + this._stackData.push(temp); + series._stackData = temp; + series._plotData = plotdata; + series._plotValues = plotValues; + } + else { + for (var i=0; i<series.data.length; i++) { + plotValues.x.push(series.data[i][0]); + plotValues.y.push(series.data[i][1]); + } + this._stackData.push(series.data); + this.series[index]._stackData = series.data; + this._plotData.push(series.data); + series._plotData = series.data; + series._plotValues = plotValues; + } + if (index>0) { + series._prevPlotData = this.series[index-1]._plotData; + } + series._sumy = 0; + series._sumx = 0; + for (i=series.data.length-1; i>-1; i--) { + series._sumy += series.data[i][1]; + series._sumx += series.data[i][0]; + } + }; + + // function to safely return colors from the color array and wrap around at the end. + this.getNextSeriesColor = (function(t) { + var idx = 0; + var sc = t.seriesColors; + + return function () { + if (idx < sc.length) { + return sc[idx++]; + } + else { + idx = 0; + return sc[idx++]; + } + }; + })(this); + + this.parseOptions = function(options){ + for (var i=0; i<this.preParseOptionsHooks.hooks.length; i++) { + this.preParseOptionsHooks.hooks[i].call(this, options); + } + for (var i=0; i<$.jqplot.preParseOptionsHooks.length; i++) { + $.jqplot.preParseOptionsHooks[i].call(this, options); + } + this.options = $.extend(true, {}, this.defaults, options); + var opts = this.options; + this.animate = opts.animate; + this.animateReplot = opts.animateReplot; + this.stackSeries = opts.stackSeries; + if ($.isPlainObject(opts.fillBetween)) { + + var temp = ['series1', 'series2', 'color', 'baseSeries', 'fill'], + tempi; + + for (var i=0, l=temp.length; i<l; i++) { + tempi = temp[i]; + if (opts.fillBetween[tempi] != null) { + this.fillBetween[tempi] = opts.fillBetween[tempi]; + } + } + } + + if (opts.seriesColors) { + this.seriesColors = opts.seriesColors; + } + if (opts.negativeSeriesColors) { + this.negativeSeriesColors = opts.negativeSeriesColors; + } + if (opts.captureRightClick) { + this.captureRightClick = opts.captureRightClick; + } + this.defaultAxisStart = (options && options.defaultAxisStart != null) ? options.defaultAxisStart : this.defaultAxisStart; + this.colorGenerator.setColors(this.seriesColors); + this.negativeColorGenerator.setColors(this.negativeSeriesColors); + // var cg = new this.colorGenerator(this.seriesColors); + // var ncg = new this.colorGenerator(this.negativeSeriesColors); + // this._gridPadding = this.options.gridPadding; + $.extend(true, this._gridPadding, opts.gridPadding); + this.sortData = (opts.sortData != null) ? opts.sortData : this.sortData; + for (var i=0; i<12; i++) { + var n = _axisNames[i]; + var axis = this.axes[n]; + axis._options = $.extend(true, {}, opts.axesDefaults, opts.axes[n]); + $.extend(true, axis, opts.axesDefaults, opts.axes[n]); + axis._plotWidth = this._width; + axis._plotHeight = this._height; + } + // if (this.data.length == 0) { + // this.data = []; + // for (var i=0; i<this.options.series.length; i++) { + // this.data.push(this.options.series.data); + // } + // } + + var normalizeData = function(data, dir, start) { + // return data as an array of point arrays, + // in form [[x1,y1...], [x2,y2...], ...] + var temp = []; + var i, l; + dir = dir || 'vertical'; + if (!$.isArray(data[0])) { + // we have a series of scalars. One line with just y values. + // turn the scalar list of data into a data array of form: + // [[1, data[0]], [2, data[1]], ...] + for (i=0, l=data.length; i<l; i++) { + if (dir == 'vertical') { + temp.push([start + i, data[i]]); + } + else { + temp.push([data[i], start+i]); + } + } + } + else { + // we have a properly formatted data series, copy it. + $.extend(true, temp, data); + } + return temp; + }; + + var colorIndex = 0; + this.series = []; + for (var i=0; i<this.data.length; i++) { + var sopts = $.extend(true, {index: i}, {seriesColors:this.seriesColors, negativeSeriesColors:this.negativeSeriesColors}, this.options.seriesDefaults, this.options.series[i], {rendererOptions:{animation:{show: this.animate}}}); + // pass in options in case something needs set prior to initialization. + var temp = new Series(sopts); + for (var j=0; j<$.jqplot.preParseSeriesOptionsHooks.length; j++) { + $.jqplot.preParseSeriesOptionsHooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]); + } + for (var j=0; j<this.preParseSeriesOptionsHooks.hooks.length; j++) { + this.preParseSeriesOptionsHooks.hooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]); + } + // Now go back and apply the options to the series. Really should just do this during initializaiton, but don't want to + // mess up preParseSeriesOptionsHooks at this point. + $.extend(true, temp, sopts); + var dir = 'vertical'; + if (temp.renderer === $.jqplot.BarRenderer && temp.rendererOptions && temp.rendererOptions.barDirection == 'horizontal') { + dir = 'horizontal'; + temp._stackAxis = 'x'; + temp._primaryAxis = '_yaxis'; + } + temp.data = normalizeData(this.data[i], dir, this.defaultAxisStart); + switch (temp.xaxis) { + case 'xaxis': + temp._xaxis = this.axes.xaxis; + break; + case 'x2axis': + temp._xaxis = this.axes.x2axis; + break; + default: + break; + } + temp._yaxis = this.axes[temp.yaxis]; + temp._xaxis._series.push(temp); + temp._yaxis._series.push(temp); + if (temp.show) { + temp._xaxis.show = true; + temp._yaxis.show = true; + } + else { + if (temp._xaxis.scaleToHiddenSeries) { + temp._xaxis.show = true; + } + if (temp._yaxis.scaleToHiddenSeries) { + temp._yaxis.show = true; + } + } + + // // parse the renderer options and apply default colors if not provided + // if (!temp.color && temp.show != false) { + // temp.color = cg.next(); + // colorIndex = cg.getIndex() - 1;; + // } + // if (!temp.negativeColor && temp.show != false) { + // temp.negativeColor = ncg.get(colorIndex); + // ncg.setIndex(colorIndex); + // } + if (!temp.label) { + temp.label = 'Series '+ (i+1).toString(); + } + // temp.rendererOptions.show = temp.show; + // $.extend(true, temp.renderer, {color:this.seriesColors[i]}, this.rendererOptions); + this.series.push(temp); + for (var j=0; j<$.jqplot.postParseSeriesOptionsHooks.length; j++) { + $.jqplot.postParseSeriesOptionsHooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]); + } + for (var j=0; j<this.postParseSeriesOptionsHooks.hooks.length; j++) { + this.postParseSeriesOptionsHooks.hooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]); + } + } + + // copy the grid and title options into this object. + $.extend(true, this.grid, this.options.grid); + // if axis border properties aren't set, set default. + for (var i=0, l=_axisNames.length; i<l; i++) { + var n = _axisNames[i]; + var axis = this.axes[n]; + if (axis.borderWidth == null) { + axis.borderWidth =this.grid.borderWidth; + } + } + + if (typeof this.options.title == 'string') { + this.title.text = this.options.title; + } + else if (typeof this.options.title == 'object') { + $.extend(true, this.title, this.options.title); + } + this.title._plotWidth = this._width; + this.legend.setOptions(this.options.legend); + + for (var i=0; i<$.jqplot.postParseOptionsHooks.length; i++) { + $.jqplot.postParseOptionsHooks[i].call(this, options); + } + for (var i=0; i<this.postParseOptionsHooks.hooks.length; i++) { + this.postParseOptionsHooks.hooks[i].call(this, options); + } + }; + + // method: destroy + // Releases all resources occupied by the plot + this.destroy = function() { + this.canvasManager.freeAllCanvases(); + if (this.eventCanvas && this.eventCanvas._elem) { + this.eventCanvas._elem.unbind(); + } + // Couple of posts on Stack Overflow indicate that empty() doesn't + // always cear up the dom and release memory. Sometimes setting + // innerHTML property to null is needed. Particularly on IE, may + // have to directly set it to null, bypassing $. + this.target.empty(); + + this.target[0].innerHTML = ''; + }; + + // method: replot + // Does a reinitialization of the plot followed by + // a redraw. Method could be used to interactively + // change plot characteristics and then replot. + // + // Parameters: + // options - Options used for replotting. + // + // Properties: + // clear - false to not clear (empty) the plot container before replotting (default: true). + // resetAxes - true to reset all axes min, max, numberTicks and tickInterval setting so axes will rescale themselves. + // optionally pass in list of axes to reset (e.g. ['xaxis', 'y2axis']) (default: false). + this.replot = function(options) { + var opts = options || {}; + var data = opts.data || null; + var clear = (opts.clear === false) ? false : true; + var resetAxes = opts.resetAxes || false; + delete opts.data; + delete opts.clear; + delete opts.resetAxes; + + this.target.trigger('jqplotPreReplot'); + + if (clear) { + this.destroy(); + } + // if have data or other options, full reinit. + // otherwise, quickinit. + if (data || !$.isEmptyObject(opts)) { + this.reInitialize(data, opts); + } + else { + this.quickInit(); + } + + if (resetAxes) { + this.resetAxesScale(resetAxes, opts.axes); + } + this.draw(); + this.target.trigger('jqplotPostReplot'); + }; + + // method: redraw + // Empties the plot target div and redraws the plot. + // This enables plot data and properties to be changed + // and then to comletely clear the plot and redraw. + // redraw *will not* reinitialize any plot elements. + // That is, axes will not be autoscaled and defaults + // will not be reapplied to any plot elements. redraw + // is used primarily with zooming. + // + // Parameters: + // clear - false to not clear (empty) the plot container before redrawing (default: true). + this.redraw = function(clear) { + clear = (clear != null) ? clear : true; + this.target.trigger('jqplotPreRedraw'); + if (clear) { + this.canvasManager.freeAllCanvases(); + this.eventCanvas._elem.unbind(); + // Dont think I bind any events to the target, this shouldn't be necessary. + // It will remove user's events. + // this.target.unbind(); + this.target.empty(); + } + for (var ax in this.axes) { + this.axes[ax]._ticks = []; + } + this.computePlotData(); + // for (var i=0; i<this.series.length; i++) { + // this.populatePlotData(this.series[i], i); + // } + this._sumy = 0; + this._sumx = 0; + for (var i=0, tsl = this.series.length; i<tsl; i++) { + this._sumy += this.series[i]._sumy; + this._sumx += this.series[i]._sumx; + } + this.draw(); + this.target.trigger('jqplotPostRedraw'); + }; + + // method: draw + // Draws all elements of the plot into the container. + // Does not clear the container before drawing. + this.draw = function(){ + if (this.drawIfHidden || this.target.is(':visible')) { + this.target.trigger('jqplotPreDraw'); + var i, + j, + l, + tempseries; + for (i=0, l=$.jqplot.preDrawHooks.length; i<l; i++) { + $.jqplot.preDrawHooks[i].call(this); + } + for (i=0, l=this.preDrawHooks.hooks.length; i<l; i++) { + this.preDrawHooks.hooks[i].apply(this, this.preDrawSeriesHooks.args[i]); + } + // create an underlying canvas to be used for special features. + this.target.append(this.baseCanvas.createElement({left:0, right:0, top:0, bottom:0}, 'jqplot-base-canvas', null, this)); + this.baseCanvas.setContext(); + this.target.append(this.title.draw()); + this.title.pack({top:0, left:0}); + + // make room for the legend between the grid and the edge. + // pass a dummy offsets object and a reference to the plot. + var legendElem = this.legend.draw({}, this); + + var gridPadding = {top:0, left:0, bottom:0, right:0}; + + if (this.legend.placement == "outsideGrid") { + // temporarily append the legend to get dimensions + this.target.append(legendElem); + switch (this.legend.location) { + case 'n': + gridPadding.top += this.legend.getHeight(); + break; + case 's': + gridPadding.bottom += this.legend.getHeight(); + break; + case 'ne': + case 'e': + case 'se': + gridPadding.right += this.legend.getWidth(); + break; + case 'nw': + case 'w': + case 'sw': + gridPadding.left += this.legend.getWidth(); + break; + default: // same as 'ne' + gridPadding.right += this.legend.getWidth(); + break; + } + legendElem = legendElem.detach(); + } + + var ax = this.axes; + var name; + // draw the yMidAxis first, so xaxis of pyramid chart can adjust itself if needed. + for (i=0; i<12; i++) { + name = _axisNames[i]; + this.target.append(ax[name].draw(this.baseCanvas._ctx, this)); + ax[name].set(); + } + if (ax.yaxis.show) { + gridPadding.left += ax.yaxis.getWidth(); + } + var ra = ['y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis']; + var rapad = [0, 0, 0, 0, 0, 0, 0, 0]; + var gpr = 0; + var n; + for (n=0; n<8; n++) { + if (ax[ra[n]].show) { + gpr += ax[ra[n]].getWidth(); + rapad[n] = gpr; + } + } + gridPadding.right += gpr; + if (ax.x2axis.show) { + gridPadding.top += ax.x2axis.getHeight(); + } + if (this.title.show) { + gridPadding.top += this.title.getHeight(); + } + if (ax.xaxis.show) { + gridPadding.bottom += ax.xaxis.getHeight(); + } + + // end of gridPadding adjustments. + + // if user passed in gridDimensions option, check against calculated gridPadding + if (this.options.gridDimensions && $.isPlainObject(this.options.gridDimensions)) { + var gdw = parseInt(this.options.gridDimensions.width, 10) || 0; + var gdh = parseInt(this.options.gridDimensions.height, 10) || 0; + var widthAdj = (this._width - gridPadding.left - gridPadding.right - gdw)/2; + var heightAdj = (this._height - gridPadding.top - gridPadding.bottom - gdh)/2; + + if (heightAdj >= 0 && widthAdj >= 0) { + gridPadding.top += heightAdj; + gridPadding.bottom += heightAdj; + gridPadding.left += widthAdj; + gridPadding.right += widthAdj; + } + } + var arr = ['top', 'bottom', 'left', 'right']; + for (var n in arr) { + if (this._gridPadding[arr[n]] == null && gridPadding[arr[n]] > 0) { + this._gridPadding[arr[n]] = gridPadding[arr[n]]; + } + else if (this._gridPadding[arr[n]] == null) { + this._gridPadding[arr[n]] = this._defaultGridPadding[arr[n]]; + } + } + + var legendPadding = this._gridPadding; + + if (this.legend.placement === 'outsideGrid') { + legendPadding = {top:this.title.getHeight(), left: 0, right: 0, bottom: 0}; + if (this.legend.location === 's') { + legendPadding.left = this._gridPadding.left; + legendPadding.right = this._gridPadding.right; + } + } + + ax.xaxis.pack({position:'absolute', bottom:this._gridPadding.bottom - ax.xaxis.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right}); + ax.yaxis.pack({position:'absolute', top:0, left:this._gridPadding.left - ax.yaxis.getWidth(), height:this._height}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); + ax.x2axis.pack({position:'absolute', top:this._gridPadding.top - ax.x2axis.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right}); + for (i=8; i>0; i--) { + ax[ra[i-1]].pack({position:'absolute', top:0, right:this._gridPadding.right - rapad[i-1]}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); + } + var ltemp = (this._width - this._gridPadding.left - this._gridPadding.right)/2.0 + this._gridPadding.left - ax.yMidAxis.getWidth()/2.0; + ax.yMidAxis.pack({position:'absolute', top:0, left:ltemp, zIndex:9, textAlign: 'center'}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); + + this.target.append(this.grid.createElement(this._gridPadding, this)); + this.grid.draw(); + + var series = this.series; + var seriesLength = series.length; + // put the shadow canvases behind the series canvases so shadows don't overlap on stacked bars. + for (i=0, l=seriesLength; i<l; i++) { + // draw series in order of stacking. This affects only + // order in which canvases are added to dom. + j = this.seriesStack[i]; + this.target.append(series[j].shadowCanvas.createElement(this._gridPadding, 'jqplot-series-shadowCanvas', null, this)); + series[j].shadowCanvas.setContext(); + series[j].shadowCanvas._elem.data('seriesIndex', j); + } + + for (i=0, l=seriesLength; i<l; i++) { + // draw series in order of stacking. This affects only + // order in which canvases are added to dom. + j = this.seriesStack[i]; + this.target.append(series[j].canvas.createElement(this._gridPadding, 'jqplot-series-canvas', null, this)); + series[j].canvas.setContext(); + series[j].canvas._elem.data('seriesIndex', j); + } + // Need to use filled canvas to capture events in IE. + // Also, canvas seems to block selection of other elements in document on FF. + this.target.append(this.eventCanvas.createElement(this._gridPadding, 'jqplot-event-canvas', null, this)); + this.eventCanvas.setContext(); + this.eventCanvas._ctx.fillStyle = 'rgba(0,0,0,0)'; + this.eventCanvas._ctx.fillRect(0,0,this.eventCanvas._ctx.canvas.width, this.eventCanvas._ctx.canvas.height); + + // bind custom event handlers to regular events. + this.bindCustomEvents(); + + // draw legend before series if the series needs to know the legend dimensions. + if (this.legend.preDraw) { + this.eventCanvas._elem.before(legendElem); + this.legend.pack(legendPadding); + if (this.legend._elem) { + this.drawSeries({legendInfo:{location:this.legend.location, placement:this.legend.placement, width:this.legend.getWidth(), height:this.legend.getHeight(), xoffset:this.legend.xoffset, yoffset:this.legend.yoffset}}); + } + else { + this.drawSeries(); + } + } + else { // draw series before legend + this.drawSeries(); + if (seriesLength) { + $(series[seriesLength-1].canvas._elem).after(legendElem); + } + this.legend.pack(legendPadding); + } + + // register event listeners on the overlay canvas + for (var i=0, l=$.jqplot.eventListenerHooks.length; i<l; i++) { + // in the handler, this will refer to the eventCanvas dom element. + // make sure there are references back into plot objects. + this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]); + } + + // register event listeners on the overlay canvas + for (var i=0, l=this.eventListenerHooks.hooks.length; i<l; i++) { + // in the handler, this will refer to the eventCanvas dom element. + // make sure there are references back into plot objects. + this.eventCanvas._elem.bind(this.eventListenerHooks.hooks[i][0], {plot:this}, this.eventListenerHooks.hooks[i][1]); + } + + var fb = this.fillBetween; + if (fb.fill && fb.series1 !== fb.series2 && fb.series1 < seriesLength && fb.series2 < seriesLength && series[fb.series1]._type === 'line' && series[fb.series2]._type === 'line') { + this.doFillBetweenLines(); + } + + for (var i=0, l=$.jqplot.postDrawHooks.length; i<l; i++) { + $.jqplot.postDrawHooks[i].call(this); + } + + for (var i=0, l=this.postDrawHooks.hooks.length; i<l; i++) { + this.postDrawHooks.hooks[i].apply(this, this.postDrawHooks.args[i]); + } + + if (this.target.is(':visible')) { + this._drawCount += 1; + } + + var temps, + tempr, + sel, + _els; + // ughh. ideally would hide all series then show them. + for (i=0, l=seriesLength; i<l; i++) { + temps = series[i]; + tempr = temps.renderer; + sel = '.jqplot-point-label.jqplot-series-'+i; + if (tempr.animation && tempr.animation._supported && tempr.animation.show && (this._drawCount < 2 || this.animateReplot)) { + _els = this.target.find(sel); + _els.stop(true, true).hide(); + temps.canvas._elem.stop(true, true).hide(); + temps.shadowCanvas._elem.stop(true, true).hide(); + temps.canvas._elem.jqplotEffect('blind', {mode: 'show', direction: tempr.animation.direction}, tempr.animation.speed); + temps.shadowCanvas._elem.jqplotEffect('blind', {mode: 'show', direction: tempr.animation.direction}, tempr.animation.speed); + _els.fadeIn(tempr.animation.speed*0.8); + } + } + _els = null; + + this.target.trigger('jqplotPostDraw', [this]); + } + }; + + jqPlot.prototype.doFillBetweenLines = function () { + var fb = this.fillBetween; + var sid1 = fb.series1; + var sid2 = fb.series2; + // first series should always be lowest index + var id1 = (sid1 < sid2) ? sid1 : sid2; + var id2 = (sid2 > sid1) ? sid2 : sid1; + + var series1 = this.series[id1]; + var series2 = this.series[id2]; + + if (series2.renderer.smooth) { + var tempgd = series2.renderer._smoothedData.slice(0).reverse(); + } + else { + var tempgd = series2.gridData.slice(0).reverse(); + } + + if (series1.renderer.smooth) { + var gd = series1.renderer._smoothedData.concat(tempgd); + } + else { + var gd = series1.gridData.concat(tempgd); + } + + var color = (fb.color !== null) ? fb.color : this.series[sid1].fillColor; + var baseSeries = (fb.baseSeries !== null) ? fb.baseSeries : id1; + + // now apply a fill to the shape on the lower series shadow canvas, + // so it is behind both series. + var sr = this.series[baseSeries].renderer.shapeRenderer; + var opts = {fillStyle: color, fill: true, closePath: true}; + sr.draw(series1.shadowCanvas._ctx, gd, opts); + }; + + this.bindCustomEvents = function() { + this.eventCanvas._elem.bind('click', {plot:this}, this.onClick); + this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick); + this.eventCanvas._elem.bind('mousedown', {plot:this}, this.onMouseDown); + this.eventCanvas._elem.bind('mousemove', {plot:this}, this.onMouseMove); + this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter); + this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave); + if (this.captureRightClick) { + this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onRightClick); + this.eventCanvas._elem.get(0).oncontextmenu = function() { + return false; + }; + } + else { + this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onMouseUp); + } + }; + + function getEventPosition(ev) { + var plot = ev.data.plot; + var go = plot.eventCanvas._elem.offset(); + var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top}; + var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null, yMidAxis:null}; + var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis']; + var ax = plot.axes; + var n, axis; + for (n=11; n>0; n--) { + axis = an[n-1]; + if (ax[axis].show) { + dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]); + } + } + + return {offsets:go, gridPos:gridPos, dataPos:dataPos}; + } + + + // function to check if event location is over a area area + function checkIntersection(gridpos, plot) { + var series = plot.series; + var i, j, k, s, r, x, y, theta, sm, sa, minang, maxang; + var d0, d, p, pp, points, bw, hp; + var threshold, t; + for (k=plot.seriesStack.length-1; k>=0; k--) { + i = plot.seriesStack[k]; + s = series[i]; + hp = s._highlightThreshold; + switch (s.renderer.constructor) { + case $.jqplot.BarRenderer: + x = gridpos.x; + y = gridpos.y; + for (j=0; j<s._barPoints.length; j++) { + points = s._barPoints[j]; + p = s.gridData[j]; + if (x>points[0][0] && x<points[2][0] && y>points[2][1] && y<points[0][1]) { + return {seriesIndex:s.index, pointIndex:j, gridData:p, data:s.data[j], points:s._barPoints[j]}; + } + } + break; + case $.jqplot.PyramidRenderer: + x = gridpos.x; + y = gridpos.y; + for (j=0; j<s._barPoints.length; j++) { + points = s._barPoints[j]; + p = s.gridData[j]; + if (x > points[0][0] + hp[0][0] && x < points[2][0] + hp[2][0] && y > points[2][1] && y < points[0][1]) { + return {seriesIndex:s.index, pointIndex:j, gridData:p, data:s.data[j], points:s._barPoints[j]}; + } + } + break; + + case $.jqplot.DonutRenderer: + sa = s.startAngle/180*Math.PI; + x = gridpos.x - s._center[0]; + y = gridpos.y - s._center[1]; + r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + if (x > 0 && -y >= 0) { + theta = 2*Math.PI - Math.atan(-y/x); + } + else if (x > 0 && -y < 0) { + theta = -Math.atan(-y/x); + } + else if (x < 0) { + theta = Math.PI - Math.atan(-y/x); + } + else if (x == 0 && -y > 0) { + theta = 3*Math.PI/2; + } + else if (x == 0 && -y < 0) { + theta = Math.PI/2; + } + else if (x == 0 && y == 0) { + theta = 0; + } + if (sa) { + theta -= sa; + if (theta < 0) { + theta += 2*Math.PI; + } + else if (theta > 2*Math.PI) { + theta -= 2*Math.PI; + } + } + + sm = s.sliceMargin/180*Math.PI; + if (r < s._radius && r > s._innerRadius) { + for (j=0; j<s.gridData.length; j++) { + minang = (j>0) ? s.gridData[j-1][1]+sm : sm; + maxang = s.gridData[j][1]; + if (theta > minang && theta < maxang) { + return {seriesIndex:s.index, pointIndex:j, gridData:[gridpos.x,gridpos.y], data:s.data[j]}; + } + } + } + break; + + case $.jqplot.PieRenderer: + sa = s.startAngle/180*Math.PI; + x = gridpos.x - s._center[0]; + y = gridpos.y - s._center[1]; + r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + if (x > 0 && -y >= 0) { + theta = 2*Math.PI - Math.atan(-y/x); + } + else if (x > 0 && -y < 0) { + theta = -Math.atan(-y/x); + } + else if (x < 0) { + theta = Math.PI - Math.atan(-y/x); + } + else if (x == 0 && -y > 0) { + theta = 3*Math.PI/2; + } + else if (x == 0 && -y < 0) { + theta = Math.PI/2; + } + else if (x == 0 && y == 0) { + theta = 0; + } + if (sa) { + theta -= sa; + if (theta < 0) { + theta += 2*Math.PI; + } + else if (theta > 2*Math.PI) { + theta -= 2*Math.PI; + } + } + + sm = s.sliceMargin/180*Math.PI; + if (r < s._radius) { + for (j=0; j<s.gridData.length; j++) { + minang = (j>0) ? s.gridData[j-1][1]+sm : sm; + maxang = s.gridData[j][1]; + if (theta > minang && theta < maxang) { + return {seriesIndex:s.index, pointIndex:j, gridData:[gridpos.x,gridpos.y], data:s.data[j]}; + } + } + } + break; + + case $.jqplot.BubbleRenderer: + x = gridpos.x; + y = gridpos.y; + var ret = null; + + if (s.show) { + for (var j=0; j<s.gridData.length; j++) { + p = s.gridData[j]; + d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) ); + if (d <= p[2] && (d <= d0 || d0 == null)) { + d0 = d; + ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + if (ret != null) { + return ret; + } + } + break; + + case $.jqplot.FunnelRenderer: + x = gridpos.x; + y = gridpos.y; + var v = s._vertices, + vfirst = v[0], + vlast = v[v.length-1], + lex, + rex, + cv; + + // equations of right and left sides, returns x, y values given height of section (y value and 2 points) + + function findedge (l, p1 , p2) { + var m = (p1[1] - p2[1])/(p1[0] - p2[0]); + var b = p1[1] - m*p1[0]; + var y = l + p1[1]; + + return [(y - b)/m, y]; + } + + // check each section + lex = findedge(y, vfirst[0], vlast[3]); + rex = findedge(y, vfirst[1], vlast[2]); + for (j=0; j<v.length; j++) { + cv = v[j]; + if (y >= cv[0][1] && y <= cv[3][1] && x >= lex[0] && x <= rex[0]) { + return {seriesIndex:s.index, pointIndex:j, gridData:null, data:s.data[j]}; + } + } + break; + + case $.jqplot.LineRenderer: + x = gridpos.x; + y = gridpos.y; + r = s.renderer; + if (s.show) { + if ((s.fill || (s.renderer.bands.show && s.renderer.bands.fill)) && (!plot.plugins.highlighter || !plot.plugins.highlighter.show)) { + // first check if it is in bounding box + var inside = false; + if (x>s._boundingBox[0][0] && x<s._boundingBox[1][0] && y>s._boundingBox[1][1] && y<s._boundingBox[0][1]) { + // now check the crossing number + + var numPoints = s._areaPoints.length; + var ii; + var j = numPoints-1; + + for(var ii=0; ii < numPoints; ii++) { + var vertex1 = [s._areaPoints[ii][0], s._areaPoints[ii][1]]; + var vertex2 = [s._areaPoints[j][0], s._areaPoints[j][1]]; + + if (vertex1[1] < y && vertex2[1] >= y || vertex2[1] < y && vertex1[1] >= y) { + if (vertex1[0] + (y - vertex1[1]) / (vertex2[1] - vertex1[1]) * (vertex2[0] - vertex1[0]) < x) { + inside = !inside; + } + } + + j = ii; + } + } + if (inside) { + return {seriesIndex:i, pointIndex:null, gridData:s.gridData, data:s.data, points:s._areaPoints}; + } + break; + + } + + else { + t = s.markerRenderer.size/2+s.neighborThreshold; + threshold = (t > 0) ? t : 0; + for (var j=0; j<s.gridData.length; j++) { + p = s.gridData[j]; + // neighbor looks different to OHLC chart. + if (r.constructor == $.jqplot.OHLCRenderer) { + if (r.candleStick) { + var yp = s._yaxis.series_u2p; + if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { + return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + // if an open hi low close chart + else if (!r.hlc){ + var yp = s._yaxis.series_u2p; + if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { + return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + // a hi low close chart + else { + var yp = s._yaxis.series_u2p; + if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) { + return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + + } + else if (p[0] != null && p[1] != null){ + d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) ); + if (d <= threshold && (d <= d0 || d0 == null)) { + d0 = d; + return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + } + } + } + break; + + default: + x = gridpos.x; + y = gridpos.y; + r = s.renderer; + if (s.show) { + t = s.markerRenderer.size/2+s.neighborThreshold; + threshold = (t > 0) ? t : 0; + for (var j=0; j<s.gridData.length; j++) { + p = s.gridData[j]; + // neighbor looks different to OHLC chart. + if (r.constructor == $.jqplot.OHLCRenderer) { + if (r.candleStick) { + var yp = s._yaxis.series_u2p; + if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { + return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + // if an open hi low close chart + else if (!r.hlc){ + var yp = s._yaxis.series_u2p; + if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { + return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + // a hi low close chart + else { + var yp = s._yaxis.series_u2p; + if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) { + return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + + } + else { + d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) ); + if (d <= threshold && (d <= d0 || d0 == null)) { + d0 = d; + return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; + } + } + } + } + break; + } + } + + return null; + } + + + + this.onClick = function(ev) { + // Event passed in is normalized and will have data attribute. + // Event passed out is unnormalized. + var positions = getEventPosition(ev); + var p = ev.data.plot; + var neighbor = checkIntersection(positions.gridPos, p); + var evt = $.Event('jqplotClick'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); + }; + + this.onDblClick = function(ev) { + // Event passed in is normalized and will have data attribute. + // Event passed out is unnormalized. + var positions = getEventPosition(ev); + var p = ev.data.plot; + var neighbor = checkIntersection(positions.gridPos, p); + var evt = $.Event('jqplotDblClick'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); + }; + + this.onMouseDown = function(ev) { + var positions = getEventPosition(ev); + var p = ev.data.plot; + var neighbor = checkIntersection(positions.gridPos, p); + var evt = $.Event('jqplotMouseDown'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); + }; + + this.onMouseUp = function(ev) { + var positions = getEventPosition(ev); + var evt = $.Event('jqplotMouseUp'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, ev.data.plot]); + }; + + this.onRightClick = function(ev) { + var positions = getEventPosition(ev); + var p = ev.data.plot; + var neighbor = checkIntersection(positions.gridPos, p); + if (p.captureRightClick) { + if (ev.which == 3) { + var evt = $.Event('jqplotRightClick'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); + } + else { + var evt = $.Event('jqplotMouseUp'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); + } + } + }; + + this.onMouseMove = function(ev) { + var positions = getEventPosition(ev); + var p = ev.data.plot; + var neighbor = checkIntersection(positions.gridPos, p); + var evt = $.Event('jqplotMouseMove'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]); + }; + + this.onMouseEnter = function(ev) { + var positions = getEventPosition(ev); + var p = ev.data.plot; + var evt = $.Event('jqplotMouseEnter'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + evt.relatedTarget = ev.relatedTarget; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]); + }; + + this.onMouseLeave = function(ev) { + var positions = getEventPosition(ev); + var p = ev.data.plot; + var evt = $.Event('jqplotMouseLeave'); + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + evt.relatedTarget = ev.relatedTarget; + $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]); + }; + + // method: drawSeries + // Redraws all or just one series on the plot. No axis scaling + // is performed and no other elements on the plot are redrawn. + // options is an options object to pass on to the series renderers. + // It can be an empty object {}. idx is the series index + // to redraw if only one series is to be redrawn. + this.drawSeries = function(options, idx){ + var i, series, ctx; + // if only one argument passed in and it is a number, use it ad idx. + idx = (typeof(options) === "number" && idx == null) ? options : idx; + options = (typeof(options) === "object") ? options : {}; + // draw specified series + if (idx != undefined) { + series = this.series[idx]; + ctx = series.shadowCanvas._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + series.drawShadow(ctx, options, this); + ctx = series.canvas._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + series.draw(ctx, options, this); + if (series.renderer.constructor == $.jqplot.BezierCurveRenderer) { + if (idx < this.series.length - 1) { + this.drawSeries(idx+1); + } + } + } + + else { + // if call series drawShadow method first, in case all series shadows + // should be drawn before any series. This will ensure, like for + // stacked bar plots, that shadows don't overlap series. + for (i=0; i<this.series.length; i++) { + // first clear the canvas + series = this.series[i]; + ctx = series.shadowCanvas._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + series.drawShadow(ctx, options, this); + ctx = series.canvas._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + series.draw(ctx, options, this); + } + } + options = idx = i = series = ctx = null; + }; + + // method: moveSeriesToFront + // This method requires jQuery 1.4+ + // Moves the specified series canvas in front of all other series canvases. + // This effectively "draws" the specified series on top of all other series, + // although it is performed through DOM manipulation, no redrawing is performed. + // + // Parameters: + // idx - 0 based index of the series to move. This will be the index of the series + // as it was first passed into the jqplot function. + this.moveSeriesToFront = function (idx) { + idx = parseInt(idx, 10); + var stackIndex = $.inArray(idx, this.seriesStack); + // if already in front, return + if (stackIndex == -1) { + return; + } + if (stackIndex == this.seriesStack.length -1) { + this.previousSeriesStack = this.seriesStack.slice(0); + return; + } + var opidx = this.seriesStack[this.seriesStack.length -1]; + var serelem = this.series[idx].canvas._elem.detach(); + var shadelem = this.series[idx].shadowCanvas._elem.detach(); + this.series[opidx].shadowCanvas._elem.after(shadelem); + this.series[opidx].canvas._elem.after(serelem); + this.previousSeriesStack = this.seriesStack.slice(0); + this.seriesStack.splice(stackIndex, 1); + this.seriesStack.push(idx); + }; + + // method: moveSeriesToBack + // This method requires jQuery 1.4+ + // Moves the specified series canvas behind all other series canvases. + // + // Parameters: + // idx - 0 based index of the series to move. This will be the index of the series + // as it was first passed into the jqplot function. + this.moveSeriesToBack = function (idx) { + idx = parseInt(idx, 10); + var stackIndex = $.inArray(idx, this.seriesStack); + // if already in back, return + if (stackIndex == 0 || stackIndex == -1) { + return; + } + var opidx = this.seriesStack[0]; + var serelem = this.series[idx].canvas._elem.detach(); + var shadelem = this.series[idx].shadowCanvas._elem.detach(); + this.series[opidx].shadowCanvas._elem.before(shadelem); + this.series[opidx].canvas._elem.before(serelem); + this.previousSeriesStack = this.seriesStack.slice(0); + this.seriesStack.splice(stackIndex, 1); + this.seriesStack.unshift(idx); + }; + + // method: restorePreviousSeriesOrder + // This method requires jQuery 1.4+ + // Restore the series canvas order to its previous state. + // Useful to put a series back where it belongs after moving + // it to the front. + this.restorePreviousSeriesOrder = function () { + var i, j, serelem, shadelem, temp, move, keep; + // if no change, return. + if (this.seriesStack == this.previousSeriesStack) { + return; + } + for (i=1; i<this.previousSeriesStack.length; i++) { + move = this.previousSeriesStack[i]; + keep = this.previousSeriesStack[i-1]; + serelem = this.series[move].canvas._elem.detach(); + shadelem = this.series[move].shadowCanvas._elem.detach(); + this.series[keep].shadowCanvas._elem.after(shadelem); + this.series[keep].canvas._elem.after(serelem); + } + temp = this.seriesStack.slice(0); + this.seriesStack = this.previousSeriesStack.slice(0); + this.previousSeriesStack = temp; + }; + + // method: restoreOriginalSeriesOrder + // This method requires jQuery 1.4+ + // Restore the series canvas order to its original order + // when the plot was created. + this.restoreOriginalSeriesOrder = function () { + var i, j, arr=[], serelem, shadelem; + for (i=0; i<this.series.length; i++) { + arr.push(i); + } + if (this.seriesStack == arr) { + return; + } + this.previousSeriesStack = this.seriesStack.slice(0); + this.seriesStack = arr; + for (i=1; i<this.seriesStack.length; i++) { + serelem = this.series[i].canvas._elem.detach(); + shadelem = this.series[i].shadowCanvas._elem.detach(); + this.series[i-1].shadowCanvas._elem.after(shadelem); + this.series[i-1].canvas._elem.after(serelem); + } + }; + + this.activateTheme = function (name) { + this.themeEngine.activate(this, name); + }; + } + + + // conpute a highlight color or array of highlight colors from given colors. + $.jqplot.computeHighlightColors = function(colors) { + var ret; + if ($.isArray(colors)) { + ret = []; + for (var i=0; i<colors.length; i++){ + var rgba = $.jqplot.getColorComponents(colors[i]); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var sum = newrgb[0] + newrgb[1] + newrgb[2]; + for (var j=0; j<3; j++) { + // when darkening, lowest color component can be is 60. + newrgb[j] = (sum > 660) ? newrgb[j] * 0.85 : 0.73 * newrgb[j] + 90; + newrgb[j] = parseInt(newrgb[j], 10); + (newrgb[j] > 255) ? 255 : newrgb[j]; + } + // newrgb[3] = (rgba[3] > 0.4) ? rgba[3] * 0.4 : rgba[3] * 1.5; + // newrgb[3] = (rgba[3] > 0.5) ? 0.8 * rgba[3] - .1 : rgba[3] + 0.2; + newrgb[3] = 0.3 + 0.35 * rgba[3]; + ret.push('rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+newrgb[3]+')'); + } + } + else { + var rgba = $.jqplot.getColorComponents(colors); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var sum = newrgb[0] + newrgb[1] + newrgb[2]; + for (var j=0; j<3; j++) { + // when darkening, lowest color component can be is 60. + // newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); + // newrgb[j] = parseInt(newrgb[j], 10); + newrgb[j] = (sum > 660) ? newrgb[j] * 0.85 : 0.73 * newrgb[j] + 90; + newrgb[j] = parseInt(newrgb[j], 10); + (newrgb[j] > 255) ? 255 : newrgb[j]; + } + // newrgb[3] = (rgba[3] > 0.4) ? rgba[3] * 0.4 : rgba[3] * 1.5; + // newrgb[3] = (rgba[3] > 0.5) ? 0.8 * rgba[3] - .1 : rgba[3] + 0.2; + newrgb[3] = 0.3 + 0.35 * rgba[3]; + ret = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+newrgb[3]+')'; + } + return ret; + }; + + $.jqplot.ColorGenerator = function(colors) { + colors = colors || $.jqplot.config.defaultColors; + var idx = 0; + + this.next = function () { + if (idx < colors.length) { + return colors[idx++]; + } + else { + idx = 0; + return colors[idx++]; + } + }; + + this.previous = function () { + if (idx > 0) { + return colors[idx--]; + } + else { + idx = colors.length-1; + return colors[idx]; + } + }; + + // get a color by index without advancing pointer. + this.get = function(i) { + var idx = i - colors.length * Math.floor(i/colors.length); + return colors[idx]; + }; + + this.setColors = function(c) { + colors = c; + }; + + this.reset = function() { + idx = 0; + }; + + this.getIndex = function() { + return idx; + }; + + this.setIndex = function(index) { + idx = index; + }; + }; + + // convert a hex color string to rgb string. + // h - 3 or 6 character hex string, with or without leading # + // a - optional alpha + $.jqplot.hex2rgb = function(h, a) { + h = h.replace('#', ''); + if (h.length == 3) { + h = h.charAt(0)+h.charAt(0)+h.charAt(1)+h.charAt(1)+h.charAt(2)+h.charAt(2); + } + var rgb; + rgb = 'rgba('+parseInt(h.slice(0,2), 16)+', '+parseInt(h.slice(2,4), 16)+', '+parseInt(h.slice(4,6), 16); + if (a) { + rgb += ', '+a; + } + rgb += ')'; + return rgb; + }; + + // convert an rgb color spec to a hex spec. ignore any alpha specification. + $.jqplot.rgb2hex = function(s) { + var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/; + var m = s.match(pat); + var h = '#'; + for (var i=1; i<4; i++) { + var temp; + if (m[i].search(/%/) != -1) { + temp = parseInt(255*m[i]/100, 10).toString(16); + if (temp.length == 1) { + temp = '0'+temp; + } + } + else { + temp = parseInt(m[i], 10).toString(16); + if (temp.length == 1) { + temp = '0'+temp; + } + } + h += temp; + } + return h; + }; + + // given a css color spec, return an rgb css color spec + $.jqplot.normalize2rgb = function(s, a) { + if (s.search(/^ *rgba?\(/) != -1) { + return s; + } + else if (s.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/) != -1) { + return $.jqplot.hex2rgb(s, a); + } + else { + throw new Error('Invalid color spec'); + } + }; + + // extract the r, g, b, a color components out of a css color spec. + $.jqplot.getColorComponents = function(s) { + // check to see if a color keyword. + s = $.jqplot.colorKeywordMap[s] || s; + var rgb = $.jqplot.normalize2rgb(s); + var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/; + var m = rgb.match(pat); + var ret = []; + for (var i=1; i<4; i++) { + if (m[i].search(/%/) != -1) { + ret[i-1] = parseInt(255*m[i]/100, 10); + } + else { + ret[i-1] = parseInt(m[i], 10); + } + } + ret[3] = parseFloat(m[4]) ? parseFloat(m[4]) : 1.0; + return ret; + }; + + $.jqplot.colorKeywordMap = { + aliceblue: 'rgb(240, 248, 255)', + antiquewhite: 'rgb(250, 235, 215)', + aqua: 'rgb( 0, 255, 255)', + aquamarine: 'rgb(127, 255, 212)', + azure: 'rgb(240, 255, 255)', + beige: 'rgb(245, 245, 220)', + bisque: 'rgb(255, 228, 196)', + black: 'rgb( 0, 0, 0)', + blanchedalmond: 'rgb(255, 235, 205)', + blue: 'rgb( 0, 0, 255)', + blueviolet: 'rgb(138, 43, 226)', + brown: 'rgb(165, 42, 42)', + burlywood: 'rgb(222, 184, 135)', + cadetblue: 'rgb( 95, 158, 160)', + chartreuse: 'rgb(127, 255, 0)', + chocolate: 'rgb(210, 105, 30)', + coral: 'rgb(255, 127, 80)', + cornflowerblue: 'rgb(100, 149, 237)', + cornsilk: 'rgb(255, 248, 220)', + crimson: 'rgb(220, 20, 60)', + cyan: 'rgb( 0, 255, 255)', + darkblue: 'rgb( 0, 0, 139)', + darkcyan: 'rgb( 0, 139, 139)', + darkgoldenrod: 'rgb(184, 134, 11)', + darkgray: 'rgb(169, 169, 169)', + darkgreen: 'rgb( 0, 100, 0)', + darkgrey: 'rgb(169, 169, 169)', + darkkhaki: 'rgb(189, 183, 107)', + darkmagenta: 'rgb(139, 0, 139)', + darkolivegreen: 'rgb( 85, 107, 47)', + darkorange: 'rgb(255, 140, 0)', + darkorchid: 'rgb(153, 50, 204)', + darkred: 'rgb(139, 0, 0)', + darksalmon: 'rgb(233, 150, 122)', + darkseagreen: 'rgb(143, 188, 143)', + darkslateblue: 'rgb( 72, 61, 139)', + darkslategray: 'rgb( 47, 79, 79)', + darkslategrey: 'rgb( 47, 79, 79)', + darkturquoise: 'rgb( 0, 206, 209)', + darkviolet: 'rgb(148, 0, 211)', + deeppink: 'rgb(255, 20, 147)', + deepskyblue: 'rgb( 0, 191, 255)', + dimgray: 'rgb(105, 105, 105)', + dimgrey: 'rgb(105, 105, 105)', + dodgerblue: 'rgb( 30, 144, 255)', + firebrick: 'rgb(178, 34, 34)', + floralwhite: 'rgb(255, 250, 240)', + forestgreen: 'rgb( 34, 139, 34)', + fuchsia: 'rgb(255, 0, 255)', + gainsboro: 'rgb(220, 220, 220)', + ghostwhite: 'rgb(248, 248, 255)', + gold: 'rgb(255, 215, 0)', + goldenrod: 'rgb(218, 165, 32)', + gray: 'rgb(128, 128, 128)', + grey: 'rgb(128, 128, 128)', + green: 'rgb( 0, 128, 0)', + greenyellow: 'rgb(173, 255, 47)', + honeydew: 'rgb(240, 255, 240)', + hotpink: 'rgb(255, 105, 180)', + indianred: 'rgb(205, 92, 92)', + indigo: 'rgb( 75, 0, 130)', + ivory: 'rgb(255, 255, 240)', + khaki: 'rgb(240, 230, 140)', + lavender: 'rgb(230, 230, 250)', + lavenderblush: 'rgb(255, 240, 245)', + lawngreen: 'rgb(124, 252, 0)', + lemonchiffon: 'rgb(255, 250, 205)', + lightblue: 'rgb(173, 216, 230)', + lightcoral: 'rgb(240, 128, 128)', + lightcyan: 'rgb(224, 255, 255)', + lightgoldenrodyellow: 'rgb(250, 250, 210)', + lightgray: 'rgb(211, 211, 211)', + lightgreen: 'rgb(144, 238, 144)', + lightgrey: 'rgb(211, 211, 211)', + lightpink: 'rgb(255, 182, 193)', + lightsalmon: 'rgb(255, 160, 122)', + lightseagreen: 'rgb( 32, 178, 170)', + lightskyblue: 'rgb(135, 206, 250)', + lightslategray: 'rgb(119, 136, 153)', + lightslategrey: 'rgb(119, 136, 153)', + lightsteelblue: 'rgb(176, 196, 222)', + lightyellow: 'rgb(255, 255, 224)', + lime: 'rgb( 0, 255, 0)', + limegreen: 'rgb( 50, 205, 50)', + linen: 'rgb(250, 240, 230)', + magenta: 'rgb(255, 0, 255)', + maroon: 'rgb(128, 0, 0)', + mediumaquamarine: 'rgb(102, 205, 170)', + mediumblue: 'rgb( 0, 0, 205)', + mediumorchid: 'rgb(186, 85, 211)', + mediumpurple: 'rgb(147, 112, 219)', + mediumseagreen: 'rgb( 60, 179, 113)', + mediumslateblue: 'rgb(123, 104, 238)', + mediumspringgreen: 'rgb( 0, 250, 154)', + mediumturquoise: 'rgb( 72, 209, 204)', + mediumvioletred: 'rgb(199, 21, 133)', + midnightblue: 'rgb( 25, 25, 112)', + mintcream: 'rgb(245, 255, 250)', + mistyrose: 'rgb(255, 228, 225)', + moccasin: 'rgb(255, 228, 181)', + navajowhite: 'rgb(255, 222, 173)', + navy: 'rgb( 0, 0, 128)', + oldlace: 'rgb(253, 245, 230)', + olive: 'rgb(128, 128, 0)', + olivedrab: 'rgb(107, 142, 35)', + orange: 'rgb(255, 165, 0)', + orangered: 'rgb(255, 69, 0)', + orchid: 'rgb(218, 112, 214)', + palegoldenrod: 'rgb(238, 232, 170)', + palegreen: 'rgb(152, 251, 152)', + paleturquoise: 'rgb(175, 238, 238)', + palevioletred: 'rgb(219, 112, 147)', + papayawhip: 'rgb(255, 239, 213)', + peachpuff: 'rgb(255, 218, 185)', + peru: 'rgb(205, 133, 63)', + pink: 'rgb(255, 192, 203)', + plum: 'rgb(221, 160, 221)', + powderblue: 'rgb(176, 224, 230)', + purple: 'rgb(128, 0, 128)', + red: 'rgb(255, 0, 0)', + rosybrown: 'rgb(188, 143, 143)', + royalblue: 'rgb( 65, 105, 225)', + saddlebrown: 'rgb(139, 69, 19)', + salmon: 'rgb(250, 128, 114)', + sandybrown: 'rgb(244, 164, 96)', + seagreen: 'rgb( 46, 139, 87)', + seashell: 'rgb(255, 245, 238)', + sienna: 'rgb(160, 82, 45)', + silver: 'rgb(192, 192, 192)', + skyblue: 'rgb(135, 206, 235)', + slateblue: 'rgb(106, 90, 205)', + slategray: 'rgb(112, 128, 144)', + slategrey: 'rgb(112, 128, 144)', + snow: 'rgb(255, 250, 250)', + springgreen: 'rgb( 0, 255, 127)', + steelblue: 'rgb( 70, 130, 180)', + tan: 'rgb(210, 180, 140)', + teal: 'rgb( 0, 128, 128)', + thistle: 'rgb(216, 191, 216)', + tomato: 'rgb(255, 99, 71)', + turquoise: 'rgb( 64, 224, 208)', + violet: 'rgb(238, 130, 238)', + wheat: 'rgb(245, 222, 179)', + white: 'rgb(255, 255, 255)', + whitesmoke: 'rgb(245, 245, 245)', + yellow: 'rgb(255, 255, 0)', + yellowgreen: 'rgb(154, 205, 50)' + }; + + + + + // class: $.jqplot.AxisLabelRenderer + // Renderer to place labels on the axes. + $.jqplot.AxisLabelRenderer = function(options) { + // Group: Properties + $.jqplot.ElemContainer.call(this); + // name of the axis associated with this tick + this.axis; + // prop: show + // whether or not to show the tick (mark and label). + this.show = true; + // prop: label + // The text or html for the label. + this.label = ''; + this.fontFamily = null; + this.fontSize = null; + this.textColor = null; + this._elem; + // prop: escapeHTML + // true to escape HTML entities in the label. + this.escapeHTML = false; + + $.extend(true, this, options); + }; + + $.jqplot.AxisLabelRenderer.prototype = new $.jqplot.ElemContainer(); + $.jqplot.AxisLabelRenderer.prototype.constructor = $.jqplot.AxisLabelRenderer; + + $.jqplot.AxisLabelRenderer.prototype.init = function(options) { + $.extend(true, this, options); + }; + + $.jqplot.AxisLabelRenderer.prototype.draw = function(ctx, plot) { + // Memory Leaks patch + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + + this._elem = $('<div style="position:absolute;" class="jqplot-'+this.axis+'-label"></div>'); + + if (Number(this.label)) { + this._elem.css('white-space', 'nowrap'); + } + + if (!this.escapeHTML) { + this._elem.html(this.label); + } + else { + this._elem.text(this.label); + } + if (this.fontFamily) { + this._elem.css('font-family', this.fontFamily); + } + if (this.fontSize) { + this._elem.css('font-size', this.fontSize); + } + if (this.textColor) { + this._elem.css('color', this.textColor); + } + + return this._elem; + }; + + $.jqplot.AxisLabelRenderer.prototype.pack = function() { + }; + + // class: $.jqplot.AxisTickRenderer + // A "tick" object showing the value of a tick/gridline on the plot. + $.jqplot.AxisTickRenderer = function(options) { + // Group: Properties + $.jqplot.ElemContainer.call(this); + // prop: mark + // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null. + this.mark = 'outside'; + // name of the axis associated with this tick + this.axis; + // prop: showMark + // whether or not to show the mark on the axis. + this.showMark = true; + // prop: showGridline + // whether or not to draw the gridline on the grid at this tick. + this.showGridline = true; + // prop: isMinorTick + // if this is a minor tick. + this.isMinorTick = false; + // prop: size + // Length of the tick beyond the grid in pixels. + // DEPRECATED: This has been superceeded by markSize + this.size = 4; + // prop: markSize + // Length of the tick marks in pixels. For 'cross' style, length + // will be stoked above and below axis, so total length will be twice this. + this.markSize = 6; + // prop: show + // whether or not to show the tick (mark and label). + // Setting this to false requires more testing. It is recommended + // to set showLabel and showMark to false instead. + this.show = true; + // prop: showLabel + // whether or not to show the label. + this.showLabel = true; + this.label = null; + this.value = null; + this._styles = {}; + // prop: formatter + // A class of a formatter for the tick text. sprintf by default. + this.formatter = $.jqplot.DefaultTickFormatter; + // prop: prefix + // String to prepend to the tick label. + // Prefix is prepended to the formatted tick label. + this.prefix = ''; + // prop: suffix + // String to append to the tick label. + // Suffix is appended to the formatted tick label. + this.suffix = ''; + // prop: formatString + // string passed to the formatter. + this.formatString = ''; + // prop: fontFamily + // css spec for the font-family css attribute. + this.fontFamily; + // prop: fontSize + // css spec for the font-size css attribute. + this.fontSize; + // prop: textColor + // css spec for the color attribute. + this.textColor; + // prop: escapeHTML + // true to escape HTML entities in the label. + this.escapeHTML = false; + this._elem; + this._breakTick = false; + + $.extend(true, this, options); + }; + + $.jqplot.AxisTickRenderer.prototype.init = function(options) { + $.extend(true, this, options); + }; + + $.jqplot.AxisTickRenderer.prototype = new $.jqplot.ElemContainer(); + $.jqplot.AxisTickRenderer.prototype.constructor = $.jqplot.AxisTickRenderer; + + $.jqplot.AxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) { + this.value = value; + this.axis = axisName; + if (isMinor) { + this.isMinorTick = true; + } + return this; + }; + + $.jqplot.AxisTickRenderer.prototype.draw = function() { + if (this.label === null) { + this.label = this.prefix + this.formatter(this.formatString, this.value) + this.suffix; + } + var style = {position: 'absolute'}; + if (Number(this.label)) { + style['whitSpace'] = 'nowrap'; + } + + // Memory Leaks patch + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + + this._elem = $(document.createElement('div')); + this._elem.addClass("jqplot-"+this.axis+"-tick"); + + if (!this.escapeHTML) { + this._elem.html(this.label); + } + else { + this._elem.text(this.label); + } + + this._elem.css(style); + + for (var s in this._styles) { + this._elem.css(s, this._styles[s]); + } + if (this.fontFamily) { + this._elem.css('font-family', this.fontFamily); + } + if (this.fontSize) { + this._elem.css('font-size', this.fontSize); + } + if (this.textColor) { + this._elem.css('color', this.textColor); + } + if (this._breakTick) { + this._elem.addClass('jqplot-breakTick'); + } + + return this._elem; + }; + + $.jqplot.DefaultTickFormatter = function (format, val) { + if (typeof val == 'number') { + if (!format) { + format = $.jqplot.config.defaultTickFormatString; + } + return $.jqplot.sprintf(format, val); + } + else { + return String(val); + } + }; + + $.jqplot.PercentTickFormatter = function (format, val) { + if (typeof val == 'number') { + val = 100 * val; + if (!format) { + format = $.jqplot.config.defaultTickFormatString; + } + return $.jqplot.sprintf(format, val); + } + else { + return String(val); + } + }; + + $.jqplot.AxisTickRenderer.prototype.pack = function() { + }; + + // Class: $.jqplot.CanvasGridRenderer + // The default jqPlot grid renderer, creating a grid on a canvas element. + // The renderer has no additional options beyond the <Grid> class. + $.jqplot.CanvasGridRenderer = function(){ + this.shadowRenderer = new $.jqplot.ShadowRenderer(); + }; + + // called with context of Grid object + $.jqplot.CanvasGridRenderer.prototype.init = function(options) { + this._ctx; + $.extend(true, this, options); + // set the shadow renderer options + var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false, strokeStyle:this.shadowColor}; + this.renderer.shadowRenderer.init(sopts); + }; + + // called with context of Grid. + $.jqplot.CanvasGridRenderer.prototype.createElement = function(plot) { + var elem; + // Memory Leaks patch + if (this._elem) { + if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) { + elem = this._elem.get(0); + window.G_vmlCanvasManager.uninitElement(elem); + elem = null; + } + + this._elem.emptyForce(); + this._elem = null; + } + + elem = plot.canvasManager.getCanvas(); + + var w = this._plotDimensions.width; + var h = this._plotDimensions.height; + elem.width = w; + elem.height = h; + this._elem = $(elem); + this._elem.addClass('jqplot-grid-canvas'); + this._elem.css({ position: 'absolute', left: 0, top: 0 }); + + elem = plot.canvasManager.initCanvas(elem); + + this._top = this._offsets.top; + this._bottom = h - this._offsets.bottom; + this._left = this._offsets.left; + this._right = w - this._offsets.right; + this._width = this._right - this._left; + this._height = this._bottom - this._top; + // avoid memory leak + elem = null; + return this._elem; + }; + + $.jqplot.CanvasGridRenderer.prototype.draw = function() { + this._ctx = this._elem.get(0).getContext("2d"); + var ctx = this._ctx; + var axes = this._axes; + // Add the grid onto the grid canvas. This is the bottom most layer. + ctx.save(); + ctx.clearRect(0, 0, this._plotDimensions.width, this._plotDimensions.height); + ctx.fillStyle = this.backgroundColor || this.background; + ctx.fillRect(this._left, this._top, this._width, this._height); + + ctx.save(); + ctx.lineJoin = 'miter'; + ctx.lineCap = 'butt'; + ctx.lineWidth = this.gridLineWidth; + ctx.strokeStyle = this.gridLineColor; + var b, e, s, m; + var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis']; + for (var i=4; i>0; i--) { + var name = ax[i-1]; + var axis = axes[name]; + var ticks = axis._ticks; + var numticks = ticks.length; + if (axis.show) { + if (axis.drawBaseline) { + var bopts = {}; + if (axis.baselineWidth !== null) { + bopts.lineWidth = axis.baselineWidth; + } + if (axis.baselineColor !== null) { + bopts.strokeStyle = axis.baselineColor; + } + switch (name) { + case 'xaxis': + drawLine (this._left, this._bottom, this._right, this._bottom, bopts); + break; + case 'yaxis': + drawLine (this._left, this._bottom, this._left, this._top, bopts); + break; + case 'x2axis': + drawLine (this._left, this._bottom, this._right, this._bottom, bopts); + break; + case 'y2axis': + drawLine (this._right, this._bottom, this._right, this._top, bopts); + break; + } + } + for (var j=numticks; j>0; j--) { + var t = ticks[j-1]; + if (t.show) { + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (name) { + case 'xaxis': + // draw the grid line if we should + if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) { + drawLine(pos, this._top, pos, this._bottom); + } + // draw the mark + if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (m) { + case 'outside': + b = this._bottom; + e = this._bottom+s; + break; + case 'inside': + b = this._bottom-s; + e = this._bottom; + break; + case 'cross': + b = this._bottom-s; + e = this._bottom+s; + break; + default: + b = this._bottom; + e = this._bottom+s; + break; + } + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false}); + } + // draw the line + drawLine(pos, b, pos, e); + } + break; + case 'yaxis': + // draw the grid line + if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) { + drawLine(this._right, pos, this._left, pos); + } + // draw the mark + if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (m) { + case 'outside': + b = this._left-s; + e = this._left; + break; + case 'inside': + b = this._left; + e = this._left+s; + break; + case 'cross': + b = this._left-s; + e = this._left+s; + break; + default: + b = this._left-s; + e = this._left; + break; + } + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); + } + drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); + } + break; + case 'x2axis': + // draw the grid line + if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) { + drawLine(pos, this._bottom, pos, this._top); + } + // draw the mark + if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (m) { + case 'outside': + b = this._top-s; + e = this._top; + break; + case 'inside': + b = this._top; + e = this._top+s; + break; + case 'cross': + b = this._top-s; + e = this._top+s; + break; + default: + b = this._top-s; + e = this._top; + break; + } + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false}); + } + drawLine(pos, b, pos, e); + } + break; + case 'y2axis': + // draw the grid line + if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) { + drawLine(this._left, pos, this._right, pos); + } + // draw the mark + if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (m) { + case 'outside': + b = this._right; + e = this._right+s; + break; + case 'inside': + b = this._right-s; + e = this._right; + break; + case 'cross': + b = this._right-s; + e = this._right+s; + break; + default: + b = this._right; + e = this._right+s; + break; + } + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); + } + drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); + } + break; + default: + break; + } + } + } + t = null; + } + axis = null; + ticks = null; + } + // Now draw grid lines for additional y axes + ////// + // TO DO: handle yMidAxis + ////// + ax = ['y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis']; + for (var i=7; i>0; i--) { + var axis = axes[ax[i-1]]; + var ticks = axis._ticks; + if (axis.show) { + var tn = ticks[axis.numberTicks-1]; + var t0 = ticks[0]; + var left = axis.getLeft(); + var points = [[left, tn.getTop() + tn.getHeight()/2], [left, t0.getTop() + t0.getHeight()/2 + 1.0]]; + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', fill:false, closePath:false}); + } + // draw the line + drawLine(points[0][0], points[0][1], points[1][0], points[1][1], {lineCap:'butt', strokeStyle:axis.borderColor, lineWidth:axis.borderWidth}); + // draw the tick marks + for (var j=ticks.length; j>0; j--) { + var t = ticks[j-1]; + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + if (t.showMark && t.mark) { + switch (m) { + case 'outside': + b = left; + e = left+s; + break; + case 'inside': + b = left-s; + e = left; + break; + case 'cross': + b = left-s; + e = left+s; + break; + default: + b = left; + e = left+s; + break; + } + points = [[b,pos], [e,pos]]; + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); + } + // draw the line + drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); + } + t = null; + } + t0 = null; + } + axis = null; + ticks = null; + } + + ctx.restore(); + + function drawLine(bx, by, ex, ey, opts) { + ctx.save(); + opts = opts || {}; + if (opts.lineWidth == null || opts.lineWidth != 0){ + $.extend(true, ctx, opts); + ctx.beginPath(); + ctx.moveTo(bx, by); + ctx.lineTo(ex, ey); + ctx.stroke(); + ctx.restore(); + } + } + + if (this.shadow) { + var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]]; + this.renderer.shadowRenderer.draw(ctx, points); + } + // Now draw border around grid. Use axis border definitions. start at + // upper left and go clockwise. + if (this.borderWidth != 0 && this.drawBorder) { + drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth}); + drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth}); + drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth}); + drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth}); + } + // ctx.lineWidth = this.borderWidth; + // ctx.strokeStyle = this.borderColor; + // ctx.strokeRect(this._left, this._top, this._width, this._height); + + ctx.restore(); + ctx = null; + axes = null; + }; + + // Class: $.jqplot.DivTitleRenderer + // The default title renderer for jqPlot. This class has no options beyond the <Title> class. + $.jqplot.DivTitleRenderer = function() { + }; + + $.jqplot.DivTitleRenderer.prototype.init = function(options) { + $.extend(true, this, options); + }; + + $.jqplot.DivTitleRenderer.prototype.draw = function() { + // Memory Leaks patch + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + + var r = this.renderer; + var elem = document.createElement('div'); + this._elem = $(elem); + this._elem.addClass('jqplot-title'); + + if (!this.text) { + this.show = false; + this._elem.height(0); + this._elem.width(0); + } + else if (this.text) { + var color; + if (this.color) { + color = this.color; + } + else if (this.textColor) { + color = this.textColor; + } + + // don't trust that a stylesheet is present, set the position. + var styles = {position:'absolute', top:'0px', left:'0px'}; + + if (this._plotWidth) { + styles['width'] = this._plotWidth+'px'; + } + if (this.fontSize) { + styles['fontSize'] = this.fontSize; + } + if (typeof this.textAlign === 'string') { + styles['textAlign'] = this.textAlign; + } + else { + styles['textAlign'] = 'center'; + } + if (color) { + styles['color'] = color; + } + if (this.paddingBottom) { + styles['paddingBottom'] = this.paddingBottom; + } + if (this.fontFamily) { + styles['fontFamily'] = this.fontFamily; + } + + this._elem.css(styles); + if (this.escapeHtml) { + this._elem.text(this.text); + } + else { + this._elem.html(this.text); + } + + + // styletext += (this._plotWidth) ? 'width:'+this._plotWidth+'px;' : ''; + // styletext += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; + // styletext += (this.textAlign) ? 'text-align:'+this.textAlign+';' : 'text-align:center;'; + // styletext += (color) ? 'color:'+color+';' : ''; + // styletext += (this.paddingBottom) ? 'padding-bottom:'+this.paddingBottom+';' : ''; + // this._elem = $('<div class="jqplot-title" style="'+styletext+'">'+this.text+'</div>'); + // if (this.fontFamily) { + // this._elem.css('font-family', this.fontFamily); + // } + } + + elem = null; + + return this._elem; + }; + + $.jqplot.DivTitleRenderer.prototype.pack = function() { + // nothing to do here + }; + + + var dotlen = 0.1; + + $.jqplot.LinePattern = function (ctx, pattern) { + + var defaultLinePatterns = { + dotted: [ dotlen, $.jqplot.config.dotGapLength ], + dashed: [ $.jqplot.config.dashLength, $.jqplot.config.gapLength ], + solid: null + }; + + if (typeof pattern === 'string') { + if (pattern[0] === '.' || pattern[0] === '-') { + var s = pattern; + pattern = []; + for (var i=0, imax=s.length; i<imax; i++) { + if (s[i] === '.') { + pattern.push( dotlen ); + } + else if (s[i] === '-') { + pattern.push( $.jqplot.config.dashLength ); + } + else { + continue; + } + pattern.push( $.jqplot.config.gapLength ); + } + } + else { + pattern = defaultLinePatterns[pattern]; + } + } + + if (!(pattern && pattern.length)) { + return ctx; + } + + var patternIndex = 0; + var patternDistance = pattern[0]; + var px = 0; + var py = 0; + var pathx0 = 0; + var pathy0 = 0; + + var moveTo = function (x, y) { + ctx.moveTo( x, y ); + px = x; + py = y; + pathx0 = x; + pathy0 = y; + }; + + var lineTo = function (x, y) { + var scale = ctx.lineWidth; + var dx = x - px; + var dy = y - py; + var dist = Math.sqrt(dx*dx+dy*dy); + if ((dist > 0) && (scale > 0)) { + dx /= dist; + dy /= dist; + while (true) { + var dp = scale * patternDistance; + if (dp < dist) { + px += dp * dx; + py += dp * dy; + if ((patternIndex & 1) == 0) { + ctx.lineTo( px, py ); + } + else { + ctx.moveTo( px, py ); + } + dist -= dp; + patternIndex++; + if (patternIndex >= pattern.length) { + patternIndex = 0; + } + patternDistance = pattern[patternIndex]; + } + else { + px = x; + py = y; + if ((patternIndex & 1) == 0) { + ctx.lineTo( px, py ); + } + else { + ctx.moveTo( px, py ); + } + patternDistance -= dist / scale; + break; + } + } + } + }; + + var beginPath = function () { + ctx.beginPath(); + }; + + var closePath = function () { + lineTo( pathx0, pathy0 ); + }; + + return { + moveTo: moveTo, + lineTo: lineTo, + beginPath: beginPath, + closePath: closePath + }; + }; + + // Class: $.jqplot.LineRenderer + // The default line renderer for jqPlot, this class has no options beyond the <Series> class. + // Draws series as a line. + $.jqplot.LineRenderer = function(){ + this.shapeRenderer = new $.jqplot.ShapeRenderer(); + this.shadowRenderer = new $.jqplot.ShadowRenderer(); + }; + + // called with scope of series. + $.jqplot.LineRenderer.prototype.init = function(options, plot) { + // Group: Properties + // + options = options || {}; + this._type='line'; + this.renderer.animation = { + show: false, + direction: 'left', + speed: 2500, + _supported: true + }; + // prop: smooth + // True to draw a smoothed (interpolated) line through the data points + // with automatically computed number of smoothing points. + // Set to an integer number > 2 to specify number of smoothing points + // to use between each data point. + this.renderer.smooth = false; // true or a number > 2 for smoothing. + this.renderer.tension = null; // null to auto compute or a number typically > 6. Fewer points requires higher tension. + // prop: constrainSmoothing + // True to use a more accurate smoothing algorithm that will + // not overshoot any data points. False to allow overshoot but + // produce a smoother looking line. + this.renderer.constrainSmoothing = true; + // this is smoothed data in grid coordinates, like gridData + this.renderer._smoothedData = []; + // this is smoothed data in plot units (plot coordinates), like plotData. + this.renderer._smoothedPlotData = []; + this.renderer._hiBandGridData = []; + this.renderer._lowBandGridData = []; + this.renderer._hiBandSmoothedData = []; + this.renderer._lowBandSmoothedData = []; + + // prop: bandData + // Data used to draw error bands or confidence intervals above/below a line. + // + // bandData can be input in 3 forms. jqPlot will figure out which is the + // low band line and which is the high band line for all forms: + // + // A 2 dimensional array like [[yl1, yl2, ...], [yu1, yu2, ...]] where + // [yl1, yl2, ...] are y values of the lower line and + // [yu1, yu2, ...] are y values of the upper line. + // In this case there must be the same number of y data points as data points + // in the series and the bands will inherit the x values of the series. + // + // A 2 dimensional array like [[[xl1, yl1], [xl2, yl2], ...], [[xh1, yh1], [xh2, yh2], ...]] + // where [xl1, yl1] are x,y data points for the lower line and + // [xh1, yh1] are x,y data points for the high line. + // x values do not have to correspond to the x values of the series and can + // be of any arbitrary length. + // + // Can be of form [[yl1, yu1], [yl2, yu2], [yl3, yu3], ...] where + // there must be 3 or more arrays and there must be the same number of arrays + // as there are data points in the series. In this case, + // [yl1, yu1] specifies the lower and upper y values for the 1st + // data point and so on. The bands will inherit the x + // values from the series. + this.renderer.bandData = []; + + // Group: bands + // Banding around line, e.g error bands or confidence intervals. + this.renderer.bands = { + // prop: show + // true to show the bands. If bandData or interval is + // supplied, show will be set to true by default. + show: false, + hiData: [], + lowData: [], + // prop: color + // color of lines at top and bottom of bands [default: series color]. + color: this.color, + // prop: showLines + // True to show lines at top and bottom of bands [default: false]. + showLines: false, + // prop: fill + // True to fill area between bands [default: true]. + fill: true, + // prop: fillColor + // css color spec for filled area. [default: series color]. + fillColor: null, + _min: null, + _max: null, + // prop: interval + // User specified interval above and below line for bands [default: '3%'']. + // Can be a value like 3 or a string like '3%' + // or an upper/lower array like [1, -2] or ['2%', '-1.5%'] + interval: '3%' + }; + + + var lopts = {highlightMouseOver: options.highlightMouseOver, highlightMouseDown: options.highlightMouseDown, highlightColor: options.highlightColor}; + + delete (options.highlightMouseOver); + delete (options.highlightMouseDown); + delete (options.highlightColor); + + $.extend(true, this.renderer, options); + + this.renderer.options = options; + + // if we are given some band data, and bands aren't explicity set to false in options, turn them on. + if (this.renderer.bandData.length > 1 && (!options.bands || options.bands.show == null)) { + this.renderer.bands.show = true; + } + + // if we are given an interval, and bands aren't explicity set to false in options, turn them on. + else if (options.bands && options.bands.show == null && options.bands.interval != null) { + this.renderer.bands.show = true; + } + + // if plot is filled, turn off bands. + if (this.fill) { + this.renderer.bands.show = false; + } + + if (this.renderer.bands.show) { + this.renderer.initBands.call(this, this.renderer.options, plot); + } + + + // smoothing is not compatible with stacked lines, disable + if (this._stack) { + this.renderer.smooth = false; + } + + // set the shape renderer options + var opts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.fillColor, lineWidth:this.lineWidth, linePattern:this.linePattern, closePath:this.fill}; + this.renderer.shapeRenderer.init(opts); + + var shadow_offset = options.shadowOffset; + // set the shadow renderer options + if (shadow_offset == null) { + // scale the shadowOffset to the width of the line. + if (this.lineWidth > 2.5) { + shadow_offset = 1.25 * (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6); + // var shadow_offset = this.shadowOffset; + } + // for skinny lines, don't make such a big shadow. + else { + shadow_offset = 1.25 * Math.atan((this.lineWidth/2.5))/0.785398163; + } + } + + var sopts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.lineWidth, linePattern:this.linePattern, closePath:this.fill}; + this.renderer.shadowRenderer.init(sopts); + this._areaPoints = []; + this._boundingBox = [[],[]]; + + if (!this.isTrendline && this.fill || this.renderer.bands.show) { + // Group: Properties + // + // prop: highlightMouseOver + // True to highlight area on a filled plot when moused over. + // This must be false to enable highlightMouseDown to highlight when clicking on an area on a filled plot. + this.highlightMouseOver = true; + // prop: highlightMouseDown + // True to highlight when a mouse button is pressed over an area on a filled plot. + // This will be disabled if highlightMouseOver is true. + this.highlightMouseDown = false; + // prop: highlightColor + // color to use when highlighting an area on a filled plot. + this.highlightColor = null; + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver + if (lopts.highlightMouseDown && lopts.highlightMouseOver == null) { + lopts.highlightMouseOver = false; + } + + $.extend(true, this, {highlightMouseOver: lopts.highlightMouseOver, highlightMouseDown: lopts.highlightMouseDown, highlightColor: lopts.highlightColor}); + + if (!this.highlightColor) { + var fc = (this.renderer.bands.show) ? this.renderer.bands.fillColor : this.fillColor; + this.highlightColor = $.jqplot.computeHighlightColors(fc); + } + // turn off (disable) the highlighter plugin + if (this.highlighter) { + this.highlighter.show = false; + } + } + + if (!this.isTrendline && plot) { + plot.plugins.lineRenderer = {}; + plot.postInitHooks.addOnce(postInit); + plot.postDrawHooks.addOnce(postPlotDraw); + plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); + plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); + plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); + plot.eventListenerHooks.addOnce('jqplotClick', handleClick); + plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); + } + + }; + + $.jqplot.LineRenderer.prototype.initBands = function(options, plot) { + // use bandData if no data specified in bands option + //var bd = this.renderer.bandData; + var bd = options.bandData || []; + var bands = this.renderer.bands; + bands.hiData = []; + bands.lowData = []; + var data = this.data; + bands._max = null; + bands._min = null; + // If 2 arrays, and each array greater than 2 elements, assume it is hi and low data bands of y values. + if (bd.length == 2) { + // Do we have an array of x,y values? + // like [[[1,1], [2,4], [3,3]], [[1,3], [2,6], [3,5]]] + if ($.isArray(bd[0][0])) { + // since an arbitrary array of points, spin through all of them to determine max and min lines. + + var p; + var bdminidx = 0, bdmaxidx = 0; + for (var i = 0, l = bd[0].length; i<l; i++) { + p = bd[0][i]; + if ((p[1] != null && p[1] > bands._max) || bands._max == null) { + bands._max = p[1]; + } + if ((p[1] != null && p[1] < bands._min) || bands._min == null) { + bands._min = p[1]; + } + } + for (var i = 0, l = bd[1].length; i<l; i++) { + p = bd[1][i]; + if ((p[1] != null && p[1] > bands._max) || bands._max == null) { + bands._max = p[1]; + bdmaxidx = 1; + } + if ((p[1] != null && p[1] < bands._min) || bands._min == null) { + bands._min = p[1]; + bdminidx = 1; + } + } + + if (bdmaxidx === bdminidx) { + bands.show = false; + } + + bands.hiData = bd[bdmaxidx]; + bands.lowData = bd[bdminidx]; + } + // else data is arrays of y values + // like [[1,4,3], [3,6,5]] + // must have same number of band data points as points in series + else if (bd[0].length === data.length && bd[1].length === data.length) { + var hi = (bd[0][0] > bd[1][0]) ? 0 : 1; + var low = (hi) ? 0 : 1; + for (var i=0, l=data.length; i < l; i++) { + bands.hiData.push([data[i][0], bd[hi][i]]); + bands.lowData.push([data[i][0], bd[low][i]]); + } + } + + // we don't have proper data array, don't show bands. + else { + bands.show = false; + } + } + + // if more than 2 arrays, have arrays of [ylow, yhi] values. + // note, can't distinguish case of [[ylow, yhi], [ylow, yhi]] from [[ylow, ylow], [yhi, yhi]] + // this is assumed to be of the latter form. + else if (bd.length > 2 && !$.isArray(bd[0][0])) { + var hi = (bd[0][0] > bd[0][1]) ? 0 : 1; + var low = (hi) ? 0 : 1; + for (var i=0, l=bd.length; i<l; i++) { + bands.hiData.push([data[i][0], bd[i][hi]]); + bands.lowData.push([data[i][0], bd[i][low]]); + } + } + + // don't have proper data, auto calculate + else { + var intrv = bands.interval; + var a = null; + var b = null; + var afunc = null; + var bfunc = null; + + if ($.isArray(intrv)) { + a = intrv[0]; + b = intrv[1]; + } + else { + a = intrv; + } + + if (isNaN(a)) { + // we have a string + if (a.charAt(a.length - 1) === '%') { + afunc = 'multiply'; + a = parseFloat(a)/100 + 1; + } + } + + else { + a = parseFloat(a); + afunc = 'add'; + } + + if (b !== null && isNaN(b)) { + // we have a string + if (b.charAt(b.length - 1) === '%') { + bfunc = 'multiply'; + b = parseFloat(b)/100 + 1; + } + } + + else if (b !== null) { + b = parseFloat(b); + bfunc = 'add'; + } + + if (a !== null) { + if (b === null) { + b = -a; + bfunc = afunc; + if (bfunc === 'multiply') { + b += 2; + } + } + + // make sure a always applies to hi band. + if (a < b) { + var temp = a; + a = b; + b = temp; + temp = afunc; + afunc = bfunc; + bfunc = temp; + } + + for (var i=0, l = data.length; i < l; i++) { + switch (afunc) { + case 'add': + bands.hiData.push([data[i][0], data[i][1] + a]); + break; + case 'multiply': + bands.hiData.push([data[i][0], data[i][1] * a]); + break; + } + switch (bfunc) { + case 'add': + bands.lowData.push([data[i][0], data[i][1] + b]); + break; + case 'multiply': + bands.lowData.push([data[i][0], data[i][1] * b]); + break; + } + } + } + + else { + bands.show = false; + } + } + + var hd = bands.hiData; + var ld = bands.lowData; + for (var i = 0, l = hd.length; i<l; i++) { + if ((hd[i][1] != null && hd[i][1] > bands._max) || bands._max == null) { + bands._max = hd[i][1]; + } + } + for (var i = 0, l = ld.length; i<l; i++) { + if ((ld[i][1] != null && ld[i][1] < bands._min) || bands._min == null) { + bands._min = ld[i][1]; + } + } + + // one last check for proper data + // these don't apply any more since allowing arbitrary x,y values + // if (bands.hiData.length != bands.lowData.length) { + // bands.show = false; + // } + + // if (bands.hiData.length != this.data.length) { + // bands.show = false; + // } + + if (bands.fillColor === null) { + var c = $.jqplot.getColorComponents(bands.color); + // now adjust alpha to differentiate fill + c[3] = c[3] * 0.5; + bands.fillColor = 'rgba(' + c[0] +', '+ c[1] +', '+ c[2] +', '+ c[3] + ')'; + } + }; + + function getSteps (d, f) { + return (3.4182054+f) * Math.pow(d, -0.3534992); + } + + function computeSteps (d1, d2) { + var s = Math.sqrt(Math.pow((d2[0]- d1[0]), 2) + Math.pow ((d2[1] - d1[1]), 2)); + return 5.7648 * Math.log(s) + 7.4456; + } + + function tanh (x) { + var a = (Math.exp(2*x) - 1) / (Math.exp(2*x) + 1); + return a; + } + + ////////// + // computeConstrainedSmoothedData + // An implementation of the constrained cubic spline interpolation + // method as presented in: + // + // Kruger, CJC, Constrained Cubic Spine Interpolation for Chemical Engineering Applications + // http://www.korf.co.uk/spline.pdf + // + // The implementation below borrows heavily from the sample Visual Basic + // implementation by CJC Kruger found in http://www.korf.co.uk/spline.xls + // + ///////// + + // called with scope of series + function computeConstrainedSmoothedData (gd) { + var smooth = this.renderer.smooth; + var dim = this.canvas.getWidth(); + var xp = this._xaxis.series_p2u; + var yp = this._yaxis.series_p2u; + var steps =null; + var _steps = null; + var dist = gd.length/dim; + var _smoothedData = []; + var _smoothedPlotData = []; + + if (!isNaN(parseFloat(smooth))) { + steps = parseFloat(smooth); + } + else { + steps = getSteps(dist, 0.5); + } + + var yy = []; + var xx = []; + + for (var i=0, l = gd.length; i<l; i++) { + yy.push(gd[i][1]); + xx.push(gd[i][0]); + } + + function dxx(x1, x0) { + if (x1 - x0 == 0) { + return Math.pow(10,10); + } + else { + return x1 - x0; + } + } + + var A, B, C, D; + // loop through each line segment. Have # points - 1 line segments. Nmber segments starting at 1. + var nmax = gd.length - 1; + for (var num = 1, gdl = gd.length; num<gdl; num++) { + var gxx = []; + var ggxx = []; + // point at each end of segment. + for (var j = 0; j < 2; j++) { + var i = num - 1 + j; // point number, 0 to # points. + + if (i == 0 || i == nmax) { + gxx[j] = Math.pow(10, 10); + } + else if (yy[i+1] - yy[i] == 0 || yy[i] - yy[i-1] == 0) { + gxx[j] = 0; + } + else if (((xx[i+1] - xx[i]) / (yy[i+1] - yy[i]) + (xx[i] - xx[i-1]) / (yy[i] - yy[i-1])) == 0 ) { + gxx[j] = 0; + } + else if ( (yy[i+1] - yy[i]) * (yy[i] - yy[i-1]) < 0 ) { + gxx[j] = 0; + } + + else { + gxx[j] = 2 / (dxx(xx[i + 1], xx[i]) / (yy[i + 1] - yy[i]) + dxx(xx[i], xx[i - 1]) / (yy[i] - yy[i - 1])); + } + } + + // Reset first derivative (slope) at first and last point + if (num == 1) { + // First point has 0 2nd derivative + gxx[0] = 3 / 2 * (yy[1] - yy[0]) / dxx(xx[1], xx[0]) - gxx[1] / 2; + } + else if (num == nmax) { + // Last point has 0 2nd derivative + gxx[1] = 3 / 2 * (yy[nmax] - yy[nmax - 1]) / dxx(xx[nmax], xx[nmax - 1]) - gxx[0] / 2; + } + + // Calc second derivative at points + ggxx[0] = -2 * (gxx[1] + 2 * gxx[0]) / dxx(xx[num], xx[num - 1]) + 6 * (yy[num] - yy[num - 1]) / Math.pow(dxx(xx[num], xx[num - 1]), 2); + ggxx[1] = 2 * (2 * gxx[1] + gxx[0]) / dxx(xx[num], xx[num - 1]) - 6 * (yy[num] - yy[num - 1]) / Math.pow(dxx(xx[num], xx[num - 1]), 2); + + // Calc constants for cubic interpolation + D = 1 / 6 * (ggxx[1] - ggxx[0]) / dxx(xx[num], xx[num - 1]); + C = 1 / 2 * (xx[num] * ggxx[0] - xx[num - 1] * ggxx[1]) / dxx(xx[num], xx[num - 1]); + B = (yy[num] - yy[num - 1] - C * (Math.pow(xx[num], 2) - Math.pow(xx[num - 1], 2)) - D * (Math.pow(xx[num], 3) - Math.pow(xx[num - 1], 3))) / dxx(xx[num], xx[num - 1]); + A = yy[num - 1] - B * xx[num - 1] - C * Math.pow(xx[num - 1], 2) - D * Math.pow(xx[num - 1], 3); + + var increment = (xx[num] - xx[num - 1]) / steps; + var temp, tempx; + + for (var j = 0, l = steps; j < l; j++) { + temp = []; + tempx = xx[num - 1] + j * increment; + temp.push(tempx); + temp.push(A + B * tempx + C * Math.pow(tempx, 2) + D * Math.pow(tempx, 3)); + _smoothedData.push(temp); + _smoothedPlotData.push([xp(temp[0]), yp(temp[1])]); + } + } + + _smoothedData.push(gd[i]); + _smoothedPlotData.push([xp(gd[i][0]), yp(gd[i][1])]); + + return [_smoothedData, _smoothedPlotData]; + } + + /////// + // computeHermiteSmoothedData + // A hermite spline smoothing of the plot data. + // This implementation is derived from the one posted + // by krypin on the jqplot-users mailing list: + // + // http://groups.google.com/group/jqplot-users/browse_thread/thread/748be6a445723cea?pli=1 + // + // with a blog post: + // + // http://blog.statscollector.com/a-plugin-renderer-for-jqplot-to-draw-a-hermite-spline/ + // + // and download of the original plugin: + // + // http://blog.statscollector.com/wp-content/uploads/2010/02/jqplot.hermiteSplineRenderer.js + ////////// + + // called with scope of series + function computeHermiteSmoothedData (gd) { + var smooth = this.renderer.smooth; + var tension = this.renderer.tension; + var dim = this.canvas.getWidth(); + var xp = this._xaxis.series_p2u; + var yp = this._yaxis.series_p2u; + var steps =null; + var _steps = null; + var a = null; + var a1 = null; + var a2 = null; + var slope = null; + var slope2 = null; + var temp = null; + var t, s, h1, h2, h3, h4; + var TiX, TiY, Ti1X, Ti1Y; + var pX, pY, p; + var sd = []; + var spd = []; + var dist = gd.length/dim; + var min, max, stretch, scale, shift; + var _smoothedData = []; + var _smoothedPlotData = []; + if (!isNaN(parseFloat(smooth))) { + steps = parseFloat(smooth); + } + else { + steps = getSteps(dist, 0.5); + } + if (!isNaN(parseFloat(tension))) { + tension = parseFloat(tension); + } + + for (var i=0, l = gd.length-1; i < l; i++) { + + if (tension === null) { + slope = Math.abs((gd[i+1][1] - gd[i][1]) / (gd[i+1][0] - gd[i][0])); + + min = 0.3; + max = 0.6; + stretch = (max - min)/2.0; + scale = 2.5; + shift = -1.4; + + temp = slope/scale + shift; + + a1 = stretch * tanh(temp) - stretch * tanh(shift) + min; + + // if have both left and right line segments, will use minimum tension. + if (i > 0) { + slope2 = Math.abs((gd[i][1] - gd[i-1][1]) / (gd[i][0] - gd[i-1][0])); + } + temp = slope2/scale + shift; + + a2 = stretch * tanh(temp) - stretch * tanh(shift) + min; + + a = (a1 + a2)/2.0; + + } + else { + a = tension; + } + for (t=0; t < steps; t++) { + s = t / steps; + h1 = (1 + 2*s)*Math.pow((1-s),2); + h2 = s*Math.pow((1-s),2); + h3 = Math.pow(s,2)*(3-2*s); + h4 = Math.pow(s,2)*(s-1); + + if (gd[i-1]) { + TiX = a * (gd[i+1][0] - gd[i-1][0]); + TiY = a * (gd[i+1][1] - gd[i-1][1]); + } else { + TiX = a * (gd[i+1][0] - gd[i][0]); + TiY = a * (gd[i+1][1] - gd[i][1]); + } + if (gd[i+2]) { + Ti1X = a * (gd[i+2][0] - gd[i][0]); + Ti1Y = a * (gd[i+2][1] - gd[i][1]); + } else { + Ti1X = a * (gd[i+1][0] - gd[i][0]); + Ti1Y = a * (gd[i+1][1] - gd[i][1]); + } + + pX = h1*gd[i][0] + h3*gd[i+1][0] + h2*TiX + h4*Ti1X; + pY = h1*gd[i][1] + h3*gd[i+1][1] + h2*TiY + h4*Ti1Y; + p = [pX, pY]; + + _smoothedData.push(p); + _smoothedPlotData.push([xp(pX), yp(pY)]); + } + } + _smoothedData.push(gd[l]); + _smoothedPlotData.push([xp(gd[l][0]), yp(gd[l][1])]); + + return [_smoothedData, _smoothedPlotData]; + } + + // setGridData + // converts the user data values to grid coordinates and stores them + // in the gridData array. + // Called with scope of a series. + $.jqplot.LineRenderer.prototype.setGridData = function(plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var data = this._plotData; + var pdata = this._prevPlotData; + this.gridData = []; + this._prevGridData = []; + this.renderer._smoothedData = []; + this.renderer._smoothedPlotData = []; + this.renderer._hiBandGridData = []; + this.renderer._lowBandGridData = []; + this.renderer._hiBandSmoothedData = []; + this.renderer._lowBandSmoothedData = []; + var bands = this.renderer.bands; + var hasNull = false; + for (var i=0, l=data.length; i < l; i++) { + // if not a line series or if no nulls in data, push the converted point onto the array. + if (data[i][0] != null && data[i][1] != null) { + this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]); + } + // else if there is a null, preserve it. + else if (data[i][0] == null) { + hasNull = true; + this.gridData.push([null, yp.call(this._yaxis, data[i][1])]); + } + else if (data[i][1] == null) { + hasNull = true; + this.gridData.push([xp.call(this._xaxis, data[i][0]), null]); + } + // if not a line series or if no nulls in data, push the converted point onto the array. + if (pdata[i] != null && pdata[i][0] != null && pdata[i][1] != null) { + this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), yp.call(this._yaxis, pdata[i][1])]); + } + // else if there is a null, preserve it. + else if (pdata[i] != null && pdata[i][0] == null) { + this._prevGridData.push([null, yp.call(this._yaxis, pdata[i][1])]); + } + else if (pdata[i] != null && pdata[i][0] != null && pdata[i][1] == null) { + this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), null]); + } + } + + // don't do smoothing or bands on broken lines. + if (hasNull) { + this.renderer.smooth = false; + if (this._type === 'line') { + bands.show = false; + } + } + + if (this._type === 'line' && bands.show) { + for (var i=0, l=bands.hiData.length; i<l; i++) { + this.renderer._hiBandGridData.push([xp.call(this._xaxis, bands.hiData[i][0]), yp.call(this._yaxis, bands.hiData[i][1])]); + } + for (var i=0, l=bands.lowData.length; i<l; i++) { + this.renderer._lowBandGridData.push([xp.call(this._xaxis, bands.lowData[i][0]), yp.call(this._yaxis, bands.lowData[i][1])]); + } + } + + // calculate smoothed data if enough points and no nulls + if (this._type === 'line' && this.renderer.smooth && this.gridData.length > 2) { + var ret; + if (this.renderer.constrainSmoothing) { + ret = computeConstrainedSmoothedData.call(this, this.gridData); + this.renderer._smoothedData = ret[0]; + this.renderer._smoothedPlotData = ret[1]; + + if (bands.show) { + ret = computeConstrainedSmoothedData.call(this, this.renderer._hiBandGridData); + this.renderer._hiBandSmoothedData = ret[0]; + ret = computeConstrainedSmoothedData.call(this, this.renderer._lowBandGridData); + this.renderer._lowBandSmoothedData = ret[0]; + } + + ret = null; + } + else { + ret = computeHermiteSmoothedData.call(this, this.gridData); + this.renderer._smoothedData = ret[0]; + this.renderer._smoothedPlotData = ret[1]; + + if (bands.show) { + ret = computeHermiteSmoothedData.call(this, this.renderer._hiBandGridData); + this.renderer._hiBandSmoothedData = ret[0]; + ret = computeHermiteSmoothedData.call(this, this.renderer._lowBandGridData); + this.renderer._lowBandSmoothedData = ret[0]; + } + + ret = null; + } + } + }; + + // makeGridData + // converts any arbitrary data values to grid coordinates and + // returns them. This method exists so that plugins can use a series' + // linerenderer to generate grid data points without overwriting the + // grid data associated with that series. + // Called with scope of a series. + $.jqplot.LineRenderer.prototype.makeGridData = function(data, plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var gd = []; + var pgd = []; + this.renderer._smoothedData = []; + this.renderer._smoothedPlotData = []; + this.renderer._hiBandGridData = []; + this.renderer._lowBandGridData = []; + this.renderer._hiBandSmoothedData = []; + this.renderer._lowBandSmoothedData = []; + var bands = this.renderer.bands; + var hasNull = false; + for (var i=0; i<data.length; i++) { + // if not a line series or if no nulls in data, push the converted point onto the array. + if (data[i][0] != null && data[i][1] != null) { + gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]); + } + // else if there is a null, preserve it. + else if (data[i][0] == null) { + hasNull = true; + gd.push([null, yp.call(this._yaxis, data[i][1])]); + } + else if (data[i][1] == null) { + hasNull = true; + gd.push([xp.call(this._xaxis, data[i][0]), null]); + } + } + + // don't do smoothing or bands on broken lines. + if (hasNull) { + this.renderer.smooth = false; + if (this._type === 'line') { + bands.show = false; + } + } + + if (this._type === 'line' && bands.show) { + for (var i=0, l=bands.hiData.length; i<l; i++) { + this.renderer._hiBandGridData.push([xp.call(this._xaxis, bands.hiData[i][0]), yp.call(this._yaxis, bands.hiData[i][1])]); + } + for (var i=0, l=bands.lowData.length; i<l; i++) { + this.renderer._lowBandGridData.push([xp.call(this._xaxis, bands.lowData[i][0]), yp.call(this._yaxis, bands.lowData[i][1])]); + } + } + + if (this._type === 'line' && this.renderer.smooth && gd.length > 2) { + var ret; + if (this.renderer.constrainSmoothing) { + ret = computeConstrainedSmoothedData.call(this, gd); + this.renderer._smoothedData = ret[0]; + this.renderer._smoothedPlotData = ret[1]; + + if (bands.show) { + ret = computeConstrainedSmoothedData.call(this, this.renderer._hiBandGridData); + this.renderer._hiBandSmoothedData = ret[0]; + ret = computeConstrainedSmoothedData.call(this, this.renderer._lowBandGridData); + this.renderer._lowBandSmoothedData = ret[0]; + } + + ret = null; + } + else { + ret = computeHermiteSmoothedData.call(this, gd); + this.renderer._smoothedData = ret[0]; + this.renderer._smoothedPlotData = ret[1]; + + if (bands.show) { + ret = computeHermiteSmoothedData.call(this, this.renderer._hiBandGridData); + this.renderer._hiBandSmoothedData = ret[0]; + ret = computeHermiteSmoothedData.call(this, this.renderer._lowBandGridData); + this.renderer._lowBandSmoothedData = ret[0]; + } + + ret = null; + } + } + return gd; + }; + + + // called within scope of series. + $.jqplot.LineRenderer.prototype.draw = function(ctx, gd, options, plot) { + var i; + // get a copy of the options, so we don't modify the original object. + var opts = $.extend(true, {}, options); + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke; + var xmin, ymin, xmax, ymax; + ctx.save(); + if (gd.length) { + if (showLine) { + // if we fill, we'll have to add points to close the curve. + if (fill) { + if (this.fillToZero) { + // have to break line up into shapes at axis crossings + var negativeColor = this.negativeColor; + if (! this.useNegativeColors) { + negativeColor = opts.fillStyle; + } + var isnegative = false; + var posfs = opts.fillStyle; + + // if stoking line as well as filling, get a copy of line data. + if (fillAndStroke) { + var fasgd = gd.slice(0); + } + // if not stacked, fill down to axis + if (this.index == 0 || !this._stack) { + + var tempgd = []; + var pd = (this.renderer.smooth) ? this.renderer._smoothedPlotData : this._plotData; + this._areaPoints = []; + var pyzero = this._yaxis.series_u2p(this.fillToValue); + var pxzero = this._xaxis.series_u2p(this.fillToValue); + + opts.closePath = true; + + if (this.fillAxis == 'y') { + tempgd.push([gd[0][0], pyzero]); + this._areaPoints.push([gd[0][0], pyzero]); + + for (var i=0; i<gd.length-1; i++) { + tempgd.push(gd[i]); + this._areaPoints.push(gd[i]); + // do we have an axis crossing? + if (pd[i][1] * pd[i+1][1] <= 0) { + if (pd[i][1] < 0) { + isnegative = true; + opts.fillStyle = negativeColor; + } + else { + isnegative = false; + opts.fillStyle = posfs; + } + + var xintercept = gd[i][0] + (gd[i+1][0] - gd[i][0]) * (pyzero-gd[i][1])/(gd[i+1][1] - gd[i][1]); + tempgd.push([xintercept, pyzero]); + this._areaPoints.push([xintercept, pyzero]); + // now draw this shape and shadow. + if (shadow) { + this.renderer.shadowRenderer.draw(ctx, tempgd, opts); + } + this.renderer.shapeRenderer.draw(ctx, tempgd, opts); + // now empty temp array and continue + tempgd = [[xintercept, pyzero]]; + // this._areaPoints = [[xintercept, pyzero]]; + } + } + if (pd[gd.length-1][1] < 0) { + isnegative = true; + opts.fillStyle = negativeColor; + } + else { + isnegative = false; + opts.fillStyle = posfs; + } + tempgd.push(gd[gd.length-1]); + this._areaPoints.push(gd[gd.length-1]); + tempgd.push([gd[gd.length-1][0], pyzero]); + this._areaPoints.push([gd[gd.length-1][0], pyzero]); + } + // now draw the last area. + if (shadow) { + this.renderer.shadowRenderer.draw(ctx, tempgd, opts); + } + this.renderer.shapeRenderer.draw(ctx, tempgd, opts); + + + // var gridymin = this._yaxis.series_u2p(0); + // // IE doesn't return new length on unshift + // gd.unshift([gd[0][0], gridymin]); + // len = gd.length; + // gd.push([gd[len - 1][0], gridymin]); + } + // if stacked, fill to line below + else { + var prev = this._prevGridData; + for (var i=prev.length; i>0; i--) { + gd.push(prev[i-1]); + // this._areaPoints.push(prev[i-1]); + } + if (shadow) { + this.renderer.shadowRenderer.draw(ctx, gd, opts); + } + this._areaPoints = gd; + this.renderer.shapeRenderer.draw(ctx, gd, opts); + } + } + ///////////////////////// + // Not filled to zero + //////////////////////// + else { + // if stoking line as well as filling, get a copy of line data. + if (fillAndStroke) { + var fasgd = gd.slice(0); + } + // if not stacked, fill down to axis + if (this.index == 0 || !this._stack) { + // var gridymin = this._yaxis.series_u2p(this._yaxis.min) - this.gridBorderWidth / 2; + var gridymin = ctx.canvas.height; + // IE doesn't return new length on unshift + gd.unshift([gd[0][0], gridymin]); + var len = gd.length; + gd.push([gd[len - 1][0], gridymin]); + } + // if stacked, fill to line below + else { + var prev = this._prevGridData; + for (var i=prev.length; i>0; i--) { + gd.push(prev[i-1]); + } + } + this._areaPoints = gd; + + if (shadow) { + this.renderer.shadowRenderer.draw(ctx, gd, opts); + } + + this.renderer.shapeRenderer.draw(ctx, gd, opts); + } + if (fillAndStroke) { + var fasopts = $.extend(true, {}, opts, {fill:false, closePath:false}); + this.renderer.shapeRenderer.draw(ctx, fasgd, fasopts); + ////////// + // TODO: figure out some way to do shadows nicely + // if (shadow) { + // this.renderer.shadowRenderer.draw(ctx, fasgd, fasopts); + // } + // now draw the markers + if (this.markerRenderer.show) { + if (this.renderer.smooth) { + fasgd = this.gridData; + } + for (i=0; i<fasgd.length; i++) { + this.markerRenderer.draw(fasgd[i][0], fasgd[i][1], ctx, opts.markerOptions); + } + } + } + } + else { + + if (this.renderer.bands.show) { + var bdat; + var bopts = $.extend(true, {}, opts); + if (this.renderer.bands.showLines) { + bdat = (this.renderer.smooth) ? this.renderer._hiBandSmoothedData : this.renderer._hiBandGridData; + this.renderer.shapeRenderer.draw(ctx, bdat, opts); + bdat = (this.renderer.smooth) ? this.renderer._lowBandSmoothedData : this.renderer._lowBandGridData; + this.renderer.shapeRenderer.draw(ctx, bdat, bopts); + } + + if (this.renderer.bands.fill) { + if (this.renderer.smooth) { + bdat = this.renderer._hiBandSmoothedData.concat(this.renderer._lowBandSmoothedData.reverse()); + } + else { + bdat = this.renderer._hiBandGridData.concat(this.renderer._lowBandGridData.reverse()); + } + this._areaPoints = bdat; + bopts.closePath = true; + bopts.fill = true; + bopts.fillStyle = this.renderer.bands.fillColor; + this.renderer.shapeRenderer.draw(ctx, bdat, bopts); + } + } + + if (shadow) { + this.renderer.shadowRenderer.draw(ctx, gd, opts); + } + + this.renderer.shapeRenderer.draw(ctx, gd, opts); + } + } + // calculate the bounding box + var xmin = xmax = ymin = ymax = null; + for (i=0; i<this._areaPoints.length; i++) { + var p = this._areaPoints[i]; + if (xmin > p[0] || xmin == null) { + xmin = p[0]; + } + if (ymax < p[1] || ymax == null) { + ymax = p[1]; + } + if (xmax < p[0] || xmax == null) { + xmax = p[0]; + } + if (ymin > p[1] || ymin == null) { + ymin = p[1]; + } + } + + if (this.type === 'line' && this.renderer.bands.show) { + ymax = this._yaxis.series_u2p(this.renderer.bands._min); + ymin = this._yaxis.series_u2p(this.renderer.bands._max); + } + + this._boundingBox = [[xmin, ymax], [xmax, ymin]]; + + // now draw the markers + if (this.markerRenderer.show && !fill) { + if (this.renderer.smooth) { + gd = this.gridData; + } + for (i=0; i<gd.length; i++) { + if (gd[i][0] != null && gd[i][1] != null) { + this.markerRenderer.draw(gd[i][0], gd[i][1], ctx, opts.markerOptions); + } + } + } + } + + ctx.restore(); + }; + + $.jqplot.LineRenderer.prototype.drawShadow = function(ctx, gd, options) { + // This is a no-op, shadows drawn with lines. + }; + + // called with scope of plot. + // make sure to not leave anything highlighted. + function postInit(target, data, options) { + for (var i=0; i<this.series.length; i++) { + if (this.series[i].renderer.constructor == $.jqplot.LineRenderer) { + // don't allow mouseover and mousedown at same time. + if (this.series[i].highlightMouseOver) { + this.series[i].highlightMouseDown = false; + } + } + } + } + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + function postPlotDraw() { + // Memory Leaks patch + if (this.plugins.lineRenderer && this.plugins.lineRenderer.highlightCanvas) { + this.plugins.lineRenderer.highlightCanvas.resetCanvas(); + this.plugins.lineRenderer.highlightCanvas = null; + } + + this.plugins.lineRenderer.highlightedSeriesIndex = null; + this.plugins.lineRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); + + this.eventCanvas._elem.before(this.plugins.lineRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-lineRenderer-highlight-canvas', this._plotDimensions, this)); + this.plugins.lineRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); + } + + function highlight (plot, sidx, pidx, points) { + var s = plot.series[sidx]; + var canvas = plot.plugins.lineRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); + s._highlightedPoint = pidx; + plot.plugins.lineRenderer.highlightedSeriesIndex = sidx; + var opts = {fillStyle: s.highlightColor}; + if (s.type === 'line' && s.renderer.bands.show) { + opts.fill = true; + opts.closePath = true; + } + s.renderer.shapeRenderer.draw(canvas._ctx, points, opts); + canvas = null; + } + + function unhighlight (plot) { + var canvas = plot.plugins.lineRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); + for (var i=0; i<plot.series.length; i++) { + plot.series[i]._highlightedPoint = null; + } + plot.plugins.lineRenderer.highlightedSeriesIndex = null; + plot.target.trigger('jqplotDataUnhighlight'); + canvas = null; + } + + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt1 = jQuery.Event('jqplotDataMouseOver'); + evt1.pageX = ev.pageX; + evt1.pageY = ev.pageY; + plot.target.trigger(evt1, ins); + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.lineRenderer.highlightedSeriesIndex)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.lineRenderer.highlightedSeriesIndex)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { + var idx = plot.plugins.lineRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + } + + function handleClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt = jQuery.Event('jqplotDataClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + function handleRightClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var idx = plot.plugins.lineRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + var evt = jQuery.Event('jqplotDataRightClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + + // class: $.jqplot.LinearAxisRenderer + // The default jqPlot axis renderer, creating a numeric axis. + $.jqplot.LinearAxisRenderer = function() { + }; + + // called with scope of axis object. + $.jqplot.LinearAxisRenderer.prototype.init = function(options){ + // prop: breakPoints + // EXPERIMENTAL!! Use at your own risk! + // Works only with linear axes and the default tick renderer. + // Array of [start, stop] points to create a broken axis. + // Broken axes have a "jump" in them, which is an immediate + // transition from a smaller value to a larger value. + // Currently, axis ticks MUST be manually assigned if using breakPoints + // by using the axis ticks array option. + this.breakPoints = null; + // prop: breakTickLabel + // Label to use at the axis break if breakPoints are specified. + this.breakTickLabel = "≈"; + // prop: drawBaseline + // True to draw the axis baseline. + this.drawBaseline = true; + // prop: baselineWidth + // width of the baseline in pixels. + this.baselineWidth = null; + // prop: baselineColor + // CSS color spec for the baseline. + this.baselineColor = null; + // prop: forceTickAt0 + // This will ensure that there is always a tick mark at 0. + // If data range is strictly positive or negative, + // this will force 0 to be inside the axis bounds unless + // the appropriate axis pad (pad, padMin or padMax) is set + // to 0, then this will force an axis min or max value at 0. + // This has know effect when any of the following options + // are set: autoscale, min, max, numberTicks or tickInterval. + this.forceTickAt0 = false; + // prop: forceTickAt100 + // This will ensure that there is always a tick mark at 100. + // If data range is strictly above or below 100, + // this will force 100 to be inside the axis bounds unless + // the appropriate axis pad (pad, padMin or padMax) is set + // to 0, then this will force an axis min or max value at 100. + // This has know effect when any of the following options + // are set: autoscale, min, max, numberTicks or tickInterval. + this.forceTickAt100 = false; + // prop: tickInset + // Controls the amount to inset the first and last ticks from + // the edges of the grid, in multiples of the tick interval. + // 0 is no inset, 0.5 is one half a tick interval, 1 is a full + // tick interval, etc. + this.tickInset = 0; + // prop: minorTicks + // Number of ticks to add between "major" ticks. + // Major ticks are ticks supplied by user or auto computed. + // Minor ticks cannot be created by user. + this.minorTicks = 0; + // prop: alignTicks + // true to align tick marks across opposed axes + // such as from the y2axis to yaxis. + this.alignTicks = false; + this._autoFormatString = ''; + this._overrideFormatString = false; + this._scalefact = 1.0; + $.extend(true, this, options); + if (this.breakPoints) { + if (!$.isArray(this.breakPoints)) { + this.breakPoints = null; + } + else if (this.breakPoints.length < 2 || this.breakPoints[1] <= this.breakPoints[0]) { + this.breakPoints = null; + } + } + if (this.numberTicks != null && this.numberTicks < 2) { + this.numberTicks = 2; + } + this.resetDataBounds(); + }; + + // called with scope of axis + $.jqplot.LinearAxisRenderer.prototype.draw = function(ctx, plot) { + if (this.show) { + // populate the axis label and value properties. + // createTicks is a method on the renderer, but + // call it within the scope of the axis. + this.renderer.createTicks.call(this, plot); + // fill a div with axes labels in the right direction. + // Need to pregenerate each axis to get its bounds and + // position it and the labels correctly on the plot. + var dim=0; + var temp; + // Added for theming. + if (this._elem) { + // Memory Leaks patch + //this._elem.empty(); + this._elem.emptyForce(); + this._elem = null; + } + + this._elem = $(document.createElement('div')); + this._elem.addClass('jqplot-axis jqplot-'+this.name); + this._elem.css('position', 'absolute'); + + + if (this.name == 'xaxis' || this.name == 'x2axis') { + this._elem.width(this._plotDimensions.width); + } + else { + this._elem.height(this._plotDimensions.height); + } + + // create a _label object. + this.labelOptions.axis = this.name; + this._label = new this.labelRenderer(this.labelOptions); + if (this._label.show) { + var elem = this._label.draw(ctx, plot); + elem.appendTo(this._elem); + elem = null; + } + + var t = this._ticks; + var tick; + for (var i=0; i<t.length; i++) { + tick = t[i]; + if (tick.show && tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { + this._elem.append(tick.draw(ctx, plot)); + } + } + tick = null; + t = null; + } + return this._elem; + }; + + // called with scope of an axis + $.jqplot.LinearAxisRenderer.prototype.reset = function() { + this.min = this._options.min; + this.max = this._options.max; + this.tickInterval = this._options.tickInterval; + this.numberTicks = this._options.numberTicks; + this._autoFormatString = ''; + if (this._overrideFormatString && this.tickOptions && this.tickOptions.formatString) { + this.tickOptions.formatString = ''; + } + + // this._ticks = this.__ticks; + }; + + // called with scope of axis + $.jqplot.LinearAxisRenderer.prototype.set = function() { + var dim = 0; + var temp; + var w = 0; + var h = 0; + var lshow = (this._label == null) ? false : this._label.show; + if (this.show) { + var t = this._ticks; + var tick; + for (var i=0; i<t.length; i++) { + tick = t[i]; + if (!tick._breakTick && tick.show && tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + temp = tick._elem.outerHeight(true); + } + else { + temp = tick._elem.outerWidth(true); + } + if (temp > dim) { + dim = temp; + } + } + } + tick = null; + t = null; + + if (lshow) { + w = this._label._elem.outerWidth(true); + h = this._label._elem.outerHeight(true); + } + if (this.name == 'xaxis') { + dim = dim + h; + this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); + } + else if (this.name == 'x2axis') { + dim = dim + h; + this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); + } + else if (this.name == 'yaxis') { + dim = dim + w; + this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css('width', w+'px'); + } + } + else { + dim = dim + w; + this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css('width', w+'px'); + } + } + } + }; + + // called with scope of axis + $.jqplot.LinearAxisRenderer.prototype.createTicks = function(plot) { + // we're are operating on an axis here + var ticks = this._ticks; + var userTicks = this.ticks; + var name = this.name; + // databounds were set on axis initialization. + var db = this._dataBounds; + var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height; + var interval; + var min, max; + var pos1, pos2; + var tt, i; + // get a copy of user's settings for min/max. + var userMin = this.min; + var userMax = this.max; + var userNT = this.numberTicks; + var userTI = this.tickInterval; + + var threshold = 30; + this._scalefact = (Math.max(dim, threshold+1) - threshold)/300.0; + + // if we already have ticks, use them. + // ticks must be in order of increasing value. + + if (userTicks.length) { + // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed + for (i=0; i<userTicks.length; i++){ + var ut = userTicks[i]; + var t = new this.tickRenderer(this.tickOptions); + if ($.isArray(ut)) { + t.value = ut[0]; + if (this.breakPoints) { + if (ut[0] == this.breakPoints[0]) { + t.label = this.breakTickLabel; + t._breakTick = true; + t.showGridline = false; + t.showMark = false; + } + else if (ut[0] > this.breakPoints[0] && ut[0] <= this.breakPoints[1]) { + t.show = false; + t.showGridline = false; + t.label = ut[1]; + } + else { + t.label = ut[1]; + } + } + else { + t.label = ut[1]; + } + t.setTick(ut[0], this.name); + this._ticks.push(t); + } + + else if ($.isPlainObject(ut)) { + $.extend(true, t, ut); + t.axis = this.name; + this._ticks.push(t); + } + + else { + t.value = ut; + if (this.breakPoints) { + if (ut == this.breakPoints[0]) { + t.label = this.breakTickLabel; + t._breakTick = true; + t.showGridline = false; + t.showMark = false; + } + else if (ut > this.breakPoints[0] && ut <= this.breakPoints[1]) { + t.show = false; + t.showGridline = false; + } + } + t.setTick(ut, this.name); + this._ticks.push(t); + } + } + this.numberTicks = userTicks.length; + this.min = this._ticks[0].value; + this.max = this._ticks[this.numberTicks-1].value; + this.tickInterval = (this.max - this.min) / (this.numberTicks - 1); + } + + // we don't have any ticks yet, let's make some! + else { + if (name == 'xaxis' || name == 'x2axis') { + dim = this._plotDimensions.width; + } + else { + dim = this._plotDimensions.height; + } + + var _numberTicks = this.numberTicks; + + // if aligning this axis, use number of ticks from previous axis. + // Do I need to reset somehow if alignTicks is changed and then graph is replotted?? + if (this.alignTicks) { + if (this.name === 'x2axis' && plot.axes.xaxis.show) { + _numberTicks = plot.axes.xaxis.numberTicks; + } + else if (this.name.charAt(0) === 'y' && this.name !== 'yaxis' && this.name !== 'yMidAxis' && plot.axes.yaxis.show) { + _numberTicks = plot.axes.yaxis.numberTicks; + } + } + + min = ((this.min != null) ? this.min : db.min); + max = ((this.max != null) ? this.max : db.max); + + var range = max - min; + var rmin, rmax; + var temp; + + if (this.tickOptions == null || !this.tickOptions.formatString) { + this._overrideFormatString = true; + } + + // Doing complete autoscaling + if (this.min == null || this.max == null && this.tickInterval == null && !this.autoscale) { + // Check if user must have tick at 0 or 100 and ensure they are in range. + // The autoscaling algorithm will always place ticks at 0 and 100 if they are in range. + if (this.forceTickAt0) { + if (min > 0) { + min = 0; + } + if (max < 0) { + max = 0; + } + } + + if (this.forceTickAt100) { + if (min > 100) { + min = 100; + } + if (max < 100) { + max = 100; + } + } + + var keepMin = false, + keepMax = false; + + if (this.min != null) { + keepMin = true; + } + + else if (this.max != null) { + keepMax = true; + } + + // var threshold = 30; + // var tdim = Math.max(dim, threshold+1); + // this._scalefact = (tdim-threshold)/300.0; + var ret = $.jqplot.LinearTickGenerator(min, max, this._scalefact, _numberTicks, keepMin, keepMax); + // calculate a padded max and min, points should be less than these + // so that they aren't too close to the edges of the plot. + // User can adjust how much padding is allowed with pad, padMin and PadMax options. + // If min or max is set, don't pad that end of axis. + var tumin = (this.min != null) ? min : min + range*(this.padMin - 1); + var tumax = (this.max != null) ? max : max - range*(this.padMax - 1); + + // if they're equal, we shouldn't have to do anything, right? + // if (min <=tumin || max >= tumax) { + if (min <tumin || max > tumax) { + tumin = (this.min != null) ? min : min - range*(this.padMin - 1); + tumax = (this.max != null) ? max : max + range*(this.padMax - 1); + ret = $.jqplot.LinearTickGenerator(tumin, tumax, this._scalefact, _numberTicks, keepMin, keepMax); + } + + this.min = ret[0]; + this.max = ret[1]; + // if numberTicks specified, it should return the same. + this.numberTicks = ret[2]; + this._autoFormatString = ret[3]; + this.tickInterval = ret[4]; + } + + // User has specified some axis scale related option, can use auto algorithm + else { + + // if min and max are same, space them out a bit + if (min == max) { + var adj = 0.05; + if (min > 0) { + adj = Math.max(Math.log(min)/Math.LN10, 0.05); + } + min -= adj; + max += adj; + } + + // autoscale. Can't autoscale if min or max is supplied. + // Will use numberTicks and tickInterval if supplied. Ticks + // across multiple axes may not line up depending on how + // bars are to be plotted. + if (this.autoscale && this.min == null && this.max == null) { + var rrange, ti, margin; + var forceMinZero = false; + var forceZeroLine = false; + var intervals = {min:null, max:null, average:null, stddev:null}; + // if any series are bars, or if any are fill to zero, and if this + // is the axis to fill toward, check to see if we can start axis at zero. + for (var i=0; i<this._series.length; i++) { + var s = this._series[i]; + var faname = (s.fillAxis == 'x') ? s._xaxis.name : s._yaxis.name; + // check to see if this is the fill axis + if (this.name == faname) { + var vals = s._plotValues[s.fillAxis]; + var vmin = vals[0]; + var vmax = vals[0]; + for (var j=1; j<vals.length; j++) { + if (vals[j] < vmin) { + vmin = vals[j]; + } + else if (vals[j] > vmax) { + vmax = vals[j]; + } + } + var dp = (vmax - vmin) / vmax; + // is this sries a bar? + if (s.renderer.constructor == $.jqplot.BarRenderer) { + // if no negative values and could also check range. + if (vmin >= 0 && (s.fillToZero || dp > 0.1)) { + forceMinZero = true; + } + else { + forceMinZero = false; + if (s.fill && s.fillToZero && vmin < 0 && vmax > 0) { + forceZeroLine = true; + } + else { + forceZeroLine = false; + } + } + } + + // if not a bar and filling, use appropriate method. + else if (s.fill) { + if (vmin >= 0 && (s.fillToZero || dp > 0.1)) { + forceMinZero = true; + } + else if (vmin < 0 && vmax > 0 && s.fillToZero) { + forceMinZero = false; + forceZeroLine = true; + } + else { + forceMinZero = false; + forceZeroLine = false; + } + } + + // if not a bar and not filling, only change existing state + // if it doesn't make sense + else if (vmin < 0) { + forceMinZero = false; + } + } + } + + // check if we need make axis min at 0. + if (forceMinZero) { + // compute number of ticks + this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing); + this.min = 0; + userMin = 0; + // what order is this range? + // what tick interval does that give us? + ti = max/(this.numberTicks-1); + temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10))); + if (ti/temp == parseInt(ti/temp, 10)) { + ti += temp; + } + this.tickInterval = Math.ceil(ti/temp) * temp; + this.max = this.tickInterval * (this.numberTicks - 1); + } + + // check if we need to make sure there is a tick at 0. + else if (forceZeroLine) { + // compute number of ticks + this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing); + var ntmin = Math.ceil(Math.abs(min)/range*(this.numberTicks-1)); + var ntmax = this.numberTicks - 1 - ntmin; + ti = Math.max(Math.abs(min/ntmin), Math.abs(max/ntmax)); + temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10))); + this.tickInterval = Math.ceil(ti/temp) * temp; + this.max = this.tickInterval * ntmax; + this.min = -this.tickInterval * ntmin; + } + + // if nothing else, do autoscaling which will try to line up ticks across axes. + else { + if (this.numberTicks == null){ + if (this.tickInterval) { + this.numberTicks = 3 + Math.ceil(range / this.tickInterval); + } + else { + this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing); + } + } + + if (this.tickInterval == null) { + // get a tick interval + ti = range/(this.numberTicks - 1); + + if (ti < 1) { + temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10))); + } + else { + temp = 1; + } + this.tickInterval = Math.ceil(ti*temp*this.pad)/temp; + } + else { + temp = 1 / this.tickInterval; + } + + // try to compute a nicer, more even tick interval + // temp = Math.pow(10, Math.floor(Math.log(ti)/Math.LN10)); + // this.tickInterval = Math.ceil(ti/temp) * temp; + rrange = this.tickInterval * (this.numberTicks - 1); + margin = (rrange - range)/2; + + if (this.min == null) { + this.min = Math.floor(temp*(min-margin))/temp; + } + if (this.max == null) { + this.max = this.min + rrange; + } + } + + // Compute a somewhat decent format string if it is needed. + // get precision of interval and determine a format string. + var sf = $.jqplot.getSignificantFigures(this.tickInterval); + + var fstr; + + // if we have only a whole number, use integer formatting + if (sf.digitsLeft >= sf.significantDigits) { + fstr = '%d'; + } + + else { + var temp = Math.max(0, 5 - sf.digitsLeft); + temp = Math.min(temp, sf.digitsRight); + fstr = '%.'+ temp + 'f'; + } + + this._autoFormatString = fstr; + } + + // Use the default algorithm which pads each axis to make the chart + // centered nicely on the grid. + else { + + rmin = (this.min != null) ? this.min : min - range*(this.padMin - 1); + rmax = (this.max != null) ? this.max : max + range*(this.padMax - 1); + range = rmax - rmin; + + if (this.numberTicks == null){ + // if tickInterval is specified by user, we will ignore computed maximum. + // max will be equal or greater to fit even # of ticks. + if (this.tickInterval != null) { + this.numberTicks = Math.ceil((rmax - rmin)/this.tickInterval)+1; + } + else if (dim > 100) { + this.numberTicks = parseInt(3+(dim-100)/75, 10); + } + else { + this.numberTicks = 2; + } + } + + if (this.tickInterval == null) { + this.tickInterval = range / (this.numberTicks-1); + } + + if (this.max == null) { + rmax = rmin + this.tickInterval*(this.numberTicks - 1); + } + if (this.min == null) { + rmin = rmax - this.tickInterval*(this.numberTicks - 1); + } + + // get precision of interval and determine a format string. + var sf = $.jqplot.getSignificantFigures(this.tickInterval); + + var fstr; + + // if we have only a whole number, use integer formatting + if (sf.digitsLeft >= sf.significantDigits) { + fstr = '%d'; + } + + else { + var temp = Math.max(0, 5 - sf.digitsLeft); + temp = Math.min(temp, sf.digitsRight); + fstr = '%.'+ temp + 'f'; + } + + + this._autoFormatString = fstr; + + this.min = rmin; + this.max = rmax; + } + + if (this.renderer.constructor == $.jqplot.LinearAxisRenderer && this._autoFormatString == '') { + // fix for misleading tick display with small range and low precision. + range = this.max - this.min; + // figure out precision + var temptick = new this.tickRenderer(this.tickOptions); + // use the tick formatString or, the default. + var fs = temptick.formatString || $.jqplot.config.defaultTickFormatString; + var fs = fs.match($.jqplot.sprintf.regex)[0]; + var precision = 0; + if (fs) { + if (fs.search(/[fFeEgGpP]/) > -1) { + var m = fs.match(/\%\.(\d{0,})?[eEfFgGpP]/); + if (m) { + precision = parseInt(m[1], 10); + } + else { + precision = 6; + } + } + else if (fs.search(/[di]/) > -1) { + precision = 0; + } + // fact will be <= 1; + var fact = Math.pow(10, -precision); + if (this.tickInterval < fact) { + // need to correct underrange + if (userNT == null && userTI == null) { + this.tickInterval = fact; + if (userMax == null && userMin == null) { + // this.min = Math.floor((this._dataBounds.min - this.tickInterval)/fact) * fact; + this.min = Math.floor(this._dataBounds.min/fact) * fact; + if (this.min == this._dataBounds.min) { + this.min = this._dataBounds.min - this.tickInterval; + } + // this.max = Math.ceil((this._dataBounds.max + this.tickInterval)/fact) * fact; + this.max = Math.ceil(this._dataBounds.max/fact) * fact; + if (this.max == this._dataBounds.max) { + this.max = this._dataBounds.max + this.tickInterval; + } + var n = (this.max - this.min)/this.tickInterval; + n = n.toFixed(11); + n = Math.ceil(n); + this.numberTicks = n + 1; + } + else if (userMax == null) { + // add one tick for top of range. + var n = (this._dataBounds.max - this.min) / this.tickInterval; + n = n.toFixed(11); + this.numberTicks = Math.ceil(n) + 2; + this.max = this.min + this.tickInterval * (this.numberTicks-1); + } + else if (userMin == null) { + // add one tick for bottom of range. + var n = (this.max - this._dataBounds.min) / this.tickInterval; + n = n.toFixed(11); + this.numberTicks = Math.ceil(n) + 2; + this.min = this.max - this.tickInterval * (this.numberTicks-1); + } + else { + // calculate a number of ticks so max is within axis scale + this.numberTicks = Math.ceil((userMax - userMin)/this.tickInterval) + 1; + // if user's min and max don't fit evenly in ticks, adjust. + // This takes care of cases such as user min set to 0, max set to 3.5 but tick + // format string set to %d (integer ticks) + this.min = Math.floor(userMin*Math.pow(10, precision))/Math.pow(10, precision); + this.max = Math.ceil(userMax*Math.pow(10, precision))/Math.pow(10, precision); + // this.max = this.min + this.tickInterval*(this.numberTicks-1); + this.numberTicks = Math.ceil((this.max - this.min)/this.tickInterval) + 1; + } + } + } + } + } + + } + + if (this._overrideFormatString && this._autoFormatString != '') { + this.tickOptions = this.tickOptions || {}; + this.tickOptions.formatString = this._autoFormatString; + } + + var t, to; + for (var i=0; i<this.numberTicks; i++){ + tt = this.min + i * this.tickInterval; + t = new this.tickRenderer(this.tickOptions); + // var t = new $.jqplot.AxisTickRenderer(this.tickOptions); + + t.setTick(tt, this.name); + this._ticks.push(t); + + if (i < this.numberTicks - 1) { + for (var j=0; j<this.minorTicks; j++) { + tt += this.tickInterval/(this.minorTicks+1); + to = $.extend(true, {}, this.tickOptions, {name:this.name, value:tt, label:'', isMinorTick:true}); + t = new this.tickRenderer(to); + this._ticks.push(t); + } + } + t = null; + } + } + + if (this.tickInset) { + this.min = this.min - this.tickInset * this.tickInterval; + this.max = this.max + this.tickInset * this.tickInterval; + } + + ticks = null; + }; + + // Used to reset just the values of the ticks and then repack, which will + // recalculate the positioning functions. It is assuemd that the + // number of ticks is the same and the values of the new array are at the + // proper interval. + // This method needs to be called with the scope of an axis object, like: + // + // > plot.axes.yaxis.renderer.resetTickValues.call(plot.axes.yaxis, yarr); + // + $.jqplot.LinearAxisRenderer.prototype.resetTickValues = function(opts) { + if ($.isArray(opts) && opts.length == this._ticks.length) { + var t; + for (var i=0; i<opts.length; i++) { + t = this._ticks[i]; + t.value = opts[i]; + t.label = t.formatter(t.formatString, opts[i]); + t.label = t.prefix + t.label; + t._elem.html(t.label); + } + t = null; + this.min = $.jqplot.arrayMin(opts); + this.max = $.jqplot.arrayMax(opts); + this.pack(); + } + // Not implemented yet. + // else if ($.isPlainObject(opts)) { + // + // } + }; + + // called with scope of axis + $.jqplot.LinearAxisRenderer.prototype.pack = function(pos, offsets) { + // Add defaults for repacking from resetTickValues function. + pos = pos || {}; + offsets = offsets || this._offsets; + + var ticks = this._ticks; + var max = this.max; + var min = this.min; + var offmax = offsets.max; + var offmin = offsets.min; + var lshow = (this._label == null) ? false : this._label.show; + + for (var p in pos) { + this._elem.css(p, pos[p]); + } + + this._offsets = offsets; + // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. + var pixellength = offmax - offmin; + var unitlength = max - min; + + // point to unit and unit to point conversions references to Plot DOM element top left corner. + if (this.breakPoints) { + unitlength = unitlength - this.breakPoints[1] + this.breakPoints[0]; + + this.p2u = function(p){ + return (p - offmin) * unitlength / pixellength + min; + }; + + this.u2p = function(u){ + if (u > this.breakPoints[0] && u < this.breakPoints[1]){ + u = this.breakPoints[0]; + } + if (u <= this.breakPoints[0]) { + return (u - min) * pixellength / unitlength + offmin; + } + else { + return (u - this.breakPoints[1] + this.breakPoints[0] - min) * pixellength / unitlength + offmin; + } + }; + + if (this.name.charAt(0) == 'x'){ + this.series_u2p = function(u){ + if (u > this.breakPoints[0] && u < this.breakPoints[1]){ + u = this.breakPoints[0]; + } + if (u <= this.breakPoints[0]) { + return (u - min) * pixellength / unitlength; + } + else { + return (u - this.breakPoints[1] + this.breakPoints[0] - min) * pixellength / unitlength; + } + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + min; + }; + } + + else { + this.series_u2p = function(u){ + if (u > this.breakPoints[0] && u < this.breakPoints[1]){ + u = this.breakPoints[0]; + } + if (u >= this.breakPoints[1]) { + return (u - max) * pixellength / unitlength; + } + else { + return (u + this.breakPoints[1] - this.breakPoints[0] - max) * pixellength / unitlength; + } + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + max; + }; + } + } + else { + this.p2u = function(p){ + return (p - offmin) * unitlength / pixellength + min; + }; + + this.u2p = function(u){ + return (u - min) * pixellength / unitlength + offmin; + }; + + if (this.name == 'xaxis' || this.name == 'x2axis'){ + this.series_u2p = function(u){ + return (u - min) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + min; + }; + } + + else { + this.series_u2p = function(u){ + return (u - max) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + max; + }; + } + } + + if (this.show) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + for (var i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + // will need to adjust auto positioning based on which axis this is. + var temp = (this.name == 'xaxis') ? 1 : -1; + switch (t.labelPosition) { + case 'auto': + // position at end + if (temp * t.angle < 0) { + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + } + // position at start + else { + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + } + break; + case 'end': + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + case 'start': + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + break; + case 'middle': + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + default: + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + } + } + else { + shim = -t.getWidth()/2; + } + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('left', val); + t.pack(); + } + } + if (lshow) { + var w = this._label._elem.outerWidth(true); + this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); + if (this.name == 'xaxis') { + this._label._elem.css('bottom', '0px'); + } + else { + this._label._elem.css('top', '0px'); + } + this._label.pack(); + } + } + else { + for (var i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + // will need to adjust auto positioning based on which axis this is. + var temp = (this.name == 'yaxis') ? 1 : -1; + switch (t.labelPosition) { + case 'auto': + // position at end + case 'end': + if (temp * t.angle < 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'start': + if (t.angle > 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'middle': + // if (t.angle > 0) { + // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + // } + // else { + // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + // } + shim = -t.getHeight()/2; + break; + default: + shim = -t.getHeight()/2; + break; + } + } + else { + shim = -t.getHeight()/2; + } + + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('top', val); + t.pack(); + } + } + if (lshow) { + var h = this._label._elem.outerHeight(true); + this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); + if (this.name == 'yaxis') { + this._label._elem.css('left', '0px'); + } + else { + this._label._elem.css('right', '0px'); + } + this._label.pack(); + } + } + } + + ticks = null; + }; + + + /** + * The following code was generaously given to me a while back by Scott Prahl. + * He did a good job at computing axes min, max and number of ticks for the + * case where the user has not set any scale related parameters (tickInterval, + * numberTicks, min or max). I had ignored this use case for a long time, + * focusing on the more difficult case where user has set some option controlling + * tick generation. Anyway, about time I got this into jqPlot. + * Thanks Scott!! + */ + + /** + * Copyright (c) 2010 Scott Prahl + * The next three routines are currently available for use in all personal + * or commercial projects under both the MIT and GPL version 2.0 licenses. + * This means that you can choose the license that best suits your project + * and use it accordingly. + */ + + // A good format string depends on the interval. If the interval is greater + // than 1 then there is no need to show any decimal digits. If it is < 1.0, then + // use the magnitude of the interval to determine the number of digits to show. + function bestFormatString (interval) + { + var fstr; + interval = Math.abs(interval); + if (interval >= 10) { + fstr = '%d'; + } + + else if (interval > 1) { + if (interval === parseInt(interval, 10)) { + fstr = '%d'; + } + else { + fstr = '%.1f'; + } + } + + else { + var expv = -Math.floor(Math.log(interval)/Math.LN10); + fstr = '%.' + expv + 'f'; + } + + return fstr; + } + + var _factors = [0.1, 0.2, 0.3, 0.4, 0.5, 0.8, 1, 2, 3, 4, 5]; + + var _getLowerFactor = function(f) { + var i = _factors.indexOf(f); + if (i > 0) { + return _factors[i-1]; + } + else { + return _factors[_factors.length - 1] / 100; + } + }; + + var _getHigherFactor = function(f) { + var i = _factors.indexOf(f); + if (i < _factors.length-1) { + return _factors[i+1]; + } + else { + return _factors[0] * 100; + } + }; + + // Given a fixed minimum and maximum and a target number ot ticks + // figure out the best interval and + // return min, max, number ticks, format string and tick interval + function bestConstrainedInterval(min, max, nttarget) { + // run through possible number to ticks and see which interval is best + var low = Math.floor(nttarget/2); + var hi = Math.ceil(nttarget*1.5); + var badness = Number.MAX_VALUE; + var r = (max - min); + var temp; + var sd; + var bestNT; + var gsf = $.jqplot.getSignificantFigures; + var fsd; + var fs; + var currentNT; + var bestPrec; + + for (var i=0, l=hi-low+1; i<l; i++) { + currentNT = low + i; + temp = r/(currentNT-1); + sd = gsf(temp); + + temp = Math.abs(nttarget - currentNT) + sd.digitsRight; + if (temp < badness) { + badness = temp; + bestNT = currentNT; + bestPrec = sd.digitsRight; + } + else if (temp === badness) { + // let nicer ticks trump number ot ticks + if (sd.digitsRight < bestPrec) { + bestNT = currentNT; + bestPrec = sd.digitsRight; + } + } + + } + + fsd = Math.max(bestPrec, Math.max(gsf(min).digitsRight, gsf(max).digitsRight)); + if (fsd === 0) { + fs = '%d'; + } + else { + fs = '%.' + fsd + 'f'; + } + temp = r / (bestNT - 1); + // min, max, number ticks, format string, tick interval + return [min, max, bestNT, fs, temp]; + } + + // This will return an interval of form 2 * 10^n, 5 * 10^n or 10 * 10^n + // it is based soley on the range and number of ticks. So if user specifies + // number of ticks, use this. + function bestInterval(range, numberTicks) { + numberTicks = numberTicks || 7; + var minimum = range / (numberTicks - 1); + var magnitude = Math.pow(10, Math.floor(Math.log(minimum) / Math.LN10)); + var residual = minimum / magnitude; + var interval; + // "nicest" ranges are 1, 2, 5 or powers of these. + // for magnitudes below 1, only allow these. + if (magnitude < 1) { + if (residual > 5) { + interval = 10 * magnitude; + } + else if (residual > 2) { + interval = 5 * magnitude; + } + else if (residual > 1) { + interval = 2 * magnitude; + } + else { + interval = magnitude; + } + } + // for large ranges (whole integers), allow intervals like 3, 4 or powers of these. + // this helps a lot with poor choices for number of ticks. + else { + if (residual > 5) { + interval = 10 * magnitude; + } + else if (residual > 4) { + interval = 5 * magnitude; + } + else if (residual > 3) { + interval = 4 * magnitude; + } + else if (residual > 2) { + interval = 3 * magnitude; + } + else if (residual > 1) { + interval = 2 * magnitude; + } + else { + interval = magnitude; + } + } + + return interval; + } + + // This will return an interval of form 2 * 10^n, 5 * 10^n or 10 * 10^n + // it is based soley on the range of data, number of ticks must be computed later. + function bestLinearInterval(range, scalefact) { + scalefact = scalefact || 1; + var expv = Math.floor(Math.log(range)/Math.LN10); + var magnitude = Math.pow(10, expv); + // 0 < f < 10 + var f = range / magnitude; + var fact; + // for large plots, scalefact will decrease f and increase number of ticks. + // for small plots, scalefact will increase f and decrease number of ticks. + f = f/scalefact; + + // for large plots, smaller interval, more ticks. + if (f<=0.38) { + fact = 0.1; + } + else if (f<=1.6) { + fact = 0.2; + } + else if (f<=4.0) { + fact = 0.5; + } + else if (f<=8.0) { + fact = 1.0; + } + // for very small plots, larger interval, less ticks in number ticks + else if (f<=16.0) { + fact = 2; + } + else { + fact = 5; + } + + return fact*magnitude; + } + + function bestLinearComponents(range, scalefact) { + var expv = Math.floor(Math.log(range)/Math.LN10); + var magnitude = Math.pow(10, expv); + // 0 < f < 10 + var f = range / magnitude; + var interval; + var fact; + // for large plots, scalefact will decrease f and increase number of ticks. + // for small plots, scalefact will increase f and decrease number of ticks. + f = f/scalefact; + + // for large plots, smaller interval, more ticks. + if (f<=0.38) { + fact = 0.1; + } + else if (f<=1.6) { + fact = 0.2; + } + else if (f<=4.0) { + fact = 0.5; + } + else if (f<=8.0) { + fact = 1.0; + } + // for very small plots, larger interval, less ticks in number ticks + else if (f<=16.0) { + fact = 2; + } + // else if (f<=20.0) { + // fact = 3; + // } + // else if (f<=24.0) { + // fact = 4; + // } + else { + fact = 5; + } + + interval = fact * magnitude; + + return [interval, fact, magnitude]; + } + + // Given the min and max for a dataset, return suitable endpoints + // for the graphing, a good number for the number of ticks, and a + // format string so that extraneous digits are not displayed. + // returned is an array containing [min, max, nTicks, format] + $.jqplot.LinearTickGenerator = function(axis_min, axis_max, scalefact, numberTicks, keepMin, keepMax) { + // Set to preserve EITHER min OR max. + // If min is preserved, max must be free. + keepMin = (keepMin === null) ? false : keepMin; + keepMax = (keepMax === null || keepMin) ? false : keepMax; + // if endpoints are equal try to include zero otherwise include one + if (axis_min === axis_max) { + axis_max = (axis_max) ? 0 : 1; + } + + scalefact = scalefact || 1.0; + + // make sure range is positive + if (axis_max < axis_min) { + var a = axis_max; + axis_max = axis_min; + axis_min = a; + } + + var r = []; + var ss = bestLinearInterval(axis_max - axis_min, scalefact); + + var gsf = $.jqplot.getSignificantFigures; + + if (numberTicks == null) { + + // Figure out the axis min, max and number of ticks + // the min and max will be some multiple of the tick interval, + // 1*10^n, 2*10^n or 5*10^n. This gaurantees that, if the + // axis min is negative, 0 will be a tick. + if (!keepMin && !keepMax) { + r[0] = Math.floor(axis_min / ss) * ss; // min + r[1] = Math.ceil(axis_max / ss) * ss; // max + r[2] = Math.round((r[1]-r[0])/ss+1.0); // number of ticks + r[3] = bestFormatString(ss); // format string + r[4] = ss; // tick Interval + } + + else if (keepMin) { + r[0] = axis_min; // min + r[2] = Math.ceil((axis_max - axis_min) / ss + 1.0); // number of ticks + r[1] = axis_min + (r[2] - 1) * ss; // max + var digitsMin = gsf(axis_min).digitsRight; + var digitsSS = gsf(ss).digitsRight; + if (digitsMin < digitsSS) { + r[3] = bestFormatString(ss); // format string + } + else { + r[3] = '%.' + digitsMin + 'f'; + } + r[4] = ss; // tick Interval + } + + else if (keepMax) { + r[1] = axis_max; // max + r[2] = Math.ceil((axis_max - axis_min) / ss + 1.0); // number of ticks + r[0] = axis_max - (r[2] - 1) * ss; // min + var digitsMax = gsf(axis_max).digitsRight; + var digitsSS = gsf(ss).digitsRight; + if (digitsMax < digitsSS) { + r[3] = bestFormatString(ss); // format string + } + else { + r[3] = '%.' + digitsMax + 'f'; + } + r[4] = ss; // tick Interval + } + } + + else { + var tempr = []; + + // Figure out the axis min, max and number of ticks + // the min and max will be some multiple of the tick interval, + // 1*10^n, 2*10^n or 5*10^n. This gaurantees that, if the + // axis min is negative, 0 will be a tick. + tempr[0] = Math.floor(axis_min / ss) * ss; // min + tempr[1] = Math.ceil(axis_max / ss) * ss; // max + tempr[2] = Math.round((tempr[1]-tempr[0])/ss+1.0); // number of ticks + tempr[3] = bestFormatString(ss); // format string + tempr[4] = ss; // tick Interval + + // first, see if we happen to get the right number of ticks + if (tempr[2] === numberTicks) { + r = tempr; + } + + else { + + var newti = bestInterval(tempr[1] - tempr[0], numberTicks); + + r[0] = tempr[0]; // min + r[2] = numberTicks; // number of ticks + r[4] = newti; // tick interval + r[3] = bestFormatString(newti); // format string + r[1] = r[0] + (r[2] - 1) * r[4]; // max + } + } + + return r; + }; + + $.jqplot.LinearTickGenerator.bestLinearInterval = bestLinearInterval; + $.jqplot.LinearTickGenerator.bestInterval = bestInterval; + $.jqplot.LinearTickGenerator.bestLinearComponents = bestLinearComponents; + $.jqplot.LinearTickGenerator.bestConstrainedInterval = bestConstrainedInterval; + + + // class: $.jqplot.MarkerRenderer + // The default jqPlot marker renderer, rendering the points on the line. + $.jqplot.MarkerRenderer = function(options){ + // Group: Properties + + // prop: show + // whether or not to show the marker. + this.show = true; + // prop: style + // One of diamond, circle, square, x, plus, dash, filledDiamond, filledCircle, filledSquare + this.style = 'filledCircle'; + // prop: lineWidth + // size of the line for non-filled markers. + this.lineWidth = 2; + // prop: size + // Size of the marker (diameter or circle, length of edge of square, etc.) + this.size = 9.0; + // prop: color + // color of marker. Will be set to color of series by default on init. + this.color = '#666666'; + // prop: shadow + // whether or not to draw a shadow on the line + this.shadow = true; + // prop: shadowAngle + // Shadow angle in degrees + this.shadowAngle = 45; + // prop: shadowOffset + // Shadow offset from line in pixels + this.shadowOffset = 1; + // prop: shadowDepth + // Number of times shadow is stroked, each stroke offset shadowOffset from the last. + this.shadowDepth = 3; + // prop: shadowAlpha + // Alpha channel transparency of shadow. 0 = transparent. + this.shadowAlpha = '0.07'; + // prop: shadowRenderer + // Renderer that will draws the shadows on the marker. + this.shadowRenderer = new $.jqplot.ShadowRenderer(); + // prop: shapeRenderer + // Renderer that will draw the marker. + this.shapeRenderer = new $.jqplot.ShapeRenderer(); + + $.extend(true, this, options); + }; + + $.jqplot.MarkerRenderer.prototype.init = function(options) { + $.extend(true, this, options); + var sdopt = {angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, lineWidth:this.lineWidth, depth:this.shadowDepth, closePath:true}; + if (this.style.indexOf('filled') != -1) { + sdopt.fill = true; + } + if (this.style.indexOf('ircle') != -1) { + sdopt.isarc = true; + sdopt.closePath = false; + } + this.shadowRenderer.init(sdopt); + + var shopt = {fill:false, isarc:false, strokeStyle:this.color, fillStyle:this.color, lineWidth:this.lineWidth, closePath:true}; + if (this.style.indexOf('filled') != -1) { + shopt.fill = true; + } + if (this.style.indexOf('ircle') != -1) { + shopt.isarc = true; + shopt.closePath = false; + } + this.shapeRenderer.init(shopt); + }; + + $.jqplot.MarkerRenderer.prototype.drawDiamond = function(x, y, ctx, fill, options) { + var stretch = 1.2; + var dx = this.size/2/stretch; + var dy = this.size/2*stretch; + var points = [[x-dx, y], [x, y+dy], [x+dx, y], [x, y-dy]]; + if (this.shadow) { + this.shadowRenderer.draw(ctx, points); + } + this.shapeRenderer.draw(ctx, points, options); + }; + + $.jqplot.MarkerRenderer.prototype.drawPlus = function(x, y, ctx, fill, options) { + var stretch = 1.0; + var dx = this.size/2*stretch; + var dy = this.size/2*stretch; + var points1 = [[x, y-dy], [x, y+dy]]; + var points2 = [[x+dx, y], [x-dx, y]]; + var opts = $.extend(true, {}, this.options, {closePath:false}); + if (this.shadow) { + this.shadowRenderer.draw(ctx, points1, {closePath:false}); + this.shadowRenderer.draw(ctx, points2, {closePath:false}); + } + this.shapeRenderer.draw(ctx, points1, opts); + this.shapeRenderer.draw(ctx, points2, opts); + }; + + $.jqplot.MarkerRenderer.prototype.drawX = function(x, y, ctx, fill, options) { + var stretch = 1.0; + var dx = this.size/2*stretch; + var dy = this.size/2*stretch; + var opts = $.extend(true, {}, this.options, {closePath:false}); + var points1 = [[x-dx, y-dy], [x+dx, y+dy]]; + var points2 = [[x-dx, y+dy], [x+dx, y-dy]]; + if (this.shadow) { + this.shadowRenderer.draw(ctx, points1, {closePath:false}); + this.shadowRenderer.draw(ctx, points2, {closePath:false}); + } + this.shapeRenderer.draw(ctx, points1, opts); + this.shapeRenderer.draw(ctx, points2, opts); + }; + + $.jqplot.MarkerRenderer.prototype.drawDash = function(x, y, ctx, fill, options) { + var stretch = 1.0; + var dx = this.size/2*stretch; + var dy = this.size/2*stretch; + var points = [[x-dx, y], [x+dx, y]]; + if (this.shadow) { + this.shadowRenderer.draw(ctx, points); + } + this.shapeRenderer.draw(ctx, points, options); + }; + + $.jqplot.MarkerRenderer.prototype.drawLine = function(p1, p2, ctx, fill, options) { + var points = [p1, p2]; + if (this.shadow) { + this.shadowRenderer.draw(ctx, points); + } + this.shapeRenderer.draw(ctx, points, options); + }; + + $.jqplot.MarkerRenderer.prototype.drawSquare = function(x, y, ctx, fill, options) { + var stretch = 1.0; + var dx = this.size/2/stretch; + var dy = this.size/2*stretch; + var points = [[x-dx, y-dy], [x-dx, y+dy], [x+dx, y+dy], [x+dx, y-dy]]; + if (this.shadow) { + this.shadowRenderer.draw(ctx, points); + } + this.shapeRenderer.draw(ctx, points, options); + }; + + $.jqplot.MarkerRenderer.prototype.drawCircle = function(x, y, ctx, fill, options) { + var radius = this.size/2; + var end = 2*Math.PI; + var points = [x, y, radius, 0, end, true]; + if (this.shadow) { + this.shadowRenderer.draw(ctx, points); + } + this.shapeRenderer.draw(ctx, points, options); + }; + + $.jqplot.MarkerRenderer.prototype.draw = function(x, y, ctx, options) { + options = options || {}; + // hack here b/c shape renderer uses canvas based color style options + // and marker uses css style names. + if (options.show == null || options.show != false) { + if (options.color && !options.fillStyle) { + options.fillStyle = options.color; + } + if (options.color && !options.strokeStyle) { + options.strokeStyle = options.color; + } + switch (this.style) { + case 'diamond': + this.drawDiamond(x,y,ctx, false, options); + break; + case 'filledDiamond': + this.drawDiamond(x,y,ctx, true, options); + break; + case 'circle': + this.drawCircle(x,y,ctx, false, options); + break; + case 'filledCircle': + this.drawCircle(x,y,ctx, true, options); + break; + case 'square': + this.drawSquare(x,y,ctx, false, options); + break; + case 'filledSquare': + this.drawSquare(x,y,ctx, true, options); + break; + case 'x': + this.drawX(x,y,ctx, true, options); + break; + case 'plus': + this.drawPlus(x,y,ctx, true, options); + break; + case 'dash': + this.drawDash(x,y,ctx, true, options); + break; + case 'line': + this.drawLine(x, y, ctx, false, options); + break; + default: + this.drawDiamond(x,y,ctx, false, options); + break; + } + } + }; + + // class: $.jqplot.shadowRenderer + // The default jqPlot shadow renderer, rendering shadows behind shapes. + $.jqplot.ShadowRenderer = function(options){ + // Group: Properties + + // prop: angle + // Angle of the shadow in degrees. Measured counter-clockwise from the x axis. + this.angle = 45; + // prop: offset + // Pixel offset at the given shadow angle of each shadow stroke from the last stroke. + this.offset = 1; + // prop: alpha + // alpha transparency of shadow stroke. + this.alpha = 0.07; + // prop: lineWidth + // width of the shadow line stroke. + this.lineWidth = 1.5; + // prop: lineJoin + // How line segments of the shadow are joined. + this.lineJoin = 'miter'; + // prop: lineCap + // how ends of the shadow line are rendered. + this.lineCap = 'round'; + // prop; closePath + // whether line path segment is closed upon itself. + this.closePath = false; + // prop: fill + // whether to fill the shape. + this.fill = false; + // prop: depth + // how many times the shadow is stroked. Each stroke will be offset by offset at angle degrees. + this.depth = 3; + this.strokeStyle = 'rgba(0,0,0,0.1)'; + // prop: isarc + // whether the shadow is an arc or not. + this.isarc = false; + + $.extend(true, this, options); + }; + + $.jqplot.ShadowRenderer.prototype.init = function(options) { + $.extend(true, this, options); + }; + + // function: draw + // draws an transparent black (i.e. gray) shadow. + // + // ctx - canvas drawing context + // points - array of points or [x, y, radius, start angle (rad), end angle (rad)] + $.jqplot.ShadowRenderer.prototype.draw = function(ctx, points, options) { + ctx.save(); + var opts = (options != null) ? options : {}; + var fill = (opts.fill != null) ? opts.fill : this.fill; + var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect; + var closePath = (opts.closePath != null) ? opts.closePath : this.closePath; + var offset = (opts.offset != null) ? opts.offset : this.offset; + var alpha = (opts.alpha != null) ? opts.alpha : this.alpha; + var depth = (opts.depth != null) ? opts.depth : this.depth; + var isarc = (opts.isarc != null) ? opts.isarc : this.isarc; + var linePattern = (opts.linePattern != null) ? opts.linePattern : this.linePattern; + ctx.lineWidth = (opts.lineWidth != null) ? opts.lineWidth : this.lineWidth; + ctx.lineJoin = (opts.lineJoin != null) ? opts.lineJoin : this.lineJoin; + ctx.lineCap = (opts.lineCap != null) ? opts.lineCap : this.lineCap; + ctx.strokeStyle = opts.strokeStyle || this.strokeStyle || 'rgba(0,0,0,'+alpha+')'; + ctx.fillStyle = opts.fillStyle || this.fillStyle || 'rgba(0,0,0,'+alpha+')'; + for (var j=0; j<depth; j++) { + var ctxPattern = $.jqplot.LinePattern(ctx, linePattern); + ctx.translate(Math.cos(this.angle*Math.PI/180)*offset, Math.sin(this.angle*Math.PI/180)*offset); + ctxPattern.beginPath(); + if (isarc) { + ctx.arc(points[0], points[1], points[2], points[3], points[4], true); + } + else if (fillRect) { + if (fillRect) { + ctx.fillRect(points[0], points[1], points[2], points[3]); + } + } + else if (points && points.length){ + var move = true; + for (var i=0; i<points.length; i++) { + // skip to the first non-null point and move to it. + if (points[i][0] != null && points[i][1] != null) { + if (move) { + ctxPattern.moveTo(points[i][0], points[i][1]); + move = false; + } + else { + ctxPattern.lineTo(points[i][0], points[i][1]); + } + } + else { + move = true; + } + } + + } + if (closePath) { + ctxPattern.closePath(); + } + if (fill) { + ctx.fill(); + } + else { + ctx.stroke(); + } + } + ctx.restore(); + }; + + // class: $.jqplot.shapeRenderer + // The default jqPlot shape renderer. Given a set of points will + // plot them and either stroke a line (fill = false) or fill them (fill = true). + // If a filled shape is desired, closePath = true must also be set to close + // the shape. + $.jqplot.ShapeRenderer = function(options){ + + this.lineWidth = 1.5; + // prop: linePattern + // line pattern 'dashed', 'dotted', 'solid', some combination + // of '-' and '.' characters such as '.-.' or a numerical array like + // [draw, skip, draw, skip, ...] such as [1, 10] to draw a dotted line, + // [1, 10, 20, 10] to draw a dot-dash line, and so on. + this.linePattern = 'solid'; + // prop: lineJoin + // How line segments of the shadow are joined. + this.lineJoin = 'miter'; + // prop: lineCap + // how ends of the shadow line are rendered. + this.lineCap = 'round'; + // prop; closePath + // whether line path segment is closed upon itself. + this.closePath = false; + // prop: fill + // whether to fill the shape. + this.fill = false; + // prop: isarc + // whether the shadow is an arc or not. + this.isarc = false; + // prop: fillRect + // true to draw shape as a filled rectangle. + this.fillRect = false; + // prop: strokeRect + // true to draw shape as a stroked rectangle. + this.strokeRect = false; + // prop: clearRect + // true to cear a rectangle. + this.clearRect = false; + // prop: strokeStyle + // css color spec for the stoke style + this.strokeStyle = '#999999'; + // prop: fillStyle + // css color spec for the fill style. + this.fillStyle = '#999999'; + + $.extend(true, this, options); + }; + + $.jqplot.ShapeRenderer.prototype.init = function(options) { + $.extend(true, this, options); + }; + + // function: draw + // draws the shape. + // + // ctx - canvas drawing context + // points - array of points for shapes or + // [x, y, width, height] for rectangles or + // [x, y, radius, start angle (rad), end angle (rad)] for circles and arcs. + $.jqplot.ShapeRenderer.prototype.draw = function(ctx, points, options) { + ctx.save(); + var opts = (options != null) ? options : {}; + var fill = (opts.fill != null) ? opts.fill : this.fill; + var closePath = (opts.closePath != null) ? opts.closePath : this.closePath; + var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect; + var strokeRect = (opts.strokeRect != null) ? opts.strokeRect : this.strokeRect; + var clearRect = (opts.clearRect != null) ? opts.clearRect : this.clearRect; + var isarc = (opts.isarc != null) ? opts.isarc : this.isarc; + var linePattern = (opts.linePattern != null) ? opts.linePattern : this.linePattern; + var ctxPattern = $.jqplot.LinePattern(ctx, linePattern); + ctx.lineWidth = opts.lineWidth || this.lineWidth; + ctx.lineJoin = opts.lineJoin || this.lineJoin; + ctx.lineCap = opts.lineCap || this.lineCap; + ctx.strokeStyle = (opts.strokeStyle || opts.color) || this.strokeStyle; + ctx.fillStyle = opts.fillStyle || this.fillStyle; + ctx.beginPath(); + if (isarc) { + ctx.arc(points[0], points[1], points[2], points[3], points[4], true); + if (closePath) { + ctx.closePath(); + } + if (fill) { + ctx.fill(); + } + else { + ctx.stroke(); + } + ctx.restore(); + return; + } + else if (clearRect) { + ctx.clearRect(points[0], points[1], points[2], points[3]); + ctx.restore(); + return; + } + else if (fillRect || strokeRect) { + if (fillRect) { + ctx.fillRect(points[0], points[1], points[2], points[3]); + } + if (strokeRect) { + ctx.strokeRect(points[0], points[1], points[2], points[3]); + ctx.restore(); + return; + } + } + else if (points && points.length){ + var move = true; + for (var i=0; i<points.length; i++) { + // skip to the first non-null point and move to it. + if (points[i][0] != null && points[i][1] != null) { + if (move) { + ctxPattern.moveTo(points[i][0], points[i][1]); + move = false; + } + else { + ctxPattern.lineTo(points[i][0], points[i][1]); + } + } + else { + move = true; + } + } + if (closePath) { + ctxPattern.closePath(); + } + if (fill) { + ctx.fill(); + } + else { + ctx.stroke(); + } + } + ctx.restore(); + }; + + // class $.jqplot.TableLegendRenderer + // The default legend renderer for jqPlot. + $.jqplot.TableLegendRenderer = function(){ + // + }; + + $.jqplot.TableLegendRenderer.prototype.init = function(options) { + $.extend(true, this, options); + }; + + $.jqplot.TableLegendRenderer.prototype.addrow = function (label, color, pad, reverse) { + var rs = (pad) ? this.rowSpacing+'px' : '0px'; + var tr; + var td; + var elem; + var div0; + var div1; + elem = document.createElement('tr'); + tr = $(elem); + tr.addClass('jqplot-table-legend'); + elem = null; + + if (reverse){ + tr.prependTo(this._elem); + } + + else{ + tr.appendTo(this._elem); + } + + if (this.showSwatches) { + td = $(document.createElement('td')); + td.addClass('jqplot-table-legend jqplot-table-legend-swatch'); + td.css({textAlign: 'center', paddingTop: rs}); + + div0 = $(document.createElement('div')); + div0.addClass('jqplot-table-legend-swatch-outline'); + div1 = $(document.createElement('div')); + div1.addClass('jqplot-table-legend-swatch'); + div1.css({backgroundColor: color, borderColor: color}); + + tr.append(td.append(div0.append(div1))); + + // $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ + // '<div><div class="jqplot-table-legend-swatch" style="background-color:'+color+';border-color:'+color+';"></div>'+ + // '</div></td>').appendTo(tr); + } + if (this.showLabels) { + td = $(document.createElement('td')); + td.addClass('jqplot-table-legend jqplot-table-legend-label'); + td.css('paddingTop', rs); + tr.append(td); + + // elem = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); + // elem.appendTo(tr); + if (this.escapeHtml) { + td.text(label); + } + else { + td.html(label); + } + } + td = null; + div0 = null; + div1 = null; + tr = null; + elem = null; + }; + + // called with scope of legend + $.jqplot.TableLegendRenderer.prototype.draw = function() { + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + + if (this.show) { + var series = this._series; + // make a table. one line label per row. + var elem = document.createElement('table'); + this._elem = $(elem); + this._elem.addClass('jqplot-table-legend'); + + var ss = {position:'absolute'}; + if (this.background) { + ss['background'] = this.background; + } + if (this.border) { + ss['border'] = this.border; + } + if (this.fontSize) { + ss['fontSize'] = this.fontSize; + } + if (this.fontFamily) { + ss['fontFamily'] = this.fontFamily; + } + if (this.textColor) { + ss['textColor'] = this.textColor; + } + if (this.marginTop != null) { + ss['marginTop'] = this.marginTop; + } + if (this.marginBottom != null) { + ss['marginBottom'] = this.marginBottom; + } + if (this.marginLeft != null) { + ss['marginLeft'] = this.marginLeft; + } + if (this.marginRight != null) { + ss['marginRight'] = this.marginRight; + } + + + var pad = false, + reverse = false, + s; + for (var i = 0; i< series.length; i++) { + s = series[i]; + if (s._stack || s.renderer.constructor == $.jqplot.BezierCurveRenderer){ + reverse = true; + } + if (s.show && s.showLabel) { + var lt = this.labels[i] || s.label.toString(); + if (lt) { + var color = s.color; + if (reverse && i < series.length - 1){ + pad = true; + } + else if (reverse && i == series.length - 1){ + pad = false; + } + this.renderer.addrow.call(this, lt, color, pad, reverse); + pad = true; + } + // let plugins add more rows to legend. Used by trend line plugin. + for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) { + var item = $.jqplot.addLegendRowHooks[j].call(this, s); + if (item) { + this.renderer.addrow.call(this, item.label, item.color, pad); + pad = true; + } + } + lt = null; + } + } + } + return this._elem; + }; + + $.jqplot.TableLegendRenderer.prototype.pack = function(offsets) { + if (this.show) { + if (this.placement == 'insideGrid') { + switch (this.location) { + case 'nw': + var a = offsets.left; + var b = offsets.top; + this._elem.css('left', a); + this._elem.css('top', b); + break; + case 'n': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + var b = offsets.top; + this._elem.css('left', a); + this._elem.css('top', b); + break; + case 'ne': + var a = offsets.right; + var b = offsets.top; + this._elem.css({right:a, top:b}); + break; + case 'e': + var a = offsets.right; + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({right:a, top:b}); + break; + case 'se': + var a = offsets.right; + var b = offsets.bottom; + this._elem.css({right:a, bottom:b}); + break; + case 's': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + var b = offsets.bottom; + this._elem.css({left:a, bottom:b}); + break; + case 'sw': + var a = offsets.left; + var b = offsets.bottom; + this._elem.css({left:a, bottom:b}); + break; + case 'w': + var a = offsets.left; + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({left:a, top:b}); + break; + default: // same as 'se' + var a = offsets.right; + var b = offsets.bottom; + this._elem.css({right:a, bottom:b}); + break; + } + + } + else if (this.placement == 'outside'){ + switch (this.location) { + case 'nw': + var a = this._plotDimensions.width - offsets.left; + var b = offsets.top; + this._elem.css('right', a); + this._elem.css('top', b); + break; + case 'n': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + var b = this._plotDimensions.height - offsets.top; + this._elem.css('left', a); + this._elem.css('bottom', b); + break; + case 'ne': + var a = this._plotDimensions.width - offsets.right; + var b = offsets.top; + this._elem.css({left:a, top:b}); + break; + case 'e': + var a = this._plotDimensions.width - offsets.right; + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({left:a, top:b}); + break; + case 'se': + var a = this._plotDimensions.width - offsets.right; + var b = offsets.bottom; + this._elem.css({left:a, bottom:b}); + break; + case 's': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + var b = this._plotDimensions.height - offsets.bottom; + this._elem.css({left:a, top:b}); + break; + case 'sw': + var a = this._plotDimensions.width - offsets.left; + var b = offsets.bottom; + this._elem.css({right:a, bottom:b}); + break; + case 'w': + var a = this._plotDimensions.width - offsets.left; + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({right:a, top:b}); + break; + default: // same as 'se' + var a = offsets.right; + var b = offsets.bottom; + this._elem.css({right:a, bottom:b}); + break; + } + } + else { + switch (this.location) { + case 'nw': + this._elem.css({left:0, top:offsets.top}); + break; + case 'n': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + this._elem.css({left: a, top:offsets.top}); + break; + case 'ne': + this._elem.css({right:0, top:offsets.top}); + break; + case 'e': + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({right:offsets.right, top:b}); + break; + case 'se': + this._elem.css({right:offsets.right, bottom:offsets.bottom}); + break; + case 's': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + this._elem.css({left: a, bottom:offsets.bottom}); + break; + case 'sw': + this._elem.css({left:offsets.left, bottom:offsets.bottom}); + break; + case 'w': + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({left:offsets.left, top:b}); + break; + default: // same as 'se' + this._elem.css({right:offsets.right, bottom:offsets.bottom}); + break; + } + } + } + }; + + /** + * Class: $.jqplot.ThemeEngine + * Theme Engine provides a programatic way to change some of the more + * common jqplot styling options such as fonts, colors and grid options. + * A theme engine instance is created with each plot. The theme engine + * manages a collection of themes which can be modified, added to, or + * applied to the plot. + * + * The themeEngine class is not instantiated directly. + * When a plot is initialized, the current plot options are scanned + * an a default theme named "Default" is created. This theme is + * used as the basis for other themes added to the theme engine and + * is always available. + * + * A theme is a simple javascript object with styling parameters for + * various entities of the plot. A theme has the form: + * + * + * > { + * > _name:f "Default", + * > target: { + * > backgroundColor: "transparent" + * > }, + * > legend: { + * > textColor: null, + * > fontFamily: null, + * > fontSize: null, + * > border: null, + * > background: null + * > }, + * > title: { + * > textColor: "rgb(102, 102, 102)", + * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif", + * > fontSize: "19.2px", + * > textAlign: "center" + * > }, + * > seriesStyles: {}, + * > series: [{ + * > color: "#4bb2c5", + * > lineWidth: 2.5, + * > linePattern: "solid", + * > shadow: true, + * > fillColor: "#4bb2c5", + * > showMarker: true, + * > markerOptions: { + * > color: "#4bb2c5", + * > show: true, + * > style: 'filledCircle', + * > lineWidth: 1.5, + * > size: 4, + * > shadow: true + * > } + * > }], + * > grid: { + * > drawGridlines: true, + * > gridLineColor: "#cccccc", + * > gridLineWidth: 1, + * > backgroundColor: "#fffdf6", + * > borderColor: "#999999", + * > borderWidth: 2, + * > shadow: true + * > }, + * > axesStyles: { + * > label: {}, + * > ticks: {} + * > }, + * > axes: { + * > xaxis: { + * > borderColor: "#999999", + * > borderWidth: 2, + * > ticks: { + * > show: true, + * > showGridline: true, + * > showLabel: true, + * > showMark: true, + * > size: 4, + * > textColor: "", + * > whiteSpace: "nowrap", + * > fontSize: "12px", + * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif" + * > }, + * > label: { + * > textColor: "rgb(102, 102, 102)", + * > whiteSpace: "normal", + * > fontSize: "14.6667px", + * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif", + * > fontWeight: "400" + * > } + * > }, + * > yaxis: { + * > borderColor: "#999999", + * > borderWidth: 2, + * > ticks: { + * > show: true, + * > showGridline: true, + * > showLabel: true, + * > showMark: true, + * > size: 4, + * > textColor: "", + * > whiteSpace: "nowrap", + * > fontSize: "12px", + * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif" + * > }, + * > label: { + * > textColor: null, + * > whiteSpace: null, + * > fontSize: null, + * > fontFamily: null, + * > fontWeight: null + * > } + * > }, + * > x2axis: {... + * > }, + * > ... + * > y9axis: {... + * > } + * > } + * > } + * + * "seriesStyles" is a style object that will be applied to all series in the plot. + * It will forcibly override any styles applied on the individual series. "axesStyles" is + * a style object that will be applied to all axes in the plot. It will also forcibly + * override any styles on the individual axes. + * + * The example shown above has series options for a line series. Options for other + * series types are shown below: + * + * Bar Series: + * + * > { + * > color: "#4bb2c5", + * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"], + * > lineWidth: 2.5, + * > shadow: true, + * > barPadding: 2, + * > barMargin: 10, + * > barWidth: 15.09375, + * > highlightColors: ["rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)"] + * > } + * + * Pie Series: + * + * > { + * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"], + * > padding: 20, + * > sliceMargin: 0, + * > fill: true, + * > shadow: true, + * > startAngle: 0, + * > lineWidth: 2.5, + * > highlightColors: ["rgb(129,201,214)", "rgb(240,189,104)", "rgb(214,202,165)", "rgb(137,180,158)", "rgb(168,180,137)", "rgb(180,174,89)", "rgb(180,113,161)", "rgb(129,141,236)", "rgb(227,205,120)", "rgb(255,138,76)", "rgb(76,169,219)", "rgb(215,126,190)", "rgb(220,232,135)", "rgb(200,167,96)", "rgb(103,202,235)", "rgb(208,154,215)"] + * > } + * + * Funnel Series: + * + * > { + * > color: "#4bb2c5", + * > lineWidth: 2, + * > shadow: true, + * > padding: { + * > top: 20, + * > right: 20, + * > bottom: 20, + * > left: 20 + * > }, + * > sectionMargin: 6, + * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"], + * > highlightColors: ["rgb(147,208,220)", "rgb(242,199,126)", "rgb(220,210,178)", "rgb(154,191,172)", "rgb(180,191,154)", "rgb(191,186,112)", "rgb(191,133,174)", "rgb(147,157,238)", "rgb(231,212,139)", "rgb(255,154,102)", "rgb(102,181,224)", "rgb(221,144,199)", "rgb(225,235,152)", "rgb(200,167,96)", "rgb(124,210,238)", "rgb(215,169,221)"] + * > } + * + */ + $.jqplot.ThemeEngine = function(){ + // Group: Properties + // + // prop: themes + // hash of themes managed by the theme engine. + // Indexed by theme name. + this.themes = {}; + // prop: activeTheme + // Pointer to currently active theme + this.activeTheme=null; + + }; + + // called with scope of plot + $.jqplot.ThemeEngine.prototype.init = function() { + // get the Default theme from the current plot settings. + var th = new $.jqplot.Theme({_name:'Default'}); + var n, i, nn; + + for (n in th.target) { + if (n == "textColor") { + th.target[n] = this.target.css('color'); + } + else { + th.target[n] = this.target.css(n); + } + } + + if (this.title.show && this.title._elem) { + for (n in th.title) { + if (n == "textColor") { + th.title[n] = this.title._elem.css('color'); + } + else { + th.title[n] = this.title._elem.css(n); + } + } + } + + for (n in th.grid) { + th.grid[n] = this.grid[n]; + } + if (th.grid.backgroundColor == null && this.grid.background != null) { + th.grid.backgroundColor = this.grid.background; + } + if (this.legend.show && this.legend._elem) { + for (n in th.legend) { + if (n == 'textColor') { + th.legend[n] = this.legend._elem.css('color'); + } + else { + th.legend[n] = this.legend._elem.css(n); + } + } + } + var s; + + for (i=0; i<this.series.length; i++) { + s = this.series[i]; + if (s.renderer.constructor == $.jqplot.LineRenderer) { + th.series.push(new LineSeriesProperties()); + } + else if (s.renderer.constructor == $.jqplot.BarRenderer) { + th.series.push(new BarSeriesProperties()); + } + else if (s.renderer.constructor == $.jqplot.PieRenderer) { + th.series.push(new PieSeriesProperties()); + } + else if (s.renderer.constructor == $.jqplot.DonutRenderer) { + th.series.push(new DonutSeriesProperties()); + } + else if (s.renderer.constructor == $.jqplot.FunnelRenderer) { + th.series.push(new FunnelSeriesProperties()); + } + else if (s.renderer.constructor == $.jqplot.MeterGaugeRenderer) { + th.series.push(new MeterSeriesProperties()); + } + else { + th.series.push({}); + } + for (n in th.series[i]) { + th.series[i][n] = s[n]; + } + } + var a, ax; + for (n in this.axes) { + ax = this.axes[n]; + a = th.axes[n] = new AxisProperties(); + a.borderColor = ax.borderColor; + a.borderWidth = ax.borderWidth; + if (ax._ticks && ax._ticks[0]) { + for (nn in a.ticks) { + if (ax._ticks[0].hasOwnProperty(nn)) { + a.ticks[nn] = ax._ticks[0][nn]; + } + else if (ax._ticks[0]._elem){ + a.ticks[nn] = ax._ticks[0]._elem.css(nn); + } + } + } + if (ax._label && ax._label.show) { + for (nn in a.label) { + // a.label[nn] = ax._label._elem.css(nn); + if (ax._label[nn]) { + a.label[nn] = ax._label[nn]; + } + else if (ax._label._elem){ + if (nn == 'textColor') { + a.label[nn] = ax._label._elem.css('color'); + } + else { + a.label[nn] = ax._label._elem.css(nn); + } + } + } + } + } + this.themeEngine._add(th); + this.themeEngine.activeTheme = this.themeEngine.themes[th._name]; + }; + /** + * Group: methods + * + * method: get + * + * Get and return the named theme or the active theme if no name given. + * + * parameter: + * + * name - name of theme to get. + * + * returns: + * + * Theme instance of given name. + */ + $.jqplot.ThemeEngine.prototype.get = function(name) { + if (!name) { + // return the active theme + return this.activeTheme; + } + else { + return this.themes[name]; + } + }; + + function numericalOrder(a,b) { return a-b; } + + /** + * method: getThemeNames + * + * Return the list of theme names in this manager in alpha-numerical order. + * + * parameter: + * + * None + * + * returns: + * + * A the list of theme names in this manager in alpha-numerical order. + */ + $.jqplot.ThemeEngine.prototype.getThemeNames = function() { + var tn = []; + for (var n in this.themes) { + tn.push(n); + } + return tn.sort(numericalOrder); + }; + + /** + * method: getThemes + * + * Return a list of themes in alpha-numerical order by name. + * + * parameter: + * + * None + * + * returns: + * + * A list of themes in alpha-numerical order by name. + */ + $.jqplot.ThemeEngine.prototype.getThemes = function() { + var tn = []; + var themes = []; + for (var n in this.themes) { + tn.push(n); + } + tn.sort(numericalOrder); + for (var i=0; i<tn.length; i++) { + themes.push(this.themes[tn[i]]); + } + return themes; + }; + + $.jqplot.ThemeEngine.prototype.activate = function(plot, name) { + // sometimes need to redraw whole plot. + var redrawPlot = false; + if (!name && this.activeTheme && this.activeTheme._name) { + name = this.activeTheme._name; + } + if (!this.themes.hasOwnProperty(name)) { + throw new Error("No theme of that name"); + } + else { + var th = this.themes[name]; + this.activeTheme = th; + var val, checkBorderColor = false, checkBorderWidth = false; + var arr = ['xaxis', 'x2axis', 'yaxis', 'y2axis']; + + for (i=0; i<arr.length; i++) { + var ax = arr[i]; + if (th.axesStyles.borderColor != null) { + plot.axes[ax].borderColor = th.axesStyles.borderColor; + } + if (th.axesStyles.borderWidth != null) { + plot.axes[ax].borderWidth = th.axesStyles.borderWidth; + } + } + + for (var axname in plot.axes) { + var axis = plot.axes[axname]; + if (axis.show) { + var thaxis = th.axes[axname] || {}; + var thaxstyle = th.axesStyles; + var thax = $.jqplot.extend(true, {}, thaxis, thaxstyle); + val = (th.axesStyles.borderColor != null) ? th.axesStyles.borderColor : thax.borderColor; + if (thax.borderColor != null) { + axis.borderColor = thax.borderColor; + redrawPlot = true; + } + val = (th.axesStyles.borderWidth != null) ? th.axesStyles.borderWidth : thax.borderWidth; + if (thax.borderWidth != null) { + axis.borderWidth = thax.borderWidth; + redrawPlot = true; + } + if (axis._ticks && axis._ticks[0]) { + for (var nn in thax.ticks) { + // val = null; + // if (th.axesStyles.ticks && th.axesStyles.ticks[nn] != null) { + // val = th.axesStyles.ticks[nn]; + // } + // else if (thax.ticks[nn] != null){ + // val = thax.ticks[nn] + // } + val = thax.ticks[nn]; + if (val != null) { + axis.tickOptions[nn] = val; + axis._ticks = []; + redrawPlot = true; + } + } + } + if (axis._label && axis._label.show) { + for (var nn in thax.label) { + // val = null; + // if (th.axesStyles.label && th.axesStyles.label[nn] != null) { + // val = th.axesStyles.label[nn]; + // } + // else if (thax.label && thax.label[nn] != null){ + // val = thax.label[nn] + // } + val = thax.label[nn]; + if (val != null) { + axis.labelOptions[nn] = val; + redrawPlot = true; + } + } + } + + } + } + + for (var n in th.grid) { + if (th.grid[n] != null) { + plot.grid[n] = th.grid[n]; + } + } + if (!redrawPlot) { + plot.grid.draw(); + } + + if (plot.legend.show) { + for (n in th.legend) { + if (th.legend[n] != null) { + plot.legend[n] = th.legend[n]; + } + } + } + if (plot.title.show) { + for (n in th.title) { + if (th.title[n] != null) { + plot.title[n] = th.title[n]; + } + } + } + + var i; + for (i=0; i<th.series.length; i++) { + var opts = {}; + var redrawSeries = false; + for (n in th.series[i]) { + val = (th.seriesStyles[n] != null) ? th.seriesStyles[n] : th.series[i][n]; + if (val != null) { + opts[n] = val; + if (n == 'color') { + plot.series[i].renderer.shapeRenderer.fillStyle = val; + plot.series[i].renderer.shapeRenderer.strokeStyle = val; + plot.series[i][n] = val; + } + else if ((n == 'lineWidth') || (n == 'linePattern')) { + plot.series[i].renderer.shapeRenderer[n] = val; + plot.series[i][n] = val; + } + else if (n == 'markerOptions') { + merge (plot.series[i].markerOptions, val); + merge (plot.series[i].markerRenderer, val); + } + else { + plot.series[i][n] = val; + } + redrawPlot = true; + } + } + } + + if (redrawPlot) { + plot.target.empty(); + plot.draw(); + } + + for (n in th.target) { + if (th.target[n] != null) { + plot.target.css(n, th.target[n]); + } + } + } + + }; + + $.jqplot.ThemeEngine.prototype._add = function(theme, name) { + if (name) { + theme._name = name; + } + if (!theme._name) { + theme._name = Date.parse(new Date()); + } + if (!this.themes.hasOwnProperty(theme._name)) { + this.themes[theme._name] = theme; + } + else { + throw new Error("jqplot.ThemeEngine Error: Theme already in use"); + } + }; + + // method remove + // Delete the named theme, return true on success, false on failure. + + + /** + * method: remove + * + * Remove the given theme from the themeEngine. + * + * parameters: + * + * name - name of the theme to remove. + * + * returns: + * + * true on success, false on failure. + */ + $.jqplot.ThemeEngine.prototype.remove = function(name) { + if (name == 'Default') { + return false; + } + return delete this.themes[name]; + }; + + /** + * method: newTheme + * + * Create a new theme based on the default theme, adding it the themeEngine. + * + * parameters: + * + * name - name of the new theme. + * obj - optional object of styles to be applied to this new theme. + * + * returns: + * + * new Theme object. + */ + $.jqplot.ThemeEngine.prototype.newTheme = function(name, obj) { + if (typeof(name) == 'object') { + obj = obj || name; + name = null; + } + if (obj && obj._name) { + name = obj._name; + } + else { + name = name || Date.parse(new Date()); + } + // var th = new $.jqplot.Theme(name); + var th = this.copy(this.themes['Default']._name, name); + $.jqplot.extend(th, obj); + return th; + }; + + // function clone(obj) { + // return eval(obj.toSource()); + // } + + function clone(obj){ + if(obj == null || typeof(obj) != 'object'){ + return obj; + } + + var temp = new obj.constructor(); + for(var key in obj){ + temp[key] = clone(obj[key]); + } + return temp; + } + + $.jqplot.clone = clone; + + function merge(obj1, obj2) { + if (obj2 == null || typeof(obj2) != 'object') { + return; + } + for (var key in obj2) { + if (key == 'highlightColors') { + obj1[key] = clone(obj2[key]); + } + if (obj2[key] != null && typeof(obj2[key]) == 'object') { + if (!obj1.hasOwnProperty(key)) { + obj1[key] = {}; + } + merge(obj1[key], obj2[key]); + } + else { + obj1[key] = obj2[key]; + } + } + } + + $.jqplot.merge = merge; + + // Use the jQuery 1.3.2 extend function since behaviour in jQuery 1.4 seems problematic + $.jqplot.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !toString.call(target) === "[object Function]" ) { + target = {}; + } + + for ( ; i < length; i++ ){ + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( var name in options ) { + var src = target[ name ], copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging object values + if ( deep && copy && typeof copy === "object" && !copy.nodeType ) { + target[ name ] = $.jqplot.extend( deep, + // Never move original objects, clone them + src || ( copy.length != null ? [ ] : { } ) + , copy ); + } + // Don't bring in undefined values + else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + // Return the modified object + return target; + }; + + /** + * method: rename + * + * Rename a theme. + * + * parameters: + * + * oldName - current name of the theme. + * newName - desired name of the theme. + * + * returns: + * + * new Theme object. + */ + $.jqplot.ThemeEngine.prototype.rename = function (oldName, newName) { + if (oldName == 'Default' || newName == 'Default') { + throw new Error ("jqplot.ThemeEngine Error: Cannot rename from/to Default"); + } + if (this.themes.hasOwnProperty(newName)) { + throw new Error ("jqplot.ThemeEngine Error: New name already in use."); + } + else if (this.themes.hasOwnProperty(oldName)) { + var th = this.copy (oldName, newName); + this.remove(oldName); + return th; + } + throw new Error("jqplot.ThemeEngine Error: Old name or new name invalid"); + }; + + /** + * method: copy + * + * Create a copy of an existing theme in the themeEngine, adding it the themeEngine. + * + * parameters: + * + * sourceName - name of the existing theme. + * targetName - name of the copy. + * obj - optional object of style parameter to apply to the new theme. + * + * returns: + * + * new Theme object. + */ + $.jqplot.ThemeEngine.prototype.copy = function (sourceName, targetName, obj) { + if (targetName == 'Default') { + throw new Error ("jqplot.ThemeEngine Error: Cannot copy over Default theme"); + } + if (!this.themes.hasOwnProperty(sourceName)) { + var s = "jqplot.ThemeEngine Error: Source name invalid"; + throw new Error(s); + } + if (this.themes.hasOwnProperty(targetName)) { + var s = "jqplot.ThemeEngine Error: Target name invalid"; + throw new Error(s); + } + else { + var th = clone(this.themes[sourceName]); + th._name = targetName; + $.jqplot.extend(true, th, obj); + this._add(th); + return th; + } + }; + + + $.jqplot.Theme = function(name, obj) { + if (typeof(name) == 'object') { + obj = obj || name; + name = null; + } + name = name || Date.parse(new Date()); + this._name = name; + this.target = { + backgroundColor: null + }; + this.legend = { + textColor: null, + fontFamily: null, + fontSize: null, + border: null, + background: null + }; + this.title = { + textColor: null, + fontFamily: null, + fontSize: null, + textAlign: null + }; + this.seriesStyles = {}; + this.series = []; + this.grid = { + drawGridlines: null, + gridLineColor: null, + gridLineWidth: null, + backgroundColor: null, + borderColor: null, + borderWidth: null, + shadow: null + }; + this.axesStyles = {label:{}, ticks:{}}; + this.axes = {}; + if (typeof(obj) == 'string') { + this._name = obj; + } + else if(typeof(obj) == 'object') { + $.jqplot.extend(true, this, obj); + } + }; + + var AxisProperties = function() { + this.borderColor = null; + this.borderWidth = null; + this.ticks = new AxisTicks(); + this.label = new AxisLabel(); + }; + + var AxisTicks = function() { + this.show = null; + this.showGridline = null; + this.showLabel = null; + this.showMark = null; + this.size = null; + this.textColor = null; + this.whiteSpace = null; + this.fontSize = null; + this.fontFamily = null; + }; + + var AxisLabel = function() { + this.textColor = null; + this.whiteSpace = null; + this.fontSize = null; + this.fontFamily = null; + this.fontWeight = null; + }; + + var LineSeriesProperties = function() { + this.color=null; + this.lineWidth=null; + this.linePattern=null; + this.shadow=null; + this.fillColor=null; + this.showMarker=null; + this.markerOptions = new MarkerOptions(); + }; + + var MarkerOptions = function() { + this.show = null; + this.style = null; + this.lineWidth = null; + this.size = null; + this.color = null; + this.shadow = null; + }; + + var BarSeriesProperties = function() { + this.color=null; + this.seriesColors=null; + this.lineWidth=null; + this.shadow=null; + this.barPadding=null; + this.barMargin=null; + this.barWidth=null; + this.highlightColors=null; + }; + + var PieSeriesProperties = function() { + this.seriesColors=null; + this.padding=null; + this.sliceMargin=null; + this.fill=null; + this.shadow=null; + this.startAngle=null; + this.lineWidth=null; + this.highlightColors=null; + }; + + var DonutSeriesProperties = function() { + this.seriesColors=null; + this.padding=null; + this.sliceMargin=null; + this.fill=null; + this.shadow=null; + this.startAngle=null; + this.lineWidth=null; + this.innerDiameter=null; + this.thickness=null; + this.ringMargin=null; + this.highlightColors=null; + }; + + var FunnelSeriesProperties = function() { + this.color=null; + this.lineWidth=null; + this.shadow=null; + this.padding=null; + this.sectionMargin=null; + this.seriesColors=null; + this.highlightColors=null; + }; + + var MeterSeriesProperties = function() { + this.padding=null; + this.backgroundColor=null; + this.ringColor=null; + this.tickColor=null; + this.ringWidth=null; + this.intervalColors=null; + this.intervalInnerRadius=null; + this.intervalOuterRadius=null; + this.hubRadius=null; + this.needleThickness=null; + this.needlePad=null; + }; + + + + + $.fn.jqplotChildText = function() { + return $(this).contents().filter(function() { + return this.nodeType == 3; // Node.TEXT_NODE not defined in I7 + }).text(); + }; + + // Returns font style as abbreviation for "font" property. + $.fn.jqplotGetComputedFontStyle = function() { + var css = window.getComputedStyle ? window.getComputedStyle(this[0], "") : this[0].currentStyle; + var attrs = css['font-style'] ? ['font-style', 'font-weight', 'font-size', 'font-family'] : ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily']; + var style = []; + + for (var i=0 ; i < attrs.length; ++i) { + var attr = String(css[attrs[i]]); + + if (attr && attr != 'normal') { + style.push(attr); + } + } + return style.join(' '); + }; + + /** + * Namespace: $.fn + * jQuery namespace to attach functions to jQuery elements. + * + */ + + $.fn.jqplotToImageCanvas = function(options) { + + options = options || {}; + var x_offset = (options.x_offset == null) ? 0 : options.x_offset; + var y_offset = (options.y_offset == null) ? 0 : options.y_offset; + var backgroundColor = (options.backgroundColor == null) ? 'rgb(255,255,255)' : options.backgroundColor; + + if ($(this).width() == 0 || $(this).height() == 0) { + return null; + } + + // excanvas and hence IE < 9 do not support toDataURL and cannot export images. + if ($.jqplot.use_excanvas) { + return null; + } + + var newCanvas = document.createElement("canvas"); + var h = $(this).outerHeight(true); + var w = $(this).outerWidth(true); + var offs = $(this).offset(); + var plotleft = offs.left; + var plottop = offs.top; + var transx = 0, transy = 0; + + // have to check if any elements are hanging outside of plot area before rendering, + // since changing width of canvas will erase canvas. + + var clses = ['jqplot-table-legend', 'jqplot-xaxis-tick', 'jqplot-x2axis-tick', 'jqplot-yaxis-tick', 'jqplot-y2axis-tick', 'jqplot-y3axis-tick', + 'jqplot-y4axis-tick', 'jqplot-y5axis-tick', 'jqplot-y6axis-tick', 'jqplot-y7axis-tick', 'jqplot-y8axis-tick', 'jqplot-y9axis-tick', + 'jqplot-xaxis-label', 'jqplot-x2axis-label', 'jqplot-yaxis-label', 'jqplot-y2axis-label', 'jqplot-y3axis-label', 'jqplot-y4axis-label', + 'jqplot-y5axis-label', 'jqplot-y6axis-label', 'jqplot-y7axis-label', 'jqplot-y8axis-label', 'jqplot-y9axis-label' ]; + + var temptop, templeft, tempbottom, tempright; + + for (var i = 0; i < clses.length; i++) { + $(this).find('.'+clses[i]).each(function() { + temptop = $(this).offset().top - plottop; + templeft = $(this).offset().left - plotleft; + tempright = templeft + $(this).outerWidth(true) + transx; + tempbottom = temptop + $(this).outerHeight(true) + transy; + if (templeft < -transx) { + w = w - transx - templeft; + transx = -templeft; + } + if (temptop < -transy) { + h = h - transy - temptop; + transy = - temptop; + } + if (tempright > w) { + w = tempright; + } + if (tempbottom > h) { + h = tempbottom; + } + }); + } + + newCanvas.width = w + Number(x_offset); + newCanvas.height = h + Number(y_offset); + + var newContext = newCanvas.getContext("2d"); + + newContext.save(); + newContext.fillStyle = backgroundColor; + newContext.fillRect(0,0, newCanvas.width, newCanvas.height); + newContext.restore(); + + newContext.translate(transx, transy); + newContext.textAlign = 'left'; + newContext.textBaseline = 'top'; + + function getLineheight(el) { + var lineheight = parseInt($(el).css('line-height'), 10); + + if (isNaN(lineheight)) { + lineheight = parseInt($(el).css('font-size'), 10) * 1.2; + } + return lineheight; + } + + function writeWrappedText (el, context, text, left, top, canvasWidth) { + var lineheight = getLineheight(el); + var tagwidth = $(el).innerWidth(); + var tagheight = $(el).innerHeight(); + var words = text.split(/\s+/); + var wl = words.length; + var w = ''; + var breaks = []; + var temptop = top; + var templeft = left; + + for (var i=0; i<wl; i++) { + w += words[i]; + if (context.measureText(w).width > tagwidth) { + breaks.push(i); + w = ''; + i--; + } + } + if (breaks.length === 0) { + // center text if necessary + if ($(el).css('textAlign') === 'center') { + templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx; + } + context.fillText(text, templeft, top); + } + else { + w = words.slice(0, breaks[0]).join(' '); + // center text if necessary + if ($(el).css('textAlign') === 'center') { + templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx; + } + context.fillText(w, templeft, temptop); + temptop += lineheight; + for (var i=1, l=breaks.length; i<l; i++) { + w = words.slice(breaks[i-1], breaks[i]).join(' '); + // center text if necessary + if ($(el).css('textAlign') === 'center') { + templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx; + } + context.fillText(w, templeft, temptop); + temptop += lineheight; + } + w = words.slice(breaks[i-1], words.length).join(' '); + // center text if necessary + if ($(el).css('textAlign') === 'center') { + templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx; + } + context.fillText(w, templeft, temptop); + } + + } + + function _jqpToImage(el, x_offset, y_offset) { + var tagname = el.tagName.toLowerCase(); + var p = $(el).position(); + var css = window.getComputedStyle ? window.getComputedStyle(el, "") : el.currentStyle; // for IE < 9 + var left = x_offset + p.left + parseInt(css.marginLeft, 10) + parseInt(css.borderLeftWidth, 10) + parseInt(css.paddingLeft, 10); + var top = y_offset + p.top + parseInt(css.marginTop, 10) + parseInt(css.borderTopWidth, 10)+ parseInt(css.paddingTop, 10); + var w = newCanvas.width; + // var left = x_offset + p.left + $(el).css('marginLeft') + $(el).css('borderLeftWidth') + + // somehow in here, for divs within divs, the width of the inner div should be used instead of the canvas. + + if ((tagname == 'div' || tagname == 'span') && !$(el).hasClass('jqplot-highlighter-tooltip')) { + $(el).children().each(function() { + _jqpToImage(this, left, top); + }); + var text = $(el).jqplotChildText(); + + if (text) { + newContext.font = $(el).jqplotGetComputedFontStyle(); + newContext.fillStyle = $(el).css('color'); + + writeWrappedText(el, newContext, text, left, top, w); + } + } + + // handle the standard table legend + + else if (tagname === 'table' && $(el).hasClass('jqplot-table-legend')) { + newContext.strokeStyle = $(el).css('border-top-color'); + newContext.fillStyle = $(el).css('background-color'); + newContext.fillRect(left, top, $(el).innerWidth(), $(el).innerHeight()); + if (parseInt($(el).css('border-top-width'), 10) > 0) { + newContext.strokeRect(left, top, $(el).innerWidth(), $(el).innerHeight()); + } + + // find all the swatches + $(el).find('div.jqplot-table-legend-swatch-outline').each(function() { + // get the first div and stroke it + var elem = $(this); + newContext.strokeStyle = elem.css('border-top-color'); + var l = left + elem.position().left; + var t = top + elem.position().top; + newContext.strokeRect(l, t, elem.innerWidth(), elem.innerHeight()); + + // now fill the swatch + + l += parseInt(elem.css('padding-left'), 10); + t += parseInt(elem.css('padding-top'), 10); + var h = elem.innerHeight() - 2 * parseInt(elem.css('padding-top'), 10); + var w = elem.innerWidth() - 2 * parseInt(elem.css('padding-left'), 10); + + var swatch = elem.children('div.jqplot-table-legend-swatch'); + newContext.fillStyle = swatch.css('background-color'); + newContext.fillRect(l, t, w, h); + }); + + // now add text + + $(el).find('td.jqplot-table-legend-label').each(function(){ + var elem = $(this); + var l = left + elem.position().left; + var t = top + elem.position().top + parseInt(elem.css('padding-top'), 10); + newContext.font = elem.jqplotGetComputedFontStyle(); + newContext.fillStyle = elem.css('color'); + writeWrappedText(elem, newContext, elem.text(), l, t, w); + }); + + var elem = null; + } + + else if (tagname == 'canvas') { + newContext.drawImage(el, left, top); + } + } + $(this).children().each(function() { + _jqpToImage(this, x_offset, y_offset); + }); + return newCanvas; + }; + + // return the raw image data string. + // Should work on canvas supporting browsers. + $.fn.jqplotToImageStr = function(options) { + var imgCanvas = $(this).jqplotToImageCanvas(options); + if (imgCanvas) { + return imgCanvas.toDataURL("image/png"); + } + else { + return null; + } + }; + + // return a DOM <img> element and return it. + // Should work on canvas supporting browsers. + $.fn.jqplotToImageElem = function(options) { + var elem = document.createElement("img"); + var str = $(this).jqplotToImageStr(options); + elem.src = str; + return elem; + }; + + // return a string for an <img> element and return it. + // Should work on canvas supporting browsers. + $.fn.jqplotToImageElemStr = function(options) { + var str = '<img src='+$(this).jqplotToImageStr(options)+' />'; + return str; + }; + + // Not guaranteed to work, even on canvas supporting browsers due to + // limitations with location.href and browser support. + $.fn.jqplotSaveImage = function() { + var imgData = $(this).jqplotToImageStr({}); + if (imgData) { + window.location.href = imgData.replace("image/png", "image/octet-stream"); + } + + }; + + // Not guaranteed to work, even on canvas supporting browsers due to + // limitations with window.open and arbitrary data. + $.fn.jqplotViewImage = function() { + var imgStr = $(this).jqplotToImageElemStr({}); + var imgData = $(this).jqplotToImageStr({}); + if (imgStr) { + var w = window.open(''); + w.document.open("image/png"); + w.document.write(imgStr); + w.document.close(); + w = null; + } + }; + + + + + /** + * @description + * <p>Object with extended date parsing and formatting capabilities. + * This library borrows many concepts and ideas from the Date Instance + * Methods by Ken Snyder along with some parts of Ken's actual code.</p> + * + * <p>jsDate takes a different approach by not extending the built-in + * Date Object, improving date parsing, allowing for multiple formatting + * syntaxes and multiple and more easily expandable localization.</p> + * + * @author Chris Leonello + * @date #date# + * @version #VERSION# + * @copyright (c) 2010-2013 Chris Leonello + * jsDate is currently available for use in all personal or commercial projects + * under both the MIT and GPL version 2.0 licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * <p>Ken's original Date Instance Methods and copyright notice:</p> + * <pre> + * Ken Snyder (ken d snyder at gmail dot com) + * 2008-09-10 + * version 2.0.2 (http://kendsnyder.com/sandbox/date/) + * Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/) + * </pre> + * + * @class + * @name jsDate + * @param {String | Number | Array | Date Object | Options Object} arguments Optional arguments, either a parsable date/time string, + * a JavaScript timestamp, an array of numbers of form [year, month, day, hours, minutes, seconds, milliseconds], + * a Date object, or an options object of form {syntax: "perl", date:some Date} where all options are optional. + */ + + var jsDate = function () { + + this.syntax = jsDate.config.syntax; + this._type = "jsDate"; + this.proxy = new Date(); + this.options = {}; + this.locale = jsDate.regional.getLocale(); + this.formatString = ''; + this.defaultCentury = jsDate.config.defaultCentury; + + switch ( arguments.length ) { + case 0: + break; + case 1: + // other objects either won't have a _type property or, + // if they do, it shouldn't be set to "jsDate", so + // assume it is an options argument. + if (get_type(arguments[0]) == "[object Object]" && arguments[0]._type != "jsDate") { + var opts = this.options = arguments[0]; + this.syntax = opts.syntax || this.syntax; + this.defaultCentury = opts.defaultCentury || this.defaultCentury; + this.proxy = jsDate.createDate(opts.date); + } + else { + this.proxy = jsDate.createDate(arguments[0]); + } + break; + default: + var a = []; + for ( var i=0; i<arguments.length; i++ ) { + a.push(arguments[i]); + } + // this should be the current date/time? + this.proxy = new Date(); + this.proxy.setFullYear.apply( this.proxy, a.slice(0,3) ); + if ( a.slice(3).length ) { + this.proxy.setHours.apply( this.proxy, a.slice(3) ); + } + break; + } + }; + + /** + * @namespace Configuration options that will be used as defaults for all instances on the page. + * @property {String} defaultLocale The default locale to use [en]. + * @property {String} syntax The default syntax to use [perl]. + * @property {Number} defaultCentury The default centry for 2 digit dates. + */ + jsDate.config = { + defaultLocale: 'en', + syntax: 'perl', + defaultCentury: 1900 + }; + + /** + * Add an arbitrary amount to the currently stored date + * + * @param {Number} number + * @param {String} unit + * @returns {jsDate} + */ + + jsDate.prototype.add = function(number, unit) { + var factor = multipliers[unit] || multipliers.day; + if (typeof factor == 'number') { + this.proxy.setTime(this.proxy.getTime() + (factor * number)); + } else { + factor.add(this, number); + } + return this; + }; + + /** + * Create a new jqplot.date object with the same date + * + * @returns {jsDate} + */ + + jsDate.prototype.clone = function() { + return new jsDate(this.proxy.getTime()); + }; + + /** + * Get the UTC TimeZone Offset of this date in milliseconds. + * + * @returns {Number} + */ + + jsDate.prototype.getUtcOffset = function() { + return this.proxy.getTimezoneOffset() * 60000; + }; + + /** + * Find the difference between this jsDate and another date. + * + * @param {String| Number| Array| jsDate Object| Date Object} dateObj + * @param {String} unit + * @param {Boolean} allowDecimal + * @returns {Number} Number of units difference between dates. + */ + + jsDate.prototype.diff = function(dateObj, unit, allowDecimal) { + // ensure we have a Date object + dateObj = new jsDate(dateObj); + if (dateObj === null) { + return null; + } + // get the multiplying factor integer or factor function + var factor = multipliers[unit] || multipliers.day; + if (typeof factor == 'number') { + // multiply + var unitDiff = (this.proxy.getTime() - dateObj.proxy.getTime()) / factor; + } else { + // run function + var unitDiff = factor.diff(this.proxy, dateObj.proxy); + } + // if decimals are not allowed, round toward zero + return (allowDecimal ? unitDiff : Math[unitDiff > 0 ? 'floor' : 'ceil'](unitDiff)); + }; + + /** + * Get the abbreviated name of the current week day + * + * @returns {String} + */ + + jsDate.prototype.getAbbrDayName = function() { + return jsDate.regional[this.locale]["dayNamesShort"][this.proxy.getDay()]; + }; + + /** + * Get the abbreviated name of the current month + * + * @returns {String} + */ + + jsDate.prototype.getAbbrMonthName = function() { + return jsDate.regional[this.locale]["monthNamesShort"][this.proxy.getMonth()]; + }; + + /** + * Get UPPER CASE AM or PM for the current time + * + * @returns {String} + */ + + jsDate.prototype.getAMPM = function() { + return this.proxy.getHours() >= 12 ? 'PM' : 'AM'; + }; + + /** + * Get lower case am or pm for the current time + * + * @returns {String} + */ + + jsDate.prototype.getAmPm = function() { + return this.proxy.getHours() >= 12 ? 'pm' : 'am'; + }; + + /** + * Get the century (19 for 20th Century) + * + * @returns {Integer} Century (19 for 20th century). + */ + jsDate.prototype.getCentury = function() { + return parseInt(this.proxy.getFullYear()/100, 10); + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getDate = function() { + return this.proxy.getDate(); + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getDay = function() { + return this.proxy.getDay(); + }; + + /** + * Get the Day of week 1 (Monday) thru 7 (Sunday) + * + * @returns {Integer} Day of week 1 (Monday) thru 7 (Sunday) + */ + jsDate.prototype.getDayOfWeek = function() { + var dow = this.proxy.getDay(); + return dow===0?7:dow; + }; + + /** + * Get the day of the year + * + * @returns {Integer} 1 - 366, day of the year + */ + jsDate.prototype.getDayOfYear = function() { + var d = this.proxy; + var ms = d - new Date('' + d.getFullYear() + '/1/1 GMT'); + ms += d.getTimezoneOffset()*60000; + d = null; + return parseInt(ms/60000/60/24, 10)+1; + }; + + /** + * Get the name of the current week day + * + * @returns {String} + */ + + jsDate.prototype.getDayName = function() { + return jsDate.regional[this.locale]["dayNames"][this.proxy.getDay()]; + }; + + /** + * Get the week number of the given year, starting with the first Sunday as the first week + * @returns {Integer} Week number (13 for the 13th full week of the year). + */ + jsDate.prototype.getFullWeekOfYear = function() { + var d = this.proxy; + var doy = this.getDayOfYear(); + var rdow = 6-d.getDay(); + var woy = parseInt((doy+rdow)/7, 10); + return woy; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getFullYear = function() { + return this.proxy.getFullYear(); + }; + + /** + * Get the GMT offset in hours and minutes (e.g. +06:30) + * + * @returns {String} + */ + + jsDate.prototype.getGmtOffset = function() { + // divide the minutes offset by 60 + var hours = this.proxy.getTimezoneOffset() / 60; + // decide if we are ahead of or behind GMT + var prefix = hours < 0 ? '+' : '-'; + // remove the negative sign if any + hours = Math.abs(hours); + // add the +/- to the padded number of hours to : to the padded minutes + return prefix + addZeros(Math.floor(hours), 2) + ':' + addZeros((hours % 1) * 60, 2); + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getHours = function() { + return this.proxy.getHours(); + }; + + /** + * Get the current hour on a 12-hour scheme + * + * @returns {Integer} + */ + + jsDate.prototype.getHours12 = function() { + var hours = this.proxy.getHours(); + return hours > 12 ? hours - 12 : (hours == 0 ? 12 : hours); + }; + + + jsDate.prototype.getIsoWeek = function() { + var d = this.proxy; + var woy = this.getWeekOfYear(); + var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay(); + // First week is 01 and not 00 as in the case of %U and %W, + // so we add 1 to the final result except if day 1 of the year + // is a Monday (then %W returns 01). + // We also need to subtract 1 if the day 1 of the year is + // Friday-Sunday, so the resulting equation becomes: + var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1); + if(idow == 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4) + { + idow = 1; + } + else if(idow === 0) + { + d = new jsDate(new Date('' + (d.getFullYear()-1) + '/12/31')); + idow = d.getIsoWeek(); + } + d = null; + return idow; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getMilliseconds = function() { + return this.proxy.getMilliseconds(); + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getMinutes = function() { + return this.proxy.getMinutes(); + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getMonth = function() { + return this.proxy.getMonth(); + }; + + /** + * Get the name of the current month + * + * @returns {String} + */ + + jsDate.prototype.getMonthName = function() { + return jsDate.regional[this.locale]["monthNames"][this.proxy.getMonth()]; + }; + + /** + * Get the number of the current month, 1-12 + * + * @returns {Integer} + */ + + jsDate.prototype.getMonthNumber = function() { + return this.proxy.getMonth() + 1; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getSeconds = function() { + return this.proxy.getSeconds(); + }; + + /** + * Return a proper two-digit year integer + * + * @returns {Integer} + */ + + jsDate.prototype.getShortYear = function() { + return this.proxy.getYear() % 100; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getTime = function() { + return this.proxy.getTime(); + }; + + /** + * Get the timezone abbreviation + * + * @returns {String} Abbreviation for the timezone + */ + jsDate.prototype.getTimezoneAbbr = function() { + return this.proxy.toString().replace(/^.*\(([^)]+)\)$/, '$1'); + }; + + /** + * Get the browser-reported name for the current timezone (e.g. MDT, Mountain Daylight Time) + * + * @returns {String} + */ + jsDate.prototype.getTimezoneName = function() { + var match = /(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString()); + return match[1] || match[2] || 'GMT' + this.getGmtOffset(); + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getTimezoneOffset = function() { + return this.proxy.getTimezoneOffset(); + }; + + + /** + * Get the week number of the given year, starting with the first Monday as the first week + * @returns {Integer} Week number (13 for the 13th week of the year). + */ + jsDate.prototype.getWeekOfYear = function() { + var doy = this.getDayOfYear(); + var rdow = 7 - this.getDayOfWeek(); + var woy = parseInt((doy+rdow)/7, 10); + return woy; + }; + + /** + * Get the current date as a Unix timestamp + * + * @returns {Integer} + */ + + jsDate.prototype.getUnix = function() { + return Math.round(this.proxy.getTime() / 1000, 0); + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.getYear = function() { + return this.proxy.getYear(); + }; + + /** + * Return a date one day ahead (or any other unit) + * + * @param {String} unit Optional, year | month | day | week | hour | minute | second | millisecond + * @returns {jsDate} + */ + + jsDate.prototype.next = function(unit) { + unit = unit || 'day'; + return this.clone().add(1, unit); + }; + + /** + * Set the jsDate instance to a new date. + * + * @param {String | Number | Array | Date Object | jsDate Object | Options Object} arguments Optional arguments, + * either a parsable date/time string, + * a JavaScript timestamp, an array of numbers of form [year, month, day, hours, minutes, seconds, milliseconds], + * a Date object, jsDate Object or an options object of form {syntax: "perl", date:some Date} where all options are optional. + */ + jsDate.prototype.set = function() { + switch ( arguments.length ) { + case 0: + this.proxy = new Date(); + break; + case 1: + // other objects either won't have a _type property or, + // if they do, it shouldn't be set to "jsDate", so + // assume it is an options argument. + if (get_type(arguments[0]) == "[object Object]" && arguments[0]._type != "jsDate") { + var opts = this.options = arguments[0]; + this.syntax = opts.syntax || this.syntax; + this.defaultCentury = opts.defaultCentury || this.defaultCentury; + this.proxy = jsDate.createDate(opts.date); + } + else { + this.proxy = jsDate.createDate(arguments[0]); + } + break; + default: + var a = []; + for ( var i=0; i<arguments.length; i++ ) { + a.push(arguments[i]); + } + // this should be the current date/time + this.proxy = new Date(); + this.proxy.setFullYear.apply( this.proxy, a.slice(0,3) ); + if ( a.slice(3).length ) { + this.proxy.setHours.apply( this.proxy, a.slice(3) ); + } + break; + } + return this; + }; + + /** + * Sets the day of the month for a specified date according to local time. + * @param {Integer} dayValue An integer from 1 to 31, representing the day of the month. + */ + jsDate.prototype.setDate = function(n) { + this.proxy.setDate(n); + return this; + }; + + /** + * Sets the full year for a specified date according to local time. + * @param {Integer} yearValue The numeric value of the year, for example, 1995. + * @param {Integer} monthValue Optional, between 0 and 11 representing the months January through December. + * @param {Integer} dayValue Optional, between 1 and 31 representing the day of the month. If you specify the dayValue parameter, you must also specify the monthValue. + */ + jsDate.prototype.setFullYear = function() { + this.proxy.setFullYear.apply(this.proxy, arguments); + return this; + }; + + /** + * Sets the hours for a specified date according to local time. + * + * @param {Integer} hoursValue An integer between 0 and 23, representing the hour. + * @param {Integer} minutesValue Optional, An integer between 0 and 59, representing the minutes. + * @param {Integer} secondsValue Optional, An integer between 0 and 59, representing the seconds. + * If you specify the secondsValue parameter, you must also specify the minutesValue. + * @param {Integer} msValue Optional, A number between 0 and 999, representing the milliseconds. + * If you specify the msValue parameter, you must also specify the minutesValue and secondsValue. + */ + jsDate.prototype.setHours = function() { + this.proxy.setHours.apply(this.proxy, arguments); + return this; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.setMilliseconds = function(n) { + this.proxy.setMilliseconds(n); + return this; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.setMinutes = function() { + this.proxy.setMinutes.apply(this.proxy, arguments); + return this; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.setMonth = function() { + this.proxy.setMonth.apply(this.proxy, arguments); + return this; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.setSeconds = function() { + this.proxy.setSeconds.apply(this.proxy, arguments); + return this; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.setTime = function(n) { + this.proxy.setTime(n); + return this; + }; + + /** + * Implements Date functionality + */ + jsDate.prototype.setYear = function() { + this.proxy.setYear.apply(this.proxy, arguments); + return this; + }; + + /** + * Provide a formatted string representation of this date. + * + * @param {String} formatString A format string. + * See: {@link jsDate.formats}. + * @returns {String} Date String. + */ + + jsDate.prototype.strftime = function(formatString) { + formatString = formatString || this.formatString || jsDate.regional[this.locale]['formatString']; + return jsDate.strftime(this, formatString, this.syntax); + }; + + /** + * Return a String representation of this jsDate object. + * @returns {String} Date string. + */ + + jsDate.prototype.toString = function() { + return this.proxy.toString(); + }; + + /** + * Convert the current date to an 8-digit integer (%Y%m%d) + * + * @returns {Integer} + */ + + jsDate.prototype.toYmdInt = function() { + return (this.proxy.getFullYear() * 10000) + (this.getMonthNumber() * 100) + this.proxy.getDate(); + }; + + /** + * @namespace Holds localizations for month/day names. + * <p>jsDate attempts to detect locale when loaded and defaults to 'en'. + * If a localization is detected which is not available, jsDate defaults to 'en'. + * Additional localizations can be added after jsDate loads. After adding a localization, + * call the jsDate.regional.getLocale() method. Currently, en, fr and de are defined.</p> + * + * <p>Localizations must be an object and have the following properties defined: monthNames, monthNamesShort, dayNames, dayNamesShort and Localizations are added like:</p> + * <pre class="code"> + * jsDate.regional['en'] = { + * monthNames : 'January February March April May June July August September October November December'.split(' '), + * monthNamesShort : 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' '), + * dayNames : 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'.split(' '), + * dayNamesShort : 'Sun Mon Tue Wed Thu Fri Sat'.split(' ') + * }; + * </pre> + * <p>After adding localizations, call <code>jsDate.regional.getLocale();</code> to update the locale setting with the + * new localizations.</p> + */ + + jsDate.regional = { + 'en': { + monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'], + monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun','Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'fr': { + monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'], + monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun','Jul','Aoû','Sep','Oct','Nov','Déc'], + dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], + dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'de': { + monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'], + monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'], + dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], + dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'es': { + monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'], + monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', 'Jul','Ago','Sep','Oct','Nov','Dic'], + dayNames: ['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'], + dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'ru': { + monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], + monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн','Июл','Авг','Сен','Окт','Ноя','Дек'], + dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'], + dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'ar': { + monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران','تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'], + monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], + dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'], + dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'pt': { + monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], + monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'], + dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], + dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'pt-BR': { + monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], + monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'], + dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], + dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'pl': { + monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec','Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], + monthNamesShort: ['Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze','Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru'], + dayNames: ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'], + dayNamesShort: ['Ni', 'Pn', 'Wt', 'Śr', 'Cz', 'Pt', 'Sb'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'nl': { + monthNames: ['Januari','Februari','Maart','April','Mei','Juni','July','Augustus','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Aug','Sep','Okt','Nov','Dec'], + dayNames:','['Zondag','Maandag','Dinsdag','Woensdag','Donderdag','Vrijdag','Zaterdag'], + dayNamesShort: ['Zo','Ma','Di','Wo','Do','Vr','Za'], + formatString: '%Y-%m-%d %H:%M:%S' + }, + + 'sv': { + monthNames: ['januari','februari','mars','april','maj','juni','juli','augusti','september','oktober','november','december'], + monthNamesShort: ['jan','feb','mar','apr','maj','jun','jul','aug','sep','okt','nov','dec'], + dayNames: ['söndag','måndag','tisdag','onsdag','torsdag','fredag','lördag'], + dayNamesShort: ['sön','mån','tis','ons','tor','fre','lör'], + formatString: '%Y-%m-%d %H:%M:%S' + } + + }; + + // Set english variants to 'en' + jsDate.regional['en-US'] = jsDate.regional['en-GB'] = jsDate.regional['en']; + + /** + * Try to determine the users locale based on the lang attribute of the html page. Defaults to 'en' + * if it cannot figure out a locale of if the locale does not have a localization defined. + * @returns {String} locale + */ + + jsDate.regional.getLocale = function () { + var l = jsDate.config.defaultLocale; + + if ( document && document.getElementsByTagName('html') && document.getElementsByTagName('html')[0].lang ) { + l = document.getElementsByTagName('html')[0].lang; + if (!jsDate.regional.hasOwnProperty(l)) { + l = jsDate.config.defaultLocale; + } + } + + return l; + }; + + // ms in day + var day = 24 * 60 * 60 * 1000; + + // padd a number with zeros + var addZeros = function(num, digits) { + num = String(num); + var i = digits - num.length; + var s = String(Math.pow(10, i)).slice(1); + return s.concat(num); + }; + + // representations used for calculating differences between dates. + // This borrows heavily from Ken Snyder's work. + var multipliers = { + millisecond: 1, + second: 1000, + minute: 60 * 1000, + hour: 60 * 60 * 1000, + day: day, + week: 7 * day, + month: { + // add a number of months + add: function(d, number) { + // add any years needed (increments of 12) + multipliers.year.add(d, Math[number > 0 ? 'floor' : 'ceil'](number / 12)); + // ensure that we properly wrap betwen December and January + // 11 % 12 = 11 + // 12 % 12 = 0 + var prevMonth = d.getMonth() + (number % 12); + if (prevMonth == 12) { + prevMonth = 0; + d.setYear(d.getFullYear() + 1); + } else if (prevMonth == -1) { + prevMonth = 11; + d.setYear(d.getFullYear() - 1); + } + d.setMonth(prevMonth); + }, + // get the number of months between two Date objects (decimal to the nearest day) + diff: function(d1, d2) { + // get the number of years + var diffYears = d1.getFullYear() - d2.getFullYear(); + // get the number of remaining months + var diffMonths = d1.getMonth() - d2.getMonth() + (diffYears * 12); + // get the number of remaining days + var diffDays = d1.getDate() - d2.getDate(); + // return the month difference with the days difference as a decimal + return diffMonths + (diffDays / 30); + } + }, + year: { + // add a number of years + add: function(d, number) { + d.setYear(d.getFullYear() + Math[number > 0 ? 'floor' : 'ceil'](number)); + }, + // get the number of years between two Date objects (decimal to the nearest day) + diff: function(d1, d2) { + return multipliers.month.diff(d1, d2) / 12; + } + } + }; + // + // Alias each multiplier with an 's' to allow 'year' and 'years' for example. + // This comes from Ken Snyders work. + // + for (var unit in multipliers) { + if (unit.substring(unit.length - 1) != 's') { // IE will iterate newly added properties :| + multipliers[unit + 's'] = multipliers[unit]; + } + } + + // + // take a jsDate instance and a format code and return the formatted value. + // This is a somewhat modified version of Ken Snyder's method. + // + var format = function(d, code, syntax) { + // if shorcut codes are used, recursively expand those. + if (jsDate.formats[syntax]["shortcuts"][code]) { + return jsDate.strftime(d, jsDate.formats[syntax]["shortcuts"][code], syntax); + } else { + // get the format code function and addZeros() argument + var getter = (jsDate.formats[syntax]["codes"][code] || '').split('.'); + var nbr = d['get' + getter[0]] ? d['get' + getter[0]]() : ''; + if (getter[1]) { + nbr = addZeros(nbr, getter[1]); + } + return nbr; + } + }; + + /** + * @static + * Static function for convert a date to a string according to a given format. Also acts as namespace for strftime format codes. + * <p>strftime formatting can be accomplished without creating a jsDate object by calling jsDate.strftime():</p> + * <pre class="code"> + * var formattedDate = jsDate.strftime('Feb 8, 2006 8:48:32', '%Y-%m-%d %H:%M:%S'); + * </pre> + * @param {String | Number | Array | jsDate Object | Date Object} date A parsable date string, JavaScript time stamp, Array of form [year, month, day, hours, minutes, seconds, milliseconds], jsDate Object or Date object. + * @param {String} formatString String with embedded date formatting codes. + * See: {@link jsDate.formats}. + * @param {String} syntax Optional syntax to use [default perl]. + * @param {String} locale Optional locale to use. + * @returns {String} Formatted representation of the date. + */ + // + // Logic as implemented here is very similar to Ken Snyder's Date Instance Methods. + // + jsDate.strftime = function(d, formatString, syntax, locale) { + var syn = 'perl'; + var loc = jsDate.regional.getLocale(); + + // check if syntax and locale are available or reversed + if (syntax && jsDate.formats.hasOwnProperty(syntax)) { + syn = syntax; + } + else if (syntax && jsDate.regional.hasOwnProperty(syntax)) { + loc = syntax; + } + + if (locale && jsDate.formats.hasOwnProperty(locale)) { + syn = locale; + } + else if (locale && jsDate.regional.hasOwnProperty(locale)) { + loc = locale; + } + + if (get_type(d) != "[object Object]" || d._type != "jsDate") { + d = new jsDate(d); + d.locale = loc; + } + if (!formatString) { + formatString = d.formatString || jsDate.regional[loc]['formatString']; + } + // default the format string to year-month-day + var source = formatString || '%Y-%m-%d', + result = '', + match; + // replace each format code + while (source.length > 0) { + if (match = source.match(jsDate.formats[syn].codes.matcher)) { + result += source.slice(0, match.index); + result += (match[1] || '') + format(d, match[2], syn); + source = source.slice(match.index + match[0].length); + } else { + result += source; + source = ''; + } + } + return result; + }; + + /** + * @namespace + * Namespace to hold format codes and format shortcuts. "perl" and "php" format codes + * and shortcuts are defined by default. Additional codes and shortcuts can be + * added like: + * + * <pre class="code"> + * jsDate.formats["perl"] = { + * "codes": { + * matcher: /someregex/, + * Y: "fullYear", // name of "get" method without the "get", + * ..., // more codes + * }, + * "shortcuts": { + * F: '%Y-%m-%d', + * ..., // more shortcuts + * } + * }; + * </pre> + * + * <p>Additionally, ISO and SQL shortcuts are defined and can be accesses via: + * <code>jsDate.formats.ISO</code> and <code>jsDate.formats.SQL</code> + */ + + jsDate.formats = { + ISO:'%Y-%m-%dT%H:%M:%S.%N%G', + SQL:'%Y-%m-%d %H:%M:%S' + }; + + /** + * Perl format codes and shortcuts for strftime. + * + * A hash (object) of codes where each code must be an array where the first member is + * the name of a Date.prototype or jsDate.prototype function to call + * and optionally a second member indicating the number to pass to addZeros() + * + * <p>The following format codes are defined:</p> + * + * <pre class="code"> + * Code Result Description + * == Years == + * %Y 2008 Four-digit year + * %y 08 Two-digit year + * + * == Months == + * %m 09 Two-digit month + * %#m 9 One or two-digit month + * %B September Full month name + * %b Sep Abbreviated month name + * + * == Days == + * %d 05 Two-digit day of month + * %#d 5 One or two-digit day of month + * %e 5 One or two-digit day of month + * %A Sunday Full name of the day of the week + * %a Sun Abbreviated name of the day of the week + * %w 0 Number of the day of the week (0 = Sunday, 6 = Saturday) + * + * == Hours == + * %H 23 Hours in 24-hour format (two digits) + * %#H 3 Hours in 24-hour integer format (one or two digits) + * %I 11 Hours in 12-hour format (two digits) + * %#I 3 Hours in 12-hour integer format (one or two digits) + * %p PM AM or PM + * + * == Minutes == + * %M 09 Minutes (two digits) + * %#M 9 Minutes (one or two digits) + * + * == Seconds == + * %S 02 Seconds (two digits) + * %#S 2 Seconds (one or two digits) + * %s 1206567625723 Unix timestamp (Seconds past 1970-01-01 00:00:00) + * + * == Milliseconds == + * %N 008 Milliseconds (three digits) + * %#N 8 Milliseconds (one to three digits) + * + * == Timezone == + * %O 360 difference in minutes between local time and GMT + * %Z Mountain Standard Time Name of timezone as reported by browser + * %G 06:00 Hours and minutes between GMT + * + * == Shortcuts == + * %F 2008-03-26 %Y-%m-%d + * %T 05:06:30 %H:%M:%S + * %X 05:06:30 %H:%M:%S + * %x 03/26/08 %m/%d/%y + * %D 03/26/08 %m/%d/%y + * %#c Wed Mar 26 15:31:00 2008 %a %b %e %H:%M:%S %Y + * %v 3-Sep-2008 %e-%b-%Y + * %R 15:31 %H:%M + * %r 03:31:00 PM %I:%M:%S %p + * + * == Characters == + * %n \n Newline + * %t \t Tab + * %% % Percent Symbol + * </pre> + * + * <p>Formatting shortcuts that will be translated into their longer version. + * Be sure that format shortcuts do not refer to themselves: this will cause an infinite loop.</p> + * + * <p>Format codes and format shortcuts can be redefined after the jsDate + * module is imported.</p> + * + * <p>Note that if you redefine the whole hash (object), you must supply a "matcher" + * regex for the parser. The default matcher is:</p> + * + * <code>/()%(#?(%|[a-z]))/i</code> + * + * <p>which corresponds to the Perl syntax used by default.</p> + * + * <p>By customizing the matcher and format codes, nearly any strftime functionality is possible.</p> + */ + + jsDate.formats.perl = { + codes: { + // + // 2-part regex matcher for format codes + // + // first match must be the character before the code (to account for escaping) + // second match must be the format code character(s) + // + matcher: /()%(#?(%|[a-z]))/i, + // year + Y: 'FullYear', + y: 'ShortYear.2', + // month + m: 'MonthNumber.2', + '#m': 'MonthNumber', + B: 'MonthName', + b: 'AbbrMonthName', + // day + d: 'Date.2', + '#d': 'Date', + e: 'Date', + A: 'DayName', + a: 'AbbrDayName', + w: 'Day', + // hours + H: 'Hours.2', + '#H': 'Hours', + I: 'Hours12.2', + '#I': 'Hours12', + p: 'AMPM', + // minutes + M: 'Minutes.2', + '#M': 'Minutes', + // seconds + S: 'Seconds.2', + '#S': 'Seconds', + s: 'Unix', + // milliseconds + N: 'Milliseconds.3', + '#N': 'Milliseconds', + // timezone + O: 'TimezoneOffset', + Z: 'TimezoneName', + G: 'GmtOffset' + }, + + shortcuts: { + // date + F: '%Y-%m-%d', + // time + T: '%H:%M:%S', + X: '%H:%M:%S', + // local format date + x: '%m/%d/%y', + D: '%m/%d/%y', + // local format extended + '#c': '%a %b %e %H:%M:%S %Y', + // local format short + v: '%e-%b-%Y', + R: '%H:%M', + r: '%I:%M:%S %p', + // tab and newline + t: '\t', + n: '\n', + '%': '%' + } + }; + + /** + * PHP format codes and shortcuts for strftime. + * + * A hash (object) of codes where each code must be an array where the first member is + * the name of a Date.prototype or jsDate.prototype function to call + * and optionally a second member indicating the number to pass to addZeros() + * + * <p>The following format codes are defined:</p> + * + * <pre class="code"> + * Code Result Description + * === Days === + * %a Sun through Sat An abbreviated textual representation of the day + * %A Sunday - Saturday A full textual representation of the day + * %d 01 to 31 Two-digit day of the month (with leading zeros) + * %e 1 to 31 Day of the month, with a space preceding single digits. + * %j 001 to 366 Day of the year, 3 digits with leading zeros + * %u 1 - 7 (Mon - Sun) ISO-8601 numeric representation of the day of the week + * %w 0 - 6 (Sun - Sat) Numeric representation of the day of the week + * + * === Week === + * %U 13 Full Week number, starting with the first Sunday as the first week + * %V 01 through 53 ISO-8601:1988 week number, starting with the first week of the year + * with at least 4 weekdays, with Monday being the start of the week + * %W 46 A numeric representation of the week of the year, + * starting with the first Monday as the first week + * === Month === + * %b Jan through Dec Abbreviated month name, based on the locale + * %B January - December Full month name, based on the locale + * %h Jan through Dec Abbreviated month name, based on the locale (an alias of %b) + * %m 01 - 12 (Jan - Dec) Two digit representation of the month + * + * === Year === + * %C 19 Two digit century (year/100, truncated to an integer) + * %y 09 for 2009 Two digit year + * %Y 2038 Four digit year + * + * === Time === + * %H 00 through 23 Two digit representation of the hour in 24-hour format + * %I 01 through 12 Two digit representation of the hour in 12-hour format + * %l 1 through 12 Hour in 12-hour format, with a space preceeding single digits + * %M 00 through 59 Two digit representation of the minute + * %p AM/PM UPPER-CASE 'AM' or 'PM' based on the given time + * %P am/pm lower-case 'am' or 'pm' based on the given time + * %r 09:34:17 PM Same as %I:%M:%S %p + * %R 00:35 Same as %H:%M + * %S 00 through 59 Two digit representation of the second + * %T 21:34:17 Same as %H:%M:%S + * %X 03:59:16 Preferred time representation based on locale, without the date + * %z -0500 or EST Either the time zone offset from UTC or the abbreviation + * %Z -0500 or EST The time zone offset/abbreviation option NOT given by %z + * + * === Time and Date === + * %D 02/05/09 Same as %m/%d/%y + * %F 2009-02-05 Same as %Y-%m-%d (commonly used in database datestamps) + * %s 305815200 Unix Epoch Time timestamp (same as the time() function) + * %x 02/05/09 Preferred date representation, without the time + * + * === Miscellaneous === + * %n --- A newline character (\n) + * %t --- A Tab character (\t) + * %% --- A literal percentage character (%) + * </pre> + */ + + jsDate.formats.php = { + codes: { + // + // 2-part regex matcher for format codes + // + // first match must be the character before the code (to account for escaping) + // second match must be the format code character(s) + // + matcher: /()%((%|[a-z]))/i, + // day + a: 'AbbrDayName', + A: 'DayName', + d: 'Date.2', + e: 'Date', + j: 'DayOfYear.3', + u: 'DayOfWeek', + w: 'Day', + // week + U: 'FullWeekOfYear.2', + V: 'IsoWeek.2', + W: 'WeekOfYear.2', + // month + b: 'AbbrMonthName', + B: 'MonthName', + m: 'MonthNumber.2', + h: 'AbbrMonthName', + // year + C: 'Century.2', + y: 'ShortYear.2', + Y: 'FullYear', + // time + H: 'Hours.2', + I: 'Hours12.2', + l: 'Hours12', + p: 'AMPM', + P: 'AmPm', + M: 'Minutes.2', + S: 'Seconds.2', + s: 'Unix', + O: 'TimezoneOffset', + z: 'GmtOffset', + Z: 'TimezoneAbbr' + }, + + shortcuts: { + D: '%m/%d/%y', + F: '%Y-%m-%d', + T: '%H:%M:%S', + X: '%H:%M:%S', + x: '%m/%d/%y', + R: '%H:%M', + r: '%I:%M:%S %p', + t: '\t', + n: '\n', + '%': '%' + } + }; + // + // Conceptually, the logic implemented here is similar to Ken Snyder's Date Instance Methods. + // I use his idea of a set of parsers which can be regular expressions or functions, + // iterating through those, and then seeing if Date.parse() will create a date. + // The parser expressions and functions are a little different and some bugs have been + // worked out. Also, a lot of "pre-parsing" is done to fix implementation + // variations of Date.parse() between browsers. + // + jsDate.createDate = function(date) { + // if passing in multiple arguments, try Date constructor + if (date == null) { + return new Date(); + } + // If the passed value is already a date object, return it + if (date instanceof Date) { + return date; + } + // if (typeof date == 'number') return new Date(date * 1000); + // If the passed value is an integer, interpret it as a javascript timestamp + if (typeof date == 'number') { + return new Date(date); + } + + // Before passing strings into Date.parse(), have to normalize them for certain conditions. + // If strings are not formatted staccording to the EcmaScript spec, results from Date parse will be implementation dependent. + // + // For example: + // * FF and Opera assume 2 digit dates are pre y2k, Chome assumes <50 is pre y2k, 50+ is 21st century. + // * Chrome will correctly parse '1984-1-25' into localtime, FF and Opera will not parse. + // * Both FF, Chrome and Opera will parse '1984/1/25' into localtime. + + // remove leading and trailing spaces + var parsable = String(date).replace(/^\s*(.+)\s*$/g, '$1'); + + // replace dahses (-) with slashes (/) in dates like n[nnn]/n[n]/n[nnn] + parsable = parsable.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/, "$1/$2/$3"); + + ///////// + // Need to check for '15-Dec-09' also. + // FF will not parse, but Chrome will. + // Chrome will set date to 2009 as well. + ///////// + + // first check for 'dd-mmm-yyyy' or 'dd/mmm/yyyy' like '15-Dec-2010' + parsable = parsable.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i, "$1 $2 $3"); + + // Now check for 'dd-mmm-yy' or 'dd/mmm/yy' and normalize years to default century. + var match = parsable.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i); + if (match && match.length > 3) { + var m3 = parseFloat(match[3]); + var ny = jsDate.config.defaultCentury + m3; + ny = String(ny); + + // now replace 2 digit year with 4 digit year + parsable = parsable.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i, match[1] +' '+ match[2] +' '+ ny); + + } + + // Check for '1/19/70 8:14PM' + // where starts with mm/dd/yy or yy/mm/dd and have something after + // Check if 1st postiion is greater than 31, assume it is year. + // Assme all 2 digit years are 1900's. + // Finally, change them into US style mm/dd/yyyy representations. + match = parsable.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/); + + function h1(parsable, match) { + var m1 = parseFloat(match[1]); + var m2 = parseFloat(match[2]); + var m3 = parseFloat(match[3]); + var cent = jsDate.config.defaultCentury; + var ny, nd, nm, str; + + if (m1 > 31) { // first number is a year + nd = m3; + nm = m2; + ny = cent + m1; + } + + else { // last number is the year + nd = m2; + nm = m1; + ny = cent + m3; + } + + str = nm+'/'+nd+'/'+ny; + + // now replace 2 digit year with 4 digit year + return parsable.replace(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/, str); + + } + + if (match && match.length > 3) { + parsable = h1(parsable, match); + } + + // Now check for '1/19/70' with nothing after and do as above + var match = parsable.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/); + + if (match && match.length > 3) { + parsable = h1(parsable, match); + } + + + var i = 0; + var length = jsDate.matchers.length; + var pattern, + ms, + current = parsable, + obj; + while (i < length) { + ms = Date.parse(current); + if (!isNaN(ms)) { + return new Date(ms); + } + pattern = jsDate.matchers[i]; + if (typeof pattern == 'function') { + obj = pattern.call(jsDate, current); + if (obj instanceof Date) { + return obj; + } + } else { + current = parsable.replace(pattern[0], pattern[1]); + } + i++; + } + return NaN; + }; + + + /** + * @static + * Handy static utility function to return the number of days in a given month. + * @param {Integer} year Year + * @param {Integer} month Month (1-12) + * @returns {Integer} Number of days in the month. + */ + // + // handy utility method Borrowed right from Ken Snyder's Date Instance Mehtods. + // + jsDate.daysInMonth = function(year, month) { + if (month == 2) { + return new Date(year, 1, 29).getDate() == 29 ? 29 : 28; + } + return [undefined,31,undefined,31,30,31,30,31,31,30,31,30,31][month]; + }; + + + // + // An Array of regular expressions or functions that will attempt to match the date string. + // Functions are called with scope of a jsDate instance. + // + jsDate.matchers = [ + // convert dd.mmm.yyyy to mm/dd/yyyy (world date to US date). + [/(3[01]|[0-2]\d)\s*\.\s*(1[0-2]|0\d)\s*\.\s*([1-9]\d{3})/, '$2/$1/$3'], + // convert yyyy-mm-dd to mm/dd/yyyy (ISO date to US date). + [/([1-9]\d{3})\s*-\s*(1[0-2]|0\d)\s*-\s*(3[01]|[0-2]\d)/, '$2/$3/$1'], + // Handle 12 hour or 24 hour time with milliseconds am/pm and optional date part. + function(str) { + var match = str.match(/^(?:(.+)\s+)?([012]?\d)(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d(\.\d*)?))?\s*(am|pm)?\s*$/i); + // opt. date hour opt. minute opt. second opt. msec opt. am or pm + if (match) { + if (match[1]) { + var d = this.createDate(match[1]); + if (isNaN(d)) { + return; + } + } else { + var d = new Date(); + d.setMilliseconds(0); + } + var hour = parseFloat(match[2]); + if (match[6]) { + hour = match[6].toLowerCase() == 'am' ? (hour == 12 ? 0 : hour) : (hour == 12 ? 12 : hour + 12); + } + d.setHours(hour, parseInt(match[3] || 0, 10), parseInt(match[4] || 0, 10), ((parseFloat(match[5] || 0)) || 0)*1000); + return d; + } + else { + return str; + } + }, + // Handle ISO timestamp with time zone. + function(str) { + var match = str.match(/^(?:(.+))[T|\s+]([012]\d)(?:\:(\d\d))(?:\:(\d\d))(?:\.\d+)([\+\-]\d\d\:\d\d)$/i); + if (match) { + if (match[1]) { + var d = this.createDate(match[1]); + if (isNaN(d)) { + return; + } + } else { + var d = new Date(); + d.setMilliseconds(0); + } + var hour = parseFloat(match[2]); + d.setHours(hour, parseInt(match[3], 10), parseInt(match[4], 10), parseFloat(match[5])*1000); + return d; + } + else { + return str; + } + }, + // Try to match ambiguous strings like 12/8/22. + // Use FF date assumption that 2 digit years are 20th century (i.e. 1900's). + // This may be redundant with pre processing of date already performed. + function(str) { + var match = str.match(/^([0-3]?\d)\s*[-\/.\s]{1}\s*([a-zA-Z]{3,9})\s*[-\/.\s]{1}\s*([0-3]?\d)$/); + if (match) { + var d = new Date(); + var cent = jsDate.config.defaultCentury; + var m1 = parseFloat(match[1]); + var m3 = parseFloat(match[3]); + var ny, nd, nm; + if (m1 > 31) { // first number is a year + nd = m3; + ny = cent + m1; + } + + else { // last number is the year + nd = m1; + ny = cent + m3; + } + + var nm = inArray(match[2], jsDate.regional[jsDate.regional.getLocale()]["monthNamesShort"]); + + if (nm == -1) { + nm = inArray(match[2], jsDate.regional[jsDate.regional.getLocale()]["monthNames"]); + } + + d.setFullYear(ny, nm, nd); + d.setHours(0,0,0,0); + return d; + } + + else { + return str; + } + } + ]; + + // + // I think John Reisig published this method on his blog, ejohn. + // + function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + } + + // + // Thanks to Kangax, Christian Sciberras and Stack Overflow for this method. + // + function get_type(thing){ + if(thing===null) return "[object Null]"; // special case + return Object.prototype.toString.call(thing); + } + + $.jsDate = jsDate; + + + /** + * JavaScript printf/sprintf functions. + * + * This code has been adapted from the publicly available sprintf methods + * by Ash Searle. His original header follows: + * + * This code is unrestricted: you are free to use it however you like. + * + * The functions should work as expected, performing left or right alignment, + * truncating strings, outputting numbers with a required precision etc. + * + * For complex cases, these functions follow the Perl implementations of + * (s)printf, allowing arguments to be passed out-of-order, and to set the + * precision or length of the output based on arguments instead of fixed + * numbers. + * + * See http://perldoc.perl.org/functions/sprintf.html for more information. + * + * Implemented: + * - zero and space-padding + * - right and left-alignment, + * - base X prefix (binary, octal and hex) + * - positive number prefix + * - (minimum) width + * - precision / truncation / maximum width + * - out of order arguments + * + * Not implemented (yet): + * - vector flag + * - size (bytes, words, long-words etc.) + * + * Will not implement: + * - %n or %p (no pass-by-reference in JavaScript) + * + * @version 2007.04.27 + * @author Ash Searle + * + * You can see the original work and comments on his blog: + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + */ + + /** + * @Modifications 2009.05.26 + * @author Chris Leonello + * + * Added %p %P specifier + * Acts like %g or %G but will not add more significant digits to the output than present in the input. + * Example: + * Format: '%.3p', Input: 0.012, Output: 0.012 + * Format: '%.3g', Input: 0.012, Output: 0.0120 + * Format: '%.4p', Input: 12.0, Output: 12.0 + * Format: '%.4g', Input: 12.0, Output: 12.00 + * Format: '%.4p', Input: 4.321e-5, Output: 4.321e-5 + * Format: '%.4g', Input: 4.321e-5, Output: 4.3210e-5 + * + * Example: + * >>> $.jqplot.sprintf('%.2f, %d', 23.3452, 43.23) + * "23.35, 43" + * >>> $.jqplot.sprintf("no value: %n, decimal with thousands separator: %'d", 23.3452, 433524) + * "no value: , decimal with thousands separator: 433,524" + */ + $.jqplot.sprintf = function() { + function pad(str, len, chr, leftJustify) { + var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr); + return leftJustify ? str + padding : padding + str; + + } + + function thousand_separate(value) { + var value_str = new String(value); + for (var i=10; i>0; i--) { + if (value_str == (value_str = value_str.replace(/^(\d+)(\d{3})/, "$1"+$.jqplot.sprintf.thousandsSeparator+"$2"))) break; + } + return value_str; + } + + function justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace) { + var diff = minWidth - value.length; + if (diff > 0) { + var spchar = ' '; + if (htmlSpace) { spchar = ' '; } + if (leftJustify || !zeroPad) { + value = pad(value, minWidth, spchar, leftJustify); + } else { + value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length); + } + } + return value; + } + + function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad, htmlSpace) { + // Note: casts negative numbers to positive ones + var number = value >>> 0; + prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || ''; + value = prefix + pad(number.toString(base), precision || 0, '0', false); + return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace); + } + + function formatString(value, leftJustify, minWidth, precision, zeroPad, htmlSpace) { + if (precision != null) { + value = value.slice(0, precision); + } + return justify(value, '', leftJustify, minWidth, zeroPad, htmlSpace); + } + + var a = arguments, i = 0, format = a[i++]; + + return format.replace($.jqplot.sprintf.regex, function(substring, valueIndex, flags, minWidth, _, precision, type) { + if (substring == '%%') { return '%'; } + + // parse flags + var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, htmlSpace = false, thousandSeparation = false; + for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) { + case ' ': positivePrefix = ' '; break; + case '+': positivePrefix = '+'; break; + case '-': leftJustify = true; break; + case '0': zeroPad = true; break; + case '#': prefixBaseX = true; break; + case '&': htmlSpace = true; break; + case '\'': thousandSeparation = true; break; + } + + // parameters may be null, undefined, empty-string or real valued + // we want to ignore null, undefined and empty-string values + + if (!minWidth) { + minWidth = 0; + } + else if (minWidth == '*') { + minWidth = +a[i++]; + } + else if (minWidth.charAt(0) == '*') { + minWidth = +a[minWidth.slice(1, -1)]; + } + else { + minWidth = +minWidth; + } + + // Note: undocumented perl feature: + if (minWidth < 0) { + minWidth = -minWidth; + leftJustify = true; + } + + if (!isFinite(minWidth)) { + throw new Error('$.jqplot.sprintf: (minimum-)width must be finite'); + } + + if (!precision) { + precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0); + } + else if (precision == '*') { + precision = +a[i++]; + } + else if (precision.charAt(0) == '*') { + precision = +a[precision.slice(1, -1)]; + } + else { + precision = +precision; + } + + // grab value using valueIndex if required? + var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++]; + + switch (type) { + case 's': { + if (value == null) { + return ''; + } + return formatString(String(value), leftJustify, minWidth, precision, zeroPad, htmlSpace); + } + case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad, htmlSpace); + case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad,htmlSpace); + case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); + case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); + case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace).toUpperCase(); + case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); + case 'i': { + var number = parseInt(+value, 10); + if (isNaN(number)) { + return ''; + } + var prefix = number < 0 ? '-' : positivePrefix; + var number_str = thousandSeparation ? thousand_separate(String(Math.abs(number))): String(Math.abs(number)); + value = prefix + pad(number_str, precision, '0', false); + //value = prefix + pad(String(Math.abs(number)), precision, '0', false); + return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace); + } + case 'd': { + var number = Math.round(+value); + if (isNaN(number)) { + return ''; + } + var prefix = number < 0 ? '-' : positivePrefix; + var number_str = thousandSeparation ? thousand_separate(String(Math.abs(number))): String(Math.abs(number)); + value = prefix + pad(number_str, precision, '0', false); + return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace); + } + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + { + var number = +value; + if (isNaN(number)) { + return ''; + } + var prefix = number < 0 ? '-' : positivePrefix; + var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())]; + var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2]; + var number_str = Math.abs(number)[method](precision); + + // Apply the decimal mark properly by splitting the number by the + // decimalMark, applying thousands separator, and then placing it + // back in. + var parts = number_str.toString().split('.'); + parts[0] = thousandSeparation ? thousand_separate(parts[0]) : parts[0]; + number_str = parts.join($.jqplot.sprintf.decimalMark); + + value = prefix + number_str; + var justified = justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform](); + + return justified; + } + case 'p': + case 'P': + { + // make sure number is a number + var number = +value; + if (isNaN(number)) { + return ''; + } + var prefix = number < 0 ? '-' : positivePrefix; + + var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/); + var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : String(number).length; + var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0; + + if (Math.abs(number) < 1) { + if (sd + zeros <= precision) { + value = prefix + Math.abs(number).toPrecision(sd); + } + else { + if (sd <= precision - 1) { + value = prefix + Math.abs(number).toExponential(sd-1); + } + else { + value = prefix + Math.abs(number).toExponential(precision-1); + } + } + } + else { + var prec = (sd <= precision) ? sd : precision; + value = prefix + Math.abs(number).toPrecision(prec); + } + var textTransform = ['toString', 'toUpperCase']['pP'.indexOf(type) % 2]; + return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform](); + } + case 'n': return ''; + default: return substring; + } + }); + }; + + $.jqplot.sprintf.thousandsSeparator = ','; + // Specifies the decimal mark for floating point values. By default a period '.' + // is used. If you change this value to for example a comma be sure to also + // change the thousands separator or else this won't work since a simple String + // replace is used (replacing all periods with the mark specified here). + $.jqplot.sprintf.decimalMark = '.'; + + $.jqplot.sprintf.regex = /%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g; + + $.jqplot.getSignificantFigures = function(number) { + var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/); + // total significant digits + var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length; + var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0; + // exponent + var expn = parseInt(parts[1], 10); + // digits to the left of the decimal place + var dleft = (expn + 1 > 0) ? expn + 1 : 0; + // digits to the right of the decimal place + var dright = (sd <= dleft) ? 0 : sd - expn - 1; + return {significantDigits: sd, digitsLeft: dleft, digitsRight: dright, zeros: zeros, exponent: expn} ; + }; + + $.jqplot.getPrecision = function(number) { + return $.jqplot.getSignificantFigures(number).digitsRight; + }; + + + + + var backCompat = $.uiBackCompat !== false; + + $.jqplot.effects = { + effect: {} + }; + + // prefix used for storing data on .data() + var dataSpace = "jqplot.storage."; + + /******************************************************************************/ + /*********************************** EFFECTS **********************************/ + /******************************************************************************/ + + $.extend( $.jqplot.effects, { + version: "1.9pre", + + // Saves a set of properties in a data storage + save: function( element, set ) { + for( var i=0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); + } + } + }, + + // Restores a set of previously saved properties from a data storage + restore: function( element, set ) { + for( var i=0; i < set.length; i++ ) { + if ( set[ i ] !== null ) { + element.css( set[ i ], element.data( dataSpace + set[ i ] ) ); + } + } + }, + + setMode: function( el, mode ) { + if (mode === "toggle") { + mode = el.is( ":hidden" ) ? "show" : "hide"; + } + return mode; + }, + + // Wraps the element around a wrapper that copies position properties + createWrapper: function( element ) { + + // if the element is already wrapped, return it + if ( element.parent().is( ".ui-effects-wrapper" )) { + return element.parent(); + } + + // wrap the element + var props = { + width: element.outerWidth(true), + height: element.outerHeight(true), + "float": element.css( "float" ) + }, + wrapper = $( "<div></div>" ) + .addClass( "ui-effects-wrapper" ) + .css({ + fontSize: "100%", + background: "transparent", + border: "none", + margin: 0, + padding: 0 + }), + // Store the size in case width/height are defined in % - Fixes #5245 + size = { + width: element.width(), + height: element.height() + }, + active = document.activeElement; + + element.wrap( wrapper ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).focus(); + } + + wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element + + // transfer positioning properties to the wrapper + if ( element.css( "position" ) === "static" ) { + wrapper.css({ position: "relative" }); + element.css({ position: "relative" }); + } else { + $.extend( props, { + position: element.css( "position" ), + zIndex: element.css( "z-index" ) + }); + $.each([ "top", "left", "bottom", "right" ], function(i, pos) { + props[ pos ] = element.css( pos ); + if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { + props[ pos ] = "auto"; + } + }); + element.css({ + position: "relative", + top: 0, + left: 0, + right: "auto", + bottom: "auto" + }); + } + element.css(size); + + return wrapper.css( props ).show(); + }, + + removeWrapper: function( element ) { + var active = document.activeElement; + + if ( element.parent().is( ".ui-effects-wrapper" ) ) { + element.parent().replaceWith( element ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).focus(); + } + } + + + return element; + } + }); + + // return an effect options object for the given parameters: + function _normalizeArguments( effect, options, speed, callback ) { + + // short path for passing an effect options object: + if ( $.isPlainObject( effect ) ) { + return effect; + } + + // convert to an object + effect = { effect: effect }; + + // catch (effect) + if ( options === undefined ) { + options = {}; + } + + // catch (effect, callback) + if ( $.isFunction( options ) ) { + callback = options; + speed = null; + options = {}; + } + + // catch (effect, speed, ?) + if ( $.type( options ) === "number" || $.fx.speeds[ options ]) { + callback = speed; + speed = options; + options = {}; + } + + // catch (effect, options, callback) + if ( $.isFunction( speed ) ) { + callback = speed; + speed = null; + } + + // add options to effect + if ( options ) { + $.extend( effect, options ); + } + + speed = speed || options.duration; + effect.duration = $.fx.off ? 0 : typeof speed === "number" + ? speed : speed in $.fx.speeds ? $.fx.speeds[ speed ] : $.fx.speeds._default; + + effect.complete = callback || options.complete; + + return effect; + } + + function standardSpeed( speed ) { + // valid standard speeds + if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) { + return true; + } + + // invalid strings - treat as "normal" speed + if ( typeof speed === "string" && !$.jqplot.effects.effect[ speed ] ) { + // TODO: remove in 2.0 (#7115) + if ( backCompat && $.jqplot.effects[ speed ] ) { + return false; + } + return true; + } + + return false; + } + + $.fn.extend({ + jqplotEffect: function( effect, options, speed, callback ) { + var args = _normalizeArguments.apply( this, arguments ), + mode = args.mode, + queue = args.queue, + effectMethod = $.jqplot.effects.effect[ args.effect ], + + // DEPRECATED: remove in 2.0 (#7115) + oldEffectMethod = !effectMethod && backCompat && $.jqplot.effects[ args.effect ]; + + if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) { + // delegate to the original method (e.g., .show()) if possible + if ( mode ) { + return this[ mode ]( args.duration, args.complete ); + } else { + return this.each( function() { + if ( args.complete ) { + args.complete.call( this ); + } + }); + } + } + + function run( next ) { + var elem = $( this ), + complete = args.complete, + mode = args.mode; + + function done() { + if ( $.isFunction( complete ) ) { + complete.call( elem[0] ); + } + if ( $.isFunction( next ) ) { + next(); + } + } + + // if the element is hiddden and mode is hide, + // or element is visible and mode is show + if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { + done(); + } else { + effectMethod.call( elem[0], args, done ); + } + } + + // TODO: remove this check in 2.0, effectMethod will always be true + if ( effectMethod ) { + return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); + } else { + // DEPRECATED: remove in 2.0 (#7115) + return oldEffectMethod.call(this, { + options: args, + duration: args.duration, + callback: args.complete, + mode: args.mode + }); + } + } + }); + + + + + var rvertical = /up|down|vertical/, + rpositivemotion = /up|left|vertical|horizontal/; + + $.jqplot.effects.effect.blind = function( o, done ) { + // Create element + var el = $( this ), + props = [ "position", "top", "bottom", "left", "right", "height", "width" ], + mode = $.jqplot.effects.setMode( el, o.mode || "hide" ), + direction = o.direction || "up", + vertical = rvertical.test( direction ), + ref = vertical ? "height" : "width", + ref2 = vertical ? "top" : "left", + motion = rpositivemotion.test( direction ), + animation = {}, + show = mode === "show", + wrapper, distance, top; + + // // if already wrapped, the wrapper's properties are my property. #6245 + if ( el.parent().is( ".ui-effects-wrapper" ) ) { + $.jqplot.effects.save( el.parent(), props ); + } else { + $.jqplot.effects.save( el, props ); + } + el.show(); + top = parseInt(el.css('top'), 10); + wrapper = $.jqplot.effects.createWrapper( el ).css({ + overflow: "hidden" + }); + + distance = vertical ? wrapper[ ref ]() + top : wrapper[ ref ](); + + animation[ ref ] = show ? String(distance) : '0'; + if ( !motion ) { + el + .css( vertical ? "bottom" : "right", 0 ) + .css( vertical ? "top" : "left", "" ) + .css({ position: "absolute" }); + animation[ ref2 ] = show ? '0' : String(distance); + } + + // // start at 0 if we are showing + if ( show ) { + wrapper.css( ref, 0 ); + if ( ! motion ) { + wrapper.css( ref2, distance ); + } + } + + // // Animate + wrapper.animate( animation, { + duration: o.duration, + easing: o.easing, + queue: false, + complete: function() { + if ( mode === "hide" ) { + el.hide(); + } + $.jqplot.effects.restore( el, props ); + $.jqplot.effects.removeWrapper( el ); + done(); + } + }); + + }; + +})(jQuery); diff --git a/plugin/jqplot/jquery.jqplot.min.css b/plugin/jqplot/jquery.jqplot.min.css new file mode 100644 index 000000000..0f84835b8 --- /dev/null +++ b/plugin/jqplot/jquery.jqplot.min.css @@ -0,0 +1 @@ +.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em}.jqplot-axis{font-size:.75em}.jqplot-xaxis{margin-top:10px}.jqplot-x2axis{margin-bottom:10px}.jqplot-yaxis{margin-right:10px}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom}.jqplot-yaxis-tick{right:0;top:15px;text-align:right}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute}.jqplot-yMidAxis-label{font-size:11pt;position:absolute}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute}.jqplot-meterGauge-tick{font-size:.75em;color:#999}.jqplot-meterGauge-label{font-size:1em;color:#999}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:1px solid #ccc;position:absolute;font-size:.75em}td.jqplot-table-legend{vertical-align:middle}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px}.jqplot-point-label{font-size:.75em;z-index:2}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em}.jqplot-error{text-align:center}.jqplot-error-message{position:relative;top:46%;display:inline-block}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%)}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7)}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3)} \ No newline at end of file diff --git a/plugin/jqplot/jquery.jqplot.min.js b/plugin/jqplot/jquery.jqplot.min.js new file mode 100644 index 000000000..8facc6c18 --- /dev/null +++ b/plugin/jqplot/jquery.jqplot.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(L){var u;L.fn.emptyForce=function(){for(var ah=0,ai;(ai=L(this)[ah])!=null;ah++){if(ai.nodeType===1){L.cleanData(ai.getElementsByTagName("*"))}if(L.jqplot.use_excanvas){ai.outerHTML=""}else{while(ai.firstChild){ai.removeChild(ai.firstChild)}}ai=null}return L(this)};L.fn.removeChildForce=function(ah){while(ah.firstChild){this.removeChildForce(ah.firstChild);ah.removeChild(ah.firstChild)}};L.fn.jqplot=function(){var ah=[];var aj=[];for(var ak=0,ai=arguments.length;ak<ai;ak++){if(L.isArray(arguments[ak])){ah.push(arguments[ak])}else{if(L.isPlainObject(arguments[ak])){aj.push(arguments[ak])}}}return this.each(function(an){var at,ar,aq=L(this),am=ah.length,al=aj.length,ap,ao;if(an<am){ap=ah[an]}else{ap=am?ah[am-1]:null}if(an<al){ao=aj[an]}else{ao=al?aj[al-1]:null}at=aq.attr("id");if(at===u){at="jqplot_target_"+L.jqplot.targetCounter++;aq.attr("id",at)}ar=L.jqplot(at,ap,ao);aq.data("jqplot",ar)})};L.jqplot=function(an,ak,ai){var aj=null,ah=null;if(arguments.length===3){aj=ak;ah=ai}else{if(arguments.length===2){if(L.isArray(ak)){aj=ak}else{if(L.isPlainObject(ak)){ah=ak}}}}if(aj===null&&ah!==null&&ah.data){aj=ah.data}var am=new R();L("#"+an).removeClass("jqplot-error");if(L.jqplot.config.catchErrors){try{am.init(an,aj,ah);am.draw();am.themeEngine.init.call(am);return am}catch(al){var ao=L.jqplot.config.errorMessage||al.message;L("#"+an).append('<div class="jqplot-error-message">'+ao+"</div>");L("#"+an).addClass("jqplot-error");document.getElementById(an).style.background=L.jqplot.config.errorBackground;document.getElementById(an).style.border=L.jqplot.config.errorBorder;document.getElementById(an).style.fontFamily=L.jqplot.config.errorFontFamily;document.getElementById(an).style.fontSize=L.jqplot.config.errorFontSize;document.getElementById(an).style.fontStyle=L.jqplot.config.errorFontStyle;document.getElementById(an).style.fontWeight=L.jqplot.config.errorFontWeight}}else{am.init(an,aj,ah);am.draw();am.themeEngine.init.call(am);return am}};L.jqplot.version="1.0.8";L.jqplot.revision="1250";L.jqplot.targetCounter=1;L.jqplot.CanvasManager=function(){if(typeof L.jqplot.CanvasManager.canvases=="undefined"){L.jqplot.CanvasManager.canvases=[];L.jqplot.CanvasManager.free=[]}var ah=[];this.getCanvas=function(){var ak;var aj=true;if(!L.jqplot.use_excanvas){for(var al=0,ai=L.jqplot.CanvasManager.canvases.length;al<ai;al++){if(L.jqplot.CanvasManager.free[al]===true){aj=false;ak=L.jqplot.CanvasManager.canvases[al];L.jqplot.CanvasManager.free[al]=false;ah.push(al);break}}}if(aj){ak=document.createElement("canvas");ah.push(L.jqplot.CanvasManager.canvases.length);L.jqplot.CanvasManager.canvases.push(ak);L.jqplot.CanvasManager.free.push(false)}return ak};this.initCanvas=function(ai){if(L.jqplot.use_excanvas){return window.G_vmlCanvasManager.initElement(ai)}return ai};this.freeAllCanvases=function(){for(var aj=0,ai=ah.length;aj<ai;aj++){this.freeCanvas(ah[aj])}ah=[]};this.freeCanvas=function(ai){if(L.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==u){window.G_vmlCanvasManager.uninitElement(L.jqplot.CanvasManager.canvases[ai]);L.jqplot.CanvasManager.canvases[ai]=null}else{var aj=L.jqplot.CanvasManager.canvases[ai];aj.getContext("2d").clearRect(0,0,aj.width,aj.height);L(aj).unbind().removeAttr("class").removeAttr("style");L(aj).css({left:"",top:"",position:""});aj.width=0;aj.height=0;L.jqplot.CanvasManager.free[ai]=true}}};L.jqplot.log=function(){if(window.console){window.console.log.apply(window.console,arguments)}};L.jqplot.config={addDomReference:false,enablePlugins:false,defaultHeight:300,defaultWidth:400,UTCAdjust:false,timezoneOffset:new Date(new Date().getTimezoneOffset()*60000),errorMessage:"",errorBackground:"",errorBorder:"",errorFontFamily:"",errorFontSize:"",errorFontStyle:"",errorFontWeight:"",catchErrors:false,defaultTickFormatString:"%.1f",defaultColors:["#4bb2c5","#EAA228","#c5b47f","#579575","#839557","#958c12","#953579","#4b5de4","#d8b83f","#ff5800","#0085cc","#c747a3","#cddf54","#FBD178","#26B4E3","#bd70c7"],defaultNegativeColors:["#498991","#C08840","#9F9274","#546D61","#646C4A","#6F6621","#6E3F5F","#4F64B0","#A89050","#C45923","#187399","#945381","#959E5C","#C7AF7B","#478396","#907294"],dashLength:4,gapLength:4,dotGapLength:2.5,srcLocation:"jqplot/src/",pluginLocation:"jqplot/src/plugins/"};L.jqplot.arrayMax=function(ah){return Math.max.apply(Math,ah)};L.jqplot.arrayMin=function(ah){return Math.min.apply(Math,ah)};L.jqplot.enablePlugins=L.jqplot.config.enablePlugins;L.jqplot.support_canvas=function(){if(typeof L.jqplot.support_canvas.result=="undefined"){L.jqplot.support_canvas.result=!!document.createElement("canvas").getContext}return L.jqplot.support_canvas.result};L.jqplot.support_canvas_text=function(){if(typeof L.jqplot.support_canvas_text.result=="undefined"){if(window.G_vmlCanvasManager!==u&&window.G_vmlCanvasManager._version>887){L.jqplot.support_canvas_text.result=true}else{L.jqplot.support_canvas_text.result=!!(document.createElement("canvas").getContext&&typeof document.createElement("canvas").getContext("2d").fillText=="function")}}return L.jqplot.support_canvas_text.result};L.jqplot.use_excanvas=((!L.support.boxModel||!L.support.objectAll||!$support.leadingWhitespace)&&!L.jqplot.support_canvas())?true:false;L.jqplot.preInitHooks=[];L.jqplot.postInitHooks=[];L.jqplot.preParseOptionsHooks=[];L.jqplot.postParseOptionsHooks=[];L.jqplot.preDrawHooks=[];L.jqplot.postDrawHooks=[];L.jqplot.preDrawSeriesHooks=[];L.jqplot.postDrawSeriesHooks=[];L.jqplot.preDrawLegendHooks=[];L.jqplot.addLegendRowHooks=[];L.jqplot.preSeriesInitHooks=[];L.jqplot.postSeriesInitHooks=[];L.jqplot.preParseSeriesOptionsHooks=[];L.jqplot.postParseSeriesOptionsHooks=[];L.jqplot.eventListenerHooks=[];L.jqplot.preDrawSeriesShadowHooks=[];L.jqplot.postDrawSeriesShadowHooks=[];L.jqplot.ElemContainer=function(){this._elem;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null}};L.jqplot.ElemContainer.prototype.createElement=function(ak,am,ai,aj,an){this._offsets=am;var ah=ai||"jqplot";var al=document.createElement(ak);this._elem=L(al);this._elem.addClass(ah);this._elem.css(aj);this._elem.attr(an);al=null;return this._elem};L.jqplot.ElemContainer.prototype.getWidth=function(){if(this._elem){return this._elem.outerWidth(true)}else{return null}};L.jqplot.ElemContainer.prototype.getHeight=function(){if(this._elem){return this._elem.outerHeight(true)}else{return null}};L.jqplot.ElemContainer.prototype.getPosition=function(){if(this._elem){return this._elem.position()}else{return{top:null,left:null,bottom:null,right:null}}};L.jqplot.ElemContainer.prototype.getTop=function(){return this.getPosition().top};L.jqplot.ElemContainer.prototype.getLeft=function(){return this.getPosition().left};L.jqplot.ElemContainer.prototype.getBottom=function(){return this._elem.css("bottom")};L.jqplot.ElemContainer.prototype.getRight=function(){return this._elem.css("right")};function w(ah){L.jqplot.ElemContainer.call(this);this.name=ah;this._series=[];this.show=false;this.tickRenderer=L.jqplot.AxisTickRenderer;this.tickOptions={};this.labelRenderer=L.jqplot.AxisLabelRenderer;this.labelOptions={};this.label=null;this.showLabel=true;this.min=null;this.max=null;this.autoscale=false;this.pad=1.2;this.padMax=null;this.padMin=null;this.ticks=[];this.numberTicks;this.tickInterval;this.renderer=L.jqplot.LinearAxisRenderer;this.rendererOptions={};this.showTicks=true;this.showTickMarks=true;this.showMinorTicks=true;this.drawMajorGridlines=true;this.drawMinorGridlines=false;this.drawMajorTickMarks=true;this.drawMinorTickMarks=true;this.useSeriesColor=false;this.borderWidth=null;this.borderColor=null;this.scaleToHiddenSeries=false;this._dataBounds={min:null,max:null};this._intervalStats=[];this._offsets={min:null,max:null};this._ticks=[];this._label=null;this.syncTicks=null;this.tickSpacing=75;this._min=null;this._max=null;this._tickInterval=null;this._numberTicks=null;this.__ticks=null;this._options={}}w.prototype=new L.jqplot.ElemContainer();w.prototype.constructor=w;w.prototype.init=function(){if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.tickOptions.axis=this.name;if(this.tickOptions.showMark==null){this.tickOptions.showMark=this.showTicks}if(this.tickOptions.showMark==null){this.tickOptions.showMark=this.showTickMarks}if(this.tickOptions.showLabel==null){this.tickOptions.showLabel=this.showTicks}if(this.label==null||this.label==""){this.showLabel=false}else{this.labelOptions.label=this.label}if(this.showLabel==false){this.labelOptions.show=false}if(this.pad==0){this.pad=1}if(this.padMax==0){this.padMax=1}if(this.padMin==0){this.padMin=1}if(this.padMax==null){this.padMax=(this.pad-1)/2+1}if(this.padMin==null){this.padMin=(this.pad-1)/2+1}this.pad=this.padMax+this.padMin-1;if(this.min!=null||this.max!=null){this.autoscale=false}if(this.syncTicks==null&&this.name.indexOf("y")>-1){this.syncTicks=true}else{if(this.syncTicks==null){this.syncTicks=false}}this.renderer.init.call(this,this.rendererOptions)};w.prototype.draw=function(ah,ai){if(this.__ticks){this.__ticks=null}return this.renderer.draw.call(this,ah,ai)};w.prototype.set=function(){this.renderer.set.call(this)};w.prototype.pack=function(ai,ah){if(this.show){this.renderer.pack.call(this,ai,ah)}if(this._min==null){this._min=this.min;this._max=this.max;this._tickInterval=this.tickInterval;this._numberTicks=this.numberTicks;this.__ticks=this._ticks}};w.prototype.reset=function(){this.renderer.reset.call(this)};w.prototype.resetScale=function(ah){L.extend(true,this,{min:null,max:null,numberTicks:null,tickInterval:null,_ticks:[],ticks:[]},ah);this.resetDataBounds()};w.prototype.resetDataBounds=function(){var ao=this._dataBounds;ao.min=null;ao.max=null;var ai,ap,am;var aj=(this.show)?true:false;for(var al=0;al<this._series.length;al++){ap=this._series[al];if(ap.show||this.scaleToHiddenSeries){am=ap._plotData;if(ap._type==="line"&&ap.renderer.bands.show&&this.name.charAt(0)!=="x"){am=[[0,ap.renderer.bands._min],[1,ap.renderer.bands._max]]}var ah=1,an=1;if(ap._type!=null&&ap._type=="ohlc"){ah=3;an=2}for(var ak=0,ai=am.length;ak<ai;ak++){if(this.name=="xaxis"||this.name=="x2axis"){if((am[ak][0]!=null&&am[ak][0]<ao.min)||ao.min==null){ao.min=am[ak][0]}if((am[ak][0]!=null&&am[ak][0]>ao.max)||ao.max==null){ao.max=am[ak][0]}}else{if((am[ak][ah]!=null&&am[ak][ah]<ao.min)||ao.min==null){ao.min=am[ak][ah]}if((am[ak][an]!=null&&am[ak][an]>ao.max)||ao.max==null){ao.max=am[ak][an]}}}if(aj&&ap.renderer.constructor!==L.jqplot.BarRenderer){aj=false}else{if(aj&&this._options.hasOwnProperty("forceTickAt0")&&this._options.forceTickAt0==false){aj=false}else{if(aj&&ap.renderer.constructor===L.jqplot.BarRenderer){if(ap.barDirection=="vertical"&&this.name!="xaxis"&&this.name!="x2axis"){if(this._options.pad!=null||this._options.padMin!=null){aj=false}}else{if(ap.barDirection=="horizontal"&&(this.name=="xaxis"||this.name=="x2axis")){if(this._options.pad!=null||this._options.padMin!=null){aj=false}}}}}}}}if(aj&&this.renderer.constructor===L.jqplot.LinearAxisRenderer&&ao.min>=0){this.padMin=1;this.forceTickAt0=true}};function q(ah){L.jqplot.ElemContainer.call(this);this.show=false;this.location="ne";this.labels=[];this.showLabels=true;this.showSwatches=true;this.placement="insideGrid";this.xoffset=0;this.yoffset=0;this.border;this.background;this.textColor;this.fontFamily;this.fontSize;this.rowSpacing="0.5em";this.renderer=L.jqplot.TableLegendRenderer;this.rendererOptions={};this.preDraw=false;this.marginTop=null;this.marginRight=null;this.marginBottom=null;this.marginLeft=null;this.escapeHtml=false;this._series=[];L.extend(true,this,ah)}q.prototype=new L.jqplot.ElemContainer();q.prototype.constructor=q;q.prototype.setOptions=function(ah){L.extend(true,this,ah);if(this.placement=="inside"){this.placement="insideGrid"}if(this.xoffset>0){if(this.placement=="insideGrid"){switch(this.location){case"nw":case"w":case"sw":if(this.marginLeft==null){this.marginLeft=this.xoffset+"px"}this.marginRight="0px";break;case"ne":case"e":case"se":default:if(this.marginRight==null){this.marginRight=this.xoffset+"px"}this.marginLeft="0px";break}}else{if(this.placement=="outside"){switch(this.location){case"nw":case"w":case"sw":if(this.marginRight==null){this.marginRight=this.xoffset+"px"}this.marginLeft="0px";break;case"ne":case"e":case"se":default:if(this.marginLeft==null){this.marginLeft=this.xoffset+"px"}this.marginRight="0px";break}}}this.xoffset=0}if(this.yoffset>0){if(this.placement=="outside"){switch(this.location){case"sw":case"s":case"se":if(this.marginTop==null){this.marginTop=this.yoffset+"px"}this.marginBottom="0px";break;case"ne":case"n":case"nw":default:if(this.marginBottom==null){this.marginBottom=this.yoffset+"px"}this.marginTop="0px";break}}else{if(this.placement=="insideGrid"){switch(this.location){case"sw":case"s":case"se":if(this.marginBottom==null){this.marginBottom=this.yoffset+"px"}this.marginTop="0px";break;case"ne":case"n":case"nw":default:if(this.marginTop==null){this.marginTop=this.yoffset+"px"}this.marginBottom="0px";break}}}this.yoffset=0}};q.prototype.init=function(){if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.renderer.init.call(this,this.rendererOptions)};q.prototype.draw=function(ai,aj){for(var ah=0;ah<L.jqplot.preDrawLegendHooks.length;ah++){L.jqplot.preDrawLegendHooks[ah].call(this,ai)}return this.renderer.draw.call(this,ai,aj)};q.prototype.pack=function(ah){this.renderer.pack.call(this,ah)};function y(ah){L.jqplot.ElemContainer.call(this);this.text=ah;this.show=true;this.fontFamily;this.fontSize;this.textAlign;this.textColor;this.renderer=L.jqplot.DivTitleRenderer;this.rendererOptions={};this.escapeHtml=false}y.prototype=new L.jqplot.ElemContainer();y.prototype.constructor=y;y.prototype.init=function(){if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.renderer.init.call(this,this.rendererOptions)};y.prototype.draw=function(ah){return this.renderer.draw.call(this,ah)};y.prototype.pack=function(){this.renderer.pack.call(this)};function S(ah){ah=ah||{};L.jqplot.ElemContainer.call(this);this.show=true;this.xaxis="xaxis";this._xaxis;this.yaxis="yaxis";this._yaxis;this.gridBorderWidth=2;this.renderer=L.jqplot.LineRenderer;this.rendererOptions={};this.data=[];this.gridData=[];this.label="";this.showLabel=true;this.color;this.negativeColor;this.lineWidth=2.5;this.lineJoin="round";this.lineCap="round";this.linePattern="solid";this.shadow=true;this.shadowAngle=45;this.shadowOffset=1.25;this.shadowDepth=3;this.shadowAlpha="0.1";this.breakOnNull=false;this.markerRenderer=L.jqplot.MarkerRenderer;this.markerOptions={};this.showLine=true;this.showMarker=true;this.index;this.fill=false;this.fillColor;this.fillAlpha;this.fillAndStroke=false;this.disableStack=false;this._stack=false;this.neighborThreshold=4;this.fillToZero=false;this.fillToValue=0;this.fillAxis="y";this.useNegativeColors=true;this._stackData=[];this._plotData=[];this._plotValues={x:[],y:[]};this._intervals={x:{},y:{}};this._prevPlotData=[];this._prevGridData=[];this._stackAxis="y";this._primaryAxis="_xaxis";this.canvas=new L.jqplot.GenericCanvas();this.shadowCanvas=new L.jqplot.GenericCanvas();this.plugins={};this._sumy=0;this._sumx=0;this._type=""}S.prototype=new L.jqplot.ElemContainer();S.prototype.constructor=S;S.prototype.init=function(ak,ao,am){this.index=ak;this.gridBorderWidth=ao;var an=this.data;var aj=[],al,ah;for(al=0,ah=an.length;al<ah;al++){if(!this.breakOnNull){if(an[al]==null||an[al][0]==null||an[al][1]==null){continue}else{aj.push(an[al])}}else{aj.push(an[al])}}this.data=aj;if(!this.color){this.color=am.colorGenerator.get(this.index)}if(!this.negativeColor){this.negativeColor=am.negativeColorGenerator.get(this.index)}if(!this.fillColor){this.fillColor=this.color}if(this.fillAlpha){var ai=L.jqplot.normalize2rgb(this.fillColor);var ai=L.jqplot.getColorComponents(ai);this.fillColor="rgba("+ai[0]+","+ai[1]+","+ai[2]+","+this.fillAlpha+")"}if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.renderer.init.call(this,this.rendererOptions,am);this.markerRenderer=new this.markerRenderer();if(!this.markerOptions.color){this.markerOptions.color=this.color}if(this.markerOptions.show==null){this.markerOptions.show=this.showMarker}this.showMarker=this.markerOptions.show;this.markerRenderer.init(this.markerOptions)};S.prototype.draw=function(an,ak,am){var ai=(ak==u)?{}:ak;an=(an==u)?this.canvas._ctx:an;var ah,al,aj;for(ah=0;ah<L.jqplot.preDrawSeriesHooks.length;ah++){L.jqplot.preDrawSeriesHooks[ah].call(this,an,ai)}if(this.show){this.renderer.setGridData.call(this,am);if(!ai.preventJqPlotSeriesDrawTrigger){L(an.canvas).trigger("jqplotSeriesDraw",[this.data,this.gridData])}al=[];if(ai.data){al=ai.data}else{if(!this._stack){al=this.data}else{al=this._plotData}}aj=ai.gridData||this.renderer.makeGridData.call(this,al,am);if(this._type==="line"&&this.renderer.smooth&&this.renderer._smoothedData.length){aj=this.renderer._smoothedData}this.renderer.draw.call(this,an,aj,ai,am)}for(ah=0;ah<L.jqplot.postDrawSeriesHooks.length;ah++){L.jqplot.postDrawSeriesHooks[ah].call(this,an,ai,am)}an=ak=am=ah=al=aj=null};S.prototype.drawShadow=function(an,ak,am){var ai=(ak==u)?{}:ak;an=(an==u)?this.shadowCanvas._ctx:an;var ah,al,aj;for(ah=0;ah<L.jqplot.preDrawSeriesShadowHooks.length;ah++){L.jqplot.preDrawSeriesShadowHooks[ah].call(this,an,ai)}if(this.shadow){this.renderer.setGridData.call(this,am);al=[];if(ai.data){al=ai.data}else{if(!this._stack){al=this.data}else{al=this._plotData}}aj=ai.gridData||this.renderer.makeGridData.call(this,al,am);this.renderer.drawShadow.call(this,an,aj,ai,am)}for(ah=0;ah<L.jqplot.postDrawSeriesShadowHooks.length;ah++){L.jqplot.postDrawSeriesShadowHooks[ah].call(this,an,ai)}an=ak=am=ah=al=aj=null};S.prototype.toggleDisplay=function(ai,ak){var ah,aj;if(ai.data.series){ah=ai.data.series}else{ah=this}if(ai.data.speed){aj=ai.data.speed}if(aj){if(ah.canvas._elem.is(":hidden")||!ah.show){ah.show=true;ah.canvas._elem.removeClass("jqplot-series-hidden");if(ah.shadowCanvas._elem){ah.shadowCanvas._elem.fadeIn(aj)}ah.canvas._elem.fadeIn(aj,ak);ah.canvas._elem.nextAll(".jqplot-point-label.jqplot-series-"+ah.index).fadeIn(aj)}else{ah.show=false;ah.canvas._elem.addClass("jqplot-series-hidden");if(ah.shadowCanvas._elem){ah.shadowCanvas._elem.fadeOut(aj)}ah.canvas._elem.fadeOut(aj,ak);ah.canvas._elem.nextAll(".jqplot-point-label.jqplot-series-"+ah.index).fadeOut(aj)}}else{if(ah.canvas._elem.is(":hidden")||!ah.show){ah.show=true;ah.canvas._elem.removeClass("jqplot-series-hidden");if(ah.shadowCanvas._elem){ah.shadowCanvas._elem.show()}ah.canvas._elem.show(0,ak);ah.canvas._elem.nextAll(".jqplot-point-label.jqplot-series-"+ah.index).show()}else{ah.show=false;ah.canvas._elem.addClass("jqplot-series-hidden");if(ah.shadowCanvas._elem){ah.shadowCanvas._elem.hide()}ah.canvas._elem.hide(0,ak);ah.canvas._elem.nextAll(".jqplot-point-label.jqplot-series-"+ah.index).hide()}}};function M(){L.jqplot.ElemContainer.call(this);this.drawGridlines=true;this.gridLineColor="#cccccc";this.gridLineWidth=1;this.background="#fffdf6";this.borderColor="#999999";this.borderWidth=2;this.drawBorder=true;this.shadow=true;this.shadowAngle=45;this.shadowOffset=1.5;this.shadowWidth=3;this.shadowDepth=3;this.shadowColor=null;this.shadowAlpha="0.07";this._left;this._top;this._right;this._bottom;this._width;this._height;this._axes=[];this.renderer=L.jqplot.CanvasGridRenderer;this.rendererOptions={};this._offsets={top:null,bottom:null,left:null,right:null}}M.prototype=new L.jqplot.ElemContainer();M.prototype.constructor=M;M.prototype.init=function(){if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.renderer.init.call(this,this.rendererOptions)};M.prototype.createElement=function(ah,ai){this._offsets=ah;return this.renderer.createElement.call(this,ai)};M.prototype.draw=function(){this.renderer.draw.call(this)};L.jqplot.GenericCanvas=function(){L.jqplot.ElemContainer.call(this);this._ctx};L.jqplot.GenericCanvas.prototype=new L.jqplot.ElemContainer();L.jqplot.GenericCanvas.prototype.constructor=L.jqplot.GenericCanvas;L.jqplot.GenericCanvas.prototype.createElement=function(al,aj,ai,am){this._offsets=al;var ah="jqplot";if(aj!=u){ah=aj}var ak;ak=am.canvasManager.getCanvas();if(ai!=null){this._plotDimensions=ai}ak.width=this._plotDimensions.width-this._offsets.left-this._offsets.right;ak.height=this._plotDimensions.height-this._offsets.top-this._offsets.bottom;this._elem=L(ak);this._elem.css({position:"absolute",left:this._offsets.left,top:this._offsets.top});this._elem.addClass(ah);ak=am.canvasManager.initCanvas(ak);ak=null;return this._elem};L.jqplot.GenericCanvas.prototype.setContext=function(){this._ctx=this._elem.get(0).getContext("2d");return this._ctx};L.jqplot.GenericCanvas.prototype.resetCanvas=function(){if(this._elem){if(L.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==u){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce()}this._ctx=null};L.jqplot.HooksManager=function(){this.hooks=[];this.args=[]};L.jqplot.HooksManager.prototype.addOnce=function(ak,ai){ai=ai||[];var al=false;for(var aj=0,ah=this.hooks.length;aj<ah;aj++){if(this.hooks[aj]==ak){al=true}}if(!al){this.hooks.push(ak);this.args.push(ai)}};L.jqplot.HooksManager.prototype.add=function(ai,ah){ah=ah||[];this.hooks.push(ai);this.args.push(ah)};L.jqplot.EventListenerManager=function(){this.hooks=[]};L.jqplot.EventListenerManager.prototype.addOnce=function(al,ak){var am=false,aj,ai;for(var ai=0,ah=this.hooks.length;ai<ah;ai++){aj=this.hooks[ai];if(aj[0]==al&&aj[1]==ak){am=true}}if(!am){this.hooks.push([al,ak])}};L.jqplot.EventListenerManager.prototype.add=function(ai,ah){this.hooks.push([ai,ah])};var U=["yMidAxis","xaxis","yaxis","x2axis","y2axis","y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis"];function R(){this.animate=false;this.animateReplot=false;this.axes={xaxis:new w("xaxis"),yaxis:new w("yaxis"),x2axis:new w("x2axis"),y2axis:new w("y2axis"),y3axis:new w("y3axis"),y4axis:new w("y4axis"),y5axis:new w("y5axis"),y6axis:new w("y6axis"),y7axis:new w("y7axis"),y8axis:new w("y8axis"),y9axis:new w("y9axis"),yMidAxis:new w("yMidAxis")};this.baseCanvas=new L.jqplot.GenericCanvas();this.captureRightClick=false;this.data=[];this.dataRenderer;this.dataRendererOptions;this.defaults={axesDefaults:{},axes:{xaxis:{},yaxis:{},x2axis:{},y2axis:{},y3axis:{},y4axis:{},y5axis:{},y6axis:{},y7axis:{},y8axis:{},y9axis:{},yMidAxis:{}},seriesDefaults:{},series:[]};this.defaultAxisStart=1;this.drawIfHidden=false;this.eventCanvas=new L.jqplot.GenericCanvas();this.fillBetween={series1:null,series2:null,color:null,baseSeries:0,fill:true};this.fontFamily;this.fontSize;this.grid=new M();this.legend=new q();this.noDataIndicator={show:false,indicator:"Loading Data...",axes:{xaxis:{min:0,max:10,tickInterval:2,show:true},yaxis:{min:0,max:12,tickInterval:3,show:true}}};this.negativeSeriesColors=L.jqplot.config.defaultNegativeColors;this.options={};this.previousSeriesStack=[];this.plugins={};this.series=[];this.seriesStack=[];this.seriesColors=L.jqplot.config.defaultColors;this.sortData=true;this.stackSeries=false;this.syncXTicks=true;this.syncYTicks=true;this.target=null;this.targetId=null;this.textColor;this.title=new y();this._drawCount=0;this._sumy=0;this._sumx=0;this._stackData=[];this._plotData=[];this._width=null;this._height=null;this._plotDimensions={height:null,width:null};this._gridPadding={top:null,right:null,bottom:null,left:null};this._defaultGridPadding={top:10,right:10,bottom:23,left:10};this._addDomReference=L.jqplot.config.addDomReference;this.preInitHooks=new L.jqplot.HooksManager();this.postInitHooks=new L.jqplot.HooksManager();this.preParseOptionsHooks=new L.jqplot.HooksManager();this.postParseOptionsHooks=new L.jqplot.HooksManager();this.preDrawHooks=new L.jqplot.HooksManager();this.postDrawHooks=new L.jqplot.HooksManager();this.preDrawSeriesHooks=new L.jqplot.HooksManager();this.postDrawSeriesHooks=new L.jqplot.HooksManager();this.preDrawLegendHooks=new L.jqplot.HooksManager();this.addLegendRowHooks=new L.jqplot.HooksManager();this.preSeriesInitHooks=new L.jqplot.HooksManager();this.postSeriesInitHooks=new L.jqplot.HooksManager();this.preParseSeriesOptionsHooks=new L.jqplot.HooksManager();this.postParseSeriesOptionsHooks=new L.jqplot.HooksManager();this.eventListenerHooks=new L.jqplot.EventListenerManager();this.preDrawSeriesShadowHooks=new L.jqplot.HooksManager();this.postDrawSeriesShadowHooks=new L.jqplot.HooksManager();this.colorGenerator=new L.jqplot.ColorGenerator();this.negativeColorGenerator=new L.jqplot.ColorGenerator();this.canvasManager=new L.jqplot.CanvasManager();this.themeEngine=new L.jqplot.ThemeEngine();var aj=0;this.init=function(av,ar,ay){ay=ay||{};for(var at=0;at<L.jqplot.preInitHooks.length;at++){L.jqplot.preInitHooks[at].call(this,av,ar,ay)}for(var at=0;at<this.preInitHooks.hooks.length;at++){this.preInitHooks.hooks[at].call(this,av,ar,ay)}this.targetId="#"+av;this.target=L("#"+av);if(this._addDomReference){this.target.data("jqplot",this)}this.target.removeClass("jqplot-error");if(!this.target.get(0)){throw new Error("No plot target specified")}if(this.target.css("position")=="static"){this.target.css("position","relative")}if(!this.target.hasClass("jqplot-target")){this.target.addClass("jqplot-target")}if(!this.target.height()){var au;if(ay&&ay.height){au=parseInt(ay.height,10)}else{if(this.target.attr("data-height")){au=parseInt(this.target.attr("data-height"),10)}else{au=parseInt(L.jqplot.config.defaultHeight,10)}}this._height=au;this.target.css("height",au+"px")}else{this._height=au=this.target.height()}if(!this.target.width()){var aw;if(ay&&ay.width){aw=parseInt(ay.width,10)}else{if(this.target.attr("data-width")){aw=parseInt(this.target.attr("data-width"),10)}else{aw=parseInt(L.jqplot.config.defaultWidth,10)}}this._width=aw;this.target.css("width",aw+"px")}else{this._width=aw=this.target.width()}for(var at=0,ap=U.length;at<ap;at++){this.axes[U[at]]=new w(U[at])}this._plotDimensions.height=this._height;this._plotDimensions.width=this._width;this.grid._plotDimensions=this._plotDimensions;this.title._plotDimensions=this._plotDimensions;this.baseCanvas._plotDimensions=this._plotDimensions;this.eventCanvas._plotDimensions=this._plotDimensions;this.legend._plotDimensions=this._plotDimensions;if(this._height<=0||this._width<=0||!this._height||!this._width){throw new Error("Canvas dimension not set")}if(ay.dataRenderer&&L.isFunction(ay.dataRenderer)){if(ay.dataRendererOptions){this.dataRendererOptions=ay.dataRendererOptions}this.dataRenderer=ay.dataRenderer;ar=this.dataRenderer(ar,this,this.dataRendererOptions)}if(ay.noDataIndicator&&L.isPlainObject(ay.noDataIndicator)){L.extend(true,this.noDataIndicator,ay.noDataIndicator)}if(ar==null||L.isArray(ar)==false||ar.length==0||L.isArray(ar[0])==false||ar[0].length==0){if(this.noDataIndicator.show==false){throw new Error("No data specified")}else{for(var al in this.noDataIndicator.axes){for(var an in this.noDataIndicator.axes[al]){this.axes[al][an]=this.noDataIndicator.axes[al][an]}}this.postDrawHooks.add(function(){var aD=this.eventCanvas.getHeight();var aA=this.eventCanvas.getWidth();var az=L('<div class="jqplot-noData-container" style="position:absolute;"></div>');this.target.append(az);az.height(aD);az.width(aA);az.css("top",this.eventCanvas._offsets.top);az.css("left",this.eventCanvas._offsets.left);var aC=L('<div class="jqplot-noData-contents" style="text-align:center; position:relative; margin-left:auto; margin-right:auto;"></div>');az.append(aC);aC.html(this.noDataIndicator.indicator);var aB=aC.height();var ax=aC.width();aC.height(aB);aC.width(ax);aC.css("top",(aD-aB)/2+"px")})}}this.data=L.extend(true,[],ar);this.parseOptions(ay);if(this.textColor){this.target.css("color",this.textColor)}if(this.fontFamily){this.target.css("font-family",this.fontFamily)}if(this.fontSize){this.target.css("font-size",this.fontSize)}this.title.init();this.legend.init();this._sumy=0;this._sumx=0;this.computePlotData();for(var at=0;at<this.series.length;at++){this.seriesStack.push(at);this.previousSeriesStack.push(at);this.series[at].shadowCanvas._plotDimensions=this._plotDimensions;this.series[at].canvas._plotDimensions=this._plotDimensions;for(var aq=0;aq<L.jqplot.preSeriesInitHooks.length;aq++){L.jqplot.preSeriesInitHooks[aq].call(this.series[at],av,this.data,this.options.seriesDefaults,this.options.series[at],this)}for(var aq=0;aq<this.preSeriesInitHooks.hooks.length;aq++){this.preSeriesInitHooks.hooks[aq].call(this.series[at],av,this.data,this.options.seriesDefaults,this.options.series[at],this)}this.series[at]._plotDimensions=this._plotDimensions;this.series[at].init(at,this.grid.borderWidth,this);for(var aq=0;aq<L.jqplot.postSeriesInitHooks.length;aq++){L.jqplot.postSeriesInitHooks[aq].call(this.series[at],av,this.data,this.options.seriesDefaults,this.options.series[at],this)}for(var aq=0;aq<this.postSeriesInitHooks.hooks.length;aq++){this.postSeriesInitHooks.hooks[aq].call(this.series[at],av,this.data,this.options.seriesDefaults,this.options.series[at],this)}this._sumy+=this.series[at]._sumy;this._sumx+=this.series[at]._sumx}var am,ao;for(var at=0,ap=U.length;at<ap;at++){am=U[at];ao=this.axes[am];ao._plotDimensions=this._plotDimensions;ao.init();if(this.axes[am].borderColor==null){if(am.charAt(0)!=="x"&&ao.useSeriesColor===true&&ao.show){ao.borderColor=ao._series[0].color}else{ao.borderColor=this.grid.borderColor}}}if(this.sortData){ah(this.series)}this.grid.init();this.grid._axes=this.axes;this.legend._series=this.series;for(var at=0;at<L.jqplot.postInitHooks.length;at++){L.jqplot.postInitHooks[at].call(this,av,this.data,ay)}for(var at=0;at<this.postInitHooks.hooks.length;at++){this.postInitHooks.hooks[at].call(this,av,this.data,ay)}};this.resetAxesScale=function(aq,am){var ao=am||{};var ap=aq||this.axes;if(ap===true){ap=this.axes}if(L.isArray(ap)){for(var an=0;an<ap.length;an++){this.axes[ap[an]].resetScale(ao[ap[an]])}}else{if(typeof(ap)==="object"){for(var al in ap){this.axes[al].resetScale(ao[al])}}}};this.reInitialize=function(au,al){var ay=L.extend(true,{},this.options,al);var aw=this.targetId.substr(1);var ar=(au==null)?this.data:au;for(var av=0;av<L.jqplot.preInitHooks.length;av++){L.jqplot.preInitHooks[av].call(this,aw,ar,ay)}for(var av=0;av<this.preInitHooks.hooks.length;av++){this.preInitHooks.hooks[av].call(this,aw,ar,ay)}this._height=this.target.height();this._width=this.target.width();if(this._height<=0||this._width<=0||!this._height||!this._width){throw new Error("Target dimension not set")}this._plotDimensions.height=this._height;this._plotDimensions.width=this._width;this.grid._plotDimensions=this._plotDimensions;this.title._plotDimensions=this._plotDimensions;this.baseCanvas._plotDimensions=this._plotDimensions;this.eventCanvas._plotDimensions=this._plotDimensions;this.legend._plotDimensions=this._plotDimensions;var am,ax,at,ao;for(var av=0,aq=U.length;av<aq;av++){am=U[av];ao=this.axes[am];ax=ao._ticks;for(var at=0,ap=ax.length;at<ap;at++){var an=ax[at]._elem;if(an){if(L.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==u){window.G_vmlCanvasManager.uninitElement(an.get(0))}an.emptyForce();an=null;ax._elem=null}}ax=null;delete ao.ticks;delete ao._ticks;this.axes[am]=new w(am);this.axes[am]._plotWidth=this._width;this.axes[am]._plotHeight=this._height}if(au){if(ay.dataRenderer&&L.isFunction(ay.dataRenderer)){if(ay.dataRendererOptions){this.dataRendererOptions=ay.dataRendererOptions}this.dataRenderer=ay.dataRenderer;au=this.dataRenderer(au,this,this.dataRendererOptions)}this.data=L.extend(true,[],au)}if(al){this.parseOptions(ay)}this.title._plotWidth=this._width;if(this.textColor){this.target.css("color",this.textColor)}if(this.fontFamily){this.target.css("font-family",this.fontFamily)}if(this.fontSize){this.target.css("font-size",this.fontSize)}this.title.init();this.legend.init();this._sumy=0;this._sumx=0;this.seriesStack=[];this.previousSeriesStack=[];this.computePlotData();for(var av=0,aq=this.series.length;av<aq;av++){this.seriesStack.push(av);this.previousSeriesStack.push(av);this.series[av].shadowCanvas._plotDimensions=this._plotDimensions;this.series[av].canvas._plotDimensions=this._plotDimensions;for(var at=0;at<L.jqplot.preSeriesInitHooks.length;at++){L.jqplot.preSeriesInitHooks[at].call(this.series[av],aw,this.data,this.options.seriesDefaults,this.options.series[av],this)}for(var at=0;at<this.preSeriesInitHooks.hooks.length;at++){this.preSeriesInitHooks.hooks[at].call(this.series[av],aw,this.data,this.options.seriesDefaults,this.options.series[av],this)}this.series[av]._plotDimensions=this._plotDimensions;this.series[av].init(av,this.grid.borderWidth,this);for(var at=0;at<L.jqplot.postSeriesInitHooks.length;at++){L.jqplot.postSeriesInitHooks[at].call(this.series[av],aw,this.data,this.options.seriesDefaults,this.options.series[av],this)}for(var at=0;at<this.postSeriesInitHooks.hooks.length;at++){this.postSeriesInitHooks.hooks[at].call(this.series[av],aw,this.data,this.options.seriesDefaults,this.options.series[av],this)}this._sumy+=this.series[av]._sumy;this._sumx+=this.series[av]._sumx}for(var av=0,aq=U.length;av<aq;av++){am=U[av];ao=this.axes[am];ao._plotDimensions=this._plotDimensions;ao.init();if(ao.borderColor==null){if(am.charAt(0)!=="x"&&ao.useSeriesColor===true&&ao.show){ao.borderColor=ao._series[0].color}else{ao.borderColor=this.grid.borderColor}}}if(this.sortData){ah(this.series)}this.grid.init();this.grid._axes=this.axes;this.legend._series=this.series;for(var av=0,aq=L.jqplot.postInitHooks.length;av<aq;av++){L.jqplot.postInitHooks[av].call(this,aw,this.data,ay)}for(var av=0,aq=this.postInitHooks.hooks.length;av<aq;av++){this.postInitHooks.hooks[av].call(this,aw,this.data,ay)}};this.quickInit=function(){this._height=this.target.height();this._width=this.target.width();if(this._height<=0||this._width<=0||!this._height||!this._width){throw new Error("Target dimension not set")}this._plotDimensions.height=this._height;this._plotDimensions.width=this._width;this.grid._plotDimensions=this._plotDimensions;this.title._plotDimensions=this._plotDimensions;this.baseCanvas._plotDimensions=this._plotDimensions;this.eventCanvas._plotDimensions=this._plotDimensions;this.legend._plotDimensions=this._plotDimensions;for(var aq in this.axes){this.axes[aq]._plotWidth=this._width;this.axes[aq]._plotHeight=this._height}this.title._plotWidth=this._width;if(this.textColor){this.target.css("color",this.textColor)}if(this.fontFamily){this.target.css("font-family",this.fontFamily)}if(this.fontSize){this.target.css("font-size",this.fontSize)}this._sumy=0;this._sumx=0;this.computePlotData();for(var ao=0;ao<this.series.length;ao++){if(this.series[ao]._type==="line"&&this.series[ao].renderer.bands.show){this.series[ao].renderer.initBands.call(this.series[ao],this.series[ao].renderer.options,this)}this.series[ao]._plotDimensions=this._plotDimensions;this.series[ao].canvas._plotDimensions=this._plotDimensions;this._sumy+=this.series[ao]._sumy;this._sumx+=this.series[ao]._sumx}var am;for(var al=0;al<12;al++){am=U[al];var an=this.axes[am]._ticks;for(var ao=0;ao<an.length;ao++){var ap=an[ao]._elem;if(ap){if(L.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==u){window.G_vmlCanvasManager.uninitElement(ap.get(0))}ap.emptyForce();ap=null;an._elem=null}}an=null;this.axes[am]._plotDimensions=this._plotDimensions;this.axes[am]._ticks=[]}if(this.sortData){ah(this.series)}this.grid._axes=this.axes;this.legend._series=this.series};function ah(ap){var au,av,aw,al,at;for(var aq=0;aq<ap.length;aq++){var am;var ar=[ap[aq].data,ap[aq]._stackData,ap[aq]._plotData,ap[aq]._prevPlotData];for(var an=0;an<4;an++){am=true;au=ar[an];if(ap[aq]._stackAxis=="x"){for(var ao=0;ao<au.length;ao++){if(typeof(au[ao][1])!="number"){am=false;break}}if(am){au.sort(function(ay,ax){return ay[1]-ax[1]})}}else{for(var ao=0;ao<au.length;ao++){if(typeof(au[ao][0])!="number"){am=false;break}}if(am){au.sort(function(ay,ax){return ay[0]-ax[0]})}}}}}this.computePlotData=function(){this._plotData=[];this._stackData=[];var at,au,ao;for(au=0,ao=this.series.length;au<ao;au++){at=this.series[au];this._plotData.push([]);this._stackData.push([]);var am=at.data;this._plotData[au]=L.extend(true,[],am);this._stackData[au]=L.extend(true,[],am);at._plotData=this._plotData[au];at._stackData=this._stackData[au];var ax={x:[],y:[]};if(this.stackSeries&&!at.disableStack){at._stack=true;var av=(at._stackAxis==="x")?0:1;for(var ap=0,al=am.length;ap<al;ap++){var aw=am[ap][av];if(aw==null){aw=0}this._plotData[au][ap][av]=aw;this._stackData[au][ap][av]=aw;if(au>0){for(var aq=au;aq--;){var an=this._plotData[aq][ap][av];if(aw*an>=0){this._plotData[au][ap][av]+=an;this._stackData[au][ap][av]+=an;break}}}}}else{for(var ar=0;ar<at.data.length;ar++){ax.x.push(at.data[ar][0]);ax.y.push(at.data[ar][1])}this._stackData.push(at.data);this.series[au]._stackData=at.data;this._plotData.push(at.data);at._plotData=at.data;at._plotValues=ax}if(au>0){at._prevPlotData=this.series[au-1]._plotData}at._sumy=0;at._sumx=0;for(ar=at.data.length-1;ar>-1;ar--){at._sumy+=at.data[ar][1];at._sumx+=at.data[ar][0]}}};this.populatePlotData=function(au,av){this._plotData=[];this._stackData=[];au._stackData=[];au._plotData=[];var ay={x:[],y:[]};if(this.stackSeries&&!au.disableStack){au._stack=true;var ax=(au._stackAxis==="x")?0:1;var az=L.extend(true,[],au.data);var aA=L.extend(true,[],au.data);var an,am,ao,aw,al;for(var ar=0;ar<av;ar++){var ap=this.series[ar].data;for(var aq=0;aq<ap.length;aq++){ao=ap[aq];an=(ao[0]!=null)?ao[0]:0;am=(ao[1]!=null)?ao[1]:0;az[aq][0]+=an;az[aq][1]+=am;aw=(ax)?am:an;if(au.data[aq][ax]*aw>=0){aA[aq][ax]+=aw}}}for(var at=0;at<aA.length;at++){ay.x.push(aA[at][0]);ay.y.push(aA[at][1])}this._plotData.push(aA);this._stackData.push(az);au._stackData=az;au._plotData=aA;au._plotValues=ay}else{for(var at=0;at<au.data.length;at++){ay.x.push(au.data[at][0]);ay.y.push(au.data[at][1])}this._stackData.push(au.data);this.series[av]._stackData=au.data;this._plotData.push(au.data);au._plotData=au.data;au._plotValues=ay}if(av>0){au._prevPlotData=this.series[av-1]._plotData}au._sumy=0;au._sumx=0;for(at=au.data.length-1;at>-1;at--){au._sumy+=au.data[at][1];au._sumx+=au.data[at][0]}};this.getNextSeriesColor=(function(am){var al=0;var an=am.seriesColors;return function(){if(al<an.length){return an[al++]}else{al=0;return an[al++]}}})(this);this.parseOptions=function(ay){for(var at=0;at<this.preParseOptionsHooks.hooks.length;at++){this.preParseOptionsHooks.hooks[at].call(this,ay)}for(var at=0;at<L.jqplot.preParseOptionsHooks.length;at++){L.jqplot.preParseOptionsHooks[at].call(this,ay)}this.options=L.extend(true,{},this.defaults,ay);var am=this.options;this.animate=am.animate;this.animateReplot=am.animateReplot;this.stackSeries=am.stackSeries;if(L.isPlainObject(am.fillBetween)){var ax=["series1","series2","color","baseSeries","fill"],au;for(var at=0,aq=ax.length;at<aq;at++){au=ax[at];if(am.fillBetween[au]!=null){this.fillBetween[au]=am.fillBetween[au]}}}if(am.seriesColors){this.seriesColors=am.seriesColors}if(am.negativeSeriesColors){this.negativeSeriesColors=am.negativeSeriesColors}if(am.captureRightClick){this.captureRightClick=am.captureRightClick}this.defaultAxisStart=(ay&&ay.defaultAxisStart!=null)?ay.defaultAxisStart:this.defaultAxisStart;this.colorGenerator.setColors(this.seriesColors);this.negativeColorGenerator.setColors(this.negativeSeriesColors);L.extend(true,this._gridPadding,am.gridPadding);this.sortData=(am.sortData!=null)?am.sortData:this.sortData;for(var at=0;at<12;at++){var an=U[at];var ap=this.axes[an];ap._options=L.extend(true,{},am.axesDefaults,am.axes[an]);L.extend(true,ap,am.axesDefaults,am.axes[an]);ap._plotWidth=this._width;ap._plotHeight=this._height}var aw=function(aD,aB,aE){var aA=[];var aC,az;aB=aB||"vertical";if(!L.isArray(aD[0])){for(aC=0,az=aD.length;aC<az;aC++){if(aB=="vertical"){aA.push([aE+aC,aD[aC]])}else{aA.push([aD[aC],aE+aC])}}}else{L.extend(true,aA,aD)}return aA};var av=0;this.series=[];for(var at=0;at<this.data.length;at++){var al=L.extend(true,{index:at},{seriesColors:this.seriesColors,negativeSeriesColors:this.negativeSeriesColors},this.options.seriesDefaults,this.options.series[at],{rendererOptions:{animation:{show:this.animate}}});var ax=new S(al);for(var ar=0;ar<L.jqplot.preParseSeriesOptionsHooks.length;ar++){L.jqplot.preParseSeriesOptionsHooks[ar].call(ax,this.options.seriesDefaults,this.options.series[at])}for(var ar=0;ar<this.preParseSeriesOptionsHooks.hooks.length;ar++){this.preParseSeriesOptionsHooks.hooks[ar].call(ax,this.options.seriesDefaults,this.options.series[at])}L.extend(true,ax,al);var ao="vertical";if(ax.renderer===L.jqplot.BarRenderer&&ax.rendererOptions&&ax.rendererOptions.barDirection=="horizontal"){ao="horizontal";ax._stackAxis="x";ax._primaryAxis="_yaxis"}ax.data=aw(this.data[at],ao,this.defaultAxisStart);switch(ax.xaxis){case"xaxis":ax._xaxis=this.axes.xaxis;break;case"x2axis":ax._xaxis=this.axes.x2axis;break;default:break}ax._yaxis=this.axes[ax.yaxis];ax._xaxis._series.push(ax);ax._yaxis._series.push(ax);if(ax.show){ax._xaxis.show=true;ax._yaxis.show=true}else{if(ax._xaxis.scaleToHiddenSeries){ax._xaxis.show=true}if(ax._yaxis.scaleToHiddenSeries){ax._yaxis.show=true}}if(!ax.label){ax.label="Series "+(at+1).toString()}this.series.push(ax);for(var ar=0;ar<L.jqplot.postParseSeriesOptionsHooks.length;ar++){L.jqplot.postParseSeriesOptionsHooks[ar].call(this.series[at],this.options.seriesDefaults,this.options.series[at])}for(var ar=0;ar<this.postParseSeriesOptionsHooks.hooks.length;ar++){this.postParseSeriesOptionsHooks.hooks[ar].call(this.series[at],this.options.seriesDefaults,this.options.series[at])}}L.extend(true,this.grid,this.options.grid);for(var at=0,aq=U.length;at<aq;at++){var an=U[at];var ap=this.axes[an];if(ap.borderWidth==null){ap.borderWidth=this.grid.borderWidth}}if(typeof this.options.title=="string"){this.title.text=this.options.title}else{if(typeof this.options.title=="object"){L.extend(true,this.title,this.options.title)}}this.title._plotWidth=this._width;this.legend.setOptions(this.options.legend);for(var at=0;at<L.jqplot.postParseOptionsHooks.length;at++){L.jqplot.postParseOptionsHooks[at].call(this,ay)}for(var at=0;at<this.postParseOptionsHooks.hooks.length;at++){this.postParseOptionsHooks.hooks[at].call(this,ay)}};this.destroy=function(){this.canvasManager.freeAllCanvases();if(this.eventCanvas&&this.eventCanvas._elem){this.eventCanvas._elem.unbind()}this.target.empty();this.target[0].innerHTML=""};this.replot=function(am){var an=am||{};var ap=an.data||null;var al=(an.clear===false)?false:true;var ao=an.resetAxes||false;delete an.data;delete an.clear;delete an.resetAxes;this.target.trigger("jqplotPreReplot");if(al){this.destroy()}if(ap||!L.isEmptyObject(an)){this.reInitialize(ap,an)}else{this.quickInit()}if(ao){this.resetAxesScale(ao,an.axes)}this.draw();this.target.trigger("jqplotPostReplot")};this.redraw=function(al){al=(al!=null)?al:true;this.target.trigger("jqplotPreRedraw");if(al){this.canvasManager.freeAllCanvases();this.eventCanvas._elem.unbind();this.target.empty()}for(var an in this.axes){this.axes[an]._ticks=[]}this.computePlotData();this._sumy=0;this._sumx=0;for(var am=0,ao=this.series.length;am<ao;am++){this._sumy+=this.series[am]._sumy;this._sumx+=this.series[am]._sumx}this.draw();this.target.trigger("jqplotPostRedraw")};this.draw=function(){if(this.drawIfHidden||this.target.is(":visible")){this.target.trigger("jqplotPreDraw");var aH,aF,aE,ao;for(aH=0,aE=L.jqplot.preDrawHooks.length;aH<aE;aH++){L.jqplot.preDrawHooks[aH].call(this)}for(aH=0,aE=this.preDrawHooks.hooks.length;aH<aE;aH++){this.preDrawHooks.hooks[aH].apply(this,this.preDrawSeriesHooks.args[aH])}this.target.append(this.baseCanvas.createElement({left:0,right:0,top:0,bottom:0},"jqplot-base-canvas",null,this));this.baseCanvas.setContext();this.target.append(this.title.draw());this.title.pack({top:0,left:0});var aL=this.legend.draw({},this);var al={top:0,left:0,bottom:0,right:0};if(this.legend.placement=="outsideGrid"){this.target.append(aL);switch(this.legend.location){case"n":al.top+=this.legend.getHeight();break;case"s":al.bottom+=this.legend.getHeight();break;case"ne":case"e":case"se":al.right+=this.legend.getWidth();break;case"nw":case"w":case"sw":al.left+=this.legend.getWidth();break;default:al.right+=this.legend.getWidth();break}aL=aL.detach()}var ar=this.axes;var aM;for(aH=0;aH<12;aH++){aM=U[aH];this.target.append(ar[aM].draw(this.baseCanvas._ctx,this));ar[aM].set()}if(ar.yaxis.show){al.left+=ar.yaxis.getWidth()}var aG=["y2axis","y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis"];var az=[0,0,0,0,0,0,0,0];var aC=0;var aB;for(aB=0;aB<8;aB++){if(ar[aG[aB]].show){aC+=ar[aG[aB]].getWidth();az[aB]=aC}}al.right+=aC;if(ar.x2axis.show){al.top+=ar.x2axis.getHeight()}if(this.title.show){al.top+=this.title.getHeight()}if(ar.xaxis.show){al.bottom+=ar.xaxis.getHeight()}if(this.options.gridDimensions&&L.isPlainObject(this.options.gridDimensions)){var at=parseInt(this.options.gridDimensions.width,10)||0;var aI=parseInt(this.options.gridDimensions.height,10)||0;var an=(this._width-al.left-al.right-at)/2;var aK=(this._height-al.top-al.bottom-aI)/2;if(aK>=0&&an>=0){al.top+=aK;al.bottom+=aK;al.left+=an;al.right+=an}}var am=["top","bottom","left","right"];for(var aB in am){if(this._gridPadding[am[aB]]==null&&al[am[aB]]>0){this._gridPadding[am[aB]]=al[am[aB]]}else{if(this._gridPadding[am[aB]]==null){this._gridPadding[am[aB]]=this._defaultGridPadding[am[aB]]}}}var aA=this._gridPadding;if(this.legend.placement==="outsideGrid"){aA={top:this.title.getHeight(),left:0,right:0,bottom:0};if(this.legend.location==="s"){aA.left=this._gridPadding.left;aA.right=this._gridPadding.right}}ar.xaxis.pack({position:"absolute",bottom:this._gridPadding.bottom-ar.xaxis.getHeight(),left:0,width:this._width},{min:this._gridPadding.left,max:this._width-this._gridPadding.right});ar.yaxis.pack({position:"absolute",top:0,left:this._gridPadding.left-ar.yaxis.getWidth(),height:this._height},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top});ar.x2axis.pack({position:"absolute",top:this._gridPadding.top-ar.x2axis.getHeight(),left:0,width:this._width},{min:this._gridPadding.left,max:this._width-this._gridPadding.right});for(aH=8;aH>0;aH--){ar[aG[aH-1]].pack({position:"absolute",top:0,right:this._gridPadding.right-az[aH-1]},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top})}var au=(this._width-this._gridPadding.left-this._gridPadding.right)/2+this._gridPadding.left-ar.yMidAxis.getWidth()/2;ar.yMidAxis.pack({position:"absolute",top:0,left:au,zIndex:9,textAlign:"center"},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top});this.target.append(this.grid.createElement(this._gridPadding,this));this.grid.draw();var aq=this.series;var aJ=aq.length;for(aH=0,aE=aJ;aH<aE;aH++){aF=this.seriesStack[aH];this.target.append(aq[aF].shadowCanvas.createElement(this._gridPadding,"jqplot-series-shadowCanvas",null,this));aq[aF].shadowCanvas.setContext();aq[aF].shadowCanvas._elem.data("seriesIndex",aF)}for(aH=0,aE=aJ;aH<aE;aH++){aF=this.seriesStack[aH];this.target.append(aq[aF].canvas.createElement(this._gridPadding,"jqplot-series-canvas",null,this));aq[aF].canvas.setContext();aq[aF].canvas._elem.data("seriesIndex",aF)}this.target.append(this.eventCanvas.createElement(this._gridPadding,"jqplot-event-canvas",null,this));this.eventCanvas.setContext();this.eventCanvas._ctx.fillStyle="rgba(0,0,0,0)";this.eventCanvas._ctx.fillRect(0,0,this.eventCanvas._ctx.canvas.width,this.eventCanvas._ctx.canvas.height);this.bindCustomEvents();if(this.legend.preDraw){this.eventCanvas._elem.before(aL);this.legend.pack(aA);if(this.legend._elem){this.drawSeries({legendInfo:{location:this.legend.location,placement:this.legend.placement,width:this.legend.getWidth(),height:this.legend.getHeight(),xoffset:this.legend.xoffset,yoffset:this.legend.yoffset}})}else{this.drawSeries()}}else{this.drawSeries();if(aJ){L(aq[aJ-1].canvas._elem).after(aL)}this.legend.pack(aA)}for(var aH=0,aE=L.jqplot.eventListenerHooks.length;aH<aE;aH++){this.eventCanvas._elem.bind(L.jqplot.eventListenerHooks[aH][0],{plot:this},L.jqplot.eventListenerHooks[aH][1])}for(var aH=0,aE=this.eventListenerHooks.hooks.length;aH<aE;aH++){this.eventCanvas._elem.bind(this.eventListenerHooks.hooks[aH][0],{plot:this},this.eventListenerHooks.hooks[aH][1])}var ay=this.fillBetween;if(ay.fill&&ay.series1!==ay.series2&&ay.series1<aJ&&ay.series2<aJ&&aq[ay.series1]._type==="line"&&aq[ay.series2]._type==="line"){this.doFillBetweenLines()}for(var aH=0,aE=L.jqplot.postDrawHooks.length;aH<aE;aH++){L.jqplot.postDrawHooks[aH].call(this)}for(var aH=0,aE=this.postDrawHooks.hooks.length;aH<aE;aH++){this.postDrawHooks.hooks[aH].apply(this,this.postDrawHooks.args[aH])}if(this.target.is(":visible")){this._drawCount+=1}var av,aw,aD,ap;for(aH=0,aE=aJ;aH<aE;aH++){av=aq[aH];aw=av.renderer;aD=".jqplot-point-label.jqplot-series-"+aH;if(aw.animation&&aw.animation._supported&&aw.animation.show&&(this._drawCount<2||this.animateReplot)){ap=this.target.find(aD);ap.stop(true,true).hide();av.canvas._elem.stop(true,true).hide();av.shadowCanvas._elem.stop(true,true).hide();av.canvas._elem.jqplotEffect("blind",{mode:"show",direction:aw.animation.direction},aw.animation.speed);av.shadowCanvas._elem.jqplotEffect("blind",{mode:"show",direction:aw.animation.direction},aw.animation.speed);ap.fadeIn(aw.animation.speed*0.8)}}ap=null;this.target.trigger("jqplotPostDraw",[this])}};R.prototype.doFillBetweenLines=function(){var an=this.fillBetween;var ax=an.series1;var av=an.series2;var aw=(ax<av)?ax:av;var au=(av>ax)?av:ax;var ar=this.series[aw];var aq=this.series[au];if(aq.renderer.smooth){var ap=aq.renderer._smoothedData.slice(0).reverse()}else{var ap=aq.gridData.slice(0).reverse()}if(ar.renderer.smooth){var at=ar.renderer._smoothedData.concat(ap)}else{var at=ar.gridData.concat(ap)}var ao=(an.color!==null)?an.color:this.series[ax].fillColor;var ay=(an.baseSeries!==null)?an.baseSeries:aw;var am=this.series[ay].renderer.shapeRenderer;var al={fillStyle:ao,fill:true,closePath:true};am.draw(ar.shadowCanvas._ctx,at,al)};this.bindCustomEvents=function(){this.eventCanvas._elem.bind("click",{plot:this},this.onClick);this.eventCanvas._elem.bind("dblclick",{plot:this},this.onDblClick);this.eventCanvas._elem.bind("mousedown",{plot:this},this.onMouseDown);this.eventCanvas._elem.bind("mousemove",{plot:this},this.onMouseMove);this.eventCanvas._elem.bind("mouseenter",{plot:this},this.onMouseEnter);this.eventCanvas._elem.bind("mouseleave",{plot:this},this.onMouseLeave);if(this.captureRightClick){this.eventCanvas._elem.bind("mouseup",{plot:this},this.onRightClick);this.eventCanvas._elem.get(0).oncontextmenu=function(){return false}}else{this.eventCanvas._elem.bind("mouseup",{plot:this},this.onMouseUp)}};function ai(av){var au=av.data.plot;var ap=au.eventCanvas._elem.offset();var at={x:av.pageX-ap.left,y:av.pageY-ap.top};var aq={xaxis:null,yaxis:null,x2axis:null,y2axis:null,y3axis:null,y4axis:null,y5axis:null,y6axis:null,y7axis:null,y8axis:null,y9axis:null,yMidAxis:null};var ar=["xaxis","yaxis","x2axis","y2axis","y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];var al=au.axes;var am,ao;for(am=11;am>0;am--){ao=ar[am-1];if(al[ao].show){aq[ao]=al[ao].series_p2u(at[ao.charAt(0)])}}return{offsets:ap,gridPos:at,dataPos:aq}}function ak(al,am){var aq=am.series;var aW,aU,aT,aO,aP,aJ,aI,aw,au,az,aA,aK;var aS,aX,aQ,ar,aH,aM,aV;var an,aN;for(aT=am.seriesStack.length-1;aT>=0;aT--){aW=am.seriesStack[aT];aO=aq[aW];aV=aO._highlightThreshold;switch(aO.renderer.constructor){case L.jqplot.BarRenderer:aJ=al.x;aI=al.y;for(aU=0;aU<aO._barPoints.length;aU++){aH=aO._barPoints[aU];aQ=aO.gridData[aU];if(aJ>aH[0][0]&&aJ<aH[2][0]&&aI>aH[2][1]&&aI<aH[0][1]){return{seriesIndex:aO.index,pointIndex:aU,gridData:aQ,data:aO.data[aU],points:aO._barPoints[aU]}}}break;case L.jqplot.PyramidRenderer:aJ=al.x;aI=al.y;for(aU=0;aU<aO._barPoints.length;aU++){aH=aO._barPoints[aU];aQ=aO.gridData[aU];if(aJ>aH[0][0]+aV[0][0]&&aJ<aH[2][0]+aV[2][0]&&aI>aH[2][1]&&aI<aH[0][1]){return{seriesIndex:aO.index,pointIndex:aU,gridData:aQ,data:aO.data[aU],points:aO._barPoints[aU]}}}break;case L.jqplot.DonutRenderer:az=aO.startAngle/180*Math.PI;aJ=al.x-aO._center[0];aI=al.y-aO._center[1];aP=Math.sqrt(Math.pow(aJ,2)+Math.pow(aI,2));if(aJ>0&&-aI>=0){aw=2*Math.PI-Math.atan(-aI/aJ)}else{if(aJ>0&&-aI<0){aw=-Math.atan(-aI/aJ)}else{if(aJ<0){aw=Math.PI-Math.atan(-aI/aJ)}else{if(aJ==0&&-aI>0){aw=3*Math.PI/2}else{if(aJ==0&&-aI<0){aw=Math.PI/2}else{if(aJ==0&&aI==0){aw=0}}}}}}if(az){aw-=az;if(aw<0){aw+=2*Math.PI}else{if(aw>2*Math.PI){aw-=2*Math.PI}}}au=aO.sliceMargin/180*Math.PI;if(aP<aO._radius&&aP>aO._innerRadius){for(aU=0;aU<aO.gridData.length;aU++){aA=(aU>0)?aO.gridData[aU-1][1]+au:au;aK=aO.gridData[aU][1];if(aw>aA&&aw<aK){return{seriesIndex:aO.index,pointIndex:aU,gridData:[al.x,al.y],data:aO.data[aU]}}}}break;case L.jqplot.PieRenderer:az=aO.startAngle/180*Math.PI;aJ=al.x-aO._center[0];aI=al.y-aO._center[1];aP=Math.sqrt(Math.pow(aJ,2)+Math.pow(aI,2));if(aJ>0&&-aI>=0){aw=2*Math.PI-Math.atan(-aI/aJ)}else{if(aJ>0&&-aI<0){aw=-Math.atan(-aI/aJ)}else{if(aJ<0){aw=Math.PI-Math.atan(-aI/aJ)}else{if(aJ==0&&-aI>0){aw=3*Math.PI/2}else{if(aJ==0&&-aI<0){aw=Math.PI/2}else{if(aJ==0&&aI==0){aw=0}}}}}}if(az){aw-=az;if(aw<0){aw+=2*Math.PI}else{if(aw>2*Math.PI){aw-=2*Math.PI}}}au=aO.sliceMargin/180*Math.PI;if(aP<aO._radius){for(aU=0;aU<aO.gridData.length;aU++){aA=(aU>0)?aO.gridData[aU-1][1]+au:au;aK=aO.gridData[aU][1];if(aw>aA&&aw<aK){return{seriesIndex:aO.index,pointIndex:aU,gridData:[al.x,al.y],data:aO.data[aU]}}}}break;case L.jqplot.BubbleRenderer:aJ=al.x;aI=al.y;var aF=null;if(aO.show){for(var aU=0;aU<aO.gridData.length;aU++){aQ=aO.gridData[aU];aX=Math.sqrt((aJ-aQ[0])*(aJ-aQ[0])+(aI-aQ[1])*(aI-aQ[1]));if(aX<=aQ[2]&&(aX<=aS||aS==null)){aS=aX;aF={seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}if(aF!=null){return aF}}break;case L.jqplot.FunnelRenderer:aJ=al.x;aI=al.y;var aL=aO._vertices,ap=aL[0],ao=aL[aL.length-1],at,aE,ay;function aR(a0,a2,a1){var aZ=(a2[1]-a1[1])/(a2[0]-a1[0]);var aY=a2[1]-aZ*a2[0];var a3=a0+a2[1];return[(a3-aY)/aZ,a3]}at=aR(aI,ap[0],ao[3]);aE=aR(aI,ap[1],ao[2]);for(aU=0;aU<aL.length;aU++){ay=aL[aU];if(aI>=ay[0][1]&&aI<=ay[3][1]&&aJ>=at[0]&&aJ<=aE[0]){return{seriesIndex:aO.index,pointIndex:aU,gridData:null,data:aO.data[aU]}}}break;case L.jqplot.LineRenderer:aJ=al.x;aI=al.y;aP=aO.renderer;if(aO.show){if((aO.fill||(aO.renderer.bands.show&&aO.renderer.bands.fill))&&(!am.plugins.highlighter||!am.plugins.highlighter.show)){var ax=false;if(aJ>aO._boundingBox[0][0]&&aJ<aO._boundingBox[1][0]&&aI>aO._boundingBox[1][1]&&aI<aO._boundingBox[0][1]){var aD=aO._areaPoints.length;var aG;var aU=aD-1;for(var aG=0;aG<aD;aG++){var aC=[aO._areaPoints[aG][0],aO._areaPoints[aG][1]];var aB=[aO._areaPoints[aU][0],aO._areaPoints[aU][1]];if(aC[1]<aI&&aB[1]>=aI||aB[1]<aI&&aC[1]>=aI){if(aC[0]+(aI-aC[1])/(aB[1]-aC[1])*(aB[0]-aC[0])<aJ){ax=!ax}}aU=aG}}if(ax){return{seriesIndex:aW,pointIndex:null,gridData:aO.gridData,data:aO.data,points:aO._areaPoints}}break}else{aN=aO.markerRenderer.size/2+aO.neighborThreshold;an=(aN>0)?aN:0;for(var aU=0;aU<aO.gridData.length;aU++){aQ=aO.gridData[aU];if(aP.constructor==L.jqplot.OHLCRenderer){if(aP.candleStick){var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._bodyWidth/2&&aJ<=aQ[0]+aP._bodyWidth/2&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{if(!aP.hlc){var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][1])&&aI<=av(aO.data[aU][2])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}else{if(aQ[0]!=null&&aQ[1]!=null){aX=Math.sqrt((aJ-aQ[0])*(aJ-aQ[0])+(aI-aQ[1])*(aI-aQ[1]));if(aX<=an&&(aX<=aS||aS==null)){aS=aX;return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}}}break;default:aJ=al.x;aI=al.y;aP=aO.renderer;if(aO.show){aN=aO.markerRenderer.size/2+aO.neighborThreshold;an=(aN>0)?aN:0;for(var aU=0;aU<aO.gridData.length;aU++){aQ=aO.gridData[aU];if(aP.constructor==L.jqplot.OHLCRenderer){if(aP.candleStick){var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._bodyWidth/2&&aJ<=aQ[0]+aP._bodyWidth/2&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{if(!aP.hlc){var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][1])&&aI<=av(aO.data[aU][2])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}else{aX=Math.sqrt((aJ-aQ[0])*(aJ-aQ[0])+(aI-aQ[1])*(aI-aQ[1]));if(aX<=an&&(aX<=aS||aS==null)){aS=aX;return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}break}}return null}this.onClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onDblClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotDblClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseDown=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotMouseDown");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseUp=function(an){var am=ai(an);var al=L.Event("jqplotMouseUp");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,null,an.data.plot])};this.onRightClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);if(ap.captureRightClick){if(an.which==3){var al=L.Event("jqplotRightClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])}else{var al=L.Event("jqplotMouseUp");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])}}};this.onMouseMove=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotMouseMove");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseEnter=function(an){var am=ai(an);var ao=an.data.plot;var al=L.Event("jqplotMouseEnter");al.pageX=an.pageX;al.pageY=an.pageY;al.relatedTarget=an.relatedTarget;L(this).trigger(al,[am.gridPos,am.dataPos,null,ao])};this.onMouseLeave=function(an){var am=ai(an);var ao=an.data.plot;var al=L.Event("jqplotMouseLeave");al.pageX=an.pageX;al.pageY=an.pageY;al.relatedTarget=an.relatedTarget;L(this).trigger(al,[am.gridPos,am.dataPos,null,ao])};this.drawSeries=function(an,al){var ap,ao,am;al=(typeof(an)==="number"&&al==null)?an:al;an=(typeof(an)==="object")?an:{};if(al!=u){ao=this.series[al];am=ao.shadowCanvas._ctx;am.clearRect(0,0,am.canvas.width,am.canvas.height);ao.drawShadow(am,an,this);am=ao.canvas._ctx;am.clearRect(0,0,am.canvas.width,am.canvas.height);ao.draw(am,an,this);if(ao.renderer.constructor==L.jqplot.BezierCurveRenderer){if(al<this.series.length-1){this.drawSeries(al+1)}}}else{for(ap=0;ap<this.series.length;ap++){ao=this.series[ap];am=ao.shadowCanvas._ctx;am.clearRect(0,0,am.canvas.width,am.canvas.height);ao.drawShadow(am,an,this);am=ao.canvas._ctx;am.clearRect(0,0,am.canvas.width,am.canvas.height);ao.draw(am,an,this)}}an=al=ap=ao=am=null};this.moveSeriesToFront=function(am){am=parseInt(am,10);var ap=L.inArray(am,this.seriesStack);if(ap==-1){return}if(ap==this.seriesStack.length-1){this.previousSeriesStack=this.seriesStack.slice(0);return}var al=this.seriesStack[this.seriesStack.length-1];var ao=this.series[am].canvas._elem.detach();var an=this.series[am].shadowCanvas._elem.detach();this.series[al].shadowCanvas._elem.after(an);this.series[al].canvas._elem.after(ao);this.previousSeriesStack=this.seriesStack.slice(0);this.seriesStack.splice(ap,1);this.seriesStack.push(am)};this.moveSeriesToBack=function(am){am=parseInt(am,10);var ap=L.inArray(am,this.seriesStack);if(ap==0||ap==-1){return}var al=this.seriesStack[0];var ao=this.series[am].canvas._elem.detach();var an=this.series[am].shadowCanvas._elem.detach();this.series[al].shadowCanvas._elem.before(an);this.series[al].canvas._elem.before(ao);this.previousSeriesStack=this.seriesStack.slice(0);this.seriesStack.splice(ap,1);this.seriesStack.unshift(am)};this.restorePreviousSeriesOrder=function(){var ar,aq,ap,ao,an,al,am;if(this.seriesStack==this.previousSeriesStack){return}for(ar=1;ar<this.previousSeriesStack.length;ar++){al=this.previousSeriesStack[ar];am=this.previousSeriesStack[ar-1];ap=this.series[al].canvas._elem.detach();ao=this.series[al].shadowCanvas._elem.detach();this.series[am].shadowCanvas._elem.after(ao);this.series[am].canvas._elem.after(ap)}an=this.seriesStack.slice(0);this.seriesStack=this.previousSeriesStack.slice(0);this.previousSeriesStack=an};this.restoreOriginalSeriesOrder=function(){var ap,ao,al=[],an,am;for(ap=0;ap<this.series.length;ap++){al.push(ap)}if(this.seriesStack==al){return}this.previousSeriesStack=this.seriesStack.slice(0);this.seriesStack=al;for(ap=1;ap<this.seriesStack.length;ap++){an=this.series[ap].canvas._elem.detach();am=this.series[ap].shadowCanvas._elem.detach();this.series[ap-1].shadowCanvas._elem.after(am);this.series[ap-1].canvas._elem.after(an)}};this.activateTheme=function(al){this.themeEngine.activate(this,al)}}L.jqplot.computeHighlightColors=function(ai){var ak;if(L.isArray(ai)){ak=[];for(var am=0;am<ai.length;am++){var al=L.jqplot.getColorComponents(ai[am]);var ah=[al[0],al[1],al[2]];var an=ah[0]+ah[1]+ah[2];for(var aj=0;aj<3;aj++){ah[aj]=(an>660)?ah[aj]*0.85:0.73*ah[aj]+90;ah[aj]=parseInt(ah[aj],10);(ah[aj]>255)?255:ah[aj]}ah[3]=0.3+0.35*al[3];ak.push("rgba("+ah[0]+","+ah[1]+","+ah[2]+","+ah[3]+")")}}else{var al=L.jqplot.getColorComponents(ai);var ah=[al[0],al[1],al[2]];var an=ah[0]+ah[1]+ah[2];for(var aj=0;aj<3;aj++){ah[aj]=(an>660)?ah[aj]*0.85:0.73*ah[aj]+90;ah[aj]=parseInt(ah[aj],10);(ah[aj]>255)?255:ah[aj]}ah[3]=0.3+0.35*al[3];ak="rgba("+ah[0]+","+ah[1]+","+ah[2]+","+ah[3]+")"}return ak};L.jqplot.ColorGenerator=function(ai){ai=ai||L.jqplot.config.defaultColors;var ah=0;this.next=function(){if(ah<ai.length){return ai[ah++]}else{ah=0;return ai[ah++]}};this.previous=function(){if(ah>0){return ai[ah--]}else{ah=ai.length-1;return ai[ah]}};this.get=function(ak){var aj=ak-ai.length*Math.floor(ak/ai.length);return ai[aj]};this.setColors=function(aj){ai=aj};this.reset=function(){ah=0};this.getIndex=function(){return ah};this.setIndex=function(aj){ah=aj}};L.jqplot.hex2rgb=function(aj,ah){aj=aj.replace("#","");if(aj.length==3){aj=aj.charAt(0)+aj.charAt(0)+aj.charAt(1)+aj.charAt(1)+aj.charAt(2)+aj.charAt(2)}var ai;ai="rgba("+parseInt(aj.slice(0,2),16)+", "+parseInt(aj.slice(2,4),16)+", "+parseInt(aj.slice(4,6),16);if(ah){ai+=", "+ah}ai+=")";return ai};L.jqplot.rgb2hex=function(am){var aj=/rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/;var ah=am.match(aj);var al="#";for(var ak=1;ak<4;ak++){var ai;if(ah[ak].search(/%/)!=-1){ai=parseInt(255*ah[ak]/100,10).toString(16);if(ai.length==1){ai="0"+ai}}else{ai=parseInt(ah[ak],10).toString(16);if(ai.length==1){ai="0"+ai}}al+=ai}return al};L.jqplot.normalize2rgb=function(ai,ah){if(ai.search(/^ *rgba?\(/)!=-1){return ai}else{if(ai.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/)!=-1){return L.jqplot.hex2rgb(ai,ah)}else{throw new Error("Invalid color spec")}}};L.jqplot.getColorComponents=function(am){am=L.jqplot.colorKeywordMap[am]||am;var ak=L.jqplot.normalize2rgb(am);var aj=/rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/;var ah=ak.match(aj);var ai=[];for(var al=1;al<4;al++){if(ah[al].search(/%/)!=-1){ai[al-1]=parseInt(255*ah[al]/100,10)}else{ai[al-1]=parseInt(ah[al],10)}}ai[3]=parseFloat(ah[4])?parseFloat(ah[4]):1;return ai};L.jqplot.colorKeywordMap={aliceblue:"rgb(240, 248, 255)",antiquewhite:"rgb(250, 235, 215)",aqua:"rgb( 0, 255, 255)",aquamarine:"rgb(127, 255, 212)",azure:"rgb(240, 255, 255)",beige:"rgb(245, 245, 220)",bisque:"rgb(255, 228, 196)",black:"rgb( 0, 0, 0)",blanchedalmond:"rgb(255, 235, 205)",blue:"rgb( 0, 0, 255)",blueviolet:"rgb(138, 43, 226)",brown:"rgb(165, 42, 42)",burlywood:"rgb(222, 184, 135)",cadetblue:"rgb( 95, 158, 160)",chartreuse:"rgb(127, 255, 0)",chocolate:"rgb(210, 105, 30)",coral:"rgb(255, 127, 80)",cornflowerblue:"rgb(100, 149, 237)",cornsilk:"rgb(255, 248, 220)",crimson:"rgb(220, 20, 60)",cyan:"rgb( 0, 255, 255)",darkblue:"rgb( 0, 0, 139)",darkcyan:"rgb( 0, 139, 139)",darkgoldenrod:"rgb(184, 134, 11)",darkgray:"rgb(169, 169, 169)",darkgreen:"rgb( 0, 100, 0)",darkgrey:"rgb(169, 169, 169)",darkkhaki:"rgb(189, 183, 107)",darkmagenta:"rgb(139, 0, 139)",darkolivegreen:"rgb( 85, 107, 47)",darkorange:"rgb(255, 140, 0)",darkorchid:"rgb(153, 50, 204)",darkred:"rgb(139, 0, 0)",darksalmon:"rgb(233, 150, 122)",darkseagreen:"rgb(143, 188, 143)",darkslateblue:"rgb( 72, 61, 139)",darkslategray:"rgb( 47, 79, 79)",darkslategrey:"rgb( 47, 79, 79)",darkturquoise:"rgb( 0, 206, 209)",darkviolet:"rgb(148, 0, 211)",deeppink:"rgb(255, 20, 147)",deepskyblue:"rgb( 0, 191, 255)",dimgray:"rgb(105, 105, 105)",dimgrey:"rgb(105, 105, 105)",dodgerblue:"rgb( 30, 144, 255)",firebrick:"rgb(178, 34, 34)",floralwhite:"rgb(255, 250, 240)",forestgreen:"rgb( 34, 139, 34)",fuchsia:"rgb(255, 0, 255)",gainsboro:"rgb(220, 220, 220)",ghostwhite:"rgb(248, 248, 255)",gold:"rgb(255, 215, 0)",goldenrod:"rgb(218, 165, 32)",gray:"rgb(128, 128, 128)",grey:"rgb(128, 128, 128)",green:"rgb( 0, 128, 0)",greenyellow:"rgb(173, 255, 47)",honeydew:"rgb(240, 255, 240)",hotpink:"rgb(255, 105, 180)",indianred:"rgb(205, 92, 92)",indigo:"rgb( 75, 0, 130)",ivory:"rgb(255, 255, 240)",khaki:"rgb(240, 230, 140)",lavender:"rgb(230, 230, 250)",lavenderblush:"rgb(255, 240, 245)",lawngreen:"rgb(124, 252, 0)",lemonchiffon:"rgb(255, 250, 205)",lightblue:"rgb(173, 216, 230)",lightcoral:"rgb(240, 128, 128)",lightcyan:"rgb(224, 255, 255)",lightgoldenrodyellow:"rgb(250, 250, 210)",lightgray:"rgb(211, 211, 211)",lightgreen:"rgb(144, 238, 144)",lightgrey:"rgb(211, 211, 211)",lightpink:"rgb(255, 182, 193)",lightsalmon:"rgb(255, 160, 122)",lightseagreen:"rgb( 32, 178, 170)",lightskyblue:"rgb(135, 206, 250)",lightslategray:"rgb(119, 136, 153)",lightslategrey:"rgb(119, 136, 153)",lightsteelblue:"rgb(176, 196, 222)",lightyellow:"rgb(255, 255, 224)",lime:"rgb( 0, 255, 0)",limegreen:"rgb( 50, 205, 50)",linen:"rgb(250, 240, 230)",magenta:"rgb(255, 0, 255)",maroon:"rgb(128, 0, 0)",mediumaquamarine:"rgb(102, 205, 170)",mediumblue:"rgb( 0, 0, 205)",mediumorchid:"rgb(186, 85, 211)",mediumpurple:"rgb(147, 112, 219)",mediumseagreen:"rgb( 60, 179, 113)",mediumslateblue:"rgb(123, 104, 238)",mediumspringgreen:"rgb( 0, 250, 154)",mediumturquoise:"rgb( 72, 209, 204)",mediumvioletred:"rgb(199, 21, 133)",midnightblue:"rgb( 25, 25, 112)",mintcream:"rgb(245, 255, 250)",mistyrose:"rgb(255, 228, 225)",moccasin:"rgb(255, 228, 181)",navajowhite:"rgb(255, 222, 173)",navy:"rgb( 0, 0, 128)",oldlace:"rgb(253, 245, 230)",olive:"rgb(128, 128, 0)",olivedrab:"rgb(107, 142, 35)",orange:"rgb(255, 165, 0)",orangered:"rgb(255, 69, 0)",orchid:"rgb(218, 112, 214)",palegoldenrod:"rgb(238, 232, 170)",palegreen:"rgb(152, 251, 152)",paleturquoise:"rgb(175, 238, 238)",palevioletred:"rgb(219, 112, 147)",papayawhip:"rgb(255, 239, 213)",peachpuff:"rgb(255, 218, 185)",peru:"rgb(205, 133, 63)",pink:"rgb(255, 192, 203)",plum:"rgb(221, 160, 221)",powderblue:"rgb(176, 224, 230)",purple:"rgb(128, 0, 128)",red:"rgb(255, 0, 0)",rosybrown:"rgb(188, 143, 143)",royalblue:"rgb( 65, 105, 225)",saddlebrown:"rgb(139, 69, 19)",salmon:"rgb(250, 128, 114)",sandybrown:"rgb(244, 164, 96)",seagreen:"rgb( 46, 139, 87)",seashell:"rgb(255, 245, 238)",sienna:"rgb(160, 82, 45)",silver:"rgb(192, 192, 192)",skyblue:"rgb(135, 206, 235)",slateblue:"rgb(106, 90, 205)",slategray:"rgb(112, 128, 144)",slategrey:"rgb(112, 128, 144)",snow:"rgb(255, 250, 250)",springgreen:"rgb( 0, 255, 127)",steelblue:"rgb( 70, 130, 180)",tan:"rgb(210, 180, 140)",teal:"rgb( 0, 128, 128)",thistle:"rgb(216, 191, 216)",tomato:"rgb(255, 99, 71)",turquoise:"rgb( 64, 224, 208)",violet:"rgb(238, 130, 238)",wheat:"rgb(245, 222, 179)",white:"rgb(255, 255, 255)",whitesmoke:"rgb(245, 245, 245)",yellow:"rgb(255, 255, 0)",yellowgreen:"rgb(154, 205, 50)"};L.jqplot.AxisLabelRenderer=function(ah){L.jqplot.ElemContainer.call(this);this.axis;this.show=true;this.label="";this.fontFamily=null;this.fontSize=null;this.textColor=null;this._elem;this.escapeHTML=false;L.extend(true,this,ah)};L.jqplot.AxisLabelRenderer.prototype=new L.jqplot.ElemContainer();L.jqplot.AxisLabelRenderer.prototype.constructor=L.jqplot.AxisLabelRenderer;L.jqplot.AxisLabelRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.AxisLabelRenderer.prototype.draw=function(ah,ai){if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=L('<div style="position:absolute;" class="jqplot-'+this.axis+'-label"></div>');if(Number(this.label)){this._elem.css("white-space","nowrap")}if(!this.escapeHTML){this._elem.html(this.label)}else{this._elem.text(this.label)}if(this.fontFamily){this._elem.css("font-family",this.fontFamily)}if(this.fontSize){this._elem.css("font-size",this.fontSize)}if(this.textColor){this._elem.css("color",this.textColor)}return this._elem};L.jqplot.AxisLabelRenderer.prototype.pack=function(){};L.jqplot.AxisTickRenderer=function(ah){L.jqplot.ElemContainer.call(this);this.mark="outside";this.axis;this.showMark=true;this.showGridline=true;this.isMinorTick=false;this.size=4;this.markSize=6;this.show=true;this.showLabel=true;this.label=null;this.value=null;this._styles={};this.formatter=L.jqplot.DefaultTickFormatter;this.prefix="";this.suffix="";this.formatString="";this.fontFamily;this.fontSize;this.textColor;this.escapeHTML=false;this._elem;this._breakTick=false;L.extend(true,this,ah)};L.jqplot.AxisTickRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.AxisTickRenderer.prototype=new L.jqplot.ElemContainer();L.jqplot.AxisTickRenderer.prototype.constructor=L.jqplot.AxisTickRenderer;L.jqplot.AxisTickRenderer.prototype.setTick=function(ah,aj,ai){this.value=ah;this.axis=aj;if(ai){this.isMinorTick=true}return this};L.jqplot.AxisTickRenderer.prototype.draw=function(){if(this.label===null){this.label=this.prefix+this.formatter(this.formatString,this.value)+this.suffix}var ai={position:"absolute"};if(Number(this.label)){ai.whitSpace="nowrap"}if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=L(document.createElement("div"));this._elem.addClass("jqplot-"+this.axis+"-tick");if(!this.escapeHTML){this._elem.html(this.label)}else{this._elem.text(this.label)}this._elem.css(ai);for(var ah in this._styles){this._elem.css(ah,this._styles[ah])}if(this.fontFamily){this._elem.css("font-family",this.fontFamily)}if(this.fontSize){this._elem.css("font-size",this.fontSize)}if(this.textColor){this._elem.css("color",this.textColor)}if(this._breakTick){this._elem.addClass("jqplot-breakTick")}return this._elem};L.jqplot.DefaultTickFormatter=function(ah,ai){if(typeof ai=="number"){if(!ah){ah=L.jqplot.config.defaultTickFormatString}return L.jqplot.sprintf(ah,ai)}else{return String(ai)}};L.jqplot.PercentTickFormatter=function(ah,ai){if(typeof ai=="number"){ai=100*ai;if(!ah){ah=L.jqplot.config.defaultTickFormatString}return L.jqplot.sprintf(ah,ai)}else{return String(ai)}};L.jqplot.AxisTickRenderer.prototype.pack=function(){};L.jqplot.CanvasGridRenderer=function(){this.shadowRenderer=new L.jqplot.ShadowRenderer()};L.jqplot.CanvasGridRenderer.prototype.init=function(ai){this._ctx;L.extend(true,this,ai);var ah={lineJoin:"miter",lineCap:"round",fill:false,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.shadowWidth,closePath:false,strokeStyle:this.shadowColor};this.renderer.shadowRenderer.init(ah)};L.jqplot.CanvasGridRenderer.prototype.createElement=function(ak){var aj;if(this._elem){if(L.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==u){aj=this._elem.get(0);window.G_vmlCanvasManager.uninitElement(aj);aj=null}this._elem.emptyForce();this._elem=null}aj=ak.canvasManager.getCanvas();var ah=this._plotDimensions.width;var ai=this._plotDimensions.height;aj.width=ah;aj.height=ai;this._elem=L(aj);this._elem.addClass("jqplot-grid-canvas");this._elem.css({position:"absolute",left:0,top:0});aj=ak.canvasManager.initCanvas(aj);this._top=this._offsets.top;this._bottom=ai-this._offsets.bottom;this._left=this._offsets.left;this._right=ah-this._offsets.right;this._width=this._right-this._left;this._height=this._bottom-this._top;aj=null;return this._elem};L.jqplot.CanvasGridRenderer.prototype.draw=function(){this._ctx=this._elem.get(0).getContext("2d");var at=this._ctx;var aw=this._axes;at.save();at.clearRect(0,0,this._plotDimensions.width,this._plotDimensions.height);at.fillStyle=this.backgroundColor||this.background;at.fillRect(this._left,this._top,this._width,this._height);at.save();at.lineJoin="miter";at.lineCap="butt";at.lineWidth=this.gridLineWidth;at.strokeStyle=this.gridLineColor;var aA,az,ap,aq;var am=["xaxis","yaxis","x2axis","y2axis"];for(var ay=4;ay>0;ay--){var aD=am[ay-1];var ah=aw[aD];var aB=ah._ticks;var ar=aB.length;if(ah.show){if(ah.drawBaseline){var aC={};if(ah.baselineWidth!==null){aC.lineWidth=ah.baselineWidth}if(ah.baselineColor!==null){aC.strokeStyle=ah.baselineColor}switch(aD){case"xaxis":ao(this._left,this._bottom,this._right,this._bottom,aC);break;case"yaxis":ao(this._left,this._bottom,this._left,this._top,aC);break;case"x2axis":ao(this._left,this._bottom,this._right,this._bottom,aC);break;case"y2axis":ao(this._right,this._bottom,this._right,this._top,aC);break}}for(var au=ar;au>0;au--){var an=aB[au-1];if(an.show){var ak=Math.round(ah.u2p(an.value))+0.5;switch(aD){case"xaxis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(ak,this._top,ak,this._bottom)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._bottom;az=this._bottom+ap;break;case"inside":aA=this._bottom-ap;az=this._bottom;break;case"cross":aA=this._bottom-ap;az=this._bottom+ap;break;default:aA=this._bottom;az=this._bottom+ap;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[ak,aA],[ak,az]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}ao(ak,aA,ak,az)}break;case"yaxis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(this._right,ak,this._left,ak)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._left-ap;az=this._left;break;case"inside":aA=this._left;az=this._left+ap;break;case"cross":aA=this._left-ap;az=this._left+ap;break;default:aA=this._left-ap;az=this._left;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[aA,ak],[az,ak]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}break;case"x2axis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(ak,this._bottom,ak,this._top)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._top-ap;az=this._top;break;case"inside":aA=this._top;az=this._top+ap;break;case"cross":aA=this._top-ap;az=this._top+ap;break;default:aA=this._top-ap;az=this._top;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[ak,aA],[ak,az]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}ao(ak,aA,ak,az)}break;case"y2axis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(this._left,ak,this._right,ak)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._right;az=this._right+ap;break;case"inside":aA=this._right-ap;az=this._right;break;case"cross":aA=this._right-ap;az=this._right+ap;break;default:aA=this._right;az=this._right+ap;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[aA,ak],[az,ak]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}break;default:break}}}an=null}ah=null;aB=null}am=["y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];for(var ay=7;ay>0;ay--){var ah=aw[am[ay-1]];var aB=ah._ticks;if(ah.show){var ai=aB[ah.numberTicks-1];var al=aB[0];var aj=ah.getLeft();var av=[[aj,ai.getTop()+ai.getHeight()/2],[aj,al.getTop()+al.getHeight()/2+1]];if(this.shadow){this.renderer.shadowRenderer.draw(at,av,{lineCap:"butt",fill:false,closePath:false})}ao(av[0][0],av[0][1],av[1][0],av[1][1],{lineCap:"butt",strokeStyle:ah.borderColor,lineWidth:ah.borderWidth});for(var au=aB.length;au>0;au--){var an=aB[au-1];ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;if(an.showMark&&an.mark){switch(aq){case"outside":aA=aj;az=aj+ap;break;case"inside":aA=aj-ap;az=aj;break;case"cross":aA=aj-ap;az=aj+ap;break;default:aA=aj;az=aj+ap;break}av=[[aA,ak],[az,ak]];if(this.shadow){this.renderer.shadowRenderer.draw(at,av,{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}an=null}al=null}ah=null;aB=null}at.restore();function ao(aH,aG,aE,ax,aF){at.save();aF=aF||{};if(aF.lineWidth==null||aF.lineWidth!=0){L.extend(true,at,aF);at.beginPath();at.moveTo(aH,aG);at.lineTo(aE,ax);at.stroke();at.restore()}}if(this.shadow){var av=[[this._left,this._bottom],[this._right,this._bottom],[this._right,this._top]];this.renderer.shadowRenderer.draw(at,av)}if(this.borderWidth!=0&&this.drawBorder){ao(this._left,this._top,this._right,this._top,{lineCap:"round",strokeStyle:aw.x2axis.borderColor,lineWidth:aw.x2axis.borderWidth});ao(this._right,this._top,this._right,this._bottom,{lineCap:"round",strokeStyle:aw.y2axis.borderColor,lineWidth:aw.y2axis.borderWidth});ao(this._right,this._bottom,this._left,this._bottom,{lineCap:"round",strokeStyle:aw.xaxis.borderColor,lineWidth:aw.xaxis.borderWidth});ao(this._left,this._bottom,this._left,this._top,{lineCap:"round",strokeStyle:aw.yaxis.borderColor,lineWidth:aw.yaxis.borderWidth})}at.restore();at=null;aw=null};L.jqplot.DivTitleRenderer=function(){};L.jqplot.DivTitleRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.DivTitleRenderer.prototype.draw=function(){if(this._elem){this._elem.emptyForce();this._elem=null}var ak=this.renderer;var aj=document.createElement("div");this._elem=L(aj);this._elem.addClass("jqplot-title");if(!this.text){this.show=false;this._elem.height(0);this._elem.width(0)}else{if(this.text){var ah;if(this.color){ah=this.color}else{if(this.textColor){ah=this.textColor}}var ai={position:"absolute",top:"0px",left:"0px"};if(this._plotWidth){ai.width=this._plotWidth+"px"}if(this.fontSize){ai.fontSize=this.fontSize}if(typeof this.textAlign==="string"){ai.textAlign=this.textAlign}else{ai.textAlign="center"}if(ah){ai.color=ah}if(this.paddingBottom){ai.paddingBottom=this.paddingBottom}if(this.fontFamily){ai.fontFamily=this.fontFamily}this._elem.css(ai);if(this.escapeHtml){this._elem.text(this.text)}else{this._elem.html(this.text)}}}aj=null;return this._elem};L.jqplot.DivTitleRenderer.prototype.pack=function(){};var r=0.1;L.jqplot.LinePattern=function(aw,aq){var ap={dotted:[r,L.jqplot.config.dotGapLength],dashed:[L.jqplot.config.dashLength,L.jqplot.config.gapLength],solid:null};if(typeof aq==="string"){if(aq[0]==="."||aq[0]==="-"){var ax=aq;aq=[];for(var ao=0,al=ax.length;ao<al;ao++){if(ax[ao]==="."){aq.push(r)}else{if(ax[ao]==="-"){aq.push(L.jqplot.config.dashLength)}else{continue}}aq.push(L.jqplot.config.gapLength)}}else{aq=ap[aq]}}if(!(aq&&aq.length)){return aw}var ak=0;var ar=aq[0];var au=0;var at=0;var an=0;var ah=0;var av=function(ay,az){aw.moveTo(ay,az);au=ay;at=az;an=ay;ah=az};var aj=function(ay,aE){var aC=aw.lineWidth;var aA=ay-au;var az=aE-at;var aB=Math.sqrt(aA*aA+az*az);if((aB>0)&&(aC>0)){aA/=aB;az/=aB;while(true){var aD=aC*ar;if(aD<aB){au+=aD*aA;at+=aD*az;if((ak&1)==0){aw.lineTo(au,at)}else{aw.moveTo(au,at)}aB-=aD;ak++;if(ak>=aq.length){ak=0}ar=aq[ak]}else{au=ay;at=aE;if((ak&1)==0){aw.lineTo(au,at)}else{aw.moveTo(au,at)}ar-=aB/aC;break}}}};var ai=function(){aw.beginPath()};var am=function(){aj(an,ah)};return{moveTo:av,lineTo:aj,beginPath:ai,closePath:am}};L.jqplot.LineRenderer=function(){this.shapeRenderer=new L.jqplot.ShapeRenderer();this.shadowRenderer=new L.jqplot.ShadowRenderer()};L.jqplot.LineRenderer.prototype.init=function(ai,an){ai=ai||{};this._type="line";this.renderer.animation={show:false,direction:"left",speed:2500,_supported:true};this.renderer.smooth=false;this.renderer.tension=null;this.renderer.constrainSmoothing=true;this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];this.renderer.bandData=[];this.renderer.bands={show:false,hiData:[],lowData:[],color:this.color,showLines:false,fill:true,fillColor:null,_min:null,_max:null,interval:"3%"};var al={highlightMouseOver:ai.highlightMouseOver,highlightMouseDown:ai.highlightMouseDown,highlightColor:ai.highlightColor};delete (ai.highlightMouseOver);delete (ai.highlightMouseDown);delete (ai.highlightColor);L.extend(true,this.renderer,ai);this.renderer.options=ai;if(this.renderer.bandData.length>1&&(!ai.bands||ai.bands.show==null)){this.renderer.bands.show=true}else{if(ai.bands&&ai.bands.show==null&&ai.bands.interval!=null){this.renderer.bands.show=true}}if(this.fill){this.renderer.bands.show=false}if(this.renderer.bands.show){this.renderer.initBands.call(this,this.renderer.options,an)}if(this._stack){this.renderer.smooth=false}var am={lineJoin:this.lineJoin,lineCap:this.lineCap,fill:this.fill,isarc:false,strokeStyle:this.color,fillStyle:this.fillColor,lineWidth:this.lineWidth,linePattern:this.linePattern,closePath:this.fill};this.renderer.shapeRenderer.init(am);var aj=ai.shadowOffset;if(aj==null){if(this.lineWidth>2.5){aj=1.25*(1+(Math.atan((this.lineWidth/2.5))/0.785398163-1)*0.6)}else{aj=1.25*Math.atan((this.lineWidth/2.5))/0.785398163}}var ah={lineJoin:this.lineJoin,lineCap:this.lineCap,fill:this.fill,isarc:false,angle:this.shadowAngle,offset:aj,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.lineWidth,linePattern:this.linePattern,closePath:this.fill};this.renderer.shadowRenderer.init(ah);this._areaPoints=[];this._boundingBox=[[],[]];if(!this.isTrendline&&this.fill||this.renderer.bands.show){this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColor=null;if(al.highlightMouseDown&&al.highlightMouseOver==null){al.highlightMouseOver=false}L.extend(true,this,{highlightMouseOver:al.highlightMouseOver,highlightMouseDown:al.highlightMouseDown,highlightColor:al.highlightColor});if(!this.highlightColor){var ak=(this.renderer.bands.show)?this.renderer.bands.fillColor:this.fillColor;this.highlightColor=L.jqplot.computeHighlightColors(ak)}if(this.highlighter){this.highlighter.show=false}}if(!this.isTrendline&&an){an.plugins.lineRenderer={};an.postInitHooks.addOnce(z);an.postDrawHooks.addOnce(af);an.eventListenerHooks.addOnce("jqplotMouseMove",h);an.eventListenerHooks.addOnce("jqplotMouseDown",e);an.eventListenerHooks.addOnce("jqplotMouseUp",ad);an.eventListenerHooks.addOnce("jqplotClick",g);an.eventListenerHooks.addOnce("jqplotRightClick",s)}};L.jqplot.LineRenderer.prototype.initBands=function(ak,av){var al=ak.bandData||[];var an=this.renderer.bands;an.hiData=[];an.lowData=[];var aB=this.data;an._max=null;an._min=null;if(al.length==2){if(L.isArray(al[0][0])){var ao;var ah=0,ar=0;for(var aw=0,at=al[0].length;aw<at;aw++){ao=al[0][aw];if((ao[1]!=null&&ao[1]>an._max)||an._max==null){an._max=ao[1]}if((ao[1]!=null&&ao[1]<an._min)||an._min==null){an._min=ao[1]}}for(var aw=0,at=al[1].length;aw<at;aw++){ao=al[1][aw];if((ao[1]!=null&&ao[1]>an._max)||an._max==null){an._max=ao[1];ar=1}if((ao[1]!=null&&ao[1]<an._min)||an._min==null){an._min=ao[1];ah=1}}if(ar===ah){an.show=false}an.hiData=al[ar];an.lowData=al[ah]}else{if(al[0].length===aB.length&&al[1].length===aB.length){var aj=(al[0][0]>al[1][0])?0:1;var aC=(aj)?0:1;for(var aw=0,at=aB.length;aw<at;aw++){an.hiData.push([aB[aw][0],al[aj][aw]]);an.lowData.push([aB[aw][0],al[aC][aw]])}}else{an.show=false}}}else{if(al.length>2&&!L.isArray(al[0][0])){var aj=(al[0][0]>al[0][1])?0:1;var aC=(aj)?0:1;for(var aw=0,at=al.length;aw<at;aw++){an.hiData.push([aB[aw][0],al[aw][aj]]);an.lowData.push([aB[aw][0],al[aw][aC]])}}else{var aq=an.interval;var aA=null;var az=null;var ai=null;var au=null;if(L.isArray(aq)){aA=aq[0];az=aq[1]}else{aA=aq}if(isNaN(aA)){if(aA.charAt(aA.length-1)==="%"){ai="multiply";aA=parseFloat(aA)/100+1}}else{aA=parseFloat(aA);ai="add"}if(az!==null&&isNaN(az)){if(az.charAt(az.length-1)==="%"){au="multiply";az=parseFloat(az)/100+1}}else{if(az!==null){az=parseFloat(az);au="add"}}if(aA!==null){if(az===null){az=-aA;au=ai;if(au==="multiply"){az+=2}}if(aA<az){var ax=aA;aA=az;az=ax;ax=ai;ai=au;au=ax}for(var aw=0,at=aB.length;aw<at;aw++){switch(ai){case"add":an.hiData.push([aB[aw][0],aB[aw][1]+aA]);break;case"multiply":an.hiData.push([aB[aw][0],aB[aw][1]*aA]);break}switch(au){case"add":an.lowData.push([aB[aw][0],aB[aw][1]+az]);break;case"multiply":an.lowData.push([aB[aw][0],aB[aw][1]*az]);break}}}else{an.show=false}}}var am=an.hiData;var ap=an.lowData;for(var aw=0,at=am.length;aw<at;aw++){if((am[aw][1]!=null&&am[aw][1]>an._max)||an._max==null){an._max=am[aw][1]}}for(var aw=0,at=ap.length;aw<at;aw++){if((ap[aw][1]!=null&&ap[aw][1]<an._min)||an._min==null){an._min=ap[aw][1]}}if(an.fillColor===null){var ay=L.jqplot.getColorComponents(an.color);ay[3]=ay[3]*0.5;an.fillColor="rgba("+ay[0]+", "+ay[1]+", "+ay[2]+", "+ay[3]+")"}};function K(ai,ah){return(3.4182054+ah)*Math.pow(ai,-0.3534992)}function n(aj,ai){var ah=Math.sqrt(Math.pow((ai[0]-aj[0]),2)+Math.pow((ai[1]-aj[1]),2));return 5.7648*Math.log(ah)+7.4456}function A(ah){var ai=(Math.exp(2*ah)-1)/(Math.exp(2*ah)+1);return ai}function J(aJ){var at=this.renderer.smooth;var aD=this.canvas.getWidth();var an=this._xaxis.series_p2u;var aG=this._yaxis.series_p2u;var aF=null;var am=null;var az=aJ.length/aD;var aj=[];var ay=[];if(!isNaN(parseFloat(at))){aF=parseFloat(at)}else{aF=K(az,0.5)}var aw=[];var ak=[];for(var aE=0,aA=aJ.length;aE<aA;aE++){aw.push(aJ[aE][1]);ak.push(aJ[aE][0])}function av(aK,aL){if(aK-aL==0){return Math.pow(10,10)}else{return aK-aL}}var ax,ar,aq,ap;var ah=aJ.length-1;for(var al=1,aB=aJ.length;al<aB;al++){var ai=[];var au=[];for(var aC=0;aC<2;aC++){var aE=al-1+aC;if(aE==0||aE==ah){ai[aC]=Math.pow(10,10)}else{if(aw[aE+1]-aw[aE]==0||aw[aE]-aw[aE-1]==0){ai[aC]=0}else{if(((ak[aE+1]-ak[aE])/(aw[aE+1]-aw[aE])+(ak[aE]-ak[aE-1])/(aw[aE]-aw[aE-1]))==0){ai[aC]=0}else{if((aw[aE+1]-aw[aE])*(aw[aE]-aw[aE-1])<0){ai[aC]=0}else{ai[aC]=2/(av(ak[aE+1],ak[aE])/(aw[aE+1]-aw[aE])+av(ak[aE],ak[aE-1])/(aw[aE]-aw[aE-1]))}}}}}if(al==1){ai[0]=3/2*(aw[1]-aw[0])/av(ak[1],ak[0])-ai[1]/2}else{if(al==ah){ai[1]=3/2*(aw[ah]-aw[ah-1])/av(ak[ah],ak[ah-1])-ai[0]/2}}au[0]=-2*(ai[1]+2*ai[0])/av(ak[al],ak[al-1])+6*(aw[al]-aw[al-1])/Math.pow(av(ak[al],ak[al-1]),2);au[1]=2*(2*ai[1]+ai[0])/av(ak[al],ak[al-1])-6*(aw[al]-aw[al-1])/Math.pow(av(ak[al],ak[al-1]),2);ap=1/6*(au[1]-au[0])/av(ak[al],ak[al-1]);aq=1/2*(ak[al]*au[0]-ak[al-1]*au[1])/av(ak[al],ak[al-1]);ar=(aw[al]-aw[al-1]-aq*(Math.pow(ak[al],2)-Math.pow(ak[al-1],2))-ap*(Math.pow(ak[al],3)-Math.pow(ak[al-1],3)))/av(ak[al],ak[al-1]);ax=aw[al-1]-ar*ak[al-1]-aq*Math.pow(ak[al-1],2)-ap*Math.pow(ak[al-1],3);var aI=(ak[al]-ak[al-1])/aF;var aH,ao;for(var aC=0,aA=aF;aC<aA;aC++){aH=[];ao=ak[al-1]+aC*aI;aH.push(ao);aH.push(ax+ar*ao+aq*Math.pow(ao,2)+ap*Math.pow(ao,3));aj.push(aH);ay.push([an(aH[0]),aG(aH[1])])}}aj.push(aJ[aE]);ay.push([an(aJ[aE][0]),aG(aJ[aE][1])]);return[aj,ay]}function F(ap){var ao=this.renderer.smooth;var aU=this.renderer.tension;var ah=this.canvas.getWidth();var aH=this._xaxis.series_p2u;var aq=this._yaxis.series_p2u;var aI=null;var aJ=null;var aT=null;var aO=null;var aM=null;var at=null;var aR=null;var am=null;var aK,aL,aD,aC,aA,ay;var ak,ai,av,au;var aB,az,aN;var aw=[];var aj=[];var al=ap.length/ah;var aS,ax,aF,aG,aE;var ar=[];var an=[];if(!isNaN(parseFloat(ao))){aI=parseFloat(ao)}else{aI=K(al,0.5)}if(!isNaN(parseFloat(aU))){aU=parseFloat(aU)}for(var aQ=0,aP=ap.length-1;aQ<aP;aQ++){if(aU===null){at=Math.abs((ap[aQ+1][1]-ap[aQ][1])/(ap[aQ+1][0]-ap[aQ][0]));aS=0.3;ax=0.6;aF=(ax-aS)/2;aG=2.5;aE=-1.4;am=at/aG+aE;aO=aF*A(am)-aF*A(aE)+aS;if(aQ>0){aR=Math.abs((ap[aQ][1]-ap[aQ-1][1])/(ap[aQ][0]-ap[aQ-1][0]))}am=aR/aG+aE;aM=aF*A(am)-aF*A(aE)+aS;aT=(aO+aM)/2}else{aT=aU}for(aK=0;aK<aI;aK++){aL=aK/aI;aD=(1+2*aL)*Math.pow((1-aL),2);aC=aL*Math.pow((1-aL),2);aA=Math.pow(aL,2)*(3-2*aL);ay=Math.pow(aL,2)*(aL-1);if(ap[aQ-1]){ak=aT*(ap[aQ+1][0]-ap[aQ-1][0]);ai=aT*(ap[aQ+1][1]-ap[aQ-1][1])}else{ak=aT*(ap[aQ+1][0]-ap[aQ][0]);ai=aT*(ap[aQ+1][1]-ap[aQ][1])}if(ap[aQ+2]){av=aT*(ap[aQ+2][0]-ap[aQ][0]);au=aT*(ap[aQ+2][1]-ap[aQ][1])}else{av=aT*(ap[aQ+1][0]-ap[aQ][0]);au=aT*(ap[aQ+1][1]-ap[aQ][1])}aB=aD*ap[aQ][0]+aA*ap[aQ+1][0]+aC*ak+ay*av;az=aD*ap[aQ][1]+aA*ap[aQ+1][1]+aC*ai+ay*au;aN=[aB,az];ar.push(aN);an.push([aH(aB),aq(az)])}}ar.push(ap[aP]);an.push([aH(ap[aP][0]),aq(ap[aP][1])]);return[ar,an]}L.jqplot.LineRenderer.prototype.setGridData=function(ap){var al=this._xaxis.series_u2p;var ah=this._yaxis.series_u2p;var am=this._plotData;var aq=this._prevPlotData;this.gridData=[];this._prevGridData=[];this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];var ak=this.renderer.bands;var ai=false;for(var an=0,aj=am.length;an<aj;an++){if(am[an][0]!=null&&am[an][1]!=null){this.gridData.push([al.call(this._xaxis,am[an][0]),ah.call(this._yaxis,am[an][1])])}else{if(am[an][0]==null){ai=true;this.gridData.push([null,ah.call(this._yaxis,am[an][1])])}else{if(am[an][1]==null){ai=true;this.gridData.push([al.call(this._xaxis,am[an][0]),null])}}}if(aq[an]!=null&&aq[an][0]!=null&&aq[an][1]!=null){this._prevGridData.push([al.call(this._xaxis,aq[an][0]),ah.call(this._yaxis,aq[an][1])])}else{if(aq[an]!=null&&aq[an][0]==null){this._prevGridData.push([null,ah.call(this._yaxis,aq[an][1])])}else{if(aq[an]!=null&&aq[an][0]!=null&&aq[an][1]==null){this._prevGridData.push([al.call(this._xaxis,aq[an][0]),null])}}}}if(ai){this.renderer.smooth=false;if(this._type==="line"){ak.show=false}}if(this._type==="line"&&ak.show){for(var an=0,aj=ak.hiData.length;an<aj;an++){this.renderer._hiBandGridData.push([al.call(this._xaxis,ak.hiData[an][0]),ah.call(this._yaxis,ak.hiData[an][1])])}for(var an=0,aj=ak.lowData.length;an<aj;an++){this.renderer._lowBandGridData.push([al.call(this._xaxis,ak.lowData[an][0]),ah.call(this._yaxis,ak.lowData[an][1])])}}if(this._type==="line"&&this.renderer.smooth&&this.gridData.length>2){var ao;if(this.renderer.constrainSmoothing){ao=J.call(this,this.gridData);this.renderer._smoothedData=ao[0];this.renderer._smoothedPlotData=ao[1];if(ak.show){ao=J.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ao[0];ao=J.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ao[0]}ao=null}else{ao=F.call(this,this.gridData);this.renderer._smoothedData=ao[0];this.renderer._smoothedPlotData=ao[1];if(ak.show){ao=F.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ao[0];ao=F.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ao[0]}ao=null}}};L.jqplot.LineRenderer.prototype.makeGridData=function(ao,aq){var am=this._xaxis.series_u2p;var ah=this._yaxis.series_u2p;var ar=[];var aj=[];this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];var al=this.renderer.bands;var ai=false;for(var an=0;an<ao.length;an++){if(ao[an][0]!=null&&ao[an][1]!=null){ar.push([am.call(this._xaxis,ao[an][0]),ah.call(this._yaxis,ao[an][1])])}else{if(ao[an][0]==null){ai=true;ar.push([null,ah.call(this._yaxis,ao[an][1])])}else{if(ao[an][1]==null){ai=true;ar.push([am.call(this._xaxis,ao[an][0]),null])}}}}if(ai){this.renderer.smooth=false;if(this._type==="line"){al.show=false}}if(this._type==="line"&&al.show){for(var an=0,ak=al.hiData.length;an<ak;an++){this.renderer._hiBandGridData.push([am.call(this._xaxis,al.hiData[an][0]),ah.call(this._yaxis,al.hiData[an][1])])}for(var an=0,ak=al.lowData.length;an<ak;an++){this.renderer._lowBandGridData.push([am.call(this._xaxis,al.lowData[an][0]),ah.call(this._yaxis,al.lowData[an][1])])}}if(this._type==="line"&&this.renderer.smooth&&ar.length>2){var ap;if(this.renderer.constrainSmoothing){ap=J.call(this,ar);this.renderer._smoothedData=ap[0];this.renderer._smoothedPlotData=ap[1];if(al.show){ap=J.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ap[0];ap=J.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ap[0]}ap=null}else{ap=F.call(this,ar);this.renderer._smoothedData=ap[0];this.renderer._smoothedPlotData=ap[1];if(al.show){ap=F.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ap[0];ap=F.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ap[0]}ap=null}}return ar};L.jqplot.LineRenderer.prototype.draw=function(ax,aI,ai,aB){var aC;var aq=L.extend(true,{},ai);var ak=(aq.shadow!=u)?aq.shadow:this.shadow;var aJ=(aq.showLine!=u)?aq.showLine:this.showLine;var aA=(aq.fill!=u)?aq.fill:this.fill;var ah=(aq.fillAndStroke!=u)?aq.fillAndStroke:this.fillAndStroke;var ar,ay,av,aE;ax.save();if(aI.length){if(aJ){if(aA){if(this.fillToZero){var aF=this.negativeColor;if(!this.useNegativeColors){aF=aq.fillStyle}var ao=false;var ap=aq.fillStyle;if(ah){var aH=aI.slice(0)}if(this.index==0||!this._stack){var aw=[];var aL=(this.renderer.smooth)?this.renderer._smoothedPlotData:this._plotData;this._areaPoints=[];var aG=this._yaxis.series_u2p(this.fillToValue);var aj=this._xaxis.series_u2p(this.fillToValue);aq.closePath=true;if(this.fillAxis=="y"){aw.push([aI[0][0],aG]);this._areaPoints.push([aI[0][0],aG]);for(var aC=0;aC<aI.length-1;aC++){aw.push(aI[aC]);this._areaPoints.push(aI[aC]);if(aL[aC][1]*aL[aC+1][1]<=0){if(aL[aC][1]<0){ao=true;aq.fillStyle=aF}else{ao=false;aq.fillStyle=ap}var an=aI[aC][0]+(aI[aC+1][0]-aI[aC][0])*(aG-aI[aC][1])/(aI[aC+1][1]-aI[aC][1]);aw.push([an,aG]);this._areaPoints.push([an,aG]);if(ak){this.renderer.shadowRenderer.draw(ax,aw,aq)}this.renderer.shapeRenderer.draw(ax,aw,aq);aw=[[an,aG]]}}if(aL[aI.length-1][1]<0){ao=true;aq.fillStyle=aF}else{ao=false;aq.fillStyle=ap}aw.push(aI[aI.length-1]);this._areaPoints.push(aI[aI.length-1]);aw.push([aI[aI.length-1][0],aG]);this._areaPoints.push([aI[aI.length-1][0],aG])}if(ak){this.renderer.shadowRenderer.draw(ax,aw,aq)}this.renderer.shapeRenderer.draw(ax,aw,aq)}else{var au=this._prevGridData;for(var aC=au.length;aC>0;aC--){aI.push(au[aC-1])}if(ak){this.renderer.shadowRenderer.draw(ax,aI,aq)}this._areaPoints=aI;this.renderer.shapeRenderer.draw(ax,aI,aq)}}else{if(ah){var aH=aI.slice(0)}if(this.index==0||!this._stack){var al=ax.canvas.height;aI.unshift([aI[0][0],al]);var aD=aI.length;aI.push([aI[aD-1][0],al])}else{var au=this._prevGridData;for(var aC=au.length;aC>0;aC--){aI.push(au[aC-1])}}this._areaPoints=aI;if(ak){this.renderer.shadowRenderer.draw(ax,aI,aq)}this.renderer.shapeRenderer.draw(ax,aI,aq)}if(ah){var az=L.extend(true,{},aq,{fill:false,closePath:false});this.renderer.shapeRenderer.draw(ax,aH,az);if(this.markerRenderer.show){if(this.renderer.smooth){aH=this.gridData}for(aC=0;aC<aH.length;aC++){this.markerRenderer.draw(aH[aC][0],aH[aC][1],ax,aq.markerOptions)}}}}else{if(this.renderer.bands.show){var am;var aK=L.extend(true,{},aq);if(this.renderer.bands.showLines){am=(this.renderer.smooth)?this.renderer._hiBandSmoothedData:this.renderer._hiBandGridData;this.renderer.shapeRenderer.draw(ax,am,aq);am=(this.renderer.smooth)?this.renderer._lowBandSmoothedData:this.renderer._lowBandGridData;this.renderer.shapeRenderer.draw(ax,am,aK)}if(this.renderer.bands.fill){if(this.renderer.smooth){am=this.renderer._hiBandSmoothedData.concat(this.renderer._lowBandSmoothedData.reverse())}else{am=this.renderer._hiBandGridData.concat(this.renderer._lowBandGridData.reverse())}this._areaPoints=am;aK.closePath=true;aK.fill=true;aK.fillStyle=this.renderer.bands.fillColor;this.renderer.shapeRenderer.draw(ax,am,aK)}}if(ak){this.renderer.shadowRenderer.draw(ax,aI,aq)}this.renderer.shapeRenderer.draw(ax,aI,aq)}}var ar=av=ay=aE=null;for(aC=0;aC<this._areaPoints.length;aC++){var at=this._areaPoints[aC];if(ar>at[0]||ar==null){ar=at[0]}if(aE<at[1]||aE==null){aE=at[1]}if(av<at[0]||av==null){av=at[0]}if(ay>at[1]||ay==null){ay=at[1]}}if(this.type==="line"&&this.renderer.bands.show){aE=this._yaxis.series_u2p(this.renderer.bands._min);ay=this._yaxis.series_u2p(this.renderer.bands._max)}this._boundingBox=[[ar,aE],[av,ay]];if(this.markerRenderer.show&&!aA){if(this.renderer.smooth){aI=this.gridData}for(aC=0;aC<aI.length;aC++){if(aI[aC][0]!=null&&aI[aC][1]!=null){this.markerRenderer.draw(aI[aC][0],aI[aC][1],ax,aq.markerOptions)}}}}ax.restore()};L.jqplot.LineRenderer.prototype.drawShadow=function(ah,aj,ai){};function z(ak,aj,ah){for(var ai=0;ai<this.series.length;ai++){if(this.series[ai].renderer.constructor==L.jqplot.LineRenderer){if(this.series[ai].highlightMouseOver){this.series[ai].highlightMouseDown=false}}}}function af(){if(this.plugins.lineRenderer&&this.plugins.lineRenderer.highlightCanvas){this.plugins.lineRenderer.highlightCanvas.resetCanvas();this.plugins.lineRenderer.highlightCanvas=null}this.plugins.lineRenderer.highlightedSeriesIndex=null;this.plugins.lineRenderer.highlightCanvas=new L.jqplot.GenericCanvas();this.eventCanvas._elem.before(this.plugins.lineRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-lineRenderer-highlight-canvas",this._plotDimensions,this));this.plugins.lineRenderer.highlightCanvas.setContext();this.eventCanvas._elem.bind("mouseleave",{plot:this},function(ah){aa(ah.data.plot)})}function ac(an,am,ak,aj){var ai=an.series[am];var ah=an.plugins.lineRenderer.highlightCanvas;ah._ctx.clearRect(0,0,ah._ctx.canvas.width,ah._ctx.canvas.height);ai._highlightedPoint=ak;an.plugins.lineRenderer.highlightedSeriesIndex=am;var al={fillStyle:ai.highlightColor};if(ai.type==="line"&&ai.renderer.bands.show){al.fill=true;al.closePath=true}ai.renderer.shapeRenderer.draw(ah._ctx,aj,al);ah=null}function aa(aj){var ah=aj.plugins.lineRenderer.highlightCanvas;ah._ctx.clearRect(0,0,ah._ctx.canvas.width,ah._ctx.canvas.height);for(var ai=0;ai<aj.series.length;ai++){aj.series[ai]._highlightedPoint=null}aj.plugins.lineRenderer.highlightedSeriesIndex=null;aj.target.trigger("jqplotDataUnhighlight");ah=null}function h(al,ak,ao,an,am){if(an){var aj=[an.seriesIndex,an.pointIndex,an.data];var ai=jQuery.Event("jqplotDataMouseOver");ai.pageX=al.pageX;ai.pageY=al.pageY;am.target.trigger(ai,aj);if(am.series[aj[0]].highlightMouseOver&&!(aj[0]==am.plugins.lineRenderer.highlightedSeriesIndex)){var ah=jQuery.Event("jqplotDataHighlight");ah.which=al.which;ah.pageX=al.pageX;ah.pageY=al.pageY;am.target.trigger(ah,aj);ac(am,an.seriesIndex,an.pointIndex,an.points)}}else{if(an==null){aa(am)}}}function e(ak,aj,an,am,al){if(am){var ai=[am.seriesIndex,am.pointIndex,am.data];if(al.series[ai[0]].highlightMouseDown&&!(ai[0]==al.plugins.lineRenderer.highlightedSeriesIndex)){var ah=jQuery.Event("jqplotDataHighlight");ah.which=ak.which;ah.pageX=ak.pageX;ah.pageY=ak.pageY;al.target.trigger(ah,ai);ac(al,am.seriesIndex,am.pointIndex,am.points)}}else{if(am==null){aa(al)}}}function ad(aj,ai,am,al,ak){var ah=ak.plugins.lineRenderer.highlightedSeriesIndex;if(ah!=null&&ak.series[ah].highlightMouseDown){aa(ak)}}function g(ak,aj,an,am,al){if(am){var ai=[am.seriesIndex,am.pointIndex,am.data];var ah=jQuery.Event("jqplotDataClick");ah.which=ak.which;ah.pageX=ak.pageX;ah.pageY=ak.pageY;al.target.trigger(ah,ai)}}function s(al,ak,ao,an,am){if(an){var aj=[an.seriesIndex,an.pointIndex,an.data];var ah=am.plugins.lineRenderer.highlightedSeriesIndex;if(ah!=null&&am.series[ah].highlightMouseDown){aa(am)}var ai=jQuery.Event("jqplotDataRightClick");ai.which=al.which;ai.pageX=al.pageX;ai.pageY=al.pageY;am.target.trigger(ai,aj)}}L.jqplot.LinearAxisRenderer=function(){};L.jqplot.LinearAxisRenderer.prototype.init=function(ah){this.breakPoints=null;this.breakTickLabel="≈";this.drawBaseline=true;this.baselineWidth=null;this.baselineColor=null;this.forceTickAt0=false;this.forceTickAt100=false;this.tickInset=0;this.minorTicks=0;this.alignTicks=false;this._autoFormatString="";this._overrideFormatString=false;this._scalefact=1;L.extend(true,this,ah);if(this.breakPoints){if(!L.isArray(this.breakPoints)){this.breakPoints=null}else{if(this.breakPoints.length<2||this.breakPoints[1]<=this.breakPoints[0]){this.breakPoints=null}}}if(this.numberTicks!=null&&this.numberTicks<2){this.numberTicks=2}this.resetDataBounds()};L.jqplot.LinearAxisRenderer.prototype.draw=function(ah,ao){if(this.show){this.renderer.createTicks.call(this,ao);var an=0;var ai;if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=L(document.createElement("div"));this._elem.addClass("jqplot-axis jqplot-"+this.name);this._elem.css("position","absolute");if(this.name=="xaxis"||this.name=="x2axis"){this._elem.width(this._plotDimensions.width)}else{this._elem.height(this._plotDimensions.height)}this.labelOptions.axis=this.name;this._label=new this.labelRenderer(this.labelOptions);if(this._label.show){var am=this._label.draw(ah,ao);am.appendTo(this._elem);am=null}var al=this._ticks;var ak;for(var aj=0;aj<al.length;aj++){ak=al[aj];if(ak.show&&ak.showLabel&&(!ak.isMinorTick||this.showMinorTicks)){this._elem.append(ak.draw(ah,ao))}}ak=null;al=null}return this._elem};L.jqplot.LinearAxisRenderer.prototype.reset=function(){this.min=this._options.min;this.max=this._options.max;this.tickInterval=this._options.tickInterval;this.numberTicks=this._options.numberTicks;this._autoFormatString="";if(this._overrideFormatString&&this.tickOptions&&this.tickOptions.formatString){this.tickOptions.formatString=""}};L.jqplot.LinearAxisRenderer.prototype.set=function(){var ao=0;var aj;var ai=0;var an=0;var ah=(this._label==null)?false:this._label.show;if(this.show){var am=this._ticks;var al;for(var ak=0;ak<am.length;ak++){al=am[ak];if(!al._breakTick&&al.show&&al.showLabel&&(!al.isMinorTick||this.showMinorTicks)){if(this.name=="xaxis"||this.name=="x2axis"){aj=al._elem.outerHeight(true)}else{aj=al._elem.outerWidth(true)}if(aj>ao){ao=aj}}}al=null;am=null;if(ah){ai=this._label._elem.outerWidth(true);an=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){ao=ao+an;this._elem.css({height:ao+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){ao=ao+an;this._elem.css({height:ao+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){ao=ao+ai;this._elem.css({width:ao+"px",left:"0px",top:"0px"});if(ah&&this._label.constructor==L.jqplot.AxisLabelRenderer){this._label._elem.css("width",ai+"px")}}else{ao=ao+ai;this._elem.css({width:ao+"px",right:"0px",top:"0px"});if(ah&&this._label.constructor==L.jqplot.AxisLabelRenderer){this._label._elem.css("width",ai+"px")}}}}}};L.jqplot.LinearAxisRenderer.prototype.createTicks=function(aj){var aT=this._ticks;var aK=this.ticks;var az=this.name;var aB=this._dataBounds;var ah=(this.name.charAt(0)==="x")?this._plotDimensions.width:this._plotDimensions.height;var an;var a6,aI;var ap,ao;var a4,a0;var aH=this.min;var a5=this.max;var aW=this.numberTicks;var ba=this.tickInterval;var am=30;this._scalefact=(Math.max(ah,am+1)-am)/300;if(aK.length){for(a0=0;a0<aK.length;a0++){var aO=aK[a0];var aU=new this.tickRenderer(this.tickOptions);if(L.isArray(aO)){aU.value=aO[0];if(this.breakPoints){if(aO[0]==this.breakPoints[0]){aU.label=this.breakTickLabel;aU._breakTick=true;aU.showGridline=false;aU.showMark=false}else{if(aO[0]>this.breakPoints[0]&&aO[0]<=this.breakPoints[1]){aU.show=false;aU.showGridline=false;aU.label=aO[1]}else{aU.label=aO[1]}}}else{aU.label=aO[1]}aU.setTick(aO[0],this.name);this._ticks.push(aU)}else{if(L.isPlainObject(aO)){L.extend(true,aU,aO);aU.axis=this.name;this._ticks.push(aU)}else{aU.value=aO;if(this.breakPoints){if(aO==this.breakPoints[0]){aU.label=this.breakTickLabel;aU._breakTick=true;aU.showGridline=false;aU.showMark=false}else{if(aO>this.breakPoints[0]&&aO<=this.breakPoints[1]){aU.show=false;aU.showGridline=false}}}aU.setTick(aO,this.name);this._ticks.push(aU)}}}this.numberTicks=aK.length;this.min=this._ticks[0].value;this.max=this._ticks[this.numberTicks-1].value;this.tickInterval=(this.max-this.min)/(this.numberTicks-1)}else{if(az=="xaxis"||az=="x2axis"){ah=this._plotDimensions.width}else{ah=this._plotDimensions.height}var ax=this.numberTicks;if(this.alignTicks){if(this.name==="x2axis"&&aj.axes.xaxis.show){ax=aj.axes.xaxis.numberTicks}else{if(this.name.charAt(0)==="y"&&this.name!=="yaxis"&&this.name!=="yMidAxis"&&aj.axes.yaxis.show){ax=aj.axes.yaxis.numberTicks}}}a6=((this.min!=null)?this.min:aB.min);aI=((this.max!=null)?this.max:aB.max);var av=aI-a6;var aS,ay;var at;if(this.tickOptions==null||!this.tickOptions.formatString){this._overrideFormatString=true}if(this.min==null||this.max==null&&this.tickInterval==null&&!this.autoscale){if(this.forceTickAt0){if(a6>0){a6=0}if(aI<0){aI=0}}if(this.forceTickAt100){if(a6>100){a6=100}if(aI<100){aI=100}}var aE=false,a1=false;if(this.min!=null){aE=true}else{if(this.max!=null){a1=true}}var aP=L.jqplot.LinearTickGenerator(a6,aI,this._scalefact,ax,aE,a1);var aw=(this.min!=null)?a6:a6+av*(this.padMin-1);var aQ=(this.max!=null)?aI:aI-av*(this.padMax-1);if(a6<aw||aI>aQ){aw=(this.min!=null)?a6:a6-av*(this.padMin-1);aQ=(this.max!=null)?aI:aI+av*(this.padMax-1);aP=L.jqplot.LinearTickGenerator(aw,aQ,this._scalefact,ax,aE,a1)}this.min=aP[0];this.max=aP[1];this.numberTicks=aP[2];this._autoFormatString=aP[3];this.tickInterval=aP[4]}else{if(a6==aI){var ai=0.05;if(a6>0){ai=Math.max(Math.log(a6)/Math.LN10,0.05)}a6-=ai;aI+=ai}if(this.autoscale&&this.min==null&&this.max==null){var ak,al,ar;var aC=false;var aN=false;var aA={min:null,max:null,average:null,stddev:null};for(var a0=0;a0<this._series.length;a0++){var aV=this._series[a0];var aD=(aV.fillAxis=="x")?aV._xaxis.name:aV._yaxis.name;if(this.name==aD){var aR=aV._plotValues[aV.fillAxis];var aG=aR[0];var a2=aR[0];for(var aZ=1;aZ<aR.length;aZ++){if(aR[aZ]<aG){aG=aR[aZ]}else{if(aR[aZ]>a2){a2=aR[aZ]}}}var au=(a2-aG)/a2;if(aV.renderer.constructor==L.jqplot.BarRenderer){if(aG>=0&&(aV.fillToZero||au>0.1)){aC=true}else{aC=false;if(aV.fill&&aV.fillToZero&&aG<0&&a2>0){aN=true}else{aN=false}}}else{if(aV.fill){if(aG>=0&&(aV.fillToZero||au>0.1)){aC=true}else{if(aG<0&&a2>0&&aV.fillToZero){aC=false;aN=true}else{aC=false;aN=false}}}else{if(aG<0){aC=false}}}}}if(aC){this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing);this.min=0;aH=0;al=aI/(this.numberTicks-1);at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)));if(al/at==parseInt(al/at,10)){al+=at}this.tickInterval=Math.ceil(al/at)*at;this.max=this.tickInterval*(this.numberTicks-1)}else{if(aN){this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing);var aJ=Math.ceil(Math.abs(a6)/av*(this.numberTicks-1));var a9=this.numberTicks-1-aJ;al=Math.max(Math.abs(a6/aJ),Math.abs(aI/a9));at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)));this.tickInterval=Math.ceil(al/at)*at;this.max=this.tickInterval*a9;this.min=-this.tickInterval*aJ}else{if(this.numberTicks==null){if(this.tickInterval){this.numberTicks=3+Math.ceil(av/this.tickInterval)}else{this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing)}}if(this.tickInterval==null){al=av/(this.numberTicks-1);if(al<1){at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)))}else{at=1}this.tickInterval=Math.ceil(al*at*this.pad)/at}else{at=1/this.tickInterval}ak=this.tickInterval*(this.numberTicks-1);ar=(ak-av)/2;if(this.min==null){this.min=Math.floor(at*(a6-ar))/at}if(this.max==null){this.max=this.min+ak}}}var aF=L.jqplot.getSignificantFigures(this.tickInterval);var aM;if(aF.digitsLeft>=aF.significantDigits){aM="%d"}else{var at=Math.max(0,5-aF.digitsLeft);at=Math.min(at,aF.digitsRight);aM="%."+at+"f"}this._autoFormatString=aM}else{aS=(this.min!=null)?this.min:a6-av*(this.padMin-1);ay=(this.max!=null)?this.max:aI+av*(this.padMax-1);av=ay-aS;if(this.numberTicks==null){if(this.tickInterval!=null){this.numberTicks=Math.ceil((ay-aS)/this.tickInterval)+1}else{if(ah>100){this.numberTicks=parseInt(3+(ah-100)/75,10)}else{this.numberTicks=2}}}if(this.tickInterval==null){this.tickInterval=av/(this.numberTicks-1)}if(this.max==null){ay=aS+this.tickInterval*(this.numberTicks-1)}if(this.min==null){aS=ay-this.tickInterval*(this.numberTicks-1)}var aF=L.jqplot.getSignificantFigures(this.tickInterval);var aM;if(aF.digitsLeft>=aF.significantDigits){aM="%d"}else{var at=Math.max(0,5-aF.digitsLeft);at=Math.min(at,aF.digitsRight);aM="%."+at+"f"}this._autoFormatString=aM;this.min=aS;this.max=ay}if(this.renderer.constructor==L.jqplot.LinearAxisRenderer&&this._autoFormatString==""){av=this.max-this.min;var a7=new this.tickRenderer(this.tickOptions);var aL=a7.formatString||L.jqplot.config.defaultTickFormatString;var aL=aL.match(L.jqplot.sprintf.regex)[0];var a3=0;if(aL){if(aL.search(/[fFeEgGpP]/)>-1){var aY=aL.match(/\%\.(\d{0,})?[eEfFgGpP]/);if(aY){a3=parseInt(aY[1],10)}else{a3=6}}else{if(aL.search(/[di]/)>-1){a3=0}}var aq=Math.pow(10,-a3);if(this.tickInterval<aq){if(aW==null&&ba==null){this.tickInterval=aq;if(a5==null&&aH==null){this.min=Math.floor(this._dataBounds.min/aq)*aq;if(this.min==this._dataBounds.min){this.min=this._dataBounds.min-this.tickInterval}this.max=Math.ceil(this._dataBounds.max/aq)*aq;if(this.max==this._dataBounds.max){this.max=this._dataBounds.max+this.tickInterval}var aX=(this.max-this.min)/this.tickInterval;aX=aX.toFixed(11);aX=Math.ceil(aX);this.numberTicks=aX+1}else{if(a5==null){var aX=(this._dataBounds.max-this.min)/this.tickInterval;aX=aX.toFixed(11);this.numberTicks=Math.ceil(aX)+2;this.max=this.min+this.tickInterval*(this.numberTicks-1)}else{if(aH==null){var aX=(this.max-this._dataBounds.min)/this.tickInterval;aX=aX.toFixed(11);this.numberTicks=Math.ceil(aX)+2;this.min=this.max-this.tickInterval*(this.numberTicks-1)}else{this.numberTicks=Math.ceil((a5-aH)/this.tickInterval)+1;this.min=Math.floor(aH*Math.pow(10,a3))/Math.pow(10,a3);this.max=Math.ceil(a5*Math.pow(10,a3))/Math.pow(10,a3);this.numberTicks=Math.ceil((this.max-this.min)/this.tickInterval)+1}}}}}}}}if(this._overrideFormatString&&this._autoFormatString!=""){this.tickOptions=this.tickOptions||{};this.tickOptions.formatString=this._autoFormatString}var aU,a8;for(var a0=0;a0<this.numberTicks;a0++){a4=this.min+a0*this.tickInterval;aU=new this.tickRenderer(this.tickOptions);aU.setTick(a4,this.name);this._ticks.push(aU);if(a0<this.numberTicks-1){for(var aZ=0;aZ<this.minorTicks;aZ++){a4+=this.tickInterval/(this.minorTicks+1);a8=L.extend(true,{},this.tickOptions,{name:this.name,value:a4,label:"",isMinorTick:true});aU=new this.tickRenderer(a8);this._ticks.push(aU)}}aU=null}}if(this.tickInset){this.min=this.min-this.tickInset*this.tickInterval;this.max=this.max+this.tickInset*this.tickInterval}aT=null};L.jqplot.LinearAxisRenderer.prototype.resetTickValues=function(aj){if(L.isArray(aj)&&aj.length==this._ticks.length){var ai;for(var ah=0;ah<aj.length;ah++){ai=this._ticks[ah];ai.value=aj[ah];ai.label=ai.formatter(ai.formatString,aj[ah]);ai.label=ai.prefix+ai.label;ai._elem.html(ai.label)}ai=null;this.min=L.jqplot.arrayMin(aj);this.max=L.jqplot.arrayMax(aj);this.pack()}};L.jqplot.LinearAxisRenderer.prototype.pack=function(aj,ai){aj=aj||{};ai=ai||this._offsets;var ay=this._ticks;var au=this.max;var at=this.min;var ao=ai.max;var am=ai.min;var aq=(this._label==null)?false:this._label.show;for(var ar in aj){this._elem.css(ar,aj[ar])}this._offsets=ai;var ak=ao-am;var al=au-at;if(this.breakPoints){al=al-this.breakPoints[1]+this.breakPoints[0];this.p2u=function(aA){return(aA-am)*al/ak+at};this.u2p=function(aA){if(aA>this.breakPoints[0]&&aA<this.breakPoints[1]){aA=this.breakPoints[0]}if(aA<=this.breakPoints[0]){return(aA-at)*ak/al+am}else{return(aA-this.breakPoints[1]+this.breakPoints[0]-at)*ak/al+am}};if(this.name.charAt(0)=="x"){this.series_u2p=function(aA){if(aA>this.breakPoints[0]&&aA<this.breakPoints[1]){aA=this.breakPoints[0]}if(aA<=this.breakPoints[0]){return(aA-at)*ak/al}else{return(aA-this.breakPoints[1]+this.breakPoints[0]-at)*ak/al}};this.series_p2u=function(aA){return aA*al/ak+at}}else{this.series_u2p=function(aA){if(aA>this.breakPoints[0]&&aA<this.breakPoints[1]){aA=this.breakPoints[0]}if(aA>=this.breakPoints[1]){return(aA-au)*ak/al}else{return(aA+this.breakPoints[1]-this.breakPoints[0]-au)*ak/al}};this.series_p2u=function(aA){return aA*al/ak+au}}}else{this.p2u=function(aA){return(aA-am)*al/ak+at};this.u2p=function(aA){return(aA-at)*ak/al+am};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(aA){return(aA-at)*ak/al};this.series_p2u=function(aA){return aA*al/ak+at}}else{this.series_u2p=function(aA){return(aA-au)*ak/al};this.series_p2u=function(aA){return aA*al/ak+au}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(var av=0;av<ay.length;av++){var ap=ay[av];if(ap.show&&ap.showLabel){var ah;if(ap.constructor==L.jqplot.CanvasAxisTickRenderer&&ap.angle){var ax=(this.name=="xaxis")?1:-1;switch(ap.labelPosition){case"auto":if(ax*ap.angle<0){ah=-ap.getWidth()+ap._textRenderer.height*Math.sin(-ap._textRenderer.angle)/2}else{ah=-ap._textRenderer.height*Math.sin(ap._textRenderer.angle)/2}break;case"end":ah=-ap.getWidth()+ap._textRenderer.height*Math.sin(-ap._textRenderer.angle)/2;break;case"start":ah=-ap._textRenderer.height*Math.sin(ap._textRenderer.angle)/2;break;case"middle":ah=-ap.getWidth()/2+ap._textRenderer.height*Math.sin(-ap._textRenderer.angle)/2;break;default:ah=-ap.getWidth()/2+ap._textRenderer.height*Math.sin(-ap._textRenderer.angle)/2;break}}else{ah=-ap.getWidth()/2}var az=this.u2p(ap.value)+ah+"px";ap._elem.css("left",az);ap.pack()}}if(aq){var an=this._label._elem.outerWidth(true);this._label._elem.css("left",am+ak/2-an/2+"px");if(this.name=="xaxis"){this._label._elem.css("bottom","0px")}else{this._label._elem.css("top","0px")}this._label.pack()}}else{for(var av=0;av<ay.length;av++){var ap=ay[av];if(ap.show&&ap.showLabel){var ah;if(ap.constructor==L.jqplot.CanvasAxisTickRenderer&&ap.angle){var ax=(this.name=="yaxis")?1:-1;switch(ap.labelPosition){case"auto":case"end":if(ax*ap.angle<0){ah=-ap._textRenderer.height*Math.cos(-ap._textRenderer.angle)/2}else{ah=-ap.getHeight()+ap._textRenderer.height*Math.cos(ap._textRenderer.angle)/2}break;case"start":if(ap.angle>0){ah=-ap._textRenderer.height*Math.cos(-ap._textRenderer.angle)/2}else{ah=-ap.getHeight()+ap._textRenderer.height*Math.cos(ap._textRenderer.angle)/2}break;case"middle":ah=-ap.getHeight()/2;break;default:ah=-ap.getHeight()/2;break}}else{ah=-ap.getHeight()/2}var az=this.u2p(ap.value)+ah+"px";ap._elem.css("top",az);ap.pack()}}if(aq){var aw=this._label._elem.outerHeight(true);this._label._elem.css("top",ao-ak/2-aw/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px")}else{this._label._elem.css("right","0px")}this._label.pack()}}}ay=null};function i(ai){var ah;ai=Math.abs(ai);if(ai>=10){ah="%d"}else{if(ai>1){if(ai===parseInt(ai,10)){ah="%d"}else{ah="%.1f"}}else{var aj=-Math.floor(Math.log(ai)/Math.LN10);ah="%."+aj+"f"}}return ah}var b=[0.1,0.2,0.3,0.4,0.5,0.8,1,2,3,4,5];var c=function(ai){var ah=b.indexOf(ai);if(ah>0){return b[ah-1]}else{return b[b.length-1]/100}};var k=function(ai){var ah=b.indexOf(ai);if(ah<b.length-1){return b[ah+1]}else{return b[0]*100}};function d(al,au,at){var aq=Math.floor(at/2);var ai=Math.ceil(at*1.5);var ak=Number.MAX_VALUE;var ah=(au-al);var ax;var ap;var ar;var ay=L.jqplot.getSignificantFigures;var aw;var an;var ao;var av;for(var am=0,aj=ai-aq+1;am<aj;am++){ao=aq+am;ax=ah/(ao-1);ap=ay(ax);ax=Math.abs(at-ao)+ap.digitsRight;if(ax<ak){ak=ax;ar=ao;av=ap.digitsRight}else{if(ax===ak){if(ap.digitsRight<av){ar=ao;av=ap.digitsRight}}}}aw=Math.max(av,Math.max(ay(al).digitsRight,ay(au).digitsRight));if(aw===0){an="%d"}else{an="%."+aw+"f"}ax=ah/(ar-1);return[al,au,ar,an,ax]}function W(ai,al){al=al||7;var ak=ai/(al-1);var aj=Math.pow(10,Math.floor(Math.log(ak)/Math.LN10));var am=ak/aj;var ah;if(aj<1){if(am>5){ah=10*aj}else{if(am>2){ah=5*aj}else{if(am>1){ah=2*aj}else{ah=aj}}}}else{if(am>5){ah=10*aj}else{if(am>4){ah=5*aj}else{if(am>3){ah=4*aj}else{if(am>2){ah=3*aj}else{if(am>1){ah=2*aj}else{ah=aj}}}}}}return ah}function Q(ai,ah){ah=ah||1;var ak=Math.floor(Math.log(ai)/Math.LN10);var am=Math.pow(10,ak);var al=ai/am;var aj;al=al/ah;if(al<=0.38){aj=0.1}else{if(al<=1.6){aj=0.2}else{if(al<=4){aj=0.5}else{if(al<=8){aj=1}else{if(al<=16){aj=2}else{aj=5}}}}}return aj*am}function x(aj,ai){var al=Math.floor(Math.log(aj)/Math.LN10);var an=Math.pow(10,al);var am=aj/an;var ah;var ak;am=am/ai;if(am<=0.38){ak=0.1}else{if(am<=1.6){ak=0.2}else{if(am<=4){ak=0.5}else{if(am<=8){ak=1}else{if(am<=16){ak=2}else{ak=5}}}}}ah=ak*an;return[ah,ak,an]}L.jqplot.LinearTickGenerator=function(an,aq,aj,ak,ao,ar){ao=(ao===null)?false:ao;ar=(ar===null||ao)?false:ar;if(an===aq){aq=(aq)?0:1}aj=aj||1;if(aq<an){var at=aq;aq=an;an=at}var ai=[];var aw=Q(aq-an,aj);var av=L.jqplot.getSignificantFigures;if(ak==null){if(!ao&&!ar){ai[0]=Math.floor(an/aw)*aw;ai[1]=Math.ceil(aq/aw)*aw;ai[2]=Math.round((ai[1]-ai[0])/aw+1);ai[3]=i(aw);ai[4]=aw}else{if(ao){ai[0]=an;ai[2]=Math.ceil((aq-an)/aw+1);ai[1]=an+(ai[2]-1)*aw;var au=av(an).digitsRight;var ap=av(aw).digitsRight;if(au<ap){ai[3]=i(aw)}else{ai[3]="%."+au+"f"}ai[4]=aw}else{if(ar){ai[1]=aq;ai[2]=Math.ceil((aq-an)/aw+1);ai[0]=aq-(ai[2]-1)*aw;var al=av(aq).digitsRight;var ap=av(aw).digitsRight;if(al<ap){ai[3]=i(aw)}else{ai[3]="%."+al+"f"}ai[4]=aw}}}}else{var am=[];am[0]=Math.floor(an/aw)*aw;am[1]=Math.ceil(aq/aw)*aw;am[2]=Math.round((am[1]-am[0])/aw+1);am[3]=i(aw);am[4]=aw;if(am[2]===ak){ai=am}else{var ah=W(am[1]-am[0],ak);ai[0]=am[0];ai[2]=ak;ai[4]=ah;ai[3]=i(ah);ai[1]=ai[0]+(ai[2]-1)*ai[4]}}return ai};L.jqplot.LinearTickGenerator.bestLinearInterval=Q;L.jqplot.LinearTickGenerator.bestInterval=W;L.jqplot.LinearTickGenerator.bestLinearComponents=x;L.jqplot.LinearTickGenerator.bestConstrainedInterval=d;L.jqplot.MarkerRenderer=function(ah){this.show=true;this.style="filledCircle";this.lineWidth=2;this.size=9;this.color="#666666";this.shadow=true;this.shadowAngle=45;this.shadowOffset=1;this.shadowDepth=3;this.shadowAlpha="0.07";this.shadowRenderer=new L.jqplot.ShadowRenderer();this.shapeRenderer=new L.jqplot.ShapeRenderer();L.extend(true,this,ah)};L.jqplot.MarkerRenderer.prototype.init=function(ah){L.extend(true,this,ah);var aj={angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,lineWidth:this.lineWidth,depth:this.shadowDepth,closePath:true};if(this.style.indexOf("filled")!=-1){aj.fill=true}if(this.style.indexOf("ircle")!=-1){aj.isarc=true;aj.closePath=false}this.shadowRenderer.init(aj);var ai={fill:false,isarc:false,strokeStyle:this.color,fillStyle:this.color,lineWidth:this.lineWidth,closePath:true};if(this.style.indexOf("filled")!=-1){ai.fill=true}if(this.style.indexOf("ircle")!=-1){ai.isarc=true;ai.closePath=false}this.shapeRenderer.init(ai)};L.jqplot.MarkerRenderer.prototype.drawDiamond=function(aj,ai,am,al,ao){var ah=1.2;var ap=this.size/2/ah;var an=this.size/2*ah;var ak=[[aj-ap,ai],[aj,ai+an],[aj+ap,ai],[aj,ai-an]];if(this.shadow){this.shadowRenderer.draw(am,ak)}this.shapeRenderer.draw(am,ak,ao)};L.jqplot.MarkerRenderer.prototype.drawPlus=function(ak,aj,an,am,aq){var ai=1;var ar=this.size/2*ai;var ao=this.size/2*ai;var ap=[[ak,aj-ao],[ak,aj+ao]];var al=[[ak+ar,aj],[ak-ar,aj]];var ah=L.extend(true,{},this.options,{closePath:false});if(this.shadow){this.shadowRenderer.draw(an,ap,{closePath:false});this.shadowRenderer.draw(an,al,{closePath:false})}this.shapeRenderer.draw(an,ap,ah);this.shapeRenderer.draw(an,al,ah)};L.jqplot.MarkerRenderer.prototype.drawX=function(ak,aj,an,am,aq){var ai=1;var ar=this.size/2*ai;var ao=this.size/2*ai;var ah=L.extend(true,{},this.options,{closePath:false});var ap=[[ak-ar,aj-ao],[ak+ar,aj+ao]];var al=[[ak-ar,aj+ao],[ak+ar,aj-ao]];if(this.shadow){this.shadowRenderer.draw(an,ap,{closePath:false});this.shadowRenderer.draw(an,al,{closePath:false})}this.shapeRenderer.draw(an,ap,ah);this.shapeRenderer.draw(an,al,ah)};L.jqplot.MarkerRenderer.prototype.drawDash=function(aj,ai,am,al,ao){var ah=1;var ap=this.size/2*ah;var an=this.size/2*ah;var ak=[[aj-ap,ai],[aj+ap,ai]];if(this.shadow){this.shadowRenderer.draw(am,ak)}this.shapeRenderer.draw(am,ak,ao)};L.jqplot.MarkerRenderer.prototype.drawLine=function(am,al,ah,ak,ai){var aj=[am,al];if(this.shadow){this.shadowRenderer.draw(ah,aj)}this.shapeRenderer.draw(ah,aj,ai)};L.jqplot.MarkerRenderer.prototype.drawSquare=function(aj,ai,am,al,ao){var ah=1;var ap=this.size/2/ah;var an=this.size/2*ah;var ak=[[aj-ap,ai-an],[aj-ap,ai+an],[aj+ap,ai+an],[aj+ap,ai-an]];if(this.shadow){this.shadowRenderer.draw(am,ak)}this.shapeRenderer.draw(am,ak,ao)};L.jqplot.MarkerRenderer.prototype.drawCircle=function(ai,ao,ak,an,al){var ah=this.size/2;var aj=2*Math.PI;var am=[ai,ao,ah,0,aj,true];if(this.shadow){this.shadowRenderer.draw(ak,am)}this.shapeRenderer.draw(ak,am,al)};L.jqplot.MarkerRenderer.prototype.draw=function(ah,ak,ai,aj){aj=aj||{};if(aj.show==null||aj.show!=false){if(aj.color&&!aj.fillStyle){aj.fillStyle=aj.color}if(aj.color&&!aj.strokeStyle){aj.strokeStyle=aj.color}switch(this.style){case"diamond":this.drawDiamond(ah,ak,ai,false,aj);break;case"filledDiamond":this.drawDiamond(ah,ak,ai,true,aj);break;case"circle":this.drawCircle(ah,ak,ai,false,aj);break;case"filledCircle":this.drawCircle(ah,ak,ai,true,aj);break;case"square":this.drawSquare(ah,ak,ai,false,aj);break;case"filledSquare":this.drawSquare(ah,ak,ai,true,aj);break;case"x":this.drawX(ah,ak,ai,true,aj);break;case"plus":this.drawPlus(ah,ak,ai,true,aj);break;case"dash":this.drawDash(ah,ak,ai,true,aj);break;case"line":this.drawLine(ah,ak,ai,false,aj);break;default:this.drawDiamond(ah,ak,ai,false,aj);break}}};L.jqplot.ShadowRenderer=function(ah){this.angle=45;this.offset=1;this.alpha=0.07;this.lineWidth=1.5;this.lineJoin="miter";this.lineCap="round";this.closePath=false;this.fill=false;this.depth=3;this.strokeStyle="rgba(0,0,0,0.1)";this.isarc=false;L.extend(true,this,ah)};L.jqplot.ShadowRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.ShadowRenderer.prototype.draw=function(av,at,ax){av.save();var ah=(ax!=null)?ax:{};var au=(ah.fill!=null)?ah.fill:this.fill;var ap=(ah.fillRect!=null)?ah.fillRect:this.fillRect;var ao=(ah.closePath!=null)?ah.closePath:this.closePath;var al=(ah.offset!=null)?ah.offset:this.offset;var aj=(ah.alpha!=null)?ah.alpha:this.alpha;var an=(ah.depth!=null)?ah.depth:this.depth;var aw=(ah.isarc!=null)?ah.isarc:this.isarc;var aq=(ah.linePattern!=null)?ah.linePattern:this.linePattern;av.lineWidth=(ah.lineWidth!=null)?ah.lineWidth:this.lineWidth;av.lineJoin=(ah.lineJoin!=null)?ah.lineJoin:this.lineJoin;av.lineCap=(ah.lineCap!=null)?ah.lineCap:this.lineCap;av.strokeStyle=ah.strokeStyle||this.strokeStyle||"rgba(0,0,0,"+aj+")";av.fillStyle=ah.fillStyle||this.fillStyle||"rgba(0,0,0,"+aj+")";for(var ak=0;ak<an;ak++){var ar=L.jqplot.LinePattern(av,aq);av.translate(Math.cos(this.angle*Math.PI/180)*al,Math.sin(this.angle*Math.PI/180)*al);ar.beginPath();if(aw){av.arc(at[0],at[1],at[2],at[3],at[4],true)}else{if(ap){if(ap){av.fillRect(at[0],at[1],at[2],at[3])}}else{if(at&&at.length){var ai=true;for(var am=0;am<at.length;am++){if(at[am][0]!=null&&at[am][1]!=null){if(ai){ar.moveTo(at[am][0],at[am][1]);ai=false}else{ar.lineTo(at[am][0],at[am][1])}}else{ai=true}}}}}if(ao){ar.closePath()}if(au){av.fill()}else{av.stroke()}}av.restore()};L.jqplot.ShapeRenderer=function(ah){this.lineWidth=1.5;this.linePattern="solid";this.lineJoin="miter";this.lineCap="round";this.closePath=false;this.fill=false;this.isarc=false;this.fillRect=false;this.strokeRect=false;this.clearRect=false;this.strokeStyle="#999999";this.fillStyle="#999999";L.extend(true,this,ah)};L.jqplot.ShapeRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.ShapeRenderer.prototype.draw=function(at,aq,av){at.save();var ah=(av!=null)?av:{};var ar=(ah.fill!=null)?ah.fill:this.fill;var am=(ah.closePath!=null)?ah.closePath:this.closePath;var an=(ah.fillRect!=null)?ah.fillRect:this.fillRect;var ak=(ah.strokeRect!=null)?ah.strokeRect:this.strokeRect;var ai=(ah.clearRect!=null)?ah.clearRect:this.clearRect;var au=(ah.isarc!=null)?ah.isarc:this.isarc;var ao=(ah.linePattern!=null)?ah.linePattern:this.linePattern;var ap=L.jqplot.LinePattern(at,ao);at.lineWidth=ah.lineWidth||this.lineWidth;at.lineJoin=ah.lineJoin||this.lineJoin;at.lineCap=ah.lineCap||this.lineCap;at.strokeStyle=(ah.strokeStyle||ah.color)||this.strokeStyle;at.fillStyle=ah.fillStyle||this.fillStyle;at.beginPath();if(au){at.arc(aq[0],aq[1],aq[2],aq[3],aq[4],true);if(am){at.closePath()}if(ar){at.fill()}else{at.stroke()}at.restore();return}else{if(ai){at.clearRect(aq[0],aq[1],aq[2],aq[3]);at.restore();return}else{if(an||ak){if(an){at.fillRect(aq[0],aq[1],aq[2],aq[3])}if(ak){at.strokeRect(aq[0],aq[1],aq[2],aq[3]);at.restore();return}}else{if(aq&&aq.length){var aj=true;for(var al=0;al<aq.length;al++){if(aq[al][0]!=null&&aq[al][1]!=null){if(aj){ap.moveTo(aq[al][0],aq[al][1]);aj=false}else{ap.lineTo(aq[al][0],aq[al][1])}}else{aj=true}}if(am){ap.closePath()}if(ar){at.fill()}else{at.stroke()}}}}}at.restore()};L.jqplot.TableLegendRenderer=function(){};L.jqplot.TableLegendRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.TableLegendRenderer.prototype.addrow=function(aq,ak,ah,ao){var al=(ah)?this.rowSpacing+"px":"0px";var ap;var aj;var ai;var an;var am;ai=document.createElement("tr");ap=L(ai);ap.addClass("jqplot-table-legend");ai=null;if(ao){ap.prependTo(this._elem)}else{ap.appendTo(this._elem)}if(this.showSwatches){aj=L(document.createElement("td"));aj.addClass("jqplot-table-legend jqplot-table-legend-swatch");aj.css({textAlign:"center",paddingTop:al});an=L(document.createElement("div"));an.addClass("jqplot-table-legend-swatch-outline");am=L(document.createElement("div"));am.addClass("jqplot-table-legend-swatch");am.css({backgroundColor:ak,borderColor:ak});ap.append(aj.append(an.append(am)))}if(this.showLabels){aj=L(document.createElement("td"));aj.addClass("jqplot-table-legend jqplot-table-legend-label");aj.css("paddingTop",al);ap.append(aj);if(this.escapeHtml){aj.text(aq)}else{aj.html(aq)}}aj=null;an=null;am=null;ap=null;ai=null};L.jqplot.TableLegendRenderer.prototype.draw=function(){if(this._elem){this._elem.emptyForce();this._elem=null}if(this.show){var am=this._series;var ai=document.createElement("table");this._elem=L(ai);this._elem.addClass("jqplot-table-legend");var ar={position:"absolute"};if(this.background){ar.background=this.background}if(this.border){ar.border=this.border}if(this.fontSize){ar.fontSize=this.fontSize}if(this.fontFamily){ar.fontFamily=this.fontFamily}if(this.textColor){ar.textColor=this.textColor}if(this.marginTop!=null){ar.marginTop=this.marginTop}if(this.marginBottom!=null){ar.marginBottom=this.marginBottom}if(this.marginLeft!=null){ar.marginLeft=this.marginLeft}if(this.marginRight!=null){ar.marginRight=this.marginRight}var ah=false,ao=false,aq;for(var an=0;an<am.length;an++){aq=am[an];if(aq._stack||aq.renderer.constructor==L.jqplot.BezierCurveRenderer){ao=true}if(aq.show&&aq.showLabel){var al=this.labels[an]||aq.label.toString();if(al){var aj=aq.color;if(ao&&an<am.length-1){ah=true}else{if(ao&&an==am.length-1){ah=false}}this.renderer.addrow.call(this,al,aj,ah,ao);ah=true}for(var ak=0;ak<L.jqplot.addLegendRowHooks.length;ak++){var ap=L.jqplot.addLegendRowHooks[ak].call(this,aq);if(ap){this.renderer.addrow.call(this,ap.label,ap.color,ah);ah=true}}al=null}}}return this._elem};L.jqplot.TableLegendRenderer.prototype.pack=function(aj){if(this.show){if(this.placement=="insideGrid"){switch(this.location){case"nw":var ai=aj.left;var ah=aj.top;this._elem.css("left",ai);this._elem.css("top",ah);break;case"n":var ai=(aj.left+(this._plotDimensions.width-aj.right))/2-this.getWidth()/2;var ah=aj.top;this._elem.css("left",ai);this._elem.css("top",ah);break;case"ne":var ai=aj.right;var ah=aj.top;this._elem.css({right:ai,top:ah});break;case"e":var ai=aj.right;var ah=(aj.top+(this._plotDimensions.height-aj.bottom))/2-this.getHeight()/2;this._elem.css({right:ai,top:ah});break;case"se":var ai=aj.right;var ah=aj.bottom;this._elem.css({right:ai,bottom:ah});break;case"s":var ai=(aj.left+(this._plotDimensions.width-aj.right))/2-this.getWidth()/2;var ah=aj.bottom;this._elem.css({left:ai,bottom:ah});break;case"sw":var ai=aj.left;var ah=aj.bottom;this._elem.css({left:ai,bottom:ah});break;case"w":var ai=aj.left;var ah=(aj.top+(this._plotDimensions.height-aj.bottom))/2-this.getHeight()/2;this._elem.css({left:ai,top:ah});break;default:var ai=aj.right;var ah=aj.bottom;this._elem.css({right:ai,bottom:ah});break}}else{if(this.placement=="outside"){switch(this.location){case"nw":var ai=this._plotDimensions.width-aj.left;var ah=aj.top;this._elem.css("right",ai);this._elem.css("top",ah);break;case"n":var ai=(aj.left+(this._plotDimensions.width-aj.right))/2-this.getWidth()/2;var ah=this._plotDimensions.height-aj.top;this._elem.css("left",ai);this._elem.css("bottom",ah);break;case"ne":var ai=this._plotDimensions.width-aj.right;var ah=aj.top;this._elem.css({left:ai,top:ah});break;case"e":var ai=this._plotDimensions.width-aj.right;var ah=(aj.top+(this._plotDimensions.height-aj.bottom))/2-this.getHeight()/2;this._elem.css({left:ai,top:ah});break;case"se":var ai=this._plotDimensions.width-aj.right;var ah=aj.bottom;this._elem.css({left:ai,bottom:ah});break;case"s":var ai=(aj.left+(this._plotDimensions.width-aj.right))/2-this.getWidth()/2;var ah=this._plotDimensions.height-aj.bottom;this._elem.css({left:ai,top:ah});break;case"sw":var ai=this._plotDimensions.width-aj.left;var ah=aj.bottom;this._elem.css({right:ai,bottom:ah});break;case"w":var ai=this._plotDimensions.width-aj.left;var ah=(aj.top+(this._plotDimensions.height-aj.bottom))/2-this.getHeight()/2;this._elem.css({right:ai,top:ah});break;default:var ai=aj.right;var ah=aj.bottom;this._elem.css({right:ai,bottom:ah});break}}else{switch(this.location){case"nw":this._elem.css({left:0,top:aj.top});break;case"n":var ai=(aj.left+(this._plotDimensions.width-aj.right))/2-this.getWidth()/2;this._elem.css({left:ai,top:aj.top});break;case"ne":this._elem.css({right:0,top:aj.top});break;case"e":var ah=(aj.top+(this._plotDimensions.height-aj.bottom))/2-this.getHeight()/2;this._elem.css({right:aj.right,top:ah});break;case"se":this._elem.css({right:aj.right,bottom:aj.bottom});break;case"s":var ai=(aj.left+(this._plotDimensions.width-aj.right))/2-this.getWidth()/2;this._elem.css({left:ai,bottom:aj.bottom});break;case"sw":this._elem.css({left:aj.left,bottom:aj.bottom});break;case"w":var ah=(aj.top+(this._plotDimensions.height-aj.bottom))/2-this.getHeight()/2;this._elem.css({left:aj.left,top:ah});break;default:this._elem.css({right:aj.right,bottom:aj.bottom});break}}}}};L.jqplot.ThemeEngine=function(){this.themes={};this.activeTheme=null};L.jqplot.ThemeEngine.prototype.init=function(){var ak=new L.jqplot.Theme({_name:"Default"});var an,ai,am;for(an in ak.target){if(an=="textColor"){ak.target[an]=this.target.css("color")}else{ak.target[an]=this.target.css(an)}}if(this.title.show&&this.title._elem){for(an in ak.title){if(an=="textColor"){ak.title[an]=this.title._elem.css("color")}else{ak.title[an]=this.title._elem.css(an)}}}for(an in ak.grid){ak.grid[an]=this.grid[an]}if(ak.grid.backgroundColor==null&&this.grid.background!=null){ak.grid.backgroundColor=this.grid.background}if(this.legend.show&&this.legend._elem){for(an in ak.legend){if(an=="textColor"){ak.legend[an]=this.legend._elem.css("color")}else{ak.legend[an]=this.legend._elem.css(an)}}}var aj;for(ai=0;ai<this.series.length;ai++){aj=this.series[ai];if(aj.renderer.constructor==L.jqplot.LineRenderer){ak.series.push(new p())}else{if(aj.renderer.constructor==L.jqplot.BarRenderer){ak.series.push(new T())}else{if(aj.renderer.constructor==L.jqplot.PieRenderer){ak.series.push(new f())}else{if(aj.renderer.constructor==L.jqplot.DonutRenderer){ak.series.push(new G())}else{if(aj.renderer.constructor==L.jqplot.FunnelRenderer){ak.series.push(new Z())}else{if(aj.renderer.constructor==L.jqplot.MeterGaugeRenderer){ak.series.push(new D())}else{ak.series.push({})}}}}}}for(an in ak.series[ai]){ak.series[ai][an]=aj[an]}}var ah,al;for(an in this.axes){al=this.axes[an];ah=ak.axes[an]=new P();ah.borderColor=al.borderColor;ah.borderWidth=al.borderWidth;if(al._ticks&&al._ticks[0]){for(am in ah.ticks){if(al._ticks[0].hasOwnProperty(am)){ah.ticks[am]=al._ticks[0][am]}else{if(al._ticks[0]._elem){ah.ticks[am]=al._ticks[0]._elem.css(am)}}}}if(al._label&&al._label.show){for(am in ah.label){if(al._label[am]){ah.label[am]=al._label[am]}else{if(al._label._elem){if(am=="textColor"){ah.label[am]=al._label._elem.css("color")}else{ah.label[am]=al._label._elem.css(am)}}}}}}this.themeEngine._add(ak);this.themeEngine.activeTheme=this.themeEngine.themes[ak._name]};L.jqplot.ThemeEngine.prototype.get=function(ah){if(!ah){return this.activeTheme}else{return this.themes[ah]}};function O(ai,ah){return ai-ah}L.jqplot.ThemeEngine.prototype.getThemeNames=function(){var ah=[];for(var ai in this.themes){ah.push(ai)}return ah.sort(O)};L.jqplot.ThemeEngine.prototype.getThemes=function(){var ai=[];var ah=[];for(var ak in this.themes){ai.push(ak)}ai.sort(O);for(var aj=0;aj<ai.length;aj++){ah.push(this.themes[ai[aj]])}return ah};L.jqplot.ThemeEngine.prototype.activate=function(av,aB){var ah=false;if(!aB&&this.activeTheme&&this.activeTheme._name){aB=this.activeTheme._name}if(!this.themes.hasOwnProperty(aB)){throw new Error("No theme of that name")}else{var am=this.themes[aB];this.activeTheme=am;var aA,at=false,ar=false;var ai=["xaxis","x2axis","yaxis","y2axis"];for(aw=0;aw<ai.length;aw++){var an=ai[aw];if(am.axesStyles.borderColor!=null){av.axes[an].borderColor=am.axesStyles.borderColor}if(am.axesStyles.borderWidth!=null){av.axes[an].borderWidth=am.axesStyles.borderWidth}}for(var az in av.axes){var ak=av.axes[az];if(ak.show){var aq=am.axes[az]||{};var ao=am.axesStyles;var al=L.jqplot.extend(true,{},aq,ao);aA=(am.axesStyles.borderColor!=null)?am.axesStyles.borderColor:al.borderColor;if(al.borderColor!=null){ak.borderColor=al.borderColor;ah=true}aA=(am.axesStyles.borderWidth!=null)?am.axesStyles.borderWidth:al.borderWidth;if(al.borderWidth!=null){ak.borderWidth=al.borderWidth;ah=true}if(ak._ticks&&ak._ticks[0]){for(var aj in al.ticks){aA=al.ticks[aj];if(aA!=null){ak.tickOptions[aj]=aA;ak._ticks=[];ah=true}}}if(ak._label&&ak._label.show){for(var aj in al.label){aA=al.label[aj];if(aA!=null){ak.labelOptions[aj]=aA;ah=true}}}}}for(var au in am.grid){if(am.grid[au]!=null){av.grid[au]=am.grid[au]}}if(!ah){av.grid.draw()}if(av.legend.show){for(au in am.legend){if(am.legend[au]!=null){av.legend[au]=am.legend[au]}}}if(av.title.show){for(au in am.title){if(am.title[au]!=null){av.title[au]=am.title[au]}}}var aw;for(aw=0;aw<am.series.length;aw++){var ap={};var ay=false;for(au in am.series[aw]){aA=(am.seriesStyles[au]!=null)?am.seriesStyles[au]:am.series[aw][au];if(aA!=null){ap[au]=aA;if(au=="color"){av.series[aw].renderer.shapeRenderer.fillStyle=aA;av.series[aw].renderer.shapeRenderer.strokeStyle=aA;av.series[aw][au]=aA}else{if((au=="lineWidth")||(au=="linePattern")){av.series[aw].renderer.shapeRenderer[au]=aA;av.series[aw][au]=aA}else{if(au=="markerOptions"){V(av.series[aw].markerOptions,aA);V(av.series[aw].markerRenderer,aA)}else{av.series[aw][au]=aA}}}ah=true}}}if(ah){av.target.empty();av.draw()}for(au in am.target){if(am.target[au]!=null){av.target.css(au,am.target[au])}}}};L.jqplot.ThemeEngine.prototype._add=function(ai,ah){if(ah){ai._name=ah}if(!ai._name){ai._name=Date.parse(new Date())}if(!this.themes.hasOwnProperty(ai._name)){this.themes[ai._name]=ai}else{throw new Error("jqplot.ThemeEngine Error: Theme already in use")}};L.jqplot.ThemeEngine.prototype.remove=function(ah){if(ah=="Default"){return false}return delete this.themes[ah]};L.jqplot.ThemeEngine.prototype.newTheme=function(ah,aj){if(typeof(ah)=="object"){aj=aj||ah;ah=null}if(aj&&aj._name){ah=aj._name}else{ah=ah||Date.parse(new Date())}var ai=this.copy(this.themes.Default._name,ah);L.jqplot.extend(ai,aj);return ai};function B(aj){if(aj==null||typeof(aj)!="object"){return aj}var ah=new aj.constructor();for(var ai in aj){ah[ai]=B(aj[ai])}return ah}L.jqplot.clone=B;function V(aj,ai){if(ai==null||typeof(ai)!="object"){return}for(var ah in ai){if(ah=="highlightColors"){aj[ah]=B(ai[ah])}if(ai[ah]!=null&&typeof(ai[ah])=="object"){if(!aj.hasOwnProperty(ah)){aj[ah]={}}V(aj[ah],ai[ah])}else{aj[ah]=ai[ah]}}}L.jqplot.merge=V;L.jqplot.extend=function(){var am=arguments[0]||{},ak=1,al=arguments.length,ah=false,aj;if(typeof am==="boolean"){ah=am;am=arguments[1]||{};ak=2}if(typeof am!=="object"&&!toString.call(am)==="[object Function]"){am={}}for(;ak<al;ak++){if((aj=arguments[ak])!=null){for(var ai in aj){var an=am[ai],ao=aj[ai];if(am===ao){continue}if(ah&&ao&&typeof ao==="object"&&!ao.nodeType){am[ai]=L.jqplot.extend(ah,an||(ao.length!=null?[]:{}),ao)}else{if(ao!==u){am[ai]=ao}}}}}return am};L.jqplot.ThemeEngine.prototype.rename=function(ai,ah){if(ai=="Default"||ah=="Default"){throw new Error("jqplot.ThemeEngine Error: Cannot rename from/to Default")}if(this.themes.hasOwnProperty(ah)){throw new Error("jqplot.ThemeEngine Error: New name already in use.")}else{if(this.themes.hasOwnProperty(ai)){var aj=this.copy(ai,ah);this.remove(ai);return aj}}throw new Error("jqplot.ThemeEngine Error: Old name or new name invalid")};L.jqplot.ThemeEngine.prototype.copy=function(ah,aj,al){if(aj=="Default"){throw new Error("jqplot.ThemeEngine Error: Cannot copy over Default theme")}if(!this.themes.hasOwnProperty(ah)){var ai="jqplot.ThemeEngine Error: Source name invalid";throw new Error(ai)}if(this.themes.hasOwnProperty(aj)){var ai="jqplot.ThemeEngine Error: Target name invalid";throw new Error(ai)}else{var ak=B(this.themes[ah]);ak._name=aj;L.jqplot.extend(true,ak,al);this._add(ak);return ak}};L.jqplot.Theme=function(ah,ai){if(typeof(ah)=="object"){ai=ai||ah;ah=null}ah=ah||Date.parse(new Date());this._name=ah;this.target={backgroundColor:null};this.legend={textColor:null,fontFamily:null,fontSize:null,border:null,background:null};this.title={textColor:null,fontFamily:null,fontSize:null,textAlign:null};this.seriesStyles={};this.series=[];this.grid={drawGridlines:null,gridLineColor:null,gridLineWidth:null,backgroundColor:null,borderColor:null,borderWidth:null,shadow:null};this.axesStyles={label:{},ticks:{}};this.axes={};if(typeof(ai)=="string"){this._name=ai}else{if(typeof(ai)=="object"){L.jqplot.extend(true,this,ai)}}};var P=function(){this.borderColor=null;this.borderWidth=null;this.ticks=new o();this.label=new t()};var o=function(){this.show=null;this.showGridline=null;this.showLabel=null;this.showMark=null;this.size=null;this.textColor=null;this.whiteSpace=null;this.fontSize=null;this.fontFamily=null};var t=function(){this.textColor=null;this.whiteSpace=null;this.fontSize=null;this.fontFamily=null;this.fontWeight=null};var p=function(){this.color=null;this.lineWidth=null;this.linePattern=null;this.shadow=null;this.fillColor=null;this.showMarker=null;this.markerOptions=new I()};var I=function(){this.show=null;this.style=null;this.lineWidth=null;this.size=null;this.color=null;this.shadow=null};var T=function(){this.color=null;this.seriesColors=null;this.lineWidth=null;this.shadow=null;this.barPadding=null;this.barMargin=null;this.barWidth=null;this.highlightColors=null};var f=function(){this.seriesColors=null;this.padding=null;this.sliceMargin=null;this.fill=null;this.shadow=null;this.startAngle=null;this.lineWidth=null;this.highlightColors=null};var G=function(){this.seriesColors=null;this.padding=null;this.sliceMargin=null;this.fill=null;this.shadow=null;this.startAngle=null;this.lineWidth=null;this.innerDiameter=null;this.thickness=null;this.ringMargin=null;this.highlightColors=null};var Z=function(){this.color=null;this.lineWidth=null;this.shadow=null;this.padding=null;this.sectionMargin=null;this.seriesColors=null;this.highlightColors=null};var D=function(){this.padding=null;this.backgroundColor=null;this.ringColor=null;this.tickColor=null;this.ringWidth=null;this.intervalColors=null;this.intervalInnerRadius=null;this.intervalOuterRadius=null;this.hubRadius=null;this.needleThickness=null;this.needlePad=null};L.fn.jqplotChildText=function(){return L(this).contents().filter(function(){return this.nodeType==3}).text()};L.fn.jqplotGetComputedFontStyle=function(){var ak=window.getComputedStyle?window.getComputedStyle(this[0],""):this[0].currentStyle;var ai=ak["font-style"]?["font-style","font-weight","font-size","font-family"]:["fontStyle","fontWeight","fontSize","fontFamily"];var al=[];for(var aj=0;aj<ai.length;++aj){var ah=String(ak[ai[aj]]);if(ah&&ah!="normal"){al.push(ah)}}return al.join(" ")};L.fn.jqplotToImageCanvas=function(aj){aj=aj||{};var av=(aj.x_offset==null)?0:aj.x_offset;var ax=(aj.y_offset==null)?0:aj.y_offset;var al=(aj.backgroundColor==null)?"rgb(255,255,255)":aj.backgroundColor;if(L(this).width()==0||L(this).height()==0){return null}if(L.jqplot.use_excanvas){return null}var an=document.createElement("canvas");var aA=L(this).outerHeight(true);var at=L(this).outerWidth(true);var am=L(this).offset();var ao=am.left;var aq=am.top;var au=0,ar=0;var ay=["jqplot-table-legend","jqplot-xaxis-tick","jqplot-x2axis-tick","jqplot-yaxis-tick","jqplot-y2axis-tick","jqplot-y3axis-tick","jqplot-y4axis-tick","jqplot-y5axis-tick","jqplot-y6axis-tick","jqplot-y7axis-tick","jqplot-y8axis-tick","jqplot-y9axis-tick","jqplot-xaxis-label","jqplot-x2axis-label","jqplot-yaxis-label","jqplot-y2axis-label","jqplot-y3axis-label","jqplot-y4axis-label","jqplot-y5axis-label","jqplot-y6axis-label","jqplot-y7axis-label","jqplot-y8axis-label","jqplot-y9axis-label"];var ap,ah,ai,aB;for(var az=0;az<ay.length;az++){L(this).find("."+ay[az]).each(function(){ap=L(this).offset().top-aq;ah=L(this).offset().left-ao;aB=ah+L(this).outerWidth(true)+au;ai=ap+L(this).outerHeight(true)+ar;if(ah<-au){at=at-au-ah;au=-ah}if(ap<-ar){aA=aA-ar-ap;ar=-ap}if(aB>at){at=aB}if(ai>aA){aA=ai}})}an.width=at+Number(av);an.height=aA+Number(ax);var ak=an.getContext("2d");ak.save();ak.fillStyle=al;ak.fillRect(0,0,an.width,an.height);ak.restore();ak.translate(au,ar);ak.textAlign="left";ak.textBaseline="top";function aC(aE){var aF=parseInt(L(aE).css("line-height"),10);if(isNaN(aF)){aF=parseInt(L(aE).css("font-size"),10)*1.2}return aF}function aD(aF,aE,aS,aG,aO,aH){var aQ=aC(aF);var aK=L(aF).innerWidth();var aL=L(aF).innerHeight();var aN=aS.split(/\s+/);var aR=aN.length;var aP="";var aM=[];var aU=aO;var aT=aG;for(var aJ=0;aJ<aR;aJ++){aP+=aN[aJ];if(aE.measureText(aP).width>aK){aM.push(aJ);aP="";aJ--}}if(aM.length===0){if(L(aF).css("textAlign")==="center"){aT=aG+(aH-aE.measureText(aP).width)/2-au}aE.fillText(aS,aT,aO)}else{aP=aN.slice(0,aM[0]).join(" ");if(L(aF).css("textAlign")==="center"){aT=aG+(aH-aE.measureText(aP).width)/2-au}aE.fillText(aP,aT,aU);aU+=aQ;for(var aJ=1,aI=aM.length;aJ<aI;aJ++){aP=aN.slice(aM[aJ-1],aM[aJ]).join(" ");if(L(aF).css("textAlign")==="center"){aT=aG+(aH-aE.measureText(aP).width)/2-au}aE.fillText(aP,aT,aU);aU+=aQ}aP=aN.slice(aM[aJ-1],aN.length).join(" ");if(L(aF).css("textAlign")==="center"){aT=aG+(aH-aE.measureText(aP).width)/2-au}aE.fillText(aP,aT,aU)}}function aw(aG,aJ,aE){var aN=aG.tagName.toLowerCase();var aF=L(aG).position();var aK=window.getComputedStyle?window.getComputedStyle(aG,""):aG.currentStyle;var aI=aJ+aF.left+parseInt(aK.marginLeft,10)+parseInt(aK.borderLeftWidth,10)+parseInt(aK.paddingLeft,10);var aL=aE+aF.top+parseInt(aK.marginTop,10)+parseInt(aK.borderTopWidth,10)+parseInt(aK.paddingTop,10);var aM=an.width;if((aN=="div"||aN=="span")&&!L(aG).hasClass("jqplot-highlighter-tooltip")){L(aG).children().each(function(){aw(this,aI,aL)});var aO=L(aG).jqplotChildText();if(aO){ak.font=L(aG).jqplotGetComputedFontStyle();ak.fillStyle=L(aG).css("color");aD(aG,ak,aO,aI,aL,aM)}}else{if(aN==="table"&&L(aG).hasClass("jqplot-table-legend")){ak.strokeStyle=L(aG).css("border-top-color");ak.fillStyle=L(aG).css("background-color");ak.fillRect(aI,aL,L(aG).innerWidth(),L(aG).innerHeight());if(parseInt(L(aG).css("border-top-width"),10)>0){ak.strokeRect(aI,aL,L(aG).innerWidth(),L(aG).innerHeight())}L(aG).find("div.jqplot-table-legend-swatch-outline").each(function(){var aU=L(this);ak.strokeStyle=aU.css("border-top-color");var aQ=aI+aU.position().left;var aR=aL+aU.position().top;ak.strokeRect(aQ,aR,aU.innerWidth(),aU.innerHeight());aQ+=parseInt(aU.css("padding-left"),10);aR+=parseInt(aU.css("padding-top"),10);var aT=aU.innerHeight()-2*parseInt(aU.css("padding-top"),10);var aP=aU.innerWidth()-2*parseInt(aU.css("padding-left"),10);var aS=aU.children("div.jqplot-table-legend-swatch");ak.fillStyle=aS.css("background-color");ak.fillRect(aQ,aR,aP,aT)});L(aG).find("td.jqplot-table-legend-label").each(function(){var aR=L(this);var aP=aI+aR.position().left;var aQ=aL+aR.position().top+parseInt(aR.css("padding-top"),10);ak.font=aR.jqplotGetComputedFontStyle();ak.fillStyle=aR.css("color");aD(aR,ak,aR.text(),aP,aQ,aM)});var aH=null}else{if(aN=="canvas"){ak.drawImage(aG,aI,aL)}}}}L(this).children().each(function(){aw(this,av,ax)});return an};L.fn.jqplotToImageStr=function(ai){var ah=L(this).jqplotToImageCanvas(ai);if(ah){return ah.toDataURL("image/png")}else{return null}};L.fn.jqplotToImageElem=function(ah){var ai=document.createElement("img");var aj=L(this).jqplotToImageStr(ah);ai.src=aj;return ai};L.fn.jqplotToImageElemStr=function(ah){var ai="<img src="+L(this).jqplotToImageStr(ah)+" />";return ai};L.fn.jqplotSaveImage=function(){var ah=L(this).jqplotToImageStr({});if(ah){window.location.href=ah.replace("image/png","image/octet-stream")}};L.fn.jqplotViewImage=function(){var ai=L(this).jqplotToImageElemStr({});var aj=L(this).jqplotToImageStr({});if(ai){var ah=window.open("");ah.document.open("image/png");ah.document.write(ai);ah.document.close();ah=null}};var ag=function(){this.syntax=ag.config.syntax;this._type="jsDate";this.proxy=new Date();this.options={};this.locale=ag.regional.getLocale();this.formatString="";this.defaultCentury=ag.config.defaultCentury;switch(arguments.length){case 0:break;case 1:if(l(arguments[0])=="[object Object]"&&arguments[0]._type!="jsDate"){var aj=this.options=arguments[0];this.syntax=aj.syntax||this.syntax;this.defaultCentury=aj.defaultCentury||this.defaultCentury;this.proxy=ag.createDate(aj.date)}else{this.proxy=ag.createDate(arguments[0])}break;default:var ah=[];for(var ai=0;ai<arguments.length;ai++){ah.push(arguments[ai])}this.proxy=new Date();this.proxy.setFullYear.apply(this.proxy,ah.slice(0,3));if(ah.slice(3).length){this.proxy.setHours.apply(this.proxy,ah.slice(3))}break}};ag.config={defaultLocale:"en",syntax:"perl",defaultCentury:1900};ag.prototype.add=function(aj,ai){var ah=E[ai]||E.day;if(typeof ah=="number"){this.proxy.setTime(this.proxy.getTime()+(ah*aj))}else{ah.add(this,aj)}return this};ag.prototype.clone=function(){return new ag(this.proxy.getTime())};ag.prototype.getUtcOffset=function(){return this.proxy.getTimezoneOffset()*60000};ag.prototype.diff=function(ai,al,ah){ai=new ag(ai);if(ai===null){return null}var aj=E[al]||E.day;if(typeof aj=="number"){var ak=(this.proxy.getTime()-ai.proxy.getTime())/aj}else{var ak=aj.diff(this.proxy,ai.proxy)}return(ah?ak:Math[ak>0?"floor":"ceil"](ak))};ag.prototype.getAbbrDayName=function(){return ag.regional[this.locale]["dayNamesShort"][this.proxy.getDay()]};ag.prototype.getAbbrMonthName=function(){return ag.regional[this.locale]["monthNamesShort"][this.proxy.getMonth()]};ag.prototype.getAMPM=function(){return this.proxy.getHours()>=12?"PM":"AM"};ag.prototype.getAmPm=function(){return this.proxy.getHours()>=12?"pm":"am"};ag.prototype.getCentury=function(){return parseInt(this.proxy.getFullYear()/100,10)};ag.prototype.getDate=function(){return this.proxy.getDate()};ag.prototype.getDay=function(){return this.proxy.getDay()};ag.prototype.getDayOfWeek=function(){var ah=this.proxy.getDay();return ah===0?7:ah};ag.prototype.getDayOfYear=function(){var ai=this.proxy;var ah=ai-new Date(""+ai.getFullYear()+"/1/1 GMT");ah+=ai.getTimezoneOffset()*60000;ai=null;return parseInt(ah/60000/60/24,10)+1};ag.prototype.getDayName=function(){return ag.regional[this.locale]["dayNames"][this.proxy.getDay()]};ag.prototype.getFullWeekOfYear=function(){var ak=this.proxy;var ah=this.getDayOfYear();var aj=6-ak.getDay();var ai=parseInt((ah+aj)/7,10);return ai};ag.prototype.getFullYear=function(){return this.proxy.getFullYear()};ag.prototype.getGmtOffset=function(){var ah=this.proxy.getTimezoneOffset()/60;var ai=ah<0?"+":"-";ah=Math.abs(ah);return ai+N(Math.floor(ah),2)+":"+N((ah%1)*60,2)};ag.prototype.getHours=function(){return this.proxy.getHours()};ag.prototype.getHours12=function(){var ah=this.proxy.getHours();return ah>12?ah-12:(ah==0?12:ah)};ag.prototype.getIsoWeek=function(){var ak=this.proxy;var aj=this.getWeekOfYear();var ah=(new Date(""+ak.getFullYear()+"/1/1")).getDay();var ai=aj+(ah>4||ah<=1?0:1);if(ai==53&&(new Date(""+ak.getFullYear()+"/12/31")).getDay()<4){ai=1}else{if(ai===0){ak=new ag(new Date(""+(ak.getFullYear()-1)+"/12/31"));ai=ak.getIsoWeek()}}ak=null;return ai};ag.prototype.getMilliseconds=function(){return this.proxy.getMilliseconds()};ag.prototype.getMinutes=function(){return this.proxy.getMinutes()};ag.prototype.getMonth=function(){return this.proxy.getMonth()};ag.prototype.getMonthName=function(){return ag.regional[this.locale]["monthNames"][this.proxy.getMonth()]};ag.prototype.getMonthNumber=function(){return this.proxy.getMonth()+1};ag.prototype.getSeconds=function(){return this.proxy.getSeconds()};ag.prototype.getShortYear=function(){return this.proxy.getYear()%100};ag.prototype.getTime=function(){return this.proxy.getTime()};ag.prototype.getTimezoneAbbr=function(){return this.proxy.toString().replace(/^.*\(([^)]+)\)$/,"$1")};ag.prototype.getTimezoneName=function(){var ah=/(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString());return ah[1]||ah[2]||"GMT"+this.getGmtOffset()};ag.prototype.getTimezoneOffset=function(){return this.proxy.getTimezoneOffset()};ag.prototype.getWeekOfYear=function(){var ah=this.getDayOfYear();var aj=7-this.getDayOfWeek();var ai=parseInt((ah+aj)/7,10);return ai};ag.prototype.getUnix=function(){return Math.round(this.proxy.getTime()/1000,0)};ag.prototype.getYear=function(){return this.proxy.getYear()};ag.prototype.next=function(ah){ah=ah||"day";return this.clone().add(1,ah)};ag.prototype.set=function(){switch(arguments.length){case 0:this.proxy=new Date();break;case 1:if(l(arguments[0])=="[object Object]"&&arguments[0]._type!="jsDate"){var aj=this.options=arguments[0];this.syntax=aj.syntax||this.syntax;this.defaultCentury=aj.defaultCentury||this.defaultCentury;this.proxy=ag.createDate(aj.date)}else{this.proxy=ag.createDate(arguments[0])}break;default:var ah=[];for(var ai=0;ai<arguments.length;ai++){ah.push(arguments[ai])}this.proxy=new Date();this.proxy.setFullYear.apply(this.proxy,ah.slice(0,3));if(ah.slice(3).length){this.proxy.setHours.apply(this.proxy,ah.slice(3))}break}return this};ag.prototype.setDate=function(ah){this.proxy.setDate(ah);return this};ag.prototype.setFullYear=function(){this.proxy.setFullYear.apply(this.proxy,arguments);return this};ag.prototype.setHours=function(){this.proxy.setHours.apply(this.proxy,arguments);return this};ag.prototype.setMilliseconds=function(ah){this.proxy.setMilliseconds(ah);return this};ag.prototype.setMinutes=function(){this.proxy.setMinutes.apply(this.proxy,arguments);return this};ag.prototype.setMonth=function(){this.proxy.setMonth.apply(this.proxy,arguments);return this};ag.prototype.setSeconds=function(){this.proxy.setSeconds.apply(this.proxy,arguments);return this};ag.prototype.setTime=function(ah){this.proxy.setTime(ah);return this};ag.prototype.setYear=function(){this.proxy.setYear.apply(this.proxy,arguments);return this};ag.prototype.strftime=function(ah){ah=ah||this.formatString||ag.regional[this.locale]["formatString"];return ag.strftime(this,ah,this.syntax)};ag.prototype.toString=function(){return this.proxy.toString()};ag.prototype.toYmdInt=function(){return(this.proxy.getFullYear()*10000)+(this.getMonthNumber()*100)+this.proxy.getDate()};ag.regional={en:{monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],formatString:"%Y-%m-%d %H:%M:%S"},fr:{monthNames:["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"],monthNamesShort:["Jan","Fév","Mar","Avr","Mai","Jun","Jul","Aoû","Sep","Oct","Nov","Déc"],dayNames:["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"],dayNamesShort:["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"],formatString:"%Y-%m-%d %H:%M:%S"},de:{monthNames:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],monthNamesShort:["Jan","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],dayNames:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],dayNamesShort:["So","Mo","Di","Mi","Do","Fr","Sa"],formatString:"%Y-%m-%d %H:%M:%S"},es:{monthNames:["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"],monthNamesShort:["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic"],dayNames:["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"],dayNamesShort:["Dom","Lun","Mar","Mié","Juv","Vie","Sáb"],formatString:"%Y-%m-%d %H:%M:%S"},ru:{monthNames:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],monthNamesShort:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],dayNames:["воскресенье","понедельник","вторник","среда","четверг","пятница","суббота"],dayNamesShort:["вск","пнд","втр","срд","чтв","птн","сбт"],formatString:"%Y-%m-%d %H:%M:%S"},ar:{monthNames:["كانون الثاني","شباط","آذار","نيسان","آذار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],monthNamesShort:["1","2","3","4","5","6","7","8","9","10","11","12"],dayNames:["السبت","الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة"],dayNamesShort:["سبت","أحد","اثنين","ثلاثاء","أربعاء","خميس","جمعة"],formatString:"%Y-%m-%d %H:%M:%S"},pt:{monthNames:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],monthNamesShort:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],dayNames:["Domingo","Segunda-feira","Terça-feira","Quarta-feira","Quinta-feira","Sexta-feira","Sábado"],dayNamesShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],formatString:"%Y-%m-%d %H:%M:%S"},"pt-BR":{monthNames:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],monthNamesShort:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],dayNames:["Domingo","Segunda-feira","Terça-feira","Quarta-feira","Quinta-feira","Sexta-feira","Sábado"],dayNamesShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],formatString:"%Y-%m-%d %H:%M:%S"},pl:{monthNames:["Styczeń","Luty","Marzec","Kwiecień","Maj","Czerwiec","Lipiec","Sierpień","Wrzesień","Październik","Listopad","Grudzień"],monthNamesShort:["Sty","Lut","Mar","Kwi","Maj","Cze","Lip","Sie","Wrz","Paź","Lis","Gru"],dayNames:["Niedziela","Poniedziałek","Wtorek","Środa","Czwartek","Piątek","Sobota"],dayNamesShort:["Ni","Pn","Wt","Śr","Cz","Pt","Sb"],formatString:"%Y-%m-%d %H:%M:%S"},nl:{monthNames:["Januari","Februari","Maart","April","Mei","Juni","July","Augustus","September","Oktober","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],dayNames:","["Zondag","Maandag","Dinsdag","Woensdag","Donderdag","Vrijdag","Zaterdag"],dayNamesShort:["Zo","Ma","Di","Wo","Do","Vr","Za"],formatString:"%Y-%m-%d %H:%M:%S"},sv:{monthNames:["januari","februari","mars","april","maj","juni","juli","augusti","september","oktober","november","december"],monthNamesShort:["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec"],dayNames:["söndag","måndag","tisdag","onsdag","torsdag","fredag","lördag"],dayNamesShort:["sön","mån","tis","ons","tor","fre","lör"],formatString:"%Y-%m-%d %H:%M:%S"}};ag.regional["en-US"]=ag.regional["en-GB"]=ag.regional.en;ag.regional.getLocale=function(){var ah=ag.config.defaultLocale;if(document&&document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){ah=document.getElementsByTagName("html")[0].lang;if(!ag.regional.hasOwnProperty(ah)){ah=ag.config.defaultLocale}}return ah};var C=24*60*60*1000;var N=function(ah,ak){ah=String(ah);var ai=ak-ah.length;var aj=String(Math.pow(10,ai)).slice(1);return aj.concat(ah)};var E={millisecond:1,second:1000,minute:60*1000,hour:60*60*1000,day:C,week:7*C,month:{add:function(aj,ah){E.year.add(aj,Math[ah>0?"floor":"ceil"](ah/12));var ai=aj.getMonth()+(ah%12);if(ai==12){ai=0;aj.setYear(aj.getFullYear()+1)}else{if(ai==-1){ai=11;aj.setYear(aj.getFullYear()-1)}}aj.setMonth(ai)},diff:function(al,aj){var ah=al.getFullYear()-aj.getFullYear();var ai=al.getMonth()-aj.getMonth()+(ah*12);var ak=al.getDate()-aj.getDate();return ai+(ak/30)}},year:{add:function(ai,ah){ai.setYear(ai.getFullYear()+Math[ah>0?"floor":"ceil"](ah))},diff:function(ai,ah){return E.month.diff(ai,ah)/12}}};for(var Y in E){if(Y.substring(Y.length-1)!="s"){E[Y+"s"]=E[Y]}}var H=function(al,ak,ai){if(ag.formats[ai]["shortcuts"][ak]){return ag.strftime(al,ag.formats[ai]["shortcuts"][ak],ai)}else{var ah=(ag.formats[ai]["codes"][ak]||"").split(".");var aj=al["get"+ah[0]]?al["get"+ah[0]]():"";if(ah[1]){aj=N(aj,ah[1])}return aj}};ag.strftime=function(an,ak,aj,ao){var ai="perl";var am=ag.regional.getLocale();if(aj&&ag.formats.hasOwnProperty(aj)){ai=aj}else{if(aj&&ag.regional.hasOwnProperty(aj)){am=aj}}if(ao&&ag.formats.hasOwnProperty(ao)){ai=ao}else{if(ao&&ag.regional.hasOwnProperty(ao)){am=ao}}if(l(an)!="[object Object]"||an._type!="jsDate"){an=new ag(an);an.locale=am}if(!ak){ak=an.formatString||ag.regional[am]["formatString"]}var ah=ak||"%Y-%m-%d",ap="",al;while(ah.length>0){if(al=ah.match(ag.formats[ai].codes.matcher)){ap+=ah.slice(0,al.index);ap+=(al[1]||"")+H(an,al[2],ai);ah=ah.slice(al.index+al[0].length)}else{ap+=ah;ah=""}}return ap};ag.formats={ISO:"%Y-%m-%dT%H:%M:%S.%N%G",SQL:"%Y-%m-%d %H:%M:%S"};ag.formats.perl={codes:{matcher:/()%(#?(%|[a-z]))/i,Y:"FullYear",y:"ShortYear.2",m:"MonthNumber.2","#m":"MonthNumber",B:"MonthName",b:"AbbrMonthName",d:"Date.2","#d":"Date",e:"Date",A:"DayName",a:"AbbrDayName",w:"Day",H:"Hours.2","#H":"Hours",I:"Hours12.2","#I":"Hours12",p:"AMPM",M:"Minutes.2","#M":"Minutes",S:"Seconds.2","#S":"Seconds",s:"Unix",N:"Milliseconds.3","#N":"Milliseconds",O:"TimezoneOffset",Z:"TimezoneName",G:"GmtOffset"},shortcuts:{F:"%Y-%m-%d",T:"%H:%M:%S",X:"%H:%M:%S",x:"%m/%d/%y",D:"%m/%d/%y","#c":"%a %b %e %H:%M:%S %Y",v:"%e-%b-%Y",R:"%H:%M",r:"%I:%M:%S %p",t:"\t",n:"\n","%":"%"}};ag.formats.php={codes:{matcher:/()%((%|[a-z]))/i,a:"AbbrDayName",A:"DayName",d:"Date.2",e:"Date",j:"DayOfYear.3",u:"DayOfWeek",w:"Day",U:"FullWeekOfYear.2",V:"IsoWeek.2",W:"WeekOfYear.2",b:"AbbrMonthName",B:"MonthName",m:"MonthNumber.2",h:"AbbrMonthName",C:"Century.2",y:"ShortYear.2",Y:"FullYear",H:"Hours.2",I:"Hours12.2",l:"Hours12",p:"AMPM",P:"AmPm",M:"Minutes.2",S:"Seconds.2",s:"Unix",O:"TimezoneOffset",z:"GmtOffset",Z:"TimezoneAbbr"},shortcuts:{D:"%m/%d/%y",F:"%Y-%m-%d",T:"%H:%M:%S",X:"%H:%M:%S",x:"%m/%d/%y",R:"%H:%M",r:"%I:%M:%S %p",t:"\t",n:"\n","%":"%"}};ag.createDate=function(aj){if(aj==null){return new Date()}if(aj instanceof Date){return aj}if(typeof aj=="number"){return new Date(aj)}var ao=String(aj).replace(/^\s*(.+)\s*$/g,"$1");ao=ao.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/,"$1/$2/$3");ao=ao.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i,"$1 $2 $3");var an=ao.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i);if(an&&an.length>3){var at=parseFloat(an[3]);var am=ag.config.defaultCentury+at;am=String(am);ao=ao.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i,an[1]+" "+an[2]+" "+am)}an=ao.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/);function ar(ax,aw){var aC=parseFloat(aw[1]);var aB=parseFloat(aw[2]);var aA=parseFloat(aw[3]);var az=ag.config.defaultCentury;var av,au,aD,ay;if(aC>31){au=aA;aD=aB;av=az+aC}else{au=aB;aD=aC;av=az+aA}ay=aD+"/"+au+"/"+av;return ax.replace(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/,ay)}if(an&&an.length>3){ao=ar(ao,an)}var an=ao.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/);if(an&&an.length>3){ao=ar(ao,an)}var al=0;var ai=ag.matchers.length;var aq,ah,ap=ao,ak;while(al<ai){ah=Date.parse(ap);if(!isNaN(ah)){return new Date(ah)}aq=ag.matchers[al];if(typeof aq=="function"){ak=aq.call(ag,ap);if(ak instanceof Date){return ak}}else{ap=ao.replace(aq[0],aq[1])}al++}return NaN};ag.daysInMonth=function(ah,ai){if(ai==2){return new Date(ah,1,29).getDate()==29?29:28}return[u,31,u,31,30,31,30,31,31,30,31,30,31][ai]};ag.matchers=[[/(3[01]|[0-2]\d)\s*\.\s*(1[0-2]|0\d)\s*\.\s*([1-9]\d{3})/,"$2/$1/$3"],[/([1-9]\d{3})\s*-\s*(1[0-2]|0\d)\s*-\s*(3[01]|[0-2]\d)/,"$2/$3/$1"],function(ak){var ai=ak.match(/^(?:(.+)\s+)?([012]?\d)(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d(\.\d*)?))?\s*(am|pm)?\s*$/i);if(ai){if(ai[1]){var aj=this.createDate(ai[1]);if(isNaN(aj)){return}}else{var aj=new Date();aj.setMilliseconds(0)}var ah=parseFloat(ai[2]);if(ai[6]){ah=ai[6].toLowerCase()=="am"?(ah==12?0:ah):(ah==12?12:ah+12)}aj.setHours(ah,parseInt(ai[3]||0,10),parseInt(ai[4]||0,10),((parseFloat(ai[5]||0))||0)*1000);return aj}else{return ak}},function(ak){var ai=ak.match(/^(?:(.+))[T|\s+]([012]\d)(?:\:(\d\d))(?:\:(\d\d))(?:\.\d+)([\+\-]\d\d\:\d\d)$/i);if(ai){if(ai[1]){var aj=this.createDate(ai[1]);if(isNaN(aj)){return}}else{var aj=new Date();aj.setMilliseconds(0)}var ah=parseFloat(ai[2]);aj.setHours(ah,parseInt(ai[3],10),parseInt(ai[4],10),parseFloat(ai[5])*1000);return aj}else{return ak}},function(al){var aj=al.match(/^([0-3]?\d)\s*[-\/.\s]{1}\s*([a-zA-Z]{3,9})\s*[-\/.\s]{1}\s*([0-3]?\d)$/);if(aj){var ak=new Date();var am=ag.config.defaultCentury;var ao=parseFloat(aj[1]);var an=parseFloat(aj[3]);var ai,ah,ap;if(ao>31){ah=an;ai=am+ao}else{ah=ao;ai=am+an}var ap=ab(aj[2],ag.regional[ag.regional.getLocale()]["monthNamesShort"]);if(ap==-1){ap=ab(aj[2],ag.regional[ag.regional.getLocale()]["monthNames"])}ak.setFullYear(ai,ap,ah);ak.setHours(0,0,0,0);return ak}else{return al}}];function ab(aj,ak){if(ak.indexOf){return ak.indexOf(aj)}for(var ah=0,ai=ak.length;ah<ai;ah++){if(ak[ah]===aj){return ah}}return -1}function l(ah){if(ah===null){return"[object Null]"}return Object.prototype.toString.call(ah)}L.jsDate=ag;L.jqplot.sprintf=function(){function an(au,ap,aq,at){var ar=(au.length>=ap)?"":Array(1+ap-au.length>>>0).join(aq);return at?au+ar:ar+au}function ak(ar){var aq=new String(ar);for(var ap=10;ap>0;ap--){if(aq==(aq=aq.replace(/^(\d+)(\d{3})/,"$1"+L.jqplot.sprintf.thousandsSeparator+"$2"))){break}}return aq}function aj(av,au,ax,ar,at,aq){var aw=ar-av.length;if(aw>0){var ap=" ";if(aq){ap=" "}if(ax||!at){av=an(av,ar,ap,ax)}else{av=av.slice(0,au.length)+an("",aw,"0",true)+av.slice(au.length)}}return av}function ao(ay,aq,aw,ar,ap,av,ax,au){var at=ay>>>0;aw=aw&&at&&{"2":"0b","8":"0","16":"0x"}[aq]||"";ay=aw+an(at.toString(aq),av||0,"0",false);return aj(ay,aw,ar,ap,ax,au)}function ah(au,av,ar,ap,at,aq){if(ap!=null){au=au.slice(0,ap)}return aj(au,"",av,ar,at,aq)}var ai=arguments,al=0,am=ai[al++];return am.replace(L.jqplot.sprintf.regex,function(aM,ax,ay,aB,aO,aJ,av){if(aM=="%%"){return"%"}var aD=false,az="",aA=false,aL=false,aw=false,au=false;for(var aI=0;ay&&aI<ay.length;aI++){switch(ay.charAt(aI)){case" ":az=" ";break;case"+":az="+";break;case"-":aD=true;break;case"0":aA=true;break;case"#":aL=true;break;case"&":aw=true;break;case"'":au=true;break}}if(!aB){aB=0}else{if(aB=="*"){aB=+ai[al++]}else{if(aB.charAt(0)=="*"){aB=+ai[aB.slice(1,-1)]}else{aB=+aB}}}if(aB<0){aB=-aB;aD=true}if(!isFinite(aB)){throw new Error("$.jqplot.sprintf: (minimum-)width must be finite")}if(!aJ){aJ="fFeE".indexOf(av)>-1?6:(av=="d")?0:void (0)}else{if(aJ=="*"){aJ=+ai[al++]}else{if(aJ.charAt(0)=="*"){aJ=+ai[aJ.slice(1,-1)]}else{aJ=+aJ}}}var aF=ax?ai[ax.slice(0,-1)]:ai[al++];switch(av){case"s":if(aF==null){return""}return ah(String(aF),aD,aB,aJ,aA,aw);case"c":return ah(String.fromCharCode(+aF),aD,aB,aJ,aA,aw);case"b":return ao(aF,2,aL,aD,aB,aJ,aA,aw);case"o":return ao(aF,8,aL,aD,aB,aJ,aA,aw);case"x":return ao(aF,16,aL,aD,aB,aJ,aA,aw);case"X":return ao(aF,16,aL,aD,aB,aJ,aA,aw).toUpperCase();case"u":return ao(aF,10,aL,aD,aB,aJ,aA,aw);case"i":var ar=parseInt(+aF,10);if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aK=au?ak(String(Math.abs(ar))):String(Math.abs(ar));aF=aH+an(aK,aJ,"0",false);return aj(aF,aH,aD,aB,aA,aw);case"d":var ar=Math.round(+aF);if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aK=au?ak(String(Math.abs(ar))):String(Math.abs(ar));aF=aH+an(aK,aJ,"0",false);return aj(aF,aH,aD,aB,aA,aw);case"e":case"E":case"f":case"F":case"g":case"G":var ar=+aF;if(isNaN(ar)){return""}var aH=ar<0?"-":az;var at=["toExponential","toFixed","toPrecision"]["efg".indexOf(av.toLowerCase())];var aN=["toString","toUpperCase"]["eEfFgG".indexOf(av)%2];var aK=Math.abs(ar)[at](aJ);var aE=aK.toString().split(".");aE[0]=au?ak(aE[0]):aE[0];aK=aE.join(L.jqplot.sprintf.decimalMark);aF=aH+aK;var aC=aj(aF,aH,aD,aB,aA,aw)[aN]();return aC;case"p":case"P":var ar=+aF;if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aE=String(Number(Math.abs(ar)).toExponential()).split(/e|E/);var aq=(aE[0].indexOf(".")!=-1)?aE[0].length-1:String(ar).length;var aG=(aE[1]<0)?-aE[1]-1:0;if(Math.abs(ar)<1){if(aq+aG<=aJ){aF=aH+Math.abs(ar).toPrecision(aq)}else{if(aq<=aJ-1){aF=aH+Math.abs(ar).toExponential(aq-1)}else{aF=aH+Math.abs(ar).toExponential(aJ-1)}}}else{var ap=(aq<=aJ)?aq:aJ;aF=aH+Math.abs(ar).toPrecision(ap)}var aN=["toString","toUpperCase"]["pP".indexOf(av)%2];return aj(aF,aH,aD,aB,aA,aw)[aN]();case"n":return"";default:return aM}})};L.jqplot.sprintf.thousandsSeparator=",";L.jqplot.sprintf.decimalMark=".";L.jqplot.sprintf.regex=/%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g;L.jqplot.getSignificantFigures=function(al){var an=String(Number(Math.abs(al)).toExponential()).split(/e|E/);var am=(an[0].indexOf(".")!=-1)?an[0].length-1:an[0].length;var ai=(an[1]<0)?-an[1]-1:0;var ah=parseInt(an[1],10);var aj=(ah+1>0)?ah+1:0;var ak=(am<=aj)?0:am-ah-1;return{significantDigits:am,digitsLeft:aj,digitsRight:ak,zeros:ai,exponent:ah}};L.jqplot.getPrecision=function(ah){return L.jqplot.getSignificantFigures(ah).digitsRight};var X=L.uiBackCompat!==false;L.jqplot.effects={effect:{}};var m="jqplot.storage.";L.extend(L.jqplot.effects,{version:"1.9pre",save:function(ai,aj){for(var ah=0;ah<aj.length;ah++){if(aj[ah]!==null){ai.data(m+aj[ah],ai[0].style[aj[ah]])}}},restore:function(ai,aj){for(var ah=0;ah<aj.length;ah++){if(aj[ah]!==null){ai.css(aj[ah],ai.data(m+aj[ah]))}}},setMode:function(ah,ai){if(ai==="toggle"){ai=ah.is(":hidden")?"show":"hide"}return ai},createWrapper:function(ai){if(ai.parent().is(".ui-effects-wrapper")){return ai.parent()}var aj={width:ai.outerWidth(true),height:ai.outerHeight(true),"float":ai.css("float")},al=L("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),ah={width:ai.width(),height:ai.height()},ak=document.activeElement;ai.wrap(al);if(ai[0]===ak||L.contains(ai[0],ak)){L(ak).focus()}al=ai.parent();if(ai.css("position")==="static"){al.css({position:"relative"});ai.css({position:"relative"})}else{L.extend(aj,{position:ai.css("position"),zIndex:ai.css("z-index")});L.each(["top","left","bottom","right"],function(am,an){aj[an]=ai.css(an);if(isNaN(parseInt(aj[an],10))){aj[an]="auto"}});ai.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}ai.css(ah);return al.css(aj).show()},removeWrapper:function(ah){var ai=document.activeElement;if(ah.parent().is(".ui-effects-wrapper")){ah.parent().replaceWith(ah);if(ah[0]===ai||L.contains(ah[0],ai)){L(ai).focus()}}return ah}});function j(ai,ah,aj,ak){if(L.isPlainObject(ai)){return ai}ai={effect:ai};if(ah===u){ah={}}if(L.isFunction(ah)){ak=ah;aj=null;ah={}}if(L.type(ah)==="number"||L.fx.speeds[ah]){ak=aj;aj=ah;ah={}}if(L.isFunction(aj)){ak=aj;aj=null}if(ah){L.extend(ai,ah)}aj=aj||ah.duration;ai.duration=L.fx.off?0:typeof aj==="number"?aj:aj in L.fx.speeds?L.fx.speeds[aj]:L.fx.speeds._default;ai.complete=ak||ah.complete;return ai}function ae(ah){if(!ah||typeof ah==="number"||L.fx.speeds[ah]){return true}if(typeof ah==="string"&&!L.jqplot.effects.effect[ah]){if(X&&L.jqplot.effects[ah]){return false}return true}return false}L.fn.extend({jqplotEffect:function(ap,aq,ai,ao){var an=j.apply(this,arguments),ak=an.mode,al=an.queue,am=L.jqplot.effects.effect[an.effect],ah=!am&&X&&L.jqplot.effects[an.effect];if(L.fx.off||!(am||ah)){if(ak){return this[ak](an.duration,an.complete)}else{return this.each(function(){if(an.complete){an.complete.call(this)}})}}function aj(au){var av=L(this),at=an.complete,aw=an.mode;function ar(){if(L.isFunction(at)){at.call(av[0])}if(L.isFunction(au)){au()}}if(av.is(":hidden")?aw==="hide":aw==="show"){ar()}else{am.call(av[0],an,ar)}}if(am){return al===false?this.each(aj):this.queue(al||"fx",aj)}else{return ah.call(this,{options:an,duration:an.duration,callback:an.complete,mode:an.mode})}}});var a=/up|down|vertical/,v=/up|left|vertical|horizontal/;L.jqplot.effects.effect.blind=function(aj,ao){var ak=L(this),ar=["position","top","bottom","left","right","height","width"],ap=L.jqplot.effects.setMode(ak,aj.mode||"hide"),au=aj.direction||"up",am=a.test(au),al=am?"height":"width",aq=am?"top":"left",aw=v.test(au),an={},av=ap==="show",ai,ah,at;if(ak.parent().is(".ui-effects-wrapper")){L.jqplot.effects.save(ak.parent(),ar)}else{L.jqplot.effects.save(ak,ar)}ak.show();at=parseInt(ak.css("top"),10);ai=L.jqplot.effects.createWrapper(ak).css({overflow:"hidden"});ah=am?ai[al]()+at:ai[al]();an[al]=av?String(ah):"0";if(!aw){ak.css(am?"bottom":"right",0).css(am?"top":"left","").css({position:"absolute"});an[aq]=av?"0":String(ah)}if(av){ai.css(al,0);if(!aw){ai.css(aq,ah)}}ai.animate(an,{duration:aj.duration,easing:aj.easing,queue:false,complete:function(){if(ap==="hide"){ak.hide()}L.jqplot.effects.restore(ak,ar);L.jqplot.effects.removeWrapper(ak);ao()}})}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.BezierCurveRenderer.js b/plugin/jqplot/plugins/jqplot.BezierCurveRenderer.js new file mode 100644 index 000000000..1c7b03103 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.BezierCurveRenderer.js @@ -0,0 +1,314 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + // Class: $.jqplot.BezierCurveRenderer.js + // Renderer which draws lines as stacked bezier curves. + // Data for the line will not be specified as an array of + // [x, y] data point values, but as a an array of [start piont, bezier curve] + // So, the line is specified as: [[xstart, ystart], [cp1x, cp1y, cp2x, cp2y, xend, yend]]. + $.jqplot.BezierCurveRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.BezierCurveRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.BezierCurveRenderer.prototype.constructor = $.jqplot.BezierCurveRenderer; + + + // Method: setGridData + // converts the user data values to grid coordinates and stores them + // in the gridData array. + // Called with scope of a series. + $.jqplot.BezierCurveRenderer.prototype.setGridData = function(plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + // this._plotData should be same as this.data + var data = this.data; + this.gridData = []; + this._prevGridData = []; + // if seriesIndex = 0, fill to x axis. + // if seriesIndex > 0, fill to previous series data. + var idx = this.index; + if (data.length == 2) { + if (idx == 0) { + this.gridData = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), + xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], + [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)], + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] + ]; + } + else { + var psd = plot.series[idx-1].data; + this.gridData = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), + xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], + [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])], + [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]), + xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), + xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] + ]; + } + } + else { + if (idx == 0) { + this.gridData = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), + xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], + [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)], + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] + ]; + } + else { + var psd = plot.series[idx-1].data; + this.gridData = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), + xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], + [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])], + [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]), + xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), + xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] + ]; + } + } + }; + + // Method: makeGridData + // converts any arbitrary data values to grid coordinates and + // returns them. This method exists so that plugins can use a series' + // linerenderer to generate grid data points without overwriting the + // grid data associated with that series. + // Called with scope of a series. + $.jqplot.BezierCurveRenderer.prototype.makeGridData = function(data, plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var gd = []; + var pgd = []; + // if seriesIndex = 0, fill to x axis. + // if seriesIndex > 0, fill to previous series data. + var idx = this.index; + if (data.length == 2) { + if (idx == 0) { + gd = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), + xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], + [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)], + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] + ]; + } + else { + var psd = plot.series[idx-1].data; + gd = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), + xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], + [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])], + [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]), + xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), + xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] + ]; + } + } + else { + if (idx == 0) { + gd = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), + xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], + [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)], + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] + ]; + } + else { + var psd = plot.series[idx-1].data; + gd = [ + [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], + [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), + xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), + xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], + [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])], + [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]), + xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), + xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] + ]; + } + } + return gd; + }; + + + // called within scope of series. + $.jqplot.BezierCurveRenderer.prototype.draw = function(ctx, gd, options) { + var i; + ctx.save(); + if (gd.length) { + if (this.showLine) { + ctx.save(); + var opts = (options != null) ? options : {}; + ctx.fillStyle = opts.fillStyle || this.color; + ctx.beginPath(); + ctx.moveTo(gd[0][0], gd[0][1]); + ctx.bezierCurveTo(gd[1][0], gd[1][1], gd[1][2], gd[1][3], gd[1][4], gd[1][5]); + ctx.lineTo(gd[2][0], gd[2][1]); + if (gd[3].length == 2) { + ctx.lineTo(gd[3][0], gd[3][1]); + } + else { + ctx.bezierCurveTo(gd[3][0], gd[3][1], gd[3][2], gd[3][3], gd[3][4], gd[3][5]); + } + ctx.closePath(); + ctx.fill(); + ctx.restore(); + } + } + + ctx.restore(); + }; + + $.jqplot.BezierCurveRenderer.prototype.drawShadow = function(ctx, gd, options) { + // This is a no-op, shadows drawn with lines. + }; + + $.jqplot.BezierAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + }; + + $.jqplot.BezierAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.BezierAxisRenderer.prototype.constructor = $.jqplot.BezierAxisRenderer; + + + // Axes on a plot with Bezier Curves + $.jqplot.BezierAxisRenderer.prototype.init = function(options){ + $.extend(true, this, options); + var db = this._dataBounds; + // Go through all the series attached to this axis and find + // the min/max bounds for this axis. + for (var i=0; i<this._series.length; i++) { + var s = this._series[i]; + var d = s.data; + if (d.length == 4) { + for (var j=0; j<d.length; j++) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + if (d[j][0] < db.min || db.min == null) { + db.min = d[j][0]; + } + if (d[j][0] > db.max || db.max == null) { + db.max = d[j][0]; + } + } + else { + if (d[j][1] < db.min || db.min == null) { + db.min = d[j][1]; + } + if (d[j][1] > db.max || db.max == null) { + db.max = d[j][1]; + } + } + } + } + else { + if (this.name == 'xaxis' || this.name == 'x2axis') { + if (d[0][0] < db.min || db.min == null) { + db.min = d[0][0]; + } + if (d[0][0] > db.max || db.max == null) { + db.max = d[0][0]; + } + for (var j=0; j<5; j+=2) { + if (d[1][j] < db.min || db.min == null) { + db.min = d[1][j]; + } + if (d[1][j] > db.max || db.max == null) { + db.max = d[1][j]; + } + } + } + else { + if (d[0][1] < db.min || db.min == null) { + db.min = d[0][1]; + } + if (d[0][1] > db.max || db.max == null) { + db.max = d[0][1]; + } + for (var j=1; j<6; j+=2) { + if (d[1][j] < db.min || db.min == null) { + db.min = d[1][j]; + } + if (d[1][j] > db.max || db.max == null) { + db.max = d[1][j]; + } + } + } + } + } + }; + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + options = options || {}; + options.axesDefaults = $.extend(true, {pad:0}, options.axesDefaults); + options.seriesDefaults = options.seriesDefaults || {}; + options.legend = $.extend(true, {placement:'outside'}, options.legend); + // only set these if there is a pie series + var setopts = false; + if (options.seriesDefaults.renderer == $.jqplot.BezierCurveRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer == $.jqplot.BezierCurveRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.BezierAxisRenderer; + } + } + + $.jqplot.preInitHooks.push(preInit); + +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.BezierCurveRenderer.min.js b/plugin/jqplot/plugins/jqplot.BezierCurveRenderer.min.js new file mode 100644 index 000000000..94c6fc5e7 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.BezierCurveRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(b){b.jqplot.BezierCurveRenderer=function(){b.jqplot.LineRenderer.call(this)};b.jqplot.BezierCurveRenderer.prototype=new b.jqplot.LineRenderer();b.jqplot.BezierCurveRenderer.prototype.constructor=b.jqplot.BezierCurveRenderer;b.jqplot.BezierCurveRenderer.prototype.setGridData=function(h){var e=this._xaxis.series_u2p;var g=this._yaxis.series_u2p;var f=this.data;this.gridData=[];this._prevGridData=[];var d=this.index;if(f.length==2){if(d==0){this.gridData=[[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,f[0][1])],[e.call(this._xaxis,f[1][0]),g.call(this._yaxis,f[1][1]),e.call(this._xaxis,f[1][2]),g.call(this._yaxis,f[1][3]),e.call(this._xaxis,f[1][4]),g.call(this._yaxis,f[1][5])],[e.call(this._xaxis,f[1][4]),g.call(this._yaxis,this._yaxis.min)],[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,this._yaxis.min)]]}else{var c=h.series[d-1].data;this.gridData=[[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,f[0][1])],[e.call(this._xaxis,f[1][0]),g.call(this._yaxis,f[1][1]),e.call(this._xaxis,f[1][2]),g.call(this._yaxis,f[1][3]),e.call(this._xaxis,f[1][4]),g.call(this._yaxis,f[1][5])],[e.call(this._xaxis,c[1][4]),g.call(this._yaxis,c[1][5])],[e.call(this._xaxis,c[1][2]),g.call(this._yaxis,c[1][3]),e.call(this._xaxis,c[1][0]),g.call(this._yaxis,c[1][1]),e.call(this._xaxis,c[0][0]),g.call(this._yaxis,c[0][1])]]}}else{if(d==0){this.gridData=[[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,f[0][1])],[e.call(this._xaxis,f[1][0]),g.call(this._yaxis,f[1][1]),e.call(this._xaxis,f[2][0]),g.call(this._yaxis,f[2][1]),e.call(this._xaxis,f[3][0]),g.call(this._yaxis,f[3][1])],[e.call(this._xaxis,f[3][1]),g.call(this._yaxis,this._yaxis.min)],[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,this._yaxis.min)]]}else{var c=h.series[d-1].data;this.gridData=[[e.call(this._xaxis,f[0][0]),g.call(this._yaxis,f[0][1])],[e.call(this._xaxis,f[1][0]),g.call(this._yaxis,f[1][1]),e.call(this._xaxis,f[2][0]),g.call(this._yaxis,f[2][1]),e.call(this._xaxis,f[3][0]),g.call(this._yaxis,f[3][1])],[e.call(this._xaxis,c[3][0]),g.call(this._yaxis,c[3][1])],[e.call(this._xaxis,c[2][0]),g.call(this._yaxis,c[2][1]),e.call(this._xaxis,c[1][0]),g.call(this._yaxis,c[1][1]),e.call(this._xaxis,c[0][0]),g.call(this._yaxis,c[0][1])]]}}};b.jqplot.BezierCurveRenderer.prototype.makeGridData=function(g,i){var f=this._xaxis.series_u2p;var h=this._yaxis.series_u2p;var e=[];var j=[];var d=this.index;if(g.length==2){if(d==0){e=[[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,g[0][1])],[f.call(this._xaxis,g[1][0]),h.call(this._yaxis,g[1][1]),f.call(this._xaxis,g[1][2]),h.call(this._yaxis,g[1][3]),f.call(this._xaxis,g[1][4]),h.call(this._yaxis,g[1][5])],[f.call(this._xaxis,g[1][4]),h.call(this._yaxis,this._yaxis.min)],[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,this._yaxis.min)]]}else{var c=i.series[d-1].data;e=[[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,g[0][1])],[f.call(this._xaxis,g[1][0]),h.call(this._yaxis,g[1][1]),f.call(this._xaxis,g[1][2]),h.call(this._yaxis,g[1][3]),f.call(this._xaxis,g[1][4]),h.call(this._yaxis,g[1][5])],[f.call(this._xaxis,c[1][4]),h.call(this._yaxis,c[1][5])],[f.call(this._xaxis,c[1][2]),h.call(this._yaxis,c[1][3]),f.call(this._xaxis,c[1][0]),h.call(this._yaxis,c[1][1]),f.call(this._xaxis,c[0][0]),h.call(this._yaxis,c[0][1])]]}}else{if(d==0){e=[[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,g[0][1])],[f.call(this._xaxis,g[1][0]),h.call(this._yaxis,g[1][1]),f.call(this._xaxis,g[2][0]),h.call(this._yaxis,g[2][1]),f.call(this._xaxis,g[3][0]),h.call(this._yaxis,g[3][1])],[f.call(this._xaxis,g[3][1]),h.call(this._yaxis,this._yaxis.min)],[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,this._yaxis.min)]]}else{var c=i.series[d-1].data;e=[[f.call(this._xaxis,g[0][0]),h.call(this._yaxis,g[0][1])],[f.call(this._xaxis,g[1][0]),h.call(this._yaxis,g[1][1]),f.call(this._xaxis,g[2][0]),h.call(this._yaxis,g[2][1]),f.call(this._xaxis,g[3][0]),h.call(this._yaxis,g[3][1])],[f.call(this._xaxis,c[3][0]),h.call(this._yaxis,c[3][1])],[f.call(this._xaxis,c[2][0]),h.call(this._yaxis,c[2][1]),f.call(this._xaxis,c[1][0]),h.call(this._yaxis,c[1][1]),f.call(this._xaxis,c[0][0]),h.call(this._yaxis,c[0][1])]]}}return e};b.jqplot.BezierCurveRenderer.prototype.draw=function(c,g,d){var e;c.save();if(g.length){if(this.showLine){c.save();var f=(d!=null)?d:{};c.fillStyle=f.fillStyle||this.color;c.beginPath();c.moveTo(g[0][0],g[0][1]);c.bezierCurveTo(g[1][0],g[1][1],g[1][2],g[1][3],g[1][4],g[1][5]);c.lineTo(g[2][0],g[2][1]);if(g[3].length==2){c.lineTo(g[3][0],g[3][1])}else{c.bezierCurveTo(g[3][0],g[3][1],g[3][2],g[3][3],g[3][4],g[3][5])}c.closePath();c.fill();c.restore()}}c.restore()};b.jqplot.BezierCurveRenderer.prototype.drawShadow=function(c,e,d){};b.jqplot.BezierAxisRenderer=function(){b.jqplot.LinearAxisRenderer.call(this)};b.jqplot.BezierAxisRenderer.prototype=new b.jqplot.LinearAxisRenderer();b.jqplot.BezierAxisRenderer.prototype.constructor=b.jqplot.BezierAxisRenderer;b.jqplot.BezierAxisRenderer.prototype.init=function(f){b.extend(true,this,f);var c=this._dataBounds;for(var g=0;g<this._series.length;g++){var h=this._series[g];var k=h.data;if(k.length==4){for(var e=0;e<k.length;e++){if(this.name=="xaxis"||this.name=="x2axis"){if(k[e][0]<c.min||c.min==null){c.min=k[e][0]}if(k[e][0]>c.max||c.max==null){c.max=k[e][0]}}else{if(k[e][1]<c.min||c.min==null){c.min=k[e][1]}if(k[e][1]>c.max||c.max==null){c.max=k[e][1]}}}}else{if(this.name=="xaxis"||this.name=="x2axis"){if(k[0][0]<c.min||c.min==null){c.min=k[0][0]}if(k[0][0]>c.max||c.max==null){c.max=k[0][0]}for(var e=0;e<5;e+=2){if(k[1][e]<c.min||c.min==null){c.min=k[1][e]}if(k[1][e]>c.max||c.max==null){c.max=k[1][e]}}}else{if(k[0][1]<c.min||c.min==null){c.min=k[0][1]}if(k[0][1]>c.max||c.max==null){c.max=k[0][1]}for(var e=1;e<6;e+=2){if(k[1][e]<c.min||c.min==null){c.min=k[1][e]}if(k[1][e]>c.max||c.max==null){c.max=k[1][e]}}}}}};function a(g,f,d){d=d||{};d.axesDefaults=b.extend(true,{pad:0},d.axesDefaults);d.seriesDefaults=d.seriesDefaults||{};d.legend=b.extend(true,{placement:"outside"},d.legend);var c=false;if(d.seriesDefaults.renderer==b.jqplot.BezierCurveRenderer){c=true}else{if(d.series){for(var e=0;e<d.series.length;e++){if(d.series[e].renderer==b.jqplot.BezierCurveRenderer){c=true}}}}if(c){d.axesDefaults.renderer=b.jqplot.BezierAxisRenderer}}b.jqplot.preInitHooks.push(a)})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.barRenderer.js b/plugin/jqplot/plugins/jqplot.barRenderer.js new file mode 100644 index 000000000..9b714e9cf --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.barRenderer.js @@ -0,0 +1,801 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + + // Class: $.jqplot.BarRenderer + // A plugin renderer for jqPlot to draw a bar plot. + // Draws series as a line. + + $.jqplot.BarRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer; + + // called with scope of series. + $.jqplot.BarRenderer.prototype.init = function(options, plot) { + // Group: Properties + // + // prop: barPadding + // Number of pixels between adjacent bars at the same axis value. + this.barPadding = 8; + // prop: barMargin + // Number of pixels between groups of bars at adjacent axis values. + this.barMargin = 10; + // prop: barDirection + // 'vertical' = up and down bars, 'horizontal' = side to side bars + this.barDirection = 'vertical'; + // prop: barWidth + // Width of the bar in pixels (auto by devaul). null = calculated automatically. + this.barWidth = null; + // prop: shadowOffset + // offset of the shadow from the slice and offset of + // each succesive stroke of the shadow from the last. + this.shadowOffset = 2; + // prop: shadowDepth + // number of strokes to apply to the shadow, + // each stroke offset shadowOffset from the last. + this.shadowDepth = 5; + // prop: shadowAlpha + // transparency of the shadow (0 = transparent, 1 = opaque) + this.shadowAlpha = 0.08; + // prop: waterfall + // true to enable waterfall plot. + this.waterfall = false; + // prop: groups + // group bars into this many groups + this.groups = 1; + // prop: varyBarColor + // true to color each bar of a series separately rather than + // have every bar of a given series the same color. + // If used for non-stacked multiple series bar plots, user should + // specify a separate 'seriesColors' array for each series. + // Otherwise, each series will set their bars to the same color array. + // This option has no Effect for stacked bar charts and is disabled. + this.varyBarColor = false; + // prop: highlightMouseOver + // True to highlight slice when moused over. + // This must be false to enable highlightMouseDown to highlight when clicking on a slice. + this.highlightMouseOver = true; + // prop: highlightMouseDown + // True to highlight when a mouse button is pressed over a slice. + // This will be disabled if highlightMouseOver is true. + this.highlightMouseDown = false; + // prop: highlightColors + // an array of colors to use when highlighting a bar. + this.highlightColors = []; + // prop: transposedData + // NOT IMPLEMENTED YET. True if this is a horizontal bar plot and + // x and y values are "transposed". Tranposed, or "swapped", data is + // required prior to rev. 894 builds of jqPlot with horizontal bars. + // Allows backward compatability of bar renderer horizontal bars with + // old style data sets. + this.transposedData = true; + this.renderer.animation = { + show: false, + direction: 'down', + speed: 3000, + _supported: true + }; + this._type = 'bar'; + + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver + if (options.highlightMouseDown && options.highlightMouseOver == null) { + options.highlightMouseOver = false; + } + + ////// + // This is probably wrong here. + // After going back and forth on whether renderer should be the thing + // or extend the thing, it seems that it it best if it is a property + // on the thing. This should be something that is commonized + // among series renderers in the future. + ////// + $.extend(true, this, options); + + // really should probably do this + $.extend(true, this.renderer, options); + // fill is still needed to properly draw the legend. + // bars have to be filled. + this.fill = true; + + // if horizontal bar and animating, reset the default direction + if (this.barDirection === 'horizontal' && this.rendererOptions.animation && this.rendererOptions.animation.direction == null) { + this.renderer.animation.direction = 'left'; + } + + if (this.waterfall) { + this.fillToZero = false; + this.disableStack = true; + } + + if (this.barDirection == 'vertical' ) { + this._primaryAxis = '_xaxis'; + this._stackAxis = 'y'; + this.fillAxis = 'y'; + } + else { + this._primaryAxis = '_yaxis'; + this._stackAxis = 'x'; + this.fillAxis = 'x'; + } + // index of the currenty highlighted point, if any + this._highlightedPoint = null; + // total number of values for all bar series, total number of bar series, and position of this series + this._plotSeriesInfo = null; + // Array of actual data colors used for each data point. + this._dataColors = []; + this._barPoints = []; + + // set the shape renderer options + var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill}; + this.renderer.shapeRenderer.init(opts); + // set the shadow renderer options + var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill}; + this.renderer.shadowRenderer.init(sopts); + + plot.postInitHooks.addOnce(postInit); + plot.postDrawHooks.addOnce(postPlotDraw); + plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); + plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); + plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); + plot.eventListenerHooks.addOnce('jqplotClick', handleClick); + plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); + }; + + // called with scope of series + function barPreInit(target, data, seriesDefaults, options) { + if (this.rendererOptions.barDirection == 'horizontal') { + this._stackAxis = 'x'; + this._primaryAxis = '_yaxis'; + } + if (this.rendererOptions.waterfall == true) { + this._data = $.extend(true, [], this.data); + var sum = 0; + var pos = (!this.rendererOptions.barDirection || this.rendererOptions.barDirection === 'vertical' || this.transposedData === false) ? 1 : 0; + for(var i=0; i<this.data.length; i++) { + sum += this.data[i][pos]; + if (i>0) { + this.data[i][pos] += this.data[i-1][pos]; + } + } + this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1]; + this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1]; + } + if (this.rendererOptions.groups > 1) { + this.breakOnNull = true; + var l = this.data.length; + var skip = parseInt(l/this.rendererOptions.groups, 10); + var count = 0; + for (var i=skip; i<l; i+=skip) { + this.data.splice(i+count, 0, [null, null]); + this._plotData.splice(i+count, 0, [null, null]); + this._stackData.splice(i+count, 0, [null, null]); + count++; + } + for (i=0; i<this.data.length; i++) { + if (this._primaryAxis == '_xaxis') { + this.data[i][0] = i+1; + this._plotData[i][0] = i+1; + this._stackData[i][0] = i+1; + } + else { + this.data[i][1] = i+1; + this._plotData[i][1] = i+1; + this._stackData[i][1] = i+1; + } + } + } + } + + $.jqplot.preSeriesInitHooks.push(barPreInit); + + // needs to be called with scope of series, not renderer. + $.jqplot.BarRenderer.prototype.calcSeriesNumbers = function() { + var nvals = 0; + var nseries = 0; + var paxis = this[this._primaryAxis]; + var s, series, pos; + // loop through all series on this axis + for (var i=0; i < paxis._series.length; i++) { + series = paxis._series[i]; + if (series === this) { + pos = i; + } + // is the series rendered as a bar? + if (series.renderer.constructor == $.jqplot.BarRenderer) { + // gridData may not be computed yet, use data length insted + nvals += series.data.length; + nseries += 1; + } + } + // return total number of values for all bar series, total number of bar series, and position of this series + return [nvals, nseries, pos]; + }; + + $.jqplot.BarRenderer.prototype.setBarWidth = function() { + // need to know how many data values we have on the approprate axis and figure it out. + var i; + var nvals = 0; + var nseries = 0; + var paxis = this[this._primaryAxis]; + var s, series, pos; + var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); + nvals = temp[0]; + nseries = temp[1]; + var nticks = paxis.numberTicks; + var nbins = (nticks-1)/2; + // so, now we have total number of axis values. + if (paxis.name == 'xaxis' || paxis.name == 'x2axis') { + if (this._stack) { + this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin; + } + else { + this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries; + // this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries; + } + } + else { + if (this._stack) { + this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin; + } + else { + this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries; + // this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries; + } + } + return [nvals, nseries]; + }; + + function computeHighlightColors (colors) { + var ret = []; + for (var i=0; i<colors.length; i++){ + var rgba = $.jqplot.getColorComponents(colors[i]); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var sum = newrgb[0] + newrgb[1] + newrgb[2]; + for (var j=0; j<3; j++) { + // when darkening, lowest color component can be is 60. + newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); + newrgb[j] = parseInt(newrgb[j], 10); + } + ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); + } + return ret; + } + + function getStart(sidx, didx, comp, plot, axis) { + // check if sign change + var seriesIndex = sidx, + prevSeriesIndex = sidx - 1, + start, + prevVal, + aidx = (axis === 'x') ? 0 : 1; + + // is this not the first series? + if (seriesIndex > 0) { + prevVal = plot.series[prevSeriesIndex]._plotData[didx][aidx]; + + // is there a sign change + if ((comp * prevVal) < 0) { + start = getStart(prevSeriesIndex, didx, comp, plot, axis); + } + + // no sign change. + else { + start = plot.series[prevSeriesIndex].gridData[didx][aidx]; + } + + } + + // if first series, return value at 0 + else { + + start = (aidx === 0) ? plot.series[seriesIndex]._xaxis.series_u2p(0) : plot.series[seriesIndex]._yaxis.series_u2p(0); + } + + return start; + } + + + $.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options, plot) { + var i; + // Ughhh, have to make a copy of options b/c it may be modified later. + var opts = $.extend({}, options); + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var xaxis = this.xaxis; + var yaxis = this.yaxis; + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var pointx, pointy; + // clear out data colors. + this._dataColors = []; + this._barPoints = []; + + if (this.barWidth == null) { + this.renderer.setBarWidth.call(this); + } + + var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); + var nvals = temp[0]; + var nseries = temp[1]; + var pos = temp[2]; + var points = []; + + if (this._stack) { + this._barNudge = 0; + } + else { + this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding); + } + if (showLine) { + var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors); + var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors); + var negativeColor = negativeColors.get(this.index); + if (! this.useNegativeColors) { + negativeColor = opts.fillStyle; + } + var positiveColor = opts.fillStyle; + var base; + var xstart; + var ystart; + + if (this.barDirection == 'vertical') { + for (var i=0; i<gridData.length; i++) { + if (!this._stack && this.data[i][1] == null) { + continue; + } + points = []; + base = gridData[i][0] + this._barNudge; + + // stacked + if (this._stack && this._prevGridData.length) { + ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y'); + } + + // not stacked + else { + if (this.fillToZero) { + ystart = this._yaxis.series_u2p(0); + } + else if (this.waterfall && i > 0 && i < this.gridData.length-1) { + ystart = this.gridData[i-1][1]; + } + else if (this.waterfall && i == 0 && i < this.gridData.length-1) { + if (this._yaxis.min <= 0 && this._yaxis.max >= 0) { + ystart = this._yaxis.series_u2p(0); + } + else if (this._yaxis.min > 0) { + ystart = ctx.canvas.height; + } + else { + ystart = 0; + } + } + else if (this.waterfall && i == this.gridData.length - 1) { + if (this._yaxis.min <= 0 && this._yaxis.max >= 0) { + ystart = this._yaxis.series_u2p(0); + } + else if (this._yaxis.min > 0) { + ystart = ctx.canvas.height; + } + else { + ystart = 0; + } + } + else { + ystart = ctx.canvas.height; + } + } + if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) { + if (this.varyBarColor && !this._stack) { + if (this.useNegativeColors) { + opts.fillStyle = negativeColors.next(); + } + else { + opts.fillStyle = positiveColors.next(); + } + } + else { + opts.fillStyle = negativeColor; + } + } + else { + if (this.varyBarColor && !this._stack) { + opts.fillStyle = positiveColors.next(); + } + else { + opts.fillStyle = positiveColor; + } + } + + if (!this.fillToZero || this._plotData[i][1] >= 0) { + points.push([base-this.barWidth/2, ystart]); + points.push([base-this.barWidth/2, gridData[i][1]]); + points.push([base+this.barWidth/2, gridData[i][1]]); + points.push([base+this.barWidth/2, ystart]); + } + // for negative bars make sure points are always ordered clockwise + else { + points.push([base-this.barWidth/2, gridData[i][1]]); + points.push([base-this.barWidth/2, ystart]); + points.push([base+this.barWidth/2, ystart]); + points.push([base+this.barWidth/2, gridData[i][1]]); + } + this._barPoints.push(points); + // now draw the shadows if not stacked. + // for stacked plots, they are predrawn by drawShadow + if (shadow && !this._stack) { + var sopts = $.extend(true, {}, opts); + // need to get rid of fillStyle on shadow. + delete sopts.fillStyle; + this.renderer.shadowRenderer.draw(ctx, points, sopts); + } + var clr = opts.fillStyle || this.color; + this._dataColors.push(clr); + this.renderer.shapeRenderer.draw(ctx, points, opts); + } + } + + else if (this.barDirection == 'horizontal'){ + for (var i=0; i<gridData.length; i++) { + if (!this._stack && this.data[i][0] == null) { + continue; + } + points = []; + base = gridData[i][1] - this._barNudge; + xstart; + + if (this._stack && this._prevGridData.length) { + xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x'); + } + // not stacked + else { + if (this.fillToZero) { + xstart = this._xaxis.series_u2p(0); + } + else if (this.waterfall && i > 0 && i < this.gridData.length-1) { + xstart = this.gridData[i-1][0]; + } + else if (this.waterfall && i == 0 && i < this.gridData.length-1) { + if (this._xaxis.min <= 0 && this._xaxis.max >= 0) { + xstart = this._xaxis.series_u2p(0); + } + else if (this._xaxis.min > 0) { + xstart = 0; + } + else { + xstart = 0; + } + } + else if (this.waterfall && i == this.gridData.length - 1) { + if (this._xaxis.min <= 0 && this._xaxis.max >= 0) { + xstart = this._xaxis.series_u2p(0); + } + else if (this._xaxis.min > 0) { + xstart = 0; + } + else { + xstart = ctx.canvas.width; + } + } + else { + xstart = 0; + } + } + if ((this.fillToZero && this._plotData[i][0] < 0) || (this.waterfall && this._data[i][0] < 0)) { + if (this.varyBarColor && !this._stack) { + if (this.useNegativeColors) { + opts.fillStyle = negativeColors.next(); + } + else { + opts.fillStyle = positiveColors.next(); + } + } + else { + opts.fillStyle = negativeColor; + } + } + else { + if (this.varyBarColor && !this._stack) { + opts.fillStyle = positiveColors.next(); + } + else { + opts.fillStyle = positiveColor; + } + } + + + if (!this.fillToZero || this._plotData[i][0] >= 0) { + points.push([xstart, base + this.barWidth / 2]); + points.push([xstart, base - this.barWidth / 2]); + points.push([gridData[i][0], base - this.barWidth / 2]); + points.push([gridData[i][0], base + this.barWidth / 2]); + } + else { + points.push([gridData[i][0], base + this.barWidth / 2]); + points.push([gridData[i][0], base - this.barWidth / 2]); + points.push([xstart, base - this.barWidth / 2]); + points.push([xstart, base + this.barWidth / 2]); + } + + this._barPoints.push(points); + // now draw the shadows if not stacked. + // for stacked plots, they are predrawn by drawShadow + if (shadow && !this._stack) { + var sopts = $.extend(true, {}, opts); + delete sopts.fillStyle; + this.renderer.shadowRenderer.draw(ctx, points, sopts); + } + var clr = opts.fillStyle || this.color; + this._dataColors.push(clr); + this.renderer.shapeRenderer.draw(ctx, points, opts); + } + } + } + + if (this.highlightColors.length == 0) { + this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors); + } + + else if (typeof(this.highlightColors) == 'string') { + var temp = this.highlightColors; + this.highlightColors = []; + for (var i=0; i<this._dataColors.length; i++) { + this.highlightColors.push(temp); + } + } + + }; + + + // for stacked plots, shadows will be pre drawn by drawShadow. + $.jqplot.BarRenderer.prototype.drawShadow = function(ctx, gridData, options, plot) { + var i; + var opts = (options != undefined) ? options : {}; + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var xaxis = this.xaxis; + var yaxis = this.yaxis; + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var pointx, points, pointy, nvals, nseries, pos; + + if (this._stack && this.shadow) { + if (this.barWidth == null) { + this.renderer.setBarWidth.call(this); + } + + var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); + nvals = temp[0]; + nseries = temp[1]; + pos = temp[2]; + + if (this._stack) { + this._barNudge = 0; + } + else { + this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding); + } + if (showLine) { + + if (this.barDirection == 'vertical') { + for (var i=0; i<gridData.length; i++) { + if (this.data[i][1] == null) { + continue; + } + points = []; + var base = gridData[i][0] + this._barNudge; + var ystart; + + if (this._stack && this._prevGridData.length) { + ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y'); + } + else { + if (this.fillToZero) { + ystart = this._yaxis.series_u2p(0); + } + else { + ystart = ctx.canvas.height; + } + } + + points.push([base-this.barWidth/2, ystart]); + points.push([base-this.barWidth/2, gridData[i][1]]); + points.push([base+this.barWidth/2, gridData[i][1]]); + points.push([base+this.barWidth/2, ystart]); + this.renderer.shadowRenderer.draw(ctx, points, opts); + } + } + + else if (this.barDirection == 'horizontal'){ + for (var i=0; i<gridData.length; i++) { + if (this.data[i][0] == null) { + continue; + } + points = []; + var base = gridData[i][1] - this._barNudge; + var xstart; + + if (this._stack && this._prevGridData.length) { + xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x'); + } + else { + if (this.fillToZero) { + xstart = this._xaxis.series_u2p(0); + } + else { + xstart = 0; + } + } + + points.push([xstart, base+this.barWidth/2]); + points.push([gridData[i][0], base+this.barWidth/2]); + points.push([gridData[i][0], base-this.barWidth/2]); + points.push([xstart, base-this.barWidth/2]); + this.renderer.shadowRenderer.draw(ctx, points, opts); + } + } + } + + } + }; + + function postInit(target, data, options) { + for (var i=0; i<this.series.length; i++) { + if (this.series[i].renderer.constructor == $.jqplot.BarRenderer) { + // don't allow mouseover and mousedown at same time. + if (this.series[i].highlightMouseOver) { + this.series[i].highlightMouseDown = false; + } + } + } + } + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + function postPlotDraw() { + // Memory Leaks patch + if (this.plugins.barRenderer && this.plugins.barRenderer.highlightCanvas) { + + this.plugins.barRenderer.highlightCanvas.resetCanvas(); + this.plugins.barRenderer.highlightCanvas = null; + } + + this.plugins.barRenderer = {highlightedSeriesIndex:null}; + this.plugins.barRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); + + this.eventCanvas._elem.before(this.plugins.barRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-barRenderer-highlight-canvas', this._plotDimensions, this)); + this.plugins.barRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); + } + + function highlight (plot, sidx, pidx, points) { + var s = plot.series[sidx]; + var canvas = plot.plugins.barRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); + s._highlightedPoint = pidx; + plot.plugins.barRenderer.highlightedSeriesIndex = sidx; + var opts = {fillStyle: s.highlightColors[pidx]}; + s.renderer.shapeRenderer.draw(canvas._ctx, points, opts); + canvas = null; + } + + function unhighlight (plot) { + var canvas = plot.plugins.barRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); + for (var i=0; i<plot.series.length; i++) { + plot.series[i]._highlightedPoint = null; + } + plot.plugins.barRenderer.highlightedSeriesIndex = null; + plot.target.trigger('jqplotDataUnhighlight'); + canvas = null; + } + + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt1 = jQuery.Event('jqplotDataMouseOver'); + evt1.pageX = ev.pageX; + evt1.pageY = ev.pageY; + plot.target.trigger(evt1, ins); + if (plot.series[ins[0]].show && plot.series[ins[0]].highlightMouseOver && + !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { + var idx = plot.plugins.barRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + } + + function handleClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt = jQuery.Event('jqplotDataClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + function handleRightClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var idx = plot.plugins.barRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + var evt = jQuery.Event('jqplotDataRightClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.barRenderer.min.js b/plugin/jqplot/plugins/jqplot.barRenderer.min.js new file mode 100644 index 000000000..93d7a45c5 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.barRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(d){d.jqplot.BarRenderer=function(){d.jqplot.LineRenderer.call(this)};d.jqplot.BarRenderer.prototype=new d.jqplot.LineRenderer();d.jqplot.BarRenderer.prototype.constructor=d.jqplot.BarRenderer;d.jqplot.BarRenderer.prototype.init=function(o,q){this.barPadding=8;this.barMargin=10;this.barDirection="vertical";this.barWidth=null;this.shadowOffset=2;this.shadowDepth=5;this.shadowAlpha=0.08;this.waterfall=false;this.groups=1;this.varyBarColor=false;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.transposedData=true;this.renderer.animation={show:false,direction:"down",speed:3000,_supported:true};this._type="bar";if(o.highlightMouseDown&&o.highlightMouseOver==null){o.highlightMouseOver=false}d.extend(true,this,o);d.extend(true,this.renderer,o);this.fill=true;if(this.barDirection==="horizontal"&&this.rendererOptions.animation&&this.rendererOptions.animation.direction==null){this.renderer.animation.direction="left"}if(this.waterfall){this.fillToZero=false;this.disableStack=true}if(this.barDirection=="vertical"){this._primaryAxis="_xaxis";this._stackAxis="y";this.fillAxis="y"}else{this._primaryAxis="_yaxis";this._stackAxis="x";this.fillAxis="x"}this._highlightedPoint=null;this._plotSeriesInfo=null;this._dataColors=[];this._barPoints=[];var p={lineJoin:"miter",lineCap:"round",fill:true,isarc:false,strokeStyle:this.color,fillStyle:this.color,closePath:this.fill};this.renderer.shapeRenderer.init(p);var n={lineJoin:"miter",lineCap:"round",fill:true,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,closePath:this.fill};this.renderer.shadowRenderer.init(n);q.postInitHooks.addOnce(h);q.postDrawHooks.addOnce(j);q.eventListenerHooks.addOnce("jqplotMouseMove",b);q.eventListenerHooks.addOnce("jqplotMouseDown",a);q.eventListenerHooks.addOnce("jqplotMouseUp",l);q.eventListenerHooks.addOnce("jqplotClick",e);q.eventListenerHooks.addOnce("jqplotRightClick",m)};function g(t,p,o,w){if(this.rendererOptions.barDirection=="horizontal"){this._stackAxis="x";this._primaryAxis="_yaxis"}if(this.rendererOptions.waterfall==true){this._data=d.extend(true,[],this.data);var s=0;var u=(!this.rendererOptions.barDirection||this.rendererOptions.barDirection==="vertical"||this.transposedData===false)?1:0;for(var q=0;q<this.data.length;q++){s+=this.data[q][u];if(q>0){this.data[q][u]+=this.data[q-1][u]}}this.data[this.data.length]=(u==1)?[this.data.length+1,s]:[s,this.data.length+1];this._data[this._data.length]=(u==1)?[this._data.length+1,s]:[s,this._data.length+1]}if(this.rendererOptions.groups>1){this.breakOnNull=true;var n=this.data.length;var v=parseInt(n/this.rendererOptions.groups,10);var r=0;for(var q=v;q<n;q+=v){this.data.splice(q+r,0,[null,null]);this._plotData.splice(q+r,0,[null,null]);this._stackData.splice(q+r,0,[null,null]);r++}for(q=0;q<this.data.length;q++){if(this._primaryAxis=="_xaxis"){this.data[q][0]=q+1;this._plotData[q][0]=q+1;this._stackData[q][0]=q+1}else{this.data[q][1]=q+1;this._plotData[q][1]=q+1;this._stackData[q][1]=q+1}}}}d.jqplot.preSeriesInitHooks.push(g);d.jqplot.BarRenderer.prototype.calcSeriesNumbers=function(){var r=0;var t=0;var q=this[this._primaryAxis];var p,o,u;for(var n=0;n<q._series.length;n++){o=q._series[n];if(o===this){u=n}if(o.renderer.constructor==d.jqplot.BarRenderer){r+=o.data.length;t+=1}}return[r,t,u]};d.jqplot.BarRenderer.prototype.setBarWidth=function(){var q;var n=0;var o=0;var t=this[this._primaryAxis];var x,r,v;var w=this._plotSeriesInfo=this.renderer.calcSeriesNumbers.call(this);n=w[0];o=w[1];var u=t.numberTicks;var p=(u-1)/2;if(t.name=="xaxis"||t.name=="x2axis"){if(this._stack){this.barWidth=(t._offsets.max-t._offsets.min)/n*o-this.barMargin}else{this.barWidth=((t._offsets.max-t._offsets.min)/p-this.barPadding*(o-1)-this.barMargin*2)/o}}else{if(this._stack){this.barWidth=(t._offsets.min-t._offsets.max)/n*o-this.barMargin}else{this.barWidth=((t._offsets.min-t._offsets.max)/p-this.barPadding*(o-1)-this.barMargin*2)/o}}return[n,o]};function f(o){var q=[];for(var s=0;s<o.length;s++){var r=d.jqplot.getColorComponents(o[s]);var n=[r[0],r[1],r[2]];var t=n[0]+n[1]+n[2];for(var p=0;p<3;p++){n[p]=(t>570)?n[p]*0.8:n[p]+0.3*(255-n[p]);n[p]=parseInt(n[p],10)}q.push("rgb("+n[0]+","+n[1]+","+n[2]+")")}return q}function i(v,u,s,t,o){var q=v,w=v-1,n,p,r=(o==="x")?0:1;if(q>0){p=t.series[w]._plotData[u][r];if((s*p)<0){n=i(w,u,s,t,o)}else{n=t.series[w].gridData[u][r]}}else{n=(r===0)?t.series[q]._xaxis.series_u2p(0):t.series[q]._yaxis.series_u2p(0)}return n}d.jqplot.BarRenderer.prototype.draw=function(E,L,q,G){var I;var A=d.extend({},q);var w=(A.shadow!=undefined)?A.shadow:this.shadow;var O=(A.showLine!=undefined)?A.showLine:this.showLine;var F=(A.fill!=undefined)?A.fill:this.fill;var p=this.xaxis;var J=this.yaxis;var y=this._xaxis.series_u2p;var K=this._yaxis.series_u2p;var D,C;this._dataColors=[];this._barPoints=[];if(this.barWidth==null){this.renderer.setBarWidth.call(this)}var N=this._plotSeriesInfo=this.renderer.calcSeriesNumbers.call(this);var x=N[0];var v=N[1];var s=N[2];var H=[];if(this._stack){this._barNudge=0}else{this._barNudge=(-Math.abs(v/2-0.5)+s)*(this.barWidth+this.barPadding)}if(O){var u=new d.jqplot.ColorGenerator(this.negativeSeriesColors);var B=new d.jqplot.ColorGenerator(this.seriesColors);var M=u.get(this.index);if(!this.useNegativeColors){M=A.fillStyle}var t=A.fillStyle;var r;var P;var o;if(this.barDirection=="vertical"){for(var I=0;I<L.length;I++){if(!this._stack&&this.data[I][1]==null){continue}H=[];r=L[I][0]+this._barNudge;if(this._stack&&this._prevGridData.length){o=i(this.index,I,this._plotData[I][1],G,"y")}else{if(this.fillToZero){o=this._yaxis.series_u2p(0)}else{if(this.waterfall&&I>0&&I<this.gridData.length-1){o=this.gridData[I-1][1]}else{if(this.waterfall&&I==0&&I<this.gridData.length-1){if(this._yaxis.min<=0&&this._yaxis.max>=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._yaxis.min<=0&&this._yaxis.max>=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{o=E.canvas.height}}}}}if((this.fillToZero&&this._plotData[I][1]<0)||(this.waterfall&&this._data[I][1]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][1]>=0){H.push([r-this.barWidth/2,o]);H.push([r-this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,o])}else{H.push([r-this.barWidth/2,L[I][1]]);H.push([r-this.barWidth/2,o]);H.push([r+this.barWidth/2,o]);H.push([r+this.barWidth/2,L[I][1]])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}else{if(this.barDirection=="horizontal"){for(var I=0;I<L.length;I++){if(!this._stack&&this.data[I][0]==null){continue}H=[];r=L[I][1]-this._barNudge;P;if(this._stack&&this._prevGridData.length){P=i(this.index,I,this._plotData[I][0],G,"x")}else{if(this.fillToZero){P=this._xaxis.series_u2p(0)}else{if(this.waterfall&&I>0&&I<this.gridData.length-1){P=this.gridData[I-1][0]}else{if(this.waterfall&&I==0&&I<this.gridData.length-1){if(this._xaxis.min<=0&&this._xaxis.max>=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._xaxis.min<=0&&this._xaxis.max>=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=E.canvas.width}}}else{P=0}}}}}if((this.fillToZero&&this._plotData[I][0]<0)||(this.waterfall&&this._data[I][0]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][0]>=0){H.push([P,r+this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([L[I][0],r+this.barWidth/2])}else{H.push([L[I][0],r+this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([P,r+this.barWidth/2])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}}}if(this.highlightColors.length==0){this.highlightColors=d.jqplot.computeHighlightColors(this._dataColors)}else{if(typeof(this.highlightColors)=="string"){var N=this.highlightColors;this.highlightColors=[];for(var I=0;I<this._dataColors.length;I++){this.highlightColors.push(N)}}}};d.jqplot.BarRenderer.prototype.drawShadow=function(z,G,p,B){var D;var w=(p!=undefined)?p:{};var t=(w.shadow!=undefined)?w.shadow:this.shadow;var I=(w.showLine!=undefined)?w.showLine:this.showLine;var A=(w.fill!=undefined)?w.fill:this.fill;var o=this.xaxis;var E=this.yaxis;var v=this._xaxis.series_u2p;var F=this._yaxis.series_u2p;var y,C,x,u,s,r;if(this._stack&&this.shadow){if(this.barWidth==null){this.renderer.setBarWidth.call(this)}var H=this._plotSeriesInfo=this.renderer.calcSeriesNumbers.call(this);u=H[0];s=H[1];r=H[2];if(this._stack){this._barNudge=0}else{this._barNudge=(-Math.abs(s/2-0.5)+r)*(this.barWidth+this.barPadding)}if(I){if(this.barDirection=="vertical"){for(var D=0;D<G.length;D++){if(this.data[D][1]==null){continue}C=[];var q=G[D][0]+this._barNudge;var n;if(this._stack&&this._prevGridData.length){n=i(this.index,D,this._plotData[D][1],B,"y")}else{if(this.fillToZero){n=this._yaxis.series_u2p(0)}else{n=z.canvas.height}}C.push([q-this.barWidth/2,n]);C.push([q-this.barWidth/2,G[D][1]]);C.push([q+this.barWidth/2,G[D][1]]);C.push([q+this.barWidth/2,n]);this.renderer.shadowRenderer.draw(z,C,w)}}else{if(this.barDirection=="horizontal"){for(var D=0;D<G.length;D++){if(this.data[D][0]==null){continue}C=[];var q=G[D][1]-this._barNudge;var J;if(this._stack&&this._prevGridData.length){J=i(this.index,D,this._plotData[D][0],B,"x")}else{if(this.fillToZero){J=this._xaxis.series_u2p(0)}else{J=0}}C.push([J,q+this.barWidth/2]);C.push([G[D][0],q+this.barWidth/2]);C.push([G[D][0],q-this.barWidth/2]);C.push([J,q-this.barWidth/2]);this.renderer.shadowRenderer.draw(z,C,w)}}}}}};function h(q,p,n){for(var o=0;o<this.series.length;o++){if(this.series[o].renderer.constructor==d.jqplot.BarRenderer){if(this.series[o].highlightMouseOver){this.series[o].highlightMouseDown=false}}}}function j(){if(this.plugins.barRenderer&&this.plugins.barRenderer.highlightCanvas){this.plugins.barRenderer.highlightCanvas.resetCanvas();this.plugins.barRenderer.highlightCanvas=null}this.plugins.barRenderer={highlightedSeriesIndex:null};this.plugins.barRenderer.highlightCanvas=new d.jqplot.GenericCanvas();this.eventCanvas._elem.before(this.plugins.barRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-barRenderer-highlight-canvas",this._plotDimensions,this));this.plugins.barRenderer.highlightCanvas.setContext();this.eventCanvas._elem.bind("mouseleave",{plot:this},function(n){k(n.data.plot)})}function c(u,t,q,p){var o=u.series[t];var n=u.plugins.barRenderer.highlightCanvas;n._ctx.clearRect(0,0,n._ctx.canvas.width,n._ctx.canvas.height);o._highlightedPoint=q;u.plugins.barRenderer.highlightedSeriesIndex=t;var r={fillStyle:o.highlightColors[q]};o.renderer.shapeRenderer.draw(n._ctx,p,r);n=null}function k(p){var n=p.plugins.barRenderer.highlightCanvas;n._ctx.clearRect(0,0,n._ctx.canvas.width,n._ctx.canvas.height);for(var o=0;o<p.series.length;o++){p.series[o]._highlightedPoint=null}p.plugins.barRenderer.highlightedSeriesIndex=null;p.target.trigger("jqplotDataUnhighlight");n=null}function b(r,q,u,t,s){if(t){var p=[t.seriesIndex,t.pointIndex,t.data];var o=jQuery.Event("jqplotDataMouseOver");o.pageX=r.pageX;o.pageY=r.pageY;s.target.trigger(o,p);if(s.series[p[0]].show&&s.series[p[0]].highlightMouseOver&&!(p[0]==s.plugins.barRenderer.highlightedSeriesIndex&&p[1]==s.series[p[0]]._highlightedPoint)){var n=jQuery.Event("jqplotDataHighlight");n.which=r.which;n.pageX=r.pageX;n.pageY=r.pageY;s.target.trigger(n,p);c(s,t.seriesIndex,t.pointIndex,t.points)}}else{if(t==null){k(s)}}}function a(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];if(r.series[o[0]].highlightMouseDown&&!(o[0]==r.plugins.barRenderer.highlightedSeriesIndex&&o[1]==r.series[o[0]]._highlightedPoint)){var n=jQuery.Event("jqplotDataHighlight");n.which=q.which;n.pageX=q.pageX;n.pageY=q.pageY;r.target.trigger(n,o);c(r,s.seriesIndex,s.pointIndex,s.points)}}else{if(s==null){k(r)}}}function l(p,o,s,r,q){var n=q.plugins.barRenderer.highlightedSeriesIndex;if(n!=null&&q.series[n].highlightMouseDown){k(q)}}function e(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];var n=jQuery.Event("jqplotDataClick");n.which=q.which;n.pageX=q.pageX;n.pageY=q.pageY;r.target.trigger(n,o)}}function m(r,q,u,t,s){if(t){var p=[t.seriesIndex,t.pointIndex,t.data];var n=s.plugins.barRenderer.highlightedSeriesIndex;if(n!=null&&s.series[n].highlightMouseDown){k(s)}var o=jQuery.Event("jqplotDataRightClick");o.which=r.which;o.pageX=r.pageX;o.pageY=r.pageY;s.target.trigger(o,p)}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.blockRenderer.js b/plugin/jqplot/plugins/jqplot.blockRenderer.js new file mode 100644 index 000000000..e7c782cd8 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.blockRenderer.js @@ -0,0 +1,235 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.BlockRenderer + * Plugin renderer to draw a x-y block chart. A Block chart has data points displayed as + * colored squares with a text label inside. Data must be supplied in the form: + * + * > [[x1, y1, "label 1", {css}], [x2, y2, "label 2", {css}], ...] + * + * The label and css object are optional. If the label is ommitted, the + * box will collapse unless a css height and/or width is specified. + * + * The css object is an object specifying css properties + * such as: + * + * > {background:'#4f98a5', border:'3px solid gray', padding:'1px'} + * + * Note that css properties specified with the data point override defaults + * specified with the series. + * + */ + $.jqplot.BlockRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.BlockRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.BlockRenderer.prototype.constructor = $.jqplot.BlockRenderer; + + // called with scope of a series + $.jqplot.BlockRenderer.prototype.init = function(options) { + // Group: Properties + // + // prop: css + // default css styles that will be applied to all data blocks. + // these values will be overridden by css styles supplied with the + // individulal data points. + this.css = {padding:'2px', border:'1px solid #999', textAlign:'center'}; + // prop: escapeHtml + // true to escape html in the box label. + this.escapeHtml = false; + // prop: insertBreaks + // true to turn spaces in data block label into html breaks <br />. + this.insertBreaks = true; + // prop: varyBlockColors + // true to vary the color of each block in this series according to + // the seriesColors array. False to set each block to the color + // specified on this series. This has no effect if a css background color + // option is specified in the renderer css options. + this.varyBlockColors = false; + $.extend(true, this, options); + if (this.css.backgroundColor) { + this.color = this.css.backgroundColor; + } + else if (this.css.background) { + this.color = this.css.background; + } + else if (!this.varyBlockColors) { + this.css.background = this.color; + } + this.canvas = new $.jqplot.BlockCanvas(); + this.shadowCanvas = new $.jqplot.BlockCanvas(); + this.canvas._plotDimensions = this._plotDimensions; + this.shadowCanvas._plotDimensions = this._plotDimensions; + this._type = 'block'; + + // group: Methods + // + // Method: moveBlock + // Moves an individual block. More efficient than redrawing + // the whole series by calling plot.drawSeries(). + // Properties: + // idx - the 0 based index of the block or point in this series. + // x - the x coordinate in data units (value on x axis) to move the block to. + // y - the y coordinate in data units (value on the y axis) to move the block to. + // duration - optional parameter to create an animated movement. Can be a + // number (higher is slower animation) or 'fast', 'normal' or 'slow'. If not + // provided, the element is moved without any animation. + this.moveBlock = function (idx, x, y, duration) { + // update plotData, stackData, data and gridData + // x and y are in data coordinates. + var el = this.canvas._elem.children(':eq('+idx+')'); + this.data[idx][0] = x; + this.data[idx][1] = y; + this._plotData[idx][0] = x; + this._plotData[idx][1] = y; + this._stackData[idx][0] = x; + this._stackData[idx][1] = y; + this.gridData[idx][0] = this._xaxis.series_u2p(x); + this.gridData[idx][1] = this._yaxis.series_u2p(y); + var w = el.outerWidth(); + var h = el.outerHeight(); + var left = this.gridData[idx][0] - w/2 + 'px'; + var top = this.gridData[idx][1] - h/2 + 'px'; + if (duration) { + if (parseInt(duration, 10)) { + duration = parseInt(duration, 10); + } + el.animate({left:left, top:top}, duration); + } + else { + el.css({left:left, top:top}); + } + el = null; + }; + }; + + // called with scope of series + $.jqplot.BlockRenderer.prototype.draw = function (ctx, gd, options) { + if (this.plugins.pointLabels) { + this.plugins.pointLabels.show = false; + } + var i, el, d, gd, t, css, w, h, left, top; + var opts = (options != undefined) ? options : {}; + var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); + this.canvas._elem.empty(); + for (i=0; i<this.gridData.length; i++) { + d = this.data[i]; + gd = this.gridData[i]; + t = ''; + css = {}; + if (typeof d[2] == 'string') { + t = d[2]; + } + else if (typeof d[2] == 'object') { + css = d[2]; + } + if (typeof d[3] == 'object') { + css = d[3]; + } + if (this.insertBreaks){ + t = t.replace(/ /g, '<br />'); + } + css = $.extend(true, {}, this.css, css); + // create a div + el = $('<div style="position:absolute;margin-left:auto;margin-right:auto;"></div>'); + this.canvas._elem.append(el); + // set text + this.escapeHtml ? el.text(t) : el.html(t); + // style it + // remove styles we don't want overridden. + delete css.position; + delete css.marginRight; + delete css.marginLeft; + if (!css.background && !css.backgroundColor && !css.backgroundImage){ + css.background = colorGenerator.next(); + } + el.css(css); + w = el.outerWidth(); + h = el.outerHeight(); + left = gd[0] - w/2 + 'px'; + top = gd[1] - h/2 + 'px'; + el.css({left:left, top:top}); + el = null; + } + }; + + $.jqplot.BlockCanvas = function() { + $.jqplot.ElemContainer.call(this); + this._ctx; + }; + + $.jqplot.BlockCanvas.prototype = new $.jqplot.ElemContainer(); + $.jqplot.BlockCanvas.prototype.constructor = $.jqplot.BlockCanvas; + + $.jqplot.BlockCanvas.prototype.createElement = function(offsets, clss, plotDimensions) { + this._offsets = offsets; + var klass = 'jqplot-blockCanvas'; + if (clss != undefined) { + klass = clss; + } + var elem; + // if this canvas already has a dom element, don't make a new one. + if (this._elem) { + elem = this._elem.get(0); + } + else { + elem = document.createElement('div'); + } + // if new plotDimensions supplied, use them. + if (plotDimensions != undefined) { + this._plotDimensions = plotDimensions; + } + + var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px'; + var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px'; + this._elem = $(elem); + this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top }); + + this._elem.addClass(klass); + return this._elem; + }; + + $.jqplot.BlockCanvas.prototype.setContext = function() { + this._ctx = { + canvas:{ + width:0, + height:0 + }, + clearRect:function(){return null;} + }; + return this._ctx; + }; + +})(jQuery); + + \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.blockRenderer.min.js b/plugin/jqplot/plugins/jqplot.blockRenderer.min.js new file mode 100644 index 000000000..d497d6d17 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.blockRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.BlockRenderer=function(){a.jqplot.LineRenderer.call(this)};a.jqplot.BlockRenderer.prototype=new a.jqplot.LineRenderer();a.jqplot.BlockRenderer.prototype.constructor=a.jqplot.BlockRenderer;a.jqplot.BlockRenderer.prototype.init=function(b){this.css={padding:"2px",border:"1px solid #999",textAlign:"center"};this.escapeHtml=false;this.insertBreaks=true;this.varyBlockColors=false;a.extend(true,this,b);if(this.css.backgroundColor){this.color=this.css.backgroundColor}else{if(this.css.background){this.color=this.css.background}else{if(!this.varyBlockColors){this.css.background=this.color}}}this.canvas=new a.jqplot.BlockCanvas();this.shadowCanvas=new a.jqplot.BlockCanvas();this.canvas._plotDimensions=this._plotDimensions;this.shadowCanvas._plotDimensions=this._plotDimensions;this._type="block";this.moveBlock=function(l,j,i,e){var c=this.canvas._elem.children(":eq("+l+")");this.data[l][0]=j;this.data[l][1]=i;this._plotData[l][0]=j;this._plotData[l][1]=i;this._stackData[l][0]=j;this._stackData[l][1]=i;this.gridData[l][0]=this._xaxis.series_u2p(j);this.gridData[l][1]=this._yaxis.series_u2p(i);var k=c.outerWidth();var f=c.outerHeight();var d=this.gridData[l][0]-k/2+"px";var g=this.gridData[l][1]-f/2+"px";if(e){if(parseInt(e,10)){e=parseInt(e,10)}c.animate({left:d,top:g},e)}else{c.css({left:d,top:g})}c=null}};a.jqplot.BlockRenderer.prototype.draw=function(q,o,r){if(this.plugins.pointLabels){this.plugins.pointLabels.show=false}var f,c,l,o,p,k,n,g,e,m;var b=(r!=undefined)?r:{};var j=new a.jqplot.ColorGenerator(this.seriesColors);this.canvas._elem.empty();for(f=0;f<this.gridData.length;f++){l=this.data[f];o=this.gridData[f];p="";k={};if(typeof l[2]=="string"){p=l[2]}else{if(typeof l[2]=="object"){k=l[2]}}if(typeof l[3]=="object"){k=l[3]}if(this.insertBreaks){p=p.replace(/ /g,"<br />")}k=a.extend(true,{},this.css,k);c=a('<div style="position:absolute;margin-left:auto;margin-right:auto;"></div>');this.canvas._elem.append(c);this.escapeHtml?c.text(p):c.html(p);delete k.position;delete k.marginRight;delete k.marginLeft;if(!k.background&&!k.backgroundColor&&!k.backgroundImage){k.background=j.next()}c.css(k);n=c.outerWidth();g=c.outerHeight();e=o[0]-n/2+"px";m=o[1]-g/2+"px";c.css({left:e,top:m});c=null}};a.jqplot.BlockCanvas=function(){a.jqplot.ElemContainer.call(this);this._ctx};a.jqplot.BlockCanvas.prototype=new a.jqplot.ElemContainer();a.jqplot.BlockCanvas.prototype.constructor=a.jqplot.BlockCanvas;a.jqplot.BlockCanvas.prototype.createElement=function(i,e,c){this._offsets=i;var b="jqplot-blockCanvas";if(e!=undefined){b=e}var g;if(this._elem){g=this._elem.get(0)}else{g=document.createElement("div")}if(c!=undefined){this._plotDimensions=c}var d=this._plotDimensions.width-this._offsets.left-this._offsets.right+"px";var f=this._plotDimensions.height-this._offsets.top-this._offsets.bottom+"px";this._elem=a(g);this._elem.css({position:"absolute",width:d,height:f,left:this._offsets.left,top:this._offsets.top});this._elem.addClass(b);return this._elem};a.jqplot.BlockCanvas.prototype.setContext=function(){this._ctx={canvas:{width:0,height:0},clearRect:function(){return null}};return this._ctx}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.bubbleRenderer.js b/plugin/jqplot/plugins/jqplot.bubbleRenderer.js new file mode 100644 index 000000000..1629d8521 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.bubbleRenderer.js @@ -0,0 +1,759 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + var arrayMax = function( array ){ + return Math.max.apply( Math, array ); + }; + var arrayMin = function( array ){ + return Math.min.apply( Math, array ); + }; + + /** + * Class: $.jqplot.BubbleRenderer + * Plugin renderer to draw a bubble chart. A Bubble chart has data points displayed as + * colored circles with an optional text label inside. To use + * the bubble renderer, you must include the bubble renderer like: + * + * > <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.bubbleRenderer.js"></script> + * + * Data must be supplied in + * the form: + * + * > [[x1, y1, r1, <label or {label:'text', color:color}>], ...] + * + * where the label or options + * object is optional. + * + * Note that all bubble colors will be the same + * unless the "varyBubbleColors" option is set to true. Colors can be specified in the data array + * or in the seriesColors array option on the series. If no colors are defined, the default jqPlot + * series of 16 colors are used. Colors are automatically cycled around again if there are more + * bubbles than colors. + * + * Bubbles are autoscaled by default to fit within the chart area while maintaining + * relative sizes. If the "autoscaleBubbles" option is set to false, the r(adius) values + * in the data array a treated as literal pixel values for the radii of the bubbles. + * + * Properties are passed into the bubble renderer in the rendererOptions object of + * the series options like: + * + * > seriesDefaults: { + * > renderer: $.jqplot.BubbleRenderer, + * > rendererOptions: { + * > bubbleAlpha: 0.7, + * > varyBubbleColors: false + * > } + * > } + * + */ + $.jqplot.BubbleRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.BubbleRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.BubbleRenderer.prototype.constructor = $.jqplot.BubbleRenderer; + + // called with scope of a series + $.jqplot.BubbleRenderer.prototype.init = function(options, plot) { + // Group: Properties + // + // prop: varyBubbleColors + // True to vary the color of each bubble in this series according to + // the seriesColors array. False to set each bubble to the color + // specified on this series. This has no effect if a css background color + // option is specified in the renderer css options. + this.varyBubbleColors = true; + // prop: autoscaleBubbles + // True to scale the bubble radius based on plot size. + // False will use the radius value as provided as a raw pixel value for + // bubble radius. + this.autoscaleBubbles = true; + // prop: autoscaleMultiplier + // Multiplier the bubble size if autoscaleBubbles is true. + this.autoscaleMultiplier = 1.0; + // prop: autoscalePointsFactor + // Factor which decreases bubble size based on how many bubbles on on the chart. + // 0 means no adjustment for number of bubbles. Negative values will decrease + // size of bubbles as more bubbles are added. Values between 0 and -0.2 + // should work well. + this.autoscalePointsFactor = -0.07; + // prop: escapeHtml + // True to escape html in bubble label text. + this.escapeHtml = true; + // prop: highlightMouseOver + // True to highlight bubbles when moused over. + // This must be false to enable highlightMouseDown to highlight when clicking on a slice. + this.highlightMouseOver = true; + // prop: highlightMouseDown + // True to highlight when a mouse button is pressed over a bubble. + // This will be disabled if highlightMouseOver is true. + this.highlightMouseDown = false; + // prop: highlightColors + // An array of colors to use when highlighting a slice. Calculated automatically + // if not supplied. + this.highlightColors = []; + // prop: bubbleAlpha + // Alpha transparency to apply to all bubbles in this series. + this.bubbleAlpha = 1.0; + // prop: highlightAlpha + // Alpha transparency to apply when highlighting bubble. + // Set to value of bubbleAlpha by default. + this.highlightAlpha = null; + // prop: bubbleGradients + // True to color the bubbles with gradient fills instead of flat colors. + // NOT AVAILABLE IN IE due to lack of excanvas support for radial gradient fills. + // will be ignored in IE. + this.bubbleGradients = false; + // prop: showLabels + // True to show labels on bubbles (if any), false to not show. + this.showLabels = true; + // array of [point index, radius] which will be sorted in descending order to plot + // largest points below smaller points. + this.radii = []; + this.maxRadius = 0; + // index of the currenty highlighted point, if any + this._highlightedPoint = null; + // array of jQuery labels. + this.labels = []; + this.bubbleCanvases = []; + this._type = 'bubble'; + + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver + if (options.highlightMouseDown && options.highlightMouseOver == null) { + options.highlightMouseOver = false; + } + + $.extend(true, this, options); + + if (this.highlightAlpha == null) { + this.highlightAlpha = this.bubbleAlpha; + if (this.bubbleGradients) { + this.highlightAlpha = 0.35; + } + } + + this.autoscaleMultiplier = this.autoscaleMultiplier * Math.pow(this.data.length, this.autoscalePointsFactor); + + // index of the currenty highlighted point, if any + this._highlightedPoint = null; + + // adjust the series colors for options colors passed in with data or for alpha. + // note, this can leave undefined holes in the seriesColors array. + var comps; + for (var i=0; i<this.data.length; i++) { + var color = null; + var d = this.data[i]; + this.maxRadius = Math.max(this.maxRadius, d[2]); + if (d[3]) { + if (typeof(d[3]) == 'object') { + color = d[3]['color']; + } + } + + if (color == null) { + if (this.seriesColors[i] != null) { + color = this.seriesColors[i]; + } + } + + if (color && this.bubbleAlpha < 1.0) { + comps = $.jqplot.getColorComponents(color); + color = 'rgba('+comps[0]+', '+comps[1]+', '+comps[2]+', '+this.bubbleAlpha+')'; + } + + if (color) { + this.seriesColors[i] = color; + } + } + + if (!this.varyBubbleColors) { + this.seriesColors = [this.color]; + } + + this.colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); + + // set highlight colors if none provided + if (this.highlightColors.length == 0) { + for (var i=0; i<this.seriesColors.length; i++){ + var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var sum = newrgb[0] + newrgb[1] + newrgb[2]; + for (var j=0; j<3; j++) { + // when darkening, lowest color component can be is 60. + newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); + newrgb[j] = parseInt(newrgb[j], 10); + } + this.highlightColors.push('rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+', '+this.highlightAlpha+')'); + } + } + + this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors); + + var sopts = {fill:true, isarc:true, angle:this.shadowAngle, alpha:this.shadowAlpha, closePath:true}; + + this.renderer.shadowRenderer.init(sopts); + + this.canvas = new $.jqplot.DivCanvas(); + this.canvas._plotDimensions = this._plotDimensions; + + plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); + plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); + plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); + plot.eventListenerHooks.addOnce('jqplotClick', handleClick); + plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); + plot.postDrawHooks.addOnce(postPlotDraw); + + }; + + + // converts the user data values to grid coordinates and stores them + // in the gridData array. + // Called with scope of a series. + $.jqplot.BubbleRenderer.prototype.setGridData = function(plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var data = this._plotData; + this.gridData = []; + var radii = []; + this.radii = []; + var dim = Math.min(plot._height, plot._width); + for (var i=0; i<this.data.length; i++) { + if (data[i] != null) { + this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1]), data[i][2]]); + this.radii.push([i, data[i][2]]); + radii.push(data[i][2]); + } + } + var r, val, maxr = this.maxRadius = arrayMax(radii); + var l = this.gridData.length; + if (this.autoscaleBubbles) { + for (var i=0; i<l; i++) { + val = radii[i]/maxr; + r = this.autoscaleMultiplier * dim / 6; + this.gridData[i][2] = r * val; + } + } + + this.radii.sort(function(a, b) { return b[1] - a[1]; }); + }; + + // converts any arbitrary data values to grid coordinates and + // returns them. This method exists so that plugins can use a series' + // linerenderer to generate grid data points without overwriting the + // grid data associated with that series. + // Called with scope of a series. + $.jqplot.BubbleRenderer.prototype.makeGridData = function(data, plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var gd = []; + var radii = []; + this.radii = []; + var dim = Math.min(plot._height, plot._width); + for (var i=0; i<data.length; i++) { + if (data[i] != null) { + gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1]), data[i][2]]); + radii.push(data[i][2]); + this.radii.push([i, data[i][2]]); + } + } + var r, val, maxr = this.maxRadius = arrayMax(radii); + var l = this.gridData.length; + if (this.autoscaleBubbles) { + for (var i=0; i<l; i++) { + val = radii[i]/maxr; + r = this.autoscaleMultiplier * dim / 6; + gd[i][2] = r * val; + } + } + this.radii.sort(function(a, b) { return b[1] - a[1]; }); + return gd; + }; + + // called with scope of series + $.jqplot.BubbleRenderer.prototype.draw = function (ctx, gd, options) { + if (this.plugins.pointLabels) { + this.plugins.pointLabels.show = false; + } + var opts = (options != undefined) ? options : {}; + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + this.canvas._elem.empty(); + for (var i=0; i<this.radii.length; i++) { + var idx = this.radii[i][0]; + var t=null; + var color = null; + var el = null; + var tel = null; + var d = this.data[idx]; + var gd = this.gridData[idx]; + if (d[3]) { + if (typeof(d[3]) == 'object') { + t = d[3]['label']; + } + else if (typeof(d[3]) == 'string') { + t = d[3]; + } + } + + // color = (this.varyBubbleColors) ? this.colorGenerator.get(idx) : this.color; + color = this.colorGenerator.get(idx); + + // If we're drawing a shadow, expand the canvas dimensions to accomodate. + var canvasRadius = gd[2]; + var offset, depth; + if (this.shadow) { + offset = (0.7 + gd[2]/40).toFixed(1); + depth = 1 + Math.ceil(gd[2]/15); + canvasRadius += offset*depth; + } + this.bubbleCanvases[idx] = new $.jqplot.BubbleCanvas(); + this.canvas._elem.append(this.bubbleCanvases[idx].createElement(gd[0], gd[1], canvasRadius)); + this.bubbleCanvases[idx].setContext(); + var ctx = this.bubbleCanvases[idx]._ctx; + var x = ctx.canvas.width/2; + var y = ctx.canvas.height/2; + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [x, y, gd[2], 0, 2*Math.PI], {offset: offset, depth: depth}); + } + this.bubbleCanvases[idx].draw(gd[2], color, this.bubbleGradients, this.shadowAngle/180*Math.PI); + + // now draw label. + if (t && this.showLabels) { + tel = $('<div style="position:absolute;" class="jqplot-bubble-label"></div>'); + if (this.escapeHtml) { + tel.text(t); + } + else { + tel.html(t); + } + this.canvas._elem.append(tel); + var h = $(tel).outerHeight(); + var w = $(tel).outerWidth(); + var top = gd[1] - 0.5*h; + var left = gd[0] - 0.5*w; + tel.css({top: top, left: left}); + this.labels[idx] = $(tel); + } + } + }; + + + $.jqplot.DivCanvas = function() { + $.jqplot.ElemContainer.call(this); + this._ctx; + }; + + $.jqplot.DivCanvas.prototype = new $.jqplot.ElemContainer(); + $.jqplot.DivCanvas.prototype.constructor = $.jqplot.DivCanvas; + + $.jqplot.DivCanvas.prototype.createElement = function(offsets, clss, plotDimensions) { + this._offsets = offsets; + var klass = 'jqplot-DivCanvas'; + if (clss != undefined) { + klass = clss; + } + var elem; + // if this canvas already has a dom element, don't make a new one. + if (this._elem) { + elem = this._elem.get(0); + } + else { + elem = document.createElement('div'); + } + // if new plotDimensions supplied, use them. + if (plotDimensions != undefined) { + this._plotDimensions = plotDimensions; + } + + var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px'; + var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px'; + this._elem = $(elem); + this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top }); + + this._elem.addClass(klass); + return this._elem; + }; + + $.jqplot.DivCanvas.prototype.setContext = function() { + this._ctx = { + canvas:{ + width:0, + height:0 + }, + clearRect:function(){return null;} + }; + return this._ctx; + }; + + $.jqplot.BubbleCanvas = function() { + $.jqplot.ElemContainer.call(this); + this._ctx; + }; + + $.jqplot.BubbleCanvas.prototype = new $.jqplot.ElemContainer(); + $.jqplot.BubbleCanvas.prototype.constructor = $.jqplot.BubbleCanvas; + + // initialize with the x,y pont of bubble center and the bubble radius. + $.jqplot.BubbleCanvas.prototype.createElement = function(x, y, r) { + var klass = 'jqplot-bubble-point'; + + var elem; + // if this canvas already has a dom element, don't make a new one. + if (this._elem) { + elem = this._elem.get(0); + } + else { + elem = document.createElement('canvas'); + } + + elem.width = (r != null) ? 2*r : elem.width; + elem.height = (r != null) ? 2*r : elem.height; + this._elem = $(elem); + var l = (x != null && r != null) ? x - r : this._elem.css('left'); + var t = (y != null && r != null) ? y - r : this._elem.css('top'); + this._elem.css({ position: 'absolute', left: l, top: t }); + + this._elem.addClass(klass); + if ($.jqplot.use_excanvas) { + window.G_vmlCanvasManager.init_(document); + elem = window.G_vmlCanvasManager.initElement(elem); + } + + return this._elem; + }; + + $.jqplot.BubbleCanvas.prototype.draw = function(r, color, gradients, angle) { + var ctx = this._ctx; + // r = Math.floor(r*1.04); + // var x = Math.round(ctx.canvas.width/2); + // var y = Math.round(ctx.canvas.height/2); + var x = ctx.canvas.width/2; + var y = ctx.canvas.height/2; + ctx.save(); + if (gradients && !$.jqplot.use_excanvas) { + r = r*1.04; + var comps = $.jqplot.getColorComponents(color); + var colorinner = 'rgba('+Math.round(comps[0]+0.8*(255-comps[0]))+', '+Math.round(comps[1]+0.8*(255-comps[1]))+', '+Math.round(comps[2]+0.8*(255-comps[2]))+', '+comps[3]+')'; + var colorend = 'rgba('+comps[0]+', '+comps[1]+', '+comps[2]+', 0)'; + // var rinner = Math.round(0.35 * r); + // var xinner = Math.round(x - Math.cos(angle) * 0.33 * r); + // var yinner = Math.round(y - Math.sin(angle) * 0.33 * r); + var rinner = 0.35 * r; + var xinner = x - Math.cos(angle) * 0.33 * r; + var yinner = y - Math.sin(angle) * 0.33 * r; + var radgrad = ctx.createRadialGradient(xinner, yinner, rinner, x, y, r); + radgrad.addColorStop(0, colorinner); + radgrad.addColorStop(0.93, color); + radgrad.addColorStop(0.96, colorend); + radgrad.addColorStop(1, colorend); + // radgrad.addColorStop(.98, colorend); + ctx.fillStyle = radgrad; + ctx.fillRect(0,0, ctx.canvas.width, ctx.canvas.height); + } + else { + ctx.fillStyle = color; + ctx.strokeStyle = color; + ctx.lineWidth = 1; + ctx.beginPath(); + var ang = 2*Math.PI; + ctx.arc(x, y, r, 0, ang, 0); + ctx.closePath(); + ctx.fill(); + } + ctx.restore(); + }; + + $.jqplot.BubbleCanvas.prototype.setContext = function() { + this._ctx = this._elem.get(0).getContext("2d"); + return this._ctx; + }; + + $.jqplot.BubbleAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + }; + + $.jqplot.BubbleAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.BubbleAxisRenderer.prototype.constructor = $.jqplot.BubbleAxisRenderer; + + // called with scope of axis object. + $.jqplot.BubbleAxisRenderer.prototype.init = function(options){ + $.extend(true, this, options); + var db = this._dataBounds; + var minsidx = 0, + minpidx = 0, + maxsidx = 0, + maxpidx = 0, + maxr = 0, + minr = 0, + minMaxRadius = 0, + maxMaxRadius = 0, + maxMult = 0, + minMult = 0; + // Go through all the series attached to this axis and find + // the min/max bounds for this axis. + for (var i=0; i<this._series.length; i++) { + var s = this._series[i]; + var d = s._plotData; + + for (var j=0; j<d.length; j++) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + if (d[j][0] < db.min || db.min == null) { + db.min = d[j][0]; + minsidx=i; + minpidx=j; + minr = d[j][2]; + minMaxRadius = s.maxRadius; + minMult = s.autoscaleMultiplier; + } + if (d[j][0] > db.max || db.max == null) { + db.max = d[j][0]; + maxsidx=i; + maxpidx=j; + maxr = d[j][2]; + maxMaxRadius = s.maxRadius; + maxMult = s.autoscaleMultiplier; + } + } + else { + if (d[j][1] < db.min || db.min == null) { + db.min = d[j][1]; + minsidx=i; + minpidx=j; + minr = d[j][2]; + minMaxRadius = s.maxRadius; + minMult = s.autoscaleMultiplier; + } + if (d[j][1] > db.max || db.max == null) { + db.max = d[j][1]; + maxsidx=i; + maxpidx=j; + maxr = d[j][2]; + maxMaxRadius = s.maxRadius; + maxMult = s.autoscaleMultiplier; + } + } + } + } + + var minRatio = minr/minMaxRadius; + var maxRatio = maxr/maxMaxRadius; + + // need to estimate the effect of the radius on total axis span and adjust axis accordingly. + var span = db.max - db.min; + // var dim = (this.name == 'xaxis' || this.name == 'x2axis') ? this._plotDimensions.width : this._plotDimensions.height; + var dim = Math.min(this._plotDimensions.width, this._plotDimensions.height); + + var minfact = minRatio * minMult/3 * span; + var maxfact = maxRatio * maxMult/3 * span; + db.max += maxfact; + db.min -= minfact; + }; + + function highlight (plot, sidx, pidx) { + plot.plugins.bubbleRenderer.highlightLabelCanvas.empty(); + var s = plot.series[sidx]; + var canvas = plot.plugins.bubbleRenderer.highlightCanvas; + var ctx = canvas._ctx; + ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); + s._highlightedPoint = pidx; + plot.plugins.bubbleRenderer.highlightedSeriesIndex = sidx; + + var color = s.highlightColorGenerator.get(pidx); + var x = s.gridData[pidx][0], + y = s.gridData[pidx][1], + r = s.gridData[pidx][2]; + ctx.save(); + ctx.fillStyle = color; + ctx.strokeStyle = color; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.arc(x, y, r, 0, 2*Math.PI, 0); + ctx.closePath(); + ctx.fill(); + ctx.restore(); + // bring label to front + if (s.labels[pidx]) { + plot.plugins.bubbleRenderer.highlightLabel = s.labels[pidx].clone(); + plot.plugins.bubbleRenderer.highlightLabel.appendTo(plot.plugins.bubbleRenderer.highlightLabelCanvas); + plot.plugins.bubbleRenderer.highlightLabel.addClass('jqplot-bubble-label-highlight'); + } + } + + function unhighlight (plot) { + var canvas = plot.plugins.bubbleRenderer.highlightCanvas; + var sidx = plot.plugins.bubbleRenderer.highlightedSeriesIndex; + plot.plugins.bubbleRenderer.highlightLabelCanvas.empty(); + canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); + for (var i=0; i<plot.series.length; i++) { + plot.series[i]._highlightedPoint = null; + } + plot.plugins.bubbleRenderer.highlightedSeriesIndex = null; + plot.target.trigger('jqplotDataUnhighlight'); + } + + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var si = neighbor.seriesIndex; + var pi = neighbor.pointIndex; + var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]]; + var evt1 = jQuery.Event('jqplotDataMouseOver'); + evt1.pageX = ev.pageX; + evt1.pageY = ev.pageY; + plot.target.trigger(evt1, ins); + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.bubbleRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var si = neighbor.seriesIndex; + var pi = neighbor.pointIndex; + var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]]; + if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.bubbleRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { + var idx = plot.plugins.bubbleRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + } + + function handleClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var si = neighbor.seriesIndex; + var pi = neighbor.pointIndex; + var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]]; + var evt = jQuery.Event('jqplotDataClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + function handleRightClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var si = neighbor.seriesIndex; + var pi = neighbor.pointIndex; + var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]]; + var idx = plot.plugins.bubbleRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + var evt = jQuery.Event('jqplotDataRightClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + function postPlotDraw() { + // Memory Leaks patch + if (this.plugins.bubbleRenderer && this.plugins.bubbleRenderer.highlightCanvas) { + this.plugins.bubbleRenderer.highlightCanvas.resetCanvas(); + this.plugins.bubbleRenderer.highlightCanvas = null; + } + + this.plugins.bubbleRenderer = {highlightedSeriesIndex:null}; + this.plugins.bubbleRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); + this.plugins.bubbleRenderer.highlightLabel = null; + this.plugins.bubbleRenderer.highlightLabelCanvas = $('<div style="position:absolute;"></div>'); + var top = this._gridPadding.top; + var left = this._gridPadding.left; + var width = this._plotDimensions.width - this._gridPadding.left - this._gridPadding.right; + var height = this._plotDimensions.height - this._gridPadding.top - this._gridPadding.bottom; + this.plugins.bubbleRenderer.highlightLabelCanvas.css({top:top, left:left, width:width+'px', height:height+'px'}); + + this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-bubbleRenderer-highlight-canvas', this._plotDimensions, this)); + this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightLabelCanvas); + + var hctx = this.plugins.bubbleRenderer.highlightCanvas.setContext(); + } + + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + options = options || {}; + options.axesDefaults = options.axesDefaults || {}; + options.seriesDefaults = options.seriesDefaults || {}; + // only set these if there is a Bubble series + var setopts = false; + if (options.seriesDefaults.renderer == $.jqplot.BubbleRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer == $.jqplot.BubbleRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.BubbleAxisRenderer; + options.sortData = false; + } + } + + $.jqplot.preInitHooks.push(preInit); + +})(jQuery); + + \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.bubbleRenderer.min.js b/plugin/jqplot/plugins/jqplot.bubbleRenderer.min.js new file mode 100644 index 000000000..dc0c1ef01 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.bubbleRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(f){var d=function(m){return Math.max.apply(Math,m)};var j=function(m){return Math.min.apply(Math,m)};f.jqplot.BubbleRenderer=function(){f.jqplot.LineRenderer.call(this)};f.jqplot.BubbleRenderer.prototype=new f.jqplot.LineRenderer();f.jqplot.BubbleRenderer.prototype.constructor=f.jqplot.BubbleRenderer;f.jqplot.BubbleRenderer.prototype.init=function(w,t){this.varyBubbleColors=true;this.autoscaleBubbles=true;this.autoscaleMultiplier=1;this.autoscalePointsFactor=-0.07;this.escapeHtml=true;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.bubbleAlpha=1;this.highlightAlpha=null;this.bubbleGradients=false;this.showLabels=true;this.radii=[];this.maxRadius=0;this._highlightedPoint=null;this.labels=[];this.bubbleCanvases=[];this._type="bubble";if(w.highlightMouseDown&&w.highlightMouseOver==null){w.highlightMouseOver=false}f.extend(true,this,w);if(this.highlightAlpha==null){this.highlightAlpha=this.bubbleAlpha;if(this.bubbleGradients){this.highlightAlpha=0.35}}this.autoscaleMultiplier=this.autoscaleMultiplier*Math.pow(this.data.length,this.autoscalePointsFactor);this._highlightedPoint=null;var n;for(var r=0;r<this.data.length;r++){var p=null;var v=this.data[r];this.maxRadius=Math.max(this.maxRadius,v[2]);if(v[3]){if(typeof(v[3])=="object"){p=v[3]["color"]}}if(p==null){if(this.seriesColors[r]!=null){p=this.seriesColors[r]}}if(p&&this.bubbleAlpha<1){n=f.jqplot.getColorComponents(p);p="rgba("+n[0]+", "+n[1]+", "+n[2]+", "+this.bubbleAlpha+")"}if(p){this.seriesColors[r]=p}}if(!this.varyBubbleColors){this.seriesColors=[this.color]}this.colorGenerator=new f.jqplot.ColorGenerator(this.seriesColors);if(this.highlightColors.length==0){for(var r=0;r<this.seriesColors.length;r++){var o=f.jqplot.getColorComponents(this.seriesColors[r]);var u=[o[0],o[1],o[2]];var s=u[0]+u[1]+u[2];for(var q=0;q<3;q++){u[q]=(s>570)?u[q]*0.8:u[q]+0.3*(255-u[q]);u[q]=parseInt(u[q],10)}this.highlightColors.push("rgba("+u[0]+","+u[1]+","+u[2]+", "+this.highlightAlpha+")")}}this.highlightColorGenerator=new f.jqplot.ColorGenerator(this.highlightColors);var m={fill:true,isarc:true,angle:this.shadowAngle,alpha:this.shadowAlpha,closePath:true};this.renderer.shadowRenderer.init(m);this.canvas=new f.jqplot.DivCanvas();this.canvas._plotDimensions=this._plotDimensions;t.eventListenerHooks.addOnce("jqplotMouseMove",a);t.eventListenerHooks.addOnce("jqplotMouseDown",b);t.eventListenerHooks.addOnce("jqplotMouseUp",k);t.eventListenerHooks.addOnce("jqplotClick",g);t.eventListenerHooks.addOnce("jqplotRightClick",l);t.postDrawHooks.addOnce(h)};f.jqplot.BubbleRenderer.prototype.setGridData=function(w){var q=this._xaxis.series_u2p;var m=this._yaxis.series_u2p;var t=this._plotData;this.gridData=[];var s=[];this.radii=[];var v=Math.min(w._height,w._width);for(var u=0;u<this.data.length;u++){if(t[u]!=null){this.gridData.push([q.call(this._xaxis,t[u][0]),m.call(this._yaxis,t[u][1]),t[u][2]]);this.radii.push([u,t[u][2]]);s.push(t[u][2])}}var n,o,x=this.maxRadius=d(s);var p=this.gridData.length;if(this.autoscaleBubbles){for(var u=0;u<p;u++){o=s[u]/x;n=this.autoscaleMultiplier*v/6;this.gridData[u][2]=n*o}}this.radii.sort(function(y,r){return r[1]-y[1]})};f.jqplot.BubbleRenderer.prototype.makeGridData=function(t,w){var q=this._xaxis.series_u2p;var n=this._yaxis.series_u2p;var x=[];var s=[];this.radii=[];var v=Math.min(w._height,w._width);for(var u=0;u<t.length;u++){if(t[u]!=null){x.push([q.call(this._xaxis,t[u][0]),n.call(this._yaxis,t[u][1]),t[u][2]]);s.push(t[u][2]);this.radii.push([u,t[u][2]])}}var m,o,y=this.maxRadius=d(s);var p=this.gridData.length;if(this.autoscaleBubbles){for(var u=0;u<p;u++){o=s[u]/y;m=this.autoscaleMultiplier*v/6;x[u][2]=m*o}}this.radii.sort(function(z,r){return r[1]-z[1]});return x};f.jqplot.BubbleRenderer.prototype.draw=function(D,J,n){if(this.plugins.pointLabels){this.plugins.pointLabels.show=false}var A=(n!=undefined)?n:{};var r=(A.shadow!=undefined)?A.shadow:this.shadow;this.canvas._elem.empty();for(var G=0;G<this.radii.length;G++){var C=this.radii[G][0];var z=null;var F=null;var m=null;var p=null;var I=this.data[C];var J=this.gridData[C];if(I[3]){if(typeof(I[3])=="object"){z=I[3]["label"]}else{if(typeof(I[3])=="string"){z=I[3]}}}F=this.colorGenerator.get(C);var E=J[2];var q,K;if(this.shadow){q=(0.7+J[2]/40).toFixed(1);K=1+Math.ceil(J[2]/15);E+=q*K}this.bubbleCanvases[C]=new f.jqplot.BubbleCanvas();this.canvas._elem.append(this.bubbleCanvases[C].createElement(J[0],J[1],E));this.bubbleCanvases[C].setContext();var D=this.bubbleCanvases[C]._ctx;var u=D.canvas.width/2;var s=D.canvas.height/2;if(this.shadow){this.renderer.shadowRenderer.draw(D,[u,s,J[2],0,2*Math.PI],{offset:q,depth:K})}this.bubbleCanvases[C].draw(J[2],F,this.bubbleGradients,this.shadowAngle/180*Math.PI);if(z&&this.showLabels){p=f('<div style="position:absolute;" class="jqplot-bubble-label"></div>');if(this.escapeHtml){p.text(z)}else{p.html(z)}this.canvas._elem.append(p);var H=f(p).outerHeight();var v=f(p).outerWidth();var B=J[1]-0.5*H;var o=J[0]-0.5*v;p.css({top:B,left:o});this.labels[C]=f(p)}}};f.jqplot.DivCanvas=function(){f.jqplot.ElemContainer.call(this);this._ctx};f.jqplot.DivCanvas.prototype=new f.jqplot.ElemContainer();f.jqplot.DivCanvas.prototype.constructor=f.jqplot.DivCanvas;f.jqplot.DivCanvas.prototype.createElement=function(s,p,n){this._offsets=s;var m="jqplot-DivCanvas";if(p!=undefined){m=p}var r;if(this._elem){r=this._elem.get(0)}else{r=document.createElement("div")}if(n!=undefined){this._plotDimensions=n}var o=this._plotDimensions.width-this._offsets.left-this._offsets.right+"px";var q=this._plotDimensions.height-this._offsets.top-this._offsets.bottom+"px";this._elem=f(r);this._elem.css({position:"absolute",width:o,height:q,left:this._offsets.left,top:this._offsets.top});this._elem.addClass(m);return this._elem};f.jqplot.DivCanvas.prototype.setContext=function(){this._ctx={canvas:{width:0,height:0},clearRect:function(){return null}};return this._ctx};f.jqplot.BubbleCanvas=function(){f.jqplot.ElemContainer.call(this);this._ctx};f.jqplot.BubbleCanvas.prototype=new f.jqplot.ElemContainer();f.jqplot.BubbleCanvas.prototype.constructor=f.jqplot.BubbleCanvas;f.jqplot.BubbleCanvas.prototype.createElement=function(n,u,s){var m="jqplot-bubble-point";var q;if(this._elem){q=this._elem.get(0)}else{q=document.createElement("canvas")}q.width=(s!=null)?2*s:q.width;q.height=(s!=null)?2*s:q.height;this._elem=f(q);var o=(n!=null&&s!=null)?n-s:this._elem.css("left");var p=(u!=null&&s!=null)?u-s:this._elem.css("top");this._elem.css({position:"absolute",left:o,top:p});this._elem.addClass(m);if(f.jqplot.use_excanvas){window.G_vmlCanvasManager.init_(document);q=window.G_vmlCanvasManager.initElement(q)}return this._elem};f.jqplot.BubbleCanvas.prototype.draw=function(m,s,v,p){var D=this._ctx;var B=D.canvas.width/2;var z=D.canvas.height/2;D.save();if(v&&!f.jqplot.use_excanvas){m=m*1.04;var o=f.jqplot.getColorComponents(s);var u="rgba("+Math.round(o[0]+0.8*(255-o[0]))+", "+Math.round(o[1]+0.8*(255-o[1]))+", "+Math.round(o[2]+0.8*(255-o[2]))+", "+o[3]+")";var t="rgba("+o[0]+", "+o[1]+", "+o[2]+", 0)";var C=0.35*m;var A=B-Math.cos(p)*0.33*m;var n=z-Math.sin(p)*0.33*m;var w=D.createRadialGradient(A,n,C,B,z,m);w.addColorStop(0,u);w.addColorStop(0.93,s);w.addColorStop(0.96,t);w.addColorStop(1,t);D.fillStyle=w;D.fillRect(0,0,D.canvas.width,D.canvas.height)}else{D.fillStyle=s;D.strokeStyle=s;D.lineWidth=1;D.beginPath();var q=2*Math.PI;D.arc(B,z,m,0,q,0);D.closePath();D.fill()}D.restore()};f.jqplot.BubbleCanvas.prototype.setContext=function(){this._ctx=this._elem.get(0).getContext("2d");return this._ctx};f.jqplot.BubbleAxisRenderer=function(){f.jqplot.LinearAxisRenderer.call(this)};f.jqplot.BubbleAxisRenderer.prototype=new f.jqplot.LinearAxisRenderer();f.jqplot.BubbleAxisRenderer.prototype.constructor=f.jqplot.BubbleAxisRenderer;f.jqplot.BubbleAxisRenderer.prototype.init=function(n){f.extend(true,this,n);var I=this._dataBounds;var H=0,v=0,m=0,y=0,q=0,r=0,D=0,t=0,F=0,z=0;for(var E=0;E<this._series.length;E++){var x=this._series[E];var G=x._plotData;for(var B=0;B<G.length;B++){if(this.name=="xaxis"||this.name=="x2axis"){if(G[B][0]<I.min||I.min==null){I.min=G[B][0];H=E;v=B;r=G[B][2];D=x.maxRadius;z=x.autoscaleMultiplier}if(G[B][0]>I.max||I.max==null){I.max=G[B][0];m=E;y=B;q=G[B][2];t=x.maxRadius;F=x.autoscaleMultiplier}}else{if(G[B][1]<I.min||I.min==null){I.min=G[B][1];H=E;v=B;r=G[B][2];D=x.maxRadius;z=x.autoscaleMultiplier}if(G[B][1]>I.max||I.max==null){I.max=G[B][1];m=E;y=B;q=G[B][2];t=x.maxRadius;F=x.autoscaleMultiplier}}}}var o=r/D;var w=q/t;var C=I.max-I.min;var A=Math.min(this._plotDimensions.width,this._plotDimensions.height);var p=o*z/3*C;var u=w*F/3*C;I.max+=u;I.min-=p};function e(p,v,q){p.plugins.bubbleRenderer.highlightLabelCanvas.empty();var z=p.series[v];var n=p.plugins.bubbleRenderer.highlightCanvas;var w=n._ctx;w.clearRect(0,0,w.canvas.width,w.canvas.height);z._highlightedPoint=q;p.plugins.bubbleRenderer.highlightedSeriesIndex=v;var o=z.highlightColorGenerator.get(q);var u=z.gridData[q][0],t=z.gridData[q][1],m=z.gridData[q][2];w.save();w.fillStyle=o;w.strokeStyle=o;w.lineWidth=1;w.beginPath();w.arc(u,t,m,0,2*Math.PI,0);w.closePath();w.fill();w.restore();if(z.labels[q]){p.plugins.bubbleRenderer.highlightLabel=z.labels[q].clone();p.plugins.bubbleRenderer.highlightLabel.appendTo(p.plugins.bubbleRenderer.highlightLabelCanvas);p.plugins.bubbleRenderer.highlightLabel.addClass("jqplot-bubble-label-highlight")}}function i(p){var m=p.plugins.bubbleRenderer.highlightCanvas;var o=p.plugins.bubbleRenderer.highlightedSeriesIndex;p.plugins.bubbleRenderer.highlightLabelCanvas.empty();m._ctx.clearRect(0,0,m._ctx.canvas.width,m._ctx.canvas.height);for(var n=0;n<p.series.length;n++){p.series[n]._highlightedPoint=null}p.plugins.bubbleRenderer.highlightedSeriesIndex=null;p.target.trigger("jqplotDataUnhighlight")}function a(s,p,m,v,r){if(v){var n=v.seriesIndex;var o=v.pointIndex;var q=[n,o,v.data,r.series[n].gridData[o][2]];var t=jQuery.Event("jqplotDataMouseOver");t.pageX=s.pageX;t.pageY=s.pageY;r.target.trigger(t,q);if(r.series[q[0]].highlightMouseOver&&!(q[0]==r.plugins.bubbleRenderer.highlightedSeriesIndex&&q[1]==r.series[q[0]]._highlightedPoint)){var u=jQuery.Event("jqplotDataHighlight");u.which=s.which;u.pageX=s.pageX;u.pageY=s.pageY;r.target.trigger(u,q);e(r,q[0],q[1])}}else{if(v==null){i(r)}}}function b(s,p,m,u,r){if(u){var n=u.seriesIndex;var o=u.pointIndex;var q=[n,o,u.data,r.series[n].gridData[o][2]];if(r.series[q[0]].highlightMouseDown&&!(q[0]==r.plugins.bubbleRenderer.highlightedSeriesIndex&&q[1]==r.series[q[0]]._highlightedPoint)){var t=jQuery.Event("jqplotDataHighlight");t.which=s.which;t.pageX=s.pageX;t.pageY=s.pageY;r.target.trigger(t,q);e(r,q[0],q[1])}}else{if(u==null){i(r)}}}function k(o,n,r,q,p){var m=p.plugins.bubbleRenderer.highlightedSeriesIndex;if(m!=null&&p.series[m].highlightMouseDown){i(p)}}function g(s,p,m,u,r){if(u){var n=u.seriesIndex;var o=u.pointIndex;var q=[n,o,u.data,r.series[n].gridData[o][2]];var t=jQuery.Event("jqplotDataClick");t.which=s.which;t.pageX=s.pageX;t.pageY=s.pageY;r.target.trigger(t,q)}}function l(s,p,m,v,r){if(v){var n=v.seriesIndex;var o=v.pointIndex;var q=[n,o,v.data,r.series[n].gridData[o][2]];var t=r.plugins.bubbleRenderer.highlightedSeriesIndex;if(t!=null&&r.series[t].highlightMouseDown){i(r)}var u=jQuery.Event("jqplotDataRightClick");u.which=s.which;u.pageX=s.pageX;u.pageY=s.pageY;r.target.trigger(u,q)}}function h(){if(this.plugins.bubbleRenderer&&this.plugins.bubbleRenderer.highlightCanvas){this.plugins.bubbleRenderer.highlightCanvas.resetCanvas();this.plugins.bubbleRenderer.highlightCanvas=null}this.plugins.bubbleRenderer={highlightedSeriesIndex:null};this.plugins.bubbleRenderer.highlightCanvas=new f.jqplot.GenericCanvas();this.plugins.bubbleRenderer.highlightLabel=null;this.plugins.bubbleRenderer.highlightLabelCanvas=f('<div style="position:absolute;"></div>');var q=this._gridPadding.top;var p=this._gridPadding.left;var n=this._plotDimensions.width-this._gridPadding.left-this._gridPadding.right;var m=this._plotDimensions.height-this._gridPadding.top-this._gridPadding.bottom;this.plugins.bubbleRenderer.highlightLabelCanvas.css({top:q,left:p,width:n+"px",height:m+"px"});this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-bubbleRenderer-highlight-canvas",this._plotDimensions,this));this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightLabelCanvas);var o=this.plugins.bubbleRenderer.highlightCanvas.setContext()}function c(q,p,n){n=n||{};n.axesDefaults=n.axesDefaults||{};n.seriesDefaults=n.seriesDefaults||{};var m=false;if(n.seriesDefaults.renderer==f.jqplot.BubbleRenderer){m=true}else{if(n.series){for(var o=0;o<n.series.length;o++){if(n.series[o].renderer==f.jqplot.BubbleRenderer){m=true}}}}if(m){n.axesDefaults.renderer=f.jqplot.BubbleAxisRenderer;n.sortData=false}}f.jqplot.preInitHooks.push(c)})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js b/plugin/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js new file mode 100644 index 000000000..6313dc132 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js @@ -0,0 +1,203 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.CanvasAxisLabelRenderer + * Renderer to draw axis labels with a canvas element to support advanced + * featrues such as rotated text. This renderer uses a separate rendering engine + * to draw the text on the canvas. Two modes of rendering the text are available. + * If the browser has native font support for canvas fonts (currently Mozila 3.5 + * and Safari 4), you can enable text rendering with the canvas fillText method. + * You do so by setting the "enableFontSupport" option to true. + * + * Browsers lacking native font support will have the text drawn on the canvas + * using the Hershey font metrics. Even if the "enableFontSupport" option is true + * non-supporting browsers will still render with the Hershey font. + * + */ + $.jqplot.CanvasAxisLabelRenderer = function(options) { + // Group: Properties + + // prop: angle + // angle of text, measured clockwise from x axis. + this.angle = 0; + // name of the axis associated with this tick + this.axis; + // prop: show + // whether or not to show the tick (mark and label). + this.show = true; + // prop: showLabel + // whether or not to show the label. + this.showLabel = true; + // prop: label + // label for the axis. + this.label = ''; + // prop: fontFamily + // CSS spec for the font-family css attribute. + // Applies only to browsers supporting native font rendering in the + // canvas tag. Currently Mozilla 3.5 and Safari 4. + this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif'; + // prop: fontSize + // CSS spec for font size. + this.fontSize = '11pt'; + // prop: fontWeight + // CSS spec for fontWeight: normal, bold, bolder, lighter or a number 100 - 900 + this.fontWeight = 'normal'; + // prop: fontStretch + // Multiplier to condense or expand font width. + // Applies only to browsers which don't support canvas native font rendering. + this.fontStretch = 1.0; + // prop: textColor + // css spec for the color attribute. + this.textColor = '#666666'; + // prop: enableFontSupport + // true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+. + // If true, label will be drawn with canvas tag native support for fonts. + // If false, label will be drawn with Hershey font metrics. + this.enableFontSupport = true; + // prop: pt2px + // Point to pixel scaling factor, used for computing height of bounding box + // around a label. The labels text renderer has a default setting of 1.4, which + // should be suitable for most fonts. Leave as null to use default. If tops of + // letters appear clipped, increase this. If bounding box seems too big, decrease. + // This is an issue only with the native font renderering capabilities of Mozilla + // 3.5 and Safari 4 since they do not provide a method to determine the font height. + this.pt2px = null; + + this._elem; + this._ctx; + this._plotWidth; + this._plotHeight; + this._plotDimensions = {height:null, width:null}; + + $.extend(true, this, options); + + if (options.angle == null && this.axis != 'xaxis' && this.axis != 'x2axis') { + this.angle = -90; + } + + var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily}; + if (this.pt2px) { + ropts.pt2px = this.pt2px; + } + + if (this.enableFontSupport) { + if ($.jqplot.support_canvas_text()) { + this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); + } + + else { + this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts); + } + } + else { + this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts); + } + }; + + $.jqplot.CanvasAxisLabelRenderer.prototype.init = function(options) { + $.extend(true, this, options); + this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily}); + }; + + // return width along the x axis + // will check first to see if an element exists. + // if not, will return the computed text box width. + $.jqplot.CanvasAxisLabelRenderer.prototype.getWidth = function(ctx) { + if (this._elem) { + return this._elem.outerWidth(true); + } + else { + var tr = this._textRenderer; + var l = tr.getWidth(ctx); + var h = tr.getHeight(ctx); + var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l); + return w; + } + }; + + // return height along the y axis. + $.jqplot.CanvasAxisLabelRenderer.prototype.getHeight = function(ctx) { + if (this._elem) { + return this._elem.outerHeight(true); + } + else { + var tr = this._textRenderer; + var l = tr.getWidth(ctx); + var h = tr.getHeight(ctx); + var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l); + return w; + } + }; + + $.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad = function() { + var a = this.angle * Math.PI/180; + return a; + }; + + $.jqplot.CanvasAxisLabelRenderer.prototype.draw = function(ctx, plot) { + // Memory Leaks patch + if (this._elem) { + if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) { + window.G_vmlCanvasManager.uninitElement(this._elem.get(0)); + } + + this._elem.emptyForce(); + this._elem = null; + } + + // create a canvas here, but can't draw on it untill it is appended + // to dom for IE compatability. + var elem = plot.canvasManager.getCanvas(); + + this._textRenderer.setText(this.label, ctx); + var w = this.getWidth(ctx); + var h = this.getHeight(ctx); + elem.width = w; + elem.height = h; + elem.style.width = w; + elem.style.height = h; + + elem = plot.canvasManager.initCanvas(elem); + + this._elem = $(elem); + this._elem.css({ position: 'absolute'}); + this._elem.addClass('jqplot-'+this.axis+'-label'); + + elem = null; + return this._elem; + }; + + $.jqplot.CanvasAxisLabelRenderer.prototype.pack = function() { + this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label); + }; + +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.canvasAxisLabelRenderer.min.js b/plugin/jqplot/plugins/jqplot.canvasAxisLabelRenderer.min.js new file mode 100644 index 000000000..ef91dd51d --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.canvasAxisLabelRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.CanvasAxisLabelRenderer=function(b){this.angle=0;this.axis;this.show=true;this.showLabel=true;this.label="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="11pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);if(b.angle==null&&this.axis!="xaxis"&&this.axis!="x2axis"){this.angle=-90}var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){if(a.jqplot.support_canvas_text()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisLabelRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisLabelRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisLabelRenderer.prototype.draw=function(c,f){if(this._elem){if(a.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==undefined){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css({position:"absolute"});this._elem.addClass("jqplot-"+this.axis+"-label");e=null;return this._elem};a.jqplot.CanvasAxisLabelRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.canvasAxisTickRenderer.js b/plugin/jqplot/plugins/jqplot.canvasAxisTickRenderer.js new file mode 100644 index 000000000..b6120d0e5 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.canvasAxisTickRenderer.js @@ -0,0 +1,253 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.CanvasAxisTickRenderer + * Renderer to draw axis ticks with a canvas element to support advanced + * featrues such as rotated text. This renderer uses a separate rendering engine + * to draw the text on the canvas. Two modes of rendering the text are available. + * If the browser has native font support for canvas fonts (currently Mozila 3.5 + * and Safari 4), you can enable text rendering with the canvas fillText method. + * You do so by setting the "enableFontSupport" option to true. + * + * Browsers lacking native font support will have the text drawn on the canvas + * using the Hershey font metrics. Even if the "enableFontSupport" option is true + * non-supporting browsers will still render with the Hershey font. + */ + $.jqplot.CanvasAxisTickRenderer = function(options) { + // Group: Properties + + // prop: mark + // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null. + this.mark = 'outside'; + // prop: showMark + // whether or not to show the mark on the axis. + this.showMark = true; + // prop: showGridline + // whether or not to draw the gridline on the grid at this tick. + this.showGridline = true; + // prop: isMinorTick + // if this is a minor tick. + this.isMinorTick = false; + // prop: angle + // angle of text, measured clockwise from x axis. + this.angle = 0; + // prop: markSize + // Length of the tick marks in pixels. For 'cross' style, length + // will be stoked above and below axis, so total length will be twice this. + this.markSize = 4; + // prop: show + // whether or not to show the tick (mark and label). + this.show = true; + // prop: showLabel + // whether or not to show the label. + this.showLabel = true; + // prop: labelPosition + // 'auto', 'start', 'middle' or 'end'. + // Whether tick label should be positioned so the start, middle, or end + // of the tick mark. + this.labelPosition = 'auto'; + this.label = ''; + this.value = null; + this._styles = {}; + // prop: formatter + // A class of a formatter for the tick text. + // The default $.jqplot.DefaultTickFormatter uses sprintf. + this.formatter = $.jqplot.DefaultTickFormatter; + // prop: formatString + // string passed to the formatter. + this.formatString = ''; + // prop: prefix + // String to prepend to the tick label. + // Prefix is prepended to the formatted tick label. + this.prefix = ''; + // prop: fontFamily + // css spec for the font-family css attribute. + this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif'; + // prop: fontSize + // CSS spec for font size. + this.fontSize = '10pt'; + // prop: fontWeight + // CSS spec for fontWeight + this.fontWeight = 'normal'; + // prop: fontStretch + // Multiplier to condense or expand font width. + // Applies only to browsers which don't support canvas native font rendering. + this.fontStretch = 1.0; + // prop: textColor + // css spec for the color attribute. + this.textColor = '#666666'; + // prop: enableFontSupport + // true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+. + // If true, tick label will be drawn with canvas tag native support for fonts. + // If false, tick label will be drawn with Hershey font metrics. + this.enableFontSupport = true; + // prop: pt2px + // Point to pixel scaling factor, used for computing height of bounding box + // around a label. The labels text renderer has a default setting of 1.4, which + // should be suitable for most fonts. Leave as null to use default. If tops of + // letters appear clipped, increase this. If bounding box seems too big, decrease. + // This is an issue only with the native font renderering capabilities of Mozilla + // 3.5 and Safari 4 since they do not provide a method to determine the font height. + this.pt2px = null; + + this._elem; + this._ctx; + this._plotWidth; + this._plotHeight; + this._plotDimensions = {height:null, width:null}; + + $.extend(true, this, options); + + var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily}; + if (this.pt2px) { + ropts.pt2px = this.pt2px; + } + + if (this.enableFontSupport) { + if ($.jqplot.support_canvas_text()) { + this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); + } + + else { + this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts); + } + } + else { + this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts); + } + }; + + $.jqplot.CanvasAxisTickRenderer.prototype.init = function(options) { + $.extend(true, this, options); + this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily}); + }; + + // return width along the x axis + // will check first to see if an element exists. + // if not, will return the computed text box width. + $.jqplot.CanvasAxisTickRenderer.prototype.getWidth = function(ctx) { + if (this._elem) { + return this._elem.outerWidth(true); + } + else { + var tr = this._textRenderer; + var l = tr.getWidth(ctx); + var h = tr.getHeight(ctx); + var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l); + return w; + } + }; + + // return height along the y axis. + $.jqplot.CanvasAxisTickRenderer.prototype.getHeight = function(ctx) { + if (this._elem) { + return this._elem.outerHeight(true); + } + else { + var tr = this._textRenderer; + var l = tr.getWidth(ctx); + var h = tr.getHeight(ctx); + var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l); + return w; + } + }; + + // return top. + $.jqplot.CanvasAxisTickRenderer.prototype.getTop = function(ctx) { + if (this._elem) { + return this._elem.position().top; + } + else { + return null; + } + }; + + $.jqplot.CanvasAxisTickRenderer.prototype.getAngleRad = function() { + var a = this.angle * Math.PI/180; + return a; + }; + + + $.jqplot.CanvasAxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) { + this.value = value; + if (isMinor) { + this.isMinorTick = true; + } + return this; + }; + + $.jqplot.CanvasAxisTickRenderer.prototype.draw = function(ctx, plot) { + if (!this.label) { + this.label = this.prefix + this.formatter(this.formatString, this.value); + } + + // Memory Leaks patch + if (this._elem) { + if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) { + window.G_vmlCanvasManager.uninitElement(this._elem.get(0)); + } + + this._elem.emptyForce(); + this._elem = null; + } + + // create a canvas here, but can't draw on it untill it is appended + // to dom for IE compatability. + + var elem = plot.canvasManager.getCanvas(); + + this._textRenderer.setText(this.label, ctx); + var w = this.getWidth(ctx); + var h = this.getHeight(ctx); + // canvases seem to need to have width and heigh attributes directly set. + elem.width = w; + elem.height = h; + elem.style.width = w; + elem.style.height = h; + elem.style.textAlign = 'left'; + elem.style.position = 'absolute'; + + elem = plot.canvasManager.initCanvas(elem); + + this._elem = $(elem); + this._elem.css(this._styles); + this._elem.addClass('jqplot-'+this.axis+'-tick'); + + elem = null; + return this._elem; + }; + + $.jqplot.CanvasAxisTickRenderer.prototype.pack = function() { + this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label); + }; + +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.canvasAxisTickRenderer.min.js b/plugin/jqplot/plugins/jqplot.canvasAxisTickRenderer.min.js new file mode 100644 index 000000000..19875be40 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.canvasAxisTickRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.CanvasAxisTickRenderer=function(b){this.mark="outside";this.showMark=true;this.showGridline=true;this.isMinorTick=false;this.angle=0;this.markSize=4;this.show=true;this.showLabel=true;this.labelPosition="auto";this.label="";this.value=null;this._styles={};this.formatter=a.jqplot.DefaultTickFormatter;this.formatString="";this.prefix="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="10pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){if(a.jqplot.support_canvas_text()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisTickRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisTickRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisTickRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisTickRenderer.prototype.getTop=function(b){if(this._elem){return this._elem.position().top}else{return null}};a.jqplot.CanvasAxisTickRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisTickRenderer.prototype.setTick=function(b,d,c){this.value=b;if(c){this.isMinorTick=true}return this};a.jqplot.CanvasAxisTickRenderer.prototype.draw=function(c,f){if(!this.label){this.label=this.prefix+this.formatter(this.formatString,this.value)}if(this._elem){if(a.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==undefined){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e.style.textAlign="left";e.style.position="absolute";e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css(this._styles);this._elem.addClass("jqplot-"+this.axis+"-tick");e=null;return this._elem};a.jqplot.CanvasAxisTickRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.canvasOverlay.js b/plugin/jqplot/plugins/jqplot.canvasOverlay.js new file mode 100644 index 000000000..40944132c --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.canvasOverlay.js @@ -0,0 +1,1021 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + var objCounter = 0; + // class: $.jqplot.CanvasOverlay + $.jqplot.CanvasOverlay = function(opts){ + var options = opts || {}; + this.options = { + show: $.jqplot.config.enablePlugins, + deferDraw: false + }; + // prop: objects + this.objects = []; + this.objectNames = []; + this.canvas = null; + this.markerRenderer = new $.jqplot.MarkerRenderer({style:'line'}); + this.markerRenderer.init(); + this.highlightObjectIndex = null; + if (options.objects) { + var objs = options.objects, + obj; + for (var i=0; i<objs.length; i++) { + obj = objs[i]; + for (var n in obj) { + switch (n) { + case 'line': + this.addLine(obj[n]); + break; + case 'horizontalLine': + this.addHorizontalLine(obj[n]); + break; + case 'dashedHorizontalLine': + this.addDashedHorizontalLine(obj[n]); + break; + case 'verticalLine': + this.addVerticalLine(obj[n]); + break; + case 'dashedVerticalLine': + this.addDashedVerticalLine(obj[n]); + break; + case 'rectangle': + this.addRectangle(obj[n]); + break; + default: + break; + } + } + } + } + $.extend(true, this.options, options); + }; + + // called with scope of a plot object + $.jqplot.CanvasOverlay.postPlotInit = function (target, data, opts) { + var options = opts || {}; + // add a canvasOverlay attribute to the plot + this.plugins.canvasOverlay = new $.jqplot.CanvasOverlay(options.canvasOverlay); + }; + + + function LineBase() { + this.uid = null; + this.type = null; + this.gridStart = null; + this.gridStop = null; + this.tooltipWidthFactor = 0; + this.options = { + // prop: name + // Optional name for the overlay object. + // Can be later used to retrieve the object by name. + name: null, + // prop: show + // true to show (draw), false to not draw. + show: true, + // prop: lineWidth + // Width of the line. + lineWidth: 2, + // prop: lineCap + // Type of ending placed on the line ['round', 'butt', 'square'] + lineCap: 'round', + // prop: color + // color of the line + color: '#666666', + // prop: shadow + // whether or not to draw a shadow on the line + shadow: true, + // prop: shadowAngle + // Shadow angle in degrees + shadowAngle: 45, + // prop: shadowOffset + // Shadow offset from line in pixels + shadowOffset: 1, + // prop: shadowDepth + // Number of times shadow is stroked, each stroke offset shadowOffset from the last. + shadowDepth: 3, + // prop: shadowAlpha + // Alpha channel transparency of shadow. 0 = transparent. + shadowAlpha: '0.07', + // prop: xaxis + // X axis to use for positioning/scaling the line. + xaxis: 'xaxis', + // prop: yaxis + // Y axis to use for positioning/scaling the line. + yaxis: 'yaxis', + // prop: showTooltip + // Show a tooltip with data point values. + showTooltip: false, + // prop: showTooltipPrecision + // Controls how close to line cursor must be to show tooltip. + // Higher number = closer to line, lower number = farther from line. + // 1.0 = cursor must be over line. + showTooltipPrecision: 0.6, + // prop: tooltipLocation + // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' + tooltipLocation: 'nw', + // prop: fadeTooltip + // true = fade in/out tooltip, flase = show/hide tooltip + fadeTooltip: true, + // prop: tooltipFadeSpeed + // 'slow', 'def', 'fast', or number of milliseconds. + tooltipFadeSpeed: "fast", + // prop: tooltipOffset + // Pixel offset of tooltip from the highlight. + tooltipOffset: 4, + // prop: tooltipFormatString + // Format string passed the x and y values of the cursor on the line. + // e.g., 'Dogs: %.2f, Cats: %d'. + tooltipFormatString: '%d, %d' + }; + } + + + function Rectangle(options) { + LineBase.call(this); + this.type = 'rectangle'; + var opts = { + // prop: xmin + // x value for the start of the line, null to scale to axis min. + xmin: null, + // prop: xmax + // x value for the end of the line, null to scale to axis max. + xmax: null, + // prop xOffset + // offset ends of the line inside the grid. Number + xOffset: '6px', // number or string. Number interpreted as units, string as pixels. + xminOffset: null, + xmaxOffset: null, + + ymin: null, + ymax: null, + yOffset: '6px', // number or string. Number interpreted as units, string as pixels. + yminOffset: null, + ymaxOffset: null + }; + $.extend(true, this.options, opts, options); + + if (this.options.showTooltipPrecision < 0.01) { + this.options.showTooltipPrecision = 0.01; + } + } + + Rectangle.prototype = new LineBase(); + Rectangle.prototype.constructor = Rectangle; + + + /** + * Class: Line + * A straight line. + */ + function Line(options) { + LineBase.call(this); + this.type = 'line'; + var opts = { + // prop: start + // [x, y] coordinates for the start of the line. + start: [], + // prop: stop + // [x, y] coordinates for the end of the line. + stop: [] + }; + $.extend(true, this.options, opts, options); + + if (this.options.showTooltipPrecision < 0.01) { + this.options.showTooltipPrecision = 0.01; + } + } + + Line.prototype = new LineBase(); + Line.prototype.constructor = Line; + + + /** + * Class: HorizontalLine + * A straight horizontal line. + */ + function HorizontalLine(options) { + LineBase.call(this); + this.type = 'horizontalLine'; + var opts = { + // prop: y + // y value to position the line + y: null, + // prop: xmin + // x value for the start of the line, null to scale to axis min. + xmin: null, + // prop: xmax + // x value for the end of the line, null to scale to axis max. + xmax: null, + // prop xOffset + // offset ends of the line inside the grid. Number + xOffset: '6px', // number or string. Number interpreted as units, string as pixels. + xminOffset: null, + xmaxOffset: null + }; + $.extend(true, this.options, opts, options); + + if (this.options.showTooltipPrecision < 0.01) { + this.options.showTooltipPrecision = 0.01; + } + } + + HorizontalLine.prototype = new LineBase(); + HorizontalLine.prototype.constructor = HorizontalLine; + + + /** + * Class: DashedHorizontalLine + * A straight dashed horizontal line. + */ + function DashedHorizontalLine(options) { + LineBase.call(this); + this.type = 'dashedHorizontalLine'; + var opts = { + y: null, + xmin: null, + xmax: null, + xOffset: '6px', // number or string. Number interpreted as units, string as pixels. + xminOffset: null, + xmaxOffset: null, + // prop: dashPattern + // Array of line, space settings in pixels. + // Default is 8 pixel of line, 8 pixel of space. + // Note, limit to a 2 element array b/c of bug with higher order arrays. + dashPattern: [8,8] + }; + $.extend(true, this.options, opts, options); + + if (this.options.showTooltipPrecision < 0.01) { + this.options.showTooltipPrecision = 0.01; + } + } + + DashedHorizontalLine.prototype = new LineBase(); + DashedHorizontalLine.prototype.constructor = DashedHorizontalLine; + + + /** + * Class: VerticalLine + * A straight vertical line. + */ + function VerticalLine(options) { + LineBase.call(this); + this.type = 'verticalLine'; + var opts = { + x: null, + ymin: null, + ymax: null, + yOffset: '6px', // number or string. Number interpreted as units, string as pixels. + yminOffset: null, + ymaxOffset: null + }; + $.extend(true, this.options, opts, options); + + if (this.options.showTooltipPrecision < 0.01) { + this.options.showTooltipPrecision = 0.01; + } + } + + VerticalLine.prototype = new LineBase(); + VerticalLine.prototype.constructor = VerticalLine; + + + /** + * Class: DashedVerticalLine + * A straight dashed vertical line. + */ + function DashedVerticalLine(options) { + LineBase.call(this); + this.type = 'dashedVerticalLine'; + this.start = null; + this.stop = null; + var opts = { + x: null, + ymin: null, + ymax: null, + yOffset: '6px', // number or string. Number interpreted as units, string as pixels. + yminOffset: null, + ymaxOffset: null, + // prop: dashPattern + // Array of line, space settings in pixels. + // Default is 8 pixel of line, 8 pixel of space. + // Note, limit to a 2 element array b/c of bug with higher order arrays. + dashPattern: [8,8] + }; + $.extend(true, this.options, opts, options); + + if (this.options.showTooltipPrecision < 0.01) { + this.options.showTooltipPrecision = 0.01; + } + } + + DashedVerticalLine.prototype = new LineBase(); + DashedVerticalLine.prototype.constructor = DashedVerticalLine; + + $.jqplot.CanvasOverlay.prototype.addLine = function(opts) { + var line = new Line(opts); + line.uid = objCounter++; + this.objects.push(line); + this.objectNames.push(line.options.name); + }; + + $.jqplot.CanvasOverlay.prototype.addHorizontalLine = function(opts) { + var line = new HorizontalLine(opts); + line.uid = objCounter++; + this.objects.push(line); + this.objectNames.push(line.options.name); + }; + + $.jqplot.CanvasOverlay.prototype.addDashedHorizontalLine = function(opts) { + var line = new DashedHorizontalLine(opts); + line.uid = objCounter++; + this.objects.push(line); + this.objectNames.push(line.options.name); + }; + + $.jqplot.CanvasOverlay.prototype.addVerticalLine = function(opts) { + var line = new VerticalLine(opts); + line.uid = objCounter++; + this.objects.push(line); + this.objectNames.push(line.options.name); + }; + + $.jqplot.CanvasOverlay.prototype.addDashedVerticalLine = function(opts) { + var line = new DashedVerticalLine(opts); + line.uid = objCounter++; + this.objects.push(line); + this.objectNames.push(line.options.name); + }; + + $.jqplot.CanvasOverlay.prototype.addRectangle = function(opts) { + var line = new Rectangle(opts); + line.uid = objCounter++; + this.objects.push(line); + this.objectNames.push(line.options.name); + }; + + $.jqplot.CanvasOverlay.prototype.removeObject = function(idx) { + // check if integer, remove by index + if ($.type(idx) == 'number') { + this.objects.splice(idx, 1); + this.objectNames.splice(idx, 1); + } + // if string, remove by name + else { + var id = $.inArray(idx, this.objectNames); + if (id != -1) { + this.objects.splice(id, 1); + this.objectNames.splice(id, 1); + } + } + }; + + $.jqplot.CanvasOverlay.prototype.getObject = function(idx) { + // check if integer, remove by index + if ($.type(idx) == 'number') { + return this.objects[idx]; + } + // if string, remove by name + else { + var id = $.inArray(idx, this.objectNames); + if (id != -1) { + return this.objects[id]; + } + } + }; + + // Set get as alias for getObject. + $.jqplot.CanvasOverlay.prototype.get = $.jqplot.CanvasOverlay.prototype.getObject; + + $.jqplot.CanvasOverlay.prototype.clear = function(plot) { + this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight()); + }; + + $.jqplot.CanvasOverlay.prototype.draw = function(plot) { + var obj, + objs = this.objects, + mr = this.markerRenderer, + start, + stop; + if (this.options.show) { + this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight()); + for (var k=0; k<objs.length; k++) { + obj = objs[k]; + var opts = $.extend(true, {}, obj.options); + if (obj.options.show) { + // style and shadow properties should be set before + // every draw of marker renderer. + mr.shadow = obj.options.shadow; + obj.tooltipWidthFactor = obj.options.lineWidth / obj.options.showTooltipPrecision; + switch (obj.type) { + case 'line': + // style and shadow properties should be set before + // every draw of marker renderer. + mr.style = 'line'; + opts.closePath = false; + start = [plot.axes[obj.options.xaxis].series_u2p(obj.options.start[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.start[1])]; + stop = [plot.axes[obj.options.xaxis].series_u2p(obj.options.stop[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.stop[1])]; + obj.gridStart = start; + obj.gridStop = stop; + mr.draw(start, stop, this.canvas._ctx, opts); + break; + case 'horizontalLine': + + // style and shadow properties should be set before + // every draw of marker renderer. + if (obj.options.y != null) { + mr.style = 'line'; + opts.closePath = false; + var xaxis = plot.axes[obj.options.xaxis], + xstart, + xstop, + y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y), + xminoff = obj.options.xminOffset || obj.options.xOffset, + xmaxoff = obj.options.xmaxOffset || obj.options.xOffset; + if (obj.options.xmin != null) { + xstart = xaxis.series_u2p(obj.options.xmin); + } + else if (xminoff != null) { + if ($.type(xminoff) == "number") { + xstart = xaxis.series_u2p(xaxis.min + xminoff); + } + else if ($.type(xminoff) == "string") { + xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff); + } + } + if (obj.options.xmax != null) { + xstop = xaxis.series_u2p(obj.options.xmax); + } + else if (xmaxoff != null) { + if ($.type(xmaxoff) == "number") { + xstop = xaxis.series_u2p(xaxis.max - xmaxoff); + } + else if ($.type(xmaxoff) == "string") { + xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff); + } + } + if (xstop != null && xstart != null) { + obj.gridStart = [xstart, y]; + obj.gridStop = [xstop, y]; + mr.draw([xstart, y], [xstop, y], this.canvas._ctx, opts); + } + } + break; + + case 'dashedHorizontalLine': + + var dashPat = obj.options.dashPattern; + var dashPatLen = 0; + for (var i=0; i<dashPat.length; i++) { + dashPatLen += dashPat[i]; + } + + // style and shadow properties should be set before + // every draw of marker renderer. + if (obj.options.y != null) { + mr.style = 'line'; + opts.closePath = false; + var xaxis = plot.axes[obj.options.xaxis], + xstart, + xstop, + y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y), + xminoff = obj.options.xminOffset || obj.options.xOffset, + xmaxoff = obj.options.xmaxOffset || obj.options.xOffset; + if (obj.options.xmin != null) { + xstart = xaxis.series_u2p(obj.options.xmin); + } + else if (xminoff != null) { + if ($.type(xminoff) == "number") { + xstart = xaxis.series_u2p(xaxis.min + xminoff); + } + else if ($.type(xminoff) == "string") { + xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff); + } + } + if (obj.options.xmax != null) { + xstop = xaxis.series_u2p(obj.options.xmax); + } + else if (xmaxoff != null) { + if ($.type(xmaxoff) == "number") { + xstop = xaxis.series_u2p(xaxis.max - xmaxoff); + } + else if ($.type(xmaxoff) == "string") { + xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff); + } + } + if (xstop != null && xstart != null) { + obj.gridStart = [xstart, y]; + obj.gridStop = [xstop, y]; + var numDash = Math.ceil((xstop - xstart)/dashPatLen); + var b=xstart, e; + for (var i=0; i<numDash; i++) { + for (var j=0; j<dashPat.length; j+=2) { + e = b+dashPat[j]; + mr.draw([b, y], [e, y], this.canvas._ctx, opts); + b += dashPat[j]; + if (j < dashPat.length-1) { + b += dashPat[j+1]; + } + } + } + } + } + break; + + case 'verticalLine': + + // style and shadow properties should be set before + // every draw of marker renderer. + if (obj.options.x != null) { + mr.style = 'line'; + opts.closePath = false; + var yaxis = plot.axes[obj.options.yaxis], + ystart, + ystop, + x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x), + yminoff = obj.options.yminOffset || obj.options.yOffset, + ymaxoff = obj.options.ymaxOffset || obj.options.yOffset; + if (obj.options.ymin != null) { + ystart = yaxis.series_u2p(obj.options.ymin); + } + else if (yminoff != null) { + if ($.type(yminoff) == "number") { + ystart = yaxis.series_u2p(yaxis.min - yminoff); + } + else if ($.type(yminoff) == "string") { + ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff); + } + } + if (obj.options.ymax != null) { + ystop = yaxis.series_u2p(obj.options.ymax); + } + else if (ymaxoff != null) { + if ($.type(ymaxoff) == "number") { + ystop = yaxis.series_u2p(yaxis.max + ymaxoff); + } + else if ($.type(ymaxoff) == "string") { + ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff); + } + } + if (ystop != null && ystart != null) { + obj.gridStart = [x, ystart]; + obj.gridStop = [x, ystop]; + mr.draw([x, ystart], [x, ystop], this.canvas._ctx, opts); + } + } + break; + + case 'dashedVerticalLine': + + var dashPat = obj.options.dashPattern; + var dashPatLen = 0; + for (var i=0; i<dashPat.length; i++) { + dashPatLen += dashPat[i]; + } + + // style and shadow properties should be set before + // every draw of marker renderer. + if (obj.options.x != null) { + mr.style = 'line'; + opts.closePath = false; + var yaxis = plot.axes[obj.options.yaxis], + ystart, + ystop, + x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x), + yminoff = obj.options.yminOffset || obj.options.yOffset, + ymaxoff = obj.options.ymaxOffset || obj.options.yOffset; + if (obj.options.ymin != null) { + ystart = yaxis.series_u2p(obj.options.ymin); + } + else if (yminoff != null) { + if ($.type(yminoff) == "number") { + ystart = yaxis.series_u2p(yaxis.min - yminoff); + } + else if ($.type(yminoff) == "string") { + ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff); + } + } + if (obj.options.ymax != null) { + ystop = yaxis.series_u2p(obj.options.ymax); + } + else if (ymaxoff != null) { + if ($.type(ymaxoff) == "number") { + ystop = yaxis.series_u2p(yaxis.max + ymaxoff); + } + else if ($.type(ymaxoff) == "string") { + ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff); + } + } + + + if (ystop != null && ystart != null) { + obj.gridStart = [x, ystart]; + obj.gridStop = [x, ystop]; + var numDash = Math.ceil((ystart - ystop)/dashPatLen); + var firstDashAdjust = ((numDash * dashPatLen) - (ystart - ystop))/2.0; + var b=ystart, e, bs, es; + for (var i=0; i<numDash; i++) { + for (var j=0; j<dashPat.length; j+=2) { + e = b - dashPat[j]; + if (e < ystop) { + e = ystop; + } + if (b < ystop) { + b = ystop; + } + // es = e; + // if (i == 0) { + // es += firstDashAdjust; + // } + mr.draw([x, b], [x, e], this.canvas._ctx, opts); + b -= dashPat[j]; + if (j < dashPat.length-1) { + b -= dashPat[j+1]; + } + } + } + } + } + break; + + case 'rectangle': + // style and shadow properties should be set before + // every draw of marker renderer. + mr.style = 'line'; + opts.closePath = true; + + var xaxis = plot.axes[obj.options.xaxis], + xstart, + xstop, + y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y), + xminoff = obj.options.xminOffset || obj.options.xOffset, + xmaxoff = obj.options.xmaxOffset || obj.options.xOffset; + if (obj.options.xmin != null) { + xstart = xaxis.series_u2p(obj.options.xmin); + } + else if (xminoff != null) { + if ($.type(xminoff) == "number") { + xstart = xaxis.series_u2p(xaxis.min + xminoff); + } + else if ($.type(xminoff) == "string") { + xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff); + } + } + if (obj.options.xmax != null) { + xstop = xaxis.series_u2p(obj.options.xmax); + } + else if (xmaxoff != null) { + if ($.type(xmaxoff) == "number") { + xstop = xaxis.series_u2p(xaxis.max - xmaxoff); + } + else if ($.type(xmaxoff) == "string") { + xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff); + } + } + + var yaxis = plot.axes[obj.options.yaxis], + ystart, + ystop, + x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x), + yminoff = obj.options.yminOffset || obj.options.yOffset, + ymaxoff = obj.options.ymaxOffset || obj.options.yOffset; + if (obj.options.ymin != null) { + ystart = yaxis.series_u2p(obj.options.ymin); + } + else if (yminoff != null) { + if ($.type(yminoff) == "number") { + ystart = yaxis.series_u2p(yaxis.min - yminoff); + } + else if ($.type(yminoff) == "string") { + ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff); + } + } + if (obj.options.ymax != null) { + ystop = yaxis.series_u2p(obj.options.ymax); + } + else if (ymaxoff != null) { + if ($.type(ymaxoff) == "number") { + ystop = yaxis.series_u2p(yaxis.max + ymaxoff); + } + else if ($.type(ymaxoff) == "string") { + ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff); + } + } + + + if (xstop != null && xstart != null && ystop != null && ystart != null) { + obj.gridStart = [xstart, ystart]; + obj.gridStop = [xstop, ystop]; + + this.canvas._ctx.fillStyle = obj.options.color; + this.canvas._ctx.fillRect(xstart, ystart, xstop - xstart, ystop - ystart); + } + break; + + default: + break; + } + } + } + } + }; + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + $.jqplot.CanvasOverlay.postPlotDraw = function() { + var co = this.plugins.canvasOverlay; + // Memory Leaks patch + if (co && co.highlightCanvas) { + co.highlightCanvas.resetCanvas(); + co.highlightCanvas = null; + } + co.canvas = new $.jqplot.GenericCanvas(); + + this.eventCanvas._elem.before(co.canvas.createElement(this._gridPadding, 'jqplot-overlayCanvas-canvas', this._plotDimensions, this)); + co.canvas.setContext(); + if (!co.deferDraw) { + co.draw(this); + } + + var elem = document.createElement('div'); + co._tooltipElem = $(elem); + elem = null; + co._tooltipElem.addClass('jqplot-canvasOverlay-tooltip'); + co._tooltipElem.css({position:'absolute', display:'none'}); + + this.eventCanvas._elem.before(co._tooltipElem); + this.eventCanvas._elem.bind('mouseleave', { elem: co._tooltipElem }, function (ev) { ev.data.elem.hide(); }); + + var co = null; + }; + + + function showTooltip(plot, obj, gridpos, datapos) { + var co = plot.plugins.canvasOverlay; + var elem = co._tooltipElem; + + var opts = obj.options, x, y; + + elem.html($.jqplot.sprintf(opts.tooltipFormatString, datapos[0], datapos[1])); + + switch (opts.tooltipLocation) { + case 'nw': + x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset; + y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true); + break; + case 'n': + x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2; + y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true); + break; + case 'ne': + x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset; + y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true); + break; + case 'e': + x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset; + y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2; + break; + case 'se': + x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset; + y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset; + break; + case 's': + x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2; + y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset; + break; + case 'sw': + x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset; + y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset; + break; + case 'w': + x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset; + y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2; + break; + default: // same as 'nw' + x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset; + y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true); + break; + } + + elem.css('left', x); + elem.css('top', y); + if (opts.fadeTooltip) { + // Fix for stacked up animations. Thnanks Trevor! + elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed); + } + else { + elem.show(); + } + elem = null; + } + + + function isNearLine(point, lstart, lstop, width) { + // r is point to test, p and q are end points. + var rx = point[0]; + var ry = point[1]; + var px = Math.round(lstop[0]); + var py = Math.round(lstop[1]); + var qx = Math.round(lstart[0]); + var qy = Math.round(lstart[1]); + + var l = Math.sqrt(Math.pow(px-qx, 2) + Math.pow(py-qy, 2)); + + // scale error term by length of line. + var eps = width*l; + var res = Math.abs((qx-px) * (ry-py) - (qy-py) * (rx-px)); + var ret = (res < eps) ? true : false; + return ret; + } + + function isNearRectangle(point, lstart, lstop, width) { + // r is point to test, p and q are end points. + var rx = point[0]; + var ry = point[1]; + var px = Math.round(lstop[0]); + var py = Math.round(lstop[1]); + var qx = Math.round(lstart[0]); + var qy = Math.round(lstart[1]); + + var temp; + if (px > qx) { temp = px; px = qx; qx = temp; } + if (py > qy) { temp = py; py = qy; qy = temp; } + + var ret = (rx >= px && rx <= qx && ry >= py && ry <= qy); + + return ret; + } + + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + var co = plot.plugins.canvasOverlay; + var objs = co.objects; + var l = objs.length; + var obj, haveHighlight=false; + var elem; + for (var i=0; i<l; i++) { + obj = objs[i]; + if (obj.options.showTooltip) { + var n; + if (obj.type === 'rectangle') { + n = isNearRectangle([gridpos.x, gridpos.y], obj.gridStart, obj.gridStop, obj.tooltipWidthFactor); + } else { + n = isNearLine([gridpos.x, gridpos.y], obj.gridStart, obj.gridStop, obj.tooltipWidthFactor); + } + datapos = [plot.axes[obj.options.xaxis].series_p2u(gridpos.x), plot.axes[obj.options.yaxis].series_p2u(gridpos.y)]; + + // cases: + // near line, no highlighting + // near line, highliting on this line + // near line, highlighting another line + // not near any line, highlighting + // not near any line, no highlighting + + // near line, not currently highlighting + if (n && co.highlightObjectIndex == null) { + switch (obj.type) { + case 'line': + showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos); + break; + + case 'horizontalLine': + case 'dashedHorizontalLine': + showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]); + break; + + case 'verticalLine': + case 'dashedVerticalLine': + showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]); + break; + + case 'rectangle': + showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]); + break; + + default: + break; + } + co.highlightObjectIndex = i; + haveHighlight = true; + break; + } + + // near line, highlighting another line. + else if (n && co.highlightObjectIndex !== i) { + // turn off tooltip. + elem = co._tooltipElem; + if (obj.fadeTooltip) { + elem.fadeOut(obj.tooltipFadeSpeed); + } + else { + elem.hide(); + } + + // turn on right tooltip. + switch (obj.type) { + case 'line': + showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos); + break; + + case 'horizontalLine': + case 'dashedHorizontalLine': + showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]); + break; + + case 'verticalLine': + case 'dashedVerticalLine': + showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]); + break; + + case 'rectangle': + showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]); + break; + + default: + break; + } + + co.highlightObjectIndex = i; + haveHighlight = true; + break; + } + + // near line, already highlighting this line, update + else if (n) { + switch (obj.type) { + case 'line': + showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos); + break; + + case 'horizontalLine': + case 'dashedHorizontalLine': + showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]); + break; + + case 'verticalLine': + case 'dashedVerticalLine': + showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]); + break; + + case 'rectangle': + showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]); + break; + + default: + break; + } + + haveHighlight = true; + break; + } + } + } + + // check if we are highlighting and not near a line, turn it off. + if (!haveHighlight && co.highlightObjectIndex !== null) { + elem = co._tooltipElem; + obj = co.getObject(co.highlightObjectIndex); + if (obj.fadeTooltip) { + elem.fadeOut(obj.tooltipFadeSpeed); + } + else { + elem.hide(); + } + co.highlightObjectIndex = null; + } + } + + $.jqplot.postInitHooks.push($.jqplot.CanvasOverlay.postPlotInit); + $.jqplot.postDrawHooks.push($.jqplot.CanvasOverlay.postPlotDraw); + $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]); + +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.canvasOverlay.min.js b/plugin/jqplot/plugins/jqplot.canvasOverlay.min.js new file mode 100644 index 000000000..fa469ad1a --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.canvasOverlay.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(d){var f=0;d.jqplot.CanvasOverlay=function(q){var o=q||{};this.options={show:d.jqplot.config.enablePlugins,deferDraw:false};this.objects=[];this.objectNames=[];this.canvas=null;this.markerRenderer=new d.jqplot.MarkerRenderer({style:"line"});this.markerRenderer.init();this.highlightObjectIndex=null;if(o.objects){var s=o.objects,r;for(var p=0;p<s.length;p++){r=s[p];for(var t in r){switch(t){case"line":this.addLine(r[t]);break;case"horizontalLine":this.addHorizontalLine(r[t]);break;case"dashedHorizontalLine":this.addDashedHorizontalLine(r[t]);break;case"verticalLine":this.addVerticalLine(r[t]);break;case"dashedVerticalLine":this.addDashedVerticalLine(r[t]);break;case"rectangle":this.addRectangle(r[t]);break;default:break}}}}d.extend(true,this.options,o)};d.jqplot.CanvasOverlay.postPlotInit=function(q,p,o){var n=o||{};this.plugins.canvasOverlay=new d.jqplot.CanvasOverlay(n.canvasOverlay)};function i(){this.uid=null;this.type=null;this.gridStart=null;this.gridStop=null;this.tooltipWidthFactor=0;this.options={name:null,show:true,lineWidth:2,lineCap:"round",color:"#666666",shadow:true,shadowAngle:45,shadowOffset:1,shadowDepth:3,shadowAlpha:"0.07",xaxis:"xaxis",yaxis:"yaxis",showTooltip:false,showTooltipPrecision:0.6,tooltipLocation:"nw",fadeTooltip:true,tooltipFadeSpeed:"fast",tooltipOffset:4,tooltipFormatString:"%d, %d"}}function m(n){i.call(this);this.type="rectangle";var o={xmin:null,xmax:null,xOffset:"6px",xminOffset:null,xmaxOffset:null,ymin:null,ymax:null,yOffset:"6px",yminOffset:null,ymaxOffset:null};d.extend(true,this.options,o,n);if(this.options.showTooltipPrecision<0.01){this.options.showTooltipPrecision=0.01}}m.prototype=new i();m.prototype.constructor=m;function b(n){i.call(this);this.type="line";var o={start:[],stop:[]};d.extend(true,this.options,o,n);if(this.options.showTooltipPrecision<0.01){this.options.showTooltipPrecision=0.01}}b.prototype=new i();b.prototype.constructor=b;function e(n){i.call(this);this.type="horizontalLine";var o={y:null,xmin:null,xmax:null,xOffset:"6px",xminOffset:null,xmaxOffset:null};d.extend(true,this.options,o,n);if(this.options.showTooltipPrecision<0.01){this.options.showTooltipPrecision=0.01}}e.prototype=new i();e.prototype.constructor=e;function j(n){i.call(this);this.type="dashedHorizontalLine";var o={y:null,xmin:null,xmax:null,xOffset:"6px",xminOffset:null,xmaxOffset:null,dashPattern:[8,8]};d.extend(true,this.options,o,n);if(this.options.showTooltipPrecision<0.01){this.options.showTooltipPrecision=0.01}}j.prototype=new i();j.prototype.constructor=j;function c(n){i.call(this);this.type="verticalLine";var o={x:null,ymin:null,ymax:null,yOffset:"6px",yminOffset:null,ymaxOffset:null};d.extend(true,this.options,o,n);if(this.options.showTooltipPrecision<0.01){this.options.showTooltipPrecision=0.01}}c.prototype=new i();c.prototype.constructor=c;function l(n){i.call(this);this.type="dashedVerticalLine";this.start=null;this.stop=null;var o={x:null,ymin:null,ymax:null,yOffset:"6px",yminOffset:null,ymaxOffset:null,dashPattern:[8,8]};d.extend(true,this.options,o,n);if(this.options.showTooltipPrecision<0.01){this.options.showTooltipPrecision=0.01}}l.prototype=new i();l.prototype.constructor=l;d.jqplot.CanvasOverlay.prototype.addLine=function(o){var n=new b(o);n.uid=f++;this.objects.push(n);this.objectNames.push(n.options.name)};d.jqplot.CanvasOverlay.prototype.addHorizontalLine=function(o){var n=new e(o);n.uid=f++;this.objects.push(n);this.objectNames.push(n.options.name)};d.jqplot.CanvasOverlay.prototype.addDashedHorizontalLine=function(o){var n=new j(o);n.uid=f++;this.objects.push(n);this.objectNames.push(n.options.name)};d.jqplot.CanvasOverlay.prototype.addVerticalLine=function(o){var n=new c(o);n.uid=f++;this.objects.push(n);this.objectNames.push(n.options.name)};d.jqplot.CanvasOverlay.prototype.addDashedVerticalLine=function(o){var n=new l(o);n.uid=f++;this.objects.push(n);this.objectNames.push(n.options.name)};d.jqplot.CanvasOverlay.prototype.addRectangle=function(o){var n=new m(o);n.uid=f++;this.objects.push(n);this.objectNames.push(n.options.name)};d.jqplot.CanvasOverlay.prototype.removeObject=function(n){if(d.type(n)=="number"){this.objects.splice(n,1);this.objectNames.splice(n,1)}else{var o=d.inArray(n,this.objectNames);if(o!=-1){this.objects.splice(o,1);this.objectNames.splice(o,1)}}};d.jqplot.CanvasOverlay.prototype.getObject=function(n){if(d.type(n)=="number"){return this.objects[n]}else{var o=d.inArray(n,this.objectNames);if(o!=-1){return this.objects[o]}}};d.jqplot.CanvasOverlay.prototype.get=d.jqplot.CanvasOverlay.prototype.getObject;d.jqplot.CanvasOverlay.prototype.clear=function(n){this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(),this.canvas.getHeight())};d.jqplot.CanvasOverlay.prototype.draw=function(K){var A,v=this.objects,F=this.markerRenderer,s,G;if(this.options.show){this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(),this.canvas.getHeight());for(var H=0;H<v.length;H++){A=v[H];var B=d.extend(true,{},A.options);if(A.options.show){F.shadow=A.options.shadow;A.tooltipWidthFactor=A.options.lineWidth/A.options.showTooltipPrecision;switch(A.type){case"line":F.style="line";B.closePath=false;s=[K.axes[A.options.xaxis].series_u2p(A.options.start[0]),K.axes[A.options.yaxis].series_u2p(A.options.start[1])];G=[K.axes[A.options.xaxis].series_u2p(A.options.stop[0]),K.axes[A.options.yaxis].series_u2p(A.options.stop[1])];A.gridStart=s;A.gridStop=G;F.draw(s,G,this.canvas._ctx,B);break;case"horizontalLine":if(A.options.y!=null){F.style="line";B.closePath=false;var p=K.axes[A.options.xaxis],S,L,w=K.axes[A.options.yaxis].series_u2p(A.options.y),I=A.options.xminOffset||A.options.xOffset,t=A.options.xmaxOffset||A.options.xOffset;if(A.options.xmin!=null){S=p.series_u2p(A.options.xmin)}else{if(I!=null){if(d.type(I)=="number"){S=p.series_u2p(p.min+I)}else{if(d.type(I)=="string"){S=p.series_u2p(p.min)+parseFloat(I)}}}}if(A.options.xmax!=null){L=p.series_u2p(A.options.xmax)}else{if(t!=null){if(d.type(t)=="number"){L=p.series_u2p(p.max-t)}else{if(d.type(t)=="string"){L=p.series_u2p(p.max)-parseFloat(t)}}}}if(L!=null&&S!=null){A.gridStart=[S,w];A.gridStop=[L,w];F.draw([S,w],[L,w],this.canvas._ctx,B)}}break;case"dashedHorizontalLine":var o=A.options.dashPattern;var E=0;for(var M=0;M<o.length;M++){E+=o[M]}if(A.options.y!=null){F.style="line";B.closePath=false;var p=K.axes[A.options.xaxis],S,L,w=K.axes[A.options.yaxis].series_u2p(A.options.y),I=A.options.xminOffset||A.options.xOffset,t=A.options.xmaxOffset||A.options.xOffset;if(A.options.xmin!=null){S=p.series_u2p(A.options.xmin)}else{if(I!=null){if(d.type(I)=="number"){S=p.series_u2p(p.min+I)}else{if(d.type(I)=="string"){S=p.series_u2p(p.min)+parseFloat(I)}}}}if(A.options.xmax!=null){L=p.series_u2p(A.options.xmax)}else{if(t!=null){if(d.type(t)=="number"){L=p.series_u2p(p.max-t)}else{if(d.type(t)=="string"){L=p.series_u2p(p.max)-parseFloat(t)}}}}if(L!=null&&S!=null){A.gridStart=[S,w];A.gridStop=[L,w];var r=Math.ceil((L-S)/E);var Q=S,O;for(var M=0;M<r;M++){for(var J=0;J<o.length;J+=2){O=Q+o[J];F.draw([Q,w],[O,w],this.canvas._ctx,B);Q+=o[J];if(J<o.length-1){Q+=o[J+1]}}}}}break;case"verticalLine":if(A.options.x!=null){F.style="line";B.closePath=false;var N=K.axes[A.options.yaxis],n,u,z=K.axes[A.options.xaxis].series_u2p(A.options.x),D=A.options.yminOffset||A.options.yOffset,q=A.options.ymaxOffset||A.options.yOffset;if(A.options.ymin!=null){n=N.series_u2p(A.options.ymin)}else{if(D!=null){if(d.type(D)=="number"){n=N.series_u2p(N.min-D)}else{if(d.type(D)=="string"){n=N.series_u2p(N.min)-parseFloat(D)}}}}if(A.options.ymax!=null){u=N.series_u2p(A.options.ymax)}else{if(q!=null){if(d.type(q)=="number"){u=N.series_u2p(N.max+q)}else{if(d.type(q)=="string"){u=N.series_u2p(N.max)+parseFloat(q)}}}}if(u!=null&&n!=null){A.gridStart=[z,n];A.gridStop=[z,u];F.draw([z,n],[z,u],this.canvas._ctx,B)}}break;case"dashedVerticalLine":var o=A.options.dashPattern;var E=0;for(var M=0;M<o.length;M++){E+=o[M]}if(A.options.x!=null){F.style="line";B.closePath=false;var N=K.axes[A.options.yaxis],n,u,z=K.axes[A.options.xaxis].series_u2p(A.options.x),D=A.options.yminOffset||A.options.yOffset,q=A.options.ymaxOffset||A.options.yOffset;if(A.options.ymin!=null){n=N.series_u2p(A.options.ymin)}else{if(D!=null){if(d.type(D)=="number"){n=N.series_u2p(N.min-D)}else{if(d.type(D)=="string"){n=N.series_u2p(N.min)-parseFloat(D)}}}}if(A.options.ymax!=null){u=N.series_u2p(A.options.ymax)}else{if(q!=null){if(d.type(q)=="number"){u=N.series_u2p(N.max+q)}else{if(d.type(q)=="string"){u=N.series_u2p(N.max)+parseFloat(q)}}}}if(u!=null&&n!=null){A.gridStart=[z,n];A.gridStop=[z,u];var r=Math.ceil((n-u)/E);var C=((r*E)-(n-u))/2;var Q=n,O,P,R;for(var M=0;M<r;M++){for(var J=0;J<o.length;J+=2){O=Q-o[J];if(O<u){O=u}if(Q<u){Q=u}F.draw([z,Q],[z,O],this.canvas._ctx,B);Q-=o[J];if(J<o.length-1){Q-=o[J+1]}}}}}break;case"rectangle":F.style="line";B.closePath=true;var p=K.axes[A.options.xaxis],S,L,w=K.axes[A.options.yaxis].series_u2p(A.options.y),I=A.options.xminOffset||A.options.xOffset,t=A.options.xmaxOffset||A.options.xOffset;if(A.options.xmin!=null){S=p.series_u2p(A.options.xmin)}else{if(I!=null){if(d.type(I)=="number"){S=p.series_u2p(p.min+I)}else{if(d.type(I)=="string"){S=p.series_u2p(p.min)+parseFloat(I)}}}}if(A.options.xmax!=null){L=p.series_u2p(A.options.xmax)}else{if(t!=null){if(d.type(t)=="number"){L=p.series_u2p(p.max-t)}else{if(d.type(t)=="string"){L=p.series_u2p(p.max)-parseFloat(t)}}}}var N=K.axes[A.options.yaxis],n,u,z=K.axes[A.options.xaxis].series_u2p(A.options.x),D=A.options.yminOffset||A.options.yOffset,q=A.options.ymaxOffset||A.options.yOffset;if(A.options.ymin!=null){n=N.series_u2p(A.options.ymin)}else{if(D!=null){if(d.type(D)=="number"){n=N.series_u2p(N.min-D)}else{if(d.type(D)=="string"){n=N.series_u2p(N.min)-parseFloat(D)}}}}if(A.options.ymax!=null){u=N.series_u2p(A.options.ymax)}else{if(q!=null){if(d.type(q)=="number"){u=N.series_u2p(N.max+q)}else{if(d.type(q)=="string"){u=N.series_u2p(N.max)+parseFloat(q)}}}}if(L!=null&&S!=null&&u!=null&&n!=null){A.gridStart=[S,n];A.gridStop=[L,u];this.canvas._ctx.fillStyle=A.options.color;this.canvas._ctx.fillRect(S,n,L-S,u-n)}break;default:break}}}}};d.jqplot.CanvasOverlay.postPlotDraw=function(){var o=this.plugins.canvasOverlay;if(o&&o.highlightCanvas){o.highlightCanvas.resetCanvas();o.highlightCanvas=null}o.canvas=new d.jqplot.GenericCanvas();this.eventCanvas._elem.before(o.canvas.createElement(this._gridPadding,"jqplot-overlayCanvas-canvas",this._plotDimensions,this));o.canvas.setContext();if(!o.deferDraw){o.draw(this)}var n=document.createElement("div");o._tooltipElem=d(n);n=null;o._tooltipElem.addClass("jqplot-canvasOverlay-tooltip");o._tooltipElem.css({position:"absolute",display:"none"});this.eventCanvas._elem.before(o._tooltipElem);this.eventCanvas._elem.bind("mouseleave",{elem:o._tooltipElem},function(p){p.data.elem.hide()});var o=null};function k(s,q,r,p){var u=s.plugins.canvasOverlay;var o=u._tooltipElem;var n=q.options,v,t;o.html(d.jqplot.sprintf(n.tooltipFormatString,p[0],p[1]));switch(n.tooltipLocation){case"nw":v=r[0]+s._gridPadding.left-o.outerWidth(true)-n.tooltipOffset;t=r[1]+s._gridPadding.top-n.tooltipOffset-o.outerHeight(true);break;case"n":v=r[0]+s._gridPadding.left-o.outerWidth(true)/2;t=r[1]+s._gridPadding.top-n.tooltipOffset-o.outerHeight(true);break;case"ne":v=r[0]+s._gridPadding.left+n.tooltipOffset;t=r[1]+s._gridPadding.top-n.tooltipOffset-o.outerHeight(true);break;case"e":v=r[0]+s._gridPadding.left+n.tooltipOffset;t=r[1]+s._gridPadding.top-o.outerHeight(true)/2;break;case"se":v=r[0]+s._gridPadding.left+n.tooltipOffset;t=r[1]+s._gridPadding.top+n.tooltipOffset;break;case"s":v=r[0]+s._gridPadding.left-o.outerWidth(true)/2;t=r[1]+s._gridPadding.top+n.tooltipOffset;break;case"sw":v=r[0]+s._gridPadding.left-o.outerWidth(true)-n.tooltipOffset;t=r[1]+s._gridPadding.top+n.tooltipOffset;break;case"w":v=r[0]+s._gridPadding.left-o.outerWidth(true)-n.tooltipOffset;t=r[1]+s._gridPadding.top-o.outerHeight(true)/2;break;default:v=r[0]+s._gridPadding.left-o.outerWidth(true)-n.tooltipOffset;t=r[1]+s._gridPadding.top-n.tooltipOffset-o.outerHeight(true);break}o.css("left",v);o.css("top",t);if(n.fadeTooltip){o.stop(true,true).fadeIn(n.tooltipFadeSpeed)}else{o.show()}o=null}function h(z,q,s,p){var o=z[0];var n=z[1];var y=Math.round(s[0]);var x=Math.round(s[1]);var u=Math.round(q[0]);var t=Math.round(q[1]);var r=Math.sqrt(Math.pow(y-u,2)+Math.pow(x-t,2));var A=p*r;var w=Math.abs((u-y)*(n-x)-(t-x)*(o-y));var v=(w<A)?true:false;return v}function g(x,q,r,p){var o=x[0];var n=x[1];var w=Math.round(r[0]);var v=Math.round(r[1]);var t=Math.round(q[0]);var s=Math.round(q[1]);var y;if(w>t){y=w;w=t;t=y}if(v>s){y=v;v=s;s=y}var u=(o>=w&&o<=t&&n>=v&&n<=s);return u}function a(z,w,r,A,x){var y=x.plugins.canvasOverlay;var v=y.objects;var s=v.length;var u,o=false;var q;for(var t=0;t<s;t++){u=v[t];if(u.options.showTooltip){var p;if(u.type==="rectangle"){p=g([w.x,w.y],u.gridStart,u.gridStop,u.tooltipWidthFactor)}else{p=h([w.x,w.y],u.gridStart,u.gridStop,u.tooltipWidthFactor)}r=[x.axes[u.options.xaxis].series_p2u(w.x),x.axes[u.options.yaxis].series_p2u(w.y)];if(p&&y.highlightObjectIndex==null){switch(u.type){case"line":k(x,u,[w.x,w.y],r);break;case"horizontalLine":case"dashedHorizontalLine":k(x,u,[w.x,u.gridStart[1]],[r[0],u.options.y]);break;case"verticalLine":case"dashedVerticalLine":k(x,u,[u.gridStart[0],w.y],[u.options.x,r[1]]);break;case"rectangle":k(x,u,[u.gridStart[0],w.y],[u.options.x,r[1]]);break;default:break}y.highlightObjectIndex=t;o=true;break}else{if(p&&y.highlightObjectIndex!==t){q=y._tooltipElem;if(u.fadeTooltip){q.fadeOut(u.tooltipFadeSpeed)}else{q.hide()}switch(u.type){case"line":k(x,u,[w.x,w.y],r);break;case"horizontalLine":case"dashedHorizontalLine":k(x,u,[w.x,u.gridStart[1]],[r[0],u.options.y]);break;case"verticalLine":case"dashedVerticalLine":k(x,u,[u.gridStart[0],w.y],[u.options.x,r[1]]);break;case"rectangle":k(x,u,[u.gridStart[0],w.y],[u.options.x,r[1]]);break;default:break}y.highlightObjectIndex=t;o=true;break}else{if(p){switch(u.type){case"line":k(x,u,[w.x,w.y],r);break;case"horizontalLine":case"dashedHorizontalLine":k(x,u,[w.x,u.gridStart[1]],[r[0],u.options.y]);break;case"verticalLine":case"dashedVerticalLine":k(x,u,[u.gridStart[0],w.y],[u.options.x,r[1]]);break;case"rectangle":k(x,u,[u.gridStart[0],w.y],[u.options.x,r[1]]);break;default:break}o=true;break}}}}}if(!o&&y.highlightObjectIndex!==null){q=y._tooltipElem;u=y.getObject(y.highlightObjectIndex);if(u.fadeTooltip){q.fadeOut(u.tooltipFadeSpeed)}else{q.hide()}y.highlightObjectIndex=null}}d.jqplot.postInitHooks.push(d.jqplot.CanvasOverlay.postPlotInit);d.jqplot.postDrawHooks.push(d.jqplot.CanvasOverlay.postPlotDraw);d.jqplot.eventListenerHooks.push(["jqplotMouseMove",a])})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.canvasTextRenderer.js b/plugin/jqplot/plugins/jqplot.canvasTextRenderer.js new file mode 100644 index 000000000..dc8434ee2 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.canvasTextRenderer.js @@ -0,0 +1,449 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + * included jsDate library by Chris Leonello: + * + * Copyright (c) 2010-2013 Chris Leonello + * + * jsDate is currently available for use in all personal or commercial projects + * under both the MIT and GPL version 2.0 licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * jsDate borrows many concepts and ideas from the Date Instance + * Methods by Ken Snyder along with some parts of Ken's actual code. + * + * Ken's original Date Instance Methods and copyright notice: + * + * Ken Snyder (ken d snyder at gmail dot com) + * 2008-09-10 + * version 2.0.2 (http://kendsnyder.com/sandbox/date/) + * Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/) + * + * jqplotToImage function based on Larry Siden's export-jqplot-to-png.js. + * Larry has generously given permission to adapt his code for inclusion + * into jqPlot. + * + * Larry's original code can be found here: + * + * https://github.com/lsiden/export-jqplot-to-png + * + * + */ + +(function($) { + // This code is a modified version of the canvastext.js code, copyright below: + // + // This code is released to the public domain by Jim Studt, 2007. + // He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/ + // + $.jqplot.CanvasTextRenderer = function(options){ + this.fontStyle = 'normal'; // normal, italic, oblique [not implemented] + this.fontVariant = 'normal'; // normal, small caps [not implemented] + this.fontWeight = 'normal'; // normal, bold, bolder, lighter, 100 - 900 + this.fontSize = '10px'; + this.fontFamily = 'sans-serif'; + this.fontStretch = 1.0; + this.fillStyle = '#666666'; + this.angle = 0; + this.textAlign = 'start'; + this.textBaseline = 'alphabetic'; + this.text; + this.width; + this.height; + this.pt2px = 1.28; + + $.extend(true, this, options); + this.normalizedFontSize = this.normalizeFontSize(this.fontSize); + this.setHeight(); + }; + + $.jqplot.CanvasTextRenderer.prototype.init = function(options) { + $.extend(true, this, options); + this.normalizedFontSize = this.normalizeFontSize(this.fontSize); + this.setHeight(); + }; + + // convert css spec into point size + // returns float + $.jqplot.CanvasTextRenderer.prototype.normalizeFontSize = function(sz) { + sz = String(sz); + var n = parseFloat(sz); + if (sz.indexOf('px') > -1) { + return n/this.pt2px; + } + else if (sz.indexOf('pt') > -1) { + return n; + } + else if (sz.indexOf('em') > -1) { + return n*12; + } + else if (sz.indexOf('%') > -1) { + return n*12/100; + } + // default to pixels; + else { + return n/this.pt2px; + } + }; + + + $.jqplot.CanvasTextRenderer.prototype.fontWeight2Float = function(w) { + // w = normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 + // return values adjusted for Hershey font. + if (Number(w)) { + return w/400; + } + else { + switch (w) { + case 'normal': + return 1; + break; + case 'bold': + return 1.75; + break; + case 'bolder': + return 2.25; + break; + case 'lighter': + return 0.75; + break; + default: + return 1; + break; + } + } + }; + + $.jqplot.CanvasTextRenderer.prototype.getText = function() { + return this.text; + }; + + $.jqplot.CanvasTextRenderer.prototype.setText = function(t, ctx) { + this.text = t; + this.setWidth(ctx); + return this; + }; + + $.jqplot.CanvasTextRenderer.prototype.getWidth = function(ctx) { + return this.width; + }; + + $.jqplot.CanvasTextRenderer.prototype.setWidth = function(ctx, w) { + if (!w) { + this.width = this.measure(ctx, this.text); + } + else { + this.width = w; + } + return this; + }; + + // return height in pixels. + $.jqplot.CanvasTextRenderer.prototype.getHeight = function(ctx) { + return this.height; + }; + + // w - height in pt + // set heigh in px + $.jqplot.CanvasTextRenderer.prototype.setHeight = function(w) { + if (!w) { + //height = this.fontSize /0.75; + this.height = this.normalizedFontSize * this.pt2px; + } + else { + this.height = w; + } + return this; + }; + + $.jqplot.CanvasTextRenderer.prototype.letter = function (ch) + { + return this.letters[ch]; + }; + + $.jqplot.CanvasTextRenderer.prototype.ascent = function() + { + return this.normalizedFontSize; + }; + + $.jqplot.CanvasTextRenderer.prototype.descent = function() + { + return 7.0*this.normalizedFontSize/25.0; + }; + + $.jqplot.CanvasTextRenderer.prototype.measure = function(ctx, str) + { + var total = 0; + var len = str.length; + + for (var i = 0; i < len; i++) { + var c = this.letter(str.charAt(i)); + if (c) { + total += c.width * this.normalizedFontSize / 25.0 * this.fontStretch; + } + } + return total; + }; + + $.jqplot.CanvasTextRenderer.prototype.draw = function(ctx,str) + { + var x = 0; + // leave room at bottom for descenders. + var y = this.height*0.72; + var total = 0; + var len = str.length; + var mag = this.normalizedFontSize / 25.0; + + ctx.save(); + var tx, ty; + + // 1st quadrant + if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) { + tx = 0; + ty = -Math.sin(this.angle) * this.width; + } + // 4th quadrant + else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) { + tx = Math.sin(this.angle) * this.height; + ty = 0; + } + // 2nd quadrant + else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) { + tx = -Math.cos(this.angle) * this.width; + ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height; + } + // 3rd quadrant + else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) { + tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width; + ty = -Math.cos(this.angle) * this.height; + } + + ctx.strokeStyle = this.fillStyle; + ctx.fillStyle = this.fillStyle; + ctx.translate(tx, ty); + ctx.rotate(this.angle); + ctx.lineCap = "round"; + // multiplier was 2.0 + var fact = (this.normalizedFontSize > 30) ? 2.0 : 2 + (30 - this.normalizedFontSize)/20; + ctx.lineWidth = fact * mag * this.fontWeight2Float(this.fontWeight); + + for ( var i = 0; i < len; i++) { + var c = this.letter( str.charAt(i)); + if ( !c) { + continue; + } + + ctx.beginPath(); + + var penUp = 1; + var needStroke = 0; + for ( var j = 0; j < c.points.length; j++) { + var a = c.points[j]; + if ( a[0] == -1 && a[1] == -1) { + penUp = 1; + continue; + } + if ( penUp) { + ctx.moveTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag); + penUp = false; + } else { + ctx.lineTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag); + } + } + ctx.stroke(); + x += c.width*mag*this.fontStretch; + } + ctx.restore(); + return total; + }; + + $.jqplot.CanvasTextRenderer.prototype.letters = { + ' ': { width: 16, points: [] }, + '!': { width: 10, points: [[5,21],[5,7],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] }, + '"': { width: 16, points: [[4,21],[4,14],[-1,-1],[12,21],[12,14]] }, + '#': { width: 21, points: [[11,25],[4,-7],[-1,-1],[17,25],[10,-7],[-1,-1],[4,12],[18,12],[-1,-1],[3,6],[17,6]] }, + '$': { width: 20, points: [[8,25],[8,-4],[-1,-1],[12,25],[12,-4],[-1,-1],[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] }, + '%': { width: 24, points: [[21,21],[3,0],[-1,-1],[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],[10,20],[13,19],[16,19],[19,20],[21,21],[-1,-1],[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] }, + '&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] }, + '\'': { width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] }, + '(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] }, + ')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] }, + '*': { width: 16, points: [[8,21],[8,9],[-1,-1],[3,18],[13,12],[-1,-1],[13,18],[3,12]] }, + '+': { width: 26, points: [[13,18],[13,0],[-1,-1],[4,9],[22,9]] }, + ',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] }, + '-': { width: 18, points: [[6,9],[12,9]] }, + '.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] }, + '/': { width: 22, points: [[20,25],[2,-7]] }, + '0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] }, + '1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] }, + '2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] }, + '3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] }, + '4': { width: 20, points: [[13,21],[3,7],[18,7],[-1,-1],[13,21],[13,0]] }, + '5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] }, + '6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] }, + '7': { width: 20, points: [[17,21],[7,0],[-1,-1],[3,21],[17,21]] }, + '8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] }, + '9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] }, + ':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] }, + ';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] }, + '<': { width: 24, points: [[20,18],[4,9],[20,0]] }, + '=': { width: 26, points: [[4,12],[22,12],[-1,-1],[4,6],[22,6]] }, + '>': { width: 24, points: [[4,18],[20,9],[4,0]] }, + '?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]] }, + '@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]] }, + 'A': { width: 18, points: [[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]] }, + 'B': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] }, + 'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] }, + 'D': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] }, + 'E': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]] }, + 'F': { width: 18, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]] }, + 'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]] }, + 'H': { width: 22, points: [[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]] }, + 'I': { width: 8, points: [[4,21],[4,0]] }, + 'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] }, + 'K': { width: 21, points: [[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]] }, + 'L': { width: 17, points: [[4,21],[4,0],[-1,-1],[4,0],[16,0]] }, + 'M': { width: 24, points: [[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]] }, + 'N': { width: 22, points: [[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]] }, + 'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] }, + 'P': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] }, + 'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]] }, + 'R': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]] }, + 'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] }, + 'T': { width: 16, points: [[8,21],[8,0],[-1,-1],[1,21],[15,21]] }, + 'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] }, + 'V': { width: 18, points: [[1,21],[9,0],[-1,-1],[17,21],[9,0]] }, + 'W': { width: 24, points: [[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]] }, + 'X': { width: 20, points: [[3,21],[17,0],[-1,-1],[17,21],[3,0]] }, + 'Y': { width: 18, points: [[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]] }, + 'Z': { width: 20, points: [[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]] }, + '[': { width: 14, points: [[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]] }, + '\\': { width: 14, points: [[0,21],[14,-3]] }, + ']': { width: 14, points: [[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]] }, + '^': { width: 16, points: [[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]] }, + '_': { width: 16, points: [[0,-2],[16,-2]] }, + '`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] }, + 'a': { width: 19, points: [[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] }, + 'b': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] }, + 'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] }, + 'd': { width: 19, points: [[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] }, + 'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] }, + 'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]] }, + 'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] }, + 'h': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] }, + 'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]] }, + 'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] }, + 'k': { width: 17, points: [[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]] }, + 'l': { width: 8, points: [[4,21],[4,0]] }, + 'm': { width: 30, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] }, + 'n': { width: 19, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] }, + 'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] }, + 'p': { width: 19, points: [[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] }, + 'q': { width: 19, points: [[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] }, + 'r': { width: 13, points: [[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]] }, + 's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] }, + 't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]] }, + 'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]] }, + 'v': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0]] }, + 'w': { width: 22, points: [[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]] }, + 'x': { width: 17, points: [[3,14],[14,0],[-1,-1],[14,14],[3,0]] }, + 'y': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] }, + 'z': { width: 17, points: [[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]] }, + '{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] }, + '|': { width: 8, points: [[4,25],[4,-7]] }, + '}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] }, + '~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] } + }; + + $.jqplot.CanvasFontRenderer = function(options) { + options = options || {}; + if (!options.pt2px) { + options.pt2px = 1.5; + } + $.jqplot.CanvasTextRenderer.call(this, options); + }; + + $.jqplot.CanvasFontRenderer.prototype = new $.jqplot.CanvasTextRenderer({}); + $.jqplot.CanvasFontRenderer.prototype.constructor = $.jqplot.CanvasFontRenderer; + + $.jqplot.CanvasFontRenderer.prototype.measure = function(ctx, str) + { + // var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily; + var fstyle = this.fontSize+' '+this.fontFamily; + ctx.save(); + ctx.font = fstyle; + var w = ctx.measureText(str).width; + ctx.restore(); + return w; + }; + + $.jqplot.CanvasFontRenderer.prototype.draw = function(ctx, str) + { + var x = 0; + // leave room at bottom for descenders. + var y = this.height*0.72; + //var y = 12; + + ctx.save(); + var tx, ty; + + // 1st quadrant + if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) { + tx = 0; + ty = -Math.sin(this.angle) * this.width; + } + // 4th quadrant + else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) { + tx = Math.sin(this.angle) * this.height; + ty = 0; + } + // 2nd quadrant + else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) { + tx = -Math.cos(this.angle) * this.width; + ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height; + } + // 3rd quadrant + else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) { + tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width; + ty = -Math.cos(this.angle) * this.height; + } + ctx.strokeStyle = this.fillStyle; + ctx.fillStyle = this.fillStyle; + // var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily; + var fstyle = this.fontSize+' '+this.fontFamily; + ctx.font = fstyle; + ctx.translate(tx, ty); + ctx.rotate(this.angle); + ctx.fillText(str, x, y); + // ctx.strokeText(str, x, y); + + ctx.restore(); + }; + +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.canvasTextRenderer.min.js b/plugin/jqplot/plugins/jqplot.canvasTextRenderer.min.js new file mode 100644 index 000000000..90199dd1b --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.canvasTextRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.CanvasTextRenderer=function(b){this.fontStyle="normal";this.fontVariant="normal";this.fontWeight="normal";this.fontSize="10px";this.fontFamily="sans-serif";this.fontStretch=1;this.fillStyle="#666666";this.angle=0;this.textAlign="start";this.textBaseline="alphabetic";this.text;this.width;this.height;this.pt2px=1.28;a.extend(true,this,b);this.normalizedFontSize=this.normalizeFontSize(this.fontSize);this.setHeight()};a.jqplot.CanvasTextRenderer.prototype.init=function(b){a.extend(true,this,b);this.normalizedFontSize=this.normalizeFontSize(this.fontSize);this.setHeight()};a.jqplot.CanvasTextRenderer.prototype.normalizeFontSize=function(b){b=String(b);var c=parseFloat(b);if(b.indexOf("px")>-1){return c/this.pt2px}else{if(b.indexOf("pt")>-1){return c}else{if(b.indexOf("em")>-1){return c*12}else{if(b.indexOf("%")>-1){return c*12/100}else{return c/this.pt2px}}}}};a.jqplot.CanvasTextRenderer.prototype.fontWeight2Float=function(b){if(Number(b)){return b/400}else{switch(b){case"normal":return 1;break;case"bold":return 1.75;break;case"bolder":return 2.25;break;case"lighter":return 0.75;break;default:return 1;break}}};a.jqplot.CanvasTextRenderer.prototype.getText=function(){return this.text};a.jqplot.CanvasTextRenderer.prototype.setText=function(c,b){this.text=c;this.setWidth(b);return this};a.jqplot.CanvasTextRenderer.prototype.getWidth=function(b){return this.width};a.jqplot.CanvasTextRenderer.prototype.setWidth=function(c,b){if(!b){this.width=this.measure(c,this.text)}else{this.width=b}return this};a.jqplot.CanvasTextRenderer.prototype.getHeight=function(b){return this.height};a.jqplot.CanvasTextRenderer.prototype.setHeight=function(b){if(!b){this.height=this.normalizedFontSize*this.pt2px}else{this.height=b}return this};a.jqplot.CanvasTextRenderer.prototype.letter=function(b){return this.letters[b]};a.jqplot.CanvasTextRenderer.prototype.ascent=function(){return this.normalizedFontSize};a.jqplot.CanvasTextRenderer.prototype.descent=function(){return 7*this.normalizedFontSize/25};a.jqplot.CanvasTextRenderer.prototype.measure=function(d,g){var f=0;var b=g.length;for(var e=0;e<b;e++){var h=this.letter(g.charAt(e));if(h){f+=h.width*this.normalizedFontSize/25*this.fontStretch}}return f};a.jqplot.CanvasTextRenderer.prototype.draw=function(s,n){var r=0;var o=this.height*0.72;var p=0;var l=n.length;var k=this.normalizedFontSize/25;s.save();var h,f;if((-Math.PI/2<=this.angle&&this.angle<=0)||(Math.PI*3/2<=this.angle&&this.angle<=Math.PI*2)){h=0;f=-Math.sin(this.angle)*this.width}else{if((0<this.angle&&this.angle<=Math.PI/2)||(-Math.PI*2<=this.angle&&this.angle<=-Math.PI*3/2)){h=Math.sin(this.angle)*this.height;f=0}else{if((-Math.PI<this.angle&&this.angle<-Math.PI/2)||(Math.PI<=this.angle&&this.angle<=Math.PI*3/2)){h=-Math.cos(this.angle)*this.width;f=-Math.sin(this.angle)*this.width-Math.cos(this.angle)*this.height}else{if((-Math.PI*3/2<this.angle&&this.angle<Math.PI)||(Math.PI/2<this.angle&&this.angle<Math.PI)){h=Math.sin(this.angle)*this.height-Math.cos(this.angle)*this.width;f=-Math.cos(this.angle)*this.height}}}}s.strokeStyle=this.fillStyle;s.fillStyle=this.fillStyle;s.translate(h,f);s.rotate(this.angle);s.lineCap="round";var t=(this.normalizedFontSize>30)?2:2+(30-this.normalizedFontSize)/20;s.lineWidth=t*k*this.fontWeight2Float(this.fontWeight);for(var g=0;g<l;g++){var m=this.letter(n.charAt(g));if(!m){continue}s.beginPath();var e=1;var b=0;for(var d=0;d<m.points.length;d++){var q=m.points[d];if(q[0]==-1&&q[1]==-1){e=1;continue}if(e){s.moveTo(r+q[0]*k*this.fontStretch,o-q[1]*k);e=false}else{s.lineTo(r+q[0]*k*this.fontStretch,o-q[1]*k)}}s.stroke();r+=m.width*k*this.fontStretch}s.restore();return p};a.jqplot.CanvasTextRenderer.prototype.letters={" ":{width:16,points:[]},"!":{width:10,points:[[5,21],[5,7],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]]},'"':{width:16,points:[[4,21],[4,14],[-1,-1],[12,21],[12,14]]},"#":{width:21,points:[[11,25],[4,-7],[-1,-1],[17,25],[10,-7],[-1,-1],[4,12],[18,12],[-1,-1],[3,6],[17,6]]},"$":{width:20,points:[[8,25],[8,-4],[-1,-1],[12,25],[12,-4],[-1,-1],[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]]},"%":{width:24,points:[[21,21],[3,0],[-1,-1],[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],[10,20],[13,19],[16,19],[19,20],[21,21],[-1,-1],[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]]},"&":{width:26,points:[[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]]},"'":{width:10,points:[[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]]},"(":{width:14,points:[[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]]},")":{width:14,points:[[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]]},"*":{width:16,points:[[8,21],[8,9],[-1,-1],[3,18],[13,12],[-1,-1],[13,18],[3,12]]},"+":{width:26,points:[[13,18],[13,0],[-1,-1],[4,9],[22,9]]},",":{width:10,points:[[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]]},"-":{width:18,points:[[6,9],[12,9]]},".":{width:10,points:[[5,2],[4,1],[5,0],[6,1],[5,2]]},"/":{width:22,points:[[20,25],[2,-7]]},"0":{width:20,points:[[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]]},"1":{width:20,points:[[6,17],[8,18],[11,21],[11,0]]},"2":{width:20,points:[[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]]},"3":{width:20,points:[[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]]},"4":{width:20,points:[[13,21],[3,7],[18,7],[-1,-1],[13,21],[13,0]]},"5":{width:20,points:[[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]]},"6":{width:20,points:[[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]]},"7":{width:20,points:[[17,21],[7,0],[-1,-1],[3,21],[17,21]]},"8":{width:20,points:[[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]]},"9":{width:20,points:[[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]]},":":{width:10,points:[[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]]},";":{width:10,points:[[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]]},"<":{width:24,points:[[20,18],[4,9],[20,0]]},"=":{width:26,points:[[4,12],[22,12],[-1,-1],[4,6],[22,6]]},">":{width:24,points:[[4,18],[20,9],[4,0]]},"?":{width:18,points:[[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]]},"@":{width:27,points:[[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]]},A:{width:18,points:[[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]]},B:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]]},C:{width:21,points:[[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]]},D:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]]},E:{width:19,points:[[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]]},F:{width:18,points:[[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]]},G:{width:21,points:[[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]]},H:{width:22,points:[[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]]},I:{width:8,points:[[4,21],[4,0]]},J:{width:16,points:[[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]]},K:{width:21,points:[[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]]},L:{width:17,points:[[4,21],[4,0],[-1,-1],[4,0],[16,0]]},M:{width:24,points:[[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]]},N:{width:22,points:[[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]]},O:{width:22,points:[[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]]},P:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]]},Q:{width:22,points:[[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]]},R:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]]},S:{width:20,points:[[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]]},T:{width:16,points:[[8,21],[8,0],[-1,-1],[1,21],[15,21]]},U:{width:22,points:[[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]]},V:{width:18,points:[[1,21],[9,0],[-1,-1],[17,21],[9,0]]},W:{width:24,points:[[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]]},X:{width:20,points:[[3,21],[17,0],[-1,-1],[17,21],[3,0]]},Y:{width:18,points:[[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]]},Z:{width:20,points:[[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]]},"[":{width:14,points:[[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]]},"\\":{width:14,points:[[0,21],[14,-3]]},"]":{width:14,points:[[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]]},"^":{width:16,points:[[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]]},_:{width:16,points:[[0,-2],[16,-2]]},"`":{width:10,points:[[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]]},a:{width:19,points:[[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},b:{width:19,points:[[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]]},c:{width:18,points:[[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},d:{width:19,points:[[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},e:{width:18,points:[[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},f:{width:12,points:[[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]]},g:{width:19,points:[[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},h:{width:19,points:[[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]]},i:{width:8,points:[[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]]},j:{width:10,points:[[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]]},k:{width:17,points:[[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]]},l:{width:8,points:[[4,21],[4,0]]},m:{width:30,points:[[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]]},n:{width:19,points:[[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]]},o:{width:19,points:[[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]]},p:{width:19,points:[[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]]},q:{width:19,points:[[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},r:{width:13,points:[[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]]},s:{width:17,points:[[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]]},t:{width:12,points:[[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]]},u:{width:19,points:[[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]]},v:{width:16,points:[[2,14],[8,0],[-1,-1],[14,14],[8,0]]},w:{width:22,points:[[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]]},x:{width:17,points:[[3,14],[14,0],[-1,-1],[14,14],[3,0]]},y:{width:16,points:[[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]]},z:{width:17,points:[[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]]},"{":{width:14,points:[[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]]},"|":{width:8,points:[[4,25],[4,-7]]},"}":{width:14,points:[[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]]},"~":{width:24,points:[[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]]}};a.jqplot.CanvasFontRenderer=function(b){b=b||{};if(!b.pt2px){b.pt2px=1.5}a.jqplot.CanvasTextRenderer.call(this,b)};a.jqplot.CanvasFontRenderer.prototype=new a.jqplot.CanvasTextRenderer({});a.jqplot.CanvasFontRenderer.prototype.constructor=a.jqplot.CanvasFontRenderer;a.jqplot.CanvasFontRenderer.prototype.measure=function(c,e){var d=this.fontSize+" "+this.fontFamily;c.save();c.font=d;var b=c.measureText(e).width;c.restore();return b};a.jqplot.CanvasFontRenderer.prototype.draw=function(e,g){var c=0;var h=this.height*0.72;e.save();var d,b;if((-Math.PI/2<=this.angle&&this.angle<=0)||(Math.PI*3/2<=this.angle&&this.angle<=Math.PI*2)){d=0;b=-Math.sin(this.angle)*this.width}else{if((0<this.angle&&this.angle<=Math.PI/2)||(-Math.PI*2<=this.angle&&this.angle<=-Math.PI*3/2)){d=Math.sin(this.angle)*this.height;b=0}else{if((-Math.PI<this.angle&&this.angle<-Math.PI/2)||(Math.PI<=this.angle&&this.angle<=Math.PI*3/2)){d=-Math.cos(this.angle)*this.width;b=-Math.sin(this.angle)*this.width-Math.cos(this.angle)*this.height}else{if((-Math.PI*3/2<this.angle&&this.angle<Math.PI)||(Math.PI/2<this.angle&&this.angle<Math.PI)){d=Math.sin(this.angle)*this.height-Math.cos(this.angle)*this.width;b=-Math.cos(this.angle)*this.height}}}}e.strokeStyle=this.fillStyle;e.fillStyle=this.fillStyle;var f=this.fontSize+" "+this.fontFamily;e.font=f;e.translate(d,b);e.rotate(this.angle);e.fillText(g,c,h);e.restore()}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.categoryAxisRenderer.js b/plugin/jqplot/plugins/jqplot.categoryAxisRenderer.js new file mode 100644 index 000000000..aa7712033 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.categoryAxisRenderer.js @@ -0,0 +1,679 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * class: $.jqplot.CategoryAxisRenderer + * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series. + * + * To use this renderer, include the plugin in your source + * > <script type="text/javascript" language="javascript" src="plugins/jqplot.categoryAxisRenderer.js"></script> + * + * and supply the appropriate options to your plot + * + * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}} + **/ + $.jqplot.CategoryAxisRenderer = function(options) { + $.jqplot.LinearAxisRenderer.call(this); + // prop: sortMergedLabels + // True to sort tick labels when labels are created by merging + // x axis values from multiple series. That is, say you have + // two series like: + // > line1 = [[2006, 4], [2008, 9], [2009, 16]]; + // > line2 = [[2006, 3], [2007, 7], [2008, 6]]; + // If no label array is specified, tick labels will be collected + // from the x values of the series. With sortMergedLabels + // set to true, tick labels will be: + // > [2006, 2007, 2008, 2009] + // With sortMergedLabels set to false, tick labels will be: + // > [2006, 2008, 2009, 2007] + // + // Note, this property is specified on the renderOptions for the + // axes when creating a plot: + // > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}} + this.sortMergedLabels = false; + }; + + $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer; + + $.jqplot.CategoryAxisRenderer.prototype.init = function(options){ + this.groups = 1; + this.groupLabels = []; + this._groupLabels = []; + this._grouped = false; + this._barsPerGroup = null; + this.reverse = false; + // prop: tickRenderer + // A class of a rendering engine for creating the ticks labels displayed on the plot, + // See <$.jqplot.AxisTickRenderer>. + // this.tickRenderer = $.jqplot.AxisTickRenderer; + // this.labelRenderer = $.jqplot.AxisLabelRenderer; + $.extend(true, this, {tickOptions:{formatString:'%d'}}, options); + var db = this._dataBounds; + // Go through all the series attached to this axis and find + // the min/max bounds for this axis. + for (var i=0; i<this._series.length; i++) { + var s = this._series[i]; + if (s.groups) { + this.groups = s.groups; + } + var d = s.data; + + for (var j=0; j<d.length; j++) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + if (d[j][0] < db.min || db.min == null) { + db.min = d[j][0]; + } + if (d[j][0] > db.max || db.max == null) { + db.max = d[j][0]; + } + } + else { + if (d[j][1] < db.min || db.min == null) { + db.min = d[j][1]; + } + if (d[j][1] > db.max || db.max == null) { + db.max = d[j][1]; + } + } + } + } + + if (this.groupLabels.length) { + this.groups = this.groupLabels.length; + } + }; + + + $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() { + // we're are operating on an axis here + var ticks = this._ticks; + var userTicks = this.ticks; + var name = this.name; + // databounds were set on axis initialization. + var db = this._dataBounds; + var dim, interval; + var min, max; + var pos1, pos2; + var tt, i; + + // if we already have ticks, use them. + if (userTicks.length) { + // adjust with blanks if we have groups + if (this.groups > 1 && !this._grouped) { + var l = userTicks.length; + var skip = parseInt(l/this.groups, 10); + var count = 0; + for (var i=skip; i<l; i+=skip) { + userTicks.splice(i+count, 0, ' '); + count++; + } + this._grouped = true; + } + this.min = 0.5; + this.max = userTicks.length + 0.5; + var range = this.max - this.min; + this.numberTicks = 2*userTicks.length + 1; + for (i=0; i<userTicks.length; i++){ + tt = this.min + 2 * i * range / (this.numberTicks-1); + // need a marker before and after the tick + var t = new this.tickRenderer(this.tickOptions); + t.showLabel = false; + // t.showMark = true; + t.setTick(tt, this.name); + this._ticks.push(t); + var t = new this.tickRenderer(this.tickOptions); + t.label = userTicks[i]; + // t.showLabel = true; + t.showMark = false; + t.showGridline = false; + t.setTick(tt+0.5, this.name); + this._ticks.push(t); + } + // now add the last tick at the end + var t = new this.tickRenderer(this.tickOptions); + t.showLabel = false; + // t.showMark = true; + t.setTick(tt+1, this.name); + this._ticks.push(t); + } + + // we don't have any ticks yet, let's make some! + else { + if (name == 'xaxis' || name == 'x2axis') { + dim = this._plotDimensions.width; + } + else { + dim = this._plotDimensions.height; + } + + // if min, max and number of ticks specified, user can't specify interval. + if (this.min != null && this.max != null && this.numberTicks != null) { + this.tickInterval = null; + } + + // if max, min, and interval specified and interval won't fit, ignore interval. + if (this.min != null && this.max != null && this.tickInterval != null) { + if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) { + this.tickInterval = null; + } + } + + // find out how many categories are in the lines and collect labels + var labels = []; + var numcats = 0; + var min = 0.5; + var max, val; + var isMerged = false; + for (var i=0; i<this._series.length; i++) { + var s = this._series[i]; + for (var j=0; j<s.data.length; j++) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + val = s.data[j][0]; + } + else { + val = s.data[j][1]; + } + if ($.inArray(val, labels) == -1) { + isMerged = true; + numcats += 1; + labels.push(val); + } + } + } + + if (isMerged && this.sortMergedLabels) { + if (typeof labels[0] == "string") { + labels.sort(); + } else { + labels.sort(function(a,b) { return a - b; }); + } + } + + // keep a reference to these tick labels to use for redrawing plot (see bug #57) + this.ticks = labels; + + // now bin the data values to the right lables. + for (var i=0; i<this._series.length; i++) { + var s = this._series[i]; + for (var j=0; j<s.data.length; j++) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + val = s.data[j][0]; + } + else { + val = s.data[j][1]; + } + // for category axis, force the values into category bins. + // we should have the value in the label array now. + var idx = $.inArray(val, labels)+1; + if (this.name == 'xaxis' || this.name == 'x2axis') { + s.data[j][0] = idx; + } + else { + s.data[j][1] = idx; + } + } + } + + // adjust with blanks if we have groups + if (this.groups > 1 && !this._grouped) { + var l = labels.length; + var skip = parseInt(l/this.groups, 10); + var count = 0; + for (var i=skip; i<l; i+=skip+1) { + labels[i] = ' '; + } + this._grouped = true; + } + + max = numcats + 0.5; + if (this.numberTicks == null) { + this.numberTicks = 2*numcats + 1; + } + + var range = max - min; + this.min = min; + this.max = max; + var track = 0; + + // todo: adjust this so more ticks displayed. + var maxVisibleTicks = parseInt(3+dim/10, 10); + var skip = parseInt(numcats/maxVisibleTicks, 10); + + if (this.tickInterval == null) { + + this.tickInterval = range / (this.numberTicks-1); + + } + // if tickInterval is specified, we will ignore any computed maximum. + for (var i=0; i<this.numberTicks; i++){ + tt = this.min + i * this.tickInterval; + var t = new this.tickRenderer(this.tickOptions); + // if even tick, it isn't a category, it's a divider + if (i/2 == parseInt(i/2, 10)) { + t.showLabel = false; + t.showMark = true; + } + else { + if (skip>0 && track<skip) { + t.showLabel = false; + track += 1; + } + else { + t.showLabel = true; + track = 0; + } + t.label = t.formatter(t.formatString, labels[(i-1)/2]); + t.showMark = false; + t.showGridline = false; + } + t.setTick(tt, this.name); + this._ticks.push(t); + } + } + + }; + + // called with scope of axis + $.jqplot.CategoryAxisRenderer.prototype.draw = function(ctx, plot) { + if (this.show) { + // populate the axis label and value properties. + // createTicks is a method on the renderer, but + // call it within the scope of the axis. + this.renderer.createTicks.call(this); + // fill a div with axes labels in the right direction. + // Need to pregenerate each axis to get its bounds and + // position it and the labels correctly on the plot. + var dim=0; + var temp; + // Added for theming. + if (this._elem) { + // this._elem.empty(); + // Memory Leaks patch + this._elem.emptyForce(); + } + + this._elem = this._elem || $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>'); + + if (this.name == 'xaxis' || this.name == 'x2axis') { + this._elem.width(this._plotDimensions.width); + } + else { + this._elem.height(this._plotDimensions.height); + } + + // create a _label object. + this.labelOptions.axis = this.name; + this._label = new this.labelRenderer(this.labelOptions); + if (this._label.show) { + var elem = this._label.draw(ctx, plot); + elem.appendTo(this._elem); + } + + var t = this._ticks; + for (var i=0; i<t.length; i++) { + var tick = t[i]; + if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { + var elem = tick.draw(ctx, plot); + elem.appendTo(this._elem); + } + } + + this._groupLabels = []; + // now make group labels + for (var i=0; i<this.groupLabels.length; i++) + { + var elem = $('<div style="position:absolute;" class="jqplot-'+this.name+'-groupLabel"></div>'); + elem.html(this.groupLabels[i]); + this._groupLabels.push(elem); + elem.appendTo(this._elem); + } + } + return this._elem; + }; + + // called with scope of axis + $.jqplot.CategoryAxisRenderer.prototype.set = function() { + var dim = 0; + var temp; + var w = 0; + var h = 0; + var lshow = (this._label == null) ? false : this._label.show; + if (this.show) { + var t = this._ticks; + for (var i=0; i<t.length; i++) { + var tick = t[i]; + if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + temp = tick._elem.outerHeight(true); + } + else { + temp = tick._elem.outerWidth(true); + } + if (temp > dim) { + dim = temp; + } + } + } + + var dim2 = 0; + for (var i=0; i<this._groupLabels.length; i++) { + var l = this._groupLabels[i]; + if (this.name == 'xaxis' || this.name == 'x2axis') { + temp = l.outerHeight(true); + } + else { + temp = l.outerWidth(true); + } + if (temp > dim2) { + dim2 = temp; + } + } + + if (lshow) { + w = this._label._elem.outerWidth(true); + h = this._label._elem.outerHeight(true); + } + if (this.name == 'xaxis') { + dim += dim2 + h; + this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); + } + else if (this.name == 'x2axis') { + dim += dim2 + h; + this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); + } + else if (this.name == 'yaxis') { + dim += dim2 + w; + this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css('width', w+'px'); + } + } + else { + dim += dim2 + w; + this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css('width', w+'px'); + } + } + } + }; + + // called with scope of axis + $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) { + var ticks = this._ticks; + var max = this.max; + var min = this.min; + var offmax = offsets.max; + var offmin = offsets.min; + var lshow = (this._label == null) ? false : this._label.show; + var i; + + for (var p in pos) { + this._elem.css(p, pos[p]); + } + + this._offsets = offsets; + // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. + var pixellength = offmax - offmin; + var unitlength = max - min; + + if (!this.reverse) { + // point to unit and unit to point conversions references to Plot DOM element top left corner. + + this.u2p = function(u){ + return (u - min) * pixellength / unitlength + offmin; + }; + + this.p2u = function(p){ + return (p - offmin) * unitlength / pixellength + min; + }; + + if (this.name == 'xaxis' || this.name == 'x2axis'){ + this.series_u2p = function(u){ + return (u - min) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + min; + }; + } + + else { + this.series_u2p = function(u){ + return (u - max) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + max; + }; + } + } + + else { + // point to unit and unit to point conversions references to Plot DOM element top left corner. + + this.u2p = function(u){ + return offmin + (max - u) * pixellength / unitlength; + }; + + this.p2u = function(p){ + return min + (p - offmin) * unitlength / pixellength; + }; + + if (this.name == 'xaxis' || this.name == 'x2axis'){ + this.series_u2p = function(u){ + return (max - u) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + max; + }; + } + + else { + this.series_u2p = function(u){ + return (min - u) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + min; + }; + } + + } + + + if (this.show) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + for (i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + // will need to adjust auto positioning based on which axis this is. + var temp = (this.name == 'xaxis') ? 1 : -1; + switch (t.labelPosition) { + case 'auto': + // position at end + if (temp * t.angle < 0) { + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + } + // position at start + else { + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + } + break; + case 'end': + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + case 'start': + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + break; + case 'middle': + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + default: + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + } + } + else { + shim = -t.getWidth()/2; + } + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('left', val); + t.pack(); + } + } + + var labeledge=['bottom', 0]; + if (lshow) { + var w = this._label._elem.outerWidth(true); + this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); + if (this.name == 'xaxis') { + this._label._elem.css('bottom', '0px'); + labeledge = ['bottom', this._label._elem.outerHeight(true)]; + } + else { + this._label._elem.css('top', '0px'); + labeledge = ['top', this._label._elem.outerHeight(true)]; + } + this._label.pack(); + } + + // draw the group labels + var step = parseInt(this._ticks.length/this.groups, 10) + 1; + for (i=0; i<this._groupLabels.length; i++) { + var mid = 0; + var count = 0; + for (var j=i*step; j<(i+1)*step; j++) { + if (j >= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one. + if (this._ticks[j]._elem && this._ticks[j].label != " ") { + var t = this._ticks[j]._elem; + var p = t.position(); + mid += p.left + t.outerWidth(true)/2; + count++; + } + } + mid = mid/count; + this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)}); + this._groupLabels[i].css(labeledge[0], labeledge[1]); + } + } + else { + for (i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + // will need to adjust auto positioning based on which axis this is. + var temp = (this.name == 'yaxis') ? 1 : -1; + switch (t.labelPosition) { + case 'auto': + // position at end + case 'end': + if (temp * t.angle < 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'start': + if (t.angle > 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'middle': + // if (t.angle > 0) { + // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + // } + // else { + // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + // } + shim = -t.getHeight()/2; + break; + default: + shim = -t.getHeight()/2; + break; + } + } + else { + shim = -t.getHeight()/2; + } + + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('top', val); + t.pack(); + } + } + + var labeledge=['left', 0]; + if (lshow) { + var h = this._label._elem.outerHeight(true); + this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); + if (this.name == 'yaxis') { + this._label._elem.css('left', '0px'); + labeledge = ['left', this._label._elem.outerWidth(true)]; + } + else { + this._label._elem.css('right', '0px'); + labeledge = ['right', this._label._elem.outerWidth(true)]; + } + this._label.pack(); + } + + // draw the group labels, position top here, do left after label position. + var step = parseInt(this._ticks.length/this.groups, 10) + 1; // step is one more than before as we don't want to have overlaps in loops + for (i=0; i<this._groupLabels.length; i++) { + var mid = 0; + var count = 0; + for (var j=i*step; j<(i+1)*step; j++) { // j must never reach (i+1)*step as we don't want to have overlap between loops + if (j >= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one. + if (this._ticks[j]._elem && this._ticks[j].label != " ") { + var t = this._ticks[j]._elem; + var p = t.position(); + mid += p.top + t.outerHeight()/2; + count++; + } + } + mid = mid/count; + this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2}); + this._groupLabels[i].css(labeledge[0], labeledge[1]); + + } + } + } + }; + + +})(jQuery); diff --git a/plugin/jqplot/plugins/jqplot.categoryAxisRenderer.min.js b/plugin/jqplot/plugins/jqplot.categoryAxisRenderer.min.js new file mode 100644 index 000000000..db61f92e3 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.categoryAxisRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.CategoryAxisRenderer=function(b){a.jqplot.LinearAxisRenderer.call(this);this.sortMergedLabels=false};a.jqplot.CategoryAxisRenderer.prototype=new a.jqplot.LinearAxisRenderer();a.jqplot.CategoryAxisRenderer.prototype.constructor=a.jqplot.CategoryAxisRenderer;a.jqplot.CategoryAxisRenderer.prototype.init=function(e){this.groups=1;this.groupLabels=[];this._groupLabels=[];this._grouped=false;this._barsPerGroup=null;this.reverse=false;a.extend(true,this,{tickOptions:{formatString:"%d"}},e);var b=this._dataBounds;for(var f=0;f<this._series.length;f++){var g=this._series[f];if(g.groups){this.groups=g.groups}var h=g.data;for(var c=0;c<h.length;c++){if(this.name=="xaxis"||this.name=="x2axis"){if(h[c][0]<b.min||b.min==null){b.min=h[c][0]}if(h[c][0]>b.max||b.max==null){b.max=h[c][0]}}else{if(h[c][1]<b.min||b.min==null){b.min=h[c][1]}if(h[c][1]>b.max||b.max==null){b.max=h[c][1]}}}}if(this.groupLabels.length){this.groups=this.groupLabels.length}};a.jqplot.CategoryAxisRenderer.prototype.createTicks=function(){var D=this._ticks;var z=this.ticks;var F=this.name;var C=this._dataBounds;var v,A;var q,w;var d,c;var b,x;if(z.length){if(this.groups>1&&!this._grouped){var r=z.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x<r;x+=p){z.splice(x+e,0," ");e++}this._grouped=true}this.min=0.5;this.max=z.length+0.5;var m=this.max-this.min;this.numberTicks=2*z.length+1;for(x=0;x<z.length;x++){b=this.min+2*x*m/(this.numberTicks-1);var h=new this.tickRenderer(this.tickOptions);h.showLabel=false;h.setTick(b,this.name);this._ticks.push(h);var h=new this.tickRenderer(this.tickOptions);h.label=z[x];h.showMark=false;h.showGridline=false;h.setTick(b+0.5,this.name);this._ticks.push(h)}var h=new this.tickRenderer(this.tickOptions);h.showLabel=false;h.setTick(b+1,this.name);this._ticks.push(h)}else{if(F=="xaxis"||F=="x2axis"){v=this._plotDimensions.width}else{v=this._plotDimensions.height}if(this.min!=null&&this.max!=null&&this.numberTicks!=null){this.tickInterval=null}if(this.min!=null&&this.max!=null&&this.tickInterval!=null){if(parseInt((this.max-this.min)/this.tickInterval,10)!=(this.max-this.min)/this.tickInterval){this.tickInterval=null}}var y=[];var B=0;var q=0.5;var w,E;var f=false;for(var x=0;x<this._series.length;x++){var k=this._series[x];for(var u=0;u<k.data.length;u++){if(this.name=="xaxis"||this.name=="x2axis"){E=k.data[u][0]}else{E=k.data[u][1]}if(a.inArray(E,y)==-1){f=true;B+=1;y.push(E)}}}if(f&&this.sortMergedLabels){if(typeof y[0]=="string"){y.sort()}else{y.sort(function(j,i){return j-i})}}this.ticks=y;for(var x=0;x<this._series.length;x++){var k=this._series[x];for(var u=0;u<k.data.length;u++){if(this.name=="xaxis"||this.name=="x2axis"){E=k.data[u][0]}else{E=k.data[u][1]}var n=a.inArray(E,y)+1;if(this.name=="xaxis"||this.name=="x2axis"){k.data[u][0]=n}else{k.data[u][1]=n}}}if(this.groups>1&&!this._grouped){var r=y.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x<r;x+=p+1){y[x]=" "}this._grouped=true}w=B+0.5;if(this.numberTicks==null){this.numberTicks=2*B+1}var m=w-q;this.min=q;this.max=w;var o=0;var g=parseInt(3+v/10,10);var p=parseInt(B/g,10);if(this.tickInterval==null){this.tickInterval=m/(this.numberTicks-1)}for(var x=0;x<this.numberTicks;x++){b=this.min+x*this.tickInterval;var h=new this.tickRenderer(this.tickOptions);if(x/2==parseInt(x/2,10)){h.showLabel=false;h.showMark=true}else{if(p>0&&o<p){h.showLabel=false;o+=1}else{h.showLabel=true;o=0}h.label=h.formatter(h.formatString,y[(x-1)/2]);h.showMark=false;h.showGridline=false}h.setTick(b,this.name);this._ticks.push(h)}}};a.jqplot.CategoryAxisRenderer.prototype.draw=function(b,j){if(this.show){this.renderer.createTicks.call(this);var h=0;var c;if(this._elem){this._elem.emptyForce()}this._elem=this._elem||a('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>');if(this.name=="xaxis"||this.name=="x2axis"){this._elem.width(this._plotDimensions.width)}else{this._elem.height(this._plotDimensions.height)}this.labelOptions.axis=this.name;this._label=new this.labelRenderer(this.labelOptions);if(this._label.show){var g=this._label.draw(b,j);g.appendTo(this._elem)}var f=this._ticks;for(var e=0;e<f.length;e++){var d=f[e];if(d.showLabel&&(!d.isMinorTick||this.showMinorTicks)){var g=d.draw(b,j);g.appendTo(this._elem)}}this._groupLabels=[];for(var e=0;e<this.groupLabels.length;e++){var g=a('<div style="position:absolute;" class="jqplot-'+this.name+'-groupLabel"></div>');g.html(this.groupLabels[e]);this._groupLabels.push(g);g.appendTo(this._elem)}}return this._elem};a.jqplot.CategoryAxisRenderer.prototype.set=function(){var e=0;var m;var k=0;var f=0;var d=(this._label==null)?false:this._label.show;if(this.show){var n=this._ticks;for(var c=0;c<n.length;c++){var g=n[c];if(g.showLabel&&(!g.isMinorTick||this.showMinorTicks)){if(this.name=="xaxis"||this.name=="x2axis"){m=g._elem.outerHeight(true)}else{m=g._elem.outerWidth(true)}if(m>e){e=m}}}var j=0;for(var c=0;c<this._groupLabels.length;c++){var b=this._groupLabels[c];if(this.name=="xaxis"||this.name=="x2axis"){m=b.outerHeight(true)}else{m=b.outerWidth(true)}if(m>j){j=m}}if(d){k=this._label._elem.outerWidth(true);f=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){e+=j+k;this._elem.css({width:e+"px",left:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}else{e+=j+k;this._elem.css({width:e+"px",right:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}}}}};a.jqplot.CategoryAxisRenderer.prototype.pack=function(e,c){var C=this._ticks;var v=this.max;var s=this.min;var n=c.max;var l=c.min;var q=(this._label==null)?false:this._label.show;var x;for(var r in e){this._elem.css(r,e[r])}this._offsets=c;var g=n-l;var k=v-s;if(!this.reverse){this.u2p=function(h){return(h-s)*g/k+l};this.p2u=function(h){return(h-l)*k/g+s};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(h-s)*g/k};this.series_p2u=function(h){return h*k/g+s}}else{this.series_u2p=function(h){return(h-v)*g/k};this.series_p2u=function(h){return h*k/g+v}}}else{this.u2p=function(h){return l+(v-h)*g/k};this.p2u=function(h){return s+(h-l)*k/g};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(v-h)*g/k};this.series_p2u=function(h){return h*k/g+v}}else{this.series_u2p=function(h){return(s-h)*g/k};this.series_p2u=function(h){return h*k/g+s}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(x=0;x<C.length;x++){var o=C[x];if(o.show&&o.showLabel){var b;if(o.constructor==a.jqplot.CanvasAxisTickRenderer&&o.angle){var A=(this.name=="xaxis")?1:-1;switch(o.labelPosition){case"auto":if(A*o.angle<0){b=-o.getWidth()+o._textRenderer.height*Math.sin(-o._textRenderer.angle)/2}else{b=-o._textRenderer.height*Math.sin(o._textRenderer.angle)/2}break;case"end":b=-o.getWidth()+o._textRenderer.height*Math.sin(-o._textRenderer.angle)/2;break;case"start":b=-o._textRenderer.height*Math.sin(o._textRenderer.angle)/2;break;case"middle":b=-o.getWidth()/2+o._textRenderer.height*Math.sin(-o._textRenderer.angle)/2;break;default:b=-o.getWidth()/2+o._textRenderer.height*Math.sin(-o._textRenderer.angle)/2;break}}else{b=-o.getWidth()/2}var D=this.u2p(o.value)+b+"px";o._elem.css("left",D);o.pack()}}var z=["bottom",0];if(q){var m=this._label._elem.outerWidth(true);this._label._elem.css("left",l+g/2-m/2+"px");if(this.name=="xaxis"){this._label._elem.css("bottom","0px");z=["bottom",this._label._elem.outerHeight(true)]}else{this._label._elem.css("top","0px");z=["top",this._label._elem.outerHeight(true)]}this._label.pack()}var d=parseInt(this._ticks.length/this.groups,10)+1;for(x=0;x<this._groupLabels.length;x++){var B=0;var f=0;for(var u=x*d;u<(x+1)*d;u++){if(u>=this._ticks.length-1){continue}if(this._ticks[u]._elem&&this._ticks[u].label!=" "){var o=this._ticks[u]._elem;var r=o.position();B+=r.left+o.outerWidth(true)/2;f++}}B=B/f;this._groupLabels[x].css({left:(B-this._groupLabels[x].outerWidth(true)/2)});this._groupLabels[x].css(z[0],z[1])}}else{for(x=0;x<C.length;x++){var o=C[x];if(o.show&&o.showLabel){var b;if(o.constructor==a.jqplot.CanvasAxisTickRenderer&&o.angle){var A=(this.name=="yaxis")?1:-1;switch(o.labelPosition){case"auto":case"end":if(A*o.angle<0){b=-o._textRenderer.height*Math.cos(-o._textRenderer.angle)/2}else{b=-o.getHeight()+o._textRenderer.height*Math.cos(o._textRenderer.angle)/2}break;case"start":if(o.angle>0){b=-o._textRenderer.height*Math.cos(-o._textRenderer.angle)/2}else{b=-o.getHeight()+o._textRenderer.height*Math.cos(o._textRenderer.angle)/2}break;case"middle":b=-o.getHeight()/2;break;default:b=-o.getHeight()/2;break}}else{b=-o.getHeight()/2}var D=this.u2p(o.value)+b+"px";o._elem.css("top",D);o.pack()}}var z=["left",0];if(q){var y=this._label._elem.outerHeight(true);this._label._elem.css("top",n-g/2-y/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px");z=["left",this._label._elem.outerWidth(true)]}else{this._label._elem.css("right","0px");z=["right",this._label._elem.outerWidth(true)]}this._label.pack()}var d=parseInt(this._ticks.length/this.groups,10)+1;for(x=0;x<this._groupLabels.length;x++){var B=0;var f=0;for(var u=x*d;u<(x+1)*d;u++){if(u>=this._ticks.length-1){continue}if(this._ticks[u]._elem&&this._ticks[u].label!=" "){var o=this._ticks[u]._elem;var r=o.position();B+=r.top+o.outerHeight()/2;f++}}B=B/f;this._groupLabels[x].css({top:B-this._groupLabels[x].outerHeight()/2});this._groupLabels[x].css(z[0],z[1])}}}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.ciParser.js b/plugin/jqplot/plugins/jqplot.ciParser.js new file mode 100644 index 000000000..2f094fc94 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.ciParser.js @@ -0,0 +1,116 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.ciParser + * Data Renderer function which converts a custom JSON data object into jqPlot data format. + * Set this as a callable on the jqplot dataRenderer plot option: + * + * > plot = $.jqplot('mychart', [data], { dataRenderer: $.jqplot.ciParser, ... }); + * + * Where data is an object in JSON format or a JSON encoded string conforming to the + * City Index API spec. + * + * Note that calling the renderer function is handled internally by jqPlot. The + * user does not have to call the function. The parameters described below will + * automatically be passed to the ciParser function. + * + * Parameters: + * data - JSON encoded string or object. + * plot - reference to jqPlot Plot object. + * + * Returns: + * data array in jqPlot format. + * + */ + $.jqplot.ciParser = function (data, plot) { + var ret = [], + line, + temp, + i, j, k, kk; + + if (typeof(data) == "string") { + data = $.jqplot.JSON.parse(data, handleStrings); + } + + else if (typeof(data) == "object") { + for (k in data) { + for (i=0; i<data[k].length; i++) { + for (kk in data[k][i]) { + data[k][i][kk] = handleStrings(kk, data[k][i][kk]); + } + } + } + } + + else { + return null; + } + + // function handleStrings + // Checks any JSON encoded strings to see if they are + // encoded dates. If so, pull out the timestamp. + // Expects dates to be represented by js timestamps. + + function handleStrings(key, value) { + var a; + if (value != null) { + if (value.toString().indexOf('Date') >= 0) { + //here we will try to extract the ticks from the Date string in the "value" fields of JSON returned data + a = /^\/Date\((-?[0-9]+)\)\/$/.exec(value); + if (a) { + return parseInt(a[1], 10); + } + } + return value; + } + } + + for (var prop in data) { + line = []; + temp = data[prop]; + switch (prop) { + case "PriceTicks": + for (i=0; i<temp.length; i++) { + line.push([temp[i]['TickDate'], temp[i]['Price']]); + } + break; + case "PriceBars": + for (i=0; i<temp.length; i++) { + line.push([temp[i]['BarDate'], temp[i]['Open'], temp[i]['High'], temp[i]['Low'], temp[i]['Close']]); + } + break; + } + ret.push(line); + } + return ret; + }; +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.ciParser.min.js b/plugin/jqplot/plugins/jqplot.ciParser.min.js new file mode 100644 index 000000000..08f46c851 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.ciParser.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.ciParser=function(g,l){var m=[],o,n,h,f,e,c;if(typeof(g)=="string"){g=a.jqplot.JSON.parse(g,d)}else{if(typeof(g)=="object"){for(e in g){for(h=0;h<g[e].length;h++){for(c in g[e][h]){g[e][h][c]=d(c,g[e][h][c])}}}}else{return null}}function d(j,k){var i;if(k!=null){if(k.toString().indexOf("Date")>=0){i=/^\/Date\((-?[0-9]+)\)\/$/.exec(k);if(i){return parseInt(i[1],10)}}return k}}for(var b in g){o=[];n=g[b];switch(b){case"PriceTicks":for(h=0;h<n.length;h++){o.push([n[h]["TickDate"],n[h]["Price"]])}break;case"PriceBars":for(h=0;h<n.length;h++){o.push([n[h]["BarDate"],n[h]["Open"],n[h]["High"],n[h]["Low"],n[h]["Close"]])}break}m.push(o)}return m}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.cursor.js b/plugin/jqplot/plugins/jqplot.cursor.js new file mode 100644 index 000000000..bf1c36f2a --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.cursor.js @@ -0,0 +1,1108 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + + /** + * Class: $.jqplot.Cursor + * Plugin class representing the cursor as displayed on the plot. + */ + $.jqplot.Cursor = function(options) { + // Group: Properties + // + // prop: style + // CSS spec for cursor style + this.style = 'crosshair'; + this.previousCursor = 'auto'; + // prop: show + // whether to show the cursor or not. + this.show = $.jqplot.config.enablePlugins; + // prop: showTooltip + // show a cursor position tooltip. Location of the tooltip + // will be controlled by followMouse and tooltipLocation. + this.showTooltip = true; + // prop: followMouse + // Tooltip follows the mouse, it is not at a fixed location. + // Tooltip will show on the grid at the location given by + // tooltipLocation, offset from the grid edge by tooltipOffset. + this.followMouse = false; + // prop: tooltipLocation + // Where to position tooltip. If followMouse is true, this is + // relative to the cursor, otherwise, it is relative to the grid. + // One of 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' + this.tooltipLocation = 'se'; + // prop: tooltipOffset + // Pixel offset of tooltip from the grid boudaries or cursor center. + this.tooltipOffset = 6; + // prop: showTooltipGridPosition + // show the grid pixel coordinates of the mouse. + this.showTooltipGridPosition = false; + // prop: showTooltipUnitPosition + // show the unit (data) coordinates of the mouse. + this.showTooltipUnitPosition = true; + // prop: showTooltipDataPosition + // Used with showVerticalLine to show intersecting data points in the tooltip. + this.showTooltipDataPosition = false; + // prop: tooltipFormatString + // sprintf format string for the tooltip. + // Uses Ash Searle's javascript sprintf implementation + // found here: http://hexmen.com/blog/2007/03/printf-sprintf/ + // See http://perldoc.perl.org/functions/sprintf.html for reference + // Note, if showTooltipDataPosition is true, the default tooltipFormatString + // will be set to the cursorLegendFormatString, not the default given here. + this.tooltipFormatString = '%.4P, %.4P'; + // prop: useAxesFormatters + // Use the x and y axes formatters to format the text in the tooltip. + this.useAxesFormatters = true; + // prop: tooltipAxisGroups + // Show position for the specified axes. + // This is an array like [['xaxis', 'yaxis'], ['xaxis', 'y2axis']] + // Default is to compute automatically for all visible axes. + this.tooltipAxisGroups = []; + // prop: zoom + // Enable plot zooming. + this.zoom = false; + // zoomProxy and zoomTarget properties are not directly set by user. + // They Will be set through call to zoomProxy method. + this.zoomProxy = false; + this.zoomTarget = false; + // prop: looseZoom + // Will expand zoom range to provide more rounded tick values. + // Works only with linear, log and date axes. + this.looseZoom = true; + // prop: clickReset + // Will reset plot zoom if single click on plot without drag. + this.clickReset = false; + // prop: dblClickReset + // Will reset plot zoom if double click on plot without drag. + this.dblClickReset = true; + // prop: showVerticalLine + // draw a vertical line across the plot which follows the cursor. + // When the line is near a data point, a special legend and/or tooltip can + // be updated with the data values. + this.showVerticalLine = false; + // prop: showHorizontalLine + // draw a horizontal line across the plot which follows the cursor. + this.showHorizontalLine = false; + // prop: constrainZoomTo + // 'none', 'x' or 'y' + this.constrainZoomTo = 'none'; + // // prop: autoscaleConstraint + // // when a constrained axis is specified, true will + // // auatoscale the adjacent axis. + // this.autoscaleConstraint = true; + this.shapeRenderer = new $.jqplot.ShapeRenderer(); + this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}, gridpos:{}, datapos:{}}; + this._tooltipElem; + this.zoomCanvas; + this.cursorCanvas; + // prop: intersectionThreshold + // pixel distance from data point or marker to consider cursor lines intersecting with point. + // If data point markers are not shown, this should be >= 1 or will often miss point intersections. + this.intersectionThreshold = 2; + // prop: showCursorLegend + // Replace the plot legend with an enhanced legend displaying intersection information. + this.showCursorLegend = false; + // prop: cursorLegendFormatString + // Format string used in the cursor legend. If showTooltipDataPosition is true, + // this will also be the default format string used by tooltipFormatString. + this.cursorLegendFormatString = $.jqplot.Cursor.cursorLegendFormatString; + // whether the cursor is over the grid or not. + this._oldHandlers = {onselectstart: null, ondrag: null, onmousedown: null}; + // prop: constrainOutsideZoom + // True to limit actual zoom area to edges of grid, even when zooming + // outside of plot area. That is, can't zoom out by mousing outside plot. + this.constrainOutsideZoom = true; + // prop: showTooltipOutsideZoom + // True will keep updating the tooltip when zooming of the grid. + this.showTooltipOutsideZoom = false; + // true if mouse is over grid, false if not. + this.onGrid = false; + $.extend(true, this, options); + }; + + $.jqplot.Cursor.cursorLegendFormatString = '%s x:%s, y:%s'; + + // called with scope of plot + $.jqplot.Cursor.init = function (target, data, opts){ + // add a cursor attribute to the plot + var options = opts || {}; + this.plugins.cursor = new $.jqplot.Cursor(options.cursor); + var c = this.plugins.cursor; + + if (c.show) { + $.jqplot.eventListenerHooks.push(['jqplotMouseEnter', handleMouseEnter]); + $.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMouseLeave]); + $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMouseMove]); + + if (c.showCursorLegend) { + opts.legend = opts.legend || {}; + opts.legend.renderer = $.jqplot.CursorLegendRenderer; + opts.legend.formatString = this.plugins.cursor.cursorLegendFormatString; + opts.legend.show = true; + } + + if (c.zoom) { + $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleMouseDown]); + + if (c.clickReset) { + $.jqplot.eventListenerHooks.push(['jqplotClick', handleClick]); + } + + if (c.dblClickReset) { + $.jqplot.eventListenerHooks.push(['jqplotDblClick', handleDblClick]); + } + } + + this.resetZoom = function() { + var axes = this.axes; + if (!c.zoomProxy) { + for (var ax in axes) { + axes[ax].reset(); + axes[ax]._ticks = []; + // fake out tick creation algorithm to make sure original auto + // computed format string is used if _overrideFormatString is true + if (c._zoom.axes[ax] !== undefined) { + axes[ax]._autoFormatString = c._zoom.axes[ax].tickFormatString; + } + } + this.redraw(); + } + else { + var ctx = this.plugins.cursor.zoomCanvas._ctx; + ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); + ctx = null; + } + this.plugins.cursor._zoom.isZoomed = false; + this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]); + }; + + + if (c.showTooltipDataPosition) { + c.showTooltipUnitPosition = false; + c.showTooltipGridPosition = false; + if (options.cursor.tooltipFormatString == undefined) { + c.tooltipFormatString = $.jqplot.Cursor.cursorLegendFormatString; + } + } + } + }; + + // called with context of plot + $.jqplot.Cursor.postDraw = function() { + var c = this.plugins.cursor; + + // Memory Leaks patch + if (c.zoomCanvas) { + c.zoomCanvas.resetCanvas(); + c.zoomCanvas = null; + } + + if (c.cursorCanvas) { + c.cursorCanvas.resetCanvas(); + c.cursorCanvas = null; + } + + if (c._tooltipElem) { + c._tooltipElem.emptyForce(); + c._tooltipElem = null; + } + + + if (c.zoom) { + c.zoomCanvas = new $.jqplot.GenericCanvas(); + this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions, this)); + c.zoomCanvas.setContext(); + } + + var elem = document.createElement('div'); + c._tooltipElem = $(elem); + elem = null; + c._tooltipElem.addClass('jqplot-cursor-tooltip'); + c._tooltipElem.css({position:'absolute', display:'none'}); + + + if (c.zoomCanvas) { + c.zoomCanvas._elem.before(c._tooltipElem); + } + + else { + this.eventCanvas._elem.before(c._tooltipElem); + } + + if (c.showVerticalLine || c.showHorizontalLine) { + c.cursorCanvas = new $.jqplot.GenericCanvas(); + this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions, this)); + c.cursorCanvas.setContext(); + } + + // if we are showing the positions in unit coordinates, and no axes groups + // were specified, create a default set. + if (c.showTooltipUnitPosition){ + if (c.tooltipAxisGroups.length === 0) { + var series = this.series; + var s; + var temp = []; + for (var i=0; i<series.length; i++) { + s = series[i]; + var ax = s.xaxis+','+s.yaxis; + if ($.inArray(ax, temp) == -1) { + temp.push(ax); + } + } + for (var i=0; i<temp.length; i++) { + c.tooltipAxisGroups.push(temp[i].split(',')); + } + } + } + }; + + // Group: methods + // + // method: $.jqplot.Cursor.zoomProxy + // links targetPlot to controllerPlot so that plot zooming of + // targetPlot will be controlled by zooming on the controllerPlot. + // controllerPlot will not actually zoom, but acts as an + // overview plot. Note, the zoom options must be set to true for + // zoomProxy to work. + $.jqplot.Cursor.zoomProxy = function(targetPlot, controllerPlot) { + var tc = targetPlot.plugins.cursor; + var cc = controllerPlot.plugins.cursor; + tc.zoomTarget = true; + tc.zoom = true; + tc.style = 'auto'; + tc.dblClickReset = false; + cc.zoom = true; + cc.zoomProxy = true; + + controllerPlot.target.bind('jqplotZoom', plotZoom); + controllerPlot.target.bind('jqplotResetZoom', plotReset); + + function plotZoom(ev, gridpos, datapos, plot, cursor) { + tc.doZoom(gridpos, datapos, targetPlot, cursor); + } + + function plotReset(ev, plot, cursor) { + targetPlot.resetZoom(); + } + }; + + $.jqplot.Cursor.prototype.resetZoom = function(plot, cursor) { + var axes = plot.axes; + var cax = cursor._zoom.axes; + if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) { + for (var ax in axes) { + // axes[ax]._ticks = []; + // axes[ax].min = cax[ax].min; + // axes[ax].max = cax[ax].max; + // axes[ax].numberTicks = cax[ax].numberTicks; + // axes[ax].tickInterval = cax[ax].tickInterval; + // // for date axes + // axes[ax].daTickInterval = cax[ax].daTickInterval; + axes[ax].reset(); + axes[ax]._ticks = []; + // fake out tick creation algorithm to make sure original auto + // computed format string is used if _overrideFormatString is true + axes[ax]._autoFormatString = cax[ax].tickFormatString; + } + plot.redraw(); + cursor._zoom.isZoomed = false; + } + else { + var ctx = cursor.zoomCanvas._ctx; + ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); + ctx = null; + } + plot.target.trigger('jqplotResetZoom', [plot, cursor]); + }; + + $.jqplot.Cursor.resetZoom = function(plot) { + plot.resetZoom(); + }; + + $.jqplot.Cursor.prototype.doZoom = function (gridpos, datapos, plot, cursor) { + var c = cursor; + var axes = plot.axes; + var zaxes = c._zoom.axes; + var start = zaxes.start; + var end = zaxes.end; + var min, max, dp, span, + newmin, newmax, curax, _numberTicks, ret; + var ctx = plot.plugins.cursor.zoomCanvas._ctx; + // don't zoom if zoom area is too small (in pixels) + if ((c.constrainZoomTo == 'none' && Math.abs(gridpos.x - c._zoom.start[0]) > 6 && Math.abs(gridpos.y - c._zoom.start[1]) > 6) || (c.constrainZoomTo == 'x' && Math.abs(gridpos.x - c._zoom.start[0]) > 6) || (c.constrainZoomTo == 'y' && Math.abs(gridpos.y - c._zoom.start[1]) > 6)) { + if (!plot.plugins.cursor.zoomProxy) { + for (var ax in datapos) { + // make a copy of the original axes to revert back. + if (c._zoom.axes[ax] == undefined) { + c._zoom.axes[ax] = {}; + c._zoom.axes[ax].numberTicks = axes[ax].numberTicks; + c._zoom.axes[ax].tickInterval = axes[ax].tickInterval; + // for date axes... + c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval; + c._zoom.axes[ax].min = axes[ax].min; + c._zoom.axes[ax].max = axes[ax].max; + c._zoom.axes[ax].tickFormatString = (axes[ax].tickOptions != null) ? axes[ax].tickOptions.formatString : ''; + } + + + if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) { + dp = datapos[ax]; + if (dp != null) { + if (dp > start[ax]) { + newmin = start[ax]; + newmax = dp; + } + else { + span = start[ax] - dp; + newmin = dp; + newmax = start[ax]; + } + + curax = axes[ax]; + + _numberTicks = null; + + // if aligning this axis, use number of ticks from previous axis. + // Do I need to reset somehow if alignTicks is changed and then graph is replotted?? + if (curax.alignTicks) { + if (curax.name === 'x2axis' && plot.axes.xaxis.show) { + _numberTicks = plot.axes.xaxis.numberTicks; + } + else if (curax.name.charAt(0) === 'y' && curax.name !== 'yaxis' && curax.name !== 'yMidAxis' && plot.axes.yaxis.show) { + _numberTicks = plot.axes.yaxis.numberTicks; + } + } + + if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer )) { //} || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) { + + ret = $.jqplot.LinearTickGenerator(newmin, newmax, curax._scalefact, _numberTicks); + + // if new minimum is less than "true" minimum of axis display, adjust it + if (axes[ax].tickInset && ret[0] < axes[ax].min + axes[ax].tickInset * axes[ax].tickInterval) { + ret[0] += ret[4]; + ret[2] -= 1; + } + + // if new maximum is greater than "true" max of axis display, adjust it + if (axes[ax].tickInset && ret[1] > axes[ax].max - axes[ax].tickInset * axes[ax].tickInterval) { + ret[1] -= ret[4]; + ret[2] -= 1; + } + + // for log axes, don't fall below current minimum, this will look bad and can't have 0 in range anyway. + if (axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer && ret[0] < axes[ax].min) { + // remove a tick and shift min up + ret[0] += ret[4]; + ret[2] -= 1; + } + + axes[ax].min = ret[0]; + axes[ax].max = ret[1]; + axes[ax]._autoFormatString = ret[3]; + axes[ax].numberTicks = ret[2]; + axes[ax].tickInterval = ret[4]; + // for date axes... + axes[ax].daTickInterval = [ret[4]/1000, 'seconds']; + } + else { + axes[ax].min = newmin; + axes[ax].max = newmax; + axes[ax].tickInterval = null; + axes[ax].numberTicks = null; + // for date axes... + axes[ax].daTickInterval = null; + } + + axes[ax]._ticks = []; + } + } + + // if ((c.constrainZoomTo == 'x' && ax.charAt(0) == 'y' && c.autoscaleConstraint) || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'x' && c.autoscaleConstraint)) { + // dp = datapos[ax]; + // if (dp != null) { + // axes[ax].max == null; + // axes[ax].min = null; + // } + // } + } + ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); + plot.redraw(); + c._zoom.isZoomed = true; + ctx = null; + } + plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]); + } + }; + + $.jqplot.preInitHooks.push($.jqplot.Cursor.init); + $.jqplot.postDrawHooks.push($.jqplot.Cursor.postDraw); + + function updateTooltip(gridpos, datapos, plot) { + var c = plot.plugins.cursor; + var s = ''; + var addbr = false; + if (c.showTooltipGridPosition) { + s = gridpos.x+', '+gridpos.y; + addbr = true; + } + if (c.showTooltipUnitPosition) { + var g; + for (var i=0; i<c.tooltipAxisGroups.length; i++) { + g = c.tooltipAxisGroups[i]; + if (addbr) { + s += '<br />'; + } + if (c.useAxesFormatters) { + for (var j=0; j<g.length; j++) { + if (j) { + s += ', '; + } + var af = plot.axes[g[j]]._ticks[0].formatter; + var afstr = plot.axes[g[j]]._ticks[0].formatString; + s += af(afstr, datapos[g[j]]); + } + } + else { + s += $.jqplot.sprintf(c.tooltipFormatString, datapos[g[0]], datapos[g[1]]); + } + addbr = true; + } + } + + if (c.showTooltipDataPosition) { + var series = plot.series; + var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y); + var addbr = false; + + for (var i = 0; i< series.length; i++) { + if (series[i].show) { + var idx = series[i].index; + var label = series[i].label.toString(); + var cellid = $.inArray(idx, ret.indices); + var sx = undefined; + var sy = undefined; + if (cellid != -1) { + var data = ret.data[cellid].data; + if (c.useAxesFormatters) { + var xf = series[i]._xaxis._ticks[0].formatter; + var yf = series[i]._yaxis._ticks[0].formatter; + var xfstr = series[i]._xaxis._ticks[0].formatString; + var yfstr = series[i]._yaxis._ticks[0].formatString; + sx = xf(xfstr, data[0]); + sy = yf(yfstr, data[1]); + } + else { + sx = data[0]; + sy = data[1]; + } + if (addbr) { + s += '<br />'; + } + s += $.jqplot.sprintf(c.tooltipFormatString, label, sx, sy); + addbr = true; + } + } + } + + } + c._tooltipElem.html(s); + } + + function moveLine(gridpos, plot) { + var c = plot.plugins.cursor; + var ctx = c.cursorCanvas._ctx; + ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); + if (c.showVerticalLine) { + c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]); + } + if (c.showHorizontalLine) { + c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]); + } + var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y); + if (c.showCursorLegend) { + var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); + for (var i=0; i<cells.length; i++) { + var idx = $(cells[i]).data('seriesIndex'); + var series = plot.series[idx]; + var label = series.label.toString(); + var cellid = $.inArray(idx, ret.indices); + var sx = undefined; + var sy = undefined; + if (cellid != -1) { + var data = ret.data[cellid].data; + if (c.useAxesFormatters) { + var xf = series._xaxis._ticks[0].formatter; + var yf = series._yaxis._ticks[0].formatter; + var xfstr = series._xaxis._ticks[0].formatString; + var yfstr = series._yaxis._ticks[0].formatString; + sx = xf(xfstr, data[0]); + sy = yf(yfstr, data[1]); + } + else { + sx = data[0]; + sy = data[1]; + } + } + if (plot.legend.escapeHtml) { + $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy)); + } + else { + $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy)); + } + } + } + ctx = null; + } + + function getIntersectingPoints(plot, x, y) { + var ret = {indices:[], data:[]}; + var s, i, d0, d, j, r, p; + var threshold; + var c = plot.plugins.cursor; + for (var i=0; i<plot.series.length; i++) { + s = plot.series[i]; + r = s.renderer; + if (s.show) { + threshold = c.intersectionThreshold; + if (s.showMarker) { + threshold += s.markerRenderer.size/2; + } + for (var j=0; j<s.gridData.length; j++) { + p = s.gridData[j]; + // check vertical line + if (c.showVerticalLine) { + if (Math.abs(x-p[0]) <= threshold) { + ret.indices.push(i); + ret.data.push({seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}); + } + } + } + } + } + return ret; + } + + function moveTooltip(gridpos, plot) { + var c = plot.plugins.cursor; + var elem = c._tooltipElem; + switch (c.tooltipLocation) { + case 'nw': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; + var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); + break; + case 'n': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; + var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); + break; + case 'ne': + var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; + var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); + break; + case 'e': + var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; + var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; + break; + case 'se': + var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; + var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; + break; + case 's': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; + var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; + break; + case 'sw': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; + var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; + break; + case 'w': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; + var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; + break; + default: + var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; + var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; + break; + } + + elem.css('left', x); + elem.css('top', y); + elem = null; + } + + function positionTooltip(plot) { + // fake a grid for positioning + var grid = plot._gridPadding; + var c = plot.plugins.cursor; + var elem = c._tooltipElem; + switch (c.tooltipLocation) { + case 'nw': + var a = grid.left + c.tooltipOffset; + var b = grid.top + c.tooltipOffset; + elem.css('left', a); + elem.css('top', b); + break; + case 'n': + var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2; + var b = grid.top + c.tooltipOffset; + elem.css('left', a); + elem.css('top', b); + break; + case 'ne': + var a = grid.right + c.tooltipOffset; + var b = grid.top + c.tooltipOffset; + elem.css({right:a, top:b}); + break; + case 'e': + var a = grid.right + c.tooltipOffset; + var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2; + elem.css({right:a, top:b}); + break; + case 'se': + var a = grid.right + c.tooltipOffset; + var b = grid.bottom + c.tooltipOffset; + elem.css({right:a, bottom:b}); + break; + case 's': + var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2; + var b = grid.bottom + c.tooltipOffset; + elem.css({left:a, bottom:b}); + break; + case 'sw': + var a = grid.left + c.tooltipOffset; + var b = grid.bottom + c.tooltipOffset; + elem.css({left:a, bottom:b}); + break; + case 'w': + var a = grid.left + c.tooltipOffset; + var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2; + elem.css({left:a, top:b}); + break; + default: // same as 'se' + var a = grid.right - c.tooltipOffset; + var b = grid.bottom + c.tooltipOffset; + elem.css({right:a, bottom:b}); + break; + } + elem = null; + } + + function handleClick (ev, gridpos, datapos, neighbor, plot) { + ev.preventDefault(); + ev.stopImmediatePropagation(); + var c = plot.plugins.cursor; + if (c.clickReset) { + c.resetZoom(plot, c); + } + var sel = window.getSelection; + if (document.selection && document.selection.empty) + { + document.selection.empty(); + } + else if (sel && !sel().isCollapsed) { + sel().collapse(); + } + return false; + } + + function handleDblClick (ev, gridpos, datapos, neighbor, plot) { + ev.preventDefault(); + ev.stopImmediatePropagation(); + var c = plot.plugins.cursor; + if (c.dblClickReset) { + c.resetZoom(plot, c); + } + var sel = window.getSelection; + if (document.selection && document.selection.empty) + { + document.selection.empty(); + } + else if (sel && !sel().isCollapsed) { + sel().collapse(); + } + return false; + } + + function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) { + var c = plot.plugins.cursor; + c.onGrid = false; + if (c.show) { + $(ev.target).css('cursor', c.previousCursor); + if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) { + c._tooltipElem.empty(); + c._tooltipElem.hide(); + } + if (c.zoom) { + c._zoom.gridpos = gridpos; + c._zoom.datapos = datapos; + } + if (c.showVerticalLine || c.showHorizontalLine) { + var ctx = c.cursorCanvas._ctx; + ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); + ctx = null; + } + if (c.showCursorLegend) { + var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); + for (var i=0; i<cells.length; i++) { + var idx = $(cells[i]).data('seriesIndex'); + var series = plot.series[idx]; + var label = series.label.toString(); + if (plot.legend.escapeHtml) { + $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); + } + else { + $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); + } + + } + } + } + } + + function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) { + var c = plot.plugins.cursor; + c.onGrid = true; + if (c.show) { + c.previousCursor = ev.target.style.cursor; + ev.target.style.cursor = c.style; + if (c.showTooltip) { + updateTooltip(gridpos, datapos, plot); + if (c.followMouse) { + moveTooltip(gridpos, plot); + } + else { + positionTooltip(plot); + } + c._tooltipElem.show(); + } + if (c.showVerticalLine || c.showHorizontalLine) { + moveLine(gridpos, plot); + } + } + + } + + function handleMouseMove(ev, gridpos, datapos, neighbor, plot) { + var c = plot.plugins.cursor; + if (c.show) { + if (c.showTooltip) { + updateTooltip(gridpos, datapos, plot); + if (c.followMouse) { + moveTooltip(gridpos, plot); + } + } + if (c.showVerticalLine || c.showHorizontalLine) { + moveLine(gridpos, plot); + } + } + } + + function getEventPosition(ev) { + var plot = ev.data.plot; + var go = plot.eventCanvas._elem.offset(); + var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top}; + ////// + // TO DO: handle yMidAxis + ////// + var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null, yMidAxis:null}; + var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis']; + var ax = plot.axes; + var n, axis; + for (n=11; n>0; n--) { + axis = an[n-1]; + if (ax[axis].show) { + dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]); + } + } + + return {offsets:go, gridPos:gridPos, dataPos:dataPos}; + } + + function handleZoomMove(ev) { + var plot = ev.data.plot; + var c = plot.plugins.cursor; + // don't do anything if not on grid. + if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) { + ev.preventDefault(); + var ctx = c.zoomCanvas._ctx; + var positions = getEventPosition(ev); + var gridpos = positions.gridPos; + var datapos = positions.dataPos; + c._zoom.gridpos = gridpos; + c._zoom.datapos = datapos; + c._zoom.zooming = true; + var xpos = gridpos.x; + var ypos = gridpos.y; + var height = ctx.canvas.height; + var width = ctx.canvas.width; + if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) { + updateTooltip(gridpos, datapos, plot); + if (c.followMouse) { + moveTooltip(gridpos, plot); + } + } + if (c.constrainZoomTo == 'x') { + c._zoom.end = [xpos, height]; + } + else if (c.constrainZoomTo == 'y') { + c._zoom.end = [width, ypos]; + } + else { + c._zoom.end = [xpos, ypos]; + } + var sel = window.getSelection; + if (document.selection && document.selection.empty) + { + document.selection.empty(); + } + else if (sel && !sel().isCollapsed) { + sel().collapse(); + } + drawZoomBox.call(c); + ctx = null; + } + } + + function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { + var c = plot.plugins.cursor; + if(plot.plugins.mobile){ + $(document).one('vmouseup.jqplot_cursor', {plot:plot}, handleMouseUp); + } else { + $(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp); + } + var axes = plot.axes; + if (document.onselectstart != undefined) { + c._oldHandlers.onselectstart = document.onselectstart; + document.onselectstart = function () { return false; }; + } + if (document.ondrag != undefined) { + c._oldHandlers.ondrag = document.ondrag; + document.ondrag = function () { return false; }; + } + if (document.onmousedown != undefined) { + c._oldHandlers.onmousedown = document.onmousedown; + document.onmousedown = function () { return false; }; + } + if (c.zoom) { + if (!c.zoomProxy) { + var ctx = c.zoomCanvas._ctx; + ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); + ctx = null; + } + if (c.constrainZoomTo == 'x') { + c._zoom.start = [gridpos.x, 0]; + } + else if (c.constrainZoomTo == 'y') { + c._zoom.start = [0, gridpos.y]; + } + else { + c._zoom.start = [gridpos.x, gridpos.y]; + } + c._zoom.started = true; + for (var ax in datapos) { + // get zoom starting position. + c._zoom.axes.start[ax] = datapos[ax]; + } + if(plot.plugins.mobile){ + $(document).bind('vmousemove.jqplotCursor', {plot:plot}, handleZoomMove); + } else { + $(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove); + } + + } + } + + function handleMouseUp(ev) { + var plot = ev.data.plot; + var c = plot.plugins.cursor; + if (c.zoom && c._zoom.zooming && !c.zoomTarget) { + var xpos = c._zoom.gridpos.x; + var ypos = c._zoom.gridpos.y; + var datapos = c._zoom.datapos; + var height = c.zoomCanvas._ctx.canvas.height; + var width = c.zoomCanvas._ctx.canvas.width; + var axes = plot.axes; + + if (c.constrainOutsideZoom && !c.onGrid) { + if (xpos < 0) { xpos = 0; } + else if (xpos > width) { xpos = width; } + if (ypos < 0) { ypos = 0; } + else if (ypos > height) { ypos = height; } + + for (var axis in datapos) { + if (datapos[axis]) { + if (axis.charAt(0) == 'x') { + datapos[axis] = axes[axis].series_p2u(xpos); + } + else { + datapos[axis] = axes[axis].series_p2u(ypos); + } + } + } + } + + if (c.constrainZoomTo == 'x') { + ypos = height; + } + else if (c.constrainZoomTo == 'y') { + xpos = width; + } + c._zoom.end = [xpos, ypos]; + c._zoom.gridpos = {x:xpos, y:ypos}; + + c.doZoom(c._zoom.gridpos, datapos, plot, c); + } + c._zoom.started = false; + c._zoom.zooming = false; + + $(document).unbind('mousemove.jqplotCursor', handleZoomMove); + + if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){ + document.onselectstart = c._oldHandlers.onselectstart; + c._oldHandlers.onselectstart = null; + } + if (document.ondrag != undefined && c._oldHandlers.ondrag != null){ + document.ondrag = c._oldHandlers.ondrag; + c._oldHandlers.ondrag = null; + } + if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){ + document.onmousedown = c._oldHandlers.onmousedown; + c._oldHandlers.onmousedown = null; + } + + } + + function drawZoomBox() { + var start = this._zoom.start; + var end = this._zoom.end; + var ctx = this.zoomCanvas._ctx; + var l, t, h, w; + if (end[0] > start[0]) { + l = start[0]; + w = end[0] - start[0]; + } + else { + l = end[0]; + w = start[0] - end[0]; + } + if (end[1] > start[1]) { + t = start[1]; + h = end[1] - start[1]; + } + else { + t = end[1]; + h = start[1] - end[1]; + } + ctx.fillStyle = 'rgba(0,0,0,0.2)'; + ctx.strokeStyle = '#999999'; + ctx.lineWidth = 1.0; + ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); + ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height); + ctx.clearRect(l, t, w, h); + // IE won't show transparent fill rect, so stroke a rect also. + ctx.strokeRect(l,t,w,h); + ctx = null; + } + + $.jqplot.CursorLegendRenderer = function(options) { + $.jqplot.TableLegendRenderer.call(this, options); + this.formatString = '%s'; + }; + + $.jqplot.CursorLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); + $.jqplot.CursorLegendRenderer.prototype.constructor = $.jqplot.CursorLegendRenderer; + + // called in context of a Legend + $.jqplot.CursorLegendRenderer.prototype.draw = function() { + if (this._elem) { + this._elem.emptyForce(); + this._elem = null; + } + if (this.show) { + var series = this._series, s; + // make a table. one line label per row. + var elem = document.createElement('table'); + this._elem = $(elem); + elem = null; + this._elem.addClass('jqplot-legend jqplot-cursor-legend'); + this._elem.css('position', 'absolute'); + + var pad = false; + for (var i = 0; i< series.length; i++) { + s = series[i]; + if (s.show && s.showLabel) { + var lt = $.jqplot.sprintf(this.formatString, s.label.toString()); + if (lt) { + var color = s.color; + if (s._stack && !s.fill) { + color = ''; + } + addrow.call(this, lt, color, pad, i); + pad = true; + } + // let plugins add more rows to legend. Used by trend line plugin. + for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) { + var item = $.jqplot.addLegendRowHooks[j].call(this, s); + if (item) { + addrow.call(this, item.label, item.color, pad); + pad = true; + } + } + } + } + series = s = null; + delete series; + delete s; + } + + function addrow(label, color, pad, idx) { + var rs = (pad) ? this.rowSpacing : '0'; + var tr = $('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem); + tr.data('seriesIndex', idx); + $('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+rs+';">'+ + '<div style="border:1px solid #cccccc;padding:0.2em;">'+ + '<div class="jqplot-cursor-legend-swatch" style="background-color:'+color+';"></div>'+ + '</div></td>').appendTo(tr); + var td = $('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+rs+';"></td>'); + td.appendTo(tr); + td.data('seriesIndex', idx); + if (this.escapeHtml) { + td.text(label); + } + else { + td.html(label); + } + tr = null; + td = null; + } + return this._elem; + }; + +})(jQuery); diff --git a/plugin/jqplot/plugins/jqplot.cursor.min.js b/plugin/jqplot/plugins/jqplot.cursor.min.js new file mode 100644 index 000000000..51580bad0 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.cursor.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(j){j.jqplot.Cursor=function(q){this.style="crosshair";this.previousCursor="auto";this.show=j.jqplot.config.enablePlugins;this.showTooltip=true;this.followMouse=false;this.tooltipLocation="se";this.tooltipOffset=6;this.showTooltipGridPosition=false;this.showTooltipUnitPosition=true;this.showTooltipDataPosition=false;this.tooltipFormatString="%.4P, %.4P";this.useAxesFormatters=true;this.tooltipAxisGroups=[];this.zoom=false;this.zoomProxy=false;this.zoomTarget=false;this.looseZoom=true;this.clickReset=false;this.dblClickReset=true;this.showVerticalLine=false;this.showHorizontalLine=false;this.constrainZoomTo="none";this.shapeRenderer=new j.jqplot.ShapeRenderer();this._zoom={start:[],end:[],started:false,zooming:false,isZoomed:false,axes:{start:{},end:{}},gridpos:{},datapos:{}};this._tooltipElem;this.zoomCanvas;this.cursorCanvas;this.intersectionThreshold=2;this.showCursorLegend=false;this.cursorLegendFormatString=j.jqplot.Cursor.cursorLegendFormatString;this._oldHandlers={onselectstart:null,ondrag:null,onmousedown:null};this.constrainOutsideZoom=true;this.showTooltipOutsideZoom=false;this.onGrid=false;j.extend(true,this,q)};j.jqplot.Cursor.cursorLegendFormatString="%s x:%s, y:%s";j.jqplot.Cursor.init=function(t,s,r){var q=r||{};this.plugins.cursor=new j.jqplot.Cursor(q.cursor);var u=this.plugins.cursor;if(u.show){j.jqplot.eventListenerHooks.push(["jqplotMouseEnter",b]);j.jqplot.eventListenerHooks.push(["jqplotMouseLeave",f]);j.jqplot.eventListenerHooks.push(["jqplotMouseMove",i]);if(u.showCursorLegend){r.legend=r.legend||{};r.legend.renderer=j.jqplot.CursorLegendRenderer;r.legend.formatString=this.plugins.cursor.cursorLegendFormatString;r.legend.show=true}if(u.zoom){j.jqplot.eventListenerHooks.push(["jqplotMouseDown",a]);if(u.clickReset){j.jqplot.eventListenerHooks.push(["jqplotClick",k])}if(u.dblClickReset){j.jqplot.eventListenerHooks.push(["jqplotDblClick",c])}}this.resetZoom=function(){var x=this.axes;if(!u.zoomProxy){for(var w in x){x[w].reset();x[w]._ticks=[];if(u._zoom.axes[w]!==undefined){x[w]._autoFormatString=u._zoom.axes[w].tickFormatString}}this.redraw()}else{var v=this.plugins.cursor.zoomCanvas._ctx;v.clearRect(0,0,v.canvas.width,v.canvas.height);v=null}this.plugins.cursor._zoom.isZoomed=false;this.target.trigger("jqplotResetZoom",[this,this.plugins.cursor])};if(u.showTooltipDataPosition){u.showTooltipUnitPosition=false;u.showTooltipGridPosition=false;if(q.cursor.tooltipFormatString==undefined){u.tooltipFormatString=j.jqplot.Cursor.cursorLegendFormatString}}}};j.jqplot.Cursor.postDraw=function(){var x=this.plugins.cursor;if(x.zoomCanvas){x.zoomCanvas.resetCanvas();x.zoomCanvas=null}if(x.cursorCanvas){x.cursorCanvas.resetCanvas();x.cursorCanvas=null}if(x._tooltipElem){x._tooltipElem.emptyForce();x._tooltipElem=null}if(x.zoom){x.zoomCanvas=new j.jqplot.GenericCanvas();this.eventCanvas._elem.before(x.zoomCanvas.createElement(this._gridPadding,"jqplot-zoom-canvas",this._plotDimensions,this));x.zoomCanvas.setContext()}var v=document.createElement("div");x._tooltipElem=j(v);v=null;x._tooltipElem.addClass("jqplot-cursor-tooltip");x._tooltipElem.css({position:"absolute",display:"none"});if(x.zoomCanvas){x.zoomCanvas._elem.before(x._tooltipElem)}else{this.eventCanvas._elem.before(x._tooltipElem)}if(x.showVerticalLine||x.showHorizontalLine){x.cursorCanvas=new j.jqplot.GenericCanvas();this.eventCanvas._elem.before(x.cursorCanvas.createElement(this._gridPadding,"jqplot-cursor-canvas",this._plotDimensions,this));x.cursorCanvas.setContext()}if(x.showTooltipUnitPosition){if(x.tooltipAxisGroups.length===0){var t=this.series;var u;var q=[];for(var r=0;r<t.length;r++){u=t[r];var w=u.xaxis+","+u.yaxis;if(j.inArray(w,q)==-1){q.push(w)}}for(var r=0;r<q.length;r++){x.tooltipAxisGroups.push(q[r].split(","))}}}};j.jqplot.Cursor.zoomProxy=function(v,r){var q=v.plugins.cursor;var u=r.plugins.cursor;q.zoomTarget=true;q.zoom=true;q.style="auto";q.dblClickReset=false;u.zoom=true;u.zoomProxy=true;r.target.bind("jqplotZoom",t);r.target.bind("jqplotResetZoom",s);function t(x,w,z,y,A){q.doZoom(w,z,v,A)}function s(w,x,y){v.resetZoom()}};j.jqplot.Cursor.prototype.resetZoom=function(u,v){var t=u.axes;var s=v._zoom.axes;if(!u.plugins.cursor.zoomProxy&&v._zoom.isZoomed){for(var r in t){t[r].reset();t[r]._ticks=[];t[r]._autoFormatString=s[r].tickFormatString}u.redraw();v._zoom.isZoomed=false}else{var q=v.zoomCanvas._ctx;q.clearRect(0,0,q.canvas.width,q.canvas.height);q=null}u.target.trigger("jqplotResetZoom",[u,v])};j.jqplot.Cursor.resetZoom=function(q){q.resetZoom()};j.jqplot.Cursor.prototype.doZoom=function(G,t,C,u){var I=u;var F=C.axes;var r=I._zoom.axes;var w=r.start;var s=r.end;var B,E,z,D,v,x,q,H,J;var A=C.plugins.cursor.zoomCanvas._ctx;if((I.constrainZoomTo=="none"&&Math.abs(G.x-I._zoom.start[0])>6&&Math.abs(G.y-I._zoom.start[1])>6)||(I.constrainZoomTo=="x"&&Math.abs(G.x-I._zoom.start[0])>6)||(I.constrainZoomTo=="y"&&Math.abs(G.y-I._zoom.start[1])>6)){if(!C.plugins.cursor.zoomProxy){for(var y in t){if(I._zoom.axes[y]==undefined){I._zoom.axes[y]={};I._zoom.axes[y].numberTicks=F[y].numberTicks;I._zoom.axes[y].tickInterval=F[y].tickInterval;I._zoom.axes[y].daTickInterval=F[y].daTickInterval;I._zoom.axes[y].min=F[y].min;I._zoom.axes[y].max=F[y].max;I._zoom.axes[y].tickFormatString=(F[y].tickOptions!=null)?F[y].tickOptions.formatString:""}if((I.constrainZoomTo=="none")||(I.constrainZoomTo=="x"&&y.charAt(0)=="x")||(I.constrainZoomTo=="y"&&y.charAt(0)=="y")){z=t[y];if(z!=null){if(z>w[y]){v=w[y];x=z}else{D=w[y]-z;v=z;x=w[y]}q=F[y];H=null;if(q.alignTicks){if(q.name==="x2axis"&&C.axes.xaxis.show){H=C.axes.xaxis.numberTicks}else{if(q.name.charAt(0)==="y"&&q.name!=="yaxis"&&q.name!=="yMidAxis"&&C.axes.yaxis.show){H=C.axes.yaxis.numberTicks}}}if(this.looseZoom&&(F[y].renderer.constructor===j.jqplot.LinearAxisRenderer||F[y].renderer.constructor===j.jqplot.LogAxisRenderer)){J=j.jqplot.LinearTickGenerator(v,x,q._scalefact,H);if(F[y].tickInset&&J[0]<F[y].min+F[y].tickInset*F[y].tickInterval){J[0]+=J[4];J[2]-=1}if(F[y].tickInset&&J[1]>F[y].max-F[y].tickInset*F[y].tickInterval){J[1]-=J[4];J[2]-=1}if(F[y].renderer.constructor===j.jqplot.LogAxisRenderer&&J[0]<F[y].min){J[0]+=J[4];J[2]-=1}F[y].min=J[0];F[y].max=J[1];F[y]._autoFormatString=J[3];F[y].numberTicks=J[2];F[y].tickInterval=J[4];F[y].daTickInterval=[J[4]/1000,"seconds"]}else{F[y].min=v;F[y].max=x;F[y].tickInterval=null;F[y].numberTicks=null;F[y].daTickInterval=null}F[y]._ticks=[]}}}A.clearRect(0,0,A.canvas.width,A.canvas.height);C.redraw();I._zoom.isZoomed=true;A=null}C.target.trigger("jqplotZoom",[G,t,C,u])}};j.jqplot.preInitHooks.push(j.jqplot.Cursor.init);j.jqplot.postDrawHooks.push(j.jqplot.Cursor.postDraw);function e(G,r,C){var J=C.plugins.cursor;var w="";var N=false;if(J.showTooltipGridPosition){w=G.x+", "+G.y;N=true}if(J.showTooltipUnitPosition){var F;for(var E=0;E<J.tooltipAxisGroups.length;E++){F=J.tooltipAxisGroups[E];if(N){w+="<br />"}if(J.useAxesFormatters){for(var D=0;D<F.length;D++){if(D){w+=", "}var H=C.axes[F[D]]._ticks[0].formatter;var B=C.axes[F[D]]._ticks[0].formatString;w+=H(B,r[F[D]])}}else{w+=j.jqplot.sprintf(J.tooltipFormatString,r[F[0]],r[F[1]])}N=true}}if(J.showTooltipDataPosition){var u=C.series;var M=d(C,G.x,G.y);var N=false;for(var E=0;E<u.length;E++){if(u[E].show){var y=u[E].index;var t=u[E].label.toString();var I=j.inArray(y,M.indices);var z=undefined;var x=undefined;if(I!=-1){var L=M.data[I].data;if(J.useAxesFormatters){var A=u[E]._xaxis._ticks[0].formatter;var q=u[E]._yaxis._ticks[0].formatter;var K=u[E]._xaxis._ticks[0].formatString;var v=u[E]._yaxis._ticks[0].formatString;z=A(K,L[0]);x=q(v,L[1])}else{z=L[0];x=L[1]}if(N){w+="<br />"}w+=j.jqplot.sprintf(J.tooltipFormatString,t,z,x);N=true}}}}J._tooltipElem.html(w)}function g(C,A){var E=A.plugins.cursor;var z=E.cursorCanvas._ctx;z.clearRect(0,0,z.canvas.width,z.canvas.height);if(E.showVerticalLine){E.shapeRenderer.draw(z,[[C.x,0],[C.x,z.canvas.height]])}if(E.showHorizontalLine){E.shapeRenderer.draw(z,[[0,C.y],[z.canvas.width,C.y]])}var G=d(A,C.x,C.y);if(E.showCursorLegend){var r=j(A.targetId+" td.jqplot-cursor-legend-label");for(var B=0;B<r.length;B++){var v=j(r[B]).data("seriesIndex");var t=A.series[v];var s=t.label.toString();var D=j.inArray(v,G.indices);var x=undefined;var w=undefined;if(D!=-1){var H=G.data[D].data;if(E.useAxesFormatters){var y=t._xaxis._ticks[0].formatter;var q=t._yaxis._ticks[0].formatter;var F=t._xaxis._ticks[0].formatString;var u=t._yaxis._ticks[0].formatString;x=y(F,H[0]);w=q(u,H[1])}else{x=H[0];w=H[1]}}if(A.legend.escapeHtml){j(r[B]).text(j.jqplot.sprintf(E.cursorLegendFormatString,s,x,w))}else{j(r[B]).html(j.jqplot.sprintf(E.cursorLegendFormatString,s,x,w))}}}z=null}function d(A,F,E){var B={indices:[],data:[]};var G,w,u,C,v,q,t;var z;var D=A.plugins.cursor;for(var w=0;w<A.series.length;w++){G=A.series[w];q=G.renderer;if(G.show){z=D.intersectionThreshold;if(G.showMarker){z+=G.markerRenderer.size/2}for(var v=0;v<G.gridData.length;v++){t=G.gridData[v];if(D.showVerticalLine){if(Math.abs(F-t[0])<=z){B.indices.push(w);B.data.push({seriesIndex:w,pointIndex:v,gridData:t,data:G.data[v]})}}}}}return B}function n(r,t){var v=t.plugins.cursor;var s=v._tooltipElem;switch(v.tooltipLocation){case"nw":var q=r.x+t._gridPadding.left-s.outerWidth(true)-v.tooltipOffset;var u=r.y+t._gridPadding.top-v.tooltipOffset-s.outerHeight(true);break;case"n":var q=r.x+t._gridPadding.left-s.outerWidth(true)/2;var u=r.y+t._gridPadding.top-v.tooltipOffset-s.outerHeight(true);break;case"ne":var q=r.x+t._gridPadding.left+v.tooltipOffset;var u=r.y+t._gridPadding.top-v.tooltipOffset-s.outerHeight(true);break;case"e":var q=r.x+t._gridPadding.left+v.tooltipOffset;var u=r.y+t._gridPadding.top-s.outerHeight(true)/2;break;case"se":var q=r.x+t._gridPadding.left+v.tooltipOffset;var u=r.y+t._gridPadding.top+v.tooltipOffset;break;case"s":var q=r.x+t._gridPadding.left-s.outerWidth(true)/2;var u=r.y+t._gridPadding.top+v.tooltipOffset;break;case"sw":var q=r.x+t._gridPadding.left-s.outerWidth(true)-v.tooltipOffset;var u=r.y+t._gridPadding.top+v.tooltipOffset;break;case"w":var q=r.x+t._gridPadding.left-s.outerWidth(true)-v.tooltipOffset;var u=r.y+t._gridPadding.top-s.outerHeight(true)/2;break;default:var q=r.x+t._gridPadding.left+v.tooltipOffset;var u=r.y+t._gridPadding.top+v.tooltipOffset;break}s.css("left",q);s.css("top",u);s=null}function m(u){var s=u._gridPadding;var v=u.plugins.cursor;var t=v._tooltipElem;switch(v.tooltipLocation){case"nw":var r=s.left+v.tooltipOffset;var q=s.top+v.tooltipOffset;t.css("left",r);t.css("top",q);break;case"n":var r=(s.left+(u._plotDimensions.width-s.right))/2-t.outerWidth(true)/2;var q=s.top+v.tooltipOffset;t.css("left",r);t.css("top",q);break;case"ne":var r=s.right+v.tooltipOffset;var q=s.top+v.tooltipOffset;t.css({right:r,top:q});break;case"e":var r=s.right+v.tooltipOffset;var q=(s.top+(u._plotDimensions.height-s.bottom))/2-t.outerHeight(true)/2;t.css({right:r,top:q});break;case"se":var r=s.right+v.tooltipOffset;var q=s.bottom+v.tooltipOffset;t.css({right:r,bottom:q});break;case"s":var r=(s.left+(u._plotDimensions.width-s.right))/2-t.outerWidth(true)/2;var q=s.bottom+v.tooltipOffset;t.css({left:r,bottom:q});break;case"sw":var r=s.left+v.tooltipOffset;var q=s.bottom+v.tooltipOffset;t.css({left:r,bottom:q});break;case"w":var r=s.left+v.tooltipOffset;var q=(s.top+(u._plotDimensions.height-s.bottom))/2-t.outerHeight(true)/2;t.css({left:r,top:q});break;default:var r=s.right-v.tooltipOffset;var q=s.bottom+v.tooltipOffset;t.css({right:r,bottom:q});break}t=null}function k(r,q,v,u,t){r.preventDefault();r.stopImmediatePropagation();var w=t.plugins.cursor;if(w.clickReset){w.resetZoom(t,w)}var s=window.getSelection;if(document.selection&&document.selection.empty){document.selection.empty()}else{if(s&&!s().isCollapsed){s().collapse()}}return false}function c(r,q,v,u,t){r.preventDefault();r.stopImmediatePropagation();var w=t.plugins.cursor;if(w.dblClickReset){w.resetZoom(t,w)}var s=window.getSelection;if(document.selection&&document.selection.empty){document.selection.empty()}else{if(s&&!s().isCollapsed){s().collapse()}}return false}function f(w,t,q,z,u){var v=u.plugins.cursor;v.onGrid=false;if(v.show){j(w.target).css("cursor",v.previousCursor);if(v.showTooltip&&!(v._zoom.zooming&&v.showTooltipOutsideZoom&&!v.constrainOutsideZoom)){v._tooltipElem.empty();v._tooltipElem.hide()}if(v.zoom){v._zoom.gridpos=t;v._zoom.datapos=q}if(v.showVerticalLine||v.showHorizontalLine){var B=v.cursorCanvas._ctx;B.clearRect(0,0,B.canvas.width,B.canvas.height);B=null}if(v.showCursorLegend){var A=j(u.targetId+" td.jqplot-cursor-legend-label");for(var s=0;s<A.length;s++){var y=j(A[s]).data("seriesIndex");var r=u.series[y];var x=r.label.toString();if(u.legend.escapeHtml){j(A[s]).text(j.jqplot.sprintf(v.cursorLegendFormatString,x,undefined,undefined))}else{j(A[s]).html(j.jqplot.sprintf(v.cursorLegendFormatString,x,undefined,undefined))}}}}}function b(r,q,u,t,s){var v=s.plugins.cursor;v.onGrid=true;if(v.show){v.previousCursor=r.target.style.cursor;r.target.style.cursor=v.style;if(v.showTooltip){e(q,u,s);if(v.followMouse){n(q,s)}else{m(s)}v._tooltipElem.show()}if(v.showVerticalLine||v.showHorizontalLine){g(q,s)}}}function i(r,q,u,t,s){var v=s.plugins.cursor;if(v.show){if(v.showTooltip){e(q,u,s);if(v.followMouse){n(q,s)}}if(v.showVerticalLine||v.showHorizontalLine){g(q,s)}}}function o(y){var x=y.data.plot;var t=x.eventCanvas._elem.offset();var w={x:y.pageX-t.left,y:y.pageY-t.top};var u={xaxis:null,yaxis:null,x2axis:null,y2axis:null,y3axis:null,y4axis:null,y5axis:null,y6axis:null,y7axis:null,y8axis:null,y9axis:null,yMidAxis:null};var v=["xaxis","yaxis","x2axis","y2axis","y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];var q=x.axes;var r,s;for(r=11;r>0;r--){s=v[r-1];if(q[s].show){u[s]=q[s].series_p2u(w[s.charAt(0)])}}return{offsets:t,gridPos:w,dataPos:u}}function h(z){var x=z.data.plot;var y=x.plugins.cursor;if(y.show&&y.zoom&&y._zoom.started&&!y.zoomTarget){z.preventDefault();var B=y.zoomCanvas._ctx;var v=o(z);var w=v.gridPos;var t=v.dataPos;y._zoom.gridpos=w;y._zoom.datapos=t;y._zoom.zooming=true;var u=w.x;var s=w.y;var A=B.canvas.height;var q=B.canvas.width;if(y.showTooltip&&!y.onGrid&&y.showTooltipOutsideZoom){e(w,t,x);if(y.followMouse){n(w,x)}}if(y.constrainZoomTo=="x"){y._zoom.end=[u,A]}else{if(y.constrainZoomTo=="y"){y._zoom.end=[q,s]}else{y._zoom.end=[u,s]}}var r=window.getSelection;if(document.selection&&document.selection.empty){document.selection.empty()}else{if(r&&!r().isCollapsed){r().collapse()}}l.call(y);B=null}}function a(w,s,r,x,t){var v=t.plugins.cursor;if(t.plugins.mobile){j(document).one("vmouseup.jqplot_cursor",{plot:t},p)}else{j(document).one("mouseup.jqplot_cursor",{plot:t},p)}var u=t.axes;if(document.onselectstart!=undefined){v._oldHandlers.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!=undefined){v._oldHandlers.ondrag=document.ondrag;document.ondrag=function(){return false}}if(document.onmousedown!=undefined){v._oldHandlers.onmousedown=document.onmousedown;document.onmousedown=function(){return false}}if(v.zoom){if(!v.zoomProxy){var y=v.zoomCanvas._ctx;y.clearRect(0,0,y.canvas.width,y.canvas.height);y=null}if(v.constrainZoomTo=="x"){v._zoom.start=[s.x,0]}else{if(v.constrainZoomTo=="y"){v._zoom.start=[0,s.y]}else{v._zoom.start=[s.x,s.y]}}v._zoom.started=true;for(var q in r){v._zoom.axes.start[q]=r[q]}if(t.plugins.mobile){j(document).bind("vmousemove.jqplotCursor",{plot:t},h)}else{j(document).bind("mousemove.jqplotCursor",{plot:t},h)}}}function p(y){var v=y.data.plot;var x=v.plugins.cursor;if(x.zoom&&x._zoom.zooming&&!x.zoomTarget){var u=x._zoom.gridpos.x;var r=x._zoom.gridpos.y;var t=x._zoom.datapos;var z=x.zoomCanvas._ctx.canvas.height;var q=x.zoomCanvas._ctx.canvas.width;var w=v.axes;if(x.constrainOutsideZoom&&!x.onGrid){if(u<0){u=0}else{if(u>q){u=q}}if(r<0){r=0}else{if(r>z){r=z}}for(var s in t){if(t[s]){if(s.charAt(0)=="x"){t[s]=w[s].series_p2u(u)}else{t[s]=w[s].series_p2u(r)}}}}if(x.constrainZoomTo=="x"){r=z}else{if(x.constrainZoomTo=="y"){u=q}}x._zoom.end=[u,r];x._zoom.gridpos={x:u,y:r};x.doZoom(x._zoom.gridpos,t,v,x)}x._zoom.started=false;x._zoom.zooming=false;j(document).unbind("mousemove.jqplotCursor",h);if(document.onselectstart!=undefined&&x._oldHandlers.onselectstart!=null){document.onselectstart=x._oldHandlers.onselectstart;x._oldHandlers.onselectstart=null}if(document.ondrag!=undefined&&x._oldHandlers.ondrag!=null){document.ondrag=x._oldHandlers.ondrag;x._oldHandlers.ondrag=null}if(document.onmousedown!=undefined&&x._oldHandlers.onmousedown!=null){document.onmousedown=x._oldHandlers.onmousedown;x._oldHandlers.onmousedown=null}}function l(){var y=this._zoom.start;var u=this._zoom.end;var s=this.zoomCanvas._ctx;var r,v,x,q;if(u[0]>y[0]){r=y[0];q=u[0]-y[0]}else{r=u[0];q=y[0]-u[0]}if(u[1]>y[1]){v=y[1];x=u[1]-y[1]}else{v=u[1];x=y[1]-u[1]}s.fillStyle="rgba(0,0,0,0.2)";s.strokeStyle="#999999";s.lineWidth=1;s.clearRect(0,0,s.canvas.width,s.canvas.height);s.fillRect(0,0,s.canvas.width,s.canvas.height);s.clearRect(r,v,q,x);s.strokeRect(r,v,q,x);s=null}j.jqplot.CursorLegendRenderer=function(q){j.jqplot.TableLegendRenderer.call(this,q);this.formatString="%s"};j.jqplot.CursorLegendRenderer.prototype=new j.jqplot.TableLegendRenderer();j.jqplot.CursorLegendRenderer.prototype.constructor=j.jqplot.CursorLegendRenderer;j.jqplot.CursorLegendRenderer.prototype.draw=function(){if(this._elem){this._elem.emptyForce();this._elem=null}if(this.show){var w=this._series,A;var r=document.createElement("table");this._elem=j(r);r=null;this._elem.addClass("jqplot-legend jqplot-cursor-legend");this._elem.css("position","absolute");var q=false;for(var x=0;x<w.length;x++){A=w[x];if(A.show&&A.showLabel){var v=j.jqplot.sprintf(this.formatString,A.label.toString());if(v){var t=A.color;if(A._stack&&!A.fill){t=""}z.call(this,v,t,q,x);q=true}for(var u=0;u<j.jqplot.addLegendRowHooks.length;u++){var y=j.jqplot.addLegendRowHooks[u].call(this,A);if(y){z.call(this,y.label,y.color,q);q=true}}}}w=A=null;delete w;delete A}function z(D,C,F,s){var B=(F)?this.rowSpacing:"0";var E=j('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem);E.data("seriesIndex",s);j('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+B+';"><div style="border:1px solid #cccccc;padding:0.2em;"><div class="jqplot-cursor-legend-swatch" style="background-color:'+C+';"></div></div></td>').appendTo(E);var G=j('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+B+';"></td>');G.appendTo(E);G.data("seriesIndex",s);if(this.escapeHtml){G.text(D)}else{G.html(D)}E=null;G=null}return this._elem}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.dateAxisRenderer.js b/plugin/jqplot/plugins/jqplot.dateAxisRenderer.js new file mode 100644 index 000000000..e371a28da --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.dateAxisRenderer.js @@ -0,0 +1,741 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.DateAxisRenderer + * A plugin for a jqPlot to render an axis as a series of date values. + * This renderer has no options beyond those supplied by the <Axis> class. + * It supplies its own tick formatter, so the tickOptions.formatter option + * should not be overridden. + * + * Thanks to Ken Synder for his enhanced Date instance methods which are + * included with this code <http://kendsnyder.com/sandbox/date/>. + * + * To use this renderer, include the plugin in your source + * > <script type="text/javascript" language="javascript" src="plugins/jqplot.dateAxisRenderer.js"></script> + * + * and supply the appropriate options to your plot + * + * > {axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer}}} + * + * Dates can be passed into the axis in almost any recognizable value and + * will be parsed. They will be rendered on the axis in the format + * specified by tickOptions.formatString. e.g. tickOptions.formatString = '%Y-%m-%d'. + * + * Accecptable format codes + * are: + * + * > Code Result Description + * > == Years == + * > %Y 2008 Four-digit year + * > %y 08 Two-digit year + * > == Months == + * > %m 09 Two-digit month + * > %#m 9 One or two-digit month + * > %B September Full month name + * > %b Sep Abbreviated month name + * > == Days == + * > %d 05 Two-digit day of month + * > %#d 5 One or two-digit day of month + * > %e 5 One or two-digit day of month + * > %A Sunday Full name of the day of the week + * > %a Sun Abbreviated name of the day of the week + * > %w 0 Number of the day of the week (0 = Sunday, 6 = Saturday) + * > %o th The ordinal suffix string following the day of the month + * > == Hours == + * > %H 23 Hours in 24-hour format (two digits) + * > %#H 3 Hours in 24-hour integer format (one or two digits) + * > %I 11 Hours in 12-hour format (two digits) + * > %#I 3 Hours in 12-hour integer format (one or two digits) + * > %p PM AM or PM + * > == Minutes == + * > %M 09 Minutes (two digits) + * > %#M 9 Minutes (one or two digits) + * > == Seconds == + * > %S 02 Seconds (two digits) + * > %#S 2 Seconds (one or two digits) + * > %s 1206567625723 Unix timestamp (Seconds past 1970-01-01 00:00:00) + * > == Milliseconds == + * > %N 008 Milliseconds (three digits) + * > %#N 8 Milliseconds (one to three digits) + * > == Timezone == + * > %O 360 difference in minutes between local time and GMT + * > %Z Mountain Standard Time Name of timezone as reported by browser + * > %G -06:00 Hours and minutes between GMT + * > == Shortcuts == + * > %F 2008-03-26 %Y-%m-%d + * > %T 05:06:30 %H:%M:%S + * > %X 05:06:30 %H:%M:%S + * > %x 03/26/08 %m/%d/%y + * > %D 03/26/08 %m/%d/%y + * > %#c Wed Mar 26 15:31:00 2008 %a %b %e %H:%M:%S %Y + * > %v 3-Sep-2008 %e-%b-%Y + * > %R 15:31 %H:%M + * > %r 3:31:00 PM %I:%M:%S %p + * > == Characters == + * > %n \n Newline + * > %t \t Tab + * > %% % Percent Symbol + */ + $.jqplot.DateAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + this.date = new $.jsDate(); + }; + + var second = 1000; + var minute = 60 * second; + var hour = 60 * minute; + var day = 24 * hour; + var week = 7 * day; + + // these are less definitive + var month = 30.4368499 * day; + var year = 365.242199 * day; + + var daysInMonths = [31,28,31,30,31,30,31,30,31,30,31,30]; + // array of consistent nice intervals. Longer intervals + // will depend on days in month, days in year, etc. + var niceFormatStrings = ['%M:%S.%#N', '%M:%S.%#N', '%M:%S.%#N', '%M:%S', '%M:%S', '%M:%S', '%M:%S', '%H:%M:%S', '%H:%M:%S', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%a %H:%M', '%a %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%v', '%v', '%v', '%v', '%v', '%v', '%v']; + var niceIntervals = [0.1*second, 0.2*second, 0.5*second, second, 2*second, 5*second, 10*second, 15*second, 30*second, minute, 2*minute, 5*minute, 10*minute, 15*minute, 30*minute, hour, 2*hour, 4*hour, 6*hour, 8*hour, 12*hour, day, 2*day, 3*day, 4*day, 5*day, week, 2*week]; + + var niceMonthlyIntervals = []; + + function bestDateInterval(min, max, titarget) { + // iterate through niceIntervals to find one closest to titarget + var badness = Number.MAX_VALUE; + var temp, bestTi, bestfmt; + for (var i=0, l=niceIntervals.length; i < l; i++) { + temp = Math.abs(titarget - niceIntervals[i]); + if (temp < badness) { + badness = temp; + bestTi = niceIntervals[i]; + bestfmt = niceFormatStrings[i]; + } + } + + return [bestTi, bestfmt]; + } + + $.jqplot.DateAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.DateAxisRenderer.prototype.constructor = $.jqplot.DateAxisRenderer; + + $.jqplot.DateTickFormatter = function(format, val) { + if (!format) { + format = '%Y/%m/%d'; + } + return $.jsDate.strftime(val, format); + }; + + $.jqplot.DateAxisRenderer.prototype.init = function(options){ + // prop: tickRenderer + // A class of a rendering engine for creating the ticks labels displayed on the plot, + // See <$.jqplot.AxisTickRenderer>. + // this.tickRenderer = $.jqplot.AxisTickRenderer; + // this.labelRenderer = $.jqplot.AxisLabelRenderer; + this.tickOptions.formatter = $.jqplot.DateTickFormatter; + // prop: tickInset + // Controls the amount to inset the first and last ticks from + // the edges of the grid, in multiples of the tick interval. + // 0 is no inset, 0.5 is one half a tick interval, 1 is a full + // tick interval, etc. + this.tickInset = 0; + // prop: drawBaseline + // True to draw the axis baseline. + this.drawBaseline = true; + // prop: baselineWidth + // width of the baseline in pixels. + this.baselineWidth = null; + // prop: baselineColor + // CSS color spec for the baseline. + this.baselineColor = null; + this.daTickInterval = null; + this._daTickInterval = null; + + $.extend(true, this, options); + + var db = this._dataBounds, + stats, + sum, + s, + d, + pd, + sd, + intv; + + // Go through all the series attached to this axis and find + // the min/max bounds for this axis. + for (var i=0; i<this._series.length; i++) { + stats = {intervals:[], frequencies:{}, sortedIntervals:[], min:null, max:null, mean:null}; + sum = 0; + s = this._series[i]; + d = s.data; + pd = s._plotData; + sd = s._stackData; + intv = 0; + + for (var j=0; j<d.length; j++) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + d[j][0] = new $.jsDate(d[j][0]).getTime(); + pd[j][0] = new $.jsDate(d[j][0]).getTime(); + sd[j][0] = new $.jsDate(d[j][0]).getTime(); + if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) { + db.min = d[j][0]; + } + if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) { + db.max = d[j][0]; + } + if (j>0) { + intv = Math.abs(d[j][0] - d[j-1][0]); + stats.intervals.push(intv); + if (stats.frequencies.hasOwnProperty(intv)) { + stats.frequencies[intv] += 1; + } + else { + stats.frequencies[intv] = 1; + } + } + sum += intv; + + } + else { + d[j][1] = new $.jsDate(d[j][1]).getTime(); + pd[j][1] = new $.jsDate(d[j][1]).getTime(); + sd[j][1] = new $.jsDate(d[j][1]).getTime(); + if ((d[j][1] != null && d[j][1] < db.min) || db.min == null) { + db.min = d[j][1]; + } + if ((d[j][1] != null && d[j][1] > db.max) || db.max == null) { + db.max = d[j][1]; + } + if (j>0) { + intv = Math.abs(d[j][1] - d[j-1][1]); + stats.intervals.push(intv); + if (stats.frequencies.hasOwnProperty(intv)) { + stats.frequencies[intv] += 1; + } + else { + stats.frequencies[intv] = 1; + } + } + } + sum += intv; + } + + if (s.renderer.bands) { + if (s.renderer.bands.hiData.length) { + var bd = s.renderer.bands.hiData; + for (var j=0, l=bd.length; j < l; j++) { + if (this.name === 'xaxis' || this.name === 'x2axis') { + bd[j][0] = new $.jsDate(bd[j][0]).getTime(); + if ((bd[j][0] != null && bd[j][0] > db.max) || db.max == null) { + db.max = bd[j][0]; + } + } + else { + bd[j][1] = new $.jsDate(bd[j][1]).getTime(); + if ((bd[j][1] != null && bd[j][1] > db.max) || db.max == null) { + db.max = bd[j][1]; + } + } + } + } + if (s.renderer.bands.lowData.length) { + var bd = s.renderer.bands.lowData; + for (var j=0, l=bd.length; j < l; j++) { + if (this.name === 'xaxis' || this.name === 'x2axis') { + bd[j][0] = new $.jsDate(bd[j][0]).getTime(); + if ((bd[j][0] != null && bd[j][0] < db.min) || db.min == null) { + db.min = bd[j][0]; + } + } + else { + bd[j][1] = new $.jsDate(bd[j][1]).getTime(); + if ((bd[j][1] != null && bd[j][1] < db.min) || db.min == null) { + db.min = bd[j][1]; + } + } + } + } + } + + var tempf = 0, + tempn=0; + for (var n in stats.frequencies) { + stats.sortedIntervals.push({interval:n, frequency:stats.frequencies[n]}); + } + stats.sortedIntervals.sort(function(a, b){ + return b.frequency - a.frequency; + }); + + stats.min = $.jqplot.arrayMin(stats.intervals); + stats.max = $.jqplot.arrayMax(stats.intervals); + stats.mean = sum/d.length; + this._intervalStats.push(stats); + stats = sum = s = d = pd = sd = null; + } + db = null; + + }; + + // called with scope of an axis + $.jqplot.DateAxisRenderer.prototype.reset = function() { + this.min = this._options.min; + this.max = this._options.max; + this.tickInterval = this._options.tickInterval; + this.numberTicks = this._options.numberTicks; + this._autoFormatString = ''; + if (this._overrideFormatString && this.tickOptions && this.tickOptions.formatString) { + this.tickOptions.formatString = ''; + } + this.daTickInterval = this._daTickInterval; + // this._ticks = this.__ticks; + }; + + $.jqplot.DateAxisRenderer.prototype.createTicks = function(plot) { + // we're are operating on an axis here + var ticks = this._ticks; + var userTicks = this.ticks; + var name = this.name; + // databounds were set on axis initialization. + var db = this._dataBounds; + var iv = this._intervalStats; + var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height; + var interval; + var min, max; + var pos1, pos2; + var tt, i; + var threshold = 30; + var insetMult = 1; + var daTickInterval = null; + + // if user specified a tick interval, convert to usable. + if (this.tickInterval != null) + { + // if interval is a number or can be converted to one, use it. + // Assume it is in SECONDS!!! + if (Number(this.tickInterval)) { + daTickInterval = [Number(this.tickInterval), 'seconds']; + } + // else, parse out something we can build from. + else if (typeof this.tickInterval == "string") { + var parts = this.tickInterval.split(' '); + if (parts.length == 1) { + daTickInterval = [1, parts[0]]; + } + else if (parts.length == 2) { + daTickInterval = [parts[0], parts[1]]; + } + } + } + + var tickInterval = this.tickInterval; + + // if we already have ticks, use them. + // ticks must be in order of increasing value. + + min = new $.jsDate((this.min != null) ? this.min : db.min).getTime(); + max = new $.jsDate((this.max != null) ? this.max : db.max).getTime(); + + // see if we're zooming. if we are, don't use the min and max we're given, + // but compute some nice ones. They will be reset later. + + var cursor = plot.plugins.cursor; + + if (cursor && cursor._zoom && cursor._zoom.zooming) { + this.min = null; + this.max = null; + } + + var range = max - min; + + if (this.tickOptions == null || !this.tickOptions.formatString) { + this._overrideFormatString = true; + } + + if (userTicks.length) { + // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed + for (i=0; i<userTicks.length; i++){ + var ut = userTicks[i]; + var t = new this.tickRenderer(this.tickOptions); + if (ut.constructor == Array) { + t.value = new $.jsDate(ut[0]).getTime(); + t.label = ut[1]; + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(t.value, this.name); + this._ticks.push(t); + } + + else { + t.value = new $.jsDate(ut).getTime(); + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(t.value, this.name); + this._ticks.push(t); + } + } + this.numberTicks = userTicks.length; + this.min = this._ticks[0].value; + this.max = this._ticks[this.numberTicks-1].value; + this.daTickInterval = [(this.max - this.min) / (this.numberTicks - 1)/1000, 'seconds']; + } + + //////// + // We don't have any ticks yet, let's make some! + //////// + + // special case when there is only one point, make three tick marks to center the point + else if (this.min == null && this.max == null && db.min == db.max) + { + var onePointOpts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null}); + var delta = 300000; + this.min = db.min - delta; + this.max = db.max + delta; + this.numberTicks = 3; + + for(var i=this.min;i<=this.max;i+= delta) + { + onePointOpts.value = i; + + var t = new this.tickRenderer(onePointOpts); + + if (this._overrideFormatString && this._autoFormatString != '') { + t.formatString = this._autoFormatString; + } + + t.showLabel = false; + t.showMark = false; + + this._ticks.push(t); + } + + if(this.showTicks) { + this._ticks[1].showLabel = true; + } + if(this.showTickMarks) { + this._ticks[1].showTickMarks = true; + } + } + // if user specified min and max are null, we set those to make best ticks. + else if (this.min == null && this.max == null) { + + var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null}); + + // want to find a nice interval + var nttarget, + titarget; + + // if no tickInterval or numberTicks options specified, make a good guess. + if (!this.tickInterval && !this.numberTicks) { + var tdim = Math.max(dim, threshold+1); + // how many ticks to put on the axis? + // date labels tend to be long. If ticks not rotated, + // don't use too many and have a high spacing factor. + // If we are rotating ticks, use a lower factor. + var spacingFactor = 115; + if (this.tickRenderer === $.jqplot.CanvasAxisTickRenderer && this.tickOptions.angle) { + spacingFactor = 115 - 40 * Math.abs(Math.sin(this.tickOptions.angle/180*Math.PI)); + } + + nttarget = Math.ceil((tdim-threshold)/spacingFactor + 1); + titarget = (max - min) / (nttarget - 1); + } + + // If tickInterval is specified, we'll try to honor it. + // Not guaranteed to get this interval, but we'll get as close as + // we can. + // tickInterval will be used before numberTicks, that is if + // both are specified, numberTicks will be ignored. + else if (this.tickInterval) { + titarget = new $.jsDate(0).add(daTickInterval[0], daTickInterval[1]).getTime(); + } + + // if numberTicks specified, try to honor it. + // Not guaranteed, but will try to get close. + else if (this.numberTicks) { + nttarget = this.numberTicks; + titarget = (max - min) / (nttarget - 1); + } + + // If we can use an interval of 2 weeks or less, pick best one + if (titarget <= 19*day) { + var ret = bestDateInterval(min, max, titarget); + var tempti = ret[0]; + this._autoFormatString = ret[1]; + + min = new $.jsDate(min); + min = Math.floor((min.getTime() - min.getUtcOffset())/tempti) * tempti + min.getUtcOffset(); + + nttarget = Math.ceil((max - min) / tempti) + 1; + this.min = min; + this.max = min + (nttarget - 1) * tempti; + + // if max is less than max, add an interval + if (this.max < max) { + this.max += tempti; + nttarget += 1; + } + this.tickInterval = tempti; + this.numberTicks = nttarget; + + for (var i=0; i<nttarget; i++) { + opts.value = this.min + i * tempti; + t = new this.tickRenderer(opts); + + if (this._overrideFormatString && this._autoFormatString != '') { + t.formatString = this._autoFormatString; + } + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + this._ticks.push(t); + } + + insetMult = this.tickInterval; + } + + // should we use a monthly interval? + else if (titarget <= 9 * month) { + + this._autoFormatString = '%v'; + + // how many months in an interval? + var intv = Math.round(titarget/month); + if (intv < 1) { + intv = 1; + } + else if (intv > 6) { + intv = 6; + } + + // figure out the starting month and ending month. + var mstart = new $.jsDate(min).setDate(1).setHours(0,0,0,0); + + // See if max ends exactly on a month + var tempmend = new $.jsDate(max); + var mend = new $.jsDate(max).setDate(1).setHours(0,0,0,0); + + if (tempmend.getTime() !== mend.getTime()) { + mend = mend.add(1, 'month'); + } + + var nmonths = mend.diff(mstart, 'month'); + + nttarget = Math.ceil(nmonths/intv) + 1; + + this.min = mstart.getTime(); + this.max = mstart.clone().add((nttarget - 1) * intv, 'month').getTime(); + this.numberTicks = nttarget; + + for (var i=0; i<nttarget; i++) { + if (i === 0) { + opts.value = mstart.getTime(); + } + else { + opts.value = mstart.add(intv, 'month').getTime(); + } + t = new this.tickRenderer(opts); + + if (this._overrideFormatString && this._autoFormatString != '') { + t.formatString = this._autoFormatString; + } + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + this._ticks.push(t); + } + + insetMult = intv * month; + } + + // use yearly intervals + else { + + this._autoFormatString = '%v'; + + // how many years in an interval? + var intv = Math.round(titarget/year); + if (intv < 1) { + intv = 1; + } + + // figure out the starting and ending years. + var mstart = new $.jsDate(min).setMonth(0, 1).setHours(0,0,0,0); + var mend = new $.jsDate(max).add(1, 'year').setMonth(0, 1).setHours(0,0,0,0); + + var nyears = mend.diff(mstart, 'year'); + + nttarget = Math.ceil(nyears/intv) + 1; + + this.min = mstart.getTime(); + this.max = mstart.clone().add((nttarget - 1) * intv, 'year').getTime(); + this.numberTicks = nttarget; + + for (var i=0; i<nttarget; i++) { + if (i === 0) { + opts.value = mstart.getTime(); + } + else { + opts.value = mstart.add(intv, 'year').getTime(); + } + t = new this.tickRenderer(opts); + + if (this._overrideFormatString && this._autoFormatString != '') { + t.formatString = this._autoFormatString; + } + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + this._ticks.push(t); + } + + insetMult = intv * year; + } + } + + //////// + // Some option(s) specified, work around that. + //////// + + else { + if (name == 'xaxis' || name == 'x2axis') { + dim = this._plotDimensions.width; + } + else { + dim = this._plotDimensions.height; + } + + // if min, max and number of ticks specified, user can't specify interval. + if (this.min != null && this.max != null && this.numberTicks != null) { + this.tickInterval = null; + } + + if (this.tickInterval != null && daTickInterval != null) { + this.daTickInterval = daTickInterval; + } + + // if min and max are same, space them out a bit + if (min == max) { + var adj = 24*60*60*500; // 1/2 day + min -= adj; + max += adj; + } + + range = max - min; + + var optNumTicks = 2 + parseInt(Math.max(0, dim-100)/100, 10); + + + var rmin, rmax; + + rmin = (this.min != null) ? new $.jsDate(this.min).getTime() : min - range/2*(this.padMin - 1); + rmax = (this.max != null) ? new $.jsDate(this.max).getTime() : max + range/2*(this.padMax - 1); + this.min = rmin; + this.max = rmax; + range = this.max - this.min; + + if (this.numberTicks == null){ + // if tickInterval is specified by user, we will ignore computed maximum. + // max will be equal or greater to fit even # of ticks. + if (this.daTickInterval != null) { + var nc = new $.jsDate(this.max).diff(this.min, this.daTickInterval[1], true); + this.numberTicks = Math.ceil(nc/this.daTickInterval[0]) +1; + // this.max = new $.jsDate(this.min).add(this.numberTicks-1, this.daTickInterval[1]).getTime(); + this.max = new $.jsDate(this.min).add((this.numberTicks-1) * this.daTickInterval[0], this.daTickInterval[1]).getTime(); + } + else if (dim > 200) { + this.numberTicks = parseInt(3+(dim-200)/100, 10); + } + else { + this.numberTicks = 2; + } + } + + insetMult = range / (this.numberTicks-1)/1000; + + if (this.daTickInterval == null) { + this.daTickInterval = [insetMult, 'seconds']; + } + + + for (var i=0; i<this.numberTicks; i++){ + var min = new $.jsDate(this.min); + tt = min.add(i*this.daTickInterval[0], this.daTickInterval[1]).getTime(); + var t = new this.tickRenderer(this.tickOptions); + // var t = new $.jqplot.AxisTickRenderer(this.tickOptions); + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(tt, this.name); + this._ticks.push(t); + } + } + + if (this.tickInset) { + this.min = this.min - this.tickInset * insetMult; + this.max = this.max + this.tickInset * insetMult; + } + + if (this._daTickInterval == null) { + this._daTickInterval = this.daTickInterval; + } + + ticks = null; + }; + +})(jQuery); + diff --git a/plugin/jqplot/plugins/jqplot.dateAxisRenderer.min.js b/plugin/jqplot/plugins/jqplot.dateAxisRenderer.min.js new file mode 100644 index 000000000..741780150 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.dateAxisRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(h){h.jqplot.DateAxisRenderer=function(){h.jqplot.LinearAxisRenderer.call(this);this.date=new h.jsDate()};var c=1000;var e=60*c;var f=60*e;var l=24*f;var b=7*l;var j=30.4368499*l;var k=365.242199*l;var g=[31,28,31,30,31,30,31,30,31,30,31,30];var i=["%M:%S.%#N","%M:%S.%#N","%M:%S.%#N","%M:%S","%M:%S","%M:%S","%M:%S","%H:%M:%S","%H:%M:%S","%H:%M","%H:%M","%H:%M","%H:%M","%H:%M","%H:%M","%a %H:%M","%a %H:%M","%b %e %H:%M","%b %e %H:%M","%b %e %H:%M","%b %e %H:%M","%v","%v","%v","%v","%v","%v","%v"];var m=[0.1*c,0.2*c,0.5*c,c,2*c,5*c,10*c,15*c,30*c,e,2*e,5*e,10*e,15*e,30*e,f,2*f,4*f,6*f,8*f,12*f,l,2*l,3*l,4*l,5*l,b,2*b];var d=[];function a(p,s,t){var o=Number.MAX_VALUE;var u,r,v;for(var q=0,n=m.length;q<n;q++){u=Math.abs(t-m[q]);if(u<o){o=u;r=m[q];v=i[q]}}return[r,v]}h.jqplot.DateAxisRenderer.prototype=new h.jqplot.LinearAxisRenderer();h.jqplot.DateAxisRenderer.prototype.constructor=h.jqplot.DateAxisRenderer;h.jqplot.DateTickFormatter=function(n,o){if(!n){n="%Y/%m/%d"}return h.jsDate.strftime(o,n)};h.jqplot.DateAxisRenderer.prototype.init=function(E){this.tickOptions.formatter=h.jqplot.DateTickFormatter;this.tickInset=0;this.drawBaseline=true;this.baselineWidth=null;this.baselineColor=null;this.daTickInterval=null;this._daTickInterval=null;h.extend(true,this,E);var C=this._dataBounds,u,x,D,y,A,z,o;for(var t=0;t<this._series.length;t++){u={intervals:[],frequencies:{},sortedIntervals:[],min:null,max:null,mean:null};x=0;D=this._series[t];y=D.data;A=D._plotData;z=D._stackData;o=0;for(var r=0;r<y.length;r++){if(this.name=="xaxis"||this.name=="x2axis"){y[r][0]=new h.jsDate(y[r][0]).getTime();A[r][0]=new h.jsDate(y[r][0]).getTime();z[r][0]=new h.jsDate(y[r][0]).getTime();if((y[r][0]!=null&&y[r][0]<C.min)||C.min==null){C.min=y[r][0]}if((y[r][0]!=null&&y[r][0]>C.max)||C.max==null){C.max=y[r][0]}if(r>0){o=Math.abs(y[r][0]-y[r-1][0]);u.intervals.push(o);if(u.frequencies.hasOwnProperty(o)){u.frequencies[o]+=1}else{u.frequencies[o]=1}}x+=o}else{y[r][1]=new h.jsDate(y[r][1]).getTime();A[r][1]=new h.jsDate(y[r][1]).getTime();z[r][1]=new h.jsDate(y[r][1]).getTime();if((y[r][1]!=null&&y[r][1]<C.min)||C.min==null){C.min=y[r][1]}if((y[r][1]!=null&&y[r][1]>C.max)||C.max==null){C.max=y[r][1]}if(r>0){o=Math.abs(y[r][1]-y[r-1][1]);u.intervals.push(o);if(u.frequencies.hasOwnProperty(o)){u.frequencies[o]+=1}else{u.frequencies[o]=1}}}x+=o}if(D.renderer.bands){if(D.renderer.bands.hiData.length){var w=D.renderer.bands.hiData;for(var r=0,q=w.length;r<q;r++){if(this.name==="xaxis"||this.name==="x2axis"){w[r][0]=new h.jsDate(w[r][0]).getTime();if((w[r][0]!=null&&w[r][0]>C.max)||C.max==null){C.max=w[r][0]}}else{w[r][1]=new h.jsDate(w[r][1]).getTime();if((w[r][1]!=null&&w[r][1]>C.max)||C.max==null){C.max=w[r][1]}}}}if(D.renderer.bands.lowData.length){var w=D.renderer.bands.lowData;for(var r=0,q=w.length;r<q;r++){if(this.name==="xaxis"||this.name==="x2axis"){w[r][0]=new h.jsDate(w[r][0]).getTime();if((w[r][0]!=null&&w[r][0]<C.min)||C.min==null){C.min=w[r][0]}}else{w[r][1]=new h.jsDate(w[r][1]).getTime();if((w[r][1]!=null&&w[r][1]<C.min)||C.min==null){C.min=w[r][1]}}}}}var B=0,v=0;for(var p in u.frequencies){u.sortedIntervals.push({interval:p,frequency:u.frequencies[p]})}u.sortedIntervals.sort(function(s,n){return n.frequency-s.frequency});u.min=h.jqplot.arrayMin(u.intervals);u.max=h.jqplot.arrayMax(u.intervals);u.mean=x/y.length;this._intervalStats.push(u);u=x=D=y=A=z=null}C=null};h.jqplot.DateAxisRenderer.prototype.reset=function(){this.min=this._options.min;this.max=this._options.max;this.tickInterval=this._options.tickInterval;this.numberTicks=this._options.numberTicks;this._autoFormatString="";if(this._overrideFormatString&&this.tickOptions&&this.tickOptions.formatString){this.tickOptions.formatString=""}this.daTickInterval=this._daTickInterval};h.jqplot.DateAxisRenderer.prototype.createTicks=function(p){var X=this._ticks;var L=this.ticks;var F=this.name;var H=this._dataBounds;var M=this._intervalStats;var n=(this.name.charAt(0)==="x")?this._plotDimensions.width:this._plotDimensions.height;var w;var ae,J;var y,x;var ad,aa;var s=30;var O=1;var U=null;if(this.tickInterval!=null){if(Number(this.tickInterval)){U=[Number(this.tickInterval),"seconds"]}else{if(typeof this.tickInterval=="string"){var ac=this.tickInterval.split(" ");if(ac.length==1){U=[1,ac[0]]}else{if(ac.length==2){U=[ac[0],ac[1]]}}}}}var v=this.tickInterval;ae=new h.jsDate((this.min!=null)?this.min:H.min).getTime();J=new h.jsDate((this.max!=null)?this.max:H.max).getTime();var A=p.plugins.cursor;if(A&&A._zoom&&A._zoom.zooming){this.min=null;this.max=null}var B=J-ae;if(this.tickOptions==null||!this.tickOptions.formatString){this._overrideFormatString=true}if(L.length){for(aa=0;aa<L.length;aa++){var P=L[aa];var Y=new this.tickRenderer(this.tickOptions);if(P.constructor==Array){Y.value=new h.jsDate(P[0]).getTime();Y.label=P[1];if(!this.showTicks){Y.showLabel=false;Y.showMark=false}else{if(!this.showTickMarks){Y.showMark=false}}Y.setTick(Y.value,this.name);this._ticks.push(Y)}else{Y.value=new h.jsDate(P).getTime();if(!this.showTicks){Y.showLabel=false;Y.showMark=false}else{if(!this.showTickMarks){Y.showMark=false}}Y.setTick(Y.value,this.name);this._ticks.push(Y)}}this.numberTicks=L.length;this.min=this._ticks[0].value;this.max=this._ticks[this.numberTicks-1].value;this.daTickInterval=[(this.max-this.min)/(this.numberTicks-1)/1000,"seconds"]}else{if(this.min==null&&this.max==null&&H.min==H.max){var E=h.extend(true,{},this.tickOptions,{name:this.name,value:null});var T=300000;this.min=H.min-T;this.max=H.max+T;this.numberTicks=3;for(var aa=this.min;aa<=this.max;aa+=T){E.value=aa;var Y=new this.tickRenderer(E);if(this._overrideFormatString&&this._autoFormatString!=""){Y.formatString=this._autoFormatString}Y.showLabel=false;Y.showMark=false;this._ticks.push(Y)}if(this.showTicks){this._ticks[1].showLabel=true}if(this.showTickMarks){this._ticks[1].showTickMarks=true}}else{if(this.min==null&&this.max==null){var N=h.extend(true,{},this.tickOptions,{name:this.name,value:null});var ab,I;if(!this.tickInterval&&!this.numberTicks){var R=Math.max(n,s+1);var Z=115;if(this.tickRenderer===h.jqplot.CanvasAxisTickRenderer&&this.tickOptions.angle){Z=115-40*Math.abs(Math.sin(this.tickOptions.angle/180*Math.PI))}ab=Math.ceil((R-s)/Z+1);I=(J-ae)/(ab-1)}else{if(this.tickInterval){I=new h.jsDate(0).add(U[0],U[1]).getTime()}else{if(this.numberTicks){ab=this.numberTicks;I=(J-ae)/(ab-1)}}}if(I<=19*l){var Q=a(ae,J,I);var r=Q[0];this._autoFormatString=Q[1];ae=new h.jsDate(ae);ae=Math.floor((ae.getTime()-ae.getUtcOffset())/r)*r+ae.getUtcOffset();ab=Math.ceil((J-ae)/r)+1;this.min=ae;this.max=ae+(ab-1)*r;if(this.max<J){this.max+=r;ab+=1}this.tickInterval=r;this.numberTicks=ab;for(var aa=0;aa<ab;aa++){N.value=this.min+aa*r;Y=new this.tickRenderer(N);if(this._overrideFormatString&&this._autoFormatString!=""){Y.formatString=this._autoFormatString}if(!this.showTicks){Y.showLabel=false;Y.showMark=false}else{if(!this.showTickMarks){Y.showMark=false}}this._ticks.push(Y)}O=this.tickInterval}else{if(I<=9*j){this._autoFormatString="%v";var D=Math.round(I/j);if(D<1){D=1}else{if(D>6){D=6}}var V=new h.jsDate(ae).setDate(1).setHours(0,0,0,0);var q=new h.jsDate(J);var z=new h.jsDate(J).setDate(1).setHours(0,0,0,0);if(q.getTime()!==z.getTime()){z=z.add(1,"month")}var S=z.diff(V,"month");ab=Math.ceil(S/D)+1;this.min=V.getTime();this.max=V.clone().add((ab-1)*D,"month").getTime();this.numberTicks=ab;for(var aa=0;aa<ab;aa++){if(aa===0){N.value=V.getTime()}else{N.value=V.add(D,"month").getTime()}Y=new this.tickRenderer(N);if(this._overrideFormatString&&this._autoFormatString!=""){Y.formatString=this._autoFormatString}if(!this.showTicks){Y.showLabel=false;Y.showMark=false}else{if(!this.showTickMarks){Y.showMark=false}}this._ticks.push(Y)}O=D*j}else{this._autoFormatString="%v";var D=Math.round(I/k);if(D<1){D=1}var V=new h.jsDate(ae).setMonth(0,1).setHours(0,0,0,0);var z=new h.jsDate(J).add(1,"year").setMonth(0,1).setHours(0,0,0,0);var K=z.diff(V,"year");ab=Math.ceil(K/D)+1;this.min=V.getTime();this.max=V.clone().add((ab-1)*D,"year").getTime();this.numberTicks=ab;for(var aa=0;aa<ab;aa++){if(aa===0){N.value=V.getTime()}else{N.value=V.add(D,"year").getTime()}Y=new this.tickRenderer(N);if(this._overrideFormatString&&this._autoFormatString!=""){Y.formatString=this._autoFormatString}if(!this.showTicks){Y.showLabel=false;Y.showMark=false}else{if(!this.showTickMarks){Y.showMark=false}}this._ticks.push(Y)}O=D*k}}}else{if(F=="xaxis"||F=="x2axis"){n=this._plotDimensions.width}else{n=this._plotDimensions.height}if(this.min!=null&&this.max!=null&&this.numberTicks!=null){this.tickInterval=null}if(this.tickInterval!=null&&U!=null){this.daTickInterval=U}if(ae==J){var o=24*60*60*500;ae-=o;J+=o}B=J-ae;var G=2+parseInt(Math.max(0,n-100)/100,10);var W,C;W=(this.min!=null)?new h.jsDate(this.min).getTime():ae-B/2*(this.padMin-1);C=(this.max!=null)?new h.jsDate(this.max).getTime():J+B/2*(this.padMax-1);this.min=W;this.max=C;B=this.max-this.min;if(this.numberTicks==null){if(this.daTickInterval!=null){var u=new h.jsDate(this.max).diff(this.min,this.daTickInterval[1],true);this.numberTicks=Math.ceil(u/this.daTickInterval[0])+1;this.max=new h.jsDate(this.min).add((this.numberTicks-1)*this.daTickInterval[0],this.daTickInterval[1]).getTime()}else{if(n>200){this.numberTicks=parseInt(3+(n-200)/100,10)}else{this.numberTicks=2}}}O=B/(this.numberTicks-1)/1000;if(this.daTickInterval==null){this.daTickInterval=[O,"seconds"]}for(var aa=0;aa<this.numberTicks;aa++){var ae=new h.jsDate(this.min);ad=ae.add(aa*this.daTickInterval[0],this.daTickInterval[1]).getTime();var Y=new this.tickRenderer(this.tickOptions);if(!this.showTicks){Y.showLabel=false;Y.showMark=false}else{if(!this.showTickMarks){Y.showMark=false}}Y.setTick(ad,this.name);this._ticks.push(Y)}}}}if(this.tickInset){this.min=this.min-this.tickInset*O;this.max=this.max+this.tickInset*O}if(this._daTickInterval==null){this._daTickInterval=this.daTickInterval}X=null}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.donutRenderer.js b/plugin/jqplot/plugins/jqplot.donutRenderer.js new file mode 100644 index 000000000..9684812e6 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.donutRenderer.js @@ -0,0 +1,805 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.DonutRenderer + * Plugin renderer to draw a donut chart. + * x values, if present, will be used as slice labels. + * y values give slice size. + * + * To use this renderer, you need to include the + * donut renderer plugin, for example: + * + * > <script type="text/javascript" src="plugins/jqplot.donutRenderer.js"></script> + * + * Properties described here are passed into the $.jqplot function + * as options on the series renderer. For example: + * + * > plot2 = $.jqplot('chart2', [s1, s2], { + * > seriesDefaults: { + * > renderer:$.jqplot.DonutRenderer, + * > rendererOptions:{ + * > sliceMargin: 2, + * > innerDiameter: 110, + * > startAngle: -90 + * > } + * > } + * > }); + * + * A donut plot will trigger events on the plot target + * according to user interaction. All events return the event object, + * the series index, the point (slice) index, and the point data for + * the appropriate slice. + * + * 'jqplotDataMouseOver' - triggered when user mouseing over a slice. + * 'jqplotDataHighlight' - triggered the first time user mouses over a slice, + * if highlighting is enabled. + * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of + * a highlighted slice. + * 'jqplotDataClick' - triggered when the user clicks on a slice. + * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if + * the "captureRightClick" option is set to true on the plot. + */ + $.jqplot.DonutRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.DonutRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.DonutRenderer.prototype.constructor = $.jqplot.DonutRenderer; + + // called with scope of a series + $.jqplot.DonutRenderer.prototype.init = function(options, plot) { + // Group: Properties + // + // prop: diameter + // Outer diameter of the donut, auto computed by default + this.diameter = null; + // prop: innerDiameter + // Inner diameter of the donut, auto calculated by default. + // If specified will override thickness value. + this.innerDiameter = null; + // prop: thickness + // thickness of the donut, auto computed by default + // Overridden by if innerDiameter is specified. + this.thickness = null; + // prop: padding + // padding between the donut and plot edges, legend, etc. + this.padding = 20; + // prop: sliceMargin + // angular spacing between donut slices in degrees. + this.sliceMargin = 0; + // prop: ringMargin + // pixel distance between rings, or multiple series in a donut plot. + // null will compute ringMargin based on sliceMargin. + this.ringMargin = null; + // prop: fill + // true or false, whether to fil the slices. + this.fill = true; + // prop: shadowOffset + // offset of the shadow from the slice and offset of + // each succesive stroke of the shadow from the last. + this.shadowOffset = 2; + // prop: shadowAlpha + // transparency of the shadow (0 = transparent, 1 = opaque) + this.shadowAlpha = 0.07; + // prop: shadowDepth + // number of strokes to apply to the shadow, + // each stroke offset shadowOffset from the last. + this.shadowDepth = 5; + // prop: highlightMouseOver + // True to highlight slice when moused over. + // This must be false to enable highlightMouseDown to highlight when clicking on a slice. + this.highlightMouseOver = true; + // prop: highlightMouseDown + // True to highlight when a mouse button is pressed over a slice. + // This will be disabled if highlightMouseOver is true. + this.highlightMouseDown = false; + // prop: highlightColors + // an array of colors to use when highlighting a slice. + this.highlightColors = []; + // prop: dataLabels + // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices. + // Defaults to percentage of each pie slice. + this.dataLabels = 'percent'; + // prop: showDataLabels + // true to show data labels on slices. + this.showDataLabels = false; + // prop: dataLabelFormatString + // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage. + this.dataLabelFormatString = null; + // prop: dataLabelThreshold + // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed. + // This applies to all label types, not just to percentage labels. + this.dataLabelThreshold = 3; + // prop: dataLabelPositionFactor + // A Multiplier (0-1) of the pie radius which controls position of label on slice. + // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie. + this.dataLabelPositionFactor = 0.4; + // prop: dataLabelNudge + // Number of pixels to slide the label away from (+) or toward (-) the center of the pie. + this.dataLabelNudge = 0; + // prop: startAngle + // Angle to start drawing donut in degrees. + // According to orientation of canvas coordinate system: + // 0 = on the positive x axis + // -90 = on the positive y axis. + // 90 = on the negaive y axis. + // 180 or - 180 = on the negative x axis. + this.startAngle = 0; + this.tickRenderer = $.jqplot.DonutTickRenderer; + // Used as check for conditions where donut shouldn't be drawn. + this._drawData = true; + this._type = 'donut'; + + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver + if (options.highlightMouseDown && options.highlightMouseOver == null) { + options.highlightMouseOver = false; + } + + $.extend(true, this, options); + if (this.diameter != null) { + this.diameter = this.diameter - this.sliceMargin; + } + this._diameter = null; + this._innerDiameter = null; + this._radius = null; + this._innerRadius = null; + this._thickness = null; + // references to the previous series in the plot to properly calculate diameters + // and thicknesses of nested rings. + this._previousSeries = []; + this._numberSeries = 1; + // array of [start,end] angles arrays, one for each slice. In radians. + this._sliceAngles = []; + // index of the currenty highlighted point, if any + this._highlightedPoint = null; + + // set highlight colors if none provided + if (this.highlightColors.length == 0) { + for (var i=0; i<this.seriesColors.length; i++){ + var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var sum = newrgb[0] + newrgb[1] + newrgb[2]; + for (var j=0; j<3; j++) { + // when darkening, lowest color component can be is 60. + newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); + newrgb[j] = parseInt(newrgb[j], 10); + } + this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); + } + } + + plot.postParseOptionsHooks.addOnce(postParseOptions); + plot.postInitHooks.addOnce(postInit); + plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); + plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); + plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); + plot.eventListenerHooks.addOnce('jqplotClick', handleClick); + plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); + plot.postDrawHooks.addOnce(postPlotDraw); + + + }; + + $.jqplot.DonutRenderer.prototype.setGridData = function(plot) { + // set gridData property. This will hold angle in radians of each data point. + var stack = []; + var td = []; + var sa = this.startAngle/180*Math.PI; + var tot = 0; + // don't know if we have any valid data yet, so set plot to not draw. + this._drawData = false; + for (var i=0; i<this.data.length; i++){ + if (this.data[i][1] != 0) { + // we have data, O.K. to draw. + this._drawData = true; + } + stack.push(this.data[i][1]); + td.push([this.data[i][0]]); + if (i>0) { + stack[i] += stack[i-1]; + } + tot += this.data[i][1]; + } + var fact = Math.PI*2/stack[stack.length - 1]; + + for (var i=0; i<stack.length; i++) { + td[i][1] = stack[i] * fact; + td[i][2] = this.data[i][1]/tot; + } + this.gridData = td; + }; + + $.jqplot.DonutRenderer.prototype.makeGridData = function(data, plot) { + var stack = []; + var td = []; + var tot = 0; + var sa = this.startAngle/180*Math.PI; + // don't know if we have any valid data yet, so set plot to not draw. + this._drawData = false; + for (var i=0; i<data.length; i++){ + if (this.data[i][1] != 0) { + // we have data, O.K. to draw. + this._drawData = true; + } + stack.push(data[i][1]); + td.push([data[i][0]]); + if (i>0) { + stack[i] += stack[i-1]; + } + tot += data[i][1]; + } + var fact = Math.PI*2/stack[stack.length - 1]; + + for (var i=0; i<stack.length; i++) { + td[i][1] = stack[i] * fact; + td[i][2] = data[i][1]/tot; + } + return td; + }; + + $.jqplot.DonutRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) { + var r = this._diameter / 2; + var ri = r - this._thickness; + var fill = this.fill; + // var lineWidth = this.lineWidth; + ctx.save(); + ctx.translate(this._center[0], this._center[1]); + // ctx.translate(this.sliceMargin*Math.cos((ang1+ang2)/2), this.sliceMargin*Math.sin((ang1+ang2)/2)); + + if (isShadow) { + for (var i=0; i<this.shadowDepth; i++) { + ctx.save(); + ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); + doDraw(); + } + } + + else { + doDraw(); + } + + function doDraw () { + // Fix for IE and Chrome that can't seem to draw circles correctly. + // ang2 should always be <= 2 pi since that is the way the data is converted. + if (ang2 > 6.282 + this.startAngle) { + ang2 = 6.282 + this.startAngle; + if (ang1 > ang2) { + ang1 = 6.281 + this.startAngle; + } + } + // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids + // ugly line on unfilled donuts. + if (ang1 >= ang2) { + return; + } + ctx.beginPath(); + ctx.fillStyle = color; + ctx.strokeStyle = color; + // ctx.lineWidth = lineWidth; + ctx.arc(0, 0, r, ang1, ang2, false); + ctx.lineTo(ri*Math.cos(ang2), ri*Math.sin(ang2)); + ctx.arc(0,0, ri, ang2, ang1, true); + ctx.closePath(); + if (fill) { + ctx.fill(); + } + else { + ctx.stroke(); + } + } + + if (isShadow) { + for (var i=0; i<this.shadowDepth; i++) { + ctx.restore(); + } + } + + ctx.restore(); + }; + + // called with scope of series + $.jqplot.DonutRenderer.prototype.draw = function (ctx, gd, options, plot) { + var i; + var opts = (options != undefined) ? options : {}; + // offset and direction of offset due to legend placement + var offx = 0; + var offy = 0; + var trans = 1; + // var colorGenerator = new this.colorGenerator(this.seriesColors); + if (options.legendInfo && options.legendInfo.placement == 'insideGrid') { + var li = options.legendInfo; + switch (li.location) { + case 'nw': + offx = li.width + li.xoffset; + break; + case 'w': + offx = li.width + li.xoffset; + break; + case 'sw': + offx = li.width + li.xoffset; + break; + case 'ne': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'e': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'se': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'n': + offy = li.height + li.yoffset; + break; + case 's': + offy = li.height + li.yoffset; + trans = -1; + break; + default: + break; + } + } + + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var cw = ctx.canvas.width; + var ch = ctx.canvas.height; + var w = cw - offx - 2 * this.padding; + var h = ch - offy - 2 * this.padding; + var mindim = Math.min(w,h); + var d = mindim; + var ringmargin = (this.ringMargin == null) ? this.sliceMargin * 2.0 : this.ringMargin; + + for (var i=0; i<this._previousSeries.length; i++) { + d -= 2.0 * this._previousSeries[i]._thickness + 2.0 * ringmargin; + } + this._diameter = this.diameter || d; + if (this.innerDiameter != null) { + var od = (this._numberSeries > 1 && this.index > 0) ? this._previousSeries[0]._diameter : this._diameter; + this._thickness = this.thickness || (od - this.innerDiameter - 2.0*ringmargin*this._numberSeries) / this._numberSeries/2.0; + } + else { + this._thickness = this.thickness || mindim / 2 / (this._numberSeries + 1) * 0.85; + } + + var r = this._radius = this._diameter/2; + this._innerRadius = this._radius - this._thickness; + var sa = this.startAngle / 180 * Math.PI; + this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy]; + + if (this.shadow) { + var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; + for (var i=0; i<gd.length; i++) { + var ang1 = (i == 0) ? sa : gd[i-1][1] + sa; + // Adjust ang1 and ang2 for sliceMargin + ang1 += this.sliceMargin/180*Math.PI; + this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true); + } + + } + for (var i=0; i<gd.length; i++) { + var ang1 = (i == 0) ? sa : gd[i-1][1] + sa; + // Adjust ang1 and ang2 for sliceMargin + ang1 += this.sliceMargin/180*Math.PI; + var ang2 = gd[i][1] + sa; + this._sliceAngles.push([ang1, ang2]); + this.renderer.drawSlice.call (this, ctx, ang1, ang2, this.seriesColors[i], false); + + if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) { + var fstr, avgang = (ang1+ang2)/2, label; + + if (this.dataLabels == 'label') { + fstr = this.dataLabelFormatString || '%s'; + label = $.jqplot.sprintf(fstr, gd[i][0]); + } + else if (this.dataLabels == 'value') { + fstr = this.dataLabelFormatString || '%d'; + label = $.jqplot.sprintf(fstr, this.data[i][1]); + } + else if (this.dataLabels == 'percent') { + fstr = this.dataLabelFormatString || '%d%%'; + label = $.jqplot.sprintf(fstr, gd[i][2]*100); + } + else if (this.dataLabels.constructor == Array) { + fstr = this.dataLabelFormatString || '%s'; + label = $.jqplot.sprintf(fstr, this.dataLabels[i]); + } + + var fact = this._innerRadius + this._thickness * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge; + + var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left; + var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top; + + var labelelem = $('<span class="jqplot-donut-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem); + x -= labelelem.width()/2; + y -= labelelem.height()/2; + x = Math.round(x); + y = Math.round(y); + labelelem.css({left: x, top: y}); + } + } + + }; + + $.jqplot.DonutAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + }; + + $.jqplot.DonutAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.DonutAxisRenderer.prototype.constructor = $.jqplot.DonutAxisRenderer; + + + // There are no traditional axes on a donut chart. We just need to provide + // dummy objects with properties so the plot will render. + // called with scope of axis object. + $.jqplot.DonutAxisRenderer.prototype.init = function(options){ + // + this.tickRenderer = $.jqplot.DonutTickRenderer; + $.extend(true, this, options); + // I don't think I'm going to need _dataBounds here. + // have to go Axis scaling in a way to fit chart onto plot area + // and provide u2p and p2u functionality for mouse cursor, etc. + // for convienence set _dataBounds to 0 and 100 and + // set min/max to 0 and 100. + this._dataBounds = {min:0, max:100}; + this.min = 0; + this.max = 100; + this.showTicks = false; + this.ticks = []; + this.showMark = false; + this.show = false; + }; + + + + + $.jqplot.DonutLegendRenderer = function(){ + $.jqplot.TableLegendRenderer.call(this); + }; + + $.jqplot.DonutLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); + $.jqplot.DonutLegendRenderer.prototype.constructor = $.jqplot.DonutLegendRenderer; + + /** + * Class: $.jqplot.DonutLegendRenderer + * Legend Renderer specific to donut plots. Set by default + * when user creates a donut plot. + */ + $.jqplot.DonutLegendRenderer.prototype.init = function(options) { + // Group: Properties + // + // prop: numberRows + // Maximum number of rows in the legend. 0 or null for unlimited. + this.numberRows = null; + // prop: numberColumns + // Maximum number of columns in the legend. 0 or null for unlimited. + this.numberColumns = null; + $.extend(true, this, options); + }; + + // called with context of legend + $.jqplot.DonutLegendRenderer.prototype.draw = function() { + var legend = this; + if (this.show) { + var series = this._series; + var ss = 'position:absolute;'; + ss += (this.background) ? 'background:'+this.background+';' : ''; + ss += (this.border) ? 'border:'+this.border+';' : ''; + ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; + ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; + ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; + ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; + ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; + ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; + ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; + this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); + // Donut charts legends don't go by number of series, but by number of data points + // in the series. Refactor things here for that. + + var pad = false, + reverse = false, + nr, nc; + var s = series[0]; + var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); + + if (s.show) { + var pd = s.data; + if (this.numberRows) { + nr = this.numberRows; + if (!this.numberColumns){ + nc = Math.ceil(pd.length/nr); + } + else{ + nc = this.numberColumns; + } + } + else if (this.numberColumns) { + nc = this.numberColumns; + nr = Math.ceil(pd.length/this.numberColumns); + } + else { + nr = pd.length; + nc = 1; + } + + var i, j, tr, td1, td2, lt, rs, color; + var idx = 0; + + for (i=0; i<nr; i++) { + if (reverse){ + tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); + } + else{ + tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); + } + for (j=0; j<nc; j++) { + if (idx < pd.length){ + lt = this.labels[idx] || pd[idx][0].toString(); + color = colorGenerator.next(); + if (!reverse){ + if (i>0){ + pad = true; + } + else{ + pad = false; + } + } + else{ + if (i == nr -1){ + pad = false; + } + else{ + pad = true; + } + } + rs = (pad) ? this.rowSpacing : '0'; + + td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ + '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ + '</div></td>'); + td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); + if (this.escapeHtml){ + td2.text(lt); + } + else { + td2.html(lt); + } + if (reverse) { + td2.prependTo(tr); + td1.prependTo(tr); + } + else { + td1.appendTo(tr); + td2.appendTo(tr); + } + pad = true; + } + idx++; + } + } + } + } + return this._elem; + }; + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + options = options || {}; + options.axesDefaults = options.axesDefaults || {}; + options.legend = options.legend || {}; + options.seriesDefaults = options.seriesDefaults || {}; + // only set these if there is a donut series + var setopts = false; + if (options.seriesDefaults.renderer == $.jqplot.DonutRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer == $.jqplot.DonutRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.DonutAxisRenderer; + options.legend.renderer = $.jqplot.DonutLegendRenderer; + options.legend.preDraw = true; + options.seriesDefaults.pointLabels = {show: false}; + } + } + + // called with scope of plot. + function postInit(target, data, options) { + // if multiple series, add a reference to the previous one so that + // donut rings can nest. + for (var i=1; i<this.series.length; i++) { + if (!this.series[i]._previousSeries.length){ + for (var j=0; j<i; j++) { + if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer && this.series[j].renderer.constructor == $.jqplot.DonutRenderer) { + this.series[i]._previousSeries.push(this.series[j]); + } + } + } + } + for (i=0; i<this.series.length; i++) { + if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer) { + this.series[i]._numberSeries = this.series.length; + // don't allow mouseover and mousedown at same time. + if (this.series[i].highlightMouseOver) { + this.series[i].highlightMouseDown = false; + } + } + } + } + + var postParseOptionsRun = false; + // called with scope of plot + function postParseOptions(options) { + for (var i=0; i<this.series.length; i++) { + this.series[i].seriesColors = this.seriesColors; + this.series[i].colorGenerator = $.jqplot.colorGenerator; + } + } + + function highlight (plot, sidx, pidx) { + var s = plot.series[sidx]; + var canvas = plot.plugins.donutRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); + s._highlightedPoint = pidx; + plot.plugins.donutRenderer.highlightedSeriesIndex = sidx; + s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColors[pidx], false); + } + + function unhighlight (plot) { + var canvas = plot.plugins.donutRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); + for (var i=0; i<plot.series.length; i++) { + plot.series[i]._highlightedPoint = null; + } + plot.plugins.donutRenderer.highlightedSeriesIndex = null; + plot.target.trigger('jqplotDataUnhighlight'); + } + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt1 = jQuery.Event('jqplotDataMouseOver'); + evt1.pageX = ev.pageX; + evt1.pageY = ev.pageY; + plot.target.trigger(evt1, ins); + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { + var idx = plot.plugins.donutRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + } + + function handleClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt = jQuery.Event('jqplotDataClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + function handleRightClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var idx = plot.plugins.donutRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + var evt = jQuery.Event('jqplotDataRightClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + function postPlotDraw() { + // Memory Leaks patch + if (this.plugins.donutRenderer && this.plugins.donutRenderer.highlightCanvas) { + this.plugins.donutRenderer.highlightCanvas.resetCanvas(); + this.plugins.donutRenderer.highlightCanvas = null; + } + + this.plugins.donutRenderer = {highlightedSeriesIndex:null}; + this.plugins.donutRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); + // do we have any data labels? if so, put highlight canvas before those + // Fix for broken jquery :first selector with canvas (VML) elements. + var labels = $(this.targetId+' .jqplot-data-label'); + if (labels.length) { + $(labels[0]).before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this)); + } + // else put highlight canvas before event canvas. + else { + this.eventCanvas._elem.before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this)); + } + var hctx = this.plugins.donutRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); + } + + $.jqplot.preInitHooks.push(preInit); + + $.jqplot.DonutTickRenderer = function() { + $.jqplot.AxisTickRenderer.call(this); + }; + + $.jqplot.DonutTickRenderer.prototype = new $.jqplot.AxisTickRenderer(); + $.jqplot.DonutTickRenderer.prototype.constructor = $.jqplot.DonutTickRenderer; + +})(jQuery); + + \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.donutRenderer.min.js b/plugin/jqplot/plugins/jqplot.donutRenderer.min.js new file mode 100644 index 000000000..737e17c6f --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.donutRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(e){e.jqplot.DonutRenderer=function(){e.jqplot.LineRenderer.call(this)};e.jqplot.DonutRenderer.prototype=new e.jqplot.LineRenderer();e.jqplot.DonutRenderer.prototype.constructor=e.jqplot.DonutRenderer;e.jqplot.DonutRenderer.prototype.init=function(p,t){this.diameter=null;this.innerDiameter=null;this.thickness=null;this.padding=20;this.sliceMargin=0;this.ringMargin=null;this.fill=true;this.shadowOffset=2;this.shadowAlpha=0.07;this.shadowDepth=5;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.dataLabels="percent";this.showDataLabels=false;this.dataLabelFormatString=null;this.dataLabelThreshold=3;this.dataLabelPositionFactor=0.4;this.dataLabelNudge=0;this.startAngle=0;this.tickRenderer=e.jqplot.DonutTickRenderer;this._drawData=true;this._type="donut";if(p.highlightMouseDown&&p.highlightMouseOver==null){p.highlightMouseOver=false}e.extend(true,this,p);if(this.diameter!=null){this.diameter=this.diameter-this.sliceMargin}this._diameter=null;this._innerDiameter=null;this._radius=null;this._innerRadius=null;this._thickness=null;this._previousSeries=[];this._numberSeries=1;this._sliceAngles=[];this._highlightedPoint=null;if(this.highlightColors.length==0){for(var r=0;r<this.seriesColors.length;r++){var q=e.jqplot.getColorComponents(this.seriesColors[r]);var n=[q[0],q[1],q[2]];var s=n[0]+n[1]+n[2];for(var o=0;o<3;o++){n[o]=(s>570)?n[o]*0.8:n[o]+0.3*(255-n[o]);n[o]=parseInt(n[o],10)}this.highlightColors.push("rgb("+n[0]+","+n[1]+","+n[2]+")")}}t.postParseOptionsHooks.addOnce(l);t.postInitHooks.addOnce(g);t.eventListenerHooks.addOnce("jqplotMouseMove",b);t.eventListenerHooks.addOnce("jqplotMouseDown",a);t.eventListenerHooks.addOnce("jqplotMouseUp",j);t.eventListenerHooks.addOnce("jqplotClick",f);t.eventListenerHooks.addOnce("jqplotRightClick",m);t.postDrawHooks.addOnce(h)};e.jqplot.DonutRenderer.prototype.setGridData=function(s){var o=[];var t=[];var n=this.startAngle/180*Math.PI;var r=0;this._drawData=false;for(var q=0;q<this.data.length;q++){if(this.data[q][1]!=0){this._drawData=true}o.push(this.data[q][1]);t.push([this.data[q][0]]);if(q>0){o[q]+=o[q-1]}r+=this.data[q][1]}var p=Math.PI*2/o[o.length-1];for(var q=0;q<o.length;q++){t[q][1]=o[q]*p;t[q][2]=this.data[q][1]/r}this.gridData=t};e.jqplot.DonutRenderer.prototype.makeGridData=function(s,t){var o=[];var u=[];var r=0;var n=this.startAngle/180*Math.PI;this._drawData=false;for(var q=0;q<s.length;q++){if(this.data[q][1]!=0){this._drawData=true}o.push(s[q][1]);u.push([s[q][0]]);if(q>0){o[q]+=o[q-1]}r+=s[q][1]}var p=Math.PI*2/o[o.length-1];for(var q=0;q<o.length;q++){u[q][1]=o[q]*p;u[q][2]=s[q][1]/r}return u};e.jqplot.DonutRenderer.prototype.drawSlice=function(x,u,t,p,s){var n=this._diameter/2;var v=n-this._thickness;var w=this.fill;x.save();x.translate(this._center[0],this._center[1]);if(s){for(var q=0;q<this.shadowDepth;q++){x.save();x.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI),this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));o()}}else{o()}function o(){if(t>6.282+this.startAngle){t=6.282+this.startAngle;if(u>t){u=6.281+this.startAngle}}if(u>=t){return}x.beginPath();x.fillStyle=p;x.strokeStyle=p;x.arc(0,0,n,u,t,false);x.lineTo(v*Math.cos(t),v*Math.sin(t));x.arc(0,0,v,t,u,true);x.closePath();if(w){x.fill()}else{x.stroke()}}if(s){for(var q=0;q<this.shadowDepth;q++){x.restore()}}x.restore()};e.jqplot.DonutRenderer.prototype.draw=function(N,V,t,P){var Q;var J=(t!=undefined)?t:{};var q=0;var p=0;var u=1;if(t.legendInfo&&t.legendInfo.placement=="insideGrid"){var I=t.legendInfo;switch(I.location){case"nw":q=I.width+I.xoffset;break;case"w":q=I.width+I.xoffset;break;case"sw":q=I.width+I.xoffset;break;case"ne":q=I.width+I.xoffset;u=-1;break;case"e":q=I.width+I.xoffset;u=-1;break;case"se":q=I.width+I.xoffset;u=-1;break;case"n":p=I.height+I.yoffset;break;case"s":p=I.height+I.yoffset;u=-1;break;default:break}}var B=(J.shadow!=undefined)?J.shadow:this.shadow;var W=(J.showLine!=undefined)?J.showLine:this.showLine;var O=(J.fill!=undefined)?J.fill:this.fill;var s=N.canvas.width;var H=N.canvas.height;var G=s-q-2*this.padding;var R=H-p-2*this.padding;var v=Math.min(G,R);var T=v;var X=(this.ringMargin==null)?this.sliceMargin*2:this.ringMargin;for(var Q=0;Q<this._previousSeries.length;Q++){T-=2*this._previousSeries[Q]._thickness+2*X}this._diameter=this.diameter||T;if(this.innerDiameter!=null){var M=(this._numberSeries>1&&this.index>0)?this._previousSeries[0]._diameter:this._diameter;this._thickness=this.thickness||(M-this.innerDiameter-2*X*this._numberSeries)/this._numberSeries/2}else{this._thickness=this.thickness||v/2/(this._numberSeries+1)*0.85}var K=this._radius=this._diameter/2;this._innerRadius=this._radius-this._thickness;var o=this.startAngle/180*Math.PI;this._center=[(s-u*q)/2+u*q,(H-u*p)/2+u*p];if(this.shadow){var L="rgba(0,0,0,"+this.shadowAlpha+")";for(var Q=0;Q<V.length;Q++){var A=(Q==0)?o:V[Q-1][1]+o;A+=this.sliceMargin/180*Math.PI;this.renderer.drawSlice.call(this,N,A,V[Q][1]+o,L,true)}}for(var Q=0;Q<V.length;Q++){var A=(Q==0)?o:V[Q-1][1]+o;A+=this.sliceMargin/180*Math.PI;var z=V[Q][1]+o;this._sliceAngles.push([A,z]);this.renderer.drawSlice.call(this,N,A,z,this.seriesColors[Q],false);if(this.showDataLabels&&V[Q][2]*100>=this.dataLabelThreshold){var S,U=(A+z)/2,C;if(this.dataLabels=="label"){S=this.dataLabelFormatString||"%s";C=e.jqplot.sprintf(S,V[Q][0])}else{if(this.dataLabels=="value"){S=this.dataLabelFormatString||"%d";C=e.jqplot.sprintf(S,this.data[Q][1])}else{if(this.dataLabels=="percent"){S=this.dataLabelFormatString||"%d%%";C=e.jqplot.sprintf(S,V[Q][2]*100)}else{if(this.dataLabels.constructor==Array){S=this.dataLabelFormatString||"%s";C=e.jqplot.sprintf(S,this.dataLabels[Q])}}}}var n=this._innerRadius+this._thickness*this.dataLabelPositionFactor+this.sliceMargin+this.dataLabelNudge;var F=this._center[0]+Math.cos(U)*n+this.canvas._offsets.left;var E=this._center[1]+Math.sin(U)*n+this.canvas._offsets.top;var D=e('<span class="jqplot-donut-series jqplot-data-label" style="position:absolute;">'+C+"</span>").insertBefore(P.eventCanvas._elem);F-=D.width()/2;E-=D.height()/2;F=Math.round(F);E=Math.round(E);D.css({left:F,top:E})}}};e.jqplot.DonutAxisRenderer=function(){e.jqplot.LinearAxisRenderer.call(this)};e.jqplot.DonutAxisRenderer.prototype=new e.jqplot.LinearAxisRenderer();e.jqplot.DonutAxisRenderer.prototype.constructor=e.jqplot.DonutAxisRenderer;e.jqplot.DonutAxisRenderer.prototype.init=function(n){this.tickRenderer=e.jqplot.DonutTickRenderer;e.extend(true,this,n);this._dataBounds={min:0,max:100};this.min=0;this.max=100;this.showTicks=false;this.ticks=[];this.showMark=false;this.show=false};e.jqplot.DonutLegendRenderer=function(){e.jqplot.TableLegendRenderer.call(this)};e.jqplot.DonutLegendRenderer.prototype=new e.jqplot.TableLegendRenderer();e.jqplot.DonutLegendRenderer.prototype.constructor=e.jqplot.DonutLegendRenderer;e.jqplot.DonutLegendRenderer.prototype.init=function(n){this.numberRows=null;this.numberColumns=null;e.extend(true,this,n)};e.jqplot.DonutLegendRenderer.prototype.draw=function(){var q=this;if(this.show){var y=this._series;var B="position:absolute;";B+=(this.background)?"background:"+this.background+";":"";B+=(this.border)?"border:"+this.border+";":"";B+=(this.fontSize)?"font-size:"+this.fontSize+";":"";B+=(this.fontFamily)?"font-family:"+this.fontFamily+";":"";B+=(this.textColor)?"color:"+this.textColor+";":"";B+=(this.marginTop!=null)?"margin-top:"+this.marginTop+";":"";B+=(this.marginBottom!=null)?"margin-bottom:"+this.marginBottom+";":"";B+=(this.marginLeft!=null)?"margin-left:"+this.marginLeft+";":"";B+=(this.marginRight!=null)?"margin-right:"+this.marginRight+";":"";this._elem=e('<table class="jqplot-table-legend" style="'+B+'"></table>');var F=false,x=false,n,v;var z=y[0];var o=new e.jqplot.ColorGenerator(z.seriesColors);if(z.show){var G=z.data;if(this.numberRows){n=this.numberRows;if(!this.numberColumns){v=Math.ceil(G.length/n)}else{v=this.numberColumns}}else{if(this.numberColumns){v=this.numberColumns;n=Math.ceil(G.length/this.numberColumns)}else{n=G.length;v=1}}var E,D,p,t,r,u,w,C;var A=0;for(E=0;E<n;E++){if(x){p=e('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem)}else{p=e('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem)}for(D=0;D<v;D++){if(A<G.length){u=this.labels[A]||G[A][0].toString();C=o.next();if(!x){if(E>0){F=true}else{F=false}}else{if(E==n-1){F=false}else{F=true}}w=(F)?this.rowSpacing:"0";t=e('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+w+';"><div><div class="jqplot-table-legend-swatch" style="border-color:'+C+';"></div></div></td>');r=e('<td class="jqplot-table-legend" style="padding-top:'+w+';"></td>');if(this.escapeHtml){r.text(u)}else{r.html(u)}if(x){r.prependTo(p);t.prependTo(p)}else{t.appendTo(p);r.appendTo(p)}F=true}A++}}}}return this._elem};function c(r,q,o){o=o||{};o.axesDefaults=o.axesDefaults||{};o.legend=o.legend||{};o.seriesDefaults=o.seriesDefaults||{};var n=false;if(o.seriesDefaults.renderer==e.jqplot.DonutRenderer){n=true}else{if(o.series){for(var p=0;p<o.series.length;p++){if(o.series[p].renderer==e.jqplot.DonutRenderer){n=true}}}}if(n){o.axesDefaults.renderer=e.jqplot.DonutAxisRenderer;o.legend.renderer=e.jqplot.DonutLegendRenderer;o.legend.preDraw=true;o.seriesDefaults.pointLabels={show:false}}}function g(r,q,o){for(var p=1;p<this.series.length;p++){if(!this.series[p]._previousSeries.length){for(var n=0;n<p;n++){if(this.series[p].renderer.constructor==e.jqplot.DonutRenderer&&this.series[n].renderer.constructor==e.jqplot.DonutRenderer){this.series[p]._previousSeries.push(this.series[n])}}}}for(p=0;p<this.series.length;p++){if(this.series[p].renderer.constructor==e.jqplot.DonutRenderer){this.series[p]._numberSeries=this.series.length;if(this.series[p].highlightMouseOver){this.series[p].highlightMouseDown=false}}}}var k=false;function l(n){for(var o=0;o<this.series.length;o++){this.series[o].seriesColors=this.seriesColors;this.series[o].colorGenerator=e.jqplot.colorGenerator}}function d(r,q,p){var o=r.series[q];var n=r.plugins.donutRenderer.highlightCanvas;n._ctx.clearRect(0,0,n._ctx.canvas.width,n._ctx.canvas.height);o._highlightedPoint=p;r.plugins.donutRenderer.highlightedSeriesIndex=q;o.renderer.drawSlice.call(o,n._ctx,o._sliceAngles[p][0],o._sliceAngles[p][1],o.highlightColors[p],false)}function i(p){var n=p.plugins.donutRenderer.highlightCanvas;n._ctx.clearRect(0,0,n._ctx.canvas.width,n._ctx.canvas.height);for(var o=0;o<p.series.length;o++){p.series[o]._highlightedPoint=null}p.plugins.donutRenderer.highlightedSeriesIndex=null;p.target.trigger("jqplotDataUnhighlight")}function b(r,q,u,t,s){if(t){var p=[t.seriesIndex,t.pointIndex,t.data];var o=jQuery.Event("jqplotDataMouseOver");o.pageX=r.pageX;o.pageY=r.pageY;s.target.trigger(o,p);if(s.series[p[0]].highlightMouseOver&&!(p[0]==s.plugins.donutRenderer.highlightedSeriesIndex&&p[1]==s.series[p[0]]._highlightedPoint)){var n=jQuery.Event("jqplotDataHighlight");n.which=r.which;n.pageX=r.pageX;n.pageY=r.pageY;s.target.trigger(n,p);d(s,p[0],p[1])}}else{if(t==null){i(s)}}}function a(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];if(r.series[o[0]].highlightMouseDown&&!(o[0]==r.plugins.donutRenderer.highlightedSeriesIndex&&o[1]==r.series[o[0]]._highlightedPoint)){var n=jQuery.Event("jqplotDataHighlight");n.which=q.which;n.pageX=q.pageX;n.pageY=q.pageY;r.target.trigger(n,o);d(r,o[0],o[1])}}else{if(s==null){i(r)}}}function j(p,o,s,r,q){var n=q.plugins.donutRenderer.highlightedSeriesIndex;if(n!=null&&q.series[n].highlightMouseDown){i(q)}}function f(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];var n=jQuery.Event("jqplotDataClick");n.which=q.which;n.pageX=q.pageX;n.pageY=q.pageY;r.target.trigger(n,o)}}function m(r,q,u,t,s){if(t){var p=[t.seriesIndex,t.pointIndex,t.data];var n=s.plugins.donutRenderer.highlightedSeriesIndex;if(n!=null&&s.series[n].highlightMouseDown){i(s)}var o=jQuery.Event("jqplotDataRightClick");o.which=r.which;o.pageX=r.pageX;o.pageY=r.pageY;s.target.trigger(o,p)}}function h(){if(this.plugins.donutRenderer&&this.plugins.donutRenderer.highlightCanvas){this.plugins.donutRenderer.highlightCanvas.resetCanvas();this.plugins.donutRenderer.highlightCanvas=null}this.plugins.donutRenderer={highlightedSeriesIndex:null};this.plugins.donutRenderer.highlightCanvas=new e.jqplot.GenericCanvas();var o=e(this.targetId+" .jqplot-data-label");if(o.length){e(o[0]).before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-donutRenderer-highlight-canvas",this._plotDimensions,this))}else{this.eventCanvas._elem.before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-donutRenderer-highlight-canvas",this._plotDimensions,this))}var n=this.plugins.donutRenderer.highlightCanvas.setContext();this.eventCanvas._elem.bind("mouseleave",{plot:this},function(p){i(p.data.plot)})}e.jqplot.preInitHooks.push(c);e.jqplot.DonutTickRenderer=function(){e.jqplot.AxisTickRenderer.call(this)};e.jqplot.DonutTickRenderer.prototype=new e.jqplot.AxisTickRenderer();e.jqplot.DonutTickRenderer.prototype.constructor=e.jqplot.DonutTickRenderer})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.dragable.js b/plugin/jqplot/plugins/jqplot.dragable.js new file mode 100644 index 000000000..a9639bf96 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.dragable.js @@ -0,0 +1,225 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + + /** + * Class: $.jqplot.Dragable + * Plugin to make plotted points dragable by the user. + */ + $.jqplot.Dragable = function(options) { + // Group: Properties + this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false}); + this.shapeRenderer = new $.jqplot.ShapeRenderer(); + this.isDragging = false; + this.isOver = false; + this._ctx; + this._elem; + this._point; + this._gridData; + // prop: color + // CSS color spec for the dragged point (and adjacent line segment or bar). + this.color; + // prop: constrainTo + // Constrain dragging motion to an axis or to none. + // Allowable values are 'none', 'x', 'y' + this.constrainTo = 'none'; // 'x', 'y', or 'none'; + $.extend(true, this, options); + }; + + function DragCanvas() { + $.jqplot.GenericCanvas.call(this); + this.isDragging = false; + this.isOver = false; + this._neighbor; + this._cursors = []; + } + + DragCanvas.prototype = new $.jqplot.GenericCanvas(); + DragCanvas.prototype.constructor = DragCanvas; + + + // called within scope of series + $.jqplot.Dragable.parseOptions = function (defaults, opts) { + var options = opts || {}; + this.plugins.dragable = new $.jqplot.Dragable(options.dragable); + // since this function is called before series options are parsed, + // we can set this here and it will be overridden if needed. + this.isDragable = $.jqplot.config.enablePlugins; + }; + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + // add a new DragCanvas object to the plot plugins to handle drawing on this new canvas. + $.jqplot.Dragable.postPlotDraw = function() { + // Memory Leaks patch + if (this.plugins.dragable && this.plugins.dragable.highlightCanvas) { + this.plugins.dragable.highlightCanvas.resetCanvas(); + this.plugins.dragable.highlightCanvas = null; + } + + this.plugins.dragable = {previousCursor:'auto', isOver:false}; + this.plugins.dragable.dragCanvas = new DragCanvas(); + + this.eventCanvas._elem.before(this.plugins.dragable.dragCanvas.createElement(this._gridPadding, 'jqplot-dragable-canvas', this._plotDimensions, this)); + var dctx = this.plugins.dragable.dragCanvas.setContext(); + }; + + //$.jqplot.preInitHooks.push($.jqplot.Dragable.init); + $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Dragable.parseOptions); + $.jqplot.postDrawHooks.push($.jqplot.Dragable.postPlotDraw); + $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]); + $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleDown]); + $.jqplot.eventListenerHooks.push(['jqplotMouseUp', handleUp]); + + + function initDragPoint(plot, neighbor) { + var s = plot.series[neighbor.seriesIndex]; + var drag = s.plugins.dragable; + + // first, init the mark renderer for the dragged point + var smr = s.markerRenderer; + var mr = drag.markerRenderer; + mr.style = smr.style; + mr.lineWidth = smr.lineWidth + 2.5; + mr.size = smr.size + 5; + if (!drag.color) { + var rgba = $.jqplot.getColorComponents(smr.color); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]); + drag.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')'; + } + mr.color = drag.color; + mr.init(); + + var start = (neighbor.pointIndex > 0) ? neighbor.pointIndex - 1 : 0; + var end = neighbor.pointIndex+2; + drag._gridData = s.gridData.slice(start, end); + } + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + if (plot.plugins.dragable.dragCanvas.isDragging) { + var dc = plot.plugins.dragable.dragCanvas; + var dp = dc._neighbor; + var s = plot.series[dp.seriesIndex]; + var drag = s.plugins.dragable; + var gd = s.gridData; + + // compute the new grid position with any constraints. + var x = (drag.constrainTo == 'y') ? dp.gridData[0] : gridpos.x; + var y = (drag.constrainTo == 'x') ? dp.gridData[1] : gridpos.y; + + // compute data values for any listeners. + var xu = s._xaxis.series_p2u(x); + var yu = s._yaxis.series_p2u(y); + + // clear the canvas then redraw effect at new position. + var ctx = dc._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + + // adjust our gridData for the new mouse position + if (dp.pointIndex > 0) { + drag._gridData[1] = [x, y]; + } + else { + drag._gridData[0] = [x, y]; + } + plot.series[dp.seriesIndex].draw(dc._ctx, {gridData:drag._gridData, shadow:false, preventJqPlotSeriesDrawTrigger:true, color:drag.color, markerOptions:{color:drag.color, shadow:false}, trendline:{show:false}}); + plot.target.trigger('jqplotSeriesPointChange', [dp.seriesIndex, dp.pointIndex, [xu,yu], [x,y]]); + } + else if (neighbor != null) { + var series = plot.series[neighbor.seriesIndex]; + if (series.isDragable) { + var dc = plot.plugins.dragable.dragCanvas; + if (!dc.isOver) { + dc._cursors.push(ev.target.style.cursor); + ev.target.style.cursor = "pointer"; + } + dc.isOver = true; + } + } + else if (neighbor == null) { + var dc = plot.plugins.dragable.dragCanvas; + if (dc.isOver) { + ev.target.style.cursor = dc._cursors.pop(); + dc.isOver = false; + } + } + } + + function handleDown(ev, gridpos, datapos, neighbor, plot) { + var dc = plot.plugins.dragable.dragCanvas; + dc._cursors.push(ev.target.style.cursor); + if (neighbor != null) { + var s = plot.series[neighbor.seriesIndex]; + var drag = s.plugins.dragable; + if (s.isDragable && !dc.isDragging) { + dc._neighbor = neighbor; + dc.isDragging = true; + initDragPoint(plot, neighbor); + drag.markerRenderer.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], dc._ctx); + ev.target.style.cursor = "move"; + plot.target.trigger('jqplotDragStart', [neighbor.seriesIndex, neighbor.pointIndex, gridpos, datapos]); + } + } + // Just in case of a hickup, we'll clear the drag canvas and reset. + else { + var ctx = dc._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + dc.isDragging = false; + } + } + + function handleUp(ev, gridpos, datapos, neighbor, plot) { + if (plot.plugins.dragable.dragCanvas.isDragging) { + var dc = plot.plugins.dragable.dragCanvas; + // clear the canvas + var ctx = dc._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + dc.isDragging = false; + // redraw the series canvas at the new point. + var dp = dc._neighbor; + var s = plot.series[dp.seriesIndex]; + var drag = s.plugins.dragable; + // compute the new grid position with any constraints. + var x = (drag.constrainTo == 'y') ? dp.data[0] : datapos[s.xaxis]; + var y = (drag.constrainTo == 'x') ? dp.data[1] : datapos[s.yaxis]; + // var x = datapos[s.xaxis]; + // var y = datapos[s.yaxis]; + s.data[dp.pointIndex][0] = x; + s.data[dp.pointIndex][1] = y; + plot.drawSeries({preventJqPlotSeriesDrawTrigger:true}, dp.seriesIndex); + dc._neighbor = null; + ev.target.style.cursor = dc._cursors.pop(); + plot.target.trigger('jqplotDragStop', [gridpos, datapos]); + } + } +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.dragable.min.js b/plugin/jqplot/plugins/jqplot.dragable.min.js new file mode 100644 index 000000000..83c8e65cc --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.dragable.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(d){d.jqplot.Dragable=function(g){this.markerRenderer=new d.jqplot.MarkerRenderer({shadow:false});this.shapeRenderer=new d.jqplot.ShapeRenderer();this.isDragging=false;this.isOver=false;this._ctx;this._elem;this._point;this._gridData;this.color;this.constrainTo="none";d.extend(true,this,g)};function b(){d.jqplot.GenericCanvas.call(this);this.isDragging=false;this.isOver=false;this._neighbor;this._cursors=[]}b.prototype=new d.jqplot.GenericCanvas();b.prototype.constructor=b;d.jqplot.Dragable.parseOptions=function(i,h){var g=h||{};this.plugins.dragable=new d.jqplot.Dragable(g.dragable);this.isDragable=d.jqplot.config.enablePlugins};d.jqplot.Dragable.postPlotDraw=function(){if(this.plugins.dragable&&this.plugins.dragable.highlightCanvas){this.plugins.dragable.highlightCanvas.resetCanvas();this.plugins.dragable.highlightCanvas=null}this.plugins.dragable={previousCursor:"auto",isOver:false};this.plugins.dragable.dragCanvas=new b();this.eventCanvas._elem.before(this.plugins.dragable.dragCanvas.createElement(this._gridPadding,"jqplot-dragable-canvas",this._plotDimensions,this));var g=this.plugins.dragable.dragCanvas.setContext()};d.jqplot.preParseSeriesOptionsHooks.push(d.jqplot.Dragable.parseOptions);d.jqplot.postDrawHooks.push(d.jqplot.Dragable.postPlotDraw);d.jqplot.eventListenerHooks.push(["jqplotMouseMove",e]);d.jqplot.eventListenerHooks.push(["jqplotMouseDown",c]);d.jqplot.eventListenerHooks.push(["jqplotMouseUp",a]);function f(n,p){var q=n.series[p.seriesIndex];var m=q.plugins.dragable;var h=q.markerRenderer;var i=m.markerRenderer;i.style=h.style;i.lineWidth=h.lineWidth+2.5;i.size=h.size+5;if(!m.color){var l=d.jqplot.getColorComponents(h.color);var o=[l[0],l[1],l[2]];var k=(l[3]>=0.6)?l[3]*0.6:l[3]*(2-l[3]);m.color="rgba("+o[0]+","+o[1]+","+o[2]+","+k+")"}i.color=m.color;i.init();var g=(p.pointIndex>0)?p.pointIndex-1:0;var j=p.pointIndex+2;m._gridData=q.gridData.slice(g,j)}function e(o,l,h,t,m){if(m.plugins.dragable.dragCanvas.isDragging){var u=m.plugins.dragable.dragCanvas;var i=u._neighbor;var w=m.series[i.seriesIndex];var k=w.plugins.dragable;var r=w.gridData;var p=(k.constrainTo=="y")?i.gridData[0]:l.x;var n=(k.constrainTo=="x")?i.gridData[1]:l.y;var g=w._xaxis.series_p2u(p);var q=w._yaxis.series_p2u(n);var v=u._ctx;v.clearRect(0,0,v.canvas.width,v.canvas.height);if(i.pointIndex>0){k._gridData[1]=[p,n]}else{k._gridData[0]=[p,n]}m.series[i.seriesIndex].draw(u._ctx,{gridData:k._gridData,shadow:false,preventJqPlotSeriesDrawTrigger:true,color:k.color,markerOptions:{color:k.color,shadow:false},trendline:{show:false}});m.target.trigger("jqplotSeriesPointChange",[i.seriesIndex,i.pointIndex,[g,q],[p,n]])}else{if(t!=null){var j=m.series[t.seriesIndex];if(j.isDragable){var u=m.plugins.dragable.dragCanvas;if(!u.isOver){u._cursors.push(o.target.style.cursor);o.target.style.cursor="pointer"}u.isOver=true}}else{if(t==null){var u=m.plugins.dragable.dragCanvas;if(u.isOver){o.target.style.cursor=u._cursors.pop();u.isOver=false}}}}}function c(k,i,g,l,j){var m=j.plugins.dragable.dragCanvas;m._cursors.push(k.target.style.cursor);if(l!=null){var o=j.series[l.seriesIndex];var h=o.plugins.dragable;if(o.isDragable&&!m.isDragging){m._neighbor=l;m.isDragging=true;f(j,l);h.markerRenderer.draw(o.gridData[l.pointIndex][0],o.gridData[l.pointIndex][1],m._ctx);k.target.style.cursor="move";j.target.trigger("jqplotDragStart",[l.seriesIndex,l.pointIndex,i,g])}}else{var n=m._ctx;n.clearRect(0,0,n.canvas.width,n.canvas.height);m.isDragging=false}}function a(m,j,g,o,k){if(k.plugins.dragable.dragCanvas.isDragging){var p=k.plugins.dragable.dragCanvas;var q=p._ctx;q.clearRect(0,0,q.canvas.width,q.canvas.height);p.isDragging=false;var h=p._neighbor;var r=k.series[h.seriesIndex];var i=r.plugins.dragable;var n=(i.constrainTo=="y")?h.data[0]:g[r.xaxis];var l=(i.constrainTo=="x")?h.data[1]:g[r.yaxis];r.data[h.pointIndex][0]=n;r.data[h.pointIndex][1]=l;k.drawSeries({preventJqPlotSeriesDrawTrigger:true},h.seriesIndex);p._neighbor=null;m.target.style.cursor=p._cursors.pop();k.target.trigger("jqplotDragStop",[j,g])}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.enhancedLegendRenderer.js b/plugin/jqplot/plugins/jqplot.enhancedLegendRenderer.js new file mode 100644 index 000000000..5a2cbc616 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.enhancedLegendRenderer.js @@ -0,0 +1,305 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + // class $.jqplot.EnhancedLegendRenderer + // Legend renderer which can specify the number of rows and/or columns in the legend. + $.jqplot.EnhancedLegendRenderer = function(){ + $.jqplot.TableLegendRenderer.call(this); + }; + + $.jqplot.EnhancedLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); + $.jqplot.EnhancedLegendRenderer.prototype.constructor = $.jqplot.EnhancedLegendRenderer; + + // called with scope of legend. + $.jqplot.EnhancedLegendRenderer.prototype.init = function(options) { + // prop: numberRows + // Maximum number of rows in the legend. 0 or null for unlimited. + this.numberRows = null; + // prop: numberColumns + // Maximum number of columns in the legend. 0 or null for unlimited. + this.numberColumns = null; + // prop: seriesToggle + // false to not enable series on/off toggling on the legend. + // true or a fadein/fadeout speed (number of milliseconds or 'fast', 'normal', 'slow') + // to enable show/hide of series on click of legend item. + this.seriesToggle = 'normal'; + // prop: seriesToggleReplot + // True to replot the chart after toggling series on/off. + // This will set the series show property to false. + // This allows for rescaling or other maniplation of chart. + // Set to an options object (e.g. {resetAxes: true}) for replot options. + this.seriesToggleReplot = false; + // prop: disableIEFading + // true to toggle series with a show/hide method only and not allow fading in/out. + // This is to overcome poor performance of fade in some versions of IE. + this.disableIEFading = true; + $.extend(true, this, options); + + if (this.seriesToggle) { + $.jqplot.postDrawHooks.push(postDraw); + } + }; + + // called with scope of legend + $.jqplot.EnhancedLegendRenderer.prototype.draw = function(offsets, plot) { + var legend = this; + if (this.show) { + var series = this._series; + var s; + var ss = 'position:absolute;'; + ss += (this.background) ? 'background:'+this.background+';' : ''; + ss += (this.border) ? 'border:'+this.border+';' : ''; + ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; + ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; + ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; + ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; + ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; + ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; + ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; + this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); + if (this.seriesToggle) { + this._elem.css('z-index', '3'); + } + + var pad = false, + reverse = false, + nr, nc; + if (this.numberRows) { + nr = this.numberRows; + if (!this.numberColumns){ + nc = Math.ceil(series.length/nr); + } + else{ + nc = this.numberColumns; + } + } + else if (this.numberColumns) { + nc = this.numberColumns; + nr = Math.ceil(series.length/this.numberColumns); + } + else { + nr = series.length; + nc = 1; + } + + var i, j, tr, td1, td2, lt, rs, div, div0, div1; + var idx = 0; + // check to see if we need to reverse + for (i=series.length-1; i>=0; i--) { + if (nc == 1 && series[i]._stack || series[i].renderer.constructor == $.jqplot.BezierCurveRenderer){ + reverse = true; + } + } + + for (i=0; i<nr; i++) { + tr = $(document.createElement('tr')); + tr.addClass('jqplot-table-legend'); + if (reverse){ + tr.prependTo(this._elem); + } + else{ + tr.appendTo(this._elem); + } + for (j=0; j<nc; j++) { + if (idx < series.length && (series[idx].show || series[idx].showLabel)){ + s = series[idx]; + lt = this.labels[idx] || s.label.toString(); + if (lt) { + var color = s.color; + if (!reverse){ + if (i>0){ + pad = true; + } + else{ + pad = false; + } + } + else{ + if (i == nr -1){ + pad = false; + } + else{ + pad = true; + } + } + rs = (pad) ? this.rowSpacing : '0'; + + td1 = $(document.createElement('td')); + td1.addClass('jqplot-table-legend jqplot-table-legend-swatch'); + td1.css({textAlign: 'center', paddingTop: rs}); + + div0 = $(document.createElement('div')); + div0.addClass('jqplot-table-legend-swatch-outline'); + div1 = $(document.createElement('div')); + div1.addClass('jqplot-table-legend-swatch'); + div1.css({backgroundColor: color, borderColor: color}); + + td1.append(div0.append(div1)); + + td2 = $(document.createElement('td')); + td2.addClass('jqplot-table-legend jqplot-table-legend-label'); + td2.css('paddingTop', rs); + + // td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ + // '<div><div class="jqplot-table-legend-swatch" style="background-color:'+color+';border-color:'+color+';"></div>'+ + // '</div></td>'); + // td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); + if (this.escapeHtml){ + td2.text(lt); + } + else { + td2.html(lt); + } + if (reverse) { + if (this.showLabels) {td2.prependTo(tr);} + if (this.showSwatches) {td1.prependTo(tr);} + } + else { + if (this.showSwatches) {td1.appendTo(tr);} + if (this.showLabels) {td2.appendTo(tr);} + } + + if (this.seriesToggle) { + + // add an overlay for clicking series on/off + // div0 = $(document.createElement('div')); + // div0.addClass('jqplot-table-legend-overlay'); + // div0.css({position:'relative', left:0, top:0, height:'100%', width:'100%'}); + // tr.append(div0); + + var speed; + if (typeof(this.seriesToggle) === 'string' || typeof(this.seriesToggle) === 'number') { + if (!$.jqplot.use_excanvas || !this.disableIEFading) { + speed = this.seriesToggle; + } + } + if (this.showSwatches) { + td1.bind('click', {series:s, speed:speed, plot: plot, replot:this.seriesToggleReplot}, handleToggle); + td1.addClass('jqplot-seriesToggle'); + } + if (this.showLabels) { + td2.bind('click', {series:s, speed:speed, plot: plot, replot:this.seriesToggleReplot}, handleToggle); + td2.addClass('jqplot-seriesToggle'); + } + + // for series that are already hidden, add the hidden class + if (!s.show && s.showLabel) { + td1.addClass('jqplot-series-hidden'); + td2.addClass('jqplot-series-hidden'); + } + } + + pad = true; + } + } + idx++; + } + + td1 = td2 = div0 = div1 = null; + } + } + return this._elem; + }; + + var handleToggle = function (ev) { + var d = ev.data, + s = d.series, + replot = d.replot, + plot = d.plot, + speed = d.speed, + sidx = s.index, + showing = false; + + if (s.canvas._elem.is(':hidden') || !s.show) { + showing = true; + } + + var doLegendToggle = function() { + + if (replot) { + var opts = {}; + + if ($.isPlainObject(replot)) { + $.extend(true, opts, replot); + } + + plot.replot(opts); + // if showing, there was no canvas element to fade in, so hide here + // and then do a fade in. + if (showing && speed) { + var s = plot.series[sidx]; + + if (s.shadowCanvas._elem) { + s.shadowCanvas._elem.hide().fadeIn(speed); + } + s.canvas._elem.hide().fadeIn(speed); + s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).hide().fadeIn(speed); + } + + } + + else { + var s = plot.series[sidx]; + + if (s.canvas._elem.is(':hidden') || !s.show) { + // Not sure if there is a better way to check for showSwatches and showLabels === true. + // Test for "undefined" since default values for both showSwatches and showLables is true. + if (typeof plot.options.legend.showSwatches === 'undefined' || plot.options.legend.showSwatches === true) { + plot.legend._elem.find('td').eq(sidx * 2).addClass('jqplot-series-hidden'); + } + if (typeof plot.options.legend.showLabels === 'undefined' || plot.options.legend.showLabels === true) { + plot.legend._elem.find('td').eq((sidx * 2) + 1).addClass('jqplot-series-hidden'); + } + } + else { + if (typeof plot.options.legend.showSwatches === 'undefined' || plot.options.legend.showSwatches === true) { + plot.legend._elem.find('td').eq(sidx * 2).removeClass('jqplot-series-hidden'); + } + if (typeof plot.options.legend.showLabels === 'undefined' || plot.options.legend.showLabels === true) { + plot.legend._elem.find('td').eq((sidx * 2) + 1).removeClass('jqplot-series-hidden'); + } + } + + } + + }; + + s.toggleDisplay(ev, doLegendToggle); + }; + + // called with scope of plot. + var postDraw = function () { + if (this.legend.renderer.constructor == $.jqplot.EnhancedLegendRenderer && this.legend.seriesToggle){ + var e = this.legend._elem.detach(); + this.eventCanvas._elem.after(e); + } + }; +})(jQuery); diff --git a/plugin/jqplot/plugins/jqplot.enhancedLegendRenderer.min.js b/plugin/jqplot/plugins/jqplot.enhancedLegendRenderer.min.js new file mode 100644 index 000000000..968e77cd0 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.enhancedLegendRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(c){c.jqplot.EnhancedLegendRenderer=function(){c.jqplot.TableLegendRenderer.call(this)};c.jqplot.EnhancedLegendRenderer.prototype=new c.jqplot.TableLegendRenderer();c.jqplot.EnhancedLegendRenderer.prototype.constructor=c.jqplot.EnhancedLegendRenderer;c.jqplot.EnhancedLegendRenderer.prototype.init=function(d){this.numberRows=null;this.numberColumns=null;this.seriesToggle="normal";this.seriesToggleReplot=false;this.disableIEFading=true;c.extend(true,this,d);if(this.seriesToggle){c.jqplot.postDrawHooks.push(b)}};c.jqplot.EnhancedLegendRenderer.prototype.draw=function(m,y){var f=this;if(this.show){var r=this._series;var u;var w="position:absolute;";w+=(this.background)?"background:"+this.background+";":"";w+=(this.border)?"border:"+this.border+";":"";w+=(this.fontSize)?"font-size:"+this.fontSize+";":"";w+=(this.fontFamily)?"font-family:"+this.fontFamily+";":"";w+=(this.textColor)?"color:"+this.textColor+";":"";w+=(this.marginTop!=null)?"margin-top:"+this.marginTop+";":"";w+=(this.marginBottom!=null)?"margin-bottom:"+this.marginBottom+";":"";w+=(this.marginLeft!=null)?"margin-left:"+this.marginLeft+";":"";w+=(this.marginRight!=null)?"margin-right:"+this.marginRight+";":"";this._elem=c('<table class="jqplot-table-legend" style="'+w+'"></table>');if(this.seriesToggle){this._elem.css("z-index","3")}var C=false,q=false,d,o;if(this.numberRows){d=this.numberRows;if(!this.numberColumns){o=Math.ceil(r.length/d)}else{o=this.numberColumns}}else{if(this.numberColumns){o=this.numberColumns;d=Math.ceil(r.length/this.numberColumns)}else{d=r.length;o=1}}var B,z,e,l,k,n,p,t,h,g;var v=0;for(B=r.length-1;B>=0;B--){if(o==1&&r[B]._stack||r[B].renderer.constructor==c.jqplot.BezierCurveRenderer){q=true}}for(B=0;B<d;B++){e=c(document.createElement("tr"));e.addClass("jqplot-table-legend");if(q){e.prependTo(this._elem)}else{e.appendTo(this._elem)}for(z=0;z<o;z++){if(v<r.length&&(r[v].show||r[v].showLabel)){u=r[v];n=this.labels[v]||u.label.toString();if(n){var x=u.color;if(!q){if(B>0){C=true}else{C=false}}else{if(B==d-1){C=false}else{C=true}}p=(C)?this.rowSpacing:"0";l=c(document.createElement("td"));l.addClass("jqplot-table-legend jqplot-table-legend-swatch");l.css({textAlign:"center",paddingTop:p});h=c(document.createElement("div"));h.addClass("jqplot-table-legend-swatch-outline");g=c(document.createElement("div"));g.addClass("jqplot-table-legend-swatch");g.css({backgroundColor:x,borderColor:x});l.append(h.append(g));k=c(document.createElement("td"));k.addClass("jqplot-table-legend jqplot-table-legend-label");k.css("paddingTop",p);if(this.escapeHtml){k.text(n)}else{k.html(n)}if(q){if(this.showLabels){k.prependTo(e)}if(this.showSwatches){l.prependTo(e)}}else{if(this.showSwatches){l.appendTo(e)}if(this.showLabels){k.appendTo(e)}}if(this.seriesToggle){var A;if(typeof(this.seriesToggle)==="string"||typeof(this.seriesToggle)==="number"){if(!c.jqplot.use_excanvas||!this.disableIEFading){A=this.seriesToggle}}if(this.showSwatches){l.bind("click",{series:u,speed:A,plot:y,replot:this.seriesToggleReplot},a);l.addClass("jqplot-seriesToggle")}if(this.showLabels){k.bind("click",{series:u,speed:A,plot:y,replot:this.seriesToggleReplot},a);k.addClass("jqplot-seriesToggle")}if(!u.show&&u.showLabel){l.addClass("jqplot-series-hidden");k.addClass("jqplot-series-hidden")}}C=true}}v++}l=k=h=g=null}}return this._elem};var a=function(j){var i=j.data,m=i.series,k=i.replot,h=i.plot,f=i.speed,l=m.index,g=false;if(m.canvas._elem.is(":hidden")||!m.show){g=true}var e=function(){if(k){var n={};if(c.isPlainObject(k)){c.extend(true,n,k)}h.replot(n);if(g&&f){var d=h.series[l];if(d.shadowCanvas._elem){d.shadowCanvas._elem.hide().fadeIn(f)}d.canvas._elem.hide().fadeIn(f);d.canvas._elem.nextAll(".jqplot-point-label.jqplot-series-"+d.index).hide().fadeIn(f)}}else{var d=h.series[l];if(d.canvas._elem.is(":hidden")||!d.show){if(typeof h.options.legend.showSwatches==="undefined"||h.options.legend.showSwatches===true){h.legend._elem.find("td").eq(l*2).addClass("jqplot-series-hidden")}if(typeof h.options.legend.showLabels==="undefined"||h.options.legend.showLabels===true){h.legend._elem.find("td").eq((l*2)+1).addClass("jqplot-series-hidden")}}else{if(typeof h.options.legend.showSwatches==="undefined"||h.options.legend.showSwatches===true){h.legend._elem.find("td").eq(l*2).removeClass("jqplot-series-hidden")}if(typeof h.options.legend.showLabels==="undefined"||h.options.legend.showLabels===true){h.legend._elem.find("td").eq((l*2)+1).removeClass("jqplot-series-hidden")}}}};m.toggleDisplay(j,e)};var b=function(){if(this.legend.renderer.constructor==c.jqplot.EnhancedLegendRenderer&&this.legend.seriesToggle){var d=this.legend._elem.detach();this.eventCanvas._elem.after(d)}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.funnelRenderer.js b/plugin/jqplot/plugins/jqplot.funnelRenderer.js new file mode 100644 index 000000000..2cbc9c2c7 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.funnelRenderer.js @@ -0,0 +1,943 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.FunnelRenderer + * Plugin renderer to draw a funnel chart. + * x values, if present, will be used as labels. + * y values give area size. + * + * Funnel charts will draw a single series + * only. + * + * To use this renderer, you need to include the + * funnel renderer plugin, for example: + * + * > <script type="text/javascript" src="plugins/jqplot.funnelRenderer.js"></script> + * + * Properties described here are passed into the $.jqplot function + * as options on the series renderer. For example: + * + * > plot2 = $.jqplot('chart2', [s1, s2], { + * > seriesDefaults: { + * > renderer:$.jqplot.FunnelRenderer, + * > rendererOptions:{ + * > sectionMargin: 12, + * > widthRatio: 0.3 + * > } + * > } + * > }); + * + * IMPORTANT + * + * *The funnel renderer will reorder data in descending order* so the largest value in + * the data set is first and displayed on top of the funnel. Data will then + * be displayed in descending order down the funnel. The area of each funnel + * section will correspond to the value of each data point relative to the sum + * of all values. That is section area is proportional to section value divided by + * sum of all section values. + * + * If your data is not in descending order when passed into the plot, *it will be + * reordered* when stored in the series.data property. A copy of the unordered + * data is kept in the series._unorderedData property. + * + * A funnel plot will trigger events on the plot target + * according to user interaction. All events return the event object, + * the series index, the point (section) index, and the point data for + * the appropriate section. *Note* the point index will referr to the ordered + * data, not the original unordered data. + * + * 'jqplotDataMouseOver' - triggered when mousing over a section. + * 'jqplotDataHighlight' - triggered the first time user mouses over a section, + * if highlighting is enabled. + * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of + * a highlighted section. + * 'jqplotDataClick' - triggered when the user clicks on a section. + * 'jqplotDataRightClick' - tiggered when the user right clicks on a section if + * the "captureRightClick" option is set to true on the plot. + */ + $.jqplot.FunnelRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.FunnelRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.FunnelRenderer.prototype.constructor = $.jqplot.FunnelRenderer; + + // called with scope of a series + $.jqplot.FunnelRenderer.prototype.init = function(options, plot) { + // Group: Properties + // + // prop: padding + // padding between the funnel and plot edges, legend, etc. + this.padding = {top: 20, right: 20, bottom: 20, left: 20}; + // prop: sectionMargin + // spacing between funnel sections in pixels. + this.sectionMargin = 6; + // prop: fill + // true or false, whether to fill the areas. + this.fill = true; + // prop: shadowOffset + // offset of the shadow from the area and offset of + // each succesive stroke of the shadow from the last. + this.shadowOffset = 2; + // prop: shadowAlpha + // transparency of the shadow (0 = transparent, 1 = opaque) + this.shadowAlpha = 0.07; + // prop: shadowDepth + // number of strokes to apply to the shadow, + // each stroke offset shadowOffset from the last. + this.shadowDepth = 5; + // prop: highlightMouseOver + // True to highlight area when moused over. + // This must be false to enable highlightMouseDown to highlight when clicking on a area. + this.highlightMouseOver = true; + // prop: highlightMouseDown + // True to highlight when a mouse button is pressed over a area. + // This will be disabled if highlightMouseOver is true. + this.highlightMouseDown = false; + // prop: highlightColors + // array of colors to use when highlighting an area. + this.highlightColors = []; + // prop: widthRatio + // The ratio of the width of the top of the funnel to the bottom. + // a ratio of 0 will make an upside down pyramid. + this.widthRatio = 0.2; + // prop: lineWidth + // width of line if areas are stroked and not filled. + this.lineWidth = 2; + // prop: dataLabels + // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices. + // Defaults to percentage of each pie slice. + this.dataLabels = 'percent'; + // prop: showDataLabels + // true to show data labels on slices. + this.showDataLabels = false; + // prop: dataLabelFormatString + // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage. + this.dataLabelFormatString = null; + // prop: dataLabelThreshold + // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed. + // This applies to all label types, not just to percentage labels. + this.dataLabelThreshold = 3; + this._type = 'funnel'; + + this.tickRenderer = $.jqplot.FunnelTickRenderer; + + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver + if (options.highlightMouseDown && options.highlightMouseOver == null) { + options.highlightMouseOver = false; + } + + $.extend(true, this, options); + + // index of the currenty highlighted point, if any + this._highlightedPoint = null; + + // lengths of bases, or horizontal sides of areas of trapezoid. + this._bases = []; + // total area + this._atot; + // areas of segments. + this._areas = []; + // vertical lengths of segments. + this._lengths = []; + // angle of the funnel to vertical. + this._angle; + this._dataIndices = []; + + // sort data + this._unorderedData = $.extend(true, [], this.data); + var idxs = $.extend(true, [], this.data); + for (var i=0; i<idxs.length; i++) { + idxs[i].push(i); + } + this.data.sort( function (a, b) { return b[1] - a[1]; } ); + idxs.sort( function (a, b) { return b[1] - a[1]; }); + for (var i=0; i<idxs.length; i++) { + this._dataIndices.push(idxs[i][2]); + } + + // set highlight colors if none provided + if (this.highlightColors.length == 0) { + for (var i=0; i<this.seriesColors.length; i++){ + var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var sum = newrgb[0] + newrgb[1] + newrgb[2]; + for (var j=0; j<3; j++) { + // when darkening, lowest color component can be is 60. + newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.4 * (255 - newrgb[j]); + newrgb[j] = parseInt(newrgb[j], 10); + } + this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); + } + } + + plot.postParseOptionsHooks.addOnce(postParseOptions); + plot.postInitHooks.addOnce(postInit); + plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); + plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); + plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); + plot.eventListenerHooks.addOnce('jqplotClick', handleClick); + plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); + plot.postDrawHooks.addOnce(postPlotDraw); + + }; + + // gridData will be of form [label, percentage of total] + $.jqplot.FunnelRenderer.prototype.setGridData = function(plot) { + // set gridData property. This will hold angle in radians of each data point. + var sum = 0; + var td = []; + for (var i=0; i<this.data.length; i++){ + sum += this.data[i][1]; + td.push([this.data[i][0], this.data[i][1]]); + } + + // normalize y values, so areas are proportional. + for (var i=0; i<td.length; i++) { + td[i][1] = td[i][1]/sum; + } + + this._bases = new Array(td.length + 1); + this._lengths = new Array(td.length); + + this.gridData = td; + }; + + $.jqplot.FunnelRenderer.prototype.makeGridData = function(data, plot) { + // set gridData property. This will hold angle in radians of each data point. + var sum = 0; + var td = []; + for (var i=0; i<this.data.length; i++){ + sum += this.data[i][1]; + td.push([this.data[i][0], this.data[i][1]]); + } + + // normalize y values, so areas are proportional. + for (var i=0; i<td.length; i++) { + td[i][1] = td[i][1]/sum; + } + + this._bases = new Array(td.length + 1); + this._lengths = new Array(td.length); + + return td; + }; + + $.jqplot.FunnelRenderer.prototype.drawSection = function (ctx, vertices, color, isShadow) { + var fill = this.fill; + var lineWidth = this.lineWidth; + ctx.save(); + + if (isShadow) { + for (var i=0; i<this.shadowDepth; i++) { + ctx.save(); + ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); + doDraw(); + } + } + + else { + doDraw(); + } + + function doDraw () { + ctx.beginPath(); + ctx.fillStyle = color; + ctx.strokeStyle = color; + ctx.lineWidth = lineWidth; + ctx.moveTo(vertices[0][0], vertices[0][1]); + for (var i=1; i<4; i++) { + ctx.lineTo(vertices[i][0], vertices[i][1]); + } + ctx.closePath(); + if (fill) { + ctx.fill(); + } + else { + ctx.stroke(); + } + } + + if (isShadow) { + for (var i=0; i<this.shadowDepth; i++) { + ctx.restore(); + } + } + + ctx.restore(); + }; + + // called with scope of series + $.jqplot.FunnelRenderer.prototype.draw = function (ctx, gd, options, plot) { + var i; + var opts = (options != undefined) ? options : {}; + // offset and direction of offset due to legend placement + var offx = 0; + var offy = 0; + var trans = 1; + this._areas = []; + // var colorGenerator = new this.colorGenerator(this.seriesColors); + if (options.legendInfo && options.legendInfo.placement == 'insideGrid') { + var li = options.legendInfo; + switch (li.location) { + case 'nw': + offx = li.width + li.xoffset; + break; + case 'w': + offx = li.width + li.xoffset; + break; + case 'sw': + offx = li.width + li.xoffset; + break; + case 'ne': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'e': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'se': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'n': + offy = li.height + li.yoffset; + break; + case 's': + offy = li.height + li.yoffset; + trans = -1; + break; + default: + break; + } + } + + var loff = (trans==1) ? this.padding.left + offx : this.padding.left; + var toff = (trans==1) ? this.padding.top + offy : this.padding.top; + var roff = (trans==-1) ? this.padding.right + offx : this.padding.right; + var boff = (trans==-1) ? this.padding.bottom + offy : this.padding.bottom; + + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var cw = ctx.canvas.width; + var ch = ctx.canvas.height; + this._bases[0] = cw - loff - roff; + var ltot = this._length = ch - toff - boff; + + var hend = this._bases[0]*this.widthRatio; + this._atot = ltot/2 * (this._bases[0] + this._bases[0]*this.widthRatio); + + this._angle = Math.atan((this._bases[0] - hend)/2/ltot); + + for (i=0; i<gd.length; i++) { + this._areas.push(gd[i][1] * this._atot); + } + + + var guess, err, count, lsum=0; + var tolerance = 0.0001; + + for (i=0; i<this._areas.length; i++) { + guess = this._areas[i]/this._bases[i]; + err = 999999; + this._lengths[i] = guess; + count = 0; + while (err > this._lengths[i]*tolerance && count < 100) { + this._lengths[i] = this._areas[i]/(this._bases[i] - this._lengths[i] * Math.tan(this._angle)); + err = Math.abs(this._lengths[i] - guess); + this._bases[i+1] = this._bases[i] - (2*this._lengths[i]*Math.tan(this._angle)); + guess = this._lengths[i]; + count++; + } + lsum += this._lengths[i]; + } + + // figure out vertices of each section + this._vertices = new Array(gd.length); + + // these are 4 coners of entire trapezoid + var p0 = [loff, toff], + p1 = [loff+this._bases[0], toff], + p2 = [loff + (this._bases[0] - this._bases[this._bases.length-1])/2, toff + this._length], + p3 = [p2[0] + this._bases[this._bases.length-1], p2[1]]; + + // equations of right and left sides, returns x, y values given height of section (y value) + function findleft (l) { + var m = (p0[1] - p2[1])/(p0[0] - p2[0]); + var b = p0[1] - m*p0[0]; + var y = l + p0[1]; + + return [(y - b)/m, y]; + } + + function findright (l) { + var m = (p1[1] - p3[1])/(p1[0] - p3[0]); + var b = p1[1] - m*p1[0]; + var y = l + p1[1]; + + return [(y - b)/m, y]; + } + + var x = offx, y = offy; + var h=0, adj=0; + + for (i=0; i<gd.length; i++) { + this._vertices[i] = new Array(); + var v = this._vertices[i]; + var sm = this.sectionMargin; + if (i == 0) { + adj = 0; + } + if (i == 1) { + adj = sm/3; + } + else if (i > 0 && i < gd.length-1) { + adj = sm/2; + } + else if (i == gd.length -1) { + adj = 2*sm/3; + } + v.push(findleft(h+adj)); + v.push(findright(h+adj)); + h += this._lengths[i]; + if (i == 0) { + adj = -2*sm/3; + } + else if (i > 0 && i < gd.length-1) { + adj = -sm/2; + } + else if (i == gd.length - 1) { + adj = 0; + } + v.push(findright(h+adj)); + v.push(findleft(h+adj)); + + } + + if (this.shadow) { + var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; + for (var i=0; i<gd.length; i++) { + this.renderer.drawSection.call (this, ctx, this._vertices[i], shadowColor, true); + } + + } + for (var i=0; i<gd.length; i++) { + var v = this._vertices[i]; + this.renderer.drawSection.call (this, ctx, v, this.seriesColors[i]); + + if (this.showDataLabels && gd[i][1]*100 >= this.dataLabelThreshold) { + var fstr, label; + + if (this.dataLabels == 'label') { + fstr = this.dataLabelFormatString || '%s'; + label = $.jqplot.sprintf(fstr, gd[i][0]); + } + else if (this.dataLabels == 'value') { + fstr = this.dataLabelFormatString || '%d'; + label = $.jqplot.sprintf(fstr, this.data[i][1]); + } + else if (this.dataLabels == 'percent') { + fstr = this.dataLabelFormatString || '%d%%'; + label = $.jqplot.sprintf(fstr, gd[i][1]*100); + } + else if (this.dataLabels.constructor == Array) { + fstr = this.dataLabelFormatString || '%s'; + label = $.jqplot.sprintf(fstr, this.dataLabels[this._dataIndices[i]]); + } + + var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge; + + var x = (v[0][0] + v[1][0])/2 + this.canvas._offsets.left; + var y = (v[1][1] + v[2][1])/2 + this.canvas._offsets.top; + + var labelelem = $('<span class="jqplot-funnel-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem); + x -= labelelem.width()/2; + y -= labelelem.height()/2; + x = Math.round(x); + y = Math.round(y); + labelelem.css({left: x, top: y}); + } + + } + + }; + + $.jqplot.FunnelAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + }; + + $.jqplot.FunnelAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.FunnelAxisRenderer.prototype.constructor = $.jqplot.FunnelAxisRenderer; + + + // There are no traditional axes on a funnel chart. We just need to provide + // dummy objects with properties so the plot will render. + // called with scope of axis object. + $.jqplot.FunnelAxisRenderer.prototype.init = function(options){ + // + this.tickRenderer = $.jqplot.FunnelTickRenderer; + $.extend(true, this, options); + // I don't think I'm going to need _dataBounds here. + // have to go Axis scaling in a way to fit chart onto plot area + // and provide u2p and p2u functionality for mouse cursor, etc. + // for convienence set _dataBounds to 0 and 100 and + // set min/max to 0 and 100. + this._dataBounds = {min:0, max:100}; + this.min = 0; + this.max = 100; + this.showTicks = false; + this.ticks = []; + this.showMark = false; + this.show = false; + }; + + + + /** + * Class: $.jqplot.FunnelLegendRenderer + * Legend Renderer specific to funnel plots. Set by default + * when the user creates a funnel plot. + */ + $.jqplot.FunnelLegendRenderer = function(){ + $.jqplot.TableLegendRenderer.call(this); + }; + + $.jqplot.FunnelLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); + $.jqplot.FunnelLegendRenderer.prototype.constructor = $.jqplot.FunnelLegendRenderer; + + $.jqplot.FunnelLegendRenderer.prototype.init = function(options) { + // Group: Properties + // + // prop: numberRows + // Maximum number of rows in the legend. 0 or null for unlimited. + this.numberRows = null; + // prop: numberColumns + // Maximum number of columns in the legend. 0 or null for unlimited. + this.numberColumns = null; + $.extend(true, this, options); + }; + + // called with context of legend + $.jqplot.FunnelLegendRenderer.prototype.draw = function() { + var legend = this; + if (this.show) { + var series = this._series; + var ss = 'position:absolute;'; + ss += (this.background) ? 'background:'+this.background+';' : ''; + ss += (this.border) ? 'border:'+this.border+';' : ''; + ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; + ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; + ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; + ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; + ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; + ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; + ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; + this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); + // Funnel charts legends don't go by number of series, but by number of data points + // in the series. Refactor things here for that. + + var pad = false, + reverse = false, + nr, nc; + var s = series[0]; + var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); + + if (s.show) { + var pd = s.data; + if (this.numberRows) { + nr = this.numberRows; + if (!this.numberColumns){ + nc = Math.ceil(pd.length/nr); + } + else{ + nc = this.numberColumns; + } + } + else if (this.numberColumns) { + nc = this.numberColumns; + nr = Math.ceil(pd.length/this.numberColumns); + } + else { + nr = pd.length; + nc = 1; + } + + var i, j, tr, td1, td2, lt, rs, color; + var idx = 0; + + for (i=0; i<nr; i++) { + if (reverse){ + tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); + } + else{ + tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); + } + for (j=0; j<nc; j++) { + if (idx < pd.length){ + lt = this.labels[idx] || pd[idx][0].toString(); + color = colorGenerator.next(); + if (!reverse){ + if (i>0){ + pad = true; + } + else{ + pad = false; + } + } + else{ + if (i == nr -1){ + pad = false; + } + else{ + pad = true; + } + } + rs = (pad) ? this.rowSpacing : '0'; + + td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ + '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ + '</div></td>'); + td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); + if (this.escapeHtml){ + td2.text(lt); + } + else { + td2.html(lt); + } + if (reverse) { + td2.prependTo(tr); + td1.prependTo(tr); + } + else { + td1.appendTo(tr); + td2.appendTo(tr); + } + pad = true; + } + idx++; + } + } + } + } + return this._elem; + }; + + // $.jqplot.FunnelLegendRenderer.prototype.pack = function(offsets) { + // if (this.show) { + // // fake a grid for positioning + // var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom}; + // if (this.placement == 'insideGrid') { + // switch (this.location) { + // case 'nw': + // var a = grid._left + this.xoffset; + // var b = grid._top + this.yoffset; + // this._elem.css('left', a); + // this._elem.css('top', b); + // break; + // case 'n': + // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + // var b = grid._top + this.yoffset; + // this._elem.css('left', a); + // this._elem.css('top', b); + // break; + // case 'ne': + // var a = offsets.right + this.xoffset; + // var b = grid._top + this.yoffset; + // this._elem.css({right:a, top:b}); + // break; + // case 'e': + // var a = offsets.right + this.xoffset; + // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + // this._elem.css({right:a, top:b}); + // break; + // case 'se': + // var a = offsets.right + this.xoffset; + // var b = offsets.bottom + this.yoffset; + // this._elem.css({right:a, bottom:b}); + // break; + // case 's': + // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + // var b = offsets.bottom + this.yoffset; + // this._elem.css({left:a, bottom:b}); + // break; + // case 'sw': + // var a = grid._left + this.xoffset; + // var b = offsets.bottom + this.yoffset; + // this._elem.css({left:a, bottom:b}); + // break; + // case 'w': + // var a = grid._left + this.xoffset; + // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + // this._elem.css({left:a, top:b}); + // break; + // default: // same as 'se' + // var a = grid._right - this.xoffset; + // var b = grid._bottom + this.yoffset; + // this._elem.css({right:a, bottom:b}); + // break; + // } + // + // } + // else { + // switch (this.location) { + // case 'nw': + // var a = this._plotDimensions.width - grid._left + this.xoffset; + // var b = grid._top + this.yoffset; + // this._elem.css('right', a); + // this._elem.css('top', b); + // break; + // case 'n': + // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + // var b = this._plotDimensions.height - grid._top + this.yoffset; + // this._elem.css('left', a); + // this._elem.css('bottom', b); + // break; + // case 'ne': + // var a = this._plotDimensions.width - offsets.right + this.xoffset; + // var b = grid._top + this.yoffset; + // this._elem.css({left:a, top:b}); + // break; + // case 'e': + // var a = this._plotDimensions.width - offsets.right + this.xoffset; + // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + // this._elem.css({left:a, top:b}); + // break; + // case 'se': + // var a = this._plotDimensions.width - offsets.right + this.xoffset; + // var b = offsets.bottom + this.yoffset; + // this._elem.css({left:a, bottom:b}); + // break; + // case 's': + // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + // var b = this._plotDimensions.height - offsets.bottom + this.yoffset; + // this._elem.css({left:a, top:b}); + // break; + // case 'sw': + // var a = this._plotDimensions.width - grid._left + this.xoffset; + // var b = offsets.bottom + this.yoffset; + // this._elem.css({right:a, bottom:b}); + // break; + // case 'w': + // var a = this._plotDimensions.width - grid._left + this.xoffset; + // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + // this._elem.css({right:a, top:b}); + // break; + // default: // same as 'se' + // var a = grid._right - this.xoffset; + // var b = grid._bottom + this.yoffset; + // this._elem.css({right:a, bottom:b}); + // break; + // } + // } + // } + // }; + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + options = options || {}; + options.axesDefaults = options.axesDefaults || {}; + options.legend = options.legend || {}; + options.seriesDefaults = options.seriesDefaults || {}; + // only set these if there is a funnel series + var setopts = false; + if (options.seriesDefaults.renderer == $.jqplot.FunnelRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer == $.jqplot.FunnelRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.FunnelAxisRenderer; + options.legend.renderer = $.jqplot.FunnelLegendRenderer; + options.legend.preDraw = true; + options.sortData = false; + options.seriesDefaults.pointLabels = {show: false}; + } + } + + function postInit(target, data, options) { + // if multiple series, add a reference to the previous one so that + // funnel rings can nest. + for (var i=0; i<this.series.length; i++) { + if (this.series[i].renderer.constructor == $.jqplot.FunnelRenderer) { + // don't allow mouseover and mousedown at same time. + if (this.series[i].highlightMouseOver) { + this.series[i].highlightMouseDown = false; + } + } + } + } + + // called with scope of plot + function postParseOptions(options) { + for (var i=0; i<this.series.length; i++) { + this.series[i].seriesColors = this.seriesColors; + this.series[i].colorGenerator = $.jqplot.colorGenerator; + } + } + + function highlight (plot, sidx, pidx) { + var s = plot.series[sidx]; + var canvas = plot.plugins.funnelRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); + s._highlightedPoint = pidx; + plot.plugins.funnelRenderer.highlightedSeriesIndex = sidx; + s.renderer.drawSection.call(s, canvas._ctx, s._vertices[pidx], s.highlightColors[pidx], false); + } + + function unhighlight (plot) { + var canvas = plot.plugins.funnelRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); + for (var i=0; i<plot.series.length; i++) { + plot.series[i]._highlightedPoint = null; + } + plot.plugins.funnelRenderer.highlightedSeriesIndex = null; + plot.target.trigger('jqplotDataUnhighlight'); + } + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt1 = jQuery.Event('jqplotDataMouseOver'); + evt1.pageX = ev.pageX; + evt1.pageY = ev.pageY; + plot.target.trigger(evt1, ins); + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { + var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + } + + function handleClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt = jQuery.Event('jqplotDataClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + function handleRightClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + var evt = jQuery.Event('jqplotDataRightClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + function postPlotDraw() { + // Memory Leaks patch + if (this.plugins.funnelRenderer && this.plugins.funnelRenderer.highlightCanvas) { + this.plugins.funnelRenderer.highlightCanvas.resetCanvas(); + this.plugins.funnelRenderer.highlightCanvas = null; + } + + this.plugins.funnelRenderer = {}; + this.plugins.funnelRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); + + // do we have any data labels? if so, put highlight canvas before those + var labels = $(this.targetId+' .jqplot-data-label'); + if (labels.length) { + $(labels[0]).before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this)); + } + // else put highlight canvas before event canvas. + else { + this.eventCanvas._elem.before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this)); + } + var hctx = this.plugins.funnelRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); + } + + $.jqplot.preInitHooks.push(preInit); + + $.jqplot.FunnelTickRenderer = function() { + $.jqplot.AxisTickRenderer.call(this); + }; + + $.jqplot.FunnelTickRenderer.prototype = new $.jqplot.AxisTickRenderer(); + $.jqplot.FunnelTickRenderer.prototype.constructor = $.jqplot.FunnelTickRenderer; + +})(jQuery); + + \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.funnelRenderer.min.js b/plugin/jqplot/plugins/jqplot.funnelRenderer.min.js new file mode 100644 index 000000000..af0dabac2 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.funnelRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(e){e.jqplot.FunnelRenderer=function(){e.jqplot.LineRenderer.call(this)};e.jqplot.FunnelRenderer.prototype=new e.jqplot.LineRenderer();e.jqplot.FunnelRenderer.prototype.constructor=e.jqplot.FunnelRenderer;e.jqplot.FunnelRenderer.prototype.init=function(p,t){this.padding={top:20,right:20,bottom:20,left:20};this.sectionMargin=6;this.fill=true;this.shadowOffset=2;this.shadowAlpha=0.07;this.shadowDepth=5;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.widthRatio=0.2;this.lineWidth=2;this.dataLabels="percent";this.showDataLabels=false;this.dataLabelFormatString=null;this.dataLabelThreshold=3;this._type="funnel";this.tickRenderer=e.jqplot.FunnelTickRenderer;if(p.highlightMouseDown&&p.highlightMouseOver==null){p.highlightMouseOver=false}e.extend(true,this,p);this._highlightedPoint=null;this._bases=[];this._atot;this._areas=[];this._lengths=[];this._angle;this._dataIndices=[];this._unorderedData=e.extend(true,[],this.data);var o=e.extend(true,[],this.data);for(var r=0;r<o.length;r++){o[r].push(r)}this.data.sort(function(v,u){return u[1]-v[1]});o.sort(function(v,u){return u[1]-v[1]});for(var r=0;r<o.length;r++){this._dataIndices.push(o[r][2])}if(this.highlightColors.length==0){for(var r=0;r<this.seriesColors.length;r++){var q=e.jqplot.getColorComponents(this.seriesColors[r]);var m=[q[0],q[1],q[2]];var s=m[0]+m[1]+m[2];for(var n=0;n<3;n++){m[n]=(s>570)?m[n]*0.8:m[n]+0.4*(255-m[n]);m[n]=parseInt(m[n],10)}this.highlightColors.push("rgb("+m[0]+","+m[1]+","+m[2]+")")}}t.postParseOptionsHooks.addOnce(k);t.postInitHooks.addOnce(g);t.eventListenerHooks.addOnce("jqplotMouseMove",a);t.eventListenerHooks.addOnce("jqplotMouseDown",b);t.eventListenerHooks.addOnce("jqplotMouseUp",j);t.eventListenerHooks.addOnce("jqplotClick",f);t.eventListenerHooks.addOnce("jqplotRightClick",l);t.postDrawHooks.addOnce(h)};e.jqplot.FunnelRenderer.prototype.setGridData=function(o){var n=0;var p=[];for(var m=0;m<this.data.length;m++){n+=this.data[m][1];p.push([this.data[m][0],this.data[m][1]])}for(var m=0;m<p.length;m++){p[m][1]=p[m][1]/n}this._bases=new Array(p.length+1);this._lengths=new Array(p.length);this.gridData=p};e.jqplot.FunnelRenderer.prototype.makeGridData=function(o,p){var n=0;var q=[];for(var m=0;m<this.data.length;m++){n+=this.data[m][1];q.push([this.data[m][0],this.data[m][1]])}for(var m=0;m<q.length;m++){q[m][1]=q[m][1]/n}this._bases=new Array(q.length+1);this._lengths=new Array(q.length);return q};e.jqplot.FunnelRenderer.prototype.drawSection=function(n,p,o,s){var t=this.fill;var m=this.lineWidth;n.save();if(s){for(var r=0;r<this.shadowDepth;r++){n.save();n.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI),this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));q()}}else{q()}function q(){n.beginPath();n.fillStyle=o;n.strokeStyle=o;n.lineWidth=m;n.moveTo(p[0][0],p[0][1]);for(var u=1;u<4;u++){n.lineTo(p[u][0],p[u][1])}n.closePath();if(t){n.fill()}else{n.stroke()}}if(s){for(var r=0;r<this.shadowDepth;r++){n.restore()}}n.restore()};e.jqplot.FunnelRenderer.prototype.draw=function(G,B,J,p){var Y;var L=(J!=undefined)?J:{};var w=0;var u=0;var R=1;this._areas=[];if(J.legendInfo&&J.legendInfo.placement=="insideGrid"){var O=J.legendInfo;switch(O.location){case"nw":w=O.width+O.xoffset;break;case"w":w=O.width+O.xoffset;break;case"sw":w=O.width+O.xoffset;break;case"ne":w=O.width+O.xoffset;R=-1;break;case"e":w=O.width+O.xoffset;R=-1;break;case"se":w=O.width+O.xoffset;R=-1;break;case"n":u=O.height+O.yoffset;break;case"s":u=O.height+O.yoffset;R=-1;break;default:break}}var t=(R==1)?this.padding.left+w:this.padding.left;var F=(R==1)?this.padding.top+u:this.padding.top;var M=(R==-1)?this.padding.right+w:this.padding.right;var o=(R==-1)?this.padding.bottom+u:this.padding.bottom;var P=(L.shadow!=undefined)?L.shadow:this.shadow;var q=(L.showLine!=undefined)?L.showLine:this.showLine;var C=(L.fill!=undefined)?L.fill:this.fill;var H=G.canvas.width;var N=G.canvas.height;this._bases[0]=H-t-M;var I=this._length=N-F-o;var r=this._bases[0]*this.widthRatio;this._atot=I/2*(this._bases[0]+this._bases[0]*this.widthRatio);this._angle=Math.atan((this._bases[0]-r)/2/I);for(Y=0;Y<B.length;Y++){this._areas.push(B[Y][1]*this._atot)}var E,aa,W,Q=0;var n=0.0001;for(Y=0;Y<this._areas.length;Y++){E=this._areas[Y]/this._bases[Y];aa=999999;this._lengths[Y]=E;W=0;while(aa>this._lengths[Y]*n&&W<100){this._lengths[Y]=this._areas[Y]/(this._bases[Y]-this._lengths[Y]*Math.tan(this._angle));aa=Math.abs(this._lengths[Y]-E);this._bases[Y+1]=this._bases[Y]-(2*this._lengths[Y]*Math.tan(this._angle));E=this._lengths[Y];W++}Q+=this._lengths[Y]}this._vertices=new Array(B.length);var ae=[t,F],ad=[t+this._bases[0],F],ac=[t+(this._bases[0]-this._bases[this._bases.length-1])/2,F+this._length],ab=[ac[0]+this._bases[this._bases.length-1],ac[1]];function V(ag){var x=(ae[1]-ac[1])/(ae[0]-ac[0]);var v=ae[1]-x*ae[0];var ah=ag+ae[1];return[(ah-v)/x,ah]}function D(ag){var x=(ad[1]-ab[1])/(ad[0]-ab[0]);var v=ad[1]-x*ad[0];var ah=ag+ad[1];return[(ah-v)/x,ah]}var T=w,S=u;var Z=0,m=0;for(Y=0;Y<B.length;Y++){this._vertices[Y]=new Array();var U=this._vertices[Y];var A=this.sectionMargin;if(Y==0){m=0}if(Y==1){m=A/3}else{if(Y>0&&Y<B.length-1){m=A/2}else{if(Y==B.length-1){m=2*A/3}}}U.push(V(Z+m));U.push(D(Z+m));Z+=this._lengths[Y];if(Y==0){m=-2*A/3}else{if(Y>0&&Y<B.length-1){m=-A/2}else{if(Y==B.length-1){m=0}}}U.push(D(Z+m));U.push(V(Z+m))}if(this.shadow){var af="rgba(0,0,0,"+this.shadowAlpha+")";for(var Y=0;Y<B.length;Y++){this.renderer.drawSection.call(this,G,this._vertices[Y],af,true)}}for(var Y=0;Y<B.length;Y++){var U=this._vertices[Y];this.renderer.drawSection.call(this,G,U,this.seriesColors[Y]);if(this.showDataLabels&&B[Y][1]*100>=this.dataLabelThreshold){var K,X;if(this.dataLabels=="label"){K=this.dataLabelFormatString||"%s";X=e.jqplot.sprintf(K,B[Y][0])}else{if(this.dataLabels=="value"){K=this.dataLabelFormatString||"%d";X=e.jqplot.sprintf(K,this.data[Y][1])}else{if(this.dataLabels=="percent"){K=this.dataLabelFormatString||"%d%%";X=e.jqplot.sprintf(K,B[Y][1]*100)}else{if(this.dataLabels.constructor==Array){K=this.dataLabelFormatString||"%s";X=e.jqplot.sprintf(K,this.dataLabels[this._dataIndices[Y]])}}}}var s=(this._radius)*this.dataLabelPositionFactor+this.sliceMargin+this.dataLabelNudge;var T=(U[0][0]+U[1][0])/2+this.canvas._offsets.left;var S=(U[1][1]+U[2][1])/2+this.canvas._offsets.top;var z=e('<span class="jqplot-funnel-series jqplot-data-label" style="position:absolute;">'+X+"</span>").insertBefore(p.eventCanvas._elem);T-=z.width()/2;S-=z.height()/2;T=Math.round(T);S=Math.round(S);z.css({left:T,top:S})}}};e.jqplot.FunnelAxisRenderer=function(){e.jqplot.LinearAxisRenderer.call(this)};e.jqplot.FunnelAxisRenderer.prototype=new e.jqplot.LinearAxisRenderer();e.jqplot.FunnelAxisRenderer.prototype.constructor=e.jqplot.FunnelAxisRenderer;e.jqplot.FunnelAxisRenderer.prototype.init=function(m){this.tickRenderer=e.jqplot.FunnelTickRenderer;e.extend(true,this,m);this._dataBounds={min:0,max:100};this.min=0;this.max=100;this.showTicks=false;this.ticks=[];this.showMark=false;this.show=false};e.jqplot.FunnelLegendRenderer=function(){e.jqplot.TableLegendRenderer.call(this)};e.jqplot.FunnelLegendRenderer.prototype=new e.jqplot.TableLegendRenderer();e.jqplot.FunnelLegendRenderer.prototype.constructor=e.jqplot.FunnelLegendRenderer;e.jqplot.FunnelLegendRenderer.prototype.init=function(m){this.numberRows=null;this.numberColumns=null;e.extend(true,this,m)};e.jqplot.FunnelLegendRenderer.prototype.draw=function(){var p=this;if(this.show){var x=this._series;var A="position:absolute;";A+=(this.background)?"background:"+this.background+";":"";A+=(this.border)?"border:"+this.border+";":"";A+=(this.fontSize)?"font-size:"+this.fontSize+";":"";A+=(this.fontFamily)?"font-family:"+this.fontFamily+";":"";A+=(this.textColor)?"color:"+this.textColor+";":"";A+=(this.marginTop!=null)?"margin-top:"+this.marginTop+";":"";A+=(this.marginBottom!=null)?"margin-bottom:"+this.marginBottom+";":"";A+=(this.marginLeft!=null)?"margin-left:"+this.marginLeft+";":"";A+=(this.marginRight!=null)?"margin-right:"+this.marginRight+";":"";this._elem=e('<table class="jqplot-table-legend" style="'+A+'"></table>');var E=false,w=false,m,u;var y=x[0];var n=new e.jqplot.ColorGenerator(y.seriesColors);if(y.show){var F=y.data;if(this.numberRows){m=this.numberRows;if(!this.numberColumns){u=Math.ceil(F.length/m)}else{u=this.numberColumns}}else{if(this.numberColumns){u=this.numberColumns;m=Math.ceil(F.length/this.numberColumns)}else{m=F.length;u=1}}var D,C,o,r,q,t,v,B;var z=0;for(D=0;D<m;D++){if(w){o=e('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem)}else{o=e('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem)}for(C=0;C<u;C++){if(z<F.length){t=this.labels[z]||F[z][0].toString();B=n.next();if(!w){if(D>0){E=true}else{E=false}}else{if(D==m-1){E=false}else{E=true}}v=(E)?this.rowSpacing:"0";r=e('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+v+';"><div><div class="jqplot-table-legend-swatch" style="border-color:'+B+';"></div></div></td>');q=e('<td class="jqplot-table-legend" style="padding-top:'+v+';"></td>');if(this.escapeHtml){q.text(t)}else{q.html(t)}if(w){q.prependTo(o);r.prependTo(o)}else{r.appendTo(o);q.appendTo(o)}E=true}z++}}}}return this._elem};function c(q,p,n){n=n||{};n.axesDefaults=n.axesDefaults||{};n.legend=n.legend||{};n.seriesDefaults=n.seriesDefaults||{};var m=false;if(n.seriesDefaults.renderer==e.jqplot.FunnelRenderer){m=true}else{if(n.series){for(var o=0;o<n.series.length;o++){if(n.series[o].renderer==e.jqplot.FunnelRenderer){m=true}}}}if(m){n.axesDefaults.renderer=e.jqplot.FunnelAxisRenderer;n.legend.renderer=e.jqplot.FunnelLegendRenderer;n.legend.preDraw=true;n.sortData=false;n.seriesDefaults.pointLabels={show:false}}}function g(p,o,m){for(var n=0;n<this.series.length;n++){if(this.series[n].renderer.constructor==e.jqplot.FunnelRenderer){if(this.series[n].highlightMouseOver){this.series[n].highlightMouseDown=false}}}}function k(m){for(var n=0;n<this.series.length;n++){this.series[n].seriesColors=this.seriesColors;this.series[n].colorGenerator=e.jqplot.colorGenerator}}function d(q,p,o){var n=q.series[p];var m=q.plugins.funnelRenderer.highlightCanvas;m._ctx.clearRect(0,0,m._ctx.canvas.width,m._ctx.canvas.height);n._highlightedPoint=o;q.plugins.funnelRenderer.highlightedSeriesIndex=p;n.renderer.drawSection.call(n,m._ctx,n._vertices[o],n.highlightColors[o],false)}function i(o){var m=o.plugins.funnelRenderer.highlightCanvas;m._ctx.clearRect(0,0,m._ctx.canvas.width,m._ctx.canvas.height);for(var n=0;n<o.series.length;n++){o.series[n]._highlightedPoint=null}o.plugins.funnelRenderer.highlightedSeriesIndex=null;o.target.trigger("jqplotDataUnhighlight")}function a(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];var n=jQuery.Event("jqplotDataMouseOver");n.pageX=q.pageX;n.pageY=q.pageY;r.target.trigger(n,o);if(r.series[o[0]].highlightMouseOver&&!(o[0]==r.plugins.funnelRenderer.highlightedSeriesIndex&&o[1]==r.series[o[0]]._highlightedPoint)){var m=jQuery.Event("jqplotDataHighlight");m.which=q.which;m.pageX=q.pageX;m.pageY=q.pageY;r.target.trigger(m,o);d(r,o[0],o[1])}}else{if(s==null){i(r)}}}function b(p,o,s,r,q){if(r){var n=[r.seriesIndex,r.pointIndex,r.data];if(q.series[n[0]].highlightMouseDown&&!(n[0]==q.plugins.funnelRenderer.highlightedSeriesIndex&&n[1]==q.series[n[0]]._highlightedPoint)){var m=jQuery.Event("jqplotDataHighlight");m.which=p.which;m.pageX=p.pageX;m.pageY=p.pageY;q.target.trigger(m,n);d(q,n[0],n[1])}}else{if(r==null){i(q)}}}function j(o,n,r,q,p){var m=p.plugins.funnelRenderer.highlightedSeriesIndex;if(m!=null&&p.series[m].highlightMouseDown){i(p)}}function f(p,o,s,r,q){if(r){var n=[r.seriesIndex,r.pointIndex,r.data];var m=jQuery.Event("jqplotDataClick");m.which=p.which;m.pageX=p.pageX;m.pageY=p.pageY;q.target.trigger(m,n)}}function l(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];var m=r.plugins.funnelRenderer.highlightedSeriesIndex;if(m!=null&&r.series[m].highlightMouseDown){i(r)}var n=jQuery.Event("jqplotDataRightClick");n.which=q.which;n.pageX=q.pageX;n.pageY=q.pageY;r.target.trigger(n,o)}}function h(){if(this.plugins.funnelRenderer&&this.plugins.funnelRenderer.highlightCanvas){this.plugins.funnelRenderer.highlightCanvas.resetCanvas();this.plugins.funnelRenderer.highlightCanvas=null}this.plugins.funnelRenderer={};this.plugins.funnelRenderer.highlightCanvas=new e.jqplot.GenericCanvas();var n=e(this.targetId+" .jqplot-data-label");if(n.length){e(n[0]).before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-funnelRenderer-highlight-canvas",this._plotDimensions,this))}else{this.eventCanvas._elem.before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-funnelRenderer-highlight-canvas",this._plotDimensions,this))}var m=this.plugins.funnelRenderer.highlightCanvas.setContext();this.eventCanvas._elem.bind("mouseleave",{plot:this},function(o){i(o.data.plot)})}e.jqplot.preInitHooks.push(c);e.jqplot.FunnelTickRenderer=function(){e.jqplot.AxisTickRenderer.call(this)};e.jqplot.FunnelTickRenderer.prototype=new e.jqplot.AxisTickRenderer();e.jqplot.FunnelTickRenderer.prototype.constructor=e.jqplot.FunnelTickRenderer})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.highlighter.js b/plugin/jqplot/plugins/jqplot.highlighter.js new file mode 100644 index 000000000..3105c8595 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.highlighter.js @@ -0,0 +1,465 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]); + + /** + * Class: $.jqplot.Highlighter + * Plugin which will highlight data points when they are moused over. + * + * To use this plugin, include the js + * file in your source: + * + * > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script> + * + * A tooltip providing information about the data point is enabled by default. + * To disable the tooltip, set "showTooltip" to false. + * + * You can control what data is displayed in the tooltip with various + * options. The "tooltipAxes" option controls whether the x, y or both + * data values are displayed. + * + * Some chart types (e.g. hi-low-close) have more than one y value per + * data point. To display the additional values in the tooltip, set the + * "yvalues" option to the desired number of y values present (3 for a hlc chart). + * + * By default, data values will be formatted with the same formatting + * specifiers as used to format the axis ticks. A custom format code + * can be supplied with the tooltipFormatString option. This will apply + * to all values in the tooltip. + * + * For more complete control, the "formatString" option can be set. This + * Allows conplete control over tooltip formatting. Values are passed to + * the format string in an order determined by the "tooltipAxes" and "yvalues" + * options. So, if you have a hi-low-close chart and you just want to display + * the hi-low-close values in the tooltip, you could set a formatString like: + * + * > highlighter: { + * > tooltipAxes: 'y', + * > yvalues: 3, + * > formatString:'<table class="jqplot-highlighter"> + * > <tr><td>hi:</td><td>%s</td></tr> + * > <tr><td>low:</td><td>%s</td></tr> + * > <tr><td>close:</td><td>%s</td></tr></table>' + * > } + * + */ + $.jqplot.Highlighter = function(options) { + // Group: Properties + // + //prop: show + // true to show the highlight. + this.show = $.jqplot.config.enablePlugins; + // prop: markerRenderer + // Renderer used to draw the marker of the highlighted point. + // Renderer will assimilate attributes from the data point being highlighted, + // so no attributes need set on the renderer directly. + // Default is to turn off shadow drawing on the highlighted point. + this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false}); + // prop: showMarker + // true to show the marker + this.showMarker = true; + // prop: lineWidthAdjust + // Pixels to add to the lineWidth of the highlight. + this.lineWidthAdjust = 2.5; + // prop: sizeAdjust + // Pixels to add to the overall size of the highlight. + this.sizeAdjust = 5; + // prop: showTooltip + // Show a tooltip with data point values. + this.showTooltip = true; + // prop: tooltipLocation + // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' + this.tooltipLocation = 'nw'; + // prop: fadeTooltip + // true = fade in/out tooltip, flase = show/hide tooltip + this.fadeTooltip = true; + // prop: tooltipFadeSpeed + // 'slow', 'def', 'fast', or number of milliseconds. + this.tooltipFadeSpeed = "fast"; + // prop: tooltipOffset + // Pixel offset of tooltip from the highlight. + this.tooltipOffset = 2; + // prop: tooltipAxes + // Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx' + // 'both' and 'xy' are equivalent, 'yx' reverses order of labels. + this.tooltipAxes = 'both'; + // prop; tooltipSeparator + // String to use to separate x and y axes in tooltip. + this.tooltipSeparator = ', '; + // prop; tooltipContentEditor + // Function used to edit/augment/replace the formatted tooltip contents. + // Called as str = tooltipContentEditor(str, seriesIndex, pointIndex) + // where str is the generated tooltip html and seriesIndex and pointIndex identify + // the data point being highlighted. Should return the html for the tooltip contents. + this.tooltipContentEditor = null; + // prop: useAxesFormatters + // Use the x and y axes formatters to format the text in the tooltip. + this.useAxesFormatters = true; + // prop: tooltipFormatString + // sprintf format string for the tooltip. + // Uses Ash Searle's javascript sprintf implementation + // found here: http://hexmen.com/blog/2007/03/printf-sprintf/ + // See http://perldoc.perl.org/functions/sprintf.html for reference. + // Additional "p" and "P" format specifiers added by Chris Leonello. + this.tooltipFormatString = '%.5P'; + // prop: formatString + // alternative to tooltipFormatString + // will format the whole tooltip text, populating with x, y values as + // indicated by tooltipAxes option. So, you could have a tooltip like: + // 'Date: %s, number of cats: %d' to format the whole tooltip at one go. + // If useAxesFormatters is true, values will be formatted according to + // Axes formatters and you can populate your tooltip string with + // %s placeholders. + this.formatString = null; + // prop: yvalues + // Number of y values to expect in the data point array. + // Typically this is 1. Certain plots, like OHLC, will + // have more y values in each data point array. + this.yvalues = 1; + // prop: bringSeriesToFront + // This option requires jQuery 1.4+ + // True to bring the series of the highlighted point to the front + // of other series. + this.bringSeriesToFront = false; + this._tooltipElem; + this.isHighlighting = false; + this.currentNeighbor = null; + + $.extend(true, this, options); + }; + + var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w']; + var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7}; + var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e']; + + // axis.renderer.tickrenderer.formatter + + // called with scope of plot + $.jqplot.Highlighter.init = function (target, data, opts){ + var options = opts || {}; + // add a highlighter attribute to the plot + this.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter); + }; + + // called within scope of series + $.jqplot.Highlighter.parseOptions = function (defaults, options) { + // Add a showHighlight option to the series + // and set it to true by default. + this.showHighlight = true; + }; + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + $.jqplot.Highlighter.postPlotDraw = function() { + // Memory Leaks patch + if (this.plugins.highlighter && this.plugins.highlighter.highlightCanvas) { + this.plugins.highlighter.highlightCanvas.resetCanvas(); + this.plugins.highlighter.highlightCanvas = null; + } + + if (this.plugins.highlighter && this.plugins.highlighter._tooltipElem) { + this.plugins.highlighter._tooltipElem.emptyForce(); + this.plugins.highlighter._tooltipElem = null; + } + + this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas(); + + this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions, this)); + this.plugins.highlighter.highlightCanvas.setContext(); + + var elem = document.createElement('div'); + this.plugins.highlighter._tooltipElem = $(elem); + elem = null; + this.plugins.highlighter._tooltipElem.addClass('jqplot-highlighter-tooltip'); + this.plugins.highlighter._tooltipElem.css({position:'absolute', display:'none'}); + + this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem); + }; + + $.jqplot.preInitHooks.push($.jqplot.Highlighter.init); + $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions); + $.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw); + + function draw(plot, neighbor) { + var hl = plot.plugins.highlighter; + var s = plot.series[neighbor.seriesIndex]; + var smr = s.markerRenderer; + var mr = hl.markerRenderer; + mr.style = smr.style; + mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust; + mr.size = smr.size + hl.sizeAdjust; + var rgba = $.jqplot.getColorComponents(smr.color); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]); + mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')'; + mr.init(); + mr.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], hl.highlightCanvas._ctx); + } + + function showTooltip(plot, series, neighbor) { + // neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]} + // gridData should be x,y pixel coords on the grid. + // add the plot._gridPadding to that to get x,y in the target. + var hl = plot.plugins.highlighter; + var elem = hl._tooltipElem; + var serieshl = series.highlighter || {}; + + var opts = $.extend(true, {}, hl, serieshl); + + if (opts.useAxesFormatters) { + var xf = series._xaxis._ticks[0].formatter; + var yf = series._yaxis._ticks[0].formatter; + var xfstr = series._xaxis._ticks[0].formatString; + var yfstr = series._yaxis._ticks[0].formatString; + var str; + var xstr = xf(xfstr, neighbor.data[0]); + var ystrs = []; + for (var i=1; i<opts.yvalues+1; i++) { + ystrs.push(yf(yfstr, neighbor.data[i])); + } + if (typeof opts.formatString === 'string') { + switch (opts.tooltipAxes) { + case 'both': + case 'xy': + ystrs.unshift(xstr); + ystrs.unshift(opts.formatString); + str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs); + break; + case 'yx': + ystrs.push(xstr); + ystrs.unshift(opts.formatString); + str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs); + break; + case 'x': + str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString, xstr]); + break; + case 'y': + ystrs.unshift(opts.formatString); + str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs); + break; + default: // same as xy + ystrs.unshift(xstr); + ystrs.unshift(opts.formatString); + str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs); + break; + } + } + else { + switch (opts.tooltipAxes) { + case 'both': + case 'xy': + str = xstr; + for (var i=0; i<ystrs.length; i++) { + str += opts.tooltipSeparator + ystrs[i]; + } + break; + case 'yx': + str = ''; + for (var i=0; i<ystrs.length; i++) { + str += ystrs[i] + opts.tooltipSeparator; + } + str += xstr; + break; + case 'x': + str = xstr; + break; + case 'y': + str = ystrs.join(opts.tooltipSeparator); + break; + default: // same as 'xy' + str = xstr; + for (var i=0; i<ystrs.length; i++) { + str += opts.tooltipSeparator + ystrs[i]; + } + break; + + } + } + } + else { + var str; + if (typeof opts.formatString === 'string') { + str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString].concat(neighbor.data)); + } + + else { + if (opts.tooltipAxes == 'both' || opts.tooltipAxes == 'xy') { + str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]); + } + else if (opts.tooltipAxes == 'yx') { + str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]); + } + else if (opts.tooltipAxes == 'x') { + str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]); + } + else if (opts.tooltipAxes == 'y') { + str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]); + } + } + } + if ($.isFunction(opts.tooltipContentEditor)) { + // args str, seriesIndex, pointIndex are essential so the hook can look up + // extra data for the point. + str = opts.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot); + } + elem.html(str); + var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]}; + var ms = 0; + var fact = 0.707; + if (series.markerRenderer.show == true) { + ms = (series.markerRenderer.size + opts.sizeAdjust)/2; + } + + var loc = locations; + if (series.fillToZero && series.fill && neighbor.data[1] < 0) { + loc = oppositeLocations; + } + + switch (loc[locationIndicies[opts.tooltipLocation]]) { + case 'nw': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms; + var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms; + break; + case 'n': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; + var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - ms; + break; + case 'ne': + var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms; + var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms; + break; + case 'e': + var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + ms; + var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; + break; + case 'se': + var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms; + var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms; + break; + case 's': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; + var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + ms; + break; + case 'sw': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms; + var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms; + break; + case 'w': + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - ms; + var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; + break; + default: // same as 'nw' + var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms; + var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms; + break; + } + elem.css('left', x); + elem.css('top', y); + if (opts.fadeTooltip) { + // Fix for stacked up animations. Thnanks Trevor! + elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed); + } + else { + elem.show(); + } + elem = null; + + } + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + var hl = plot.plugins.highlighter; + var c = plot.plugins.cursor; + if (hl.show) { + if (neighbor == null && hl.isHighlighting) { + var evt = jQuery.Event('jqplotHighlighterUnhighlight'); + plot.target.trigger(evt); + + var ctx = hl.highlightCanvas._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + if (hl.fadeTooltip) { + hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed); + } + else { + hl._tooltipElem.hide(); + } + if (hl.bringSeriesToFront) { + plot.restorePreviousSeriesOrder(); + } + hl.isHighlighting = false; + hl.currentNeighbor = null; + ctx = null; + } + else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) { + var evt = jQuery.Event('jqplotHighlighterHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data, plot]; + plot.target.trigger(evt, ins); + + hl.isHighlighting = true; + hl.currentNeighbor = neighbor; + if (hl.showMarker) { + draw(plot, neighbor); + } + if (plot.series[neighbor.seriesIndex].show && hl.showTooltip && (!c || !c._zoom.started)) { + showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor); + } + if (hl.bringSeriesToFront) { + plot.moveSeriesToFront(neighbor.seriesIndex); + } + } + // check to see if we're highlighting the wrong point. + else if (neighbor != null && hl.isHighlighting && hl.currentNeighbor != neighbor) { + // highlighting the wrong point. + + // if new series allows highlighting, highlight new point. + if (plot.series[neighbor.seriesIndex].showHighlight) { + var ctx = hl.highlightCanvas._ctx; + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + hl.isHighlighting = true; + hl.currentNeighbor = neighbor; + if (hl.showMarker) { + draw(plot, neighbor); + } + if (plot.series[neighbor.seriesIndex].show && hl.showTooltip && (!c || !c._zoom.started)) { + showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor); + } + if (hl.bringSeriesToFront) { + plot.moveSeriesToFront(neighbor.seriesIndex); + } + } + } + } + } +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.highlighter.min.js b/plugin/jqplot/plugins/jqplot.highlighter.min.js new file mode 100644 index 000000000..1e0f6e55a --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.highlighter.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(d){d.jqplot.eventListenerHooks.push(["jqplotMouseMove",f]);d.jqplot.Highlighter=function(h){this.show=d.jqplot.config.enablePlugins;this.markerRenderer=new d.jqplot.MarkerRenderer({shadow:false});this.showMarker=true;this.lineWidthAdjust=2.5;this.sizeAdjust=5;this.showTooltip=true;this.tooltipLocation="nw";this.fadeTooltip=true;this.tooltipFadeSpeed="fast";this.tooltipOffset=2;this.tooltipAxes="both";this.tooltipSeparator=", ";this.tooltipContentEditor=null;this.useAxesFormatters=true;this.tooltipFormatString="%.5P";this.formatString=null;this.yvalues=1;this.bringSeriesToFront=false;this._tooltipElem;this.isHighlighting=false;this.currentNeighbor=null;d.extend(true,this,h)};var b=["nw","n","ne","e","se","s","sw","w"];var e={nw:0,n:1,ne:2,e:3,se:4,s:5,sw:6,w:7};var c=["se","s","sw","w","nw","n","ne","e"];d.jqplot.Highlighter.init=function(k,j,i){var h=i||{};this.plugins.highlighter=new d.jqplot.Highlighter(h.highlighter)};d.jqplot.Highlighter.parseOptions=function(i,h){this.showHighlight=true};d.jqplot.Highlighter.postPlotDraw=function(){if(this.plugins.highlighter&&this.plugins.highlighter.highlightCanvas){this.plugins.highlighter.highlightCanvas.resetCanvas();this.plugins.highlighter.highlightCanvas=null}if(this.plugins.highlighter&&this.plugins.highlighter._tooltipElem){this.plugins.highlighter._tooltipElem.emptyForce();this.plugins.highlighter._tooltipElem=null}this.plugins.highlighter.highlightCanvas=new d.jqplot.GenericCanvas();this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding,"jqplot-highlight-canvas",this._plotDimensions,this));this.plugins.highlighter.highlightCanvas.setContext();var h=document.createElement("div");this.plugins.highlighter._tooltipElem=d(h);h=null;this.plugins.highlighter._tooltipElem.addClass("jqplot-highlighter-tooltip");this.plugins.highlighter._tooltipElem.css({position:"absolute",display:"none"});this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem)};d.jqplot.preInitHooks.push(d.jqplot.Highlighter.init);d.jqplot.preParseSeriesOptionsHooks.push(d.jqplot.Highlighter.parseOptions);d.jqplot.postDrawHooks.push(d.jqplot.Highlighter.postPlotDraw);function a(m,o){var j=m.plugins.highlighter;var p=m.series[o.seriesIndex];var h=p.markerRenderer;var i=j.markerRenderer;i.style=h.style;i.lineWidth=h.lineWidth+j.lineWidthAdjust;i.size=h.size+j.sizeAdjust;var l=d.jqplot.getColorComponents(h.color);var n=[l[0],l[1],l[2]];var k=(l[3]>=0.6)?l[3]*0.6:l[3]*(2-l[3]);i.color="rgba("+n[0]+","+n[1]+","+n[2]+","+k+")";i.init();i.draw(p.gridData[o.pointIndex][0],p.gridData[o.pointIndex][1],j.highlightCanvas._ctx)}function g(A,q,m){var k=A.plugins.highlighter;var D=k._tooltipElem;var r=q.highlighter||{};var t=d.extend(true,{},k,r);if(t.useAxesFormatters){var w=q._xaxis._ticks[0].formatter;var h=q._yaxis._ticks[0].formatter;var E=q._xaxis._ticks[0].formatString;var s=q._yaxis._ticks[0].formatString;var z;var u=w(E,m.data[0]);var l=[];for(var B=1;B<t.yvalues+1;B++){l.push(h(s,m.data[B]))}if(typeof t.formatString==="string"){switch(t.tooltipAxes){case"both":case"xy":l.unshift(u);l.unshift(t.formatString);z=d.jqplot.sprintf.apply(d.jqplot.sprintf,l);break;case"yx":l.push(u);l.unshift(t.formatString);z=d.jqplot.sprintf.apply(d.jqplot.sprintf,l);break;case"x":z=d.jqplot.sprintf.apply(d.jqplot.sprintf,[t.formatString,u]);break;case"y":l.unshift(t.formatString);z=d.jqplot.sprintf.apply(d.jqplot.sprintf,l);break;default:l.unshift(u);l.unshift(t.formatString);z=d.jqplot.sprintf.apply(d.jqplot.sprintf,l);break}}else{switch(t.tooltipAxes){case"both":case"xy":z=u;for(var B=0;B<l.length;B++){z+=t.tooltipSeparator+l[B]}break;case"yx":z="";for(var B=0;B<l.length;B++){z+=l[B]+t.tooltipSeparator}z+=u;break;case"x":z=u;break;case"y":z=l.join(t.tooltipSeparator);break;default:z=u;for(var B=0;B<l.length;B++){z+=t.tooltipSeparator+l[B]}break}}}else{var z;if(typeof t.formatString==="string"){z=d.jqplot.sprintf.apply(d.jqplot.sprintf,[t.formatString].concat(m.data))}else{if(t.tooltipAxes=="both"||t.tooltipAxes=="xy"){z=d.jqplot.sprintf(t.tooltipFormatString,m.data[0])+t.tooltipSeparator+d.jqplot.sprintf(t.tooltipFormatString,m.data[1])}else{if(t.tooltipAxes=="yx"){z=d.jqplot.sprintf(t.tooltipFormatString,m.data[1])+t.tooltipSeparator+d.jqplot.sprintf(t.tooltipFormatString,m.data[0])}else{if(t.tooltipAxes=="x"){z=d.jqplot.sprintf(t.tooltipFormatString,m.data[0])}else{if(t.tooltipAxes=="y"){z=d.jqplot.sprintf(t.tooltipFormatString,m.data[1])}}}}}}if(d.isFunction(t.tooltipContentEditor)){z=t.tooltipContentEditor(z,m.seriesIndex,m.pointIndex,A)}D.html(z);var C={x:m.gridData[0],y:m.gridData[1]};var v=0;var j=0.707;if(q.markerRenderer.show==true){v=(q.markerRenderer.size+t.sizeAdjust)/2}var o=b;if(q.fillToZero&&q.fill&&m.data[1]<0){o=c}switch(o[e[t.tooltipLocation]]){case"nw":var p=C.x+A._gridPadding.left-D.outerWidth(true)-t.tooltipOffset-j*v;var n=C.y+A._gridPadding.top-t.tooltipOffset-D.outerHeight(true)-j*v;break;case"n":var p=C.x+A._gridPadding.left-D.outerWidth(true)/2;var n=C.y+A._gridPadding.top-t.tooltipOffset-D.outerHeight(true)-v;break;case"ne":var p=C.x+A._gridPadding.left+t.tooltipOffset+j*v;var n=C.y+A._gridPadding.top-t.tooltipOffset-D.outerHeight(true)-j*v;break;case"e":var p=C.x+A._gridPadding.left+t.tooltipOffset+v;var n=C.y+A._gridPadding.top-D.outerHeight(true)/2;break;case"se":var p=C.x+A._gridPadding.left+t.tooltipOffset+j*v;var n=C.y+A._gridPadding.top+t.tooltipOffset+j*v;break;case"s":var p=C.x+A._gridPadding.left-D.outerWidth(true)/2;var n=C.y+A._gridPadding.top+t.tooltipOffset+v;break;case"sw":var p=C.x+A._gridPadding.left-D.outerWidth(true)-t.tooltipOffset-j*v;var n=C.y+A._gridPadding.top+t.tooltipOffset+j*v;break;case"w":var p=C.x+A._gridPadding.left-D.outerWidth(true)-t.tooltipOffset-v;var n=C.y+A._gridPadding.top-D.outerHeight(true)/2;break;default:var p=C.x+A._gridPadding.left-D.outerWidth(true)-t.tooltipOffset-j*v;var n=C.y+A._gridPadding.top-t.tooltipOffset-D.outerHeight(true)-j*v;break}D.css("left",p);D.css("top",n);if(t.fadeTooltip){D.stop(true,true).fadeIn(t.tooltipFadeSpeed)}else{D.show()}D=null}function f(n,j,i,p,l){var h=l.plugins.highlighter;var m=l.plugins.cursor;if(h.show){if(p==null&&h.isHighlighting){var o=jQuery.Event("jqplotHighlighterUnhighlight");l.target.trigger(o);var q=h.highlightCanvas._ctx;q.clearRect(0,0,q.canvas.width,q.canvas.height);if(h.fadeTooltip){h._tooltipElem.fadeOut(h.tooltipFadeSpeed)}else{h._tooltipElem.hide()}if(h.bringSeriesToFront){l.restorePreviousSeriesOrder()}h.isHighlighting=false;h.currentNeighbor=null;q=null}else{if(p!=null&&l.series[p.seriesIndex].showHighlight&&!h.isHighlighting){var o=jQuery.Event("jqplotHighlighterHighlight");o.which=n.which;o.pageX=n.pageX;o.pageY=n.pageY;var k=[p.seriesIndex,p.pointIndex,p.data,l];l.target.trigger(o,k);h.isHighlighting=true;h.currentNeighbor=p;if(h.showMarker){a(l,p)}if(l.series[p.seriesIndex].show&&h.showTooltip&&(!m||!m._zoom.started)){g(l,l.series[p.seriesIndex],p)}if(h.bringSeriesToFront){l.moveSeriesToFront(p.seriesIndex)}}else{if(p!=null&&h.isHighlighting&&h.currentNeighbor!=p){if(l.series[p.seriesIndex].showHighlight){var q=h.highlightCanvas._ctx;q.clearRect(0,0,q.canvas.width,q.canvas.height);h.isHighlighting=true;h.currentNeighbor=p;if(h.showMarker){a(l,p)}if(l.series[p.seriesIndex].show&&h.showTooltip&&(!m||!m._zoom.started)){g(l,l.series[p.seriesIndex],p)}if(h.bringSeriesToFront){l.moveSeriesToFront(p.seriesIndex)}}}}}}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.json2.js b/plugin/jqplot/plugins/jqplot.json2.js new file mode 100644 index 000000000..46fb942ba --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.json2.js @@ -0,0 +1,475 @@ +/* + 2010-11-01 Chris Leonello + + Slightly modified version of the original json2.js to put JSON + functions under the $.jqplot namespace. + + licensing and orignal comments follow: + + http://www.JSON.org/json2.js + 2010-08-25 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + $.jqplot.JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + $.jqplot.JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = $.jqplot.JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = $.jqplot.JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = $.jqplot.JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + $.jqplot.JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = $.jqplot.JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = $.jqplot.JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +(function($) { + + $.jqplot.JSON = window.JSON; + + if (!window.JSON) { + $.jqplot.JSON = {}; + } + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof $.jqplot.JSON.stringify !== 'function') { + $.jqplot.JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('$.jqplot.JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof $.jqplot.JSON.parse !== 'function') { + $.jqplot.JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('$.jqplot.JSON.parse'); + }; + } +})(jQuery); diff --git a/plugin/jqplot/plugins/jqplot.json2.min.js b/plugin/jqplot/plugins/jqplot.json2.min.js new file mode 100644 index 000000000..3d8c626fd --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.json2.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function($){$.jqplot.JSON=window.JSON;if(!window.JSON){$.jqplot.JSON={}}function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof $.jqplot.JSON.stringify!=="function"){$.jqplot.JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("$.jqplot.JSON.stringify")}return str("",{"":value})}}if(typeof $.jqplot.JSON.parse!=="function"){$.jqplot.JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("$.jqplot.JSON.parse")}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.logAxisRenderer.js b/plugin/jqplot/plugins/jqplot.logAxisRenderer.js new file mode 100644 index 000000000..3bd3e2a51 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.logAxisRenderer.js @@ -0,0 +1,534 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * class: $.jqplot.LogAxisRenderer + * A plugin for a jqPlot to render a logarithmic axis. + * + * To use this renderer, include the plugin in your source + * > <script type="text/javascript" language="javascript" src="plugins/jqplot.logAxisRenderer.js"></script> + * + * and supply the appropriate options to your plot + * + * > {axes:{xaxis:{renderer:$.jqplot.LogAxisRenderer}}} + **/ + $.jqplot.LogAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + // prop: axisDefaults + // Default properties which will be applied directly to the series. + // + // Group: Properties + // + // Properties + // + // base - the logarithmic base, commonly 2, 10 or Math.E + // tickDistribution - Deprecated. "power" distribution of ticks + // always used. Option has no effect. + this.axisDefaults = { + base : 10, + tickDistribution :'power' + }; + }; + + $.jqplot.LogAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.LogAxisRenderer.prototype.constructor = $.jqplot.LogAxisRenderer; + + $.jqplot.LogAxisRenderer.prototype.init = function(options) { + // prop: drawBaseline + // True to draw the axis baseline. + this.drawBaseline = true; + // prop: minorTicks + // Number of ticks to add between "major" ticks. + // Major ticks are ticks supplied by user or auto computed. + // Minor ticks cannot be created by user. + this.minorTicks = 'auto'; + this._scalefact = 1.0; + + $.extend(true, this, options); + + this._autoFormatString = '%d'; + this._overrideFormatString = false; + + for (var d in this.renderer.axisDefaults) { + if (this[d] == null) { + this[d] = this.renderer.axisDefaults[d]; + } + } + + this.resetDataBounds(); + }; + + $.jqplot.LogAxisRenderer.prototype.createTicks = function(plot) { + // we're are operating on an axis here + var ticks = this._ticks; + var userTicks = this.ticks; + var name = this.name; + var db = this._dataBounds; + var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height; + var interval; + var min, max; + var pos1, pos2; + var tt, i; + + var threshold = 30; + // For some reason scalefactor is screwing up ticks. + this._scalefact = (Math.max(dim, threshold+1) - threshold)/300; + + // if we already have ticks, use them. + // ticks must be in order of increasing value. + if (userTicks.length) { + // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed + for (i=0; i<userTicks.length; i++){ + var ut = userTicks[i]; + var t = new this.tickRenderer(this.tickOptions); + if (ut.constructor == Array) { + t.value = ut[0]; + t.label = ut[1]; + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(ut[0], this.name); + this._ticks.push(t); + } + + else if ($.isPlainObject(ut)) { + $.extend(true, t, ut); + t.axis = this.name; + this._ticks.push(t); + } + + else { + t.value = ut; + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(ut, this.name); + this._ticks.push(t); + } + } + this.numberTicks = userTicks.length; + this.min = this._ticks[0].value; + this.max = this._ticks[this.numberTicks-1].value; + } + + // we don't have any ticks yet, let's make some! + else if (this.min == null && this.max == null) { + min = db.min * (2 - this.padMin); + max = db.max * this.padMax; + + // if min and max are same, space them out a bit + if (min == max) { + var adj = 0.05; + min = min*(1-adj); + max = max*(1+adj); + } + + // perform some checks + if (this.min != null && this.min <= 0) { + throw new Error("Log axis minimum must be greater than 0"); + } + if (this.max != null && this.max <= 0) { + throw new Error("Log axis maximum must be greater than 0"); + } + + function findCeil (val) { + var order = Math.pow(10, Math.floor(Math.log(val)/Math.LN10)); + return Math.ceil(val/order) * order; + } + + function findFloor(val) { + var order = Math.pow(10, Math.floor(Math.log(val)/Math.LN10)); + return Math.floor(val/order) * order; + } + + // var range = max - min; + var rmin, rmax; + + // for power distribution, open up range to get a nice power of axis.renderer.base. + // power distribution won't respect the user's min/max settings. + rmin = Math.pow(this.base, Math.floor(Math.log(min)/Math.log(this.base))); + rmax = Math.pow(this.base, Math.ceil(Math.log(max)/Math.log(this.base))); + + // // if min and max are same, space them out a bit + // if (rmin === rmax) { + // var adj = 0.05; + // rmin = rmin*(1-adj); + // rmax = rmax*(1+adj); + // } + + // Handle case where a data value was zero + if (rmin === 0) { + rmin = 1; + } + + var order = Math.round(Math.log(rmin)/Math.LN10); + + if (this.tickOptions == null || !this.tickOptions.formatString) { + this._overrideFormatString = true; + } + + this.min = rmin; + this.max = rmax; + var range = this.max - this.min; + + var minorTicks = (this.minorTicks === 'auto') ? 0 : this.minorTicks; + var numberTicks; + if (this.numberTicks == null){ + if (dim > 140) { + numberTicks = Math.round(Math.log(this.max/this.min)/Math.log(this.base) + 1); + if (numberTicks < 2) { + numberTicks = 2; + } + if (minorTicks === 0) { + var temp = dim/(numberTicks - 1); + if (temp < 100) { + minorTicks = 0; + } + else if (temp < 190) { + minorTicks = 1; + } + else if (temp < 250) { + minorTicks = 3; + } + else if (temp < 600) { + minorTicks = 4; + } + else { + minorTicks = 9; + } + } + } + else { + numberTicks = 2; + if (minorTicks === 0) { + minorTicks = 1; + } + minorTicks = 0; + } + } + else { + numberTicks = this.numberTicks; + } + + if (order >= 0 && minorTicks !== 3) { + this._autoFormatString = '%d'; + } + // Adjust format string for case with 3 ticks where we'll have like 1, 2.5, 5, 7.5, 10 + else if (order <= 0 && minorTicks === 3) { + var temp = -(order - 1); + this._autoFormatString = '%.'+ Math.abs(order-1) + 'f'; + } + + // Adjust format string for values less than 1. + else if (order < 0) { + var temp = -order; + this._autoFormatString = '%.'+ Math.abs(order) + 'f'; + } + + else { + this._autoFormatString = '%d'; + } + + var to, t, val, tt1, spread, interval; + for (var i=0; i<numberTicks; i++){ + tt = Math.pow(this.base, i - numberTicks + 1) * this.max; + + t = new this.tickRenderer(this.tickOptions); + + if (this._overrideFormatString) { + t.formatString = this._autoFormatString; + } + + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(tt, this.name); + this._ticks.push(t); + + if (minorTicks && i<numberTicks-1) { + tt1 = Math.pow(this.base, i - numberTicks + 2) * this.max; + spread = tt1 - tt; + interval = tt1 / (minorTicks+1); + for (var j=minorTicks-1; j>=0; j--) { + val = tt1-interval*(j+1); + t = new this.tickRenderer(this.tickOptions); + + if (this._overrideFormatString && this._autoFormatString != '') { + t.formatString = this._autoFormatString; + } + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(val, this.name); + this._ticks.push(t); + } + } + } + } + + // min and max are set as would be the case with zooming + else if (this.min != null && this.max != null) { + var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null}); + var nt, ti; + // don't have an interval yet, pick one that gives the most + // "round" ticks we can get. + if (this.numberTicks == null && this.tickInterval == null) { + // var threshold = 30; + var tdim = Math.max(dim, threshold+1); + var nttarget = Math.ceil((tdim-threshold)/35 + 1); + + var ret = $.jqplot.LinearTickGenerator.bestConstrainedInterval(this.min, this.max, nttarget); + + this._autoFormatString = ret[3]; + nt = ret[2]; + ti = ret[4]; + + for (var i=0; i<nt; i++) { + opts.value = this.min + i * ti; + t = new this.tickRenderer(opts); + + if (this._overrideFormatString && this._autoFormatString != '') { + t.formatString = this._autoFormatString; + } + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + this._ticks.push(t); + } + } + + // for loose zoom, number ticks and interval are also set. + else if (this.numberTicks != null && this.tickInterval != null) { + nt = this.numberTicks; + for (var i=0; i<nt; i++) { + opts.value = this.min + i * this.tickInterval; + t = new this.tickRenderer(opts); + + if (this._overrideFormatString && this._autoFormatString != '') { + t.formatString = this._autoFormatString; + } + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + this._ticks.push(t); + } + } + } + }; + + $.jqplot.LogAxisRenderer.prototype.pack = function(pos, offsets) { + var lb = parseInt(this.base, 10); + var ticks = this._ticks; + var trans = function (v) { return Math.log(v)/Math.log(lb); }; + var invtrans = function (v) { return Math.pow(Math.E, (Math.log(lb)*v)); }; + var max = trans(this.max); + var min = trans(this.min); + var offmax = offsets.max; + var offmin = offsets.min; + var lshow = (this._label == null) ? false : this._label.show; + + for (var p in pos) { + this._elem.css(p, pos[p]); + } + + this._offsets = offsets; + // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. + var pixellength = offmax - offmin; + var unitlength = max - min; + + // point to unit and unit to point conversions references to Plot DOM element top left corner. + this.p2u = function(p){ + return invtrans((p - offmin) * unitlength / pixellength + min); + }; + + this.u2p = function(u){ + return (trans(u) - min) * pixellength / unitlength + offmin; + }; + + if (this.name == 'xaxis' || this.name == 'x2axis'){ + this.series_u2p = function(u){ + return (trans(u) - min) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return invtrans(p * unitlength / pixellength + min); + }; + } + // yaxis is max at top of canvas. + else { + this.series_u2p = function(u){ + return (trans(u) - max) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return invtrans(p * unitlength / pixellength + max); + }; + } + + if (this.show) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + for (var i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + switch (t.labelPosition) { + case 'auto': + // position at end + if (t.angle < 0) { + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + } + // position at start + else { + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + } + break; + case 'end': + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + case 'start': + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + break; + case 'middle': + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + default: + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + } + } + else { + shim = -t.getWidth()/2; + } + // var shim = t.getWidth()/2; + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('left', val); + t.pack(); + } + } + if (lshow) { + var w = this._label._elem.outerWidth(true); + this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); + if (this.name == 'xaxis') { + this._label._elem.css('bottom', '0px'); + } + else { + this._label._elem.css('top', '0px'); + } + this._label.pack(); + } + } + else { + for (var i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + switch (t.labelPosition) { + case 'auto': + // position at end + case 'end': + if (t.angle < 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'start': + if (t.angle > 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'middle': + // if (t.angle > 0) { + // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + // } + // else { + // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + // } + shim = -t.getHeight()/2; + break; + default: + shim = -t.getHeight()/2; + break; + } + } + else { + shim = -t.getHeight()/2; + } + + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('top', val); + t.pack(); + } + } + if (lshow) { + var h = this._label._elem.outerHeight(true); + this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); + if (this.name == 'yaxis') { + this._label._elem.css('left', '0px'); + } + else { + this._label._elem.css('right', '0px'); + } + this._label.pack(); + } + } + } + }; +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.logAxisRenderer.min.js b/plugin/jqplot/plugins/jqplot.logAxisRenderer.min.js new file mode 100644 index 000000000..855f9a1a3 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.logAxisRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.LogAxisRenderer=function(){a.jqplot.LinearAxisRenderer.call(this);this.axisDefaults={base:10,tickDistribution:"power"}};a.jqplot.LogAxisRenderer.prototype=new a.jqplot.LinearAxisRenderer();a.jqplot.LogAxisRenderer.prototype.constructor=a.jqplot.LogAxisRenderer;a.jqplot.LogAxisRenderer.prototype.init=function(b){this.drawBaseline=true;this.minorTicks="auto";this._scalefact=1;a.extend(true,this,b);this._autoFormatString="%d";this._overrideFormatString=false;for(var c in this.renderer.axisDefaults){if(this[c]==null){this[c]=this.renderer.axisDefaults[c]}}this.resetDataBounds()};a.jqplot.LogAxisRenderer.prototype.createTicks=function(d){var G=this._ticks;var w=this.ticks;var s=this.name;var u=this._dataBounds;var b=(this.name.charAt(0)==="x")?this._plotDimensions.width:this._plotDimensions.height;var k;var N,v;var m,l;var M,K;var g=30;this._scalefact=(Math.max(b,g+1)-g)/300;if(w.length){for(K=0;K<w.length;K++){var A=w[K];var H=new this.tickRenderer(this.tickOptions);if(A.constructor==Array){H.value=A[0];H.label=A[1];if(!this.showTicks){H.showLabel=false;H.showMark=false}else{if(!this.showTickMarks){H.showMark=false}}H.setTick(A[0],this.name);this._ticks.push(H)}else{if(a.isPlainObject(A)){a.extend(true,H,A);H.axis=this.name;this._ticks.push(H)}else{H.value=A;if(!this.showTicks){H.showLabel=false;H.showMark=false}else{if(!this.showTickMarks){H.showMark=false}}H.setTick(A,this.name);this._ticks.push(H)}}}this.numberTicks=w.length;this.min=this._ticks[0].value;this.max=this._ticks[this.numberTicks-1].value}else{if(this.min==null&&this.max==null){N=u.min*(2-this.padMin);v=u.max*this.padMax;if(N==v){var c=0.05;N=N*(1-c);v=v*(1+c)}if(this.min!=null&&this.min<=0){throw new Error("Log axis minimum must be greater than 0")}if(this.max!=null&&this.max<=0){throw new Error("Log axis maximum must be greater than 0")}function f(j){var i=Math.pow(10,Math.floor(Math.log(j)/Math.LN10));return Math.ceil(j/i)*i}function x(j){var i=Math.pow(10,Math.floor(Math.log(j)/Math.LN10));return Math.floor(j/i)*i}var F,r;F=Math.pow(this.base,Math.floor(Math.log(N)/Math.log(this.base)));r=Math.pow(this.base,Math.ceil(Math.log(v)/Math.log(this.base)));if(F===0){F=1}var E=Math.round(Math.log(F)/Math.LN10);if(this.tickOptions==null||!this.tickOptions.formatString){this._overrideFormatString=true}this.min=F;this.max=r;var q=this.max-this.min;var C=(this.minorTicks==="auto")?0:this.minorTicks;var h;if(this.numberTicks==null){if(b>140){h=Math.round(Math.log(this.max/this.min)/Math.log(this.base)+1);if(h<2){h=2}if(C===0){var o=b/(h-1);if(o<100){C=0}else{if(o<190){C=1}else{if(o<250){C=3}else{if(o<600){C=4}else{C=9}}}}}}else{h=2;if(C===0){C=1}C=0}}else{h=this.numberTicks}if(E>=0&&C!==3){this._autoFormatString="%d"}else{if(E<=0&&C===3){var o=-(E-1);this._autoFormatString="%."+Math.abs(E-1)+"f"}else{if(E<0){var o=-E;this._autoFormatString="%."+Math.abs(E)+"f"}else{this._autoFormatString="%d"}}}var O,H,z,p,n,k;for(var K=0;K<h;K++){M=Math.pow(this.base,K-h+1)*this.max;H=new this.tickRenderer(this.tickOptions);if(this._overrideFormatString){H.formatString=this._autoFormatString}if(!this.showTicks){H.showLabel=false;H.showMark=false}else{if(!this.showTickMarks){H.showMark=false}}H.setTick(M,this.name);this._ticks.push(H);if(C&&K<h-1){p=Math.pow(this.base,K-h+2)*this.max;n=p-M;k=p/(C+1);for(var J=C-1;J>=0;J--){z=p-k*(J+1);H=new this.tickRenderer(this.tickOptions);if(this._overrideFormatString&&this._autoFormatString!=""){H.formatString=this._autoFormatString}if(!this.showTicks){H.showLabel=false;H.showMark=false}else{if(!this.showTickMarks){H.showMark=false}}H.setTick(z,this.name);this._ticks.push(H)}}}}else{if(this.min!=null&&this.max!=null){var y=a.extend(true,{},this.tickOptions,{name:this.name,value:null});var I,e;if(this.numberTicks==null&&this.tickInterval==null){var D=Math.max(b,g+1);var L=Math.ceil((D-g)/35+1);var B=a.jqplot.LinearTickGenerator.bestConstrainedInterval(this.min,this.max,L);this._autoFormatString=B[3];I=B[2];e=B[4];for(var K=0;K<I;K++){y.value=this.min+K*e;H=new this.tickRenderer(y);if(this._overrideFormatString&&this._autoFormatString!=""){H.formatString=this._autoFormatString}if(!this.showTicks){H.showLabel=false;H.showMark=false}else{if(!this.showTickMarks){H.showMark=false}}this._ticks.push(H)}}else{if(this.numberTicks!=null&&this.tickInterval!=null){I=this.numberTicks;for(var K=0;K<I;K++){y.value=this.min+K*this.tickInterval;H=new this.tickRenderer(y);if(this._overrideFormatString&&this._autoFormatString!=""){H.formatString=this._autoFormatString}if(!this.showTicks){H.showLabel=false;H.showMark=false}else{if(!this.showTickMarks){H.showMark=false}}this._ticks.push(H)}}}}}}};a.jqplot.LogAxisRenderer.prototype.pack=function(f,e){var r=parseInt(this.base,10);var y=this._ticks;var d=function(h){return Math.log(h)/Math.log(r)};var b=function(h){return Math.pow(Math.E,(Math.log(r)*h))};var u=d(this.max);var s=d(this.min);var m=e.max;var k=e.min;var o=(this._label==null)?false:this._label.show;for(var q in f){this._elem.css(q,f[q])}this._offsets=e;var g=m-k;var j=u-s;this.p2u=function(h){return b((h-k)*j/g+s)};this.u2p=function(h){return(d(h)-s)*g/j+k};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(d(h)-s)*g/j};this.series_p2u=function(h){return b(h*j/g+s)}}else{this.series_u2p=function(h){return(d(h)-u)*g/j};this.series_p2u=function(h){return b(h*j/g+u)}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(var v=0;v<y.length;v++){var n=y[v];if(n.show&&n.showLabel){var c;if(n.constructor==a.jqplot.CanvasAxisTickRenderer&&n.angle){switch(n.labelPosition){case"auto":if(n.angle<0){c=-n.getWidth()+n._textRenderer.height*Math.sin(-n._textRenderer.angle)/2}else{c=-n._textRenderer.height*Math.sin(n._textRenderer.angle)/2}break;case"end":c=-n.getWidth()+n._textRenderer.height*Math.sin(-n._textRenderer.angle)/2;break;case"start":c=-n._textRenderer.height*Math.sin(n._textRenderer.angle)/2;break;case"middle":c=-n.getWidth()/2+n._textRenderer.height*Math.sin(-n._textRenderer.angle)/2;break;default:c=-n.getWidth()/2+n._textRenderer.height*Math.sin(-n._textRenderer.angle)/2;break}}else{c=-n.getWidth()/2}var z=this.u2p(n.value)+c+"px";n._elem.css("left",z);n.pack()}}if(o){var l=this._label._elem.outerWidth(true);this._label._elem.css("left",k+g/2-l/2+"px");if(this.name=="xaxis"){this._label._elem.css("bottom","0px")}else{this._label._elem.css("top","0px")}this._label.pack()}}else{for(var v=0;v<y.length;v++){var n=y[v];if(n.show&&n.showLabel){var c;if(n.constructor==a.jqplot.CanvasAxisTickRenderer&&n.angle){switch(n.labelPosition){case"auto":case"end":if(n.angle<0){c=-n._textRenderer.height*Math.cos(-n._textRenderer.angle)/2}else{c=-n.getHeight()+n._textRenderer.height*Math.cos(n._textRenderer.angle)/2}break;case"start":if(n.angle>0){c=-n._textRenderer.height*Math.cos(-n._textRenderer.angle)/2}else{c=-n.getHeight()+n._textRenderer.height*Math.cos(n._textRenderer.angle)/2}break;case"middle":c=-n.getHeight()/2;break;default:c=-n.getHeight()/2;break}}else{c=-n.getHeight()/2}var z=this.u2p(n.value)+c+"px";n._elem.css("top",z);n.pack()}}if(o){var x=this._label._elem.outerHeight(true);this._label._elem.css("top",m-g/2-x/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px")}else{this._label._elem.css("right","0px")}this._label.pack()}}}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.mekkoAxisRenderer.js b/plugin/jqplot/plugins/jqplot.mekkoAxisRenderer.js new file mode 100644 index 000000000..b90c5bc68 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.mekkoAxisRenderer.js @@ -0,0 +1,611 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + // class: $.jqplot.MekkoAxisRenderer + // An axis renderer for a Mekko chart. + // Should be used with a Mekko chart where the mekkoRenderer is used on the series. + // Displays the Y axis as a range from 0 to 1 (0 to 100%) and the x axis with a tick + // for each series scaled to the sum of all the y values. + $.jqplot.MekkoAxisRenderer = function() { + }; + + // called with scope of axis object. + $.jqplot.MekkoAxisRenderer.prototype.init = function(options){ + // prop: tickMode + // How to space the ticks on the axis. + // 'bar' will place a tick at the width of each bar. + // This is the default for the x axis. + // 'even' will place ticks at even intervals. This is + // the default for x2 axis and y axis. y axis cannot be changed. + this.tickMode; + // prop: barLabelRenderer + // renderer to use to draw labels under each bar. + this.barLabelRenderer = $.jqplot.AxisLabelRenderer; + // prop: barLabels + // array of labels to put under each bar. + this.barLabels = this.barLabels || []; + // prop: barLabelOptions + // options object to pass to the bar label renderer. + this.barLabelOptions = {}; + this.tickOptions = $.extend(true, {showGridline:false}, this.tickOptions); + this._barLabels = []; + $.extend(true, this, options); + if (this.name == 'yaxis') { + this.tickOptions.formatString = this.tickOptions.formatString || "%d\%"; + } + var db = this._dataBounds; + db.min = 0; + // for y axes, scale always go from 0 to 1 (0 to 100%) + if (this.name == 'yaxis' || this.name == 'y2axis') { + db.max = 100; + this.tickMode = 'even'; + } + // For x axes, scale goes from 0 to sum of all y values. + else if (this.name == 'xaxis'){ + this.tickMode = (this.tickMode == null) ? 'bar' : this.tickMode; + for (var i=0; i<this._series.length; i++) { + db.max += this._series[i]._sumy; + } + } + else if (this.name == 'x2axis'){ + this.tickMode = (this.tickMode == null) ? 'even' : this.tickMode; + for (var i=0; i<this._series.length; i++) { + db.max += this._series[i]._sumy; + } + } + }; + + // called with scope of axis + $.jqplot.MekkoAxisRenderer.prototype.draw = function(ctx, plot) { + if (this.show) { + // populate the axis label and value properties. + // createTicks is a method on the renderer, but + // call it within the scope of the axis. + this.renderer.createTicks.call(this); + // fill a div with axes labels in the right direction. + // Need to pregenerate each axis to get its bounds and + // position it and the labels correctly on the plot. + var dim=0; + var temp; + + var elem = document.createElement('div'); + this._elem = $(elem); + this._elem.addClass('jqplot-axis jqplot-'+this.name); + this._elem.css('position', 'absolute'); + elem = null; + + if (this.name == 'xaxis' || this.name == 'x2axis') { + this._elem.width(this._plotDimensions.width); + } + else { + this._elem.height(this._plotDimensions.height); + } + + // draw the axis label + // create a _label object. + this.labelOptions.axis = this.name; + this._label = new this.labelRenderer(this.labelOptions); + if (this._label.show) { + this._elem.append(this._label.draw(ctx)); + } + + var t, tick, elem; + if (this.showTicks) { + t = this._ticks; + for (var i=0; i<t.length; i++) { + tick = t[i]; + if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { + this._elem.append(tick.draw(ctx)); + } + } + } + + // draw the series labels + for (i=0; i<this.barLabels.length; i++) { + this.barLabelOptions.axis = this.name; + this.barLabelOptions.label = this.barLabels[i]; + this._barLabels.push(new this.barLabelRenderer(this.barLabelOptions)); + if (this.tickMode != 'bar') { + this._barLabels[i].show = false; + } + if (this._barLabels[i].show) { + var elem = this._barLabels[i].draw(ctx, plot); + elem.removeClass('jqplot-'+this.name+'-label'); + elem.addClass('jqplot-'+this.name+'-tick'); + elem.addClass('jqplot-mekko-barLabel'); + elem.appendTo(this._elem); + elem = null; + } + } + + } + return this._elem; + }; + + // called with scope of an axis + $.jqplot.MekkoAxisRenderer.prototype.reset = function() { + this.min = this._min; + this.max = this._max; + this.tickInterval = this._tickInterval; + this.numberTicks = this._numberTicks; + // this._ticks = this.__ticks; + }; + + // called with scope of axis + $.jqplot.MekkoAxisRenderer.prototype.set = function() { + var dim = 0; + var temp; + var w = 0; + var h = 0; + var lshow = (this._label == null) ? false : this._label.show; + if (this.show && this.showTicks) { + var t = this._ticks; + for (var i=0; i<t.length; i++) { + var tick = t[i]; + if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + temp = tick._elem.outerHeight(true); + } + else { + temp = tick._elem.outerWidth(true); + } + if (temp > dim) { + dim = temp; + } + } + } + + if (lshow) { + w = this._label._elem.outerWidth(true); + h = this._label._elem.outerHeight(true); + } + if (this.name == 'xaxis') { + dim = dim + h; + this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); + } + else if (this.name == 'x2axis') { + dim = dim + h; + this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); + } + else if (this.name == 'yaxis') { + dim = dim + w; + this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css('width', w+'px'); + } + } + else { + dim = dim + w; + this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css('width', w+'px'); + } + } + } + }; + + // called with scope of axis + $.jqplot.MekkoAxisRenderer.prototype.createTicks = function() { + // we're are operating on an axis here + var ticks = this._ticks; + var userTicks = this.ticks; + var name = this.name; + // databounds were set on axis initialization. + var db = this._dataBounds; + var dim, interval; + var min, max; + var pos1, pos2; + var t, tt, i, j; + + // if we already have ticks, use them. + // ticks must be in order of increasing value. + + if (userTicks.length) { + // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed + for (i=0; i<userTicks.length; i++){ + var ut = userTicks[i]; + var t = new this.tickRenderer(this.tickOptions); + if (ut.constructor == Array) { + t.value = ut[0]; + t.label = ut[1]; + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(ut[0], this.name); + this._ticks.push(t); + } + + else { + t.value = ut; + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(ut, this.name); + this._ticks.push(t); + } + } + this.numberTicks = userTicks.length; + this.min = this._ticks[0].value; + this.max = this._ticks[this.numberTicks-1].value; + this.tickInterval = (this.max - this.min) / (this.numberTicks - 1); + } + + // we don't have any ticks yet, let's make some! + else { + if (name == 'xaxis' || name == 'x2axis') { + dim = this._plotDimensions.width; + } + else { + dim = this._plotDimensions.height; + } + + // if min, max and number of ticks specified, user can't specify interval. + if (this.min != null && this.max != null && this.numberTicks != null) { + this.tickInterval = null; + } + + min = (this.min != null) ? this.min : db.min; + max = (this.max != null) ? this.max : db.max; + + // if min and max are same, space them out a bit.+ + if (min == max) { + var adj = 0.05; + if (min > 0) { + adj = Math.max(Math.log(min)/Math.LN10, 0.05); + } + min -= adj; + max += adj; + } + + var range = max - min; + var rmin, rmax; + var temp, prev, curr; + var ynumticks = [3,5,6,11,21]; + + // yaxis divide ticks in nice intervals from 0 to 1. + if (this.name == 'yaxis' || this.name == 'y2axis') { + this.min = 0; + this.max = 100; + // user didn't specify number of ticks. + if (!this.numberTicks){ + if (this.tickInterval) { + this.numberTicks = 3 + Math.ceil(range / this.tickInterval); + } + else { + temp = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing); + for (i=0; i<ynumticks.length; i++) { + curr = temp/ynumticks[i]; + if (curr == 1) { + this.numberTicks = ynumticks[i]; + break; + } + else if (curr > 1) { + prev = curr; + continue; + } + else if (curr < 1) { + // was prev or is curr closer to one? + if (Math.abs(prev - 1) < Math.abs(curr - 1)) { + this.numberTicks = ynumticks[i-1]; + break; + } + else { + this.numberTicks = ynumticks[i]; + break; + } + } + else if (i == ynumticks.length -1) { + this.numberTicks = ynumticks[i]; + } + } + this.tickInterval = range / (this.numberTicks - 1); + } + } + + // user did specify number of ticks. + else { + this.tickInterval = range / (this.numberTicks - 1); + } + + for (var i=0; i<this.numberTicks; i++){ + tt = this.min + i * this.tickInterval; + t = new this.tickRenderer(this.tickOptions); + // var t = new $.jqplot.AxisTickRenderer(this.tickOptions); + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(tt, this.name); + this._ticks.push(t); + } + } + + // for x axes, have number ot ticks equal to number of series and ticks placed + // at sum of y values for each series. + else if (this.tickMode == 'bar') { + this.min = 0; + this.numberTicks = this._series.length + 1; + t = new this.tickRenderer(this.tickOptions); + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(0, this.name); + this._ticks.push(t); + + temp = 0; + + for (i=1; i<this.numberTicks; i++){ + temp += this._series[i-1]._sumy; + t = new this.tickRenderer(this.tickOptions); + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(temp, this.name); + this._ticks.push(t); + } + this.max = this.max || temp; + + // if user specified a max and it is greater than sum, add a tick + if (this.max > temp) { + t = new this.tickRenderer(this.tickOptions); + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(this.max, this.name); + this._ticks.push(t); + + } + } + + else if (this.tickMode == 'even') { + this.min = 0; + this.max = this.max || db.max; + // get a desired number of ticks + var nt = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing); + range = this.max - this.min; + this.numberTicks = nt; + this.tickInterval = range / (this.numberTicks - 1); + + for (i=0; i<this.numberTicks; i++){ + tt = this.min + i * this.tickInterval; + t = new this.tickRenderer(this.tickOptions); + // var t = new $.jqplot.AxisTickRenderer(this.tickOptions); + if (!this.showTicks) { + t.showLabel = false; + t.showMark = false; + } + else if (!this.showTickMarks) { + t.showMark = false; + } + t.setTick(tt, this.name); + this._ticks.push(t); + } + + } + } + }; + + // called with scope of axis + $.jqplot.MekkoAxisRenderer.prototype.pack = function(pos, offsets) { + var ticks = this._ticks; + var max = this.max; + var min = this.min; + var offmax = offsets.max; + var offmin = offsets.min; + var lshow = (this._label == null) ? false : this._label.show; + + for (var p in pos) { + this._elem.css(p, pos[p]); + } + + this._offsets = offsets; + // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. + var pixellength = offmax - offmin; + var unitlength = max - min; + + // point to unit and unit to point conversions references to Plot DOM element top left corner. + this.p2u = function(p){ + return (p - offmin) * unitlength / pixellength + min; + }; + + this.u2p = function(u){ + return (u - min) * pixellength / unitlength + offmin; + }; + + if (this.name == 'xaxis' || this.name == 'x2axis'){ + this.series_u2p = function(u){ + return (u - min) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + min; + }; + } + + else { + this.series_u2p = function(u){ + return (u - max) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + max; + }; + } + + if (this.show) { + if (this.name == 'xaxis' || this.name == 'x2axis') { + for (var i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + // will need to adjust auto positioning based on which axis this is. + var temp = (this.name == 'xaxis') ? 1 : -1; + switch (t.labelPosition) { + case 'auto': + // position at end + if (temp * t.angle < 0) { + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + } + // position at start + else { + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + } + break; + case 'end': + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + case 'start': + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + break; + case 'middle': + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + default: + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + } + } + else { + shim = -t.getWidth()/2; + } + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('left', val); + t.pack(); + } + } + var w; + if (lshow) { + w = this._label._elem.outerWidth(true); + this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); + if (this.name == 'xaxis') { + this._label._elem.css('bottom', '0px'); + } + else { + this._label._elem.css('top', '0px'); + } + this._label.pack(); + } + // now show the labels under the bars. + var b, l, r; + for (var i=0; i<this.barLabels.length; i++) { + b = this._barLabels[i]; + if (b.show) { + w = b.getWidth(); + l = this._ticks[i].getLeft() + this._ticks[i].getWidth(); + r = this._ticks[i+1].getLeft(); + b._elem.css('left', (r+l-w)/2+'px'); + b._elem.css('top', this._ticks[i]._elem.css('top')); + b.pack(); + } + } + } + else { + for (var i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + // will need to adjust auto positioning based on which axis this is. + var temp = (this.name == 'yaxis') ? 1 : -1; + switch (t.labelPosition) { + case 'auto': + // position at end + case 'end': + if (temp * t.angle < 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'start': + if (t.angle > 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'middle': + shim = -t.getHeight()/2; + break; + default: + shim = -t.getHeight()/2; + break; + } + } + else { + shim = -t.getHeight()/2; + } + + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('top', val); + t.pack(); + } + } + if (lshow) { + var h = this._label._elem.outerHeight(true); + this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); + if (this.name == 'yaxis') { + this._label._elem.css('left', '0px'); + } + else { + this._label._elem.css('right', '0px'); + } + this._label.pack(); + } + } + } + }; +})(jQuery); diff --git a/plugin/jqplot/plugins/jqplot.mekkoAxisRenderer.min.js b/plugin/jqplot/plugins/jqplot.mekkoAxisRenderer.min.js new file mode 100644 index 000000000..7969de739 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.mekkoAxisRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.MekkoAxisRenderer=function(){};a.jqplot.MekkoAxisRenderer.prototype.init=function(c){this.tickMode;this.barLabelRenderer=a.jqplot.AxisLabelRenderer;this.barLabels=this.barLabels||[];this.barLabelOptions={};this.tickOptions=a.extend(true,{showGridline:false},this.tickOptions);this._barLabels=[];a.extend(true,this,c);if(this.name=="yaxis"){this.tickOptions.formatString=this.tickOptions.formatString||"%d%"}var b=this._dataBounds;b.min=0;if(this.name=="yaxis"||this.name=="y2axis"){b.max=100;this.tickMode="even"}else{if(this.name=="xaxis"){this.tickMode=(this.tickMode==null)?"bar":this.tickMode;for(var d=0;d<this._series.length;d++){b.max+=this._series[d]._sumy}}else{if(this.name=="x2axis"){this.tickMode=(this.tickMode==null)?"even":this.tickMode;for(var d=0;d<this._series.length;d++){b.max+=this._series[d]._sumy}}}}};a.jqplot.MekkoAxisRenderer.prototype.draw=function(b,j){if(this.show){this.renderer.createTicks.call(this);var h=0;var c;var g=document.createElement("div");this._elem=a(g);this._elem.addClass("jqplot-axis jqplot-"+this.name);this._elem.css("position","absolute");g=null;if(this.name=="xaxis"||this.name=="x2axis"){this._elem.width(this._plotDimensions.width)}else{this._elem.height(this._plotDimensions.height)}this.labelOptions.axis=this.name;this._label=new this.labelRenderer(this.labelOptions);if(this._label.show){this._elem.append(this._label.draw(b))}var f,e,g;if(this.showTicks){f=this._ticks;for(var d=0;d<f.length;d++){e=f[d];if(e.showLabel&&(!e.isMinorTick||this.showMinorTicks)){this._elem.append(e.draw(b))}}}for(d=0;d<this.barLabels.length;d++){this.barLabelOptions.axis=this.name;this.barLabelOptions.label=this.barLabels[d];this._barLabels.push(new this.barLabelRenderer(this.barLabelOptions));if(this.tickMode!="bar"){this._barLabels[d].show=false}if(this._barLabels[d].show){var g=this._barLabels[d].draw(b,j);g.removeClass("jqplot-"+this.name+"-label");g.addClass("jqplot-"+this.name+"-tick");g.addClass("jqplot-mekko-barLabel");g.appendTo(this._elem);g=null}}}return this._elem};a.jqplot.MekkoAxisRenderer.prototype.reset=function(){this.min=this._min;this.max=this._max;this.tickInterval=this._tickInterval;this.numberTicks=this._numberTicks};a.jqplot.MekkoAxisRenderer.prototype.set=function(){var k=0;var d;var c=0;var j=0;var b=(this._label==null)?false:this._label.show;if(this.show&&this.showTicks){var g=this._ticks;for(var f=0;f<g.length;f++){var e=g[f];if(e.showLabel&&(!e.isMinorTick||this.showMinorTicks)){if(this.name=="xaxis"||this.name=="x2axis"){d=e._elem.outerHeight(true)}else{d=e._elem.outerWidth(true)}if(d>k){k=d}}}if(b){c=this._label._elem.outerWidth(true);j=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){k=k+j;this._elem.css({height:k+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){k=k+j;this._elem.css({height:k+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){k=k+c;this._elem.css({width:k+"px",left:"0px",top:"0px"});if(b&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",c+"px")}}else{k=k+c;this._elem.css({width:k+"px",right:"0px",top:"0px"});if(b&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",c+"px")}}}}}};a.jqplot.MekkoAxisRenderer.prototype.createTicks=function(){var z=this._ticks;var w=this.ticks;var B=this.name;var y=this._dataBounds;var p,x;var n,r;var d,c;var h,b,s,q;if(w.length){for(s=0;s<w.length;s++){var e=w[s];var h=new this.tickRenderer(this.tickOptions);if(e.constructor==Array){h.value=e[0];h.label=e[1];if(!this.showTicks){h.showLabel=false;h.showMark=false}else{if(!this.showTickMarks){h.showMark=false}}h.setTick(e[0],this.name);this._ticks.push(h)}else{h.value=e;if(!this.showTicks){h.showLabel=false;h.showMark=false}else{if(!this.showTickMarks){h.showMark=false}}h.setTick(e,this.name);this._ticks.push(h)}}this.numberTicks=w.length;this.min=this._ticks[0].value;this.max=this._ticks[this.numberTicks-1].value;this.tickInterval=(this.max-this.min)/(this.numberTicks-1)}else{if(B=="xaxis"||B=="x2axis"){p=this._plotDimensions.width}else{p=this._plotDimensions.height}if(this.min!=null&&this.max!=null&&this.numberTicks!=null){this.tickInterval=null}n=(this.min!=null)?this.min:y.min;r=(this.max!=null)?this.max:y.max;if(n==r){var g=0.05;if(n>0){g=Math.max(Math.log(n)/Math.LN10,0.05)}n-=g;r+=g}var k=r-n;var m,o;var v,l,u;var f=[3,5,6,11,21];if(this.name=="yaxis"||this.name=="y2axis"){this.min=0;this.max=100;if(!this.numberTicks){if(this.tickInterval){this.numberTicks=3+Math.ceil(k/this.tickInterval)}else{v=2+Math.ceil((p-(this.tickSpacing-1))/this.tickSpacing);for(s=0;s<f.length;s++){u=v/f[s];if(u==1){this.numberTicks=f[s];break}else{if(u>1){l=u;continue}else{if(u<1){if(Math.abs(l-1)<Math.abs(u-1)){this.numberTicks=f[s-1];break}else{this.numberTicks=f[s];break}}else{if(s==f.length-1){this.numberTicks=f[s]}}}}}this.tickInterval=k/(this.numberTicks-1)}}else{this.tickInterval=k/(this.numberTicks-1)}for(var s=0;s<this.numberTicks;s++){b=this.min+s*this.tickInterval;h=new this.tickRenderer(this.tickOptions);if(!this.showTicks){h.showLabel=false;h.showMark=false}else{if(!this.showTickMarks){h.showMark=false}}h.setTick(b,this.name);this._ticks.push(h)}}else{if(this.tickMode=="bar"){this.min=0;this.numberTicks=this._series.length+1;h=new this.tickRenderer(this.tickOptions);if(!this.showTicks){h.showLabel=false;h.showMark=false}else{if(!this.showTickMarks){h.showMark=false}}h.setTick(0,this.name);this._ticks.push(h);v=0;for(s=1;s<this.numberTicks;s++){v+=this._series[s-1]._sumy;h=new this.tickRenderer(this.tickOptions);if(!this.showTicks){h.showLabel=false;h.showMark=false}else{if(!this.showTickMarks){h.showMark=false}}h.setTick(v,this.name);this._ticks.push(h)}this.max=this.max||v;if(this.max>v){h=new this.tickRenderer(this.tickOptions);if(!this.showTicks){h.showLabel=false;h.showMark=false}else{if(!this.showTickMarks){h.showMark=false}}h.setTick(this.max,this.name);this._ticks.push(h)}}else{if(this.tickMode=="even"){this.min=0;this.max=this.max||y.max;var A=2+Math.ceil((p-(this.tickSpacing-1))/this.tickSpacing);k=this.max-this.min;this.numberTicks=A;this.tickInterval=k/(this.numberTicks-1);for(s=0;s<this.numberTicks;s++){b=this.min+s*this.tickInterval;h=new this.tickRenderer(this.tickOptions);if(!this.showTicks){h.showLabel=false;h.showMark=false}else{if(!this.showTickMarks){h.showMark=false}}h.setTick(b,this.name);this._ticks.push(h)}}}}}};a.jqplot.MekkoAxisRenderer.prototype.pack=function(e,d){var C=this._ticks;var x=this.max;var v=this.min;var m=d.max;var j=d.min;var o=(this._label==null)?false:this._label.show;for(var s in e){this._elem.css(s,e[s])}this._offsets=d;var f=m-j;var g=x-v;this.p2u=function(b){return(b-j)*g/f+v};this.u2p=function(b){return(b-v)*f/g+j};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(b){return(b-v)*f/g};this.series_p2u=function(b){return b*g/f+v}}else{this.series_u2p=function(b){return(b-x)*f/g};this.series_p2u=function(b){return b*g/f+x}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(var y=0;y<C.length;y++){var n=C[y];if(n.show&&n.showLabel){var c;if(n.constructor==a.jqplot.CanvasAxisTickRenderer&&n.angle){var A=(this.name=="xaxis")?1:-1;switch(n.labelPosition){case"auto":if(A*n.angle<0){c=-n.getWidth()+n._textRenderer.height*Math.sin(-n._textRenderer.angle)/2}else{c=-n._textRenderer.height*Math.sin(n._textRenderer.angle)/2}break;case"end":c=-n.getWidth()+n._textRenderer.height*Math.sin(-n._textRenderer.angle)/2;break;case"start":c=-n._textRenderer.height*Math.sin(n._textRenderer.angle)/2;break;case"middle":c=-n.getWidth()/2+n._textRenderer.height*Math.sin(-n._textRenderer.angle)/2;break;default:c=-n.getWidth()/2+n._textRenderer.height*Math.sin(-n._textRenderer.angle)/2;break}}else{c=-n.getWidth()/2}var D=this.u2p(n.value)+c+"px";n._elem.css("left",D);n.pack()}}var k;if(o){k=this._label._elem.outerWidth(true);this._label._elem.css("left",j+f/2-k/2+"px");if(this.name=="xaxis"){this._label._elem.css("bottom","0px")}else{this._label._elem.css("top","0px")}this._label.pack()}var B,u,q;for(var y=0;y<this.barLabels.length;y++){B=this._barLabels[y];if(B.show){k=B.getWidth();u=this._ticks[y].getLeft()+this._ticks[y].getWidth();q=this._ticks[y+1].getLeft();B._elem.css("left",(q+u-k)/2+"px");B._elem.css("top",this._ticks[y]._elem.css("top"));B.pack()}}}else{for(var y=0;y<C.length;y++){var n=C[y];if(n.show&&n.showLabel){var c;if(n.constructor==a.jqplot.CanvasAxisTickRenderer&&n.angle){var A=(this.name=="yaxis")?1:-1;switch(n.labelPosition){case"auto":case"end":if(A*n.angle<0){c=-n._textRenderer.height*Math.cos(-n._textRenderer.angle)/2}else{c=-n.getHeight()+n._textRenderer.height*Math.cos(n._textRenderer.angle)/2}break;case"start":if(n.angle>0){c=-n._textRenderer.height*Math.cos(-n._textRenderer.angle)/2}else{c=-n.getHeight()+n._textRenderer.height*Math.cos(n._textRenderer.angle)/2}break;case"middle":c=-n.getHeight()/2;break;default:c=-n.getHeight()/2;break}}else{c=-n.getHeight()/2}var D=this.u2p(n.value)+c+"px";n._elem.css("top",D);n.pack()}}if(o){var z=this._label._elem.outerHeight(true);this._label._elem.css("top",m-f/2-z/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px")}else{this._label._elem.css("right","0px")}this._label.pack()}}}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.mekkoRenderer.js b/plugin/jqplot/plugins/jqplot.mekkoRenderer.js new file mode 100644 index 000000000..05f495fb5 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.mekkoRenderer.js @@ -0,0 +1,437 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.MekkoRenderer + * Draws a Mekko style chart which shows 3 dimensional data on a 2 dimensional graph. + * the <$.jqplot.MekkoAxisRenderer> should be used with mekko charts. The mekko renderer + * overrides the default legend renderer with its own $.jqplot.MekkoLegendRenderer + * which allows more flexibility to specify number of rows and columns in the legend. + * + * Data is specified per bar in the chart. You can specify data as an array of y values, or as + * an array of [label, value] pairs. Note that labels are used only on the first series. + * Labels on subsequent series are ignored: + * + * > bar1 = [['shirts', 8],['hats', 14],['shoes', 6],['gloves', 16],['dolls', 12]]; + * > bar2 = [15,6,9,13,6]; + * > bar3 = [['grumpy',4],['sneezy',2],['happy',7],['sleepy',9],['doc',7]]; + * + * If you want to place labels for each bar under the axis, you use the barLabels option on + * the axes. The bar labels can be styled with the ".jqplot-mekko-barLabel" css class. + * + * > barLabels = ['Mickey Mouse', 'Donald Duck', 'Goofy']; + * > axes:{xaxis:{barLabels:barLabels}} + * + */ + + + $.jqplot.MekkoRenderer = function(){ + this.shapeRenderer = new $.jqplot.ShapeRenderer(); + // prop: borderColor + // color of the borders between areas on the chart + this.borderColor = null; + // prop: showBorders + // True to draw borders lines between areas on the chart. + // False will draw borders lines with the same color as the area. + this.showBorders = true; + }; + + // called with scope of series. + $.jqplot.MekkoRenderer.prototype.init = function(options, plot) { + this.fill = false; + this.fillRect = true; + this.strokeRect = true; + this.shadow = false; + // width of bar on x axis. + this._xwidth = 0; + this._xstart = 0; + $.extend(true, this.renderer, options); + // set the shape renderer options + var opts = {lineJoin:'miter', lineCap:'butt', isarc:false, fillRect:this.fillRect, strokeRect:this.strokeRect}; + this.renderer.shapeRenderer.init(opts); + plot.axes.x2axis._series.push(this); + this._type = 'mekko'; + }; + + // Method: setGridData + // converts the user data values to grid coordinates and stores them + // in the gridData array. Will convert user data into appropriate + // rectangles. + // Called with scope of a series. + $.jqplot.MekkoRenderer.prototype.setGridData = function(plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var data = this._plotData; + this.gridData = []; + // figure out width on x axis. + // this._xwidth = this._sumy / plot._sumy * this.canvas.getWidth(); + this._xwidth = xp(this._sumy) - xp(0); + if (this.index>0) { + this._xstart = plot.series[this.index-1]._xstart + plot.series[this.index-1]._xwidth; + } + var totheight = this.canvas.getHeight(); + var sumy = 0; + var cury; + var curheight; + for (var i=0; i<data.length; i++) { + if (data[i] != null) { + sumy += data[i][1]; + cury = totheight - (sumy / this._sumy * totheight); + curheight = data[i][1] / this._sumy * totheight; + this.gridData.push([this._xstart, cury, this._xwidth, curheight]); + } + } + }; + + // Method: makeGridData + // converts any arbitrary data values to grid coordinates and + // returns them. This method exists so that plugins can use a series' + // linerenderer to generate grid data points without overwriting the + // grid data associated with that series. + // Called with scope of a series. + $.jqplot.MekkoRenderer.prototype.makeGridData = function(data, plot) { + // recalculate the grid data + // figure out width on x axis. + var xp = this._xaxis.series_u2p; + var totheight = this.canvas.getHeight(); + var sumy = 0; + var cury; + var curheight; + var gd = []; + for (var i=0; i<data.length; i++) { + if (data[i] != null) { + sumy += data[i][1]; + cury = totheight - (sumy / this._sumy * totheight); + curheight = data[i][1] / this._sumy * totheight; + gd.push([this._xstart, cury, this._xwidth, curheight]); + } + } + return gd; + }; + + + // called within scope of series. + $.jqplot.MekkoRenderer.prototype.draw = function(ctx, gd, options) { + var i; + var opts = (options != undefined) ? options : {}; + var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; + var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); + ctx.save(); + if (gd.length) { + if (showLine) { + for (i=0; i<gd.length; i++){ + opts.fillStyle = colorGenerator.next(); + if (this.renderer.showBorders) { + opts.strokeStyle = this.renderer.borderColor; + } + else { + opts.strokeStyle = opts.fillStyle; + } + this.renderer.shapeRenderer.draw(ctx, gd[i], opts); + } + } + } + + ctx.restore(); + }; + + $.jqplot.MekkoRenderer.prototype.drawShadow = function(ctx, gd, options) { + // This is a no-op, no shadows on mekko charts. + }; + + /** + * Class: $.jqplot.MekkoLegendRenderer + * Legend renderer used by mekko charts with options for + * controlling number or rows and columns as well as placement + * outside of plot area. + * + */ + $.jqplot.MekkoLegendRenderer = function(){ + // + }; + + $.jqplot.MekkoLegendRenderer.prototype.init = function(options) { + // prop: numberRows + // Maximum number of rows in the legend. 0 or null for unlimited. + this.numberRows = null; + // prop: numberColumns + // Maximum number of columns in the legend. 0 or null for unlimited. + this.numberColumns = null; + // this will override the placement option on the Legend object + this.placement = "outside"; + $.extend(true, this, options); + }; + + // called with scope of legend + $.jqplot.MekkoLegendRenderer.prototype.draw = function() { + var legend = this; + if (this.show) { + var series = this._series; + var ss = 'position:absolute;'; + ss += (this.background) ? 'background:'+this.background+';' : ''; + ss += (this.border) ? 'border:'+this.border+';' : ''; + ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; + ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; + ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; + this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); + // Mekko charts legends don't go by number of series, but by number of data points + // in the series. Refactor things here for that. + + var pad = false, + reverse = true, // mekko charts are always stacked, so reverse + nr, nc; + var s = series[0]; + var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); + + if (s.show) { + var pd = s.data; + if (this.numberRows) { + nr = this.numberRows; + if (!this.numberColumns){ + nc = Math.ceil(pd.length/nr); + } + else{ + nc = this.numberColumns; + } + } + else if (this.numberColumns) { + nc = this.numberColumns; + nr = Math.ceil(pd.length/this.numberColumns); + } + else { + nr = pd.length; + nc = 1; + } + + var i, j, tr, td1, td2, lt, rs, color; + var idx = 0; + + for (i=0; i<nr; i++) { + if (reverse){ + tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); + } + else{ + tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); + } + for (j=0; j<nc; j++) { + if (idx < pd.length) { + lt = this.labels[idx] || pd[idx][0].toString(); + color = colorGenerator.next(); + if (!reverse){ + if (i>0){ + pad = true; + } + else{ + pad = false; + } + } + else{ + if (i == nr -1){ + pad = false; + } + else{ + pad = true; + } + } + rs = (pad) ? this.rowSpacing : '0'; + + td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ + '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ + '</div></td>'); + td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); + if (this.escapeHtml){ + td2.text(lt); + } + else { + td2.html(lt); + } + if (reverse) { + td2.prependTo(tr); + td1.prependTo(tr); + } + else { + td1.appendTo(tr); + td2.appendTo(tr); + } + pad = true; + } + idx++; + } + } + + tr = null; + td1 = null; + td2 = null; + } + } + return this._elem; + }; + + $.jqplot.MekkoLegendRenderer.prototype.pack = function(offsets) { + if (this.show) { + // fake a grid for positioning + var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom}; + if (this.placement == 'insideGrid') { + switch (this.location) { + case 'nw': + var a = grid._left + this.xoffset; + var b = grid._top + this.yoffset; + this._elem.css('left', a); + this._elem.css('top', b); + break; + case 'n': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + var b = grid._top + this.yoffset; + this._elem.css('left', a); + this._elem.css('top', b); + break; + case 'ne': + var a = offsets.right + this.xoffset; + var b = grid._top + this.yoffset; + this._elem.css({right:a, top:b}); + break; + case 'e': + var a = offsets.right + this.xoffset; + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({right:a, top:b}); + break; + case 'se': + var a = offsets.right + this.xoffset; + var b = offsets.bottom + this.yoffset; + this._elem.css({right:a, bottom:b}); + break; + case 's': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + var b = offsets.bottom + this.yoffset; + this._elem.css({left:a, bottom:b}); + break; + case 'sw': + var a = grid._left + this.xoffset; + var b = offsets.bottom + this.yoffset; + this._elem.css({left:a, bottom:b}); + break; + case 'w': + var a = grid._left + this.xoffset; + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({left:a, top:b}); + break; + default: // same as 'se' + var a = grid._right - this.xoffset; + var b = grid._bottom + this.yoffset; + this._elem.css({right:a, bottom:b}); + break; + } + + } + else { + switch (this.location) { + case 'nw': + var a = this._plotDimensions.width - grid._left + this.xoffset; + var b = grid._top + this.yoffset; + this._elem.css('right', a); + this._elem.css('top', b); + break; + case 'n': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + var b = this._plotDimensions.height - grid._top + this.yoffset; + this._elem.css('left', a); + this._elem.css('bottom', b); + break; + case 'ne': + var a = this._plotDimensions.width - offsets.right + this.xoffset; + var b = grid._top + this.yoffset; + this._elem.css({left:a, top:b}); + break; + case 'e': + var a = this._plotDimensions.width - offsets.right + this.xoffset; + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({left:a, top:b}); + break; + case 'se': + var a = this._plotDimensions.width - offsets.right + this.xoffset; + var b = offsets.bottom + this.yoffset; + this._elem.css({left:a, bottom:b}); + break; + case 's': + var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; + var b = this._plotDimensions.height - offsets.bottom + this.yoffset; + this._elem.css({left:a, top:b}); + break; + case 'sw': + var a = this._plotDimensions.width - grid._left + this.xoffset; + var b = offsets.bottom + this.yoffset; + this._elem.css({right:a, bottom:b}); + break; + case 'w': + var a = this._plotDimensions.width - grid._left + this.xoffset; + var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; + this._elem.css({right:a, top:b}); + break; + default: // same as 'se' + var a = grid._right - this.xoffset; + var b = grid._bottom + this.yoffset; + this._elem.css({right:a, bottom:b}); + break; + } + } + } + }; + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + options = options || {}; + options.axesDefaults = options.axesDefaults || {}; + options.legend = options.legend || {}; + options.seriesDefaults = options.seriesDefaults || {}; + var setopts = false; + if (options.seriesDefaults.renderer == $.jqplot.MekkoRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer == $.jqplot.MekkoRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.MekkoAxisRenderer; + options.legend.renderer = $.jqplot.MekkoLegendRenderer; + options.legend.preDraw = true; + } + } + + $.jqplot.preInitHooks.push(preInit); + +})(jQuery); diff --git a/plugin/jqplot/plugins/jqplot.mekkoRenderer.min.js b/plugin/jqplot/plugins/jqplot.mekkoRenderer.min.js new file mode 100644 index 000000000..18dc3a12b --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.mekkoRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(b){b.jqplot.MekkoRenderer=function(){this.shapeRenderer=new b.jqplot.ShapeRenderer();this.borderColor=null;this.showBorders=true};b.jqplot.MekkoRenderer.prototype.init=function(c,e){this.fill=false;this.fillRect=true;this.strokeRect=true;this.shadow=false;this._xwidth=0;this._xstart=0;b.extend(true,this.renderer,c);var d={lineJoin:"miter",lineCap:"butt",isarc:false,fillRect:this.fillRect,strokeRect:this.strokeRect};this.renderer.shapeRenderer.init(d);e.axes.x2axis._series.push(this);this._type="mekko"};b.jqplot.MekkoRenderer.prototype.setGridData=function(h){var e=this._xaxis.series_u2p;var c=this._yaxis.series_u2p;var g=this._plotData;this.gridData=[];this._xwidth=e(this._sumy)-e(0);if(this.index>0){this._xstart=h.series[this.index-1]._xstart+h.series[this.index-1]._xwidth}var l=this.canvas.getHeight();var d=0;var k;var j;for(var f=0;f<g.length;f++){if(g[f]!=null){d+=g[f][1];k=l-(d/this._sumy*l);j=g[f][1]/this._sumy*l;this.gridData.push([this._xstart,k,this._xwidth,j])}}};b.jqplot.MekkoRenderer.prototype.makeGridData=function(f,g){var d=this._xaxis.series_u2p;var l=this.canvas.getHeight();var c=0;var j;var h;var k=[];for(var e=0;e<f.length;e++){if(f[e]!=null){c+=f[e][1];j=l-(c/this._sumy*l);h=f[e][1]/this._sumy*l;k.push([this._xstart,j,this._xwidth,h])}}return k};b.jqplot.MekkoRenderer.prototype.draw=function(c,h,d){var e;var g=(d!=undefined)?d:{};var f=(g.showLine!=undefined)?g.showLine:this.showLine;var j=new b.jqplot.ColorGenerator(this.seriesColors);c.save();if(h.length){if(f){for(e=0;e<h.length;e++){g.fillStyle=j.next();if(this.renderer.showBorders){g.strokeStyle=this.renderer.borderColor}else{g.strokeStyle=g.fillStyle}this.renderer.shapeRenderer.draw(c,h[e],g)}}}c.restore()};b.jqplot.MekkoRenderer.prototype.drawShadow=function(c,e,d){};b.jqplot.MekkoLegendRenderer=function(){};b.jqplot.MekkoLegendRenderer.prototype.init=function(c){this.numberRows=null;this.numberColumns=null;this.placement="outside";b.extend(true,this,c)};b.jqplot.MekkoLegendRenderer.prototype.draw=function(){var f=this;if(this.show){var o=this._series;var r="position:absolute;";r+=(this.background)?"background:"+this.background+";":"";r+=(this.border)?"border:"+this.border+";":"";r+=(this.fontSize)?"font-size:"+this.fontSize+";":"";r+=(this.fontFamily)?"font-family:"+this.fontFamily+";":"";r+=(this.textColor)?"color:"+this.textColor+";":"";this._elem=b('<table class="jqplot-table-legend" style="'+r+'"></table>');var w=false,n=true,c,l;var p=o[0];var d=new b.jqplot.ColorGenerator(p.seriesColors);if(p.show){var x=p.data;if(this.numberRows){c=this.numberRows;if(!this.numberColumns){l=Math.ceil(x.length/c)}else{l=this.numberColumns}}else{if(this.numberColumns){l=this.numberColumns;c=Math.ceil(x.length/this.numberColumns)}else{c=x.length;l=1}}var v,u,e,h,g,k,m,t;var q=0;for(v=0;v<c;v++){if(n){e=b('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem)}else{e=b('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem)}for(u=0;u<l;u++){if(q<x.length){k=this.labels[q]||x[q][0].toString();t=d.next();if(!n){if(v>0){w=true}else{w=false}}else{if(v==c-1){w=false}else{w=true}}m=(w)?this.rowSpacing:"0";h=b('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+m+';"><div><div class="jqplot-table-legend-swatch" style="border-color:'+t+';"></div></div></td>');g=b('<td class="jqplot-table-legend" style="padding-top:'+m+';"></td>');if(this.escapeHtml){g.text(k)}else{g.html(k)}if(n){g.prependTo(e);h.prependTo(e)}else{h.appendTo(e);g.appendTo(e)}w=true}q++}}e=null;h=null;g=null}}return this._elem};b.jqplot.MekkoLegendRenderer.prototype.pack=function(f){if(this.show){var e={_top:f.top,_left:f.left,_right:f.right,_bottom:this._plotDimensions.height-f.bottom};if(this.placement=="insideGrid"){switch(this.location){case"nw":var d=e._left+this.xoffset;var c=e._top+this.yoffset;this._elem.css("left",d);this._elem.css("top",c);break;case"n":var d=(f.left+(this._plotDimensions.width-f.right))/2-this.getWidth()/2;var c=e._top+this.yoffset;this._elem.css("left",d);this._elem.css("top",c);break;case"ne":var d=f.right+this.xoffset;var c=e._top+this.yoffset;this._elem.css({right:d,top:c});break;case"e":var d=f.right+this.xoffset;var c=(f.top+(this._plotDimensions.height-f.bottom))/2-this.getHeight()/2;this._elem.css({right:d,top:c});break;case"se":var d=f.right+this.xoffset;var c=f.bottom+this.yoffset;this._elem.css({right:d,bottom:c});break;case"s":var d=(f.left+(this._plotDimensions.width-f.right))/2-this.getWidth()/2;var c=f.bottom+this.yoffset;this._elem.css({left:d,bottom:c});break;case"sw":var d=e._left+this.xoffset;var c=f.bottom+this.yoffset;this._elem.css({left:d,bottom:c});break;case"w":var d=e._left+this.xoffset;var c=(f.top+(this._plotDimensions.height-f.bottom))/2-this.getHeight()/2;this._elem.css({left:d,top:c});break;default:var d=e._right-this.xoffset;var c=e._bottom+this.yoffset;this._elem.css({right:d,bottom:c});break}}else{switch(this.location){case"nw":var d=this._plotDimensions.width-e._left+this.xoffset;var c=e._top+this.yoffset;this._elem.css("right",d);this._elem.css("top",c);break;case"n":var d=(f.left+(this._plotDimensions.width-f.right))/2-this.getWidth()/2;var c=this._plotDimensions.height-e._top+this.yoffset;this._elem.css("left",d);this._elem.css("bottom",c);break;case"ne":var d=this._plotDimensions.width-f.right+this.xoffset;var c=e._top+this.yoffset;this._elem.css({left:d,top:c});break;case"e":var d=this._plotDimensions.width-f.right+this.xoffset;var c=(f.top+(this._plotDimensions.height-f.bottom))/2-this.getHeight()/2;this._elem.css({left:d,top:c});break;case"se":var d=this._plotDimensions.width-f.right+this.xoffset;var c=f.bottom+this.yoffset;this._elem.css({left:d,bottom:c});break;case"s":var d=(f.left+(this._plotDimensions.width-f.right))/2-this.getWidth()/2;var c=this._plotDimensions.height-f.bottom+this.yoffset;this._elem.css({left:d,top:c});break;case"sw":var d=this._plotDimensions.width-e._left+this.xoffset;var c=f.bottom+this.yoffset;this._elem.css({right:d,bottom:c});break;case"w":var d=this._plotDimensions.width-e._left+this.xoffset;var c=(f.top+(this._plotDimensions.height-f.bottom))/2-this.getHeight()/2;this._elem.css({right:d,top:c});break;default:var d=e._right-this.xoffset;var c=e._bottom+this.yoffset;this._elem.css({right:d,bottom:c});break}}}};function a(g,f,d){d=d||{};d.axesDefaults=d.axesDefaults||{};d.legend=d.legend||{};d.seriesDefaults=d.seriesDefaults||{};var c=false;if(d.seriesDefaults.renderer==b.jqplot.MekkoRenderer){c=true}else{if(d.series){for(var e=0;e<d.series.length;e++){if(d.series[e].renderer==b.jqplot.MekkoRenderer){c=true}}}}if(c){d.axesDefaults.renderer=b.jqplot.MekkoAxisRenderer;d.legend.renderer=b.jqplot.MekkoLegendRenderer;d.legend.preDraw=true}}b.jqplot.preInitHooks.push(a)})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.meterGaugeRenderer.js b/plugin/jqplot/plugins/jqplot.meterGaugeRenderer.js new file mode 100644 index 000000000..8bd899d6c --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.meterGaugeRenderer.js @@ -0,0 +1,1029 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.MeterGaugeRenderer + * Plugin renderer to draw a meter gauge chart. + * + * Data consists of a single series with 1 data point to position the gauge needle. + * + * To use this renderer, you need to include the + * meter gauge renderer plugin, for example: + * + * > <script type="text/javascript" src="plugins/jqplot.meterGaugeRenderer.js"></script> + * + * Properties described here are passed into the $.jqplot function + * as options on the series renderer. For example: + * + * > plot0 = $.jqplot('chart0',[[18]],{ + * > title: 'Network Speed', + * > seriesDefaults: { + * > renderer: $.jqplot.MeterGaugeRenderer, + * > rendererOptions: { + * > label: 'MB/s' + * > } + * > } + * > }); + * + * A meterGauge plot does not support events. + */ + $.jqplot.MeterGaugeRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.MeterGaugeRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.MeterGaugeRenderer.prototype.constructor = $.jqplot.MeterGaugeRenderer; + + // called with scope of a series + $.jqplot.MeterGaugeRenderer.prototype.init = function(options) { + // Group: Properties + // + // prop: diameter + // Outer diameter of the meterGauge, auto computed by default + this.diameter = null; + // prop: padding + // padding between the meterGauge and plot edges, auto + // calculated by default. + this.padding = null; + // prop: shadowOffset + // offset of the shadow from the gauge ring and offset of + // each succesive stroke of the shadow from the last. + this.shadowOffset = 2; + // prop: shadowAlpha + // transparency of the shadow (0 = transparent, 1 = opaque) + this.shadowAlpha = 0.07; + // prop: shadowDepth + // number of strokes to apply to the shadow, + // each stroke offset shadowOffset from the last. + this.shadowDepth = 4; + // prop: background + // background color of the inside of the gauge. + this.background = "#efefef"; + // prop: ringColor + // color of the outer ring, hub, and needle of the gauge. + this.ringColor = "#BBC6D0"; + // needle color not implemented yet. + this.needleColor = "#C3D3E5"; + // prop: tickColor + // color of the tick marks around the gauge. + this.tickColor = "#989898"; + // prop: ringWidth + // width of the ring around the gauge. Auto computed by default. + this.ringWidth = null; + // prop: min + // Minimum value on the gauge. Auto computed by default + this.min; + // prop: max + // Maximum value on the gauge. Auto computed by default + this.max; + // prop: ticks + // Array of tick values. Auto computed by default. + this.ticks = []; + // prop: showTicks + // true to show ticks around gauge. + this.showTicks = true; + // prop: showTickLabels + // true to show tick labels next to ticks. + this.showTickLabels = true; + // prop: label + // A gauge label like 'kph' or 'Volts' + this.label = null; + // prop: labelHeightAdjust + // Number of Pixels to offset the label up (-) or down (+) from its default position. + this.labelHeightAdjust = 0; + // prop: labelPosition + // Where to position the label, either 'inside' or 'bottom'. + this.labelPosition = 'inside'; + // prop: intervals + // Array of ranges to be drawn around the gauge. + // Array of form: + // > [value1, value2, ...] + // indicating the values for the first, second, ... intervals. + this.intervals = []; + // prop: intervalColors + // Array of colors to use for the intervals. + this.intervalColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"]; + // prop: intervalInnerRadius + // Radius of the inner circle of the interval ring. + this.intervalInnerRadius = null; + // prop: intervalOuterRadius + // Radius of the outer circle of the interval ring. + this.intervalOuterRadius = null; + this.tickRenderer = $.jqplot.MeterGaugeTickRenderer; + // ticks spaced every 1, 2, 2.5, 5, 10, 20, .1, .2, .25, .5, etc. + this.tickPositions = [1, 2, 2.5, 5, 10]; + // prop: tickSpacing + // Degrees between ticks. This is a target number, if + // incompatible span and ticks are supplied, a suitable + // spacing close to this value will be computed. + this.tickSpacing = 30; + this.numberMinorTicks = null; + // prop: hubRadius + // Radius of the hub at the bottom center of gauge which the needle attaches to. + // Auto computed by default + this.hubRadius = null; + // prop: tickPadding + // padding of the tick marks to the outer ring and the tick labels to marks. + // Auto computed by default. + this.tickPadding = null; + // prop: needleThickness + // Maximum thickness the needle. Auto computed by default. + this.needleThickness = null; + // prop: needlePad + // Padding between needle and inner edge of the ring when the needle is at the min or max gauge value. + this.needlePad = 6; + // prop: pegNeedle + // True will stop needle just below/above the min/max values if data is below/above min/max, + // as if the meter is "pegged". + this.pegNeedle = true; + this._type = 'meterGauge'; + + $.extend(true, this, options); + this.type = null; + this.numberTicks = null; + this.tickInterval = null; + // span, the sweep (in degrees) from min to max. This gauge is + // a semi-circle. + this.span = 180; + // get rid of this nonsense + // this.innerSpan = this.span; + if (this.type == 'circular') { + this.semiCircular = false; + } + else if (this.type != 'circular') { + this.semiCircular = true; + } + else { + this.semiCircular = (this.span <= 180) ? true : false; + } + this._tickPoints = []; + // reference to label element. + this._labelElem = null; + + // start the gauge at the beginning of the span + this.startAngle = (90 + (360 - this.span)/2) * Math.PI/180; + this.endAngle = (90 - (360 - this.span)/2) * Math.PI/180; + + this.setmin = !!(this.min == null); + this.setmax = !!(this.max == null); + + // if given intervals and is an array of values, create labels and colors. + if (this.intervals.length) { + if (this.intervals[0].length == null || this.intervals.length == 1) { + for (var i=0; i<this.intervals.length; i++) { + this.intervals[i] = [this.intervals[i], this.intervals[i], this.intervalColors[i]]; + } + } + else if (this.intervals[0].length == 2) { + for (i=0; i<this.intervals.length; i++) { + this.intervals[i] = [this.intervals[i][0], this.intervals[i][1], this.intervalColors[i]]; + } + } + } + + // compute min, max and ticks if not supplied: + if (this.ticks.length) { + if (this.ticks[0].length == null || this.ticks[0].length == 1) { + for (var i=0; i<this.ticks.length; i++) { + this.ticks[i] = [this.ticks[i], this.ticks[i]]; + } + } + this.min = (this.min == null) ? this.ticks[0][0] : this.min; + this.max = (this.max == null) ? this.ticks[this.ticks.length-1][0] : this.max; + this.setmin = false; + this.setmax = false; + this.numberTicks = this.ticks.length; + this.tickInterval = this.ticks[1][0] - this.ticks[0][0]; + this.tickFactor = Math.floor(parseFloat((Math.log(this.tickInterval)/Math.log(10)).toFixed(11))); + // use the first interal to calculate minor ticks; + this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor); + if (!this.numberMinorTicks) { + this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1); + } + if (!this.numberMinorTicks) { + this.numberMinorTicks = 1; + } + } + + else if (this.intervals.length) { + this.min = (this.min == null) ? 0 : this.min; + this.setmin = false; + if (this.max == null) { + if (this.intervals[this.intervals.length-1][0] >= this.data[0][1]) { + this.max = this.intervals[this.intervals.length-1][0]; + this.setmax = false; + } + } + else { + this.setmax = false; + } + } + + else { + // no ticks and no intervals supplied, put needle in middle + this.min = (this.min == null) ? 0 : this.min; + this.setmin = false; + if (this.max == null) { + this.max = this.data[0][1] * 1.25; + this.setmax = true; + } + else { + this.setmax = false; + } + } + }; + + $.jqplot.MeterGaugeRenderer.prototype.setGridData = function(plot) { + // set gridData property. This will hold angle in radians of each data point. + var stack = []; + var td = []; + var sa = this.startAngle; + for (var i=0; i<this.data.length; i++){ + stack.push(this.data[i][1]); + td.push([this.data[i][0]]); + if (i>0) { + stack[i] += stack[i-1]; + } + } + var fact = Math.PI*2/stack[stack.length - 1]; + + for (var i=0; i<stack.length; i++) { + td[i][1] = stack[i] * fact; + } + this.gridData = td; + }; + + $.jqplot.MeterGaugeRenderer.prototype.makeGridData = function(data, plot) { + var stack = []; + var td = []; + var sa = this.startAngle; + for (var i=0; i<data.length; i++){ + stack.push(data[i][1]); + td.push([data[i][0]]); + if (i>0) { + stack[i] += stack[i-1]; + } + } + var fact = Math.PI*2/stack[stack.length - 1]; + + for (var i=0; i<stack.length; i++) { + td[i][1] = stack[i] * fact; + } + return td; + }; + + + function getnmt(pos, interval, fact) { + var temp; + for (var i=pos.length-1; i>=0; i--) { + temp = interval/(pos[i] * Math.pow(10, fact)); + if (temp == 4 || temp == 5) { + return temp - 1; + } + } + return null; + } + + // called with scope of series + $.jqplot.MeterGaugeRenderer.prototype.draw = function (ctx, gd, options) { + var i; + var opts = (options != undefined) ? options : {}; + // offset and direction of offset due to legend placement + var offx = 0; + var offy = 0; + var trans = 1; + if (options.legendInfo && options.legendInfo.placement == 'inside') { + var li = options.legendInfo; + switch (li.location) { + case 'nw': + offx = li.width + li.xoffset; + break; + case 'w': + offx = li.width + li.xoffset; + break; + case 'sw': + offx = li.width + li.xoffset; + break; + case 'ne': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'e': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'se': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'n': + offy = li.height + li.yoffset; + break; + case 's': + offy = li.height + li.yoffset; + trans = -1; + break; + default: + break; + } + } + + + + // pre-draw so can get its dimensions. + if (this.label) { + this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>'); + this.canvas._elem.after(this._labelElem); + } + + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var cw = ctx.canvas.width; + var ch = ctx.canvas.height; + if (this.padding == null) { + this.padding = Math.round(Math.min(cw, ch)/30); + } + var w = cw - offx - 2 * this.padding; + var h = ch - offy - 2 * this.padding; + if (this.labelPosition == 'bottom' && this.label) { + h -= this._labelElem.outerHeight(true); + } + var mindim = Math.min(w,h); + var d = mindim; + + if (!this.diameter) { + if (this.semiCircular) { + if ( w >= 2*h) { + if (!this.ringWidth) { + this.ringWidth = 2*h/35; + } + this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8); + this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad; + this.diameter = 2 * (h - 2*this.innerPad); + } + else { + if (!this.ringWidth) { + this.ringWidth = w/35; + } + this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8); + this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad; + this.diameter = w - 2*this.innerPad - this.ringWidth - this.padding; + } + // center taking into account legend and over draw for gauge bottom below hub. + // this will be center of hub. + this._center = [(cw - trans * offx)/2 + trans * offx, (ch + trans*offy - this.padding - this.ringWidth - this.innerPad)]; + } + else { + if (!this.ringWidth) { + this.ringWidth = d/35; + } + this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8); + this.innerPad = 0; + this.diameter = d - this.ringWidth; + // center in middle of canvas taking into account legend. + // will be center of hub. + this._center = [(cw-trans*offx)/2 + trans * offx, (ch-trans*offy)/2 + trans * offy]; + } + if (this._labelElem && this.labelPosition == 'bottom') { + this._center[1] -= this._labelElem.outerHeight(true); + } + + } + + this._radius = this.diameter/2; + + this.tickSpacing = 6000/this.diameter; + + if (!this.hubRadius) { + this.hubRadius = this.diameter/18; + } + + this.shadowOffset = 0.5 + this.ringWidth/9; + this.shadowWidth = this.ringWidth*1; + + this.tickPadding = 3 + Math.pow(this.diameter/20, 0.7); + this.tickOuterRadius = this._radius - this.ringWidth/2 - this.tickPadding; + this.tickLength = (this.showTicks) ? this._radius/13 : 0; + + if (this.ticks.length == 0) { + // no ticks, lets make some. + var max = this.max, + min = this.min, + setmax = this.setmax, + setmin = this.setmin, + ti = (max - min) * this.tickSpacing / this.span; + var tf = Math.floor(parseFloat((Math.log(ti)/Math.log(10)).toFixed(11))); + var tp = (ti/Math.pow(10, tf)); + (tp > 2 && tp <= 2.5) ? tp = 2.5 : tp = Math.ceil(tp); + var t = this.tickPositions; + var tpindex, nt; + + for (i=0; i<t.length; i++) { + if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) { + ti = t[i]*Math.pow(10, tf); + tpindex = i; + } + } + + for (i=0; i<t.length; i++) { + if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) { + ti = t[i]*Math.pow(10, tf); + nt = Math.ceil((max - min) / ti); + } + } + + // both max and min are free + if (setmax && setmin) { + var tmin = (min > 0) ? min - min % ti : min - min % ti - ti; + if (!this.forceZero) { + var diff = Math.min(min - tmin, 0.8*ti); + var ntp = Math.floor(diff/t[tpindex]); + if (ntp > 1) { + tmin = tmin + t[tpindex] * (ntp-1); + if (parseInt(tmin, 10) != tmin && parseInt(tmin-t[tpindex], 10) == tmin-t[tpindex]) { + tmin = tmin - t[tpindex]; + } + } + } + if (min == tmin) { + min -= ti; + } + else { + // tmin should always be lower than dataMin + if (min - tmin > 0.23*ti) { + min = tmin; + } + else { + min = tmin -ti; + nt += 1; + } + } + nt += 1; + var tmax = min + (nt - 1) * ti; + if (max >= tmax) { + tmax += ti; + nt += 1; + } + // now tmax should always be mroe than dataMax + if (tmax - max < 0.23*ti) { + tmax += ti; + nt += 1; + } + this.max = max = tmax; + this.min = min; + + this.tickInterval = ti; + this.numberTicks = nt; + var it; + for (i=0; i<nt; i++) { + it = parseFloat((min+i*ti).toFixed(11)); + this.ticks.push([it, it]); + } + this.max = this.ticks[nt-1][1]; + + this.tickFactor = tf; + // determine number of minor ticks + + this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor); + + if (!this.numberMinorTicks) { + this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1); + } + } + // max is free, min is fixed + else if (setmax) { + var tmax = min + (nt - 1) * ti; + if (max >= tmax) { + max = tmax + ti; + nt += 1; + } + else { + max = tmax; + } + + this.tickInterval = this.tickInterval || ti; + this.numberTicks = this.numberTicks || nt; + var it; + for (i=0; i<this.numberTicks; i++) { + it = parseFloat((min+i*this.tickInterval).toFixed(11)); + this.ticks.push([it, it]); + } + this.max = this.ticks[this.numberTicks-1][1]; + + this.tickFactor = tf; + // determine number of minor ticks + this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor); + + if (!this.numberMinorTicks) { + this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1); + } + } + + // not setting max or min + if (!setmax && !setmin) { + var range = this.max - this.min; + tf = Math.floor(parseFloat((Math.log(range)/Math.log(10)).toFixed(11))) - 1; + var nticks = [5,6,4,7,3,8,9,10,2], res, numticks, nonSigDigits=0, sigRange; + // check to see how many zeros are at the end of the range + if (range > 1) { + var rstr = String(range); + if (rstr.search(/\./) == -1) { + var pos = rstr.search(/0+$/); + nonSigDigits = (pos > 0) ? rstr.length - pos - 1 : 0; + } + } + sigRange = range/Math.pow(10, nonSigDigits); + for (i=0; i<nticks.length; i++) { + res = sigRange/(nticks[i]-1); + if (res == parseInt(res, 10)) { + this.numberTicks = nticks[i]; + this.tickInterval = range/(this.numberTicks-1); + this.tickFactor = tf+1; + break; + } + } + var it; + for (i=0; i<this.numberTicks; i++) { + it = parseFloat((this.min+i*this.tickInterval).toFixed(11)); + this.ticks.push([it, it]); + } + // determine number of minor ticks + this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor); + + if (!this.numberMinorTicks) { + this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1); + } + + if (!this.numberMinorTicks) { + this.numberMinorTicks = 1; + var nums = [4, 5, 3, 6, 2]; + for (i=0; i<5; i++) { + var temp = this.tickInterval/nums[i]; + if (temp == parseInt(temp, 10)) { + this.numberMinorTicks = nums[i]-1; + break; + } + } + } + } + } + + + var r = this._radius, + sa = this.startAngle, + ea = this.endAngle, + pi = Math.PI, + hpi = Math.PI/2; + + if (this.semiCircular) { + var overAngle = Math.atan(this.innerPad/r), + outersa = this.outerStartAngle = sa - overAngle, + outerea = this.outerEndAngle = ea + overAngle, + hubsa = this.hubStartAngle = sa - Math.atan(this.innerPad/this.hubRadius*2), + hubea = this.hubEndAngle = ea + Math.atan(this.innerPad/this.hubRadius*2); + + ctx.save(); + + ctx.translate(this._center[0], this._center[1]); + ctx.lineJoin = "round"; + ctx.lineCap = "round"; + + // draw the innerbackground + ctx.save(); + ctx.beginPath(); + ctx.fillStyle = this.background; + ctx.arc(0, 0, r, outersa, outerea, false); + ctx.closePath(); + ctx.fill(); + ctx.restore(); + + // draw the shadow + // the outer ring. + var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; + ctx.save(); + for (var i=0; i<this.shadowDepth; i++) { + ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); + ctx.beginPath(); + ctx.strokeStyle = shadowColor; + ctx.lineWidth = this.shadowWidth; + ctx.arc(0 ,0, r, outersa, outerea, false); + ctx.closePath(); + ctx.stroke(); + } + ctx.restore(); + + // the inner hub. + ctx.save(); + var tempd = parseInt((this.shadowDepth+1)/2, 10); + for (var i=0; i<tempd; i++) { + ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); + ctx.beginPath(); + ctx.fillStyle = shadowColor; + ctx.arc(0 ,0, this.hubRadius, hubsa, hubea, false); + ctx.closePath(); + ctx.fill(); + } + ctx.restore(); + + // draw the outer ring. + ctx.save(); + ctx.beginPath(); + ctx.strokeStyle = this.ringColor; + ctx.lineWidth = this.ringWidth; + ctx.arc(0 ,0, r, outersa, outerea, false); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); + + // draw the hub + + ctx.save(); + ctx.beginPath(); + ctx.fillStyle = this.ringColor; + ctx.arc(0 ,0, this.hubRadius,hubsa, hubea, false); + ctx.closePath(); + ctx.fill(); + ctx.restore(); + + // draw the ticks + if (this.showTicks) { + ctx.save(); + var orad = this.tickOuterRadius, + tl = this.tickLength, + mtl = tl/2, + nmt = this.numberMinorTicks, + ts = this.span * Math.PI / 180 / (this.ticks.length-1), + mts = ts/(nmt + 1); + + for (i = 0; i<this.ticks.length; i++) { + ctx.beginPath(); + ctx.lineWidth = 1.5 + this.diameter/360; + ctx.strokeStyle = this.ringColor; + var wps = ts*i+sa; + ctx.moveTo(-orad * Math.cos(ts*i+sa), orad * Math.sin(ts*i+sa)); + ctx.lineTo(-(orad-tl) * Math.cos(ts*i+sa), (orad - tl) * Math.sin(ts*i+sa)); + this._tickPoints.push([(orad-tl) * Math.cos(ts*i+sa) + this._center[0] + this.canvas._offsets.left, (orad - tl) * Math.sin(ts*i+sa) + this._center[1] + this.canvas._offsets.top, ts*i+sa]); + ctx.stroke(); + ctx.lineWidth = 1.0 + this.diameter/440; + if (i<this.ticks.length-1) { + for (var j=1; j<=nmt; j++) { + ctx.beginPath(); + ctx.moveTo(-orad * Math.cos(ts*i+mts*j+sa), orad * Math.sin(ts*i+mts*j+sa)); + ctx.lineTo(-(orad-mtl) * Math.cos(ts*i+mts*j+sa), (orad-mtl) * Math.sin(ts*i+mts*j+sa)); + ctx.stroke(); + } + } + } + ctx.restore(); + } + + // draw the tick labels + if (this.showTickLabels) { + var elem, l, t, ew, eh, dim, maxdim=0; + var tp = this.tickPadding * (1 - 1/(this.diameter/80+1)); + for (i=0; i<this.ticks.length; i++) { + elem = $('<div class="jqplot-meterGauge-tick" style="position:absolute;">'+this.ticks[i][1]+'</div>'); + this.canvas._elem.after(elem); + ew = elem.outerWidth(true); + eh = elem.outerHeight(true); + l = this._tickPoints[i][0] - ew * (this._tickPoints[i][2]-Math.PI)/Math.PI - tp * Math.cos(this._tickPoints[i][2]); + t = this._tickPoints[i][1] - eh/2 + eh/2 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) + tp/3 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) ; + // t = this._tickPoints[i][1] - eh/2 - eh/2 * Math.sin(this._tickPoints[i][2]) - tp/2 * Math.sin(this._tickPoints[i][2]); + elem.css({left:l, top:t, color: this.tickColor}); + dim = ew*Math.cos(this._tickPoints[i][2]) + eh*Math.sin(Math.PI/2+this._tickPoints[i][2]/2); + maxdim = (dim > maxdim) ? dim : maxdim; + } + } + + // draw the gauge label + if (this.label && this.labelPosition == 'inside') { + var l = this._center[0] + this.canvas._offsets.left; + var tp = this.tickPadding * (1 - 1/(this.diameter/80+1)); + var t = 0.5*(this._center[1] + this.canvas._offsets.top - this.hubRadius) + 0.5*(this._center[1] + this.canvas._offsets.top - this.tickOuterRadius + this.tickLength + tp) + this.labelHeightAdjust; + // this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>'); + // this.canvas._elem.after(this._labelElem); + l -= this._labelElem.outerWidth(true)/2; + t -= this._labelElem.outerHeight(true)/2; + this._labelElem.css({left:l, top:t}); + } + + else if (this.label && this.labelPosition == 'bottom') { + var l = this._center[0] + this.canvas._offsets.left - this._labelElem.outerWidth(true)/2; + var t = this._center[1] + this.canvas._offsets.top + this.innerPad + this.ringWidth + this.padding + this.labelHeightAdjust; + this._labelElem.css({left:l, top:t}); + + } + + // draw the intervals + + ctx.save(); + var inner = this.intervalInnerRadius || this.hubRadius * 1.5; + if (this.intervalOuterRadius == null) { + if (this.showTickLabels) { + var outer = (this.tickOuterRadius - this.tickLength - this.tickPadding - this.diameter/8); + } + else { + var outer = (this.tickOuterRadius - this.tickLength - this.diameter/16); + } + } + else { + var outer = this.intervalOuterRadius; + } + var range = this.max - this.min; + var intrange = this.intervals[this.intervals.length-1] - this.min; + var start, end, span = this.span*Math.PI/180; + for (i=0; i<this.intervals.length; i++) { + start = (i == 0) ? sa : sa + (this.intervals[i-1][0] - this.min)*span/range; + if (start < 0) { + start = 0; + } + end = sa + (this.intervals[i][0] - this.min)*span/range; + if (end < 0) { + end = 0; + } + ctx.beginPath(); + ctx.fillStyle = this.intervals[i][2]; + ctx.arc(0, 0, inner, start, end, false); + ctx.lineTo(outer*Math.cos(end), outer*Math.sin(end)); + ctx.arc(0, 0, outer, end, start, true); + ctx.lineTo(inner*Math.cos(start), inner*Math.sin(start)); + ctx.closePath(); + ctx.fill(); + } + ctx.restore(); + + // draw the needle + var datapoint = this.data[0][1]; + var dataspan = this.max - this.min; + if (this.pegNeedle) { + if (this.data[0][1] > this.max + dataspan*3/this.span) { + datapoint = this.max + dataspan*3/this.span; + } + if (this.data[0][1] < this.min - dataspan*3/this.span) { + datapoint = this.min - dataspan*3/this.span; + } + } + var dataang = (datapoint - this.min)/dataspan * this.span * Math.PI/180 + this.startAngle; + + + ctx.save(); + ctx.beginPath(); + ctx.fillStyle = this.ringColor; + ctx.strokeStyle = this.ringColor; + this.needleLength = (this.tickOuterRadius - this.tickLength) * 0.85; + this.needleThickness = (this.needleThickness < 2) ? 2 : this.needleThickness; + var endwidth = this.needleThickness * 0.4; + + + var dl = this.needleLength/10; + var dt = (this.needleThickness - endwidth)/10; + var templ; + for (var i=0; i<10; i++) { + templ = this.needleThickness - i*dt; + ctx.moveTo(dl*i*Math.cos(dataang), dl*i*Math.sin(dataang)); + ctx.lineWidth = templ; + ctx.lineTo(dl*(i+1)*Math.cos(dataang), dl*(i+1)*Math.sin(dataang)); + ctx.stroke(); + } + + ctx.restore(); + } + else { + this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy]; + } + }; + + $.jqplot.MeterGaugeAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + }; + + $.jqplot.MeterGaugeAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.MeterGaugeAxisRenderer.prototype.constructor = $.jqplot.MeterGaugeAxisRenderer; + + + // There are no traditional axes on a gauge chart. We just need to provide + // dummy objects with properties so the plot will render. + // called with scope of axis object. + $.jqplot.MeterGaugeAxisRenderer.prototype.init = function(options){ + // + this.tickRenderer = $.jqplot.MeterGaugeTickRenderer; + $.extend(true, this, options); + // I don't think I'm going to need _dataBounds here. + // have to go Axis scaling in a way to fit chart onto plot area + // and provide u2p and p2u functionality for mouse cursor, etc. + // for convienence set _dataBounds to 0 and 100 and + // set min/max to 0 and 100. + this._dataBounds = {min:0, max:100}; + this.min = 0; + this.max = 100; + this.showTicks = false; + this.ticks = []; + this.showMark = false; + this.show = false; + }; + + $.jqplot.MeterGaugeLegendRenderer = function(){ + $.jqplot.TableLegendRenderer.call(this); + }; + + $.jqplot.MeterGaugeLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); + $.jqplot.MeterGaugeLegendRenderer.prototype.constructor = $.jqplot.MeterGaugeLegendRenderer; + + /** + * Class: $.jqplot.MeterGaugeLegendRenderer + *Meter gauges don't typically have a legend, this overrides the default legend renderer. + */ + $.jqplot.MeterGaugeLegendRenderer.prototype.init = function(options) { + // Maximum number of rows in the legend. 0 or null for unlimited. + this.numberRows = null; + // Maximum number of columns in the legend. 0 or null for unlimited. + this.numberColumns = null; + $.extend(true, this, options); + }; + + // called with context of legend + $.jqplot.MeterGaugeLegendRenderer.prototype.draw = function() { + if (this.show) { + var series = this._series; + var ss = 'position:absolute;'; + ss += (this.background) ? 'background:'+this.background+';' : ''; + ss += (this.border) ? 'border:'+this.border+';' : ''; + ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; + ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; + ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; + ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; + ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; + ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; + ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; + this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); + // MeterGauge charts legends don't go by number of series, but by number of data points + // in the series. Refactor things here for that. + + var pad = false, + reverse = false, + nr, nc; + var s = series[0]; + + if (s.show) { + var pd = s.data; + if (this.numberRows) { + nr = this.numberRows; + if (!this.numberColumns){ + nc = Math.ceil(pd.length/nr); + } + else{ + nc = this.numberColumns; + } + } + else if (this.numberColumns) { + nc = this.numberColumns; + nr = Math.ceil(pd.length/this.numberColumns); + } + else { + nr = pd.length; + nc = 1; + } + + var i, j, tr, td1, td2, lt, rs, color; + var idx = 0; + + for (i=0; i<nr; i++) { + if (reverse){ + tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); + } + else{ + tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); + } + for (j=0; j<nc; j++) { + if (idx < pd.length){ + // debugger + lt = this.labels[idx] || pd[idx][0].toString(); + color = s.color; + if (!reverse){ + if (i>0){ + pad = true; + } + else{ + pad = false; + } + } + else{ + if (i == nr -1){ + pad = false; + } + else{ + pad = true; + } + } + rs = (pad) ? this.rowSpacing : '0'; + + td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ + '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ + '</div></td>'); + td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); + if (this.escapeHtml){ + td2.text(lt); + } + else { + td2.html(lt); + } + if (reverse) { + td2.prependTo(tr); + td1.prependTo(tr); + } + else { + td1.appendTo(tr); + td2.appendTo(tr); + } + pad = true; + } + idx++; + } + } + } + } + return this._elem; + }; + + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + // debugger + options = options || {}; + options.axesDefaults = options.axesDefaults || {}; + options.legend = options.legend || {}; + options.seriesDefaults = options.seriesDefaults || {}; + options.grid = options.grid || {}; + + // only set these if there is a gauge series + var setopts = false; + if (options.seriesDefaults.renderer == $.jqplot.MeterGaugeRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer == $.jqplot.MeterGaugeRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.MeterGaugeAxisRenderer; + options.legend.renderer = $.jqplot.MeterGaugeLegendRenderer; + options.legend.preDraw = true; + options.grid.background = options.grid.background || 'white'; + options.grid.drawGridlines = false; + options.grid.borderWidth = (options.grid.borderWidth != null) ? options.grid.borderWidth : 0; + options.grid.shadow = (options.grid.shadow != null) ? options.grid.shadow : false; + } + } + + // called with scope of plot + function postParseOptions(options) { + // + } + + $.jqplot.preInitHooks.push(preInit); + $.jqplot.postParseOptionsHooks.push(postParseOptions); + + $.jqplot.MeterGaugeTickRenderer = function() { + $.jqplot.AxisTickRenderer.call(this); + }; + + $.jqplot.MeterGaugeTickRenderer.prototype = new $.jqplot.AxisTickRenderer(); + $.jqplot.MeterGaugeTickRenderer.prototype.constructor = $.jqplot.MeterGaugeTickRenderer; + +})(jQuery); + + diff --git a/plugin/jqplot/plugins/jqplot.meterGaugeRenderer.min.js b/plugin/jqplot/plugins/jqplot.meterGaugeRenderer.min.js new file mode 100644 index 000000000..e0f1081f0 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.meterGaugeRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(c){c.jqplot.MeterGaugeRenderer=function(){c.jqplot.LineRenderer.call(this)};c.jqplot.MeterGaugeRenderer.prototype=new c.jqplot.LineRenderer();c.jqplot.MeterGaugeRenderer.prototype.constructor=c.jqplot.MeterGaugeRenderer;c.jqplot.MeterGaugeRenderer.prototype.init=function(e){this.diameter=null;this.padding=null;this.shadowOffset=2;this.shadowAlpha=0.07;this.shadowDepth=4;this.background="#efefef";this.ringColor="#BBC6D0";this.needleColor="#C3D3E5";this.tickColor="#989898";this.ringWidth=null;this.min;this.max;this.ticks=[];this.showTicks=true;this.showTickLabels=true;this.label=null;this.labelHeightAdjust=0;this.labelPosition="inside";this.intervals=[];this.intervalColors=["#4bb2c5","#EAA228","#c5b47f","#579575","#839557","#958c12","#953579","#4b5de4","#d8b83f","#ff5800","#0085cc","#c747a3","#cddf54","#FBD178","#26B4E3","#bd70c7"];this.intervalInnerRadius=null;this.intervalOuterRadius=null;this.tickRenderer=c.jqplot.MeterGaugeTickRenderer;this.tickPositions=[1,2,2.5,5,10];this.tickSpacing=30;this.numberMinorTicks=null;this.hubRadius=null;this.tickPadding=null;this.needleThickness=null;this.needlePad=6;this.pegNeedle=true;this._type="meterGauge";c.extend(true,this,e);this.type=null;this.numberTicks=null;this.tickInterval=null;this.span=180;if(this.type=="circular"){this.semiCircular=false}else{if(this.type!="circular"){this.semiCircular=true}else{this.semiCircular=(this.span<=180)?true:false}}this._tickPoints=[];this._labelElem=null;this.startAngle=(90+(360-this.span)/2)*Math.PI/180;this.endAngle=(90-(360-this.span)/2)*Math.PI/180;this.setmin=!!(this.min==null);this.setmax=!!(this.max==null);if(this.intervals.length){if(this.intervals[0].length==null||this.intervals.length==1){for(var f=0;f<this.intervals.length;f++){this.intervals[f]=[this.intervals[f],this.intervals[f],this.intervalColors[f]]}}else{if(this.intervals[0].length==2){for(f=0;f<this.intervals.length;f++){this.intervals[f]=[this.intervals[f][0],this.intervals[f][1],this.intervalColors[f]]}}}}if(this.ticks.length){if(this.ticks[0].length==null||this.ticks[0].length==1){for(var f=0;f<this.ticks.length;f++){this.ticks[f]=[this.ticks[f],this.ticks[f]]}}this.min=(this.min==null)?this.ticks[0][0]:this.min;this.max=(this.max==null)?this.ticks[this.ticks.length-1][0]:this.max;this.setmin=false;this.setmax=false;this.numberTicks=this.ticks.length;this.tickInterval=this.ticks[1][0]-this.ticks[0][0];this.tickFactor=Math.floor(parseFloat((Math.log(this.tickInterval)/Math.log(10)).toFixed(11)));this.numberMinorTicks=b(this.tickPositions,this.tickInterval,this.tickFactor);if(!this.numberMinorTicks){this.numberMinorTicks=b(this.tickPositions,this.tickInterval,this.tickFactor-1)}if(!this.numberMinorTicks){this.numberMinorTicks=1}}else{if(this.intervals.length){this.min=(this.min==null)?0:this.min;this.setmin=false;if(this.max==null){if(this.intervals[this.intervals.length-1][0]>=this.data[0][1]){this.max=this.intervals[this.intervals.length-1][0];this.setmax=false}}else{this.setmax=false}}else{this.min=(this.min==null)?0:this.min;this.setmin=false;if(this.max==null){this.max=this.data[0][1]*1.25;this.setmax=true}else{this.setmax=false}}}};c.jqplot.MeterGaugeRenderer.prototype.setGridData=function(j){var f=[];var k=[];var e=this.startAngle;for(var h=0;h<this.data.length;h++){f.push(this.data[h][1]);k.push([this.data[h][0]]);if(h>0){f[h]+=f[h-1]}}var g=Math.PI*2/f[f.length-1];for(var h=0;h<f.length;h++){k[h][1]=f[h]*g}this.gridData=k};c.jqplot.MeterGaugeRenderer.prototype.makeGridData=function(j,k){var f=[];var l=[];var e=this.startAngle;for(var h=0;h<j.length;h++){f.push(j[h][1]);l.push([j[h][0]]);if(h>0){f[h]+=f[h-1]}}var g=Math.PI*2/f[f.length-1];for(var h=0;h<f.length;h++){l[h][1]=f[h]*g}return l};function b(j,f,g){var e;for(var h=j.length-1;h>=0;h--){e=f/(j[h]*Math.pow(10,g));if(e==4||e==5){return e-1}}return null}c.jqplot.MeterGaugeRenderer.prototype.draw=function(X,aC,ap){var aa;var aM=(ap!=undefined)?ap:{};var ai=0;var ah=0;var at=1;if(ap.legendInfo&&ap.legendInfo.placement=="inside"){var aI=ap.legendInfo;switch(aI.location){case"nw":ai=aI.width+aI.xoffset;break;case"w":ai=aI.width+aI.xoffset;break;case"sw":ai=aI.width+aI.xoffset;break;case"ne":ai=aI.width+aI.xoffset;at=-1;break;case"e":ai=aI.width+aI.xoffset;at=-1;break;case"se":ai=aI.width+aI.xoffset;at=-1;break;case"n":ah=aI.height+aI.yoffset;break;case"s":ah=aI.height+aI.yoffset;at=-1;break;default:break}}if(this.label){this._labelElem=c('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+"</div>");this.canvas._elem.after(this._labelElem)}var m=(aM.shadow!=undefined)?aM.shadow:this.shadow;var N=(aM.showLine!=undefined)?aM.showLine:this.showLine;var I=(aM.fill!=undefined)?aM.fill:this.fill;var K=X.canvas.width;var S=X.canvas.height;if(this.padding==null){this.padding=Math.round(Math.min(K,S)/30)}var Q=K-ai-2*this.padding;var ab=S-ah-2*this.padding;if(this.labelPosition=="bottom"&&this.label){ab-=this._labelElem.outerHeight(true)}var L=Math.min(Q,ab);var ad=L;if(!this.diameter){if(this.semiCircular){if(Q>=2*ab){if(!this.ringWidth){this.ringWidth=2*ab/35}this.needleThickness=this.needleThickness||2+Math.pow(this.ringWidth,0.8);this.innerPad=this.ringWidth/2+this.needleThickness/2+this.needlePad;this.diameter=2*(ab-2*this.innerPad)}else{if(!this.ringWidth){this.ringWidth=Q/35}this.needleThickness=this.needleThickness||2+Math.pow(this.ringWidth,0.8);this.innerPad=this.ringWidth/2+this.needleThickness/2+this.needlePad;this.diameter=Q-2*this.innerPad-this.ringWidth-this.padding}this._center=[(K-at*ai)/2+at*ai,(S+at*ah-this.padding-this.ringWidth-this.innerPad)]}else{if(!this.ringWidth){this.ringWidth=ad/35}this.needleThickness=this.needleThickness||2+Math.pow(this.ringWidth,0.8);this.innerPad=0;this.diameter=ad-this.ringWidth;this._center=[(K-at*ai)/2+at*ai,(S-at*ah)/2+at*ah]}if(this._labelElem&&this.labelPosition=="bottom"){this._center[1]-=this._labelElem.outerHeight(true)}}this._radius=this.diameter/2;this.tickSpacing=6000/this.diameter;if(!this.hubRadius){this.hubRadius=this.diameter/18}this.shadowOffset=0.5+this.ringWidth/9;this.shadowWidth=this.ringWidth*1;this.tickPadding=3+Math.pow(this.diameter/20,0.7);this.tickOuterRadius=this._radius-this.ringWidth/2-this.tickPadding;this.tickLength=(this.showTicks)?this._radius/13:0;if(this.ticks.length==0){var A=this.max,aL=this.min,q=this.setmax,aG=this.setmin,au=(A-aL)*this.tickSpacing/this.span;var aw=Math.floor(parseFloat((Math.log(au)/Math.log(10)).toFixed(11)));var an=(au/Math.pow(10,aw));(an>2&&an<=2.5)?an=2.5:an=Math.ceil(an);var T=this.tickPositions;var aA,ak;for(aa=0;aa<T.length;aa++){if(an==T[aa]||aa&&T[aa-1]<an&&an<T[aa]){au=T[aa]*Math.pow(10,aw);aA=aa}}for(aa=0;aa<T.length;aa++){if(an==T[aa]||aa&&T[aa-1]<an&&an<T[aa]){au=T[aa]*Math.pow(10,aw);ak=Math.ceil((A-aL)/au)}}if(q&&aG){var aP=(aL>0)?aL-aL%au:aL-aL%au-au;if(!this.forceZero){var D=Math.min(aL-aP,0.8*au);var o=Math.floor(D/T[aA]);if(o>1){aP=aP+T[aA]*(o-1);if(parseInt(aP,10)!=aP&&parseInt(aP-T[aA],10)==aP-T[aA]){aP=aP-T[aA]}}}if(aL==aP){aL-=au}else{if(aL-aP>0.23*au){aL=aP}else{aL=aP-au;ak+=1}}ak+=1;var E=aL+(ak-1)*au;if(A>=E){E+=au;ak+=1}if(E-A<0.23*au){E+=au;ak+=1}this.max=A=E;this.min=aL;this.tickInterval=au;this.numberTicks=ak;var O;for(aa=0;aa<ak;aa++){O=parseFloat((aL+aa*au).toFixed(11));this.ticks.push([O,O])}this.max=this.ticks[ak-1][1];this.tickFactor=aw;this.numberMinorTicks=b(this.tickPositions,this.tickInterval,this.tickFactor);if(!this.numberMinorTicks){this.numberMinorTicks=b(this.tickPositions,this.tickInterval,this.tickFactor-1)}}else{if(q){var E=aL+(ak-1)*au;if(A>=E){A=E+au;ak+=1}else{A=E}this.tickInterval=this.tickInterval||au;this.numberTicks=this.numberTicks||ak;var O;for(aa=0;aa<this.numberTicks;aa++){O=parseFloat((aL+aa*this.tickInterval).toFixed(11));this.ticks.push([O,O])}this.max=this.ticks[this.numberTicks-1][1];this.tickFactor=aw;this.numberMinorTicks=b(this.tickPositions,this.tickInterval,this.tickFactor);if(!this.numberMinorTicks){this.numberMinorTicks=b(this.tickPositions,this.tickInterval,this.tickFactor-1)}}}if(!q&&!aG){var P=this.max-this.min;aw=Math.floor(parseFloat((Math.log(P)/Math.log(10)).toFixed(11)))-1;var aN=[5,6,4,7,3,8,9,10,2],V,C,av=0,M;if(P>1){var aJ=String(P);if(aJ.search(/\./)==-1){var aF=aJ.search(/0+$/);av=(aF>0)?aJ.length-aF-1:0}}M=P/Math.pow(10,av);for(aa=0;aa<aN.length;aa++){V=M/(aN[aa]-1);if(V==parseInt(V,10)){this.numberTicks=aN[aa];this.tickInterval=P/(this.numberTicks-1);this.tickFactor=aw+1;break}}var O;for(aa=0;aa<this.numberTicks;aa++){O=parseFloat((this.min+aa*this.tickInterval).toFixed(11));this.ticks.push([O,O])}this.numberMinorTicks=b(this.tickPositions,this.tickInterval,this.tickFactor);if(!this.numberMinorTicks){this.numberMinorTicks=b(this.tickPositions,this.tickInterval,this.tickFactor-1)}if(!this.numberMinorTicks){this.numberMinorTicks=1;var aH=[4,5,3,6,2];for(aa=0;aa<5;aa++){var ao=this.tickInterval/aH[aa];if(ao==parseInt(ao,10)){this.numberMinorTicks=aH[aa]-1;break}}}}}var U=this._radius,aE=this.startAngle,k=this.endAngle,H=Math.PI,e=Math.PI/2;if(this.semiCircular){var z=Math.atan(this.innerPad/U),ac=this.outerStartAngle=aE-z,aB=this.outerEndAngle=k+z,B=this.hubStartAngle=aE-Math.atan(this.innerPad/this.hubRadius*2),af=this.hubEndAngle=k+Math.atan(this.innerPad/this.hubRadius*2);X.save();X.translate(this._center[0],this._center[1]);X.lineJoin="round";X.lineCap="round";X.save();X.beginPath();X.fillStyle=this.background;X.arc(0,0,U,ac,aB,false);X.closePath();X.fill();X.restore();var aj="rgba(0,0,0,"+this.shadowAlpha+")";X.save();for(var aa=0;aa<this.shadowDepth;aa++){X.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI),this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));X.beginPath();X.strokeStyle=aj;X.lineWidth=this.shadowWidth;X.arc(0,0,U,ac,aB,false);X.closePath();X.stroke()}X.restore();X.save();var az=parseInt((this.shadowDepth+1)/2,10);for(var aa=0;aa<az;aa++){X.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI),this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));X.beginPath();X.fillStyle=aj;X.arc(0,0,this.hubRadius,B,af,false);X.closePath();X.fill()}X.restore();X.save();X.beginPath();X.strokeStyle=this.ringColor;X.lineWidth=this.ringWidth;X.arc(0,0,U,ac,aB,false);X.closePath();X.stroke();X.restore();X.save();X.beginPath();X.fillStyle=this.ringColor;X.arc(0,0,this.hubRadius,B,af,false);X.closePath();X.fill();X.restore();if(this.showTicks){X.save();var f=this.tickOuterRadius,aq=this.tickLength,v=aq/2,F=this.numberMinorTicks,am=this.span*Math.PI/180/(this.ticks.length-1),p=am/(F+1);for(aa=0;aa<this.ticks.length;aa++){X.beginPath();X.lineWidth=1.5+this.diameter/360;X.strokeStyle=this.ringColor;var ae=am*aa+aE;X.moveTo(-f*Math.cos(am*aa+aE),f*Math.sin(am*aa+aE));X.lineTo(-(f-aq)*Math.cos(am*aa+aE),(f-aq)*Math.sin(am*aa+aE));this._tickPoints.push([(f-aq)*Math.cos(am*aa+aE)+this._center[0]+this.canvas._offsets.left,(f-aq)*Math.sin(am*aa+aE)+this._center[1]+this.canvas._offsets.top,am*aa+aE]);X.stroke();X.lineWidth=1+this.diameter/440;if(aa<this.ticks.length-1){for(var Y=1;Y<=F;Y++){X.beginPath();X.moveTo(-f*Math.cos(am*aa+p*Y+aE),f*Math.sin(am*aa+p*Y+aE));X.lineTo(-(f-v)*Math.cos(am*aa+p*Y+aE),(f-v)*Math.sin(am*aa+p*Y+aE));X.stroke()}}}X.restore()}if(this.showTickLabels){var J,W,T,aO,g,G,n=0;var an=this.tickPadding*(1-1/(this.diameter/80+1));for(aa=0;aa<this.ticks.length;aa++){J=c('<div class="jqplot-meterGauge-tick" style="position:absolute;">'+this.ticks[aa][1]+"</div>");this.canvas._elem.after(J);aO=J.outerWidth(true);g=J.outerHeight(true);W=this._tickPoints[aa][0]-aO*(this._tickPoints[aa][2]-Math.PI)/Math.PI-an*Math.cos(this._tickPoints[aa][2]);T=this._tickPoints[aa][1]-g/2+g/2*Math.pow(Math.abs((Math.sin(this._tickPoints[aa][2]))),0.5)+an/3*Math.pow(Math.abs((Math.sin(this._tickPoints[aa][2]))),0.5);J.css({left:W,top:T,color:this.tickColor});G=aO*Math.cos(this._tickPoints[aa][2])+g*Math.sin(Math.PI/2+this._tickPoints[aa][2]/2);n=(G>n)?G:n}}if(this.label&&this.labelPosition=="inside"){var W=this._center[0]+this.canvas._offsets.left;var an=this.tickPadding*(1-1/(this.diameter/80+1));var T=0.5*(this._center[1]+this.canvas._offsets.top-this.hubRadius)+0.5*(this._center[1]+this.canvas._offsets.top-this.tickOuterRadius+this.tickLength+an)+this.labelHeightAdjust;W-=this._labelElem.outerWidth(true)/2;T-=this._labelElem.outerHeight(true)/2;this._labelElem.css({left:W,top:T})}else{if(this.label&&this.labelPosition=="bottom"){var W=this._center[0]+this.canvas._offsets.left-this._labelElem.outerWidth(true)/2;var T=this._center[1]+this.canvas._offsets.top+this.innerPad+this.ringWidth+this.padding+this.labelHeightAdjust;this._labelElem.css({left:W,top:T})}}X.save();var ax=this.intervalInnerRadius||this.hubRadius*1.5;if(this.intervalOuterRadius==null){if(this.showTickLabels){var ag=(this.tickOuterRadius-this.tickLength-this.tickPadding-this.diameter/8)}else{var ag=(this.tickOuterRadius-this.tickLength-this.diameter/16)}}else{var ag=this.intervalOuterRadius}var P=this.max-this.min;var aD=this.intervals[this.intervals.length-1]-this.min;var y,Z,u=this.span*Math.PI/180;for(aa=0;aa<this.intervals.length;aa++){y=(aa==0)?aE:aE+(this.intervals[aa-1][0]-this.min)*u/P;if(y<0){y=0}Z=aE+(this.intervals[aa][0]-this.min)*u/P;if(Z<0){Z=0}X.beginPath();X.fillStyle=this.intervals[aa][2];X.arc(0,0,ax,y,Z,false);X.lineTo(ag*Math.cos(Z),ag*Math.sin(Z));X.arc(0,0,ag,Z,y,true);X.lineTo(ax*Math.cos(y),ax*Math.sin(y));X.closePath();X.fill()}X.restore();var ay=this.data[0][1];var R=this.max-this.min;if(this.pegNeedle){if(this.data[0][1]>this.max+R*3/this.span){ay=this.max+R*3/this.span}if(this.data[0][1]<this.min-R*3/this.span){ay=this.min-R*3/this.span}}var al=(ay-this.min)/R*this.span*Math.PI/180+this.startAngle;X.save();X.beginPath();X.fillStyle=this.ringColor;X.strokeStyle=this.ringColor;this.needleLength=(this.tickOuterRadius-this.tickLength)*0.85;this.needleThickness=(this.needleThickness<2)?2:this.needleThickness;var aK=this.needleThickness*0.4;var x=this.needleLength/10;var s=(this.needleThickness-aK)/10;var ar;for(var aa=0;aa<10;aa++){ar=this.needleThickness-aa*s;X.moveTo(x*aa*Math.cos(al),x*aa*Math.sin(al));X.lineWidth=ar;X.lineTo(x*(aa+1)*Math.cos(al),x*(aa+1)*Math.sin(al));X.stroke()}X.restore()}else{this._center=[(K-at*ai)/2+at*ai,(S-at*ah)/2+at*ah]}};c.jqplot.MeterGaugeAxisRenderer=function(){c.jqplot.LinearAxisRenderer.call(this)};c.jqplot.MeterGaugeAxisRenderer.prototype=new c.jqplot.LinearAxisRenderer();c.jqplot.MeterGaugeAxisRenderer.prototype.constructor=c.jqplot.MeterGaugeAxisRenderer;c.jqplot.MeterGaugeAxisRenderer.prototype.init=function(e){this.tickRenderer=c.jqplot.MeterGaugeTickRenderer;c.extend(true,this,e);this._dataBounds={min:0,max:100};this.min=0;this.max=100;this.showTicks=false;this.ticks=[];this.showMark=false;this.show=false};c.jqplot.MeterGaugeLegendRenderer=function(){c.jqplot.TableLegendRenderer.call(this)};c.jqplot.MeterGaugeLegendRenderer.prototype=new c.jqplot.TableLegendRenderer();c.jqplot.MeterGaugeLegendRenderer.prototype.constructor=c.jqplot.MeterGaugeLegendRenderer;c.jqplot.MeterGaugeLegendRenderer.prototype.init=function(e){this.numberRows=null;this.numberColumns=null;c.extend(true,this,e)};c.jqplot.MeterGaugeLegendRenderer.prototype.draw=function(){if(this.show){var p=this._series;var x="position:absolute;";x+=(this.background)?"background:"+this.background+";":"";x+=(this.border)?"border:"+this.border+";":"";x+=(this.fontSize)?"font-size:"+this.fontSize+";":"";x+=(this.fontFamily)?"font-family:"+this.fontFamily+";":"";x+=(this.textColor)?"color:"+this.textColor+";":"";x+=(this.marginTop!=null)?"margin-top:"+this.marginTop+";":"";x+=(this.marginBottom!=null)?"margin-bottom:"+this.marginBottom+";":"";x+=(this.marginLeft!=null)?"margin-left:"+this.marginLeft+";":"";x+=(this.marginRight!=null)?"margin-right:"+this.marginRight+";":"";this._elem=c('<table class="jqplot-table-legend" style="'+x+'"></table>');var f=false,q=false,u,o;var w=p[0];if(w.show){var t=w.data;if(this.numberRows){u=this.numberRows;if(!this.numberColumns){o=Math.ceil(t.length/u)}else{o=this.numberColumns}}else{if(this.numberColumns){o=this.numberColumns;u=Math.ceil(t.length/this.numberColumns)}else{u=t.length;o=1}}var n,m,r,g,e,l,k,h;var v=0;for(n=0;n<u;n++){if(q){r=c('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem)}else{r=c('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem)}for(m=0;m<o;m++){if(v<t.length){l=this.labels[v]||t[v][0].toString();h=w.color;if(!q){if(n>0){f=true}else{f=false}}else{if(n==u-1){f=false}else{f=true}}k=(f)?this.rowSpacing:"0";g=c('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+k+';"><div><div class="jqplot-table-legend-swatch" style="border-color:'+h+';"></div></div></td>');e=c('<td class="jqplot-table-legend" style="padding-top:'+k+';"></td>');if(this.escapeHtml){e.text(l)}else{e.html(l)}if(q){e.prependTo(r);g.prependTo(r)}else{g.appendTo(r);e.appendTo(r)}f=true}v++}}}}return this._elem};function a(j,h,f){f=f||{};f.axesDefaults=f.axesDefaults||{};f.legend=f.legend||{};f.seriesDefaults=f.seriesDefaults||{};f.grid=f.grid||{};var e=false;if(f.seriesDefaults.renderer==c.jqplot.MeterGaugeRenderer){e=true}else{if(f.series){for(var g=0;g<f.series.length;g++){if(f.series[g].renderer==c.jqplot.MeterGaugeRenderer){e=true}}}}if(e){f.axesDefaults.renderer=c.jqplot.MeterGaugeAxisRenderer;f.legend.renderer=c.jqplot.MeterGaugeLegendRenderer;f.legend.preDraw=true;f.grid.background=f.grid.background||"white";f.grid.drawGridlines=false;f.grid.borderWidth=(f.grid.borderWidth!=null)?f.grid.borderWidth:0;f.grid.shadow=(f.grid.shadow!=null)?f.grid.shadow:false}}function d(e){}c.jqplot.preInitHooks.push(a);c.jqplot.postParseOptionsHooks.push(d);c.jqplot.MeterGaugeTickRenderer=function(){c.jqplot.AxisTickRenderer.call(this)};c.jqplot.MeterGaugeTickRenderer.prototype=new c.jqplot.AxisTickRenderer();c.jqplot.MeterGaugeTickRenderer.prototype.constructor=c.jqplot.MeterGaugeTickRenderer})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.mobile.js b/plugin/jqplot/plugins/jqplot.mobile.js new file mode 100644 index 000000000..7fd60f19b --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.mobile.js @@ -0,0 +1,45 @@ +/** + * jqplot.jquerymobile plugin + * jQuery Mobile virtual event support. + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2011 Takashi Okamoto + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + */ +(function($) { + function postInit(target, data, options){ + this.bindCustomEvents = function() { + this.eventCanvas._elem.bind('vclick', {plot:this}, this.onClick); + this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick); + this.eventCanvas._elem.bind('taphold', {plot:this}, this.onDblClick); + this.eventCanvas._elem.bind('vmousedown', {plot:this}, this.onMouseDown); + this.eventCanvas._elem.bind('vmousemove', {plot:this}, this.onMouseMove); + this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter); + this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave); + if (this.captureRightClick) { + this.eventCanvas._elem.bind('vmouseup', {plot:this}, this.onRightClick); + this.eventCanvas._elem.get(0).oncontextmenu = function() { + return false; + }; + } + else { + this.eventCanvas._elem.bind('vmouseup', {plot:this}, this.onMouseUp); + } + }; + this.plugins.mobile = true; + } + $.jqplot.postInitHooks.push(postInit); +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.mobile.min.js b/plugin/jqplot/plugins/jqplot.mobile.min.js new file mode 100644 index 000000000..c9681739e --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.mobile.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(b){function a(e,d,c){this.bindCustomEvents=function(){this.eventCanvas._elem.bind("vclick",{plot:this},this.onClick);this.eventCanvas._elem.bind("dblclick",{plot:this},this.onDblClick);this.eventCanvas._elem.bind("taphold",{plot:this},this.onDblClick);this.eventCanvas._elem.bind("vmousedown",{plot:this},this.onMouseDown);this.eventCanvas._elem.bind("vmousemove",{plot:this},this.onMouseMove);this.eventCanvas._elem.bind("mouseenter",{plot:this},this.onMouseEnter);this.eventCanvas._elem.bind("mouseleave",{plot:this},this.onMouseLeave);if(this.captureRightClick){this.eventCanvas._elem.bind("vmouseup",{plot:this},this.onRightClick);this.eventCanvas._elem.get(0).oncontextmenu=function(){return false}}else{this.eventCanvas._elem.bind("vmouseup",{plot:this},this.onMouseUp)}};this.plugins.mobile=true}b.jqplot.postInitHooks.push(a)})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.ohlcRenderer.js b/plugin/jqplot/plugins/jqplot.ohlcRenderer.js new file mode 100644 index 000000000..3cffbfbb6 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.ohlcRenderer.js @@ -0,0 +1,373 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.OHLCRenderer + * jqPlot Plugin to draw Open Hi Low Close, Candlestick and Hi Low Close charts. + * + * To use this plugin, include the renderer js file in + * your source: + * + * > <script type="text/javascript" src="plugins/jqplot.ohlcRenderer.js"></script> + * + * You will most likely want to use a date axis renderer + * for the x axis also, so include the date axis render js file also: + * + * > <script type="text/javascript" src="plugins/jqplot.dateAxisRenderer.js"></script> + * + * Then you set the renderer in the series options on your plot: + * + * > series: [{renderer:$.jqplot.OHLCRenderer}] + * + * For OHLC and candlestick charts, data should be specified + * like so: + * + * > dat = [['07/06/2009',138.7,139.68,135.18,135.4], ['06/29/2009',143.46,144.66,139.79,140.02], ...] + * + * If the data array has only 4 values per point instead of 5, + * the renderer will create a Hi Low Close chart instead. In that case, + * data should be supplied like: + * + * > dat = [['07/06/2009',139.68,135.18,135.4], ['06/29/2009',144.66,139.79,140.02], ...] + * + * To generate a candlestick chart instead of an OHLC chart, + * set the "candlestick" option to true: + * + * > series: [{renderer:$.jqplot.OHLCRenderer, rendererOptions:{candleStick:true}}], + * + */ + $.jqplot.OHLCRenderer = function(){ + // subclass line renderer to make use of some of its methods. + $.jqplot.LineRenderer.call(this); + // prop: candleStick + // true to render chart as candleStick. + // Must have an open price, cannot be a hlc chart. + this.candleStick = false; + // prop: tickLength + // length of the line in pixels indicating open and close price. + // Default will auto calculate based on plot width and + // number of points displayed. + this.tickLength = 'auto'; + // prop: bodyWidth + // width of the candlestick body in pixels. Default will auto calculate + // based on plot width and number of candlesticks displayed. + this.bodyWidth = 'auto'; + // prop: openColor + // color of the open price tick mark. Default is series color. + this.openColor = null; + // prop: closeColor + // color of the close price tick mark. Default is series color. + this.closeColor = null; + // prop: wickColor + // color of the hi-lo line thorugh the candlestick body. + // Default is the series color. + this.wickColor = null; + // prop: fillUpBody + // true to render an "up" day (close price greater than open price) + // with a filled candlestick body. + this.fillUpBody = false; + // prop: fillDownBody + // true to render a "down" day (close price lower than open price) + // with a filled candlestick body. + this.fillDownBody = true; + // prop: upBodyColor + // Color of candlestick body of an "up" day. Default is series color. + this.upBodyColor = null; + // prop: downBodyColor + // Color of candlestick body on a "down" day. Default is series color. + this.downBodyColor = null; + // prop: hlc + // true if is a hi-low-close chart (no open price). + // This is determined automatically from the series data. + this.hlc = false; + // prop: lineWidth + // Width of the hi-low line and open/close ticks. + // Must be set in the rendererOptions for the series. + this.lineWidth = 1.5; + this._tickLength; + this._bodyWidth; + }; + + $.jqplot.OHLCRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.OHLCRenderer.prototype.constructor = $.jqplot.OHLCRenderer; + + // called with scope of series. + $.jqplot.OHLCRenderer.prototype.init = function(options) { + options = options || {}; + // lineWidth has to be set on the series, changes in renderer + // constructor have no effect. set the default here + // if no renderer option for lineWidth is specified. + this.lineWidth = options.lineWidth || 1.5; + $.jqplot.LineRenderer.prototype.init.call(this, options); + this._type = 'ohlc'; + // set the yaxis data bounds here to account for hi and low values + var db = this._yaxis._dataBounds; + var d = this._plotData; + // if data points have less than 5 values, force a hlc chart. + if (d[0].length < 5) { + this.renderer.hlc = true; + + for (var j=0; j<d.length; j++) { + if (d[j][2] < db.min || db.min == null) { + db.min = d[j][2]; + } + if (d[j][1] > db.max || db.max == null) { + db.max = d[j][1]; + } + } + } + else { + for (var j=0; j<d.length; j++) { + if (d[j][3] < db.min || db.min == null) { + db.min = d[j][3]; + } + if (d[j][2] > db.max || db.max == null) { + db.max = d[j][2]; + } + } + } + + }; + + // called within scope of series. + $.jqplot.OHLCRenderer.prototype.draw = function(ctx, gd, options) { + var d = this.data; + var xmin = this._xaxis.min; + var xmax = this._xaxis.max; + // index of last value below range of plot. + var xminidx = 0; + // index of first value above range of plot. + var xmaxidx = d.length; + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var i, prevColor, ops, b, h, w, a, points; + var o; + var r = this.renderer; + var opts = (options != undefined) ? options : {}; + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke; + r.bodyWidth = (opts.bodyWidth != undefined) ? opts.bodyWidth : r.bodyWidth; + r.tickLength = (opts.tickLength != undefined) ? opts.tickLength : r.tickLength; + ctx.save(); + if (this.show) { + var x, open, hi, low, close; + // need to get widths based on number of points shown, + // not on total number of points. Use the results + // to speed up drawing in next step. + for (var i=0; i<d.length; i++) { + if (d[i][0] < xmin) { + xminidx = i; + } + else if (d[i][0] < xmax) { + xmaxidx = i+1; + } + } + + var dwidth = this.gridData[xmaxidx-1][0] - this.gridData[xminidx][0]; + var nvisiblePoints = xmaxidx - xminidx; + try { + var dinterval = Math.abs(this._xaxis.series_u2p(parseInt(this._xaxis._intervalStats[0].sortedIntervals[0].interval, 10)) - this._xaxis.series_u2p(0)); + } + + catch (e) { + var dinterval = dwidth / nvisiblePoints; + } + + if (r.candleStick) { + if (typeof(r.bodyWidth) == 'number') { + r._bodyWidth = r.bodyWidth; + } + else { + r._bodyWidth = Math.min(20, dinterval/1.65); + } + } + else { + if (typeof(r.tickLength) == 'number') { + r._tickLength = r.tickLength; + } + else { + r._tickLength = Math.min(10, dinterval/3.5); + } + } + + for (var i=xminidx; i<xmaxidx; i++) { + x = xp(d[i][0]); + if (r.hlc) { + open = null; + hi = yp(d[i][1]); + low = yp(d[i][2]); + close = yp(d[i][3]); + } + else { + open = yp(d[i][1]); + hi = yp(d[i][2]); + low = yp(d[i][3]); + close = yp(d[i][4]); + } + o = {}; + if (r.candleStick && !r.hlc) { + w = r._bodyWidth; + a = x - w/2; + // draw candle + // determine if candle up or down + // up, remember grid coordinates increase downward + if (close < open) { + // draw wick + if (r.wickColor) { + o.color = r.wickColor; + } + else if (r.downBodyColor) { + o.color = r.upBodyColor; + } + ops = $.extend(true, {}, opts, o); + r.shapeRenderer.draw(ctx, [[x, hi], [x, close]], ops); + r.shapeRenderer.draw(ctx, [[x, open], [x, low]], ops); + o = {}; + b = close; + h = open - close; + // if color specified, use it + if (r.fillUpBody) { + o.fillRect = true; + } + else { + o.strokeRect = true; + w = w - this.lineWidth; + a = x - w/2; + } + if (r.upBodyColor) { + o.color = r.upBodyColor; + o.fillStyle = r.upBodyColor; + } + points = [a, b, w, h]; + } + // down + else if (close > open) { + // draw wick + if (r.wickColor) { + o.color = r.wickColor; + } + else if (r.downBodyColor) { + o.color = r.downBodyColor; + } + ops = $.extend(true, {}, opts, o); + r.shapeRenderer.draw(ctx, [[x, hi], [x, open]], ops); + r.shapeRenderer.draw(ctx, [[x, close], [x, low]], ops); + + o = {}; + + b = open; + h = close - open; + // if color specified, use it + if (r.fillDownBody) { + o.fillRect = true; + } + else { + o.strokeRect = true; + w = w - this.lineWidth; + a = x - w/2; + } + if (r.downBodyColor) { + o.color = r.downBodyColor; + o.fillStyle = r.downBodyColor; + } + points = [a, b, w, h]; + } + // even, open = close + else { + // draw wick + if (r.wickColor) { + o.color = r.wickColor; + } + ops = $.extend(true, {}, opts, o); + r.shapeRenderer.draw(ctx, [[x, hi], [x, low]], ops); + o = {}; + o.fillRect = false; + o.strokeRect = false; + a = [x - w/2, open]; + b = [x + w/2, close]; + w = null; + h = null; + points = [a, b]; + } + ops = $.extend(true, {}, opts, o); + r.shapeRenderer.draw(ctx, points, ops); + } + else { + prevColor = opts.color; + if (r.openColor) { + opts.color = r.openColor; + } + // draw open tick + if (!r.hlc) { + r.shapeRenderer.draw(ctx, [[x-r._tickLength, open], [x, open]], opts); + } + opts.color = prevColor; + // draw wick + if (r.wickColor) { + opts.color = r.wickColor; + } + r.shapeRenderer.draw(ctx, [[x, hi], [x, low]], opts); + opts.color = prevColor; + // draw close tick + if (r.closeColor) { + opts.color = r.closeColor; + } + r.shapeRenderer.draw(ctx, [[x, close], [x+r._tickLength, close]], opts); + opts.color = prevColor; + } + } + } + + ctx.restore(); + }; + + $.jqplot.OHLCRenderer.prototype.drawShadow = function(ctx, gd, options) { + // This is a no-op, shadows drawn with lines. + }; + + // called with scope of plot. + $.jqplot.OHLCRenderer.checkOptions = function(target, data, options) { + // provide some sensible highlighter options by default + // These aren't good for hlc, only for ohlc or candlestick + if (!options.highlighter) { + options.highlighter = { + showMarker:false, + tooltipAxes: 'y', + yvalues: 4, + formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>' + }; + } + }; + + //$.jqplot.preInitHooks.push($.jqplot.OHLCRenderer.checkOptions); + +})(jQuery); diff --git a/plugin/jqplot/plugins/jqplot.ohlcRenderer.min.js b/plugin/jqplot/plugins/jqplot.ohlcRenderer.min.js new file mode 100644 index 000000000..540bcf530 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.ohlcRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.OHLCRenderer=function(){a.jqplot.LineRenderer.call(this);this.candleStick=false;this.tickLength="auto";this.bodyWidth="auto";this.openColor=null;this.closeColor=null;this.wickColor=null;this.fillUpBody=false;this.fillDownBody=true;this.upBodyColor=null;this.downBodyColor=null;this.hlc=false;this.lineWidth=1.5;this._tickLength;this._bodyWidth};a.jqplot.OHLCRenderer.prototype=new a.jqplot.LineRenderer();a.jqplot.OHLCRenderer.prototype.constructor=a.jqplot.OHLCRenderer;a.jqplot.OHLCRenderer.prototype.init=function(e){e=e||{};this.lineWidth=e.lineWidth||1.5;a.jqplot.LineRenderer.prototype.init.call(this,e);this._type="ohlc";var b=this._yaxis._dataBounds;var f=this._plotData;if(f[0].length<5){this.renderer.hlc=true;for(var c=0;c<f.length;c++){if(f[c][2]<b.min||b.min==null){b.min=f[c][2]}if(f[c][1]>b.max||b.max==null){b.max=f[c][1]}}}else{for(var c=0;c<f.length;c++){if(f[c][3]<b.min||b.min==null){b.min=f[c][3]}if(f[c][2]>b.max||b.max==null){b.max=f[c][2]}}}};a.jqplot.OHLCRenderer.prototype.draw=function(A,N,j){var J=this.data;var v=this._xaxis.min;var z=this._xaxis.max;var l=0;var K=J.length;var p=this._xaxis.series_u2p;var G=this._yaxis.series_u2p;var D,E,f,M,F,n,O,C;var y;var u=this.renderer;var s=(j!=undefined)?j:{};var k=(s.shadow!=undefined)?s.shadow:this.shadow;var B=(s.fill!=undefined)?s.fill:this.fill;var c=(s.fillAndStroke!=undefined)?s.fillAndStroke:this.fillAndStroke;u.bodyWidth=(s.bodyWidth!=undefined)?s.bodyWidth:u.bodyWidth;u.tickLength=(s.tickLength!=undefined)?s.tickLength:u.tickLength;A.save();if(this.show){var m,q,g,Q,t;for(var D=0;D<J.length;D++){if(J[D][0]<v){l=D}else{if(J[D][0]<z){K=D+1}}}var I=this.gridData[K-1][0]-this.gridData[l][0];var L=K-l;try{var P=Math.abs(this._xaxis.series_u2p(parseInt(this._xaxis._intervalStats[0].sortedIntervals[0].interval,10))-this._xaxis.series_u2p(0))}catch(H){var P=I/L}if(u.candleStick){if(typeof(u.bodyWidth)=="number"){u._bodyWidth=u.bodyWidth}else{u._bodyWidth=Math.min(20,P/1.65)}}else{if(typeof(u.tickLength)=="number"){u._tickLength=u.tickLength}else{u._tickLength=Math.min(10,P/3.5)}}for(var D=l;D<K;D++){m=p(J[D][0]);if(u.hlc){q=null;g=G(J[D][1]);Q=G(J[D][2]);t=G(J[D][3])}else{q=G(J[D][1]);g=G(J[D][2]);Q=G(J[D][3]);t=G(J[D][4])}y={};if(u.candleStick&&!u.hlc){n=u._bodyWidth;O=m-n/2;if(t<q){if(u.wickColor){y.color=u.wickColor}else{if(u.downBodyColor){y.color=u.upBodyColor}}f=a.extend(true,{},s,y);u.shapeRenderer.draw(A,[[m,g],[m,t]],f);u.shapeRenderer.draw(A,[[m,q],[m,Q]],f);y={};M=t;F=q-t;if(u.fillUpBody){y.fillRect=true}else{y.strokeRect=true;n=n-this.lineWidth;O=m-n/2}if(u.upBodyColor){y.color=u.upBodyColor;y.fillStyle=u.upBodyColor}C=[O,M,n,F]}else{if(t>q){if(u.wickColor){y.color=u.wickColor}else{if(u.downBodyColor){y.color=u.downBodyColor}}f=a.extend(true,{},s,y);u.shapeRenderer.draw(A,[[m,g],[m,q]],f);u.shapeRenderer.draw(A,[[m,t],[m,Q]],f);y={};M=q;F=t-q;if(u.fillDownBody){y.fillRect=true}else{y.strokeRect=true;n=n-this.lineWidth;O=m-n/2}if(u.downBodyColor){y.color=u.downBodyColor;y.fillStyle=u.downBodyColor}C=[O,M,n,F]}else{if(u.wickColor){y.color=u.wickColor}f=a.extend(true,{},s,y);u.shapeRenderer.draw(A,[[m,g],[m,Q]],f);y={};y.fillRect=false;y.strokeRect=false;O=[m-n/2,q];M=[m+n/2,t];n=null;F=null;C=[O,M]}}f=a.extend(true,{},s,y);u.shapeRenderer.draw(A,C,f)}else{E=s.color;if(u.openColor){s.color=u.openColor}if(!u.hlc){u.shapeRenderer.draw(A,[[m-u._tickLength,q],[m,q]],s)}s.color=E;if(u.wickColor){s.color=u.wickColor}u.shapeRenderer.draw(A,[[m,g],[m,Q]],s);s.color=E;if(u.closeColor){s.color=u.closeColor}u.shapeRenderer.draw(A,[[m,t],[m+u._tickLength,t]],s);s.color=E}}}A.restore()};a.jqplot.OHLCRenderer.prototype.drawShadow=function(b,d,c){};a.jqplot.OHLCRenderer.checkOptions=function(d,c,b){if(!b.highlighter){b.highlighter={showMarker:false,tooltipAxes:"y",yvalues:4,formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>'}}}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pieRenderer.js b/plugin/jqplot/plugins/jqplot.pieRenderer.js new file mode 100644 index 000000000..1d508bd67 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pieRenderer.js @@ -0,0 +1,904 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + /** + * Class: $.jqplot.PieRenderer + * Plugin renderer to draw a pie chart. + * x values, if present, will be used as slice labels. + * y values give slice size. + * + * To use this renderer, you need to include the + * pie renderer plugin, for example: + * + * > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script> + * + * Properties described here are passed into the $.jqplot function + * as options on the series renderer. For example: + * + * > plot2 = $.jqplot('chart2', [s1, s2], { + * > seriesDefaults: { + * > renderer:$.jqplot.PieRenderer, + * > rendererOptions:{ + * > sliceMargin: 2, + * > startAngle: -90 + * > } + * > } + * > }); + * + * A pie plot will trigger events on the plot target + * according to user interaction. All events return the event object, + * the series index, the point (slice) index, and the point data for + * the appropriate slice. + * + * 'jqplotDataMouseOver' - triggered when user mouseing over a slice. + * 'jqplotDataHighlight' - triggered the first time user mouses over a slice, + * if highlighting is enabled. + * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of + * a highlighted slice. + * 'jqplotDataClick' - triggered when the user clicks on a slice. + * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if + * the "captureRightClick" option is set to true on the plot. + */ + $.jqplot.PieRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer; + + // called with scope of a series + $.jqplot.PieRenderer.prototype.init = function(options, plot) { + // Group: Properties + // + // prop: diameter + // Outer diameter of the pie, auto computed by default + this.diameter = null; + // prop: padding + // padding between the pie and plot edges, legend, etc. + this.padding = 20; + // prop: sliceMargin + // angular spacing between pie slices in degrees. + this.sliceMargin = 0; + // prop: fill + // true or false, whether to fil the slices. + this.fill = true; + // prop: shadowOffset + // offset of the shadow from the slice and offset of + // each succesive stroke of the shadow from the last. + this.shadowOffset = 2; + // prop: shadowAlpha + // transparency of the shadow (0 = transparent, 1 = opaque) + this.shadowAlpha = 0.07; + // prop: shadowDepth + // number of strokes to apply to the shadow, + // each stroke offset shadowOffset from the last. + this.shadowDepth = 5; + // prop: highlightMouseOver + // True to highlight slice when moused over. + // This must be false to enable highlightMouseDown to highlight when clicking on a slice. + this.highlightMouseOver = true; + // prop: highlightMouseDown + // True to highlight when a mouse button is pressed over a slice. + // This will be disabled if highlightMouseOver is true. + this.highlightMouseDown = false; + // prop: highlightColors + // an array of colors to use when highlighting a slice. + this.highlightColors = []; + // prop: dataLabels + // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices. + // Defaults to percentage of each pie slice. + this.dataLabels = 'percent'; + // prop: showDataLabels + // true to show data labels on slices. + this.showDataLabels = false; + // prop: dataLabelFormatString + // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage. + this.dataLabelFormatString = null; + // prop: dataLabelThreshold + // Threshhold in percentage (0-100) of pie area, below which no label will be displayed. + // This applies to all label types, not just to percentage labels. + this.dataLabelThreshold = 3; + // prop: dataLabelPositionFactor + // A Multiplier (0-1) of the pie radius which controls position of label on slice. + // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie. + this.dataLabelPositionFactor = 0.52; + // prop: dataLabelNudge + // Number of pixels to slide the label away from (+) or toward (-) the center of the pie. + this.dataLabelNudge = 2; + // prop: dataLabelCenterOn + // True to center the data label at its position. + // False to set the inside facing edge of the label at its position. + this.dataLabelCenterOn = true; + // prop: startAngle + // Angle to start drawing pie in degrees. + // According to orientation of canvas coordinate system: + // 0 = on the positive x axis + // -90 = on the positive y axis. + // 90 = on the negaive y axis. + // 180 or - 180 = on the negative x axis. + this.startAngle = 0; + this.tickRenderer = $.jqplot.PieTickRenderer; + // Used as check for conditions where pie shouldn't be drawn. + this._drawData = true; + this._type = 'pie'; + + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver + if (options.highlightMouseDown && options.highlightMouseOver == null) { + options.highlightMouseOver = false; + } + + $.extend(true, this, options); + + if (this.sliceMargin < 0) { + this.sliceMargin = 0; + } + + this._diameter = null; + this._radius = null; + // array of [start,end] angles arrays, one for each slice. In radians. + this._sliceAngles = []; + // index of the currenty highlighted point, if any + this._highlightedPoint = null; + + // set highlight colors if none provided + if (this.highlightColors.length == 0) { + for (var i=0; i<this.seriesColors.length; i++){ + var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); + var newrgb = [rgba[0], rgba[1], rgba[2]]; + var sum = newrgb[0] + newrgb[1] + newrgb[2]; + for (var j=0; j<3; j++) { + // when darkening, lowest color component can be is 60. + newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); + newrgb[j] = parseInt(newrgb[j], 10); + } + this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); + } + } + + this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors); + + plot.postParseOptionsHooks.addOnce(postParseOptions); + plot.postInitHooks.addOnce(postInit); + plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); + plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); + plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); + plot.eventListenerHooks.addOnce('jqplotClick', handleClick); + plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); + plot.postDrawHooks.addOnce(postPlotDraw); + }; + + $.jqplot.PieRenderer.prototype.setGridData = function(plot) { + // set gridData property. This will hold angle in radians of each data point. + var stack = []; + var td = []; + var sa = this.startAngle/180*Math.PI; + var tot = 0; + // don't know if we have any valid data yet, so set plot to not draw. + this._drawData = false; + for (var i=0; i<this.data.length; i++){ + if (this.data[i][1] != 0) { + // we have data, O.K. to draw. + this._drawData = true; + } + stack.push(this.data[i][1]); + td.push([this.data[i][0]]); + if (i>0) { + stack[i] += stack[i-1]; + } + tot += this.data[i][1]; + } + var fact = Math.PI*2/stack[stack.length - 1]; + + for (var i=0; i<stack.length; i++) { + td[i][1] = stack[i] * fact; + td[i][2] = this.data[i][1]/tot; + } + this.gridData = td; + }; + + $.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) { + var stack = []; + var td = []; + var tot = 0; + var sa = this.startAngle/180*Math.PI; + // don't know if we have any valid data yet, so set plot to not draw. + this._drawData = false; + for (var i=0; i<data.length; i++){ + if (this.data[i][1] != 0) { + // we have data, O.K. to draw. + this._drawData = true; + } + stack.push(data[i][1]); + td.push([data[i][0]]); + if (i>0) { + stack[i] += stack[i-1]; + } + tot += data[i][1]; + } + var fact = Math.PI*2/stack[stack.length - 1]; + + for (var i=0; i<stack.length; i++) { + td[i][1] = stack[i] * fact; + td[i][2] = data[i][1]/tot; + } + return td; + }; + + function calcRadiusAdjustment(ang) { + return Math.sin((ang - (ang-Math.PI) / 8 / Math.PI )/2.0); + } + + function calcRPrime(ang1, ang2, sliceMargin, fill, lineWidth) { + var rprime = 0; + var ang = ang2 - ang1; + var absang = Math.abs(ang); + var sm = sliceMargin; + if (fill == false) { + sm += lineWidth; + } + + if (sm > 0 && absang > 0.01 && absang < 6.282) { + rprime = parseFloat(sm) / 2.0 / calcRadiusAdjustment(ang); + } + + return rprime; + } + + $.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) { + if (this._drawData) { + var r = this._radius; + var fill = this.fill; + var lineWidth = this.lineWidth; + var sm = this.sliceMargin; + if (this.fill == false) { + sm += this.lineWidth; + } + ctx.save(); + ctx.translate(this._center[0], this._center[1]); + + var rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth); + + var transx = rprime * Math.cos((ang1 + ang2) / 2.0); + var transy = rprime * Math.sin((ang1 + ang2) / 2.0); + + if ((ang2 - ang1) <= Math.PI) { + r -= rprime; + } + else { + r += rprime; + } + + ctx.translate(transx, transy); + + if (isShadow) { + for (var i=0, l=this.shadowDepth; i<l; i++) { + ctx.save(); + ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); + doDraw(r); + } + for (var i=0, l=this.shadowDepth; i<l; i++) { + ctx.restore(); + } + } + + else { + doDraw(r); + } + ctx.restore(); + } + + function doDraw (rad) { + // Fix for IE and Chrome that can't seem to draw circles correctly. + // ang2 should always be <= 2 pi since that is the way the data is converted. + // 2Pi = 6.2831853, Pi = 3.1415927 + if (ang2 > 6.282 + this.startAngle) { + ang2 = 6.282 + this.startAngle; + if (ang1 > ang2) { + ang1 = 6.281 + this.startAngle; + } + } + // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids + // ugly line on unfilled pies. + if (ang1 >= ang2) { + return; + } + + ctx.beginPath(); + ctx.fillStyle = color; + ctx.strokeStyle = color; + ctx.lineWidth = lineWidth; + ctx.arc(0, 0, rad, ang1, ang2, false); + ctx.lineTo(0,0); + ctx.closePath(); + + if (fill) { + ctx.fill(); + } + else { + ctx.stroke(); + } + } + }; + + // called with scope of series + $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) { + var i; + var opts = (options != undefined) ? options : {}; + // offset and direction of offset due to legend placement + var offx = 0; + var offy = 0; + var trans = 1; + var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); + if (options.legendInfo && options.legendInfo.placement == 'insideGrid') { + var li = options.legendInfo; + switch (li.location) { + case 'nw': + offx = li.width + li.xoffset; + break; + case 'w': + offx = li.width + li.xoffset; + break; + case 'sw': + offx = li.width + li.xoffset; + break; + case 'ne': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'e': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'se': + offx = li.width + li.xoffset; + trans = -1; + break; + case 'n': + offy = li.height + li.yoffset; + break; + case 's': + offy = li.height + li.yoffset; + trans = -1; + break; + default: + break; + } + } + + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var cw = ctx.canvas.width; + var ch = ctx.canvas.height; + var w = cw - offx - 2 * this.padding; + var h = ch - offy - 2 * this.padding; + var mindim = Math.min(w,h); + var d = mindim; + + // Fixes issue #272. Thanks hugwijst! + // reset slice angles array. + this._sliceAngles = []; + + var sm = this.sliceMargin; + if (this.fill == false) { + sm += this.lineWidth; + } + + var rprime; + var maxrprime = 0; + + var ang, ang1, ang2, shadowColor; + var sa = this.startAngle / 180 * Math.PI; + + // have to pre-draw shadows, so loop throgh here and calculate some values also. + for (var i=0, l=gd.length; i<l; i++) { + ang1 = (i == 0) ? sa : gd[i-1][1] + sa; + ang2 = gd[i][1] + sa; + + this._sliceAngles.push([ang1, ang2]); + + rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth); + + if (Math.abs(ang2-ang1) > Math.PI) { + maxrprime = Math.max(rprime, maxrprime); + } + } + + if (this.diameter != null && this.diameter > 0) { + this._diameter = this.diameter - 2*maxrprime; + } + else { + this._diameter = d - 2*maxrprime; + } + + // Need to check for undersized pie. This can happen if + // plot area too small and legend is too big. + if (this._diameter < 6) { + $.jqplot.log('Diameter of pie too small, not rendering.'); + return; + } + + var r = this._radius = this._diameter/2; + + this._center = [(cw - trans * offx)/2 + trans * offx + maxrprime * Math.cos(sa), (ch - trans*offy)/2 + trans * offy + maxrprime * Math.sin(sa)]; + + if (this.shadow) { + for (var i=0, l=gd.length; i<l; i++) { + shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; + this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], shadowColor, true); + } + } + + for (var i=0; i<gd.length; i++) { + + this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], colorGenerator.next(), false); + + if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) { + var fstr, avgang = (this._sliceAngles[i][0] + this._sliceAngles[i][1])/2, label; + + if (this.dataLabels == 'label') { + fstr = this.dataLabelFormatString || '%s'; + label = $.jqplot.sprintf(fstr, gd[i][0]); + } + else if (this.dataLabels == 'value') { + fstr = this.dataLabelFormatString || '%d'; + label = $.jqplot.sprintf(fstr, this.data[i][1]); + } + else if (this.dataLabels == 'percent') { + fstr = this.dataLabelFormatString || '%d%%'; + label = $.jqplot.sprintf(fstr, gd[i][2]*100); + } + else if (this.dataLabels.constructor == Array) { + fstr = this.dataLabelFormatString || '%s'; + label = $.jqplot.sprintf(fstr, this.dataLabels[i]); + } + + var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge; + + var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left; + var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top; + + var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem); + if (this.dataLabelCenterOn) { + x -= labelelem.width()/2; + y -= labelelem.height()/2; + } + else { + x -= labelelem.width() * Math.sin(avgang/2); + y -= labelelem.height()/2; + } + x = Math.round(x); + y = Math.round(y); + labelelem.css({left: x, top: y}); + } + } + }; + + $.jqplot.PieAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + }; + + $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer; + + + // There are no traditional axes on a pie chart. We just need to provide + // dummy objects with properties so the plot will render. + // called with scope of axis object. + $.jqplot.PieAxisRenderer.prototype.init = function(options){ + // + this.tickRenderer = $.jqplot.PieTickRenderer; + $.extend(true, this, options); + // I don't think I'm going to need _dataBounds here. + // have to go Axis scaling in a way to fit chart onto plot area + // and provide u2p and p2u functionality for mouse cursor, etc. + // for convienence set _dataBounds to 0 and 100 and + // set min/max to 0 and 100. + this._dataBounds = {min:0, max:100}; + this.min = 0; + this.max = 100; + this.showTicks = false; + this.ticks = []; + this.showMark = false; + this.show = false; + }; + + + + + $.jqplot.PieLegendRenderer = function(){ + $.jqplot.TableLegendRenderer.call(this); + }; + + $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); + $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer; + + /** + * Class: $.jqplot.PieLegendRenderer + * Legend Renderer specific to pie plots. Set by default + * when user creates a pie plot. + */ + $.jqplot.PieLegendRenderer.prototype.init = function(options) { + // Group: Properties + // + // prop: numberRows + // Maximum number of rows in the legend. 0 or null for unlimited. + this.numberRows = null; + // prop: numberColumns + // Maximum number of columns in the legend. 0 or null for unlimited. + this.numberColumns = null; + $.extend(true, this, options); + }; + + // called with context of legend + $.jqplot.PieLegendRenderer.prototype.draw = function() { + var legend = this; + if (this.show) { + var series = this._series; + + + this._elem = $(document.createElement('table')); + this._elem.addClass('jqplot-table-legend'); + + var ss = {position:'absolute'}; + if (this.background) { + ss['background'] = this.background; + } + if (this.border) { + ss['border'] = this.border; + } + if (this.fontSize) { + ss['fontSize'] = this.fontSize; + } + if (this.fontFamily) { + ss['fontFamily'] = this.fontFamily; + } + if (this.textColor) { + ss['textColor'] = this.textColor; + } + if (this.marginTop != null) { + ss['marginTop'] = this.marginTop; + } + if (this.marginBottom != null) { + ss['marginBottom'] = this.marginBottom; + } + if (this.marginLeft != null) { + ss['marginLeft'] = this.marginLeft; + } + if (this.marginRight != null) { + ss['marginRight'] = this.marginRight; + } + + this._elem.css(ss); + + // Pie charts legends don't go by number of series, but by number of data points + // in the series. Refactor things here for that. + + var pad = false, + reverse = false, + nr, + nc; + var s = series[0]; + var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); + + if (s.show) { + var pd = s.data; + if (this.numberRows) { + nr = this.numberRows; + if (!this.numberColumns){ + nc = Math.ceil(pd.length/nr); + } + else{ + nc = this.numberColumns; + } + } + else if (this.numberColumns) { + nc = this.numberColumns; + nr = Math.ceil(pd.length/this.numberColumns); + } + else { + nr = pd.length; + nc = 1; + } + + var i, j; + var tr, td1, td2; + var lt, rs, color; + var idx = 0; + var div0, div1; + + for (i=0; i<nr; i++) { + tr = $(document.createElement('tr')); + tr.addClass('jqplot-table-legend'); + + if (reverse){ + tr.prependTo(this._elem); + } + + else{ + tr.appendTo(this._elem); + } + + for (j=0; j<nc; j++) { + if (idx < pd.length){ + lt = this.labels[idx] || pd[idx][0].toString(); + color = colorGenerator.next(); + if (!reverse){ + if (i>0){ + pad = true; + } + else{ + pad = false; + } + } + else{ + if (i == nr -1){ + pad = false; + } + else{ + pad = true; + } + } + rs = (pad) ? this.rowSpacing : '0'; + + + + td1 = $(document.createElement('td')); + td1.addClass('jqplot-table-legend jqplot-table-legend-swatch'); + td1.css({textAlign: 'center', paddingTop: rs}); + + div0 = $(document.createElement('div')); + div0.addClass('jqplot-table-legend-swatch-outline'); + div1 = $(document.createElement('div')); + div1.addClass('jqplot-table-legend-swatch'); + div1.css({backgroundColor: color, borderColor: color}); + td1.append(div0.append(div1)); + + td2 = $(document.createElement('td')); + td2.addClass('jqplot-table-legend jqplot-table-legend-label'); + td2.css('paddingTop', rs); + + if (this.escapeHtml){ + td2.text(lt); + } + else { + td2.html(lt); + } + if (reverse) { + td2.prependTo(tr); + td1.prependTo(tr); + } + else { + td1.appendTo(tr); + td2.appendTo(tr); + } + pad = true; + } + idx++; + } + } + } + } + return this._elem; + }; + + $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + plot.target.trigger('jqplotDataMouseOver', ins); + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + plot.target.trigger('jqplotDataHighlight', ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + }; + + + // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]); + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + options = options || {}; + options.axesDefaults = options.axesDefaults || {}; + options.legend = options.legend || {}; + options.seriesDefaults = options.seriesDefaults || {}; + // only set these if there is a pie series + var setopts = false; + if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer == $.jqplot.PieRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.PieAxisRenderer; + options.legend.renderer = $.jqplot.PieLegendRenderer; + options.legend.preDraw = true; + options.seriesDefaults.pointLabels = {show: false}; + } + } + + function postInit(target, data, options) { + for (var i=0; i<this.series.length; i++) { + if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) { + // don't allow mouseover and mousedown at same time. + if (this.series[i].highlightMouseOver) { + this.series[i].highlightMouseDown = false; + } + } + } + } + + // called with scope of plot + function postParseOptions(options) { + for (var i=0; i<this.series.length; i++) { + this.series[i].seriesColors = this.seriesColors; + this.series[i].colorGenerator = $.jqplot.colorGenerator; + } + } + + function highlight (plot, sidx, pidx) { + var s = plot.series[sidx]; + var canvas = plot.plugins.pieRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); + s._highlightedPoint = pidx; + plot.plugins.pieRenderer.highlightedSeriesIndex = sidx; + s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false); + } + + function unhighlight (plot) { + var canvas = plot.plugins.pieRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); + for (var i=0; i<plot.series.length; i++) { + plot.series[i]._highlightedPoint = null; + } + plot.plugins.pieRenderer.highlightedSeriesIndex = null; + plot.target.trigger('jqplotDataUnhighlight'); + } + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt1 = jQuery.Event('jqplotDataMouseOver'); + evt1.pageX = ev.pageX; + evt1.pageY = ev.pageY; + plot.target.trigger(evt1, ins); + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, ins[0], ins[1]); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { + var idx = plot.plugins.pieRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + } + + function handleClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt = jQuery.Event('jqplotDataClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + function handleRightClick(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var idx = plot.plugins.pieRenderer.highlightedSeriesIndex; + if (idx != null && plot.series[idx].highlightMouseDown) { + unhighlight(plot); + } + var evt = jQuery.Event('jqplotDataRightClick'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + } + } + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + function postPlotDraw() { + // Memory Leaks patch + if (this.plugins.pieRenderer && this.plugins.pieRenderer.highlightCanvas) { + this.plugins.pieRenderer.highlightCanvas.resetCanvas(); + this.plugins.pieRenderer.highlightCanvas = null; + } + + this.plugins.pieRenderer = {highlightedSeriesIndex:null}; + this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); + + // do we have any data labels? if so, put highlight canvas before those + var labels = $(this.targetId+' .jqplot-data-label'); + if (labels.length) { + $(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this)); + } + // else put highlight canvas before event canvas. + else { + this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this)); + } + + var hctx = this.plugins.pieRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); + } + + $.jqplot.preInitHooks.push(preInit); + + $.jqplot.PieTickRenderer = function() { + $.jqplot.AxisTickRenderer.call(this); + }; + + $.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer(); + $.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer; + +})(jQuery); + + \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pieRenderer.min.js b/plugin/jqplot/plugins/jqplot.pieRenderer.min.js new file mode 100644 index 000000000..a09f8f107 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pieRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(e){e.jqplot.PieRenderer=function(){e.jqplot.LineRenderer.call(this)};e.jqplot.PieRenderer.prototype=new e.jqplot.LineRenderer();e.jqplot.PieRenderer.prototype.constructor=e.jqplot.PieRenderer;e.jqplot.PieRenderer.prototype.init=function(q,u){this.diameter=null;this.padding=20;this.sliceMargin=0;this.fill=true;this.shadowOffset=2;this.shadowAlpha=0.07;this.shadowDepth=5;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.dataLabels="percent";this.showDataLabels=false;this.dataLabelFormatString=null;this.dataLabelThreshold=3;this.dataLabelPositionFactor=0.52;this.dataLabelNudge=2;this.dataLabelCenterOn=true;this.startAngle=0;this.tickRenderer=e.jqplot.PieTickRenderer;this._drawData=true;this._type="pie";if(q.highlightMouseDown&&q.highlightMouseOver==null){q.highlightMouseOver=false}e.extend(true,this,q);if(this.sliceMargin<0){this.sliceMargin=0}this._diameter=null;this._radius=null;this._sliceAngles=[];this._highlightedPoint=null;if(this.highlightColors.length==0){for(var s=0;s<this.seriesColors.length;s++){var r=e.jqplot.getColorComponents(this.seriesColors[s]);var o=[r[0],r[1],r[2]];var t=o[0]+o[1]+o[2];for(var p=0;p<3;p++){o[p]=(t>570)?o[p]*0.8:o[p]+0.3*(255-o[p]);o[p]=parseInt(o[p],10)}this.highlightColors.push("rgb("+o[0]+","+o[1]+","+o[2]+")")}}this.highlightColorGenerator=new e.jqplot.ColorGenerator(this.highlightColors);u.postParseOptionsHooks.addOnce(m);u.postInitHooks.addOnce(g);u.eventListenerHooks.addOnce("jqplotMouseMove",b);u.eventListenerHooks.addOnce("jqplotMouseDown",a);u.eventListenerHooks.addOnce("jqplotMouseUp",l);u.eventListenerHooks.addOnce("jqplotClick",f);u.eventListenerHooks.addOnce("jqplotRightClick",n);u.postDrawHooks.addOnce(i)};e.jqplot.PieRenderer.prototype.setGridData=function(t){var p=[];var u=[];var o=this.startAngle/180*Math.PI;var s=0;this._drawData=false;for(var r=0;r<this.data.length;r++){if(this.data[r][1]!=0){this._drawData=true}p.push(this.data[r][1]);u.push([this.data[r][0]]);if(r>0){p[r]+=p[r-1]}s+=this.data[r][1]}var q=Math.PI*2/p[p.length-1];for(var r=0;r<p.length;r++){u[r][1]=p[r]*q;u[r][2]=this.data[r][1]/s}this.gridData=u};e.jqplot.PieRenderer.prototype.makeGridData=function(t,u){var p=[];var v=[];var s=0;var o=this.startAngle/180*Math.PI;this._drawData=false;for(var r=0;r<t.length;r++){if(this.data[r][1]!=0){this._drawData=true}p.push(t[r][1]);v.push([t[r][0]]);if(r>0){p[r]+=p[r-1]}s+=t[r][1]}var q=Math.PI*2/p[p.length-1];for(var r=0;r<p.length;r++){v[r][1]=p[r]*q;v[r][2]=t[r][1]/s}return v};function h(o){return Math.sin((o-(o-Math.PI)/8/Math.PI)/2)}function j(u,t,o,v,r){var w=0;var q=t-u;var s=Math.abs(q);var p=o;if(v==false){p+=r}if(p>0&&s>0.01&&s<6.282){w=parseFloat(p)/2/h(q)}return w}e.jqplot.PieRenderer.prototype.drawSlice=function(B,z,y,u,w){if(this._drawData){var p=this._radius;var A=this.fill;var x=this.lineWidth;var s=this.sliceMargin;if(this.fill==false){s+=this.lineWidth}B.save();B.translate(this._center[0],this._center[1]);var D=j(z,y,this.sliceMargin,this.fill,this.lineWidth);var o=D*Math.cos((z+y)/2);var C=D*Math.sin((z+y)/2);if((y-z)<=Math.PI){p-=D}else{p+=D}B.translate(o,C);if(w){for(var v=0,t=this.shadowDepth;v<t;v++){B.save();B.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI),this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));q(p)}for(var v=0,t=this.shadowDepth;v<t;v++){B.restore()}}else{q(p)}B.restore()}function q(r){if(y>6.282+this.startAngle){y=6.282+this.startAngle;if(z>y){z=6.281+this.startAngle}}if(z>=y){return}B.beginPath();B.fillStyle=u;B.strokeStyle=u;B.lineWidth=x;B.arc(0,0,r,z,y,false);B.lineTo(0,0);B.closePath();if(A){B.fill()}else{B.stroke()}}};e.jqplot.PieRenderer.prototype.draw=function(B,z,E,o){var W;var H=(E!=undefined)?E:{};var t=0;var s=0;var N=1;var L=new e.jqplot.ColorGenerator(this.seriesColors);if(E.legendInfo&&E.legendInfo.placement=="insideGrid"){var J=E.legendInfo;switch(J.location){case"nw":t=J.width+J.xoffset;break;case"w":t=J.width+J.xoffset;break;case"sw":t=J.width+J.xoffset;break;case"ne":t=J.width+J.xoffset;N=-1;break;case"e":t=J.width+J.xoffset;N=-1;break;case"se":t=J.width+J.xoffset;N=-1;break;case"n":s=J.height+J.yoffset;break;case"s":s=J.height+J.yoffset;N=-1;break;default:break}}var K=(H.shadow!=undefined)?H.shadow:this.shadow;var A=(H.fill!=undefined)?H.fill:this.fill;var C=B.canvas.width;var I=B.canvas.height;var Q=C-t-2*this.padding;var X=I-s-2*this.padding;var M=Math.min(Q,X);var Y=M;this._sliceAngles=[];var v=this.sliceMargin;if(this.fill==false){v+=this.lineWidth}var q;var G=0;var R,aa,Z,ab;var D=this.startAngle/180*Math.PI;for(var W=0,V=z.length;W<V;W++){aa=(W==0)?D:z[W-1][1]+D;Z=z[W][1]+D;this._sliceAngles.push([aa,Z]);q=j(aa,Z,this.sliceMargin,this.fill,this.lineWidth);if(Math.abs(Z-aa)>Math.PI){G=Math.max(q,G)}}if(this.diameter!=null&&this.diameter>0){this._diameter=this.diameter-2*G}else{this._diameter=Y-2*G}if(this._diameter<6){e.jqplot.log("Diameter of pie too small, not rendering.");return}var S=this._radius=this._diameter/2;this._center=[(C-N*t)/2+N*t+G*Math.cos(D),(I-N*s)/2+N*s+G*Math.sin(D)];if(this.shadow){for(var W=0,V=z.length;W<V;W++){ab="rgba(0,0,0,"+this.shadowAlpha+")";this.renderer.drawSlice.call(this,B,this._sliceAngles[W][0],this._sliceAngles[W][1],ab,true)}}for(var W=0;W<z.length;W++){this.renderer.drawSlice.call(this,B,this._sliceAngles[W][0],this._sliceAngles[W][1],L.next(),false);if(this.showDataLabels&&z[W][2]*100>=this.dataLabelThreshold){var F,U=(this._sliceAngles[W][0]+this._sliceAngles[W][1])/2,T;if(this.dataLabels=="label"){F=this.dataLabelFormatString||"%s";T=e.jqplot.sprintf(F,z[W][0])}else{if(this.dataLabels=="value"){F=this.dataLabelFormatString||"%d";T=e.jqplot.sprintf(F,this.data[W][1])}else{if(this.dataLabels=="percent"){F=this.dataLabelFormatString||"%d%%";T=e.jqplot.sprintf(F,z[W][2]*100)}else{if(this.dataLabels.constructor==Array){F=this.dataLabelFormatString||"%s";T=e.jqplot.sprintf(F,this.dataLabels[W])}}}}var p=(this._radius)*this.dataLabelPositionFactor+this.sliceMargin+this.dataLabelNudge;var P=this._center[0]+Math.cos(U)*p+this.canvas._offsets.left;var O=this._center[1]+Math.sin(U)*p+this.canvas._offsets.top;var u=e('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">'+T+"</div>").insertBefore(o.eventCanvas._elem);if(this.dataLabelCenterOn){P-=u.width()/2;O-=u.height()/2}else{P-=u.width()*Math.sin(U/2);O-=u.height()/2}P=Math.round(P);O=Math.round(O);u.css({left:P,top:O})}}};e.jqplot.PieAxisRenderer=function(){e.jqplot.LinearAxisRenderer.call(this)};e.jqplot.PieAxisRenderer.prototype=new e.jqplot.LinearAxisRenderer();e.jqplot.PieAxisRenderer.prototype.constructor=e.jqplot.PieAxisRenderer;e.jqplot.PieAxisRenderer.prototype.init=function(o){this.tickRenderer=e.jqplot.PieTickRenderer;e.extend(true,this,o);this._dataBounds={min:0,max:100};this.min=0;this.max=100;this.showTicks=false;this.ticks=[];this.showMark=false;this.show=false};e.jqplot.PieLegendRenderer=function(){e.jqplot.TableLegendRenderer.call(this)};e.jqplot.PieLegendRenderer.prototype=new e.jqplot.TableLegendRenderer();e.jqplot.PieLegendRenderer.prototype.constructor=e.jqplot.PieLegendRenderer;e.jqplot.PieLegendRenderer.prototype.init=function(o){this.numberRows=null;this.numberColumns=null;e.extend(true,this,o)};e.jqplot.PieLegendRenderer.prototype.draw=function(){var r=this;if(this.show){var B=this._series;this._elem=e(document.createElement("table"));this._elem.addClass("jqplot-table-legend");var E={position:"absolute"};if(this.background){E.background=this.background}if(this.border){E.border=this.border}if(this.fontSize){E.fontSize=this.fontSize}if(this.fontFamily){E.fontFamily=this.fontFamily}if(this.textColor){E.textColor=this.textColor}if(this.marginTop!=null){E.marginTop=this.marginTop}if(this.marginBottom!=null){E.marginBottom=this.marginBottom}if(this.marginLeft!=null){E.marginLeft=this.marginLeft}if(this.marginRight!=null){E.marginRight=this.marginRight}this._elem.css(E);var I=false,A=false,o,y;var C=B[0];var p=new e.jqplot.ColorGenerator(C.seriesColors);if(C.show){var J=C.data;if(this.numberRows){o=this.numberRows;if(!this.numberColumns){y=Math.ceil(J.length/o)}else{y=this.numberColumns}}else{if(this.numberColumns){y=this.numberColumns;o=Math.ceil(J.length/this.numberColumns)}else{o=J.length;y=1}}var H,G;var q,w,v;var x,z,F;var D=0;var u,t;for(H=0;H<o;H++){q=e(document.createElement("tr"));q.addClass("jqplot-table-legend");if(A){q.prependTo(this._elem)}else{q.appendTo(this._elem)}for(G=0;G<y;G++){if(D<J.length){x=this.labels[D]||J[D][0].toString();F=p.next();if(!A){if(H>0){I=true}else{I=false}}else{if(H==o-1){I=false}else{I=true}}z=(I)?this.rowSpacing:"0";w=e(document.createElement("td"));w.addClass("jqplot-table-legend jqplot-table-legend-swatch");w.css({textAlign:"center",paddingTop:z});u=e(document.createElement("div"));u.addClass("jqplot-table-legend-swatch-outline");t=e(document.createElement("div"));t.addClass("jqplot-table-legend-swatch");t.css({backgroundColor:F,borderColor:F});w.append(u.append(t));v=e(document.createElement("td"));v.addClass("jqplot-table-legend jqplot-table-legend-label");v.css("paddingTop",z);if(this.escapeHtml){v.text(x)}else{v.html(x)}if(A){v.prependTo(q);w.prependTo(q)}else{w.appendTo(q);v.appendTo(q)}I=true}D++}}}}return this._elem};e.jqplot.PieRenderer.prototype.handleMove=function(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];r.target.trigger("jqplotDataMouseOver",o);if(r.series[o[0]].highlightMouseOver&&!(o[0]==r.plugins.pieRenderer.highlightedSeriesIndex&&o[1]==r.series[o[0]]._highlightedPoint)){r.target.trigger("jqplotDataHighlight",o);d(r,o[0],o[1])}}else{if(s==null){k(r)}}};function c(s,r,p){p=p||{};p.axesDefaults=p.axesDefaults||{};p.legend=p.legend||{};p.seriesDefaults=p.seriesDefaults||{};var o=false;if(p.seriesDefaults.renderer==e.jqplot.PieRenderer){o=true}else{if(p.series){for(var q=0;q<p.series.length;q++){if(p.series[q].renderer==e.jqplot.PieRenderer){o=true}}}}if(o){p.axesDefaults.renderer=e.jqplot.PieAxisRenderer;p.legend.renderer=e.jqplot.PieLegendRenderer;p.legend.preDraw=true;p.seriesDefaults.pointLabels={show:false}}}function g(r,q,o){for(var p=0;p<this.series.length;p++){if(this.series[p].renderer.constructor==e.jqplot.PieRenderer){if(this.series[p].highlightMouseOver){this.series[p].highlightMouseDown=false}}}}function m(o){for(var p=0;p<this.series.length;p++){this.series[p].seriesColors=this.seriesColors;this.series[p].colorGenerator=e.jqplot.colorGenerator}}function d(t,r,q){var p=t.series[r];var o=t.plugins.pieRenderer.highlightCanvas;o._ctx.clearRect(0,0,o._ctx.canvas.width,o._ctx.canvas.height);p._highlightedPoint=q;t.plugins.pieRenderer.highlightedSeriesIndex=r;p.renderer.drawSlice.call(p,o._ctx,p._sliceAngles[q][0],p._sliceAngles[q][1],p.highlightColorGenerator.get(q),false)}function k(q){var o=q.plugins.pieRenderer.highlightCanvas;o._ctx.clearRect(0,0,o._ctx.canvas.width,o._ctx.canvas.height);for(var p=0;p<q.series.length;p++){q.series[p]._highlightedPoint=null}q.plugins.pieRenderer.highlightedSeriesIndex=null;q.target.trigger("jqplotDataUnhighlight")}function b(s,r,v,u,t){if(u){var q=[u.seriesIndex,u.pointIndex,u.data];var p=jQuery.Event("jqplotDataMouseOver");p.pageX=s.pageX;p.pageY=s.pageY;t.target.trigger(p,q);if(t.series[q[0]].highlightMouseOver&&!(q[0]==t.plugins.pieRenderer.highlightedSeriesIndex&&q[1]==t.series[q[0]]._highlightedPoint)){var o=jQuery.Event("jqplotDataHighlight");o.which=s.which;o.pageX=s.pageX;o.pageY=s.pageY;t.target.trigger(o,q);d(t,q[0],q[1])}}else{if(u==null){k(t)}}}function a(r,q,u,t,s){if(t){var p=[t.seriesIndex,t.pointIndex,t.data];if(s.series[p[0]].highlightMouseDown&&!(p[0]==s.plugins.pieRenderer.highlightedSeriesIndex&&p[1]==s.series[p[0]]._highlightedPoint)){var o=jQuery.Event("jqplotDataHighlight");o.which=r.which;o.pageX=r.pageX;o.pageY=r.pageY;s.target.trigger(o,p);d(s,p[0],p[1])}}else{if(t==null){k(s)}}}function l(q,p,t,s,r){var o=r.plugins.pieRenderer.highlightedSeriesIndex;if(o!=null&&r.series[o].highlightMouseDown){k(r)}}function f(r,q,u,t,s){if(t){var p=[t.seriesIndex,t.pointIndex,t.data];var o=jQuery.Event("jqplotDataClick");o.which=r.which;o.pageX=r.pageX;o.pageY=r.pageY;s.target.trigger(o,p)}}function n(s,r,v,u,t){if(u){var q=[u.seriesIndex,u.pointIndex,u.data];var o=t.plugins.pieRenderer.highlightedSeriesIndex;if(o!=null&&t.series[o].highlightMouseDown){k(t)}var p=jQuery.Event("jqplotDataRightClick");p.which=s.which;p.pageX=s.pageX;p.pageY=s.pageY;t.target.trigger(p,q)}}function i(){if(this.plugins.pieRenderer&&this.plugins.pieRenderer.highlightCanvas){this.plugins.pieRenderer.highlightCanvas.resetCanvas();this.plugins.pieRenderer.highlightCanvas=null}this.plugins.pieRenderer={highlightedSeriesIndex:null};this.plugins.pieRenderer.highlightCanvas=new e.jqplot.GenericCanvas();var p=e(this.targetId+" .jqplot-data-label");if(p.length){e(p[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-pieRenderer-highlight-canvas",this._plotDimensions,this))}else{this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-pieRenderer-highlight-canvas",this._plotDimensions,this))}var o=this.plugins.pieRenderer.highlightCanvas.setContext();this.eventCanvas._elem.bind("mouseleave",{plot:this},function(q){k(q.data.plot)})}e.jqplot.preInitHooks.push(c);e.jqplot.PieTickRenderer=function(){e.jqplot.AxisTickRenderer.call(this)};e.jqplot.PieTickRenderer.prototype=new e.jqplot.AxisTickRenderer();e.jqplot.PieTickRenderer.prototype.constructor=e.jqplot.PieTickRenderer})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pointLabels.js b/plugin/jqplot/plugins/jqplot.pointLabels.js new file mode 100644 index 000000000..4edc69e45 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pointLabels.js @@ -0,0 +1,377 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + + /** + * Class: $.jqplot.PointLabels + * Plugin for putting labels at the data points. + * + * To use this plugin, include the js + * file in your source: + * + * > <script type="text/javascript" src="plugins/jqplot.pointLabels.js"></script> + * + * By default, the last value in the data ponit array in the data series is used + * for the label. For most series renderers, extra data can be added to the + * data point arrays and the last value will be used as the label. + * + * For instance, + * this series: + * + * > [[1,4], [3,5], [7,2]] + * + * Would, by default, use the y values in the labels. + * Extra data can be added to the series like so: + * + * > [[1,4,'mid'], [3 5,'hi'], [7,2,'low']] + * + * And now the point labels would be 'mid', 'low', and 'hi'. + * + * Options to the point labels and a custom labels array can be passed into the + * "pointLabels" option on the series option like so: + * + * > series:[{pointLabels:{ + * > labels:['mid', 'hi', 'low'], + * > location:'se', + * > ypadding: 12 + * > } + * > }] + * + * A custom labels array in the options takes precendence over any labels + * in the series data. If you have a custom labels array in the options, + * but still want to use values from the series array as labels, set the + * "labelsFromSeries" option to true. + * + * By default, html entities (<, >, etc.) are escaped in point labels. + * If you want to include actual html markup in the labels, + * set the "escapeHTML" option to false. + * + */ + $.jqplot.PointLabels = function(options) { + // Group: Properties + // + // prop: show + // show the labels or not. + this.show = $.jqplot.config.enablePlugins; + // prop: location + // compass location where to position the label around the point. + // 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' + this.location = 'n'; + // prop: labelsFromSeries + // true to use labels within data point arrays. + this.labelsFromSeries = false; + // prop: seriesLabelIndex + // array index for location of labels within data point arrays. + // if null, will use the last element of the data point array. + this.seriesLabelIndex = null; + // prop: labels + // array of arrays of labels, one array for each series. + this.labels = []; + // actual labels that will get displayed. + // needed to preserve user specified labels in labels array. + this._labels = []; + // prop: stackedValue + // true to display value as stacked in a stacked plot. + // no effect if labels is specified. + this.stackedValue = false; + // prop: ypadding + // vertical padding in pixels between point and label + this.ypadding = 6; + // prop: xpadding + // horizontal padding in pixels between point and label + this.xpadding = 6; + // prop: escapeHTML + // true to escape html entities in the labels. + // If you want to include markup in the labels, set to false. + this.escapeHTML = true; + // prop: edgeTolerance + // Number of pixels that the label must be away from an axis + // boundary in order to be drawn. Negative values will allow overlap + // with the grid boundaries. + this.edgeTolerance = -5; + // prop: formatter + // A class of a formatter for the tick text. sprintf by default. + this.formatter = $.jqplot.DefaultTickFormatter; + // prop: formatString + // string passed to the formatter. + this.formatString = ''; + // prop: hideZeros + // true to not show a label for a value which is 0. + this.hideZeros = false; + this._elems = []; + + $.extend(true, this, options); + }; + + var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w']; + var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7}; + var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e']; + + // called with scope of a series + $.jqplot.PointLabels.init = function (target, data, seriesDefaults, opts, plot){ + var options = $.extend(true, {}, seriesDefaults, opts); + options.pointLabels = options.pointLabels || {}; + if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal' && !options.pointLabels.location) { + options.pointLabels.location = 'e'; + } + // add a pointLabels attribute to the series plugins + this.plugins.pointLabels = new $.jqplot.PointLabels(options.pointLabels); + this.plugins.pointLabels.setLabels.call(this); + }; + + // called with scope of series + $.jqplot.PointLabels.prototype.setLabels = function() { + var p = this.plugins.pointLabels; + var labelIdx; + if (p.seriesLabelIndex != null) { + labelIdx = p.seriesLabelIndex; + } + else if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal') { + labelIdx = (this._plotData[0].length < 3) ? 0 : this._plotData[0].length -1; + } + else { + labelIdx = (this._plotData.length === 0) ? 0 : this._plotData[0].length -1; + } + p._labels = []; + if (p.labels.length === 0 || p.labelsFromSeries) { + if (p.stackedValue) { + if (this._plotData.length && this._plotData[0].length){ + // var idx = p.seriesLabelIndex || this._plotData[0].length -1; + for (var i=0; i<this._plotData.length; i++) { + p._labels.push(this._plotData[i][labelIdx]); + } + } + } + else { + // var d = this._plotData; + var d = this.data; + if (this.renderer.constructor === $.jqplot.BarRenderer && this.waterfall) { + d = this._data; + } + if (d.length && d[0].length) { + // var idx = p.seriesLabelIndex || d[0].length -1; + for (var i=0; i<d.length; i++) { + p._labels.push(d[i][labelIdx]); + } + } + d = null; + } + } + else if (p.labels.length){ + p._labels = p.labels; + } + }; + + $.jqplot.PointLabels.prototype.xOffset = function(elem, location, padding) { + location = location || this.location; + padding = padding || this.xpadding; + var offset; + + switch (location) { + case 'nw': + offset = -elem.outerWidth(true) - this.xpadding; + break; + case 'n': + offset = -elem.outerWidth(true)/2; + break; + case 'ne': + offset = this.xpadding; + break; + case 'e': + offset = this.xpadding; + break; + case 'se': + offset = this.xpadding; + break; + case 's': + offset = -elem.outerWidth(true)/2; + break; + case 'sw': + offset = -elem.outerWidth(true) - this.xpadding; + break; + case 'w': + offset = -elem.outerWidth(true) - this.xpadding; + break; + default: // same as 'nw' + offset = -elem.outerWidth(true) - this.xpadding; + break; + } + return offset; + }; + + $.jqplot.PointLabels.prototype.yOffset = function(elem, location, padding) { + location = location || this.location; + padding = padding || this.xpadding; + var offset; + + switch (location) { + case 'nw': + offset = -elem.outerHeight(true) - this.ypadding; + break; + case 'n': + offset = -elem.outerHeight(true) - this.ypadding; + break; + case 'ne': + offset = -elem.outerHeight(true) - this.ypadding; + break; + case 'e': + offset = -elem.outerHeight(true)/2; + break; + case 'se': + offset = this.ypadding; + break; + case 's': + offset = this.ypadding; + break; + case 'sw': + offset = this.ypadding; + break; + case 'w': + offset = -elem.outerHeight(true)/2; + break; + default: // same as 'nw' + offset = -elem.outerHeight(true) - this.ypadding; + break; + } + return offset; + }; + + // called with scope of series + $.jqplot.PointLabels.draw = function (sctx, options, plot) { + var p = this.plugins.pointLabels; + // set labels again in case they have changed. + p.setLabels.call(this); + // remove any previous labels + for (var i=0; i<p._elems.length; i++) { + // Memory Leaks patch + // p._elems[i].remove(); + p._elems[i].emptyForce(); + } + p._elems.splice(0, p._elems.length); + + if (p.show) { + var ax = '_'+this._stackAxis+'axis'; + + if (!p.formatString) { + p.formatString = this[ax]._ticks[0].formatString; + p.formatter = this[ax]._ticks[0].formatter; + } + + var pd = this._plotData; + var ppd = this._prevPlotData; + var xax = this._xaxis; + var yax = this._yaxis; + var elem, helem; + + for (var i=0, l=p._labels.length; i < l; i++) { + var label = p._labels[i]; + + if (label == null || (p.hideZeros && parseInt(label, 10) == 0)) { + continue; + } + + label = p.formatter(p.formatString, label); + + helem = document.createElement('div'); + p._elems[i] = $(helem); + + elem = p._elems[i]; + + + elem.addClass('jqplot-point-label jqplot-series-'+this.index+' jqplot-point-'+i); + elem.css('position', 'absolute'); + elem.insertAfter(sctx.canvas); + + if (p.escapeHTML) { + elem.text(label); + } + else { + elem.html(label); + } + var location = p.location; + if ((this.fillToZero && pd[i][1] < 0) || (this.fillToZero && this._type === 'bar' && this.barDirection === 'horizontal' && pd[i][0] < 0) || (this.waterfall && parseInt(label, 10)) < 0) { + location = oppositeLocations[locationIndicies[location]]; + } + + + var ell = xax.u2p(pd[i][0]) + p.xOffset(elem, location); + var elt = yax.u2p(pd[i][1]) + p.yOffset(elem, location); + + // we have stacked chart but are not showing stacked values, + // place labels in center. + if (this._stack && !p.stackedValue) { + if (this.barDirection === "vertical") { + elt = (this._barPoints[i][0][1] + this._barPoints[i][1][1]) / 2 + plot._gridPadding.top - 0.5 * elem.outerHeight(true); + } + else { + ell = (this._barPoints[i][2][0] + this._barPoints[i][0][0]) / 2 + plot._gridPadding.left - 0.5 * elem.outerWidth(true); + } + } + + if (this.renderer.constructor == $.jqplot.BarRenderer) { + if (this.barDirection == "vertical") { + ell += this._barNudge; + } + else { + elt -= this._barNudge; + } + } + elem.css('left', ell); + elem.css('top', elt); + var elr = ell + elem.width(); + var elb = elt + elem.height(); + var et = p.edgeTolerance; + var scl = $(sctx.canvas).position().left; + var sct = $(sctx.canvas).position().top; + var scr = sctx.canvas.width + scl; + var scb = sctx.canvas.height + sct; + // if label is outside of allowed area, remove it + if (ell - et < scl || elt - et < sct || elr + et > scr || elb + et > scb) { + elem.remove(); + } + + elem = null; + helem = null; + } + + // finally, animate them if the series is animated + // if (this.renderer.animation && this.renderer.animation._supported && this.renderer.animation.show && plot._drawCount < 2) { + // var sel = '.jqplot-point-label.jqplot-series-'+this.index; + // $(sel).hide(); + // $(sel).fadeIn(1000); + // } + + } + }; + + $.jqplot.postSeriesInitHooks.push($.jqplot.PointLabels.init); + $.jqplot.postDrawSeriesHooks.push($.jqplot.PointLabels.draw); +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pointLabels.min.js b/plugin/jqplot/plugins/jqplot.pointLabels.min.js new file mode 100644 index 000000000..01a75629f --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pointLabels.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(c){c.jqplot.PointLabels=function(e){this.show=c.jqplot.config.enablePlugins;this.location="n";this.labelsFromSeries=false;this.seriesLabelIndex=null;this.labels=[];this._labels=[];this.stackedValue=false;this.ypadding=6;this.xpadding=6;this.escapeHTML=true;this.edgeTolerance=-5;this.formatter=c.jqplot.DefaultTickFormatter;this.formatString="";this.hideZeros=false;this._elems=[];c.extend(true,this,e)};var a=["nw","n","ne","e","se","s","sw","w"];var d={nw:0,n:1,ne:2,e:3,se:4,s:5,sw:6,w:7};var b=["se","s","sw","w","nw","n","ne","e"];c.jqplot.PointLabels.init=function(j,h,f,g,i){var e=c.extend(true,{},f,g);e.pointLabels=e.pointLabels||{};if(this.renderer.constructor===c.jqplot.BarRenderer&&this.barDirection==="horizontal"&&!e.pointLabels.location){e.pointLabels.location="e"}this.plugins.pointLabels=new c.jqplot.PointLabels(e.pointLabels);this.plugins.pointLabels.setLabels.call(this)};c.jqplot.PointLabels.prototype.setLabels=function(){var f=this.plugins.pointLabels;var h;if(f.seriesLabelIndex!=null){h=f.seriesLabelIndex}else{if(this.renderer.constructor===c.jqplot.BarRenderer&&this.barDirection==="horizontal"){h=(this._plotData[0].length<3)?0:this._plotData[0].length-1}else{h=(this._plotData.length===0)?0:this._plotData[0].length-1}}f._labels=[];if(f.labels.length===0||f.labelsFromSeries){if(f.stackedValue){if(this._plotData.length&&this._plotData[0].length){for(var e=0;e<this._plotData.length;e++){f._labels.push(this._plotData[e][h])}}}else{var g=this.data;if(this.renderer.constructor===c.jqplot.BarRenderer&&this.waterfall){g=this._data}if(g.length&&g[0].length){for(var e=0;e<g.length;e++){f._labels.push(g[e][h])}}g=null}}else{if(f.labels.length){f._labels=f.labels}}};c.jqplot.PointLabels.prototype.xOffset=function(f,e,g){e=e||this.location;g=g||this.xpadding;var h;switch(e){case"nw":h=-f.outerWidth(true)-this.xpadding;break;case"n":h=-f.outerWidth(true)/2;break;case"ne":h=this.xpadding;break;case"e":h=this.xpadding;break;case"se":h=this.xpadding;break;case"s":h=-f.outerWidth(true)/2;break;case"sw":h=-f.outerWidth(true)-this.xpadding;break;case"w":h=-f.outerWidth(true)-this.xpadding;break;default:h=-f.outerWidth(true)-this.xpadding;break}return h};c.jqplot.PointLabels.prototype.yOffset=function(f,e,g){e=e||this.location;g=g||this.xpadding;var h;switch(e){case"nw":h=-f.outerHeight(true)-this.ypadding;break;case"n":h=-f.outerHeight(true)-this.ypadding;break;case"ne":h=-f.outerHeight(true)-this.ypadding;break;case"e":h=-f.outerHeight(true)/2;break;case"se":h=this.ypadding;break;case"s":h=this.ypadding;break;case"sw":h=this.ypadding;break;case"w":h=-f.outerHeight(true)/2;break;default:h=-f.outerHeight(true)-this.ypadding;break}return h};c.jqplot.PointLabels.draw=function(x,j,v){var t=this.plugins.pointLabels;t.setLabels.call(this);for(var w=0;w<t._elems.length;w++){t._elems[w].emptyForce()}t._elems.splice(0,t._elems.length);if(t.show){var r="_"+this._stackAxis+"axis";if(!t.formatString){t.formatString=this[r]._ticks[0].formatString;t.formatter=this[r]._ticks[0].formatter}var E=this._plotData;var D=this._prevPlotData;var A=this._xaxis;var q=this._yaxis;var z,f;for(var w=0,u=t._labels.length;w<u;w++){var o=t._labels[w];if(o==null||(t.hideZeros&&parseInt(o,10)==0)){continue}o=t.formatter(t.formatString,o);f=document.createElement("div");t._elems[w]=c(f);z=t._elems[w];z.addClass("jqplot-point-label jqplot-series-"+this.index+" jqplot-point-"+w);z.css("position","absolute");z.insertAfter(x.canvas);if(t.escapeHTML){z.text(o)}else{z.html(o)}var g=t.location;if((this.fillToZero&&E[w][1]<0)||(this.fillToZero&&this._type==="bar"&&this.barDirection==="horizontal"&&E[w][0]<0)||(this.waterfall&&parseInt(o,10))<0){g=b[d[g]]}var n=A.u2p(E[w][0])+t.xOffset(z,g);var h=q.u2p(E[w][1])+t.yOffset(z,g);if(this._stack&&!t.stackedValue){if(this.barDirection==="vertical"){h=(this._barPoints[w][0][1]+this._barPoints[w][1][1])/2+v._gridPadding.top-0.5*z.outerHeight(true)}else{n=(this._barPoints[w][2][0]+this._barPoints[w][0][0])/2+v._gridPadding.left-0.5*z.outerWidth(true)}}if(this.renderer.constructor==c.jqplot.BarRenderer){if(this.barDirection=="vertical"){n+=this._barNudge}else{h-=this._barNudge}}z.css("left",n);z.css("top",h);var k=n+z.width();var s=h+z.height();var C=t.edgeTolerance;var e=c(x.canvas).position().left;var y=c(x.canvas).position().top;var B=x.canvas.width+e;var m=x.canvas.height+y;if(n-C<e||h-C<y||k+C>B||s+C>m){z.remove()}z=null;f=null}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pyramidAxisRenderer.js b/plugin/jqplot/plugins/jqplot.pyramidAxisRenderer.js new file mode 100644 index 000000000..7650e30df --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pyramidAxisRenderer.js @@ -0,0 +1,728 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + $.jqplot.PyramidAxisRenderer = function() { + $.jqplot.LinearAxisRenderer.call(this); + }; + + $.jqplot.PyramidAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); + $.jqplot.PyramidAxisRenderer.prototype.constructor = $.jqplot.PyramidAxisRenderer; + + // called with scope of axis + $.jqplot.PyramidAxisRenderer.prototype.init = function(options){ + // Group: Properties + // + // prop: position + // Position of axis. Values are: top, bottom , left, center, right. + // By default, x and x2 axes are bottom, y axis is center. + this.position = null; + // prop: drawBaseline + // True to draw the axis baseline. + this.drawBaseline = true; + // prop: baselineWidth + // width of the baseline in pixels. + this.baselineWidth = null; + // prop: baselineColor + // CSS color spec for the baseline. + this.baselineColor = null; + this.tickSpacingFactor = 25; + this._type = 'pyramid'; + this._splitAxis = false; + this._splitLength = null; + this.category = false; + this._autoFormatString = ''; + this._overrideFormatString = false; + + $.extend(true, this, options); + this.renderer.options = options; + + this.resetDataBounds = this.renderer.resetDataBounds; + this.resetDataBounds(); + + }; + + $.jqplot.PyramidAxisRenderer.prototype.resetDataBounds = function() { + // Go through all the series attached to this axis and find + // the min/max bounds for this axis. + var db = this._dataBounds; + db.min = null; + db.max = null; + var temp; + for (var i=0; i<this._series.length; i++) { + var s = this._series[i]; + var d = s._plotData; + + for (var j=0, l=d.length; j<l; j++) { + if (this.name.charAt(0) === 'x') { + temp = d[j][1]; + if ((temp !== null && temp < db.min) || db.min === null) { + db.min = temp; + } + if ((temp !== null && temp > db.max) || db.max === null) { + db.max = temp; + } + } + else { + temp = d[j][0]; + if ((temp !== null && temp < db.min) || db.min === null) { + db.min = temp; + } + if ((temp !== null && temp > db.max) || db.max === null) { + db.max = temp; + } + } + } + } + }; + + // called with scope of axis + $.jqplot.PyramidAxisRenderer.prototype.draw = function(ctx, plot) { + if (this.show) { + // populate the axis label and value properties. + // createTicks is a method on the renderer, but + // call it within the scope of the axis. + this.renderer.createTicks.call(this, plot); + // fill a div with axes labels in the right direction. + // Need to pregenerate each axis to get its bounds and + // position it and the labels correctly on the plot. + var dim=0; + var temp; + // Added for theming. + if (this._elem) { + // Memory Leaks patch + //this._elem.empty(); + this._elem.emptyForce(); + this._elem = null; + } + + this._elem = $(document.createElement('div')); + this._elem.addClass('jqplot-axis jqplot-'+this.name); + this._elem.css('position', 'absolute'); + + + if (this.name == 'xaxis' || this.name == 'x2axis') { + this._elem.width(this._plotDimensions.width); + } + else { + this._elem.height(this._plotDimensions.height); + } + + // create a _label object. + this.labelOptions.axis = this.name; + this._label = new this.labelRenderer(this.labelOptions); + if (this._label.show) { + var elem = this._label.draw(ctx, plot); + elem.appendTo(this._elem); + elem = null; + } + + var t = this._ticks; + var tick; + for (var i=0; i<t.length; i++) { + tick = t[i]; + if (tick.show && tick.showLabel && (!tick.isMinorTick)) { + this._elem.append(tick.draw(ctx, plot)); + } + } + tick = null; + t = null; + } + return this._elem; + }; + + // Note, primes can be found on http://primes.utm.edu/ + var _primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]; + + + var _primesHash = {}; + + for (var i =0, l = _primes.length; i < l; i++) { + _primesHash[_primes[i]] = _primes[i]; + } + + // called with scope of axis + $.jqplot.PyramidAxisRenderer.prototype.createTicks = function(plot) { + // we're are operating on an axis here + var userTicks = this.ticks; + // databounds were set on axis initialization. + var db = this._dataBounds; + var dim; + var interval; + var min; + var max; + var range; + var pos1; + var pos2; + var tt; + var i; + var l; + var s; + // get a copy of user's settings for min/max. + var userMin = this.min; + var userMax = this.max; + var ut; + var t; + var threshold; + var tdim; + var scalefact; + var ret; + var tumin; + var tumax; + var maxVisibleTicks; + var val; + var skip = null; + var temp; + + // if we already have ticks, use them. + // ticks must be in order of increasing value. + + if (userTicks.length) { + // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed + for (i=0, l=userTicks.length; i<l; i++){ + ut = userTicks[i]; + t = new this.tickRenderer(this.tickOptions); + if ($.isArray(ut)) { + t.value = ut[0]; + t.label = ut[1]; + t.setTick(ut[0], this.name); + this._ticks.push(t); + } + + else if ($.isPlainObject(ut)) { + $.extend(true, t, ut); + t.axis = this.name; + this._ticks.push(t); + } + + else { + if (typeof ut === 'string') { + val = i + plot.defaultAxisStart; + } + else { + val = ut; + } + t.value = val; + t.label = ut; + t.axis = this.name; + this._ticks.push(t); + } + } + this.numberTicks = userTicks.length; + this.min = this._ticks[0].value; + this.max = this._ticks[this.numberTicks-1].value; + this.tickInterval = (this.max - this.min) / (this.numberTicks - 1); + + // use user specified tickInterval if there is one + if (this._options.tickInterval) { + // hide every tick except for ticks on interval + var ti = this._options.tickInterval; + for (i=0; i<this.numberTicks; i++) { + if (i%ti !== 0) { + // this._ticks[i].show = false; + this._ticks[i].isMinorTick = true; + } + } + } + + else { + // check if we have too many ticks + dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height; + maxVisibleTicks = Math.round(2.0 + dim/this.tickSpacingFactor); + + if (this.numberTicks > maxVisibleTicks) { + // check for number of ticks we can skip + temp = this.numberTicks - 1; + for (i=2; i<temp; i++) { + if (temp % i === 0 && temp/i < maxVisibleTicks) { + skip = i-1; + break; + } + } + + if (skip !== null) { + var count = 1; + for (i=1, l=this._ticks.length; i<l; i++) { + if (count <= skip) { + this._ticks[i].show = false; + count += 1; + } + else { + count = 1; + } + } + } + } + } + + // if category style, add minor ticks in between + temp = []; + if (this.category) { + // turn off gridline and mark on first tick + this._ticks[0].showGridline = false; + this._ticks[0].showMark = false; + + for (i=this._ticks.length-1; i>0; i--) { + t = new this.tickRenderer(this.tickOptions); + t.value = this._ticks[i-1].value + this.tickInterval/2.0; + t.label = ''; + t.showLabel = false; + t.axis = this.name; + this._ticks[i].showGridline = false; + this._ticks[i].showMark = false; + this._ticks.splice(i, 0, t); + // temp.push(t); + } + + // merge in the new ticks + // for (i=1, l=temp.length; i<l; i++) { + // this._ticks.splice(i, 0, temp[i]); + // } + + // now add a tick at beginning and end + t = new this.tickRenderer(this.tickOptions); + t.value = this._ticks[0].value - this.tickInterval/2.0; + t.label = ''; + t.showLabel = false; + t.axis = this.name; + this._ticks.unshift(t); + + t = new this.tickRenderer(this.tickOptions); + t.value = this._ticks[this._ticks.length-1].value + this.tickInterval/2.0; + t.label = ''; + t.showLabel = false; + t.axis = this.name; + this._ticks.push(t); + + this.tickInterval = this.tickInterval / 2.0; + this.numberTicks = this._ticks.length; + this.min = this._ticks[0].value; + this.max = this._ticks[this._ticks.length-1].value; + } + } + + // we don't have any ticks yet, let's make some! + else { + if (this.name.charAt(0) === 'x') { + dim = this._plotDimensions.width; + // make sure x axis is symetric about 0. + var tempmax = Math.max(db.max, Math.abs(db.min)); + var tempmin = Math.min(db.min, -tempmax); + // min = ((this.min != null) ? this.min : tempmin); + // max = ((this.max != null) ? this.max : tempmax); + min = tempmin; + max = tempmax; + range = max - min; + + if (this.tickOptions == null || !this.tickOptions.formatString) { + this._overrideFormatString = true; + } + + threshold = 30; + tdim = Math.max(dim, threshold+1); + scalefact = (tdim-threshold)/300.0; + ret = $.jqplot.LinearTickGenerator(min, max, scalefact); + // calculate a padded max and min, points should be less than these + // so that they aren't too close to the edges of the plot. + // User can adjust how much padding is allowed with pad, padMin and PadMax options. + tumin = min + range*(this.padMin - 1); + tumax = max - range*(this.padMax - 1); + + if (min < tumin || max > tumax) { + tumin = min - range*(this.padMin - 1); + tumax = max + range*(this.padMax - 1); + ret = $.jqplot.LinearTickGenerator(tumin, tumax, scalefact); + } + + this.min = ret[0]; + this.max = ret[1]; + this.numberTicks = ret[2]; + this._autoFormatString = ret[3]; + this.tickInterval = ret[4]; + } + else { + dim = this._plotDimensions.height; + + // ticks will be on whole integers like 1, 2, 3, ... or 1, 4, 7, ... + min = db.min; + max = db.max; + s = this._series[0]; + this._ticks = []; + + range = max - min; + + // if range is a prime, will get only 2 ticks, expand range in that case. + if (_primesHash[range]) { + range += 1; + max += 1; + } + + this.max = max; + this.min = min; + + maxVisibleTicks = Math.round(2.0 + dim/this.tickSpacingFactor); + + if (range + 1 <= maxVisibleTicks) { + this.numberTicks = range + 1; + this.tickInterval = 1.0; + } + + else { + // figure out a round number of ticks to skip in every interval + // range / ti + 1 = nt + // ti = range / (nt - 1) + for (var i=maxVisibleTicks; i>1; i--) { + if (range/(i - 1) === Math.round(range/(i - 1))) { + this.numberTicks = i; + this.tickInterval = range/(i - 1); + break; + } + + } + } + } + + if (this._overrideFormatString && this._autoFormatString != '') { + this.tickOptions = this.tickOptions || {}; + this.tickOptions.formatString = this._autoFormatString; + } + + var labelval; + for (i=0; i<this.numberTicks; i++) { + this.tickOptions.axis = this.name; + labelval = this.min + this.tickInterval * i; + if (this.name.charAt(0) === 'x') { + labelval = Math.abs(labelval); + } + // this.tickOptions.label = String (labelval); + this.tickOptions.value = this.min + this.tickInterval * i; + t = new this.tickRenderer(this.tickOptions); + + t.label = t.prefix + t.formatter(t.formatString, labelval); + + this._ticks.push(t); + // for x axis, if y axis is in middle, add a symetrical 0 tick + if (this.name.charAt(0) === 'x' && plot.axes.yMidAxis.show && this.tickOptions.value === 0) { + this._splitAxis = true; + this._splitLength = plot.axes.yMidAxis.getWidth(); + // t.value = -this.max/2000.0; + t = new this.tickRenderer(this.tickOptions); + this._ticks.push(t); + t.value = this.max/2000.0; + } + } + t = null; + } + }; + + // called with scope of axis + $.jqplot.PyramidAxisRenderer.prototype.set = function() { + var dim = 0; + var temp; + var w = 0; + var h = 0; + var i; + var t; + var tick; + var lshow = (this._label == null) ? false : this._label.show; + if (this.show) { + t = this._ticks; + l = t.length; + for (i=0; i<l; i++) { + tick = t[i]; + if (!tick._breakTick && tick.show && tick.showLabel && !tick.isMinorTick) { + if (this.name.charAt(0) === 'x') { + temp = tick._elem.outerHeight(true); + } + else { + temp = tick._elem.outerWidth(true); + } + if (temp > dim) { + dim = temp; + } + } + } + + if (this.name === 'yMidAxis') { + for (i=0; i<l; i++) { + tick = t[i]; + if (tick._elem) { + temp = (dim - tick._elem.outerWidth(true))/2.0; + tick._elem.css('left', temp); + } + } + } + tick = null; + t = null; + + if (lshow) { + w = this._label._elem.outerWidth(true); + h = this._label._elem.outerHeight(true); + } + if (this.name === 'xaxis') { + dim = dim + h; + this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); + } + else if (this.name === 'x2axis') { + dim = dim + h; + this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); + } + else if (this.name === 'yaxis') { + dim = dim + w; + this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css('width', w+'px'); + } + } + else if (this.name === 'yMidAxis') { + // don't include width of label at all in width of axis? + // dim = (dim > w) ? dim : w; + var temp = dim/2.0 - w/2.0; + this._elem.css({'width':dim+'px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css({width: w, left: temp, top: 0}); + } + } + else { + dim = dim + w; + this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); + if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { + this._label._elem.css('width', w+'px'); + } + } + } + }; + + $.jqplot.PyramidAxisRenderer.prototype.pack = function(pos, offsets) { + // Add defaults for repacking from resetTickValues function. + pos = pos || {}; + offsets = offsets || this._offsets; + + var ticks = this._ticks; + var max = this.max; + var min = this.min; + var offmax = offsets.max; + var offmin = offsets.min; + var lshow = (this._label == null) ? false : this._label.show; + + for (var p in pos) { + this._elem.css(p, pos[p]); + } + + this._offsets = offsets; + // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. + var pixellength = offmax - offmin; + var unitlength = max - min; + var sl = this._splitLength; + + // point to unit and unit to point conversions references to Plot DOM element top left corner. + if (this._splitAxis) { + pixellength -= this._splitLength; + + // don't know that this one is correct. + this.p2u = function(p){ + return (p - offmin) * unitlength / pixellength + min; + }; + + this.u2p = function(u){ + if (u <= 0) { + return (u - min) * pixellength / unitlength + offmin; + } + else { + return (u - min) * pixellength / unitlength + offmin + sl; + } + }; + + this.series_u2p = function(u){ + if (u <= 0) { + return (u - min) * pixellength / unitlength; + } + else { + return (u - min) * pixellength / unitlength + sl; + } + }; + + // don't know that this one is correct. + this.series_p2u = function(p){ + return p * unitlength / pixellength + min; + }; + } + else { + this.p2u = function(p){ + return (p - offmin) * unitlength / pixellength + min; + }; + + this.u2p = function(u){ + return (u - min) * pixellength / unitlength + offmin; + }; + + if (this.name.charAt(0) === 'x'){ + this.series_u2p = function(u){ + return (u - min) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + min; + }; + } + + else { + this.series_u2p = function(u){ + return (u - max) * pixellength / unitlength; + }; + this.series_p2u = function(p){ + return p * unitlength / pixellength + max; + }; + } + } + + if (this.show) { + if (this.name.charAt(0) === 'x') { + for (var i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel) { + var shim; + + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + // will need to adjust auto positioning based on which axis this is. + var temp = (this.name == 'xaxis') ? 1 : -1; + switch (t.labelPosition) { + case 'auto': + // position at end + if (temp * t.angle < 0) { + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + } + // position at start + else { + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + } + break; + case 'end': + shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + case 'start': + shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + break; + case 'middle': + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + default: + shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + break; + } + } + else { + shim = -t.getWidth()/2; + } + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('left', val); + t.pack(); + } + } + if (lshow) { + var w = this._label._elem.outerWidth(true); + this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); + if (this.name == 'xaxis') { + this._label._elem.css('bottom', '0px'); + } + else { + this._label._elem.css('top', '0px'); + } + this._label.pack(); + } + } + else { + for (var i=0; i<ticks.length; i++) { + var t = ticks[i]; + if (t.show && t.showLabel && !t.isMinorTick) { + var shim; + if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { + // will need to adjust auto positioning based on which axis this is. + var temp = (this.name == 'yaxis') ? 1 : -1; + switch (t.labelPosition) { + case 'auto': + // position at end + case 'end': + if (temp * t.angle < 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'start': + if (t.angle > 0) { + shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; + } + else { + shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; + } + break; + case 'middle': + // if (t.angle > 0) { + // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; + // } + // else { + // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; + // } + shim = -t.getHeight()/2; + break; + default: + shim = -t.getHeight()/2; + break; + } + } + else { + shim = -t.getHeight()/2; + } + + var val = this.u2p(t.value) + shim + 'px'; + t._elem.css('top', val); + t.pack(); + } + } + if (lshow) { + var h = this._label._elem.outerHeight(true); + if (this.name !== 'yMidAxis') { + this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); + } + if (this.name == 'yaxis') { + this._label._elem.css('left', '0px'); + } + else if (this.name !== 'yMidAxis') { + this._label._elem.css('right', '0px'); + } + this._label.pack(); + } + } + } + + ticks = null; + }; +})(jQuery); diff --git a/plugin/jqplot/plugins/jqplot.pyramidAxisRenderer.min.js b/plugin/jqplot/plugins/jqplot.pyramidAxisRenderer.min.js new file mode 100644 index 000000000..7b5db948f --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pyramidAxisRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(e){e.jqplot.PyramidAxisRenderer=function(){e.jqplot.LinearAxisRenderer.call(this)};e.jqplot.PyramidAxisRenderer.prototype=new e.jqplot.LinearAxisRenderer();e.jqplot.PyramidAxisRenderer.prototype.constructor=e.jqplot.PyramidAxisRenderer;e.jqplot.PyramidAxisRenderer.prototype.init=function(f){this.position=null;this.drawBaseline=true;this.baselineWidth=null;this.baselineColor=null;this.tickSpacingFactor=25;this._type="pyramid";this._splitAxis=false;this._splitLength=null;this.category=false;this._autoFormatString="";this._overrideFormatString=false;e.extend(true,this,f);this.renderer.options=f;this.resetDataBounds=this.renderer.resetDataBounds;this.resetDataBounds()};e.jqplot.PyramidAxisRenderer.prototype.resetDataBounds=function(){var h=this._dataBounds;h.min=null;h.max=null;var g;for(var m=0;m<this._series.length;m++){var n=this._series[m];var o=n._plotData;for(var k=0,f=o.length;k<f;k++){if(this.name.charAt(0)==="x"){g=o[k][1];if((g!==null&&g<h.min)||h.min===null){h.min=g}if((g!==null&&g>h.max)||h.max===null){h.max=g}}else{g=o[k][0];if((g!==null&&g<h.min)||h.min===null){h.min=g}if((g!==null&&g>h.max)||h.max===null){h.max=g}}}}};e.jqplot.PyramidAxisRenderer.prototype.draw=function(f,n){if(this.show){this.renderer.createTicks.call(this,n);var m=0;var g;if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=e(document.createElement("div"));this._elem.addClass("jqplot-axis jqplot-"+this.name);this._elem.css("position","absolute");if(this.name=="xaxis"||this.name=="x2axis"){this._elem.width(this._plotDimensions.width)}else{this._elem.height(this._plotDimensions.height)}this.labelOptions.axis=this.name;this._label=new this.labelRenderer(this.labelOptions);if(this._label.show){var l=this._label.draw(f,n);l.appendTo(this._elem);l=null}var k=this._ticks;var j;for(var h=0;h<k.length;h++){j=k[h];if(j.show&&j.showLabel&&(!j.isMinorTick)){this._elem.append(j.draw(f,n))}}j=null;k=null}return this._elem};var b=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];var d={};for(var c=0,a=b.length;c<a;c++){d[b[c]]=b[c]}e.jqplot.PyramidAxisRenderer.prototype.createTicks=function(D){var J=this.ticks;var M=this._dataBounds;var E;var K;var B;var G;var y;var n;var k;var h;var H;var C;var x;var L=this.min;var N=this.max;var q;var v;var m;var g;var j;var O;var A;var F;var r;var P;var z=null;var I;if(J.length){for(H=0,C=J.length;H<C;H++){q=J[H];v=new this.tickRenderer(this.tickOptions);if(e.isArray(q)){v.value=q[0];v.label=q[1];v.setTick(q[0],this.name);this._ticks.push(v)}else{if(e.isPlainObject(q)){e.extend(true,v,q);v.axis=this.name;this._ticks.push(v)}else{if(typeof q==="string"){P=H+D.defaultAxisStart}else{P=q}v.value=P;v.label=q;v.axis=this.name;this._ticks.push(v)}}}this.numberTicks=J.length;this.min=this._ticks[0].value;this.max=this._ticks[this.numberTicks-1].value;this.tickInterval=(this.max-this.min)/(this.numberTicks-1);if(this._options.tickInterval){var o=this._options.tickInterval;for(H=0;H<this.numberTicks;H++){if(H%o!==0){this._ticks[H].isMinorTick=true}}}else{E=(this.name.charAt(0)==="x")?this._plotDimensions.width:this._plotDimensions.height;r=Math.round(2+E/this.tickSpacingFactor);if(this.numberTicks>r){I=this.numberTicks-1;for(H=2;H<I;H++){if(I%H===0&&I/H<r){z=H-1;break}}if(z!==null){var p=1;for(H=1,C=this._ticks.length;H<C;H++){if(p<=z){this._ticks[H].show=false;p+=1}else{p=1}}}}}I=[];if(this.category){this._ticks[0].showGridline=false;this._ticks[0].showMark=false;for(H=this._ticks.length-1;H>0;H--){v=new this.tickRenderer(this.tickOptions);v.value=this._ticks[H-1].value+this.tickInterval/2;v.label="";v.showLabel=false;v.axis=this.name;this._ticks[H].showGridline=false;this._ticks[H].showMark=false;this._ticks.splice(H,0,v)}v=new this.tickRenderer(this.tickOptions);v.value=this._ticks[0].value-this.tickInterval/2;v.label="";v.showLabel=false;v.axis=this.name;this._ticks.unshift(v);v=new this.tickRenderer(this.tickOptions);v.value=this._ticks[this._ticks.length-1].value+this.tickInterval/2;v.label="";v.showLabel=false;v.axis=this.name;this._ticks.push(v);this.tickInterval=this.tickInterval/2;this.numberTicks=this._ticks.length;this.min=this._ticks[0].value;this.max=this._ticks[this._ticks.length-1].value}}else{if(this.name.charAt(0)==="x"){E=this._plotDimensions.width;var w=Math.max(M.max,Math.abs(M.min));var u=Math.min(M.min,-w);B=u;G=w;y=G-B;if(this.tickOptions==null||!this.tickOptions.formatString){this._overrideFormatString=true}m=30;g=Math.max(E,m+1);j=(g-m)/300;O=e.jqplot.LinearTickGenerator(B,G,j);A=B+y*(this.padMin-1);F=G-y*(this.padMax-1);if(B<A||G>F){A=B-y*(this.padMin-1);F=G+y*(this.padMax-1);O=e.jqplot.LinearTickGenerator(A,F,j)}this.min=O[0];this.max=O[1];this.numberTicks=O[2];this._autoFormatString=O[3];this.tickInterval=O[4]}else{E=this._plotDimensions.height;B=M.min;G=M.max;x=this._series[0];this._ticks=[];y=G-B;if(d[y]){y+=1;G+=1}this.max=G;this.min=B;r=Math.round(2+E/this.tickSpacingFactor);if(y+1<=r){this.numberTicks=y+1;this.tickInterval=1}else{for(var H=r;H>1;H--){if(y/(H-1)===Math.round(y/(H-1))){this.numberTicks=H;this.tickInterval=y/(H-1);break}}}}if(this._overrideFormatString&&this._autoFormatString!=""){this.tickOptions=this.tickOptions||{};this.tickOptions.formatString=this._autoFormatString}var f;for(H=0;H<this.numberTicks;H++){this.tickOptions.axis=this.name;f=this.min+this.tickInterval*H;if(this.name.charAt(0)==="x"){f=Math.abs(f)}this.tickOptions.value=this.min+this.tickInterval*H;v=new this.tickRenderer(this.tickOptions);v.label=v.prefix+v.formatter(v.formatString,f);this._ticks.push(v);if(this.name.charAt(0)==="x"&&D.axes.yMidAxis.show&&this.tickOptions.value===0){this._splitAxis=true;this._splitLength=D.axes.yMidAxis.getWidth();v=new this.tickRenderer(this.tickOptions);this._ticks.push(v);v.value=this.max/2000}}v=null}};e.jqplot.PyramidAxisRenderer.prototype.set=function(){var o=0;var j;var g=0;var n=0;var m;var l;var k;var f=(this._label==null)?false:this._label.show;if(this.show){l=this._ticks;a=l.length;for(m=0;m<a;m++){k=l[m];if(!k._breakTick&&k.show&&k.showLabel&&!k.isMinorTick){if(this.name.charAt(0)==="x"){j=k._elem.outerHeight(true)}else{j=k._elem.outerWidth(true)}if(j>o){o=j}}}if(this.name==="yMidAxis"){for(m=0;m<a;m++){k=l[m];if(k._elem){j=(o-k._elem.outerWidth(true))/2;k._elem.css("left",j)}}}k=null;l=null;if(f){g=this._label._elem.outerWidth(true);n=this._label._elem.outerHeight(true)}if(this.name==="xaxis"){o=o+n;this._elem.css({height:o+"px",left:"0px",bottom:"0px"})}else{if(this.name==="x2axis"){o=o+n;this._elem.css({height:o+"px",left:"0px",top:"0px"})}else{if(this.name==="yaxis"){o=o+g;this._elem.css({width:o+"px",left:"0px",top:"0px"});if(f&&this._label.constructor==e.jqplot.AxisLabelRenderer){this._label._elem.css("width",g+"px")}}else{if(this.name==="yMidAxis"){var j=o/2-g/2;this._elem.css({width:o+"px",top:"0px"});if(f&&this._label.constructor==e.jqplot.AxisLabelRenderer){this._label._elem.css({width:g,left:j,top:0})}}else{o=o+g;this._elem.css({width:o+"px",right:"0px",top:"0px"});if(f&&this._label.constructor==e.jqplot.AxisLabelRenderer){this._label._elem.css("width",g+"px")}}}}}}};e.jqplot.PyramidAxisRenderer.prototype.pack=function(j,g){j=j||{};g=g||this._offsets;var B=this._ticks;var v=this.max;var u=this.min;var o=g.max;var m=g.min;var r=(this._label==null)?false:this._label.show;for(var s in j){this._elem.css(s,j[s])}this._offsets=g;var k=o-m;var l=v-u;var z=this._splitLength;if(this._splitAxis){k-=this._splitLength;this.p2u=function(h){return(h-m)*l/k+u};this.u2p=function(h){if(h<=0){return(h-u)*k/l+m}else{return(h-u)*k/l+m+z}};this.series_u2p=function(h){if(h<=0){return(h-u)*k/l}else{return(h-u)*k/l+z}};this.series_p2u=function(h){return h*l/k+u}}else{this.p2u=function(h){return(h-m)*l/k+u};this.u2p=function(h){return(h-u)*k/l+m};if(this.name.charAt(0)==="x"){this.series_u2p=function(h){return(h-u)*k/l};this.series_p2u=function(h){return h*l/k+u}}else{this.series_u2p=function(h){return(h-v)*k/l};this.series_p2u=function(h){return h*l/k+v}}}if(this.show){if(this.name.charAt(0)==="x"){for(var x=0;x<B.length;x++){var q=B[x];if(q.show&&q.showLabel){var f;if(q.constructor==e.jqplot.CanvasAxisTickRenderer&&q.angle){var A=(this.name=="xaxis")?1:-1;switch(q.labelPosition){case"auto":if(A*q.angle<0){f=-q.getWidth()+q._textRenderer.height*Math.sin(-q._textRenderer.angle)/2}else{f=-q._textRenderer.height*Math.sin(q._textRenderer.angle)/2}break;case"end":f=-q.getWidth()+q._textRenderer.height*Math.sin(-q._textRenderer.angle)/2;break;case"start":f=-q._textRenderer.height*Math.sin(q._textRenderer.angle)/2;break;case"middle":f=-q.getWidth()/2+q._textRenderer.height*Math.sin(-q._textRenderer.angle)/2;break;default:f=-q.getWidth()/2+q._textRenderer.height*Math.sin(-q._textRenderer.angle)/2;break}}else{f=-q.getWidth()/2}var C=this.u2p(q.value)+f+"px";q._elem.css("left",C);q.pack()}}if(r){var n=this._label._elem.outerWidth(true);this._label._elem.css("left",m+k/2-n/2+"px");if(this.name=="xaxis"){this._label._elem.css("bottom","0px")}else{this._label._elem.css("top","0px")}this._label.pack()}}else{for(var x=0;x<B.length;x++){var q=B[x];if(q.show&&q.showLabel&&!q.isMinorTick){var f;if(q.constructor==e.jqplot.CanvasAxisTickRenderer&&q.angle){var A=(this.name=="yaxis")?1:-1;switch(q.labelPosition){case"auto":case"end":if(A*q.angle<0){f=-q._textRenderer.height*Math.cos(-q._textRenderer.angle)/2}else{f=-q.getHeight()+q._textRenderer.height*Math.cos(q._textRenderer.angle)/2}break;case"start":if(q.angle>0){f=-q._textRenderer.height*Math.cos(-q._textRenderer.angle)/2}else{f=-q.getHeight()+q._textRenderer.height*Math.cos(q._textRenderer.angle)/2}break;case"middle":f=-q.getHeight()/2;break;default:f=-q.getHeight()/2;break}}else{f=-q.getHeight()/2}var C=this.u2p(q.value)+f+"px";q._elem.css("top",C);q.pack()}}if(r){var y=this._label._elem.outerHeight(true);if(this.name!=="yMidAxis"){this._label._elem.css("top",o-k/2-y/2+"px")}if(this.name=="yaxis"){this._label._elem.css("left","0px")}else{if(this.name!=="yMidAxis"){this._label._elem.css("right","0px")}}this._label.pack()}}}B=null}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pyramidGridRenderer.js b/plugin/jqplot/plugins/jqplot.pyramidGridRenderer.js new file mode 100644 index 000000000..aeea42377 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pyramidGridRenderer.js @@ -0,0 +1,429 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + // Class: $.jqplot.CanvasGridRenderer + // The default jqPlot grid renderer, creating a grid on a canvas element. + // The renderer has no additional options beyond the <Grid> class. + $.jqplot.PyramidGridRenderer = function(){ + $.jqplot.CanvasGridRenderer.call(this); + }; + + $.jqplot.PyramidGridRenderer.prototype = new $.jqplot.CanvasGridRenderer(); + $.jqplot.PyramidGridRenderer.prototype.constructor = $.jqplot.PyramidGridRenderer; + + // called with context of Grid object + $.jqplot.CanvasGridRenderer.prototype.init = function(options) { + this._ctx; + this.plotBands = { + show: false, + color: 'rgb(230, 219, 179)', + axis: 'y', + start: null, + interval: 10 + }; + $.extend(true, this, options); + // set the shadow renderer options + var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false, strokeStyle:this.shadowColor}; + this.renderer.shadowRenderer.init(sopts); + }; + + $.jqplot.PyramidGridRenderer.prototype.draw = function() { + this._ctx = this._elem.get(0).getContext("2d"); + var ctx = this._ctx; + var axes = this._axes; + var xp = axes.xaxis.u2p; + var yp = axes.yMidAxis.u2p; + var xnudge = axes.xaxis.max/1000.0; + var xp0 = xp(0); + var xpn = xp(xnudge); + var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis','yMidAxis']; + // Add the grid onto the grid canvas. This is the bottom most layer. + ctx.save(); + ctx.clearRect(0, 0, this._plotDimensions.width, this._plotDimensions.height); + ctx.fillStyle = this.backgroundColor || this.background; + + ctx.fillRect(this._left, this._top, this._width, this._height); + + if (this.plotBands.show) { + ctx.save(); + var pb = this.plotBands; + ctx.fillStyle = pb.color; + var axis; + var x, y, w, h; + // find axis to work with + if (pb.axis.charAt(0) === 'x') { + if (axes.xaxis.show) { + axis = axes.xaxis; + } + } + else if (pb.axis.charAt(0) === 'y') { + if (axes.yaxis.show) { + axis = axes.yaxis; + } + else if (axes.y2axis.show) { + axis = axes.y2axis; + } + else if (axes.yMidAxis.show) { + axis = axes.yMidAxis; + } + } + + if (axis !== undefined) { + // draw some rectangles + var start = pb.start; + if (start === null) { + start = axis.min; + } + for (var i = start; i < axis.max; i += 2 * pb.interval) { + if (axis.name.charAt(0) === 'y') { + x = this._left; + if ((i + pb.interval) < axis.max) { + y = axis.series_u2p(i + pb.interval) + this._top; + } + else { + y = axis.series_u2p(axis.max) + this._top; + } + w = this._right - this._left; + h = axis.series_u2p(start) - axis.series_u2p(start + pb.interval); + ctx.fillRect(x, y, w, h); + } + // else { + // y = 0; + // x = axis.series_u2p(i); + // h = this._height; + // w = axis.series_u2p(start + pb.interval) - axis.series_u2p(start); + // } + + } + } + ctx.restore(); + } + + ctx.save(); + ctx.lineJoin = 'miter'; + ctx.lineCap = 'butt'; + ctx.lineWidth = this.gridLineWidth; + ctx.strokeStyle = this.gridLineColor; + var b, e, s, m; + for (var i=5; i>0; i--) { + var name = ax[i-1]; + var axis = axes[name]; + var ticks = axis._ticks; + var numticks = ticks.length; + if (axis.show) { + if (axis.drawBaseline) { + var bopts = {}; + if (axis.baselineWidth !== null) { + bopts.lineWidth = axis.baselineWidth; + } + if (axis.baselineColor !== null) { + bopts.strokeStyle = axis.baselineColor; + } + switch (name) { + case 'xaxis': + if (axes.yMidAxis.show) { + drawLine (this._left, this._bottom, xp0, this._bottom, bopts); + drawLine (xpn, this._bottom, this._right, this._bottom, bopts); + } + else { + drawLine (this._left, this._bottom, this._right, this._bottom, bopts); + } + break; + case 'yaxis': + drawLine (this._left, this._bottom, this._left, this._top, bopts); + break; + case 'yMidAxis': + drawLine(xp0, this._bottom, xp0, this._top, bopts); + drawLine(xpn, this._bottom, xpn, this._top, bopts); + break; + case 'x2axis': + if (axes.yMidAxis.show) { + drawLine (this._left, this._top, xp0, this._top, bopts); + drawLine (xpn, this._top, this._right, this._top, bopts); + } + else { + drawLine (this._left, this._bottom, this._right, this._bottom, bopts); + } + break; + case 'y2axis': + drawLine (this._right, this._bottom, this._right, this._top, bopts); + break; + + } + } + for (var j=numticks; j>0; j--) { + var t = ticks[j-1]; + if (t.show) { + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (name) { + case 'xaxis': + // draw the grid line if we should + if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) { + drawLine(pos, this._top, pos, this._bottom); + } + + // draw the mark + if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (m) { + case 'outside': + b = this._bottom; + e = this._bottom+s; + break; + case 'inside': + b = this._bottom-s; + e = this._bottom; + break; + case 'cross': + b = this._bottom-s; + e = this._bottom+s; + break; + default: + b = this._bottom; + e = this._bottom+s; + break; + } + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false}); + } + // draw the line + drawLine(pos, b, pos, e); + } + break; + case 'yaxis': + // draw the grid line + if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) { + drawLine(this._right, pos, this._left, pos); + } + + // draw the mark + if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (m) { + case 'outside': + b = this._left-s; + e = this._left; + break; + case 'inside': + b = this._left; + e = this._left+s; + break; + case 'cross': + b = this._left-s; + e = this._left+s; + break; + default: + b = this._left-s; + e = this._left; + break; + } + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); + } + drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); + } + break; + case 'yMidAxis': + // draw the grid line + if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) { + drawLine(this._left, pos, xp0, pos); + drawLine(xpn, pos, this._right, pos); + } + // draw the mark + if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + + b = xp0; + e = xp0 + s; + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); + } + drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); + + b = xpn - s; + e = xpn; + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); + } + drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); + } + break; + case 'x2axis': + // draw the grid line + if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) { + drawLine(pos, this._bottom, pos, this._top); + } + + // draw the mark + if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (m) { + case 'outside': + b = this._top-s; + e = this._top; + break; + case 'inside': + b = this._top; + e = this._top+s; + break; + case 'cross': + b = this._top-s; + e = this._top+s; + break; + default: + b = this._top-s; + e = this._top; + break; + } + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false}); + } + drawLine(pos, b, pos, e); + } + break; + case 'y2axis': + // draw the grid line + if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) { + drawLine(this._left, pos, this._right, pos); + } + + // draw the mark + if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) { + s = t.markSize; + m = t.mark; + var pos = Math.round(axis.u2p(t.value)) + 0.5; + switch (m) { + case 'outside': + b = this._right; + e = this._right+s; + break; + case 'inside': + b = this._right-s; + e = this._right; + break; + case 'cross': + b = this._right-s; + e = this._right+s; + break; + default: + b = this._right; + e = this._right+s; + break; + } + // draw the shadow + if (this.shadow) { + this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); + } + drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); + } + break; + default: + break; + } + } + } + t = null; + } + axis = null; + ticks = null; + } + + ctx.restore(); + + function drawLine(bx, by, ex, ey, opts) { + ctx.save(); + opts = opts || {}; + if (opts.lineWidth == null || opts.lineWidth != 0){ + $.extend(true, ctx, opts); + ctx.beginPath(); + ctx.moveTo(bx, by); + ctx.lineTo(ex, ey); + ctx.stroke(); + } + ctx.restore(); + } + + if (this.shadow) { + if (axes.yMidAxis.show) { + var points = [[this._left, this._bottom], [xp0, this._bottom]]; + this.renderer.shadowRenderer.draw(ctx, points); + var points = [[xpn, this._bottom], [this._right, this._bottom], [this._right, this._top]]; + this.renderer.shadowRenderer.draw(ctx, points); + var points = [[xp0, this._bottom], [xp0, this._top]]; + this.renderer.shadowRenderer.draw(ctx, points); + } + else { + var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]]; + this.renderer.shadowRenderer.draw(ctx, points); + } + } + // Now draw border around grid. Use axis border definitions. start at + // upper left and go clockwise. + if (this.borderWidth != 0 && this.drawBorder) { + if (axes.yMidAxis.show) { + drawLine (this._left, this._top, xp0, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth}); + drawLine (xpn, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth}); + drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth}); + drawLine (this._right, this._bottom, xpn, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth}); + drawLine (xp0, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth}); + drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth}); + drawLine (xp0, this._bottom, xp0, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth}); + drawLine (xpn, this._bottom, xpn, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth}); + } + else { + drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth}); + drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth}); + drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth}); + drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth}); + } + } + // ctx.lineWidth = this.borderWidth; + // ctx.strokeStyle = this.borderColor; + // ctx.strokeRect(this._left, this._top, this._width, this._height); + + ctx.restore(); + ctx = null; + axes = null; + }; +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pyramidGridRenderer.min.js b/plugin/jqplot/plugins/jqplot.pyramidGridRenderer.min.js new file mode 100644 index 000000000..25769919d --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pyramidGridRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(a){a.jqplot.PyramidGridRenderer=function(){a.jqplot.CanvasGridRenderer.call(this)};a.jqplot.PyramidGridRenderer.prototype=new a.jqplot.CanvasGridRenderer();a.jqplot.PyramidGridRenderer.prototype.constructor=a.jqplot.PyramidGridRenderer;a.jqplot.CanvasGridRenderer.prototype.init=function(c){this._ctx;this.plotBands={show:false,color:"rgb(230, 219, 179)",axis:"y",start:null,interval:10};a.extend(true,this,c);var b={lineJoin:"miter",lineCap:"round",fill:false,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.shadowWidth,closePath:false,strokeStyle:this.shadowColor};this.renderer.shadowRenderer.init(b)};a.jqplot.PyramidGridRenderer.prototype.draw=function(){this._ctx=this._elem.get(0).getContext("2d");var D=this._ctx;var G=this._axes;var q=G.xaxis.u2p;var J=G.yMidAxis.u2p;var l=G.xaxis.max/1000;var u=q(0);var f=q(l);var r=["xaxis","yaxis","x2axis","y2axis","yMidAxis"];D.save();D.clearRect(0,0,this._plotDimensions.width,this._plotDimensions.height);D.fillStyle=this.backgroundColor||this.background;D.fillRect(this._left,this._top,this._width,this._height);if(this.plotBands.show){D.save();var c=this.plotBands;D.fillStyle=c.color;var d;var o,n,p,I;if(c.axis.charAt(0)==="x"){if(G.xaxis.show){d=G.xaxis}}else{if(c.axis.charAt(0)==="y"){if(G.yaxis.show){d=G.yaxis}else{if(G.y2axis.show){d=G.y2axis}else{if(G.yMidAxis.show){d=G.yMidAxis}}}}}if(d!==undefined){var g=c.start;if(g===null){g=d.min}for(var H=g;H<d.max;H+=2*c.interval){if(d.name.charAt(0)==="y"){o=this._left;if((H+c.interval)<d.max){n=d.series_u2p(H+c.interval)+this._top}else{n=d.series_u2p(d.max)+this._top}p=this._right-this._left;I=d.series_u2p(g)-d.series_u2p(g+c.interval);D.fillRect(o,n,p,I)}}}D.restore()}D.save();D.lineJoin="miter";D.lineCap="butt";D.lineWidth=this.gridLineWidth;D.strokeStyle=this.gridLineColor;var L,K,A,C;for(var H=5;H>0;H--){var O=r[H-1];var d=G[O];var M=d._ticks;var B=M.length;if(d.show){if(d.drawBaseline){var N={};if(d.baselineWidth!==null){N.lineWidth=d.baselineWidth}if(d.baselineColor!==null){N.strokeStyle=d.baselineColor}switch(O){case"xaxis":if(G.yMidAxis.show){z(this._left,this._bottom,u,this._bottom,N);z(f,this._bottom,this._right,this._bottom,N)}else{z(this._left,this._bottom,this._right,this._bottom,N)}break;case"yaxis":z(this._left,this._bottom,this._left,this._top,N);break;case"yMidAxis":z(u,this._bottom,u,this._top,N);z(f,this._bottom,f,this._top,N);break;case"x2axis":if(G.yMidAxis.show){z(this._left,this._top,u,this._top,N);z(f,this._top,this._right,this._top,N)}else{z(this._left,this._bottom,this._right,this._bottom,N)}break;case"y2axis":z(this._right,this._bottom,this._right,this._top,N);break}}for(var E=B;E>0;E--){var v=M[E-1];if(v.show){var k=Math.round(d.u2p(v.value))+0.5;switch(O){case"xaxis":if(v.showGridline&&this.drawGridlines&&(!v.isMinorTick||d.showMinorTicks)){z(k,this._top,k,this._bottom)}if(v.showMark&&v.mark&&(!v.isMinorTick||d.showMinorTicks)){A=v.markSize;C=v.mark;var k=Math.round(d.u2p(v.value))+0.5;switch(C){case"outside":L=this._bottom;K=this._bottom+A;break;case"inside":L=this._bottom-A;K=this._bottom;break;case"cross":L=this._bottom-A;K=this._bottom+A;break;default:L=this._bottom;K=this._bottom+A;break}if(this.shadow){this.renderer.shadowRenderer.draw(D,[[k,L],[k,K]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}z(k,L,k,K)}break;case"yaxis":if(v.showGridline&&this.drawGridlines&&(!v.isMinorTick||d.showMinorTicks)){z(this._right,k,this._left,k)}if(v.showMark&&v.mark&&(!v.isMinorTick||d.showMinorTicks)){A=v.markSize;C=v.mark;var k=Math.round(d.u2p(v.value))+0.5;switch(C){case"outside":L=this._left-A;K=this._left;break;case"inside":L=this._left;K=this._left+A;break;case"cross":L=this._left-A;K=this._left+A;break;default:L=this._left-A;K=this._left;break}if(this.shadow){this.renderer.shadowRenderer.draw(D,[[L,k],[K,k]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}z(L,k,K,k,{strokeStyle:d.borderColor})}break;case"yMidAxis":if(v.showGridline&&this.drawGridlines&&(!v.isMinorTick||d.showMinorTicks)){z(this._left,k,u,k);z(f,k,this._right,k)}if(v.showMark&&v.mark&&(!v.isMinorTick||d.showMinorTicks)){A=v.markSize;C=v.mark;var k=Math.round(d.u2p(v.value))+0.5;L=u;K=u+A;if(this.shadow){this.renderer.shadowRenderer.draw(D,[[L,k],[K,k]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}z(L,k,K,k,{strokeStyle:d.borderColor});L=f-A;K=f;if(this.shadow){this.renderer.shadowRenderer.draw(D,[[L,k],[K,k]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}z(L,k,K,k,{strokeStyle:d.borderColor})}break;case"x2axis":if(v.showGridline&&this.drawGridlines&&(!v.isMinorTick||d.showMinorTicks)){z(k,this._bottom,k,this._top)}if(v.showMark&&v.mark&&(!v.isMinorTick||d.showMinorTicks)){A=v.markSize;C=v.mark;var k=Math.round(d.u2p(v.value))+0.5;switch(C){case"outside":L=this._top-A;K=this._top;break;case"inside":L=this._top;K=this._top+A;break;case"cross":L=this._top-A;K=this._top+A;break;default:L=this._top-A;K=this._top;break}if(this.shadow){this.renderer.shadowRenderer.draw(D,[[k,L],[k,K]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}z(k,L,k,K)}break;case"y2axis":if(v.showGridline&&this.drawGridlines&&(!v.isMinorTick||d.showMinorTicks)){z(this._left,k,this._right,k)}if(v.showMark&&v.mark&&(!v.isMinorTick||d.showMinorTicks)){A=v.markSize;C=v.mark;var k=Math.round(d.u2p(v.value))+0.5;switch(C){case"outside":L=this._right;K=this._right+A;break;case"inside":L=this._right-A;K=this._right;break;case"cross":L=this._right-A;K=this._right+A;break;default:L=this._right;K=this._right+A;break}if(this.shadow){this.renderer.shadowRenderer.draw(D,[[L,k],[K,k]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}z(L,k,K,k,{strokeStyle:d.borderColor})}break;default:break}}}v=null}d=null;M=null}D.restore();function z(j,i,e,b,h){D.save();h=h||{};if(h.lineWidth==null||h.lineWidth!=0){a.extend(true,D,h);D.beginPath();D.moveTo(j,i);D.lineTo(e,b);D.stroke()}D.restore()}if(this.shadow){if(G.yMidAxis.show){var F=[[this._left,this._bottom],[u,this._bottom]];this.renderer.shadowRenderer.draw(D,F);var F=[[f,this._bottom],[this._right,this._bottom],[this._right,this._top]];this.renderer.shadowRenderer.draw(D,F);var F=[[u,this._bottom],[u,this._top]];this.renderer.shadowRenderer.draw(D,F)}else{var F=[[this._left,this._bottom],[this._right,this._bottom],[this._right,this._top]];this.renderer.shadowRenderer.draw(D,F)}}if(this.borderWidth!=0&&this.drawBorder){if(G.yMidAxis.show){z(this._left,this._top,u,this._top,{lineCap:"round",strokeStyle:G.x2axis.borderColor,lineWidth:G.x2axis.borderWidth});z(f,this._top,this._right,this._top,{lineCap:"round",strokeStyle:G.x2axis.borderColor,lineWidth:G.x2axis.borderWidth});z(this._right,this._top,this._right,this._bottom,{lineCap:"round",strokeStyle:G.y2axis.borderColor,lineWidth:G.y2axis.borderWidth});z(this._right,this._bottom,f,this._bottom,{lineCap:"round",strokeStyle:G.xaxis.borderColor,lineWidth:G.xaxis.borderWidth});z(u,this._bottom,this._left,this._bottom,{lineCap:"round",strokeStyle:G.xaxis.borderColor,lineWidth:G.xaxis.borderWidth});z(this._left,this._bottom,this._left,this._top,{lineCap:"round",strokeStyle:G.yaxis.borderColor,lineWidth:G.yaxis.borderWidth});z(u,this._bottom,u,this._top,{lineCap:"round",strokeStyle:G.yaxis.borderColor,lineWidth:G.yaxis.borderWidth});z(f,this._bottom,f,this._top,{lineCap:"round",strokeStyle:G.yaxis.borderColor,lineWidth:G.yaxis.borderWidth})}else{z(this._left,this._top,this._right,this._top,{lineCap:"round",strokeStyle:G.x2axis.borderColor,lineWidth:G.x2axis.borderWidth});z(this._right,this._top,this._right,this._bottom,{lineCap:"round",strokeStyle:G.y2axis.borderColor,lineWidth:G.y2axis.borderWidth});z(this._right,this._bottom,this._left,this._bottom,{lineCap:"round",strokeStyle:G.xaxis.borderColor,lineWidth:G.xaxis.borderWidth});z(this._left,this._bottom,this._left,this._top,{lineCap:"round",strokeStyle:G.yaxis.borderColor,lineWidth:G.yaxis.borderWidth})}}D.restore();D=null;G=null}})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pyramidRenderer.js b/plugin/jqplot/plugins/jqplot.pyramidRenderer.js new file mode 100644 index 000000000..f230d9fae --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pyramidRenderer.js @@ -0,0 +1,514 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + + // Need to ensure pyramid axis and grid renderers are loaded. + // You should load these with script tags in the html head, that is more efficient + // as the browser will cache the request. + // Note, have to block with synchronous request in order to execute bar renderer code. + if ($.jqplot.PyramidAxisRenderer === undefined) { + $.ajax({ + url: $.jqplot.pluginLocation + 'jqplot.pyramidAxisRenderer.js', + dataType: "script", + async: false + }); + } + + if ($.jqplot.PyramidGridRenderer === undefined) { + $.ajax({ + url: $.jqplot.pluginLocation + 'jqplot.pyramidGridRenderer.js', + dataType: "script", + async: false + }); + } + + $.jqplot.PyramidRenderer = function(){ + $.jqplot.LineRenderer.call(this); + }; + + $.jqplot.PyramidRenderer.prototype = new $.jqplot.LineRenderer(); + $.jqplot.PyramidRenderer.prototype.constructor = $.jqplot.PyramidRenderer; + + // called with scope of a series + $.jqplot.PyramidRenderer.prototype.init = function(options, plot) { + options = options || {}; + this._type = 'pyramid'; + // Group: Properties + // + // prop: barPadding + this.barPadding = 10; + this.barWidth = null; + // prop: fill + // True to fill the bars. + this.fill = true; + // prop: highlightMouseOver + // True to highlight slice when moused over. + // This must be false to enable highlightMouseDown to highlight when clicking on a slice. + this.highlightMouseOver = true; + // prop: highlightMouseDown + // True to highlight when a mouse button is pressed over a slice. + // This will be disabled if highlightMouseOver is true. + this.highlightMouseDown = false; + // prop: highlightColors + // an array of colors to use when highlighting a slice. + this.highlightColors = []; + // prop highlightThreshold + // Expand the highlightable region in the x direction. + // E.g. a value of 3 will highlight a bar when the mouse is + // within 3 pixels of the bar in the x direction. + this.highlightThreshold = 2; + // prop: synchronizeHighlight + // Index of another series to highlight when this series is highlighted. + // null or false to not synchronize. + this.synchronizeHighlight = false; + // prop: offsetBars + // False will center bars on their y value. + // True will push bars up by 1/2 bar width to fill between their y values. + // If true, there needs to be 1 more tick than there are bars. + this.offsetBars = false; + + // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver + if (options.highlightMouseDown && options.highlightMouseOver == null) { + options.highlightMouseOver = false; + } + + this.side = 'right'; + + $.extend(true, this, options); + + // if (this.fill === false) { + // this.shadow = false; + // } + + if (this.side === 'left') { + this._highlightThreshold = [[-this.highlightThreshold, 0], [-this.highlightThreshold, 0], [0,0], [0,0]]; + } + + else { + this._highlightThreshold = [[0,0], [0,0], [this.highlightThreshold, 0], [this.highlightThreshold, 0]]; + } + + this.renderer.options = options; + // index of the currenty highlighted point, if any + this._highlightedPoint = null; + // Array of actual data colors used for each data point. + this._dataColors = []; + this._barPoints = []; + this.fillAxis = 'y'; + this._primaryAxis = '_yaxis'; + this._xnudge = 0; + + // set the shape renderer options + var opts = {lineJoin:'miter', lineCap:'butt', fill:this.fill, fillRect:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill, lineWidth: this.lineWidth}; + this.renderer.shapeRenderer.init(opts); + // set the shadow renderer options + var shadow_offset = options.shadowOffset; + // set the shadow renderer options + if (shadow_offset == null) { + // scale the shadowOffset to the width of the line. + if (this.lineWidth > 2.5) { + shadow_offset = 1.25 * (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6); + // var shadow_offset = this.shadowOffset; + } + // for skinny lines, don't make such a big shadow. + else { + shadow_offset = 1.25 * Math.atan((this.lineWidth/2.5))/0.785398163; + } + } + var sopts = {lineJoin:'miter', lineCap:'butt', fill:this.fill, fillRect:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill, lineWidth: this.lineWidth}; + this.renderer.shadowRenderer.init(sopts); + + plot.postDrawHooks.addOnce(postPlotDraw); + plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); + + // if this is the left side of pyramid, set y values to negative. + if (this.side === 'left') { + for (var i=0, l=this.data.length; i<l; i++) { + this.data[i][1] = -Math.abs(this.data[i][1]); + } + } + }; + + // setGridData + // converts the user data values to grid coordinates and stores them + // in the gridData array. + // Called with scope of a series. + $.jqplot.PyramidRenderer.prototype.setGridData = function(plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var data = this._plotData; + var pdata = this._prevPlotData; + this.gridData = []; + this._prevGridData = []; + var l = data.length; + var adjust = false; + var i; + + // if any data values are < 0, consider this a negative series + for (i = 0; i < l; i++) { + if (data[i][1] < 0) { + this.side = 'left'; + } + } + + if (this._yaxis.name === 'yMidAxis' && this.side === 'right') { + this._xnudge = this._xaxis.max/2000.0; + adjust = true; + } + + for (i = 0; i < l; i++) { + // if not a line series or if no nulls in data, push the converted point onto the array. + if (data[i][0] != null && data[i][1] != null) { + this.gridData.push([xp(data[i][1]), yp(data[i][0])]); + } + // else if there is a null, preserve it. + else if (data[i][0] == null) { + this.gridData.push([xp(data[i][1]), null]); + } + else if (data[i][1] == null) { + this.gridData.push(null, [yp(data[i][0])]); + } + // finally, adjust x grid data if have to + if (data[i][1] === 0 && adjust) { + this.gridData[i][0] = xp(this._xnudge); + } + } + }; + + // makeGridData + // converts any arbitrary data values to grid coordinates and + // returns them. This method exists so that plugins can use a series' + // linerenderer to generate grid data points without overwriting the + // grid data associated with that series. + // Called with scope of a series. + $.jqplot.PyramidRenderer.prototype.makeGridData = function(data, plot) { + // recalculate the grid data + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var gd = []; + var l = data.length; + var adjust = false; + var i; + + // if any data values are < 0, consider this a negative series + for (i = 0; i < l; i++) { + if (data[i][1] < 0) { + this.side = 'left'; + } + } + + if (this._yaxis.name === 'yMidAxis' && this.side === 'right') { + this._xnudge = this._xaxis.max/2000.0; + adjust = true; + } + + for (i = 0; i < l; i++) { + // if not a line series or if no nulls in data, push the converted point onto the array. + if (data[i][0] != null && data[i][1] != null) { + gd.push([xp(data[i][1]), yp(data[i][0])]); + } + // else if there is a null, preserve it. + else if (data[i][0] == null) { + gd.push([xp(data[i][1]), null]); + } + else if (data[i][1] == null) { + gd.push([null, yp(data[i][0])]); + } + // finally, adjust x grid data if have to + if (data[i][1] === 0 && adjust) { + gd[i][0] = xp(this._xnudge); + } + } + + return gd; + }; + + $.jqplot.PyramidRenderer.prototype.setBarWidth = function() { + // need to know how many data values we have on the approprate axis and figure it out. + var i; + var nvals = 0; + var nseries = 0; + var paxis = this[this._primaryAxis]; + var s, series, pos; + nvals = paxis.max - paxis.min; + var nticks = paxis.numberTicks; + var nbins = (nticks-1)/2; + // so, now we have total number of axis values. + var temp = (this.barPadding === 0) ? 1.0 : 0; + if (paxis.name == 'xaxis' || paxis.name == 'x2axis') { + this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding + temp; + } + else { + if (this.fill) { + this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding + temp; + } + else { + this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals; + } + } + }; + + $.jqplot.PyramidRenderer.prototype.draw = function(ctx, gridData, options) { + var i; + // Ughhh, have to make a copy of options b/c it may be modified later. + var opts = $.extend({}, options); + var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; + var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; + var fill = (opts.fill != undefined) ? opts.fill : this.fill; + var xp = this._xaxis.series_u2p; + var yp = this._yaxis.series_u2p; + var pointx, pointy; + // clear out data colors. + this._dataColors = []; + this._barPoints = []; + + if (this.renderer.options.barWidth == null) { + this.renderer.setBarWidth.call(this); + } + + // var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); + // var nvals = temp[0]; + // var nseries = temp[1]; + // var pos = temp[2]; + var points = [], + w, + h; + + // this._barNudge = 0; + + if (showLine) { + var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors); + var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors); + var negativeColor = negativeColors.get(this.index); + if (! this.useNegativeColors) { + negativeColor = opts.fillStyle; + } + var positiveColor = opts.fillStyle; + var base; + var xstart = this._xaxis.series_u2p(this._xnudge); + var ystart = this._yaxis.series_u2p(this._yaxis.min); + var yend = this._yaxis.series_u2p(this._yaxis.max); + var bw = this.barWidth; + var bw2 = bw/2.0; + var points = []; + var yadj = this.offsetBars ? bw2 : 0; + + for (var i=0, l=gridData.length; i<l; i++) { + if (this.data[i][0] == null) { + continue; + } + base = gridData[i][1]; + // not stacked and first series in stack + + if (this._plotData[i][1] < 0) { + if (this.varyBarColor && !this._stack) { + if (this.useNegativeColors) { + opts.fillStyle = negativeColors.next(); + } + else { + opts.fillStyle = positiveColors.next(); + } + } + } + else { + if (this.varyBarColor && !this._stack) { + opts.fillStyle = positiveColors.next(); + } + else { + opts.fillStyle = positiveColor; + } + } + + if (this.fill) { + + if (this._plotData[i][1] >= 0) { + // xstart = this._xaxis.series_u2p(this._xnudge); + w = gridData[i][0] - xstart; + h = this.barWidth; + points = [xstart, base - bw2 - yadj, w, h]; + } + else { + // xstart = this._xaxis.series_u2p(0); + w = xstart - gridData[i][0]; + h = this.barWidth; + points = [gridData[i][0], base - bw2 - yadj, w, h]; + } + + this._barPoints.push([[points[0], points[1] + h], [points[0], points[1]], [points[0] + w, points[1]], [points[0] + w, points[1] + h]]); + + if (shadow) { + this.renderer.shadowRenderer.draw(ctx, points); + } + var clr = opts.fillStyle || this.color; + this._dataColors.push(clr); + this.renderer.shapeRenderer.draw(ctx, points, opts); + } + + else { + if (i === 0) { + points =[[xstart, ystart], [gridData[i][0], ystart], [gridData[i][0], gridData[i][1] - bw2 - yadj]]; + } + + else if (i < l-1) { + points = points.concat([[gridData[i-1][0], gridData[i-1][1] - bw2 - yadj], [gridData[i][0], gridData[i][1] + bw2 - yadj], [gridData[i][0], gridData[i][1] - bw2 - yadj]]); + } + + // finally, draw the line + else { + points = points.concat([[gridData[i-1][0], gridData[i-1][1] - bw2 - yadj], [gridData[i][0], gridData[i][1] + bw2 - yadj], [gridData[i][0], yend], [xstart, yend]]); + + if (shadow) { + this.renderer.shadowRenderer.draw(ctx, points); + } + var clr = opts.fillStyle || this.color; + this._dataColors.push(clr); + this.renderer.shapeRenderer.draw(ctx, points, opts); + } + } + } + } + + if (this.highlightColors.length == 0) { + this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors); + } + + else if (typeof(this.highlightColors) == 'string') { + this.highlightColors = []; + for (var i=0; i<this._dataColors.length; i++) { + this.highlightColors.push(this.highlightColors); + } + } + + }; + + + // setup default renderers for axes and legend so user doesn't have to + // called with scope of plot + function preInit(target, data, options) { + options = options || {}; + options.axesDefaults = options.axesDefaults || {}; + options.grid = options.grid || {}; + options.legend = options.legend || {}; + options.seriesDefaults = options.seriesDefaults || {}; + // only set these if there is a pie series + var setopts = false; + if (options.seriesDefaults.renderer === $.jqplot.PyramidRenderer) { + setopts = true; + } + else if (options.series) { + for (var i=0; i < options.series.length; i++) { + if (options.series[i].renderer === $.jqplot.PyramidRenderer) { + setopts = true; + } + } + } + + if (setopts) { + options.axesDefaults.renderer = $.jqplot.PyramidAxisRenderer; + options.grid.renderer = $.jqplot.PyramidGridRenderer; + options.seriesDefaults.pointLabels = {show: false}; + } + } + + // called within context of plot + // create a canvas which we can draw on. + // insert it before the eventCanvas, so eventCanvas will still capture events. + function postPlotDraw() { + // Memory Leaks patch + if (this.plugins.pyramidRenderer && this.plugins.pyramidRenderer.highlightCanvas) { + + this.plugins.pyramidRenderer.highlightCanvas.resetCanvas(); + this.plugins.pyramidRenderer.highlightCanvas = null; + } + + this.plugins.pyramidRenderer = {highlightedSeriesIndex:null}; + this.plugins.pyramidRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); + + this.eventCanvas._elem.before(this.plugins.pyramidRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pyramidRenderer-highlight-canvas', this._plotDimensions, this)); + this.plugins.pyramidRenderer.highlightCanvas.setContext(); + this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); + } + + function highlight (plot, sidx, pidx, points) { + var s = plot.series[sidx]; + var canvas = plot.plugins.pyramidRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); + s._highlightedPoint = pidx; + plot.plugins.pyramidRenderer.highlightedSeriesIndex = sidx; + var opts = {fillStyle: s.highlightColors[pidx], fillRect: false}; + s.renderer.shapeRenderer.draw(canvas._ctx, points, opts); + if (s.synchronizeHighlight !== false && plot.series.length >= s.synchronizeHighlight && s.synchronizeHighlight !== sidx) { + s = plot.series[s.synchronizeHighlight]; + opts = {fillStyle: s.highlightColors[pidx], fillRect: false}; + s.renderer.shapeRenderer.draw(canvas._ctx, s._barPoints[pidx], opts); + } + canvas = null; + } + + function unhighlight (plot) { + var canvas = plot.plugins.pyramidRenderer.highlightCanvas; + canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); + for (var i=0; i<plot.series.length; i++) { + plot.series[i]._highlightedPoint = null; + } + plot.plugins.pyramidRenderer.highlightedSeriesIndex = null; + plot.target.trigger('jqplotDataUnhighlight'); + canvas = null; + } + + + function handleMove(ev, gridpos, datapos, neighbor, plot) { + if (neighbor) { + var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; + var evt1 = jQuery.Event('jqplotDataMouseOver'); + evt1.pageX = ev.pageX; + evt1.pageY = ev.pageY; + plot.target.trigger(evt1, ins); + if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pyramidRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { + var evt = jQuery.Event('jqplotDataHighlight'); + evt.which = ev.which; + evt.pageX = ev.pageX; + evt.pageY = ev.pageY; + plot.target.trigger(evt, ins); + highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points); + } + } + else if (neighbor == null) { + unhighlight (plot); + } + } + + // Have to add hook here, becuase it needs called before series is inited. + $.jqplot.preInitHooks.push(preInit); + + +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.pyramidRenderer.min.js b/plugin/jqplot/plugins/jqplot.pyramidRenderer.min.js new file mode 100644 index 000000000..9266e2273 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.pyramidRenderer.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(c){if(c.jqplot.PyramidAxisRenderer===undefined){c.ajax({url:c.jqplot.pluginLocation+"jqplot.pyramidAxisRenderer.js",dataType:"script",async:false})}if(c.jqplot.PyramidGridRenderer===undefined){c.ajax({url:c.jqplot.pluginLocation+"jqplot.pyramidGridRenderer.js",dataType:"script",async:false})}c.jqplot.PyramidRenderer=function(){c.jqplot.LineRenderer.call(this)};c.jqplot.PyramidRenderer.prototype=new c.jqplot.LineRenderer();c.jqplot.PyramidRenderer.prototype.constructor=c.jqplot.PyramidRenderer;c.jqplot.PyramidRenderer.prototype.init=function(j,o){j=j||{};this._type="pyramid";this.barPadding=10;this.barWidth=null;this.fill=true;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.highlightThreshold=2;this.synchronizeHighlight=false;this.offsetBars=false;if(j.highlightMouseDown&&j.highlightMouseOver==null){j.highlightMouseOver=false}this.side="right";c.extend(true,this,j);if(this.side==="left"){this._highlightThreshold=[[-this.highlightThreshold,0],[-this.highlightThreshold,0],[0,0],[0,0]]}else{this._highlightThreshold=[[0,0],[0,0],[this.highlightThreshold,0],[this.highlightThreshold,0]]}this.renderer.options=j;this._highlightedPoint=null;this._dataColors=[];this._barPoints=[];this.fillAxis="y";this._primaryAxis="_yaxis";this._xnudge=0;var n={lineJoin:"miter",lineCap:"butt",fill:this.fill,fillRect:this.fill,isarc:false,strokeStyle:this.color,fillStyle:this.color,closePath:this.fill,lineWidth:this.lineWidth};this.renderer.shapeRenderer.init(n);var m=j.shadowOffset;if(m==null){if(this.lineWidth>2.5){m=1.25*(1+(Math.atan((this.lineWidth/2.5))/0.785398163-1)*0.6)}else{m=1.25*Math.atan((this.lineWidth/2.5))/0.785398163}}var h={lineJoin:"miter",lineCap:"butt",fill:this.fill,fillRect:this.fill,isarc:false,angle:this.shadowAngle,offset:m,alpha:this.shadowAlpha,depth:this.shadowDepth,closePath:this.fill,lineWidth:this.lineWidth};this.renderer.shadowRenderer.init(h);o.postDrawHooks.addOnce(f);o.eventListenerHooks.addOnce("jqplotMouseMove",e);if(this.side==="left"){for(var k=0,g=this.data.length;k<g;k++){this.data[k][1]=-Math.abs(this.data[k][1])}}};c.jqplot.PyramidRenderer.prototype.setGridData=function(p){var j=this._xaxis.series_u2p;var o=this._yaxis.series_u2p;var k=this._plotData;var n=this._prevPlotData;this.gridData=[];this._prevGridData=[];var g=k.length;var m=false;var h;for(h=0;h<g;h++){if(k[h][1]<0){this.side="left"}}if(this._yaxis.name==="yMidAxis"&&this.side==="right"){this._xnudge=this._xaxis.max/2000;m=true}for(h=0;h<g;h++){if(k[h][0]!=null&&k[h][1]!=null){this.gridData.push([j(k[h][1]),o(k[h][0])])}else{if(k[h][0]==null){this.gridData.push([j(k[h][1]),null])}else{if(k[h][1]==null){this.gridData.push(null,[o(k[h][0])])}}}if(k[h][1]===0&&m){this.gridData[h][0]=j(this._xnudge)}}};c.jqplot.PyramidRenderer.prototype.makeGridData=function(m,p){var k=this._xaxis.series_u2p;var o=this._yaxis.series_u2p;var j=[];var g=m.length;var n=false;var h;for(h=0;h<g;h++){if(m[h][1]<0){this.side="left"}}if(this._yaxis.name==="yMidAxis"&&this.side==="right"){this._xnudge=this._xaxis.max/2000;n=true}for(h=0;h<g;h++){if(m[h][0]!=null&&m[h][1]!=null){j.push([k(m[h][1]),o(m[h][0])])}else{if(m[h][0]==null){j.push([k(m[h][1]),null])}else{if(m[h][1]==null){j.push([null,o(m[h][0])])}}}if(m[h][1]===0&&n){j[h][0]=k(this._xnudge)}}return j};c.jqplot.PyramidRenderer.prototype.setBarWidth=function(){var k;var g=0;var h=0;var m=this[this._primaryAxis];var q,l,o;g=m.max-m.min;var n=m.numberTicks;var j=(n-1)/2;var p=(this.barPadding===0)?1:0;if(m.name=="xaxis"||m.name=="x2axis"){this.barWidth=(m._offsets.max-m._offsets.min)/g-this.barPadding+p}else{if(this.fill){this.barWidth=(m._offsets.min-m._offsets.max)/g-this.barPadding+p}else{this.barWidth=(m._offsets.min-m._offsets.max)/g}}};c.jqplot.PyramidRenderer.prototype.draw=function(B,I,k){var E;var u=c.extend({},k);var p=(u.shadow!=undefined)?u.shadow:this.shadow;var K=(u.showLine!=undefined)?u.showLine:this.showLine;var C=(u.fill!=undefined)?u.fill:this.fill;var t=this._xaxis.series_u2p;var G=this._yaxis.series_u2p;var z,x;this._dataColors=[];this._barPoints=[];if(this.renderer.options.barWidth==null){this.renderer.setBarWidth.call(this)}var D=[],s,F;if(K){var q=new c.jqplot.ColorGenerator(this.negativeSeriesColors);var v=new c.jqplot.ColorGenerator(this.seriesColors);var J=q.get(this.index);if(!this.useNegativeColors){J=u.fillStyle}var o=u.fillStyle;var n;var L=this._xaxis.series_u2p(this._xnudge);var j=this._yaxis.series_u2p(this._yaxis.min);var m=this._yaxis.series_u2p(this._yaxis.max);var H=this.barWidth;var y=H/2;var D=[];var r=this.offsetBars?y:0;for(var E=0,A=I.length;E<A;E++){if(this.data[E][0]==null){continue}n=I[E][1];if(this._plotData[E][1]<0){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){u.fillStyle=q.next()}else{u.fillStyle=v.next()}}}else{if(this.varyBarColor&&!this._stack){u.fillStyle=v.next()}else{u.fillStyle=o}}if(this.fill){if(this._plotData[E][1]>=0){s=I[E][0]-L;F=this.barWidth;D=[L,n-y-r,s,F]}else{s=L-I[E][0];F=this.barWidth;D=[I[E][0],n-y-r,s,F]}this._barPoints.push([[D[0],D[1]+F],[D[0],D[1]],[D[0]+s,D[1]],[D[0]+s,D[1]+F]]);if(p){this.renderer.shadowRenderer.draw(B,D)}var g=u.fillStyle||this.color;this._dataColors.push(g);this.renderer.shapeRenderer.draw(B,D,u)}else{if(E===0){D=[[L,j],[I[E][0],j],[I[E][0],I[E][1]-y-r]]}else{if(E<A-1){D=D.concat([[I[E-1][0],I[E-1][1]-y-r],[I[E][0],I[E][1]+y-r],[I[E][0],I[E][1]-y-r]])}else{D=D.concat([[I[E-1][0],I[E-1][1]-y-r],[I[E][0],I[E][1]+y-r],[I[E][0],m],[L,m]]);if(p){this.renderer.shadowRenderer.draw(B,D)}var g=u.fillStyle||this.color;this._dataColors.push(g);this.renderer.shapeRenderer.draw(B,D,u)}}}}}if(this.highlightColors.length==0){this.highlightColors=c.jqplot.computeHighlightColors(this._dataColors)}else{if(typeof(this.highlightColors)=="string"){this.highlightColors=[];for(var E=0;E<this._dataColors.length;E++){this.highlightColors.push(this.highlightColors)}}}};function b(l,k,h){h=h||{};h.axesDefaults=h.axesDefaults||{};h.grid=h.grid||{};h.legend=h.legend||{};h.seriesDefaults=h.seriesDefaults||{};var g=false;if(h.seriesDefaults.renderer===c.jqplot.PyramidRenderer){g=true}else{if(h.series){for(var j=0;j<h.series.length;j++){if(h.series[j].renderer===c.jqplot.PyramidRenderer){g=true}}}}if(g){h.axesDefaults.renderer=c.jqplot.PyramidAxisRenderer;h.grid.renderer=c.jqplot.PyramidGridRenderer;h.seriesDefaults.pointLabels={show:false}}}function f(){if(this.plugins.pyramidRenderer&&this.plugins.pyramidRenderer.highlightCanvas){this.plugins.pyramidRenderer.highlightCanvas.resetCanvas();this.plugins.pyramidRenderer.highlightCanvas=null}this.plugins.pyramidRenderer={highlightedSeriesIndex:null};this.plugins.pyramidRenderer.highlightCanvas=new c.jqplot.GenericCanvas();this.eventCanvas._elem.before(this.plugins.pyramidRenderer.highlightCanvas.createElement(this._gridPadding,"jqplot-pyramidRenderer-highlight-canvas",this._plotDimensions,this));this.plugins.pyramidRenderer.highlightCanvas.setContext();this.eventCanvas._elem.bind("mouseleave",{plot:this},function(g){d(g.data.plot)})}function a(m,l,j,i){var h=m.series[l];var g=m.plugins.pyramidRenderer.highlightCanvas;g._ctx.clearRect(0,0,g._ctx.canvas.width,g._ctx.canvas.height);h._highlightedPoint=j;m.plugins.pyramidRenderer.highlightedSeriesIndex=l;var k={fillStyle:h.highlightColors[j],fillRect:false};h.renderer.shapeRenderer.draw(g._ctx,i,k);if(h.synchronizeHighlight!==false&&m.series.length>=h.synchronizeHighlight&&h.synchronizeHighlight!==l){h=m.series[h.synchronizeHighlight];k={fillStyle:h.highlightColors[j],fillRect:false};h.renderer.shapeRenderer.draw(g._ctx,h._barPoints[j],k)}g=null}function d(j){var g=j.plugins.pyramidRenderer.highlightCanvas;g._ctx.clearRect(0,0,g._ctx.canvas.width,g._ctx.canvas.height);for(var h=0;h<j.series.length;h++){j.series[h]._highlightedPoint=null}j.plugins.pyramidRenderer.highlightedSeriesIndex=null;j.target.trigger("jqplotDataUnhighlight");g=null}function e(k,j,n,m,l){if(m){var i=[m.seriesIndex,m.pointIndex,m.data];var h=jQuery.Event("jqplotDataMouseOver");h.pageX=k.pageX;h.pageY=k.pageY;l.target.trigger(h,i);if(l.series[i[0]].highlightMouseOver&&!(i[0]==l.plugins.pyramidRenderer.highlightedSeriesIndex&&i[1]==l.series[i[0]]._highlightedPoint)){var g=jQuery.Event("jqplotDataHighlight");g.which=k.which;g.pageX=k.pageX;g.pageY=k.pageY;l.target.trigger(g,i);a(l,m.seriesIndex,m.pointIndex,m.points)}}else{if(m==null){d(l)}}}c.jqplot.preInitHooks.push(b)})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.trendline.js b/plugin/jqplot/plugins/jqplot.trendline.js new file mode 100644 index 000000000..666498a92 --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.trendline.js @@ -0,0 +1,223 @@ +/** + * jqPlot + * Pure JavaScript plotting plugin using jQuery + * + * Version: 1.0.8 + * Revision: 1250 + * + * Copyright (c) 2009-2013 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL + * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris at jqplot dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + * + * sprintf functions contained in jqplot.sprintf.js by Ash Searle: + * + * version 2007.04.27 + * author Ash Searle + * http://hexmen.com/blog/2007/03/printf-sprintf/ + * http://hexmen.com/js/sprintf.js + * The author (Ash Searle) has placed this code in the public domain: + * "This code is unrestricted: you are free to use it however you like." + * + */ +(function($) { + + /** + * Class: $.jqplot.Trendline + * Plugin which will automatically compute and draw trendlines for plotted data. + */ + $.jqplot.Trendline = function() { + // Group: Properties + + // prop: show + // Wether or not to show the trend line. + this.show = $.jqplot.config.enablePlugins; + // prop: color + // CSS color spec for the trend line. + // By default this wil be the same color as the primary line. + this.color = '#666666'; + // prop: renderer + // Renderer to use to draw the trend line. + // The data series that is plotted may not be rendered as a line. + // Therefore, we use our own line renderer here to draw a trend line. + this.renderer = new $.jqplot.LineRenderer(); + // prop: rendererOptions + // Options to pass to the line renderer. + // By default, markers are not shown on trend lines. + this.rendererOptions = {marker:{show:false}}; + // prop: label + // Label for the trend line to use in the legend. + this.label = ''; + // prop: type + // Either 'exponential', 'exp', or 'linear'. + this.type = 'linear'; + // prop: shadow + // true or false, whether or not to show the shadow. + this.shadow = true; + // prop: markerRenderer + // Renderer to use to draw markers on the line. + // I think this is wrong. + this.markerRenderer = {show:false}; + // prop: lineWidth + // Width of the trend line. + this.lineWidth = 1.5; + // prop: shadowAngle + // Angle of the shadow on the trend line. + this.shadowAngle = 45; + // prop: shadowOffset + // pixel offset for each stroke of the shadow. + this.shadowOffset = 1.0; + // prop: shadowAlpha + // Alpha transparency of the shadow. + this.shadowAlpha = 0.07; + // prop: shadowDepth + // number of strokes to make of the shadow. + this.shadowDepth = 3; + this.isTrendline = true; + + }; + + $.jqplot.postSeriesInitHooks.push(parseTrendLineOptions); + $.jqplot.postDrawSeriesHooks.push(drawTrendline); + $.jqplot.addLegendRowHooks.push(addTrendlineLegend); + + // called witin scope of the legend object + // current series passed in + // must return null or an object {label:label, color:color} + function addTrendlineLegend(series) { + var ret = null; + if (series.trendline && series.trendline.show) { + var lt = series.trendline.label.toString(); + if (lt) { + ret = {label:lt, color:series.trendline.color}; + } + } + return ret; + } + + // called within scope of a series + function parseTrendLineOptions (target, data, seriesDefaults, options, plot) { + if (this._type && (this._type === 'line' || this._type == 'bar')) { + this.trendline = new $.jqplot.Trendline(); + options = options || {}; + $.extend(true, this.trendline, {color:this.color}, seriesDefaults.trendline, options.trendline); + this.trendline.renderer.init.call(this.trendline, null); + } + } + + // called within scope of series object + function drawTrendline(sctx, options) { + // if we have options, merge trendline options in with precedence + options = $.extend(true, {}, this.trendline, options); + + if (this.trendline && options.show) { + var fit; + // this.renderer.setGridData.call(this); + var data = options.data || this.data; + fit = fitData(data, this.trendline.type); + var gridData = options.gridData || this.renderer.makeGridData.call(this, fit.data); + this.trendline.renderer.draw.call(this.trendline, sctx, gridData, {showLine:true, shadow:this.trendline.shadow}); + } + } + + function regression(x, y, typ) { + var type = (typ == null) ? 'linear' : typ; + var N = x.length; + var slope; + var intercept; + var SX = 0; + var SY = 0; + var SXX = 0; + var SXY = 0; + var SYY = 0; + var Y = []; + var X = []; + + if (type == 'linear') { + X = x; + Y = y; + } + else if (type == 'exp' || type == 'exponential') { + for ( var i=0; i<y.length; i++) { + // ignore points <= 0, log undefined. + if (y[i] <= 0) { + N--; + } + else { + X.push(x[i]); + Y.push(Math.log(y[i])); + } + } + } + + for ( var i = 0; i < N; i++) { + SX = SX + X[i]; + SY = SY + Y[i]; + SXY = SXY + X[i]* Y[i]; + SXX = SXX + X[i]* X[i]; + SYY = SYY + Y[i]* Y[i]; + } + + slope = (N*SXY - SX*SY)/(N*SXX - SX*SX); + intercept = (SY - slope*SX)/N; + + return [slope, intercept]; + } + + function linearRegression(X,Y) { + var ret; + ret = regression(X,Y,'linear'); + return [ret[0],ret[1]]; + } + + function expRegression(X,Y) { + var ret; + var x = X; + var y = Y; + ret = regression(x, y,'exp'); + var base = Math.exp(ret[0]); + var coeff = Math.exp(ret[1]); + return [base, coeff]; + } + + function fitData(data, typ) { + var type = (typ == null) ? 'linear' : typ; + var ret; + var res; + var x = []; + var y = []; + var ypred = []; + + for (i=0; i<data.length; i++){ + if (data[i] != null && data[i][0] != null && data[i][1] != null) { + x.push(data[i][0]); + y.push(data[i][1]); + } + } + + if (type == 'linear') { + ret = linearRegression(x,y); + for ( var i=0; i<x.length; i++){ + res = ret[0]*x[i] + ret[1]; + ypred.push([x[i], res]); + } + } + else if (type == 'exp' || type == 'exponential') { + ret = expRegression(x,y); + for ( var i=0; i<x.length; i++){ + res = ret[1]*Math.pow(ret[0],x[i]); + ypred.push([x[i], res]); + } + } + return {data: ypred, slope: ret[0], intercept: ret[1]}; + } + +})(jQuery); \ No newline at end of file diff --git a/plugin/jqplot/plugins/jqplot.trendline.min.js b/plugin/jqplot/plugins/jqplot.trendline.min.js new file mode 100644 index 000000000..54744357b --- /dev/null +++ b/plugin/jqplot/plugins/jqplot.trendline.min.js @@ -0,0 +1,3 @@ +/* jqPlot 1.0.8r1250 | (c) 2009-2013 Chris Leonello | jplot.com + jsDate | (c) 2010-2013 Chris Leonello + */(function(f){f.jqplot.Trendline=function(){this.show=f.jqplot.config.enablePlugins;this.color="#666666";this.renderer=new f.jqplot.LineRenderer();this.rendererOptions={marker:{show:false}};this.label="";this.type="linear";this.shadow=true;this.markerRenderer={show:false};this.lineWidth=1.5;this.shadowAngle=45;this.shadowOffset=1;this.shadowAlpha=0.07;this.shadowDepth=3;this.isTrendline=true};f.jqplot.postSeriesInitHooks.push(e);f.jqplot.postDrawSeriesHooks.push(g);f.jqplot.addLegendRowHooks.push(a);function a(k){var j=null;if(k.trendline&&k.trendline.show){var i=k.trendline.label.toString();if(i){j={label:i,color:k.trendline.color}}}return j}function e(m,k,j,i,l){if(this._type&&(this._type==="line"||this._type=="bar")){this.trendline=new f.jqplot.Trendline();i=i||{};f.extend(true,this.trendline,{color:this.color},j.trendline,i.trendline);this.trendline.renderer.init.call(this.trendline,null)}}function g(m,i){i=f.extend(true,{},this.trendline,i);if(this.trendline&&i.show){var k;var l=i.data||this.data;k=c(l,this.trendline.type);var j=i.gridData||this.renderer.makeGridData.call(this,k.data);this.trendline.renderer.draw.call(this.trendline,m,j,{showLine:true,shadow:this.trendline.shadow})}}function b(w,v,n){var u=(n==null)?"linear":n;var s=w.length;var t;var z;var o=0;var m=0;var r=0;var q=0;var l=0;var j=[];var k=[];if(u=="linear"){k=w;j=v}else{if(u=="exp"||u=="exponential"){for(var p=0;p<v.length;p++){if(v[p]<=0){s--}else{k.push(w[p]);j.push(Math.log(v[p]))}}}}for(var p=0;p<s;p++){o=o+k[p];m=m+j[p];q=q+k[p]*j[p];r=r+k[p]*k[p];l=l+j[p]*j[p]}t=(s*q-o*m)/(s*r-o*o);z=(m-t*o)/s;return[t,z]}function h(k,j){var i;i=b(k,j,"linear");return[i[0],i[1]]}function d(o,m){var k;var i=o;var n=m;k=b(i,n,"exp");var l=Math.exp(k[0]);var j=Math.exp(k[1]);return[l,j]}function c(l,j){var p=(j==null)?"linear":j;var n;var o;var r=[];var q=[];var m=[];for(k=0;k<l.length;k++){if(l[k]!=null&&l[k][0]!=null&&l[k][1]!=null){r.push(l[k][0]);q.push(l[k][1])}}if(p=="linear"){n=h(r,q);for(var k=0;k<r.length;k++){o=n[0]*r[k]+n[1];m.push([r[k],o])}}else{if(p=="exp"||p=="exponential"){n=d(r,q);for(var k=0;k<r.length;k++){o=n[1]*Math.pow(n[0],r[k]);m.push([r[k],o])}}}return{data:m,slope:n[0],intercept:n[1]}}})(jQuery); \ No newline at end of file From ccd04e73b17779cfdd89f174b6d51c723caeb4ea Mon Sep 17 00:00:00 2001 From: chicpro <chicpro@sir.co.kr> Date: Fri, 28 Aug 2015 11:40:34 +0900 Subject: [PATCH 20/21] =?UTF-8?q?=EB=B2=84=EC=A0=84=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.php b/config.php index 48f73aa44..6f6a6bfed 100644 --- a/config.php +++ b/config.php @@ -5,7 +5,7 @@ ********************/ define('G5_VERSION', '그누보드5'); -define('G5_GNUBOARD_VER', '5.1.0'); +define('G5_GNUBOARD_VER', '5.1.1'); // 이 상수가 정의되지 않으면 각각의 개별 페이지는 별도로 실행될 수 없음 define('_GNUBOARD_', true); From b90672ae0e6aa8ac767fdce74d9a526f126ee143 Mon Sep 17 00:00:00 2001 From: chicpro <chicpro@sir.co.kr> Date: Fri, 28 Aug 2015 16:21:31 +0900 Subject: [PATCH 21/21] =?UTF-8?q?=EC=95=84=EC=9D=B4=ED=95=80=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=84=9C=EB=B9=84=EC=8A=A4=20url=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/okname/ipin.config.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/okname/ipin.config.php b/plugin/okname/ipin.config.php index 542ece16b..c4a0098cc 100644 --- a/plugin/okname/ipin.config.php +++ b/plugin/okname/ipin.config.php @@ -29,9 +29,9 @@ if($config['cf_cert_use'] == 2) { } else { // 테스트일 경우 $cpCode = 'P00000000000'; - $idpUrl = 'https://tipin.ok-name.co.kr:8443/tis/ti/POTI90B_SendCertInfo.jsp'; + $idpUrl = 'https://tmpin.ok-name.co.kr:5443/tis/ti/POTI90B_SendCertInfo.jsp'; $EndPointURL = 'http://twww.ok-name.co.kr:8888/KcbWebService/OkNameService'; //EndPointURL, 테스트 서버 - $kcbForm_action = 'https://tipin.ok-name.co.kr:8443/tis/ti/POTI01A_LoginRP.jsp'; + $kcbForm_action = 'https://tmpin.ok-name.co.kr:5443/tis/ti/POTI01A_LoginRP.jsp'; } $idpCode = 'V';